![]() |
Rama
physically-based lighting Shadows |
For a linear light source $\bs(x)$ in Rama, the direct ligthing integral at a point $\bp$ with normal $\bn$ has the following form (see the diffuse and specular models): \begin{equation} L=\int_{-l}^{+l} \ldots V(\bs(x),\bp)\ldots\mathrm{max}\left(\frac{\bs(x)-\bp}{\Vert\bs(x)-\bp\Vert}\cdot\bn,0\right)\ldots\mathrm{d} x \end{equation} where $V(\bx,\by)$ is $1$ if there is no occluder between $\bx$ and $\by$, or $0$ otherwise.
The $V$ term and the $\mathrm{max}$ function are problematic when one wants to find analytic approximations of this integral. In theory we can always get rid of them, by restricting the integral to the subset of the integration interval where $V$ is equal to $1$ and the dot product is positive. However, in general, this subset is hard to compute. We show here that this subset is a simple sub interval that can be analytically computed, if we restict ourselves to simple occluders like the cylindrical walls enclosing the cylindrical sea, or the horns of the south pole (neglecting the Manhattan buildings, much smaller in comparison, and the mountains).
The visibility term $V$ can be decomposed into a product of visibility terms $V=\Pi_i V_i$, one per occluder (the product acts as a logical AND, i.e. it means that the source is visible from $\bp$ if and only if it is not masked by any occluder). Each $V_i$ can be removed from the integral by restricting the integration interval to its intersection with the set $S_i$ where $V_i$ is equal to 1. Then the $V$ term can be removed by restricting the integration interval to its intersection with all the $S_i$. For simple occluders like the cylindrical walls or the conical "horns" in the south pole, each $S_i$ is a simple interval, which can be computed analytically, yielding a restricted integration interval which is still an interval. In the following we consider the case of the cylindrical walls. The conical horns can be handled in a similar way.
Let us consider the south cylindrical wall, with a point $\bp$ on one side and a linear light source on the other side (see Fig. 1).
Case 1 | Case 2 |
The visibility term $V(\bs(x),\bp)$ will be 0 for all $x$ such that the intersection $\bw(x)$ of the line from $\bp$ to $\bs(x)$ with the plane containing the cylindrical wall is not above the wall, but on the wall. We show below that this is the case for all $x \le x_0$ for some value $x_0$.
In the following we suppose that
We can now distinguish two cases (see Fig. 1):
Thus, in both cases, we can restrict the integral to all $u \gt u'_0$ and remove the visibility term in the integrand: \begin{equation} L=\int_{\mathrm{max}(u_0,u'_0)}^{u_1} \ldots \frac{au+b}{\Vert\bs(u)-\bp\Vert}\ldots\mathrm{d} u \end{equation}
// Compute the part of a linear light centered at s which is occluded // by the cylindrical wall for an observer at p (s and p must be given // in Rama coordinates). The result is given in coordinates relative // to p. All the points s + vec3(x,0.0,0.0) on the light source with // s.x - p.x + x smaller than the returned value are not visible from p. float wallIntersection(vec3 s, vec3 p) { float sSide = sign(s.x - Wx); float pSide = sign(p.x - Wx); float alpha = dot(p.yz, p.yz) - Wr * Wr; if (pSide * sSide < 0.0 && pSide * alpha > 0.0) { vec2 l = (Wx - p.x) * (s - p).yz; float beta = dot(p.yz, l); float gamma = dot(l, l); return (-beta - sqrt(beta * beta - alpha * gamma)) / alpha; } return -1e9; }
and one combining it with the sub interval computation to remove the $\mathrm{max}$ function:
// Compute the part of a linear light centered at s, of length 2l and // aligned with the x-axis which is visible from a surface patch // centered at p, of normal n. The result is given in coordinates // relative to p, i.e. it is a sub-interval of [s.x-p.x-l,s.x-p.x+l]. vec2 visibleLightSegment(vec3 s, float l, vec3 p, vec3 n) { vec3 ps = s - p; float a = n.x; float b = dot(ps.yz, n.yz); float u0 = a > 0.0 ? max(-b / a, ps.x - l) : ps.x - l; float u1 = a < 0.0 ? min(-b / a, ps.x + l) : ps.x + l; u0 = max(u0, wallIntersection(s, p)); return u0 < u1 ? vec2(u0, u1) : vec2(0.0); }