示例#1
0
        /// <inheritdoc />
        public override Vector3 GetNormalAt(Vector2 uv)
        {
            float u = uv.X;
            float v = uv.Y;

            Vector3 curveTangent  = Vector3.Normalize(CenterCurve.GetTangentAt(v));
            Vector3 curveNormal   = Vector3.Normalize(CenterCurve.GetNormalAt(v));
            Vector3 curveBinormal = Vector3.Cross(curveTangent, curveNormal);

            float startAngle = StartAngle.GetValueAt(v);
            float endAngle   = EndAngle.GetValueAt(v);

            return((float)Math.Cos(u) * curveNormal + (float)Math.Sin(u) * curveBinormal);
        }
示例#2
0
        /// <inheritdoc />
        public override dvec3 GetNormalAt(dvec2 uv)
        {
            DebugUtil.AssertAllFinite(uv, nameof(uv));
            double u = uv.x;
            double v = uv.y;

            dvec3 curveTangent  = CenterCurve.GetTangentAt(v).Normalized;
            dvec3 curveNormal   = CenterCurve.GetNormalAt(v).Normalized;
            dvec3 curveBinormal = dvec3.Cross(curveTangent, curveNormal);

            double startAngle = StartAngle.GetValueAt(v);
            double endAngle   = EndAngle.GetValueAt(v);

            return(Math.Cos(u) * curveNormal + Math.Sin(u) * curveBinormal);
        }
示例#3
0
        /// <inheritdoc />
        public override List <Vertex> GenerateVertexList(int resolutionU, int resolutionV)
        {
            // If asked to sample at zero points, return an empty list.
            if (resolutionU <= 0 || resolutionV <= 0)
            {
                return(new List <Vertex>());
            }
            var roughs = ParallelEnumerable.Range(0, resolutionV + 1).AsOrdered().SelectMany((j =>
            {
                double v = (double)j / (double)resolutionV;

                // Find the values at each ring:
                dvec3 curveTangent = CenterCurve.GetTangentAt(v).Normalized;
                dvec3 curveNormal = CenterCurve.GetNormalAt(v).Normalized;
                dvec3 curveBinormal = dvec3.Cross(curveTangent, curveNormal);

                dvec3 translation = CenterCurve.GetPositionAt(v);

                double startAngle = StartAngle.GetValueAt(v);
                double endAngle = EndAngle.GetValueAt(v);

                return(Enumerable.Range(0, resolutionU).Select((i) =>
                {
                    double u = startAngle + (endAngle - startAngle) * (double)i / (double)resolutionU;

                    double radius = Radius.GetValueAt(new dvec2(u, v));

                    // Calculate the position of the rings of vertices:
                    dvec3 surfaceNormal = (double)Math.Cos(u) * curveNormal + (double)Math.Sin(u) * curveBinormal;
                    dvec3 surfacePosition = translation + radius * surfaceNormal;
                    return new Vertex((vec3)surfacePosition, (vec3)surfaceNormal);
                }));
            }));

            List <Vertex> output = roughs.ToList();

            // Recalculate the surface normal after deformation:
            for (int j = 1; j < resolutionV; j++)
            {
                for (int i = 0; i < (resolutionU - 1); i++)
                {
                    dvec3 surfacePosition = output[(j - 1) * resolutionU + i].Position;
                    dvec3 du = surfacePosition - output[(j - 1) * resolutionU + i + 1].Position;
                    dvec3 dv = surfacePosition - output[(j) * resolutionU + i].Position;

                    // Calculate the position of the rings of vertices:
                    dvec3 surfaceNormal = dvec3.Cross(du.Normalized, dv.Normalized);

                    output[(j - 1) * resolutionU + i] = new Vertex((vec3)surfacePosition, (vec3)surfaceNormal);
                }

                // Stitch the end of the triangles:
                dvec3 surfacePosition2 = output[(j - 1) * resolutionU + resolutionU - 1].Position;
                dvec3 du2 = surfacePosition2 - output[(j - 1) * resolutionU].Position;
                dvec3 dv2 = surfacePosition2 - output[(j) * resolutionU + resolutionU - 1].Position;

                // Calculate the position of the rings of vertices:
                dvec3 surfaceNormal2 = dvec3.Cross(du2.Normalized, dv2.Normalized);

                output[(j - 1) * resolutionU + resolutionU - 1] = new Vertex((vec3)surfacePosition2, (vec3)surfaceNormal2);
            }

            return(output);
        }
