The Persistence of Vision Raytracer (POV-Ray).
This is the legacy Bug Tracking System for the POV-Ray 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.
Opened by Juha Nieminen - 2012-05-20
Last edited by William F Pokorny - 2016-11-07
FS#242 - Algorithm to fix the so-called shadow line artifact
The so-called 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 dot-product with the light vector is negative) but the perturbed normal points towards it (dot-product positive), then ignore the first shadow-test 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 shadow-testing, and vice-versa.
- Perhaps simply add a feature to make surfaces one-sided (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 one-sided (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 non-perturbed 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 POV-Ray 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 POV-Ray computes it indeed suggests it does. POV-Ray takes a function (via a function statement or implicitly via a built-in 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. POV-Ray 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 height-offset 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 user-defined function, it is the height function, isn't it? (I presume POV-Ray 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 hard-coded 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 POV-Ray it uses a hard-coded 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 user-defined 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 self-shadowing.
Now tracked on github as issue 148. Relates to github issue 132.