Exemple #1
0
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);
  }
}
Exemple #2
0
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 );
	}
}
Exemple #3
0
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);
}
Exemple #4
0
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);
}
Exemple #5
0
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);
}
Exemple #6
0
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);
  }
}