示例#4
0
        /// <inheritdoc />
        public float RayIntersect(Ray ray)
        {
            Vector3 rayStart     = ray.StartPosition;
            Vector3 rayDirection = ray.Direction;

            // Since we raytrace only using a cylindrical surface that is horizontal and at the origin, we
            // first shift and rotate the ray such that we get the right orientation:
            Vector3 start = CenterCurve.GetStartPosition();
            Vector3 end   = CenterCurve.GetEndPosition();

            Vector3 tangent  = Vector3.Normalize(CenterCurve.GetTangentAt(0.0f));
            Vector3 normal   = Vector3.Normalize(CenterCurve.GetNormalAt(0.0f));
            Vector3 binormal = Vector3.Normalize(CenterCurve.GetBinormalAt(0.0f));

            float length = Vector3.Distance(start, end);

            // CenterCurve is guaranteed to be a LineSegment, since the base property CenterCurve is masked by this
            // class' CenterCurve property that only accepts a LineSegment, and similarly this class' constructor only
            // accepts a LineSegment. The following mathematics, which assumes that the central axis is a line segment,
            // is therefore valid.

            Matrix4x4 rotationMatrix = new Matrix4x4(normal.X, binormal.X, tangent.X / length, 0.0f,
                                                     normal.Y, binormal.Y, tangent.Y / length, 0.0f,
                                                     normal.Z, binormal.Z, tangent.Z / length, 0.0f,
                                                     0.0f, 0.0f, 0.0f, 1.0f);

            Vector3 rescaledRay  = Vector3.Transform(rayStart - start, rotationMatrix);
            Vector3 newDirection = Vector3.TransformNormal(Vector3.Normalize(rayDirection), rotationMatrix);


            float x0 = rescaledRay.X;
            float y0 = rescaledRay.Y;
            float z0 = rescaledRay.Z;

            float a = newDirection.X;
            float b = newDirection.Y;
            float c = newDirection.Z;

            // Raytrace using a cylindrical surface equation x^2 + y^2. The parameters in the following line
            // represent the coefficients of the expanded cylindrical surface equation, after the substitution
            // x = x_0 + a t and y = y_0 + b t:
            QuarticFunction surfaceFunction = new QuarticFunction(x0 * x0 + y0 * y0, 2.0f * (x0 * a + y0 * b), a * a + b * b, 0.0f, 0.0f);

            IEnumerable <float> intersections = Radius.SolveRaytrace(surfaceFunction, z0, c);

            // The previous function returns a list of intersection distances. The value closest to 0.0f represents the
            // closest intersection point.
            float minimum = Single.PositiveInfinity;

            foreach (float i in intersections)
            {
                // Calculate the 3d point at which the ray intersects the cylinder:
                Vector3 intersectionPoint = rayStart + i * rayDirection;

                // Find the closest point to the intersectionPoint on the centerLine.
                // Get the vector v from the start of the cylinder to the intersection point:
                Vector3 v = intersectionPoint - start;

                // ...And project this vector onto the center line:
                float t = -Vector3.Dot(intersectionPoint, tangent * length) / (length * length);

                // Now we have the parameter t on the surface of the SymmetricCylinder at which the ray intersects.

                // Find the angle to the normal of the centerLine, so that we can determine whether the
                // angle is within the bound of the pie-slice at position t:
                Vector3 centerLineNormal   = CenterCurve.GetNormalAt(t);
                Vector3 centerLineBinormal = CenterCurve.GetBinormalAt(t);
                Vector3 d = intersectionPoint - CenterCurve.GetPositionAt(t);
                float   correctionShift = (float)Math.Sign(Vector3.Dot(d, centerLineBinormal));
                float   phi             = (correctionShift * (float)Math.Acos(Vector3.Dot(d, centerLineNormal))) % (2.0f * (float)Math.PI);

                // Determine if the ray is inside the pie-slice of the cylinder that is being displayed,
                // otherwise discard:
                if (phi > StartAngle.GetValueAt(t) && phi < EndAngle.GetValueAt(t) && i >= 0.0f)
                {
                    minimum = Math.Sign(i) * (float)Math.Min(Math.Abs(minimum), Math.Abs(i));
                }
            }

            return(minimum);
        }
