|
|
This is my solution to the bug posted by PoD on June 22. It also relates
to the 'Ghost of POV' posting in .general by Rune Johansen.
POV-Ray does not handle slope-maps correctly for patterned textures.
The problem is the way that slope-maps are calculated. The way it works
is by choosing 4 points in a tetrahedron (pyaramid) around the point
and finding the normals at these points from the slope-map and
interpolating.
The problem is that the 4 points are not warped along with the center
point as they should be. My solution is two-fold.
First, I think that different points should be chosen. I chose 4 points
that lie on a plane tangent to the surface. This allows the points to
be placed closer together (smaller DELTA) without floating point errors.
The ability to use a smaller DELTA means that the 'Ghost of POV' problem
can be made less visible.
Secondly, these points are computed on the first call to Perturb_Normal()
and within this call and in subsequent calls are warped along with the
center point. This second part is achieved by renaming Perturb_Normal()
to Perturb_Normal2() and changing all references in normal.c to this
new function. This is the recurisve part of Perturb_Normal(). Then a
new Perturb_Normal() function is created with the same parameters as the
original. This function simply creates the locus of 4 points (stored
in static variables for speed) and calls Perturb_Normal2(). Thus
Perturb_Normal() remains the entry point for the normal calculations.
Within Perturb_Normal2(), whenever EPoint is warped, the four sample
points must also be warped. This will, of course, slow down the process,
but that is apparantly the price we have to pay for the correct output.
It may be possible to set a flag (in Post_Tnormal) to prevent warping
these points if we know that the slope_map will not be used.
Below is my Perturb_Normal (this also has some code in it for the
reset_children warp).
Comments? (especially from the POV-Team...)
-Nathan Kopp
-------------------------------------------------------------
#define DELTA 0.002
/* these static variables are not thread safe */
static VECTOR sm_up, sm_n2, sm_n3;
static VECTOR sm_a, sm_b, sm_c, sm_d;
void Perturb_Normal2(VECTOR Layer_Normal, TNORMAL *Tnormal, VECTOR
EPoint,INTERSECTION *Intersection);
/* perturb_normal is not reentrant */
void Perturb_Normal(VECTOR Layer_Normal, TNORMAL *Tnormal, VECTOR
EPoint,INTERSECTION *Intersection)
{
/* some code from radiosit.c ;-) */
if ( fabs(fabs(Layer_Normal[Z])- 1.) < .1 )
{
/* too close to vertical for comfort, so use cross product with horizon */
sm_up[X] = 0.; sm_up[Y] = 1.; sm_up[Z] = 0.;
}
else
{
sm_up[X] = 0.; sm_up[Y] = 0.; sm_up[Z] = 1.;
}
VCross(sm_n2, Layer_Normal, sm_up); VNormalizeEq(sm_n2);
VCross(sm_n3, Layer_Normal, sm_n2); VNormalizeEq(sm_n3);
/* find 4 points on tangent plane - for slope_map */
VAddScaled(sm_a,EPoint,DELTA,sm_n2);
VAddScaled(sm_b,EPoint,DELTA,sm_n3);
VAddScaled(sm_c,EPoint,-DELTA,sm_n2);
VAddScaled(sm_d,EPoint,-DELTA,sm_n3);
Perturb_Normal2(Layer_Normal, Tnormal, EPoint, Intersection);
}
void Perturb_Normal2(VECTOR Layer_Normal, TNORMAL *Tnormal, VECTOR
EPoint,INTERSECTION *Intersection)
{
VECTOR TPoint,P1;
DBL value1,value2,Amount;
int i;
BLEND_MAP *Blend_Map;
BLEND_MAP_ENTRY *Prev, *Cur;
/* If normal_map present, use it and return */
if ((Blend_Map=Tnormal->Blend_Map) != NULL)
{
if ((Blend_Map->Type == NORMAL_TYPE) && (Tnormal->Type != AVERAGE_PATTERN))
{
value1 = Evaluate_TPat((TPATTERN *)Tnormal,EPoint);
Search_Blend_Map (value1,Blend_Map,&Prev,&Cur);
Assign_Vector(P1,Layer_Normal);
/* NK 1998 reset_children - added ", TRUE" - RESET_CHILDREN warps will be
executed */
Warp_EPoint (TPoint, EPoint, (TPATTERN *)Tnormal, TRUE);
Warp_EPoint (sm_a, sm_a, (TPATTERN *)Tnormal, TRUE);
Warp_EPoint (sm_b, sm_b, (TPATTERN *)Tnormal, TRUE);
Warp_EPoint (sm_c, sm_c, (TPATTERN *)Tnormal, TRUE);
Warp_EPoint (sm_d, sm_d, (TPATTERN *)Tnormal, TRUE);
Perturb_Normal2(Layer_Normal,Cur->Vals.Tnormal,TPoint,Intersection);
if (Prev != Cur)
{
Perturb_Normal2(P1,Prev->Vals.Tnormal,TPoint,Intersection);
value2 = (value1-Prev->value)/(Cur->value-Prev->value);
value1 = 1.0-value2;
VLinComb2(Layer_Normal,value1,P1,value2,Layer_Normal)
}
VNormalizeEq(Layer_Normal);
return;
}
}
/* No normal_map. */
if (Tnormal->Type <= LAST_NORM_ONLY_PATTERN)
{
/* NK 1998 reset_children - added ", FALSE" - RESET_CHILDREN warps will not
be executed */
/* NK 1999 reset_children - fixed bug with if */
if (Tnormal->Type == AVERAGE_PATTERN || Tnormal->Type == QUILTED_PATTERN)
{
Warp_EPoint (TPoint, EPoint, (TPATTERN *)Tnormal, TRUE);
Warp_EPoint (sm_a, sm_a, (TPATTERN *)Tnormal, TRUE);
Warp_EPoint (sm_b, sm_b, (TPATTERN *)Tnormal, TRUE);
Warp_EPoint (sm_c, sm_c, (TPATTERN *)Tnormal, TRUE);
Warp_EPoint (sm_d, sm_d, (TPATTERN *)Tnormal, TRUE);
}
else
{
Warp_EPoint (TPoint, EPoint, (TPATTERN *)Tnormal, FALSE);
Warp_EPoint (sm_a, sm_a, (TPATTERN *)Tnormal, FALSE);
Warp_EPoint (sm_b, sm_b, (TPATTERN *)Tnormal, FALSE);
Warp_EPoint (sm_c, sm_c, (TPATTERN *)Tnormal, FALSE);
Warp_EPoint (sm_d, sm_d, (TPATTERN *)Tnormal, FALSE);
}
switch (Tnormal->Type)
{
case BITMAP_PATTERN: bump_map (TPoint, Tnormal, Layer_Normal); break;
case BUMPS_PATTERN: bumps (TPoint, Tnormal, Layer_Normal); break;
case DENTS_PATTERN: dents (TPoint, Tnormal, Layer_Normal); break;
case RIPPLES_PATTERN:ripples (TPoint, Tnormal, Layer_Normal); break;
case WAVES_PATTERN: waves (TPoint, Tnormal, Layer_Normal); break;
case WRINKLES_PATTERN:wrinkles (TPoint, Tnormal, Layer_Normal);break;
case QUILTED_PATTERN:quilted (TPoint, Tnormal, Layer_Normal); break;
case AVERAGE_PATTERN: Do_Average_Normals (TPoint, Tnormal, Layer_Normal,
Intersection); break;
default:
Error("Normal pattern not yet implemented.");
}
}
else
{
Amount=Tnormal->Amount * -5.0; /*fudge factor*/
#if(1)
/* THIS IS THE NEW WAY */
value1 = Do_Slope_Map(Evaluate_TPat((TPATTERN *)Tnormal,sm_a),Blend_Map);
VAddScaledEq(Layer_Normal,value1*Amount*.02/DELTA,sm_n2);
value1 = Do_Slope_Map(Evaluate_TPat((TPATTERN *)Tnormal,sm_b),Blend_Map);
VAddScaledEq(Layer_Normal,value1*Amount*.02/DELTA,sm_n3);
value1 = Do_Slope_Map(Evaluate_TPat((TPATTERN *)Tnormal,sm_c),Blend_Map);
VAddScaledEq(Layer_Normal,-value1*Amount*.02/DELTA,sm_n2);
value1 = Do_Slope_Map(Evaluate_TPat((TPATTERN *)Tnormal,sm_d),Blend_Map);
VAddScaledEq(Layer_Normal,-value1*Amount*.02/DELTA,sm_n3);
#else
/* THIS IS THE OLD WAY */
/* Note, even though DELTA and Pyramid_Vect are constants, we may later
make DELTA a user-defined parameter. Good optimising compilers
should merge the constants anyway. */
for(i=0; i<=3; i++)
{
VAddScaled(P1,EPoint,DELTA,Pyramid_Vect[i]);
value1 = Do_Slope_Map(Evaluate_TPat((TPATTERN *)Tnormal,P1),Blend_Map);
/* NK 1999 - added "*.02/DELTA" */
VAddScaledEq(Layer_Normal,value1*Amount*.02/DELTA,Pyramid_Vect[i]);
}
#endif
}
VNormalizeEq(Layer_Normal);
}
Post a reply to this message
|
|