void Torus::Normal(VECTOR Result, Intersection *Inter, TraceThreadData *Thread) const { DBL dist; VECTOR P, N, M; /* Transform the point into the torus space. */ MInvTransPoint(P, Inter->IPoint, Trans); /* Get normal from derivatives. */ dist = sqrt(P[X] * P[X] + P[Z] * P[Z]); if (dist > EPSILON) { M[X] = MajorRadius * P[X] / dist; M[Y] = 0.0; M[Z] = MajorRadius * P[Z] / dist; } else { Make_Vector(M, 0.0, 0.0, 0.0); } VSub(N, P, M); /* Transform the normalt out of the torus space. */ MTransNormal(Result, N, Trans); VNormalize(Result, Result); }
void UnWarp_Normal (VECTOR TNorm, VECTOR ENorm, TPATTERN *TPat, int DontScaleBumps) { WARP *Warp = NULL; if(!DontScaleBumps) VNormalize(TNorm,ENorm); else Assign_Vector(TNorm,ENorm); if(TPat->Warps != NULL) { // go to the last entry for(Warp = TPat->Warps; Warp->Next_Warp != NULL; Warp = Warp->Next_Warp) ; // walk backwards from the last entry for(; Warp != NULL; Warp = Warp->Prev_Warp) { if(Warp->Warp_Type == TRANSFORM_WARP) MTransNormal(TNorm, TNorm, &(((TRANS *)Warp)->Trans)); } } if(!DontScaleBumps) VNormalizeEq(TNorm); }
void Warp_Normal (VECTOR TNorm, VECTOR ENorm, TPATTERN *TPat, int DontScaleBumps) { WARP *Warp=TPat->Warps; TRANS *Tr; if(!DontScaleBumps) VNormalize(TNorm,ENorm); else Assign_Vector(TNorm,ENorm); while(Warp != NULL) { switch(Warp->Warp_Type) { default: case NO_WARP: break; case TRANSFORM_WARP: Tr=(TRANS *)Warp; MInvTransNormal(TNorm, TNorm, &(Tr->Trans)); break; /* default: Error("Warp type %d not yet implemented",Warp->Warp_Type); */ } Warp=Warp->Next_Warp; } if(!DontScaleBumps) VNormalizeEq(TNorm); }
void Parametric::Normal(VECTOR Result, Intersection *Inter, TraceThreadData *Thread) const { VECTOR RU, RV; UV_VECT uv_vect; uv_vect[U] = Inter->Iuv[U]; uv_vect[V] = Inter->Iuv[V]; RU[X] = RV[X] = -Evaluate_Function_UV(Thread->functionContext, *(Function[X]), uv_vect); RU[Y] = RV[Y] = -Evaluate_Function_UV(Thread->functionContext, *(Function[Y]), uv_vect); RU[Z] = RV[Z] = -Evaluate_Function_UV(Thread->functionContext, *(Function[Z]), uv_vect); uv_vect[U] += accuracy; RU[X] += Evaluate_Function_UV(Thread->functionContext, *(Function[X]), uv_vect); RU[Y] += Evaluate_Function_UV(Thread->functionContext, *(Function[Y]), uv_vect); RU[Z] += Evaluate_Function_UV(Thread->functionContext, *(Function[Z]), uv_vect); uv_vect[U] = Inter->Iuv[U]; uv_vect[V] += accuracy; RV[X] += Evaluate_Function_UV(Thread->functionContext, *(Function[X]), uv_vect); RV[Y] += Evaluate_Function_UV(Thread->functionContext, *(Function[Y]), uv_vect); RV[Z] += Evaluate_Function_UV(Thread->functionContext, *(Function[Z]), uv_vect); VCross(Result, RU, RV); if (Trans != NULL) MTransNormal(Result, Result, Trans); VNormalize(Result, Result); }
void Compute_Axis_Rotation_Transform (TRANSFORM *transform, const VECTOR AxisVect, DBL angle) { DBL cosx, sinx; VECTOR V1; VNormalize(V1, AxisVect); MIdentity(transform->matrix); cosx = cos(angle); sinx = sin(angle); transform->matrix[0][0] = V1[X] * V1[X] + cosx * (1.0 - V1[X] * V1[X]); transform->matrix[0][1] = V1[X] * V1[Y] * (1.0 - cosx) + V1[Z] * sinx; transform->matrix[0][2] = V1[X] * V1[Z] * (1.0 - cosx) - V1[Y] * sinx; transform->matrix[1][0] = V1[X] * V1[Y] * (1.0 - cosx) - V1[Z] * sinx; transform->matrix[1][1] = V1[Y] * V1[Y] + cosx * (1.0 - V1[Y] * V1[Y]); transform->matrix[1][2] = V1[Y] * V1[Z] * (1.0 - cosx) + V1[X] * sinx; transform->matrix[2][0] = V1[X] * V1[Z] * (1.0 - cosx) + V1[Y] * sinx; transform->matrix[2][1] = V1[Y] * V1[Z] * (1.0 - cosx) - V1[X] * sinx; transform->matrix[2][2] = V1[Z] * V1[Z] + cosx * (1.0 - V1[Z] * V1[Z]); MTranspose(transform->inverse, transform->matrix); }
static void Smooth_Triangle_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Inter) { int Axis; DBL u, v; VECTOR PIMinusP1; SMOOTH_TRIANGLE *Triangle = (SMOOTH_TRIANGLE *)Object; VSub(PIMinusP1, Inter->IPoint, Triangle->P1); VDot(u, PIMinusP1, Triangle->Perp); if (u < EPSILON) { Assign_Vector(Result, Triangle->N1); return; } Axis = Triangle->vAxis; v = (PIMinusP1[Axis] / u + Triangle->P1[Axis] - Triangle->P2[Axis]) / (Triangle->P3[Axis] - Triangle->P2[Axis]); /* This is faster. [DB 8/94] */ Result[X] = Triangle->N1[X] + u * (Triangle->N2[X] - Triangle->N1[X] + v * (Triangle->N3[X] - Triangle->N2[X])); Result[Y] = Triangle->N1[Y] + u * (Triangle->N2[Y] - Triangle->N1[Y] + v * (Triangle->N3[Y] - Triangle->N2[Y])); Result[Z] = Triangle->N1[Z] + u * (Triangle->N2[Z] - Triangle->N1[Z] + v * (Triangle->N3[Z] - Triangle->N2[Z])); VNormalize(Result, Result); }
void Parametric_Normal(VECTOR Result, OBJECT* Object, INTERSECTION* Inter) { VECTOR RU, RV; PARAMETRIC * Par = (PARAMETRIC *)Object; VECTOR * IPoint = &(Inter->IPoint); UV_VECT uv_vect; uv_vect[U] = Par->last_u; uv_vect[V] = Par->last_v; RU[X] = RV[X] = -Evaluate_Function_UV(*(Par->Function[X]), uv_vect); RU[Y] = RV[Y] = -Evaluate_Function_UV(*(Par->Function[Y]), uv_vect); RU[Z] = RV[Z] = -Evaluate_Function_UV(*(Par->Function[Z]), uv_vect); uv_vect[U] += Par->accuracy; RU[X] += Evaluate_Function_UV(*(Par->Function[X]), uv_vect); RU[Y] += Evaluate_Function_UV(*(Par->Function[Y]), uv_vect); RU[Z] += Evaluate_Function_UV(*(Par->Function[Z]), uv_vect); uv_vect[U] = Par->last_u; uv_vect[V] += Par->accuracy; RV[X] += Evaluate_Function_UV(*(Par->Function[X]), uv_vect); RV[Y] += Evaluate_Function_UV(*(Par->Function[Y]), uv_vect); RV[Z] += Evaluate_Function_UV(*(Par->Function[Z]), uv_vect); VCross(Result, RU, RV); if (Par->Trans != NULL) MTransNormal(Result, Result, Par->Trans); VNormalize(Result, Result); }
static int compute_smooth_triangle(SMOOTH_TRIANGLE *Triangle) { VECTOR P3MinusP2, VTemp1, VTemp2; DBL x, y, z, uDenominator, Proj; VSub(P3MinusP2, Triangle->P3, Triangle->P2); x = fabs(P3MinusP2[X]); y = fabs(P3MinusP2[Y]); z = fabs(P3MinusP2[Z]); Triangle->vAxis = max3_coordinate(x, y, z); VSub(VTemp1, Triangle->P2, Triangle->P3); VNormalize(VTemp1, VTemp1); VSub(VTemp2, Triangle->P1, Triangle->P3); VDot(Proj, VTemp2, VTemp1); VScaleEq(VTemp1, Proj); VSub(Triangle->Perp, VTemp1, VTemp2); VNormalize(Triangle->Perp, Triangle->Perp); VDot(uDenominator, VTemp2, Triangle->Perp); VInverseScaleEq(Triangle->Perp, -uDenominator); /* Degenerate if smooth normals are more than 90 from actual normal or its inverse. */ VDot(x,Triangle->Normal_Vector,Triangle->N1); VDot(y,Triangle->Normal_Vector,Triangle->N2); VDot(z,Triangle->Normal_Vector,Triangle->N3); if ( ((x<0.0) && (y<0.0) && (z<0.0)) || ((x>0.0) && (y>0.0) && (z>0.0)) ) { return(true); } Set_Flag(Triangle, DEGENERATE_FLAG); return(false); }
static void Plane_Normal (VECTOR Result, OBJECT *Object, INTERSECTION *) { Assign_Vector(Result,((PLANE *)Object)->Normal_Vector); if (((PLANE *)Object)->Trans != NULL) { MTransNormal(Result, Result, ((PLANE *)Object)->Trans); VNormalize(Result, Result); } }
void Plane::Normal(VECTOR Result, Intersection *, TraceThreadData *) const { Assign_Vector(Result, Normal_Vector); if(Trans != NULL) { MTransNormal(Result, Result, Trans); VNormalize(Result, Result); } }
static void Transform_Disc (OBJECT *Object, TRANSFORM *Trans) { DISC *Disc = (DISC *)Object; MTransNormal(((DISC *)Object)->normal, ((DISC *)Object)->normal, Trans); VNormalize(((DISC *)Object)->normal, ((DISC *)Object)->normal); Compose_Transforms(Disc->Trans, Trans); /* Recalculate the bounds */ Compute_Disc_BBox(Disc); }
static void Cone_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Inter) { CONE *Cone = (CONE *)Object; /* Transform the point into the cones space */ MInvTransPoint(Result, Inter->IPoint, Cone->Trans); /* Calculating the normal is real simple in canonical cone space */ switch (Inter->i1) { case SIDE_HIT: if (Test_Flag(Cone, CYLINDER_FLAG)) { Result[Z] = 0.0; } else { Result[Z] = -Result[Z]; } break; case BASE_HIT: Make_Vector(Result, 0.0, 0.0, -1.0); break; case CAP_HIT: Make_Vector(Result, 0.0, 0.0, 1.0); break; } /* Transform the point out of the cones space */ MTransNormal(Result, Result, Cone->Trans); VNormalize(Result, Result); }
static void Box_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Inter) { switch (Inter->i1) { case SIDE_X_0: Make_Vector(Result, -1.0, 0.0, 0.0); break; case SIDE_X_1: Make_Vector(Result, 1.0, 0.0, 0.0); break; case SIDE_Y_0: Make_Vector(Result, 0.0, -1.0, 0.0); break; case SIDE_Y_1: Make_Vector(Result, 0.0, 1.0, 0.0); break; case SIDE_Z_0: Make_Vector(Result, 0.0, 0.0, -1.0); break; case SIDE_Z_1: Make_Vector(Result, 0.0, 0.0, 1.0); break; default: Error("Unknown box side in Box_Normal()."); } /* Transform the point into the boxes space. */ if (((BOX *)Object)->Trans != NULL) { MTransNormal(Result, Result, ((BOX *)Object)->Trans); VNormalize(Result, Result); } }
void Compute_Polygon(POLYGON *Polyg, int Number, VECTOR *Points) { int i; DBL x, y, z, d; VECTOR o, u, v, w, N; MATRIX a, b; /* Create polygon data. */ if (Polyg->Data == NULL) { Polyg->Data = (POLYGON_DATA *)POV_MALLOC(sizeof(POLYGON_DATA), "polygon points"); Polyg->Data->References = 1; Polyg->Data->Number = Number; Polyg->Data->Points = (UV_VECT *)POV_MALLOC(Number*sizeof(UV_VECT), "polygon points"); } else { Error("Polygon data already computed."); } /* Get polygon's coordinate system (one of the many possible) */ Assign_Vector(o, Points[0]); /* Find valid, i.e. non-zero u vector. */ for (i = 1; i < Number; i++) { VSub(u, Points[i], o); if (VSumSqr(u) > EPSILON) { break; } } if (i == Number) { Set_Flag(Polyg, DEGENERATE_FLAG); Warning(0, "Points in polygon are co-linear. Ignoring polygon."); } /* Find valid, i.e. non-zero v and w vectors. */ for (i++; i < Number; i++) { VSub(v, Points[i], o); VCross(w, u, v); if ((VSumSqr(v) > EPSILON) && (VSumSqr(w) > EPSILON)) { break; } } if (i == Number) { Set_Flag(Polyg, DEGENERATE_FLAG); Warning(0, "Points in polygon are co-linear. Ignoring polygon."); } VCross(u, v, w); VCross(v, w, u); VNormalize(u, u); VNormalize(v, v); VNormalize(w, w); MIdentity(a); MIdentity(b); a[3][0] = -o[X]; a[3][1] = -o[Y]; a[3][2] = -o[Z]; b[0][0] = u[X]; b[1][0] = u[Y]; b[2][0] = u[Z]; b[0][1] = v[X]; b[1][1] = v[Y]; b[2][1] = v[Z]; b[0][2] = w[X]; b[1][2] = w[Y]; b[2][2] = w[Z]; MTimesC(Polyg->Trans->inverse, a, b); MInvers(Polyg->Trans->matrix, Polyg->Trans->inverse); /* Project points onto the u,v-plane (3D --> 2D) */ for (i = 0; i < Number; i++) { x = Points[i][X] - o[X]; y = Points[i][Y] - o[Y]; z = Points[i][Z] - o[Z]; d = x * w[X] + y * w[Y] + z * w[Z]; if (fabs(d) > ZERO_TOLERANCE) { Set_Flag(Polyg, DEGENERATE_FLAG); Warning(0, "Points in polygon are not co-planar. Ignoring polygons."); } Polyg->Data->Points[i][X] = x * u[X] + y * u[Y] + z * u[Z]; Polyg->Data->Points[i][Y] = x * v[X] + y * v[Y] + z * v[Z]; } Make_Vector(N, 0.0, 0.0, 1.0); MTransNormal(Polyg->S_Normal, N, Polyg->Trans); VNormalizeEq(Polyg->S_Normal); Compute_Polygon_BBox(Polyg); }
static void facets (const VECTOR EPoint, const TNORMAL *Tnormal, VECTOR normal, TraceThreadData *Thread) { int i; int thisseed; DBL sum, minsum; VECTOR sv, tv, dv, t1, add, newnormal, pert; DBL scale; int UseSquare; int UseUnity; DBL Metric; VECTOR *cv = Thread->Facets_Cube; Metric = Tnormal->Vals.Facets.Metric; UseSquare = (Metric == 2 ); UseUnity = (Metric == 1 ); VNormalize( normal, normal ); if ( Tnormal->Vals.Facets.UseCoords ) { Assign_Vector(tv,EPoint); } else { Assign_Vector(tv,normal); } if ( Tnormal->Vals.Facets.Size < 1e-6 ) { scale = 1e6; } else { scale = 1. / Tnormal->Vals.Facets.Size; } VScaleEq( tv, scale ); /* * Check to see if the input point is in the same unit cube as the last * call to this function, to use cache of cubelets for speed. */ thisseed = PickInCube(tv, t1); if (thisseed != Thread->Facets_Last_Seed) { /* * No, not same unit cube. Calculate the random points for this new * cube and its 80 neighbours which differ in any axis by 1 or 2. * Why distance of 2? If there is 1 point in each cube, located * randomly, it is possible for the closest random point to be in the * cube 2 over, or the one two over and one up. It is NOT possible * for it to be two over and two up. Picture a 3x3x3 cube with 9 more * cubes glued onto each face. */ /* Now store a points for this cube and each of the 80 neighbour cubes. */ int cvc = 0; for (add[X] = -2.0; add[X] < 2.5; add[X] +=1.0) { for (add[Y] = -2.0; add[Y] < 2.5; add[Y] += 1.0) { for (add[Z] = -2.0; add[Z] < 2.5; add[Z] += 1.0) { /* For each cubelet in a 5x5 cube. */ if ((fabs(add[X])>1.5)+(fabs(add[Y])>1.5)+(fabs(add[Z])>1.5) <= 1.0) { /* Yes, it's within a 3d knight move away. */ VAdd(sv, tv, add); PickInCube(sv, t1); cv[cvc][X] = t1[X]; cv[cvc][Y] = t1[Y]; cv[cvc][Z] = t1[Z]; cvc++; } } } } Thread->Facets_Last_Seed = thisseed; Thread->Facets_CVC = cvc; } /* * Find the point with the shortest distance from the input point. */ VSub(dv, cv[0], tv); if ( UseSquare ) { minsum = VSumSqr(dv); } else if ( UseUnity ) { minsum = dv[X]+dv[Y]+dv[Z]; } else { minsum = pow(fabs(dv[X]), Metric)+ pow(fabs(dv[Y]), Metric)+ pow(fabs(dv[Z]), Metric); } Assign_Vector( newnormal, cv[0] ); /* Loop for the 81 cubelets to find closest. */ for (i = 1; i < Thread->Facets_CVC; i++) { VSub(dv, cv[i], tv); if ( UseSquare ) { sum = VSumSqr(dv); } else { if ( UseUnity ) { sum = dv[X]+dv[Y]+dv[Z]; } else { sum = pow(fabs(dv[X]), Metric)+ pow(fabs(dv[Y]), Metric)+ pow(fabs(dv[Z]), Metric); } } if (sum < minsum) { minsum = sum; Assign_Vector( newnormal, cv[i] ); } } if ( Tnormal->Vals.Facets.UseCoords ) { DNoise( pert, newnormal ); VDot( sum, pert, normal ); VScale( newnormal, normal, sum ); VSubEq( pert, newnormal ); VAddScaledEq( normal, Tnormal->Vals.Facets.UseCoords, pert ); } else { Assign_Vector( normal, newnormal ); } }
void bump_map(VECTOR EPoint, TNORMAL *Tnormal, VECTOR normal) { DBL xcoor = 0.0, ycoor = 0.0; int index, index2, index3; COLOUR colour1, colour2, colour3; VECTOR p1, p2, p3; VECTOR bump_normal; VECTOR xprime, yprime, zprime, Temp; DBL Length; DBL Amount = Tnormal->Amount; IMAGE *Image = Tnormal->Vals.Image; Make_ColourA(colour1, 0.0, 0.0, 0.0, 0.0, 0.0); Make_ColourA(colour2, 0.0, 0.0, 0.0, 0.0, 0.0); Make_ColourA(colour3, 0.0, 0.0, 0.0, 0.0, 0.0); /* going to have to change this */ /* need to know if bump point is off of image for all 3 points */ if (map(EPoint, (TPATTERN *) Tnormal, &xcoor, &ycoor)) { return; } else { image_colour_at(Image, xcoor, ycoor, colour1, &index); } xcoor--; ycoor++; if (xcoor < 0.0) { xcoor += (DBL)Image->iwidth; } else { if (xcoor >= Image->iwidth) { xcoor -= (DBL)Image->iwidth; } } if (ycoor < 0.0) { ycoor += (DBL)Image->iheight; } else { if (ycoor >= (DBL)Image->iheight) { ycoor -= (DBL)Image->iheight; } } image_colour_at(Image, xcoor, ycoor, colour2, &index2); xcoor += 2.0; if (xcoor < 0.0) { xcoor += (DBL)Image->iwidth; } else { if (xcoor >= Image->iwidth) { xcoor -= (DBL)Image->iwidth; } } image_colour_at(Image, xcoor, ycoor, colour3, &index3); if (Image->Colour_Map == NULL || Image->Use_Colour_Flag) { p1[X] = 0; p1[Y] = Amount * (GREY_SCALE( colour1 )); p1[Z] = 0; p2[X] = -1; p2[Y] = Amount * (GREY_SCALE( colour2 )); p2[Z] = 1; p3[X] = 1; p3[Y] = Amount * (GREY_SCALE( colour3 )); p3[Z] = 1; } else { p1[X] = 0; p1[Y] = Amount * index; p1[Z] = 0; p2[X] = -1; p2[Y] = Amount * index2; p2[Z] = 1; p3[X] = 1; p3[Y] = Amount * index3; p3[Z] = 1; } /* we have points 1,2,3 for a triangle now we need the surface normal for it */ VSub(xprime, p1, p2); VSub(yprime, p3, p2); VCross(bump_normal, yprime, xprime); VNormalize(bump_normal, bump_normal); Assign_Vector(yprime, normal); Make_Vector(Temp, 0.0, 1.0, 0.0); VCross(xprime, yprime, Temp); VLength(Length, xprime); if (Length < EPSILON) { if (fabs(normal[Y] - 1.0) < Small_Tolerance) { Make_Vector(yprime, 0.0, 1.0, 0.0); Make_Vector(xprime, 1.0, 0.0, 0.0); Length = 1.0; } else { Make_Vector(yprime, 0.0, -1.0, 0.0); Make_Vector(xprime, 1.0, 0.0, 0.0); Length = 1.0; } } VScaleEq(xprime, 1.0 / Length); VCross(zprime, xprime, yprime); VNormalizeEq(zprime); VScaleEq(xprime, bump_normal[X]); VScaleEq(yprime, bump_normal[Y]); VScaleEq(zprime, bump_normal[Z]); VAdd(Temp, xprime, yprime); VScaleEq(zprime, -1); VAdd(normal, Temp, zprime); }
static void IsoSurface_Normal(VECTOR Result, OBJECT* Object, INTERSECTION* Inter) { VECTOR New_Point, TPoint; ISOSURFACE *Isosrf = (ISOSURFACE *)Object; FUNCTION Function = *(((ISOSURFACE *)Object)->Function); DBL funct; switch (Inter->i1) { case SIDE_X_0: Make_Vector(Result, -1.0, 0.0, 0.0); break; case SIDE_X_1: Make_Vector(Result, 1.0, 0.0, 0.0); break; case SIDE_Y_0: Make_Vector(Result, 0.0, -1.0, 0.0); break; case SIDE_Y_1: Make_Vector(Result, 0.0, 1.0, 0.0); break; case SIDE_Z_0: Make_Vector(Result, 0.0, 0.0, -1.0); break; case SIDE_Z_1: Make_Vector(Result, 0.0, 0.0, 1.0); break; default: /* Transform the point into the isosurface space */ if(((ISOSURFACE *)Object)->Trans != NULL) MInvTransPoint(New_Point, Inter->IPoint, Isosrf->Trans); else Assign_Vector(New_Point, Inter->IPoint); if(Isosrf->container_shape) { VSub(Result, New_Point, Isosrf->container.sphere.center); VLength(funct, Result); if(fabs(funct - Isosrf->container.sphere.radius) < EPSILON) { VInverseScaleEq(Result, Isosrf->container.sphere.radius); break; } } Assign_Vector(TPoint, New_Point); funct = Evaluate_Function(Function, TPoint); Assign_Vector(TPoint, New_Point); TPoint[X] += Isosrf->accuracy; Result[X] = Evaluate_Function(Function, TPoint) - funct; Assign_Vector(TPoint, New_Point); TPoint[Y] += Isosrf->accuracy; Result[Y] = Evaluate_Function(Function, TPoint) - funct; Assign_Vector(TPoint, New_Point); TPoint[Z] += Isosrf->accuracy; Result[Z] = Evaluate_Function(Function, TPoint) - funct; if((Result[X] == 0) && (Result[Y] == 0) && (Result[Z] == 0)) Result[X] = 1.0; VNormalize(Result, Result); } /* Transform the point into the boxes space. */ if(((ISOSURFACE *)Object)->Trans != NULL) { MTransNormal(Result, Result, ((ISOSURFACE *)Object)->Trans); VNormalize(Result, Result); } }