示例#5
0
        /// <inheritdoc />
        public double RayIntersect(Ray ray)
        {
            dvec3 rayStart     = ray.StartPosition;
            dvec3 rayDirection = ray.Direction;

            DebugUtil.AssertAllFinite(rayStart, nameof(rayStart));
            DebugUtil.AssertAllFinite(rayDirection, nameof(rayDirection));

            // Since we raytrace only using a cylindrical surface that is horizontal and at the origin, we
            // first shift and rotate the ray such that we get the right orientation:
            dvec3 start = CenterCurve.GetStartPosition();
            dvec3 end   = CenterCurve.GetEndPosition();

            DebugUtil.AssertAllFinite(start, nameof(start));
            DebugUtil.AssertAllFinite(end, nameof(end));

            dvec3 tangent  = CenterCurve.GetTangentAt(0.0).Normalized;
            dvec3 normal   = CenterCurve.GetNormalAt(0.0).Normalized;
            dvec3 binormal = CenterCurve.GetBinormalAt(0.0).Normalized;

            DebugUtil.AssertAllFinite(tangent, nameof(tangent));
            DebugUtil.AssertAllFinite(normal, nameof(normal));
            DebugUtil.AssertAllFinite(binormal, nameof(binormal));

            double length = dvec3.Distance(start, end);

            DebugUtil.AssertFinite(length, nameof(length));

            // CenterCurve is guaranteed to be a LineSegment, since the base property CenterCurve is masked by this
            // class' CenterCurve property that only accepts a LineSegment, and similarly this class' constructor only
            // accepts a LineSegment. The following mathematics, which assumes that the central axis is a line segment,
            // is therefore valid.

            dmat3 rotationMatrix = new dmat3(normal, binormal, tangent / length).Transposed;

            dvec3 rescaledRay  = rotationMatrix * (rayStart - start);
            dvec3 newDirection = rotationMatrix * rayDirection.Normalized;


            double x0 = rescaledRay.x;
            double y0 = rescaledRay.y;
            double z0 = rescaledRay.z;

            double a = newDirection.x;
            double b = newDirection.y;
            double c = newDirection.z;

            // Raytrace using a cylindrical surface equation x^2 + y^2. The parameters in the following line
            // represent the coefficients of the expanded cylindrical surface equation, after the substitution
            // x = x_0 + a t and y = y_0 + b t:
            QuarticFunction surfaceFunction = new QuarticFunction(x0 * x0 + y0 * y0, 2.0 * (x0 * a + y0 * b), a * a + b * b, 0.0, 0.0);

            IEnumerable <double> intersections = Radius.SolveRaytrace(surfaceFunction, z0, c);

            // The previous function returns a list of intersection distances. The value closest to 0.0f represents the
            // closest intersection point.
            double minimum = Single.PositiveInfinity;

            foreach (double i in intersections)
            {
                // Calculate the 3d point at which the ray intersects the cylinder:
                dvec3 intersectionPoint = rayStart + i * rayDirection;

                // Find the closest point to the intersectionPoint on the centerLine.
                // Get the vector v from the start of the cylinder to the intersection point:
                dvec3 v = intersectionPoint - start;

                // ...And project this vector onto the center line:
                double t = -dvec3.Dot(intersectionPoint, tangent * length) / (length * length);

                // Now we have the parameter t on the surface of the SymmetricCylinder at which the ray intersects.

                // Find the angle to the normal of the centerLine, so that we can determine whether the
                // angle is within the bound of the pie-slice at position t:
                dvec3  centerLineNormal   = CenterCurve.GetNormalAt(t);
                dvec3  centerLineBinormal = CenterCurve.GetBinormalAt(t);
                dvec3  d = intersectionPoint - CenterCurve.GetPositionAt(t);
                double correctionShift = Math.Sign(dvec3.Dot(d, centerLineBinormal));
                double phi             = (correctionShift * Math.Acos(dvec3.Dot(d, centerLineNormal))) % (2.0 * Math.PI);

                // Determine if the ray is inside the pie-slice of the cylinder that is being displayed,
                // otherwise discard:
                if (phi > StartAngle.GetValueAt(t) && phi < EndAngle.GetValueAt(t) && i >= 0.0)
                {
                    minimum = Math.Sign(i) * Math.Min(Math.Abs(minimum), Math.Abs(i));
                }
            }

            return(minimum);
        }
