static int subpatch_normal(VECTOR v1, VECTOR v2, VECTOR v3, VECTOR Result, DBL *d) { VECTOR V1, V2; DBL squared_v1, squared_v2; DBL Length; VSub(V1, v1, v2); VSub(V2, v3, v2); VCross(Result, V1, V2); Length = VSumSqr(Result); squared_v1 = VSumSqr(V1); squared_v2 = VSumSqr(V2); if (Length <= (BEZIER_EPSILON * squared_v1 * squared_v2)) { Make_Vector(Result, 1.0, 0.0, 0.0); *d = -1.0 * v1[X]; return (0); } else { Length = sqrt(Length); VInverseScale(Result, Result, Length); VDot(*d, Result, v1); *d = 0.0 - *d; return (1); } }
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 ); } }
int Torus::Intersect(const Ray& ray, DBL *Depth, SceneThreadData *Thread) const { int i, n; DBL len, R2, Py2, Dy2, PDy2, k1, k2; DBL y1, y2, r1, r2; DBL c[5]; DBL r[4]; VECTOR P, D; DBL DistanceP; // Distance from P to torus center (origo). DBL BoundingSphereRadius; // Sphere fully (amply) enclosing torus. DBL Closer; // P is moved Closer*D closer to torus. Thread->Stats()[Ray_Torus_Tests]++; /* Transform the ray into the torus space. */ MInvTransPoint(P, ray.Origin, Trans); MInvTransDirection(D, ray.Direction, Trans); VLength(len, D); VInverseScaleEq(D, len); i = 0; y1 = -MinorRadius; y2 = MinorRadius; r1 = Sqr(MajorRadius - MinorRadius); if ( MajorRadius < MinorRadius ) r1 = 0; r2 = Sqr(MajorRadius + MinorRadius); #ifdef TORUS_EXTRA_STATS Thread->Stats()[Torus_Bound_Tests]++; #endif if (Test_Thick_Cylinder(P, D, y1, y2, r1, r2)) { #ifdef TORUS_EXTRA_STATS Thread->Stats()[Torus_Bound_Tests_Succeeded]++; #endif // Move P close to bounding sphere to have more precise root calculation. // Bounding sphere radius is R + r, we add r once more to ensure // that P is safely outside sphere. BoundingSphereRadius = MajorRadius + MinorRadius + MinorRadius; DistanceP = VSumSqr(P); // Distance is currently squared. Closer = 0.0; if (DistanceP > Sqr(BoundingSphereRadius)) { DistanceP = sqrt(DistanceP); // Now real distance. Closer = DistanceP - BoundingSphereRadius; VAddScaledEq(P, Closer, D); } R2 = Sqr(MajorRadius); r2 = Sqr(MinorRadius); Py2 = P[Y] * P[Y]; Dy2 = D[Y] * D[Y]; PDy2 = P[Y] * D[Y]; k1 = P[X] * P[X] + P[Z] * P[Z] + Py2 - R2 - r2; k2 = P[X] * D[X] + P[Z] * D[Z] + PDy2; c[0] = 1.0; c[1] = 4.0 * k2; c[2] = 2.0 * (k1 + 2.0 * (k2 * k2 + R2 * Dy2)); c[3] = 4.0 * (k2 * k1 + 2.0 * R2 * PDy2); c[4] = k1 * k1 + 4.0 * R2 * (Py2 - r2); n = Solve_Polynomial(4, c, r, Test_Flag(this, STURM_FLAG), ROOT_TOLERANCE, Thread); while(n--) Depth[i++] = (r[n] + Closer) / len; } if (i) Thread->Stats()[Ray_Torus_Tests_Succeeded]++; return(i); }
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 int intersect_subpatch(BICUBIC_PATCH *Shape, RAY *ray, VECTOR V1[3], DBL uu[3], DBL vv[3], DBL *Depth, VECTOR P, VECTOR N, DBL *u, DBL *v) { DBL squared_b0, squared_b1; DBL d, n, a, b, r; VECTOR Q, T1; VECTOR B[3], IB[3], NN[3]; VSub(B[0], V1[1], V1[0]); VSub(B[1], V1[2], V1[0]); VCross(B[2], B[0], B[1]); VDot(d, B[2], B[2]); squared_b0 = VSumSqr(B[0]); squared_b1 = VSumSqr(B[1]); if (d <= (BEZIER_EPSILON * squared_b1 * squared_b0)) { return (0); } d = 1.0 / sqrt(d); VScaleEq(B[2], d); /* Degenerate triangle. */ if (!MInvers3(B, IB)) { return (0); } VDot(d, ray->Direction, IB[2]); if (fabs(d) < BEZIER_EPSILON) { return (0); } VSub(Q, V1[0], ray->Initial); VDot(n, Q, IB[2]); *Depth = n / d; if (*Depth < BEZIER_TOLERANCE) { return (0); } VScale(T1, ray->Direction, *Depth); VAdd(P, ray->Initial, T1); VSub(Q, P, V1[0]); VDot(a, Q, IB[0]); VDot(b, Q, IB[1]); if ((a < 0.0) || (b < 0.0) || (a + b > 1.0)) { return (0); } r = 1.0 - a - b; Make_Vector(N, 0.0, 0.0, 0.0); bezier_value((VECTOR(*)[4][4])&Shape->Control_Points, uu[0], vv[0], T1, NN[0]); bezier_value((VECTOR(*)[4][4])&Shape->Control_Points, uu[1], vv[1], T1, NN[1]); bezier_value((VECTOR(*)[4][4])&Shape->Control_Points, uu[2], vv[2], T1, NN[2]); VScale(T1, NN[0], r); VAddEq(N, T1); VScale(T1, NN[1], a); VAddEq(N, T1); VScale(T1, NN[2], b); VAddEq(N, T1); *u = r * uu[0] + a * uu[1] + b * uu[2]; *v = r * vv[0] + a * vv[1] + b * vv[2]; VDot(d, N, N); if (d > BEZIER_EPSILON) { d = 1.0 / sqrt(d); VScaleEq(N, d); } else { Make_Vector(N, 1, 0, 0); } return (1); }
static void bezier_value(VECTOR (*Control_Points)[4][4], DBL u0, DBL v0, VECTOR P, VECTOR N) { const DBL C[] = { 1.0, 3.0, 3.0, 1.0 }; int i, j; DBL c, t, ut, vt; DBL u[4], uu[4], v[4], vv[4]; DBL du[4], duu[4], dv[4], dvv[4]; DBL squared_u1, squared_v1; VECTOR U1, V1; /* Calculate binomial coefficients times coordinate positions. */ u[0] = 1.0; uu[0] = 1.0; du[0] = 0.0; duu[0] = 0.0; v[0] = 1.0; vv[0] = 1.0; dv[0] = 0.0; dvv[0] = 0.0; for (i = 1; i < 4; i++) { u[i] = u[i - 1] * u0; uu[i] = uu[i - 1] * (1.0 - u0); v[i] = v[i - 1] * v0; vv[i] = vv[i - 1] * (1.0 - v0); du[i] = i * u[i - 1]; duu[i] = -i * uu[i - 1]; dv[i] = i * v[i - 1]; dvv[i] = -i * vv[i - 1]; } /* Now evaluate position and tangents based on control points. */ Make_Vector(P, 0, 0, 0); Make_Vector(U1, 0, 0, 0); Make_Vector(V1, 0, 0, 0); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { c = C[i] * C[j]; ut = u[i] * uu[3 - i]; vt = v[j] * vv[3 - j]; t = c * ut * vt; VAddScaledEq(P, t, (*Control_Points)[i][j]); t = c * vt * (du[i] * uu[3 - i] + u[i] * duu[3 - i]); VAddScaledEq(U1, t, (*Control_Points)[i][j]); t = c * ut * (dv[j] * vv[3 - j] + v[j] * dvv[3 - j]); VAddScaledEq(V1, t, (*Control_Points)[i][j]); } } /* Make the normal from the cross product of the tangents. */ VCross(N, U1, V1); VDot(t, N, N); squared_u1 = VSumSqr(U1); squared_v1 = VSumSqr(V1); if (t > (BEZIER_EPSILON * squared_u1 * squared_v1)) { t = 1.0 / sqrt(t); VScaleEq(N, t); } else { Make_Vector(N, 1, 0, 0); } }