POV-Ray / povray

The Persistence of Vision Raytracer: http://www.povray.org/
GNU Affero General Public License v3.0
1.35k stars 282 forks source link

Port of FS242 - Algorithm to fix the so-called shadow line artifact #148

Open wfpokorny opened 7 years ago

wfpokorny commented 7 years ago

http://bugs.povray.org/task/242

See too github issue #132


Details

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:

See: FS242.zip


Comments:


Comment by Christoph Lipka (clipka) - Tuesday, 17 July 2012, 14:23 GMT+5

  • 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 } }"


Comment by Benedikt Adelmann (badelmann) - Wednesday, 20 March 2013, 19:42 GMT+5

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. Shadow Line Artefact.png (143.3 KiB)


Comment by Simon (infoised) - Monday, 25 March 2013, 23:40 GMT+5

@Benedikt I don't think you can find correct "height", because normal perturbation does not necessarily correspond to any real surface.


Comment by Benedikt Adelmann (badelmann) - Tuesday, 26 March 2013, 01:41 GMT+5

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?)


Comment by Simon (infoised) - Tuesday, 26 March 2013, 03:21 GMT+5

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.


Comment by Christoph Lipka (clipka) - Tuesday, 26 March 2013, 04:37 GMT+5

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

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.

(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?)

Only if the object in question is sufficiently simple. For instance you can't use this workaround for meshes.


Comment by Benedikt Adelmann (badelmann) - Tuesday, 26 March 2013, 15:02 GMT+5

POV-Ray actually only needs the derivative of the "height" function

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.)

and some normal perturbations are implemented this way

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?

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.

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.


Comment by Christoph Lipka (clipka) - Tuesday, 26 March 2013, 17:58 GMT+5

POV-Ray actually only needs the derivative of the "height" function

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.)

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.


Comment by Benedikt Adelmann (badelmann) - Tuesday, 26 March 2013, 18:33 GMT+5

when using certain patterns in POV-Ray it uses a hard-coded derivative of the respective function. It's simply faster and more precise

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.

There are infinitely many matching height functions

...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.

...

c-lipka commented 3 years ago

For the records: Since this is a long-stating issue, and the proposed solution is not entirely trivial to implement, we probably don't want to tackle in a hurry while we prepare for v3.8.0 release.