示例#6
0
        /// <inheritdoc />
        public override List <Vertex> GenerateVertexList(int resolutionU, int resolutionV)
        {
            List <Vertex> output = new List <Vertex>(CalculateVertexCount(resolutionU, resolutionV));

            for (int j = 0; j < (resolutionV + 1); j++)
            {
                float v = (float)j / (float)resolutionV;

                // Find the values at each ring:
                Vector3 curveTangent  = Vector3.Normalize(CenterCurve.GetTangentAt(v));
                Vector3 curveNormal   = Vector3.Normalize(CenterCurve.GetNormalAt(v));
                Vector3 curveBinormal = Vector3.Cross(curveTangent, curveNormal);

                Vector3 translation = CenterCurve.GetPositionAt(v);

                float startAngle = StartAngle.GetValueAt(v);
                float endAngle   = EndAngle.GetValueAt(v);

                for (int i = 0; i < resolutionU; i++)
                {
                    // First find the normalized uv-coordinates, u = [0, 2pi], v = [0, 1]:
                    float u = startAngle + (endAngle - startAngle) * (float)i / (float)resolutionU;

                    float radius = Radius.GetValueAt(new Vector2(u, v));

                    // Calculate the position of the rings of vertices:
                    Vector3 surfaceNormal   = (float)Math.Cos(u) * curveNormal + (float)Math.Sin(u) * curveBinormal;
                    Vector3 surfacePosition = translation + radius * surfaceNormal;

                    output.Add(new Vertex(surfacePosition, surfaceNormal));
                }
            }

            // Recalculate the surface normal after deformation:
            for (int j = 1; j < resolutionV; j++)
            {
                for (int i = 0; i < (resolutionU - 1); i++)
                {
                    Vector3 surfacePosition = output[(j - 1) * resolutionU + i].Position;
                    Vector3 du = surfacePosition - output[(j - 1) * resolutionU + i + 1].Position;
                    Vector3 dv = surfacePosition - output[(j) * resolutionU + i].Position;

                    // Calculate the position of the rings of vertices:
                    Vector3 surfaceNormal = Vector3.Cross(Vector3.Normalize(du), Vector3.Normalize(dv));

                    output[(j - 1) * resolutionU + i] = new Vertex(surfacePosition, surfaceNormal);
                }

                // Stitch the end of the triangles:
                Vector3 surfacePosition2 = output[(j - 1) * resolutionU + resolutionU - 1].Position;
                Vector3 du2 = surfacePosition2 - output[(j - 1) * resolutionU].Position;
                Vector3 dv2 = surfacePosition2 - output[(j) * resolutionU + resolutionU - 1].Position;

                // Calculate the position of the rings of vertices:
                Vector3 surfaceNormal2 = Vector3.Cross(Vector3.Normalize(du2), Vector3.Normalize(dv2));

                output[(j - 1) * resolutionU + resolutionU - 1] = new Vertex(surfacePosition2, surfaceNormal2);
            }

            return(output);
        }