The Persistence of Vision Raytracer (POVRay).
This is the legacy Bug Tracking System for the POVRay project. Bugs listed here are being migrated to our github issue tracker. Please refer to that for new reports or updates to existing ones on this system.
FS#242  Algorithm to fix the socalled shadow line artifact
Opened by Juha Nieminen (Warp)  Sunday, 20 May 2012, 08:13 GMT
Last edited by William F Pokorny (wfpokorny)  Monday, 07 November 2016, 12:55 GMT

DetailsThe socalled shadow line artifact (http://wiki.povray.org/content/Knowledgebase:The_Shadow_Line_Artifact) which affects objects with a ‘normal’ statement as well as smooth meshes and heightfields can be really annoying sometimes. Currently the only way to remove it is to make the object shadowless, which isn’t a good solution except in very special cases. This algorithm could remove the artifact: If the actual normal vector of the object points away from the light source (its dotproduct with the light vector is negative) but the perturbed normal points towards it (dotproduct positive), then ignore the first shadowtest intersection with the object itself. There are alternative ways of implementing an equivalent functionality:  Don’t check the condition (if it’s too difficult to check due to how the code is designed) but always ignore the first intersection with the objects itself. This will work properly with closed surfaces but not with open ones, so it might need to be a feature for the user to turn on with a keyword (similar to eg. ‘double_illuminate’).  Alternatively, don’t ignore the first intersection, but instead ignore the “opposite side” of the object’s surface (again, possibly only if a keyword has been specified). In other words, if we are rendering the outer side of the object, ignore its inner side when shadowtesting, and viceversa.  Perhaps simply add a feature to make surfaces onesided (similarly to how they can be made so in OpenGL and similar scanline rendering systems). In other words, the inner side of a surface is completely ignored everywhere, making the object virtually invisible from the inside. The advantage of this feature would be that it can have uses other than simply removing the shadow line artifact. 
" Perhaps simply add a feature to make surfaces onesided (similarly to how they can be made so in OpenGL and similar scanline rendering systems). In other words, the inner side of a surface is completely ignored everywhere, making the object virtually invisible from the inside. The advantage of this feature would be that it can have uses other than simply removing the shadow line artifact. "
Such a feature already exists; it is called "interior_texture { pigment { rgbt 1 } }"
What if the origin of the ray testing against the light source (i.e. the shadow test ray) is not set to the actual location of the surface (the point the primary intersection occured) but that point shifted along the nonperturbed normal vector of the surface by an amount representing the "height" of that point (as normal perturbation is supposed to simulate changing "heights" of the surface making it look structured)? As POVRay computes the normal perturbation from a function that actually gives the "height" in any point of 3D space, this should not be a problem; if the shift amount is sufficiently high, the effect would be that no intersection with the object itself would not occur anymore (see attached file).
Admittedly this method would probably not be practicable for the shadow line artefact of smooth triangles.
@Benedikt I don't think you can find correct "height", because normal perturbation does not necessarily correspond to any real surface.
Normal perturbation  as archieved with the "normal" statement  need not correspond to any real surface, yet the way POVRay computes it indeed suggests it does. POVRay takes a function (via a function statement or implicitly via a builtin pattern, which is also internally represented as a scalar function in 3D space if I understood this correctly), interprets it as the "height" to be simulated above the real surface, and computes the slope needed for the actual perturbation by some triangulation (IIRC, that's what the documentation said). Then you do have a height, which is just the function value mapped into coordinate space.
For smooth triangles, I do not know whether a "height" is applicable  probably not , so I think this method would not be practicable for them.
(Correct me if I'm wrong, but isn't the main point of normal perturbation to make a surface look like a real surface that is warped, and isn't it possible to archieve the same effect  putting up with increased rendering duration  using an isosurface?)
Ok I agree, you are right. Somehow I had in mind that there is also a way of specifying full normal vectors (like for meshes), in which case it wouldn't be possible. So it could probably work, although I'm not sure how it would look like  it's worth trying.
It will probably only work well for shallow bump maps and surfaces that are not too bumpy themselves  remember, the shadow ray will still test intersection with the smooth surface.
Not really. POVRay actually only needs the derivative of the "height" function, and some normal perturbations are implemented this way. There are infinitely many matching height functions.
Also, consider a bump map defined by an image: Both a pitch black and a blinding white image yield a perfectly smooth surface, but they would give different (and therefore in at least one case obviously wrong) results when applying the proposed heightoffset algorithm.
Only if the object in question is sufficiently simple. For instance you can't use this workaround for meshes.
Mathematically yes (a vector of partial derivatives, the gradient), but when you specify a pattern or a userdefined function, it is the height function, isn't it? (I presume POVRay does not differentiate those functions internally.)
I think you are referring to patterns such as "bumps", of which the documentation says, "When used as a normal pattern, this pattern uses a specialized normal perturbation function" (sounds to me you differentiated the noise function and hardcoded the derivative). However, cannot the original height values also be accessed?
That's indeed a tough nut to crack. It would be interesting to see what result my proposed algorithm would produce in such cases. Actually, a fully white image would mean e.g. the radius of a sphere is faked to be larger than it is. So I would expect some kind of "shifting" applied to the shadow's border.
For patterns, it actually does; or, rather, when using certain patterns in POVRay it uses a hardcoded derivative of the respective function. It's simply faster and more precise than approximating the derivative by taking three samples.
As I said, I expected patterns like "bumps" to work this way. I know it is faster; however, as I also tried to point out, the use of the derivative does not necessarily make my algorithm impossible if the original (height) function's value can still be accessed.
...which all differ by a constant additional term, since their slopes have to be equal. Reconsidering the issue with the image bump map, it seems to me that if this algorithm would be used to circumvent the shadow line artefact either the user should be able to specify such a constant "shift" (especially for userdefined functions and images) inside the "normal" statement or a shift should be provided by the pattern used.
However, I have not yet figured out which value range would be appropriate for a height function fitting to solve the artefact. Throughout positive values are needed because with negative ones the artefact would just as well be generated; yet the smallest value should be zero so that no surface is being elevated illegally; on the other hand, in that particular point a nonzero value could be needed to avoid selfshadowing.
Now tracked on github as issue 148. Relates to github issue 132.