|
![](/i/fill.gif) |
I was able to produce a fix for this bug. I submit it here to the
POV-Ray team. If you'd like a copy of my LIGHTING.C file, just let
me know and I'll send it.
-Nathan Kopp
=================
The cause of the bug is kind of tricky. Imagine a bumpy surface:
_______
/ \
| | <--- these don't have to be exactly vertical
______/ \________ (object X)
In POV, the faked bump really looks like this:
______/|/_____\|\________ (object Y)
A B
Reflecting rays don't have much of a problem unless they hit the
parts where the slope is almost perpendicular to un-perturbed normal
(for example, points A or B). In this case, if you have a faked
normal, rays coming straight down towards the object just "fall
through the cracks." In real life, they would really get reflected
two (or more) times:
__ ray in
##\ /
##| /
##|/ ray out (if the surface was shaped like this)
##|\ /
##| \ /
###\_\/_______
##############
##############
With a faked normal, you don't get the second intersection:
ray in
/
/
__\|\________
\
\
\ ray out
So here's how I fixed it. The bug occurs when the direction of the
reflection ray is going the opposite direction of the non-perturbed (raw)
normal. (Note that this version of the raw normal has been flipped to point
towards the camera.)
So when this situation arises, I reflect the ray's direction across
the non-perturbed surface of the object.
===============
Here are the changes (all are in LIGHTING.C):
These changes HAVE been tested. (Of course, only to a limited extent.)
First, I fixed some redundant and buggy code in compute_lighted_texture()
The code
------------------
/* If the surface normal points away, flip its direction. */
VDot(Normal_Direction, RawNormal, Ray->Direction);
if (Normal_Direction > 0.0)
{
VScaleEq(RawNormal, -1.0);
}
------------------
appears in some radiosity-related stuff at the beginning of the funciton,
and then again (in a slightly different form) when the normals are being
perturbed. I simply consolidated this code and moved it to the beginning
of the function (outside of all if statements) so that it always gets
executed.
Now that I was sure that RawNormal had been properly flipped in all
situations, I added a vector parameter "Raw_Normal" to both Reflect()
and Refract(), passed the "RawNormal" variable to it. When Refract()
calls Reflect(), it just passes on the same "Raw_Normal" that it recieved.
Then, right after the line
------------------
VLinComb2(NRay.Direction, n, Normal, 1.0, Ray->Direction);
------------------
in Reflect(), I added:
------------------
/* NK 1998 - Reflection bugfix
if the new ray is going the same direction as raw normal, we
reflect it across the un-perturbed surface. */
VDot(NRay_Direction, NRay.Direction, Raw_Normal);
if (NRay_Direction < 0.0)
{
/* subtract twice the projection of NRay.Direction onto Raw_Normal
from Raw_Normal */
DBL Proj;
Proj = NRay_Direction * -2;
VAddScaledEq(NRay.Direction, Proj, Raw_Normal);
}
/* NK ---- */
------------------
This should fix the problem, and should not cause any un-wanted side
effects. Of course, it needs further testing.
-Nathan Kopp
Markus Becker wrote:
>
> Hello,
>
> here's another one that someone postet over there on c.g.r.r:
>
> The following scene consists of an opaque, reflective plane with
> a normal applied to it. The underlying plane with a checker
> pigment seems to come through the upper plane.
>
> camera { location <-1,20,-20> look_at <0,12,0> }
>
> light_source {
> <300,500,100>
> color rgb <1,1,1>
> }
>
> background { color rgb <0,1,0> }
>
> plane {
> y, 0
> texture {
> pigment { color rgb<.5,.5,.5> }
> normal { wood 0.5 scale 10 }
> finish { reflection 1}
> }
> }
>
> plane{
> y,-1
> texture {
> pigment {
> checker
> color rgb<1,0,0>
> color rgb<0,1,0>
> }
> scale 10
> }
> finish { ambient 1 }
> }
>
> //----------------- cut here ----------------------
>
> Markus
Post a reply to this message
|
![](/i/fill.gif) |