Example #1
0
    public ArraySegment Add(ImporterOcclusionSurrogate surrogate)
    {
        int dummyVertexCount = surrogate.SampleCount;
        var dummyMesh        = new SubdivisionMesh(
            0,
            new QuadTopology(dummyVertexCount, new Quad[0]),
            PackedLists <WeightedIndexWithDerivatives> .MakeEmptyLists(dummyVertexCount));
        var dummyFaceTransparencies = new float[0];

        var segment = Add(dummyMesh, dummyFaceTransparencies);

        //apply mask
        int  maskIdx = nextMaskIdx++;
        uint mask    = 1u << maskIdx;

        for (int i = 0; i < segment.Count; ++i)
        {
            int vertexIdx = i + segment.Offset;
            vertexMasks[vertexIdx] |= mask;
        }
        foreach (int faceIdx in surrogate.AttachedFaces)
        {
            faceMasks[faceIdx] |= mask;
        }

        return(segment);
    }
Example #2
0
    public FigureRenderer Load(IArchiveDirectory figureDir, MaterialSetAndVariantOption materialSetOption)
    {
        SurfaceProperties surfaceProperties = Persistance.Load <SurfaceProperties>(figureDir.File("surface-properties.dat"));

        var refinementDirectory = figureDir.Subdirectory("refinement");

        var controlMeshDirectory = refinementDirectory.Subdirectory("control");

        int[] surfaceMap = controlMeshDirectory.File("surface-map.array").ReadArray <int>();

        var             refinedMeshDirectory = refinementDirectory.Subdirectory("level-" + surfaceProperties.SubdivisionLevel);
        SubdivisionMesh mesh = SubdivisionMeshPersistance.Load(refinedMeshDirectory);

        int[] controlFaceMap = refinedMeshDirectory.File("control-face-map.array").ReadArray <int>();

        var materialSet = MaterialSet.LoadActive(device, shaderCache, textureCache, dataDir, figureDir, materialSetOption, surfaceProperties);
        var materials   = materialSet.Materials;

        Scatterer scatterer = surfaceProperties.PrecomputeScattering ? Scatterer.Load(device, shaderCache, figureDir, materialSetOption.MaterialSet.Label) : null;

        var uvSetName = materials[0].UvSet;
        IArchiveDirectory uvSetDirectory = figureDir.Subdirectory("uv-sets").Subdirectory(uvSetName);

        var texturedVertexInfos = uvSetDirectory.File("textured-vertex-infos.array").ReadArray <TexturedVertexInfo>();

        Quad[] texturedFaces = uvSetDirectory.File("textured-faces.array").ReadArray <Quad>();

        var vertexRefiner = new VertexRefiner(device, shaderCache, mesh, texturedVertexInfos);

        FigureSurface[] surfaces = FigureSurface.MakeSurfaces(device, materials.Length, texturedFaces, controlFaceMap, surfaceMap, materialSet.FaceTransparencies);

        HashSet <int> visitedSurfaceIndices = new HashSet <int>();
        List <int>    surfaceOrder          = new List <int>(surfaces.Length);

        bool[] areUnorderedTransparent = new bool[surfaces.Length];

        //first add surfaces with an explicity-set render order
        foreach (int surfaceIdx in surfaceProperties.RenderOrder)
        {
            visitedSurfaceIndices.Add(surfaceIdx);
            surfaceOrder.Add(surfaceIdx);
            areUnorderedTransparent[surfaceIdx] = false;
        }

        //then add any remaining surfaces
        for (int surfaceIdx = 0; surfaceIdx < surfaces.Length; ++surfaceIdx)
        {
            if (visitedSurfaceIndices.Contains(surfaceIdx))
            {
                continue;
            }
            surfaceOrder.Add(surfaceIdx);
            areUnorderedTransparent[surfaceIdx] = true;
        }

        var isOneSided = figureDir.Name == "genesis-3-female";         //hack

        return(new FigureRenderer(device, shaderCache, scatterer, vertexRefiner, materialSet, surfaces, isOneSided, surfaceOrder.ToArray(), areUnorderedTransparent));
    }
Example #3
0
        private static void Subdivide(SubdivisionMesh subdivisionMesh, TriangleIndicesUnsignedInt triangle, int level)
        {
            if (level > 0)
            {
                IList <Vector3D> positions = subdivisionMesh.Positions;
                Vector3D         n01       = ((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize();
                Vector3D         n12       = ((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize();
                Vector3D         n20       = ((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize();

                Vector3D p01 = n01.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii);
                Vector3D p12 = n12.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii);
                Vector3D p20 = n20.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii);

                positions.Add(p01);
                positions.Add(p12);
                positions.Add(p20);

                int i01 = positions.Count - 3;
                int i12 = positions.Count - 2;
                int i20 = positions.Count - 1;

                if ((subdivisionMesh.Normals != null) || (subdivisionMesh.TextureCoordinate != null))
                {
                    Vector3D d01 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p01);
                    Vector3D d12 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p12);
                    Vector3D d20 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p20);

                    if (subdivisionMesh.Normals != null)
                    {
                        subdivisionMesh.Normals.Add(d01.ToVector3H());
                        subdivisionMesh.Normals.Add(d12.ToVector3H());
                        subdivisionMesh.Normals.Add(d20.ToVector3H());
                    }

                    if (subdivisionMesh.TextureCoordinate != null)
                    {
                        subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d01));
                        subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d12));
                        subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d20));
                    }
                }

                //
                // Subdivide input triangle into four triangles
                //
                --level;
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, i12, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level);
            }
            else
            {
                subdivisionMesh.Indices.AddTriangle(triangle);
            }
        }
Example #4
0
    public static SubdivisionMesh Combine(SubdivisionMesh meshA, SubdivisionMesh meshB)
    {
        int offset = meshA.ControlVertexCount;

        return(new SubdivisionMesh(
                   meshA.ControlVertexCount + meshB.ControlVertexCount,
                   QuadTopology.Combine(meshA.Topology, meshB.Topology),
                   PackedLists <WeightedIndexWithDerivatives> .Concat(
                       meshA.Stencils,
                       meshB.Stencils.Map(w => w.Reindex(offset)))));
    }
Example #5
0
    public static RefinementResult Combine(RefinementResult resultA, RefinementResult resultB)
    {
        SubdivisionMesh combinedMesh = SubdivisionMesh.Combine(
            resultA.Mesh,
            resultB.Mesh);

        int[] combinedControlFaceMap = Enumerable.Concat(
            resultA.ControlFaceMap,
            resultB.ControlFaceMap).ToArray();

        return(new RefinementResult(combinedMesh, combinedControlFaceMap));
    }
Example #6
0
    public static Scatterer Load(Device device, ShaderCache shaderCache, IArchiveDirectory figureDir, String materialSetName)
    {
        var             l0GeometryDir = figureDir.Subdirectory("refinement").Subdirectory("level-0");
        SubdivisionMesh level0Mesh    = SubdivisionMeshPersistance.Load(l0GeometryDir);

        var scatteringDir      = figureDir.Subdirectory("scattering").Subdirectory(materialSetName);
        var formFactorSegments = scatteringDir.File(FormFactorSegmentsFilename).ReadArray <ArraySegment>();
        var formFactorElements = scatteringDir.File(FormFactoryElementsFilename).ReadArray <Vector3WeightedIndex>();
        var formFactors        = new PackedLists <Vector3WeightedIndex>(formFactorSegments, formFactorElements);

        return(new Scatterer(device, shaderCache, level0Mesh, formFactors));
    }
Example #7
0
    public Scatterer(Device device, ShaderCache shaderCache, SubdivisionMesh mesh, PackedLists <Vector3WeightedIndex> formFactors)
    {
        vertexCount        = mesh.Stencils.Count;
        stencilSegments    = BufferUtilities.ToStructuredBufferView(device, mesh.Stencils.Segments);
        stencilElems       = BufferUtilities.ToStructuredBufferView(device, mesh.Stencils.Elems);
        formFactorSegments = BufferUtilities.ToStructuredBufferView(device, formFactors.Segments);
        formFactorElements = BufferUtilities.ToStructuredBufferView(device, formFactors.Elems);

        samplingShader   = shaderCache.GetComputeShader <Scatterer>("figure/scattering/SampleVertexIrradiances");
        scatteringShader = shaderCache.GetComputeShader <Scatterer>("figure/scattering/ScatterIrradiances");

        sampledIrrandiancesBufferManager   = new InOutStructuredBufferManager <Vector3>(device, vertexCount);
        scatteredIrrandiancesBufferManager = new InOutStructuredBufferManager <Vector3>(device, vertexCount);
    }
    public static RefinementResult Make(QuadTopology controlTopology, int[] controlSurfaceMap, int refinementLevel, bool derivativesOnly)
    {
        if (controlTopology.Faces.Length == 0 && controlTopology.VertexCount == 0)
        {
            return(RefinementResult.Empty);
        }

        PackedLists <WeightedIndex> limitStencils, limitDuStencils, limitDvStencils;
        QuadTopology            refinedTopology;
        SubdivisionTopologyInfo refinedTopologyInfo;

        int[] controlFaceMap;
        using (var refinement = new Refinement(controlTopology, refinementLevel)) {
            limitStencils   = refinement.GetStencils(StencilKind.LimitStencils);
            limitDuStencils = refinement.GetStencils(StencilKind.LimitDuStencils);
            limitDvStencils = refinement.GetStencils(StencilKind.LimitDvStencils);
            refinedTopology = refinement.GetTopology();

            var adjacentVertices = refinement.GetAdjacentVertices();
            var rules            = refinement.GetVertexRules();
            refinedTopologyInfo = new SubdivisionTopologyInfo(adjacentVertices, rules);

            controlFaceMap = refinement.GetFaceMap();
        }

        if (derivativesOnly)
        {
            if (refinementLevel != 0)
            {
                throw new InvalidOperationException("derivatives-only mode can only be used at refinement level 0");
            }

            limitStencils = PackedLists <WeightedIndex> .Pack(Enumerable.Range(0, controlTopology.VertexCount)
                                                              .Select(vertexIdx => {
                var selfWeight = new WeightedIndex(vertexIdx, 1);
                return(new List <WeightedIndex> {
                    selfWeight
                });
            }).ToList());
        }

        PackedLists <WeightedIndexWithDerivatives> stencils = WeightedIndexWithDerivatives.Merge(limitStencils, limitDuStencils, limitDvStencils);
        var refinedMesh = new SubdivisionMesh(controlTopology.VertexCount, refinedTopology, stencils);

        return(new RefinementResult(refinedMesh, refinedTopologyInfo, controlFaceMap));
    }
        private static void Subdivide(SubdivisionMesh subdivisionMesh, TriangleIndicesUnsignedInt triangle, int level)
        {
            if (level > 0)
            {
                IList <Vector3D> positions = subdivisionMesh.Positions;
                Vector3D         p01       = ((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize();
                Vector3D         p12       = ((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize();
                Vector3D         p20       = ((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize();

                positions.Add(p01);
                positions.Add(p12);
                positions.Add(p20);

                int i01 = positions.Count - 3;
                int i12 = positions.Count - 2;
                int i20 = positions.Count - 1;

                if (subdivisionMesh.Normals != null)
                {
                    subdivisionMesh.Normals.Add(p01.ToVector3H());
                    subdivisionMesh.Normals.Add(p12.ToVector3H());
                    subdivisionMesh.Normals.Add(p20.ToVector3H());
                }

                if (subdivisionMesh.TextureCoordinate != null)
                {
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p01));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p12));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p20));
                }

                //
                // Subdivide input triangle into four triangles
                //
                --level;
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, i12, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level);
            }
            else
            {
                subdivisionMesh.Indices.AddTriangle(triangle);
            }
        }
Example #10
0
    public ArraySegment Add(SubdivisionMesh mesh, float[] faceTransparencies)
    {
        if (mesh.Topology.Faces.Length != faceTransparencies.Length)
        {
            throw new ArgumentException("face count mismatch");
        }

        int startingOffset = combinedMesh.Topology.VertexCount;

        combinedMesh = SubdivisionMesh.Combine(this.combinedMesh, mesh);
        combinedFaceTransparencies = this.combinedFaceTransparencies.Concat(faceTransparencies).ToArray();
        Array.Resize(ref faceMasks, combinedMesh.Topology.Faces.Count());
        Array.Resize(ref vertexMasks, combinedMesh.Topology.VertexCount);

        int count = mesh.Topology.VertexCount;

        return(new ArraySegment(startingOffset, count));
    }
Example #11
0
    private readonly Buffer refinedVertexBuffer;     // stream-out | vertex

    public VertexRefiner(Device device, ShaderCache shaderCache, SubdivisionMesh mesh, TexturedVertexInfo[] texturedVertexInfos)
    {
        this.refinedVertexCount = texturedVertexInfos.Length;

        var vertexRefinerShaderAndBytecode = shaderCache.GetVertexShader <FigureRenderer>("figure/rendering/VertexRefiner");

        this.vertexRefinerShader         = vertexRefinerShaderAndBytecode;
        this.vertexRefinerGeometryShader = new GeometryShader(device, vertexRefinerShaderAndBytecode.Bytecode, StreamOutputElements, new int[] { StreamStride }, GeometryShader.StreamOutputNoRasterizedStream);

        this.shaderResources = new ShaderResourceView[] {
            BufferUtilities.ToStructuredBufferView(device, mesh.Stencils.Segments),
            BufferUtilities.ToStructuredBufferView(device, mesh.Stencils.Elems),
            BufferUtilities.ToStructuredBufferView(device, texturedVertexInfos)
        };

        this.refinedVertexBuffer = new Buffer(device, new BufferDescription {
            SizeInBytes = refinedVertexCount * StreamStride,
            Usage       = ResourceUsage.Default,
            BindFlags   = BindFlags.StreamOutput | BindFlags.VertexBuffer
        });
    }
Example #12
0
        public static Mesh Compute(Ellipsoid ellipsoid, int numberOfSubdivisions, SubdivisionEllipsoidVertexAttributes vertexAttributes)
        {
            if (numberOfSubdivisions < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfSubdivisions");
            }

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.Position) != SubdivisionEllipsoidVertexAttributes.Position)
            {
                throw new ArgumentException("Positions must be provided.", "vertexAttributes");
            }

            Mesh mesh = new Mesh();

            mesh.PrimitiveType         = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfVertices = SubdivisionUtility.NumberOfVertices(numberOfSubdivisions);
            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3("position", numberOfVertices);

            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * SubdivisionUtility.NumberOfTriangles(numberOfSubdivisions));

            mesh.Indices = indices;

            SubdivisionMesh subdivisionMesh = new SubdivisionMesh();

            subdivisionMesh.Ellipsoid = ellipsoid;
            subdivisionMesh.Positions = positionsAttribute.Values;
            subdivisionMesh.Indices   = indices;

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.Normal) == SubdivisionEllipsoidVertexAttributes.Normal)
            {
                VertexAttributeHalfFloatVector3 normalsAttribute = new VertexAttributeHalfFloatVector3("normal", numberOfVertices);
                mesh.Attributes.Add(normalsAttribute);
                subdivisionMesh.Normals = normalsAttribute.Values;
            }

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.TextureCoordinate) == SubdivisionEllipsoidVertexAttributes.TextureCoordinate)
            {
                VertexAttributeHalfFloatVector2 textureCoordinateAttribute = new VertexAttributeHalfFloatVector2("textureCoordinate", numberOfVertices);
                mesh.Attributes.Add(textureCoordinateAttribute);
                subdivisionMesh.TextureCoordinate = textureCoordinateAttribute.Values;
            }

            //
            // Initial tetrahedron
            //
            double       negativeRootTwoOverThree = -Math.Sqrt(2.0) / 3.0;
            const double negativeOneThird         = -1.0 / 3.0;
            double       rootSixOverThree         = Math.Sqrt(6.0) / 3.0;

            Vector3D n0 = new Vector3D(0, 0, 1);
            Vector3D n1 = new Vector3D(0, (2.0 * Math.Sqrt(2.0)) / 3.0, negativeOneThird);
            Vector3D n2 = new Vector3D(-rootSixOverThree, negativeRootTwoOverThree, negativeOneThird);
            Vector3D n3 = new Vector3D(rootSixOverThree, negativeRootTwoOverThree, negativeOneThird);

            Vector3D p0 = n0.MultiplyComponents(ellipsoid.Radii);
            Vector3D p1 = n1.MultiplyComponents(ellipsoid.Radii);
            Vector3D p2 = n2.MultiplyComponents(ellipsoid.Radii);
            Vector3D p3 = n3.MultiplyComponents(ellipsoid.Radii);

            subdivisionMesh.Positions.Add(p0);
            subdivisionMesh.Positions.Add(p1);
            subdivisionMesh.Positions.Add(p2);
            subdivisionMesh.Positions.Add(p3);

            if ((subdivisionMesh.Normals != null) || (subdivisionMesh.TextureCoordinate != null))
            {
                Vector3D d0 = ellipsoid.GeodeticSurfaceNormal(p0);
                Vector3D d1 = ellipsoid.GeodeticSurfaceNormal(p1);
                Vector3D d2 = ellipsoid.GeodeticSurfaceNormal(p2);
                Vector3D d3 = ellipsoid.GeodeticSurfaceNormal(p3);

                if (subdivisionMesh.Normals != null)
                {
                    subdivisionMesh.Normals.Add(d0.ToVector3H());
                    subdivisionMesh.Normals.Add(d1.ToVector3H());
                    subdivisionMesh.Normals.Add(d2.ToVector3H());
                    subdivisionMesh.Normals.Add(d3.ToVector3H());
                }

                if (subdivisionMesh.TextureCoordinate != null)
                {
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d0));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d1));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d2));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d3));
                }
            }

            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 1, 2), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 2, 3), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 3, 1), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(1, 3, 2), numberOfSubdivisions);

            return(mesh);
        }
 public static void Save(System.IO.DirectoryInfo directory, SubdivisionMesh mesh)
 {
     directory.File(StencilSegmentsFilename).WriteArray(mesh.Stencils.Segments);
     directory.File(StencilElementsFilename).WriteArray(mesh.Stencils.Elems);
     directory.File(StencilFacesFilename).WriteArray(mesh.Topology.Faces);
 }
Example #14
0
 public RefinementResult(SubdivisionMesh mesh, int[] controlFaceMap)
 {
     Mesh           = mesh;
     ControlFaceMap = controlFaceMap;
 }
        public static Mesh Compute(Ellipsoid ellipsoid, int numberOfSubdivisions, SubdivisionEllipsoidVertexAttributes vertexAttributes)
        {
            if (numberOfSubdivisions < 0)
            {
                throw new ArgumentOutOfRangeException("numberOfSubdivisions");
            }

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.Position) != SubdivisionEllipsoidVertexAttributes.Position)
            {
                throw new ArgumentException("Positions must be provided.", "vertexAttributes");
            }

            Mesh mesh = new Mesh();
            mesh.PrimitiveType = PrimitiveType.Triangles;
            mesh.FrontFaceWindingOrder = WindingOrder.Counterclockwise;

            int numberOfVertices = SubdivisionUtility.NumberOfVertices(numberOfSubdivisions);
            VertexAttributeDoubleVector3 positionsAttribute = new VertexAttributeDoubleVector3("position", numberOfVertices);
            mesh.Attributes.Add(positionsAttribute);

            IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * SubdivisionUtility.NumberOfTriangles(numberOfSubdivisions));
            mesh.Indices = indices;

            SubdivisionMesh subdivisionMesh = new SubdivisionMesh();
            subdivisionMesh.Ellipsoid = ellipsoid;
            subdivisionMesh.Positions = positionsAttribute.Values;
            subdivisionMesh.Indices = indices;

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.Normal) == SubdivisionEllipsoidVertexAttributes.Normal)
            {
                VertexAttributeHalfFloatVector3 normalsAttribute = new VertexAttributeHalfFloatVector3("normal", numberOfVertices);
                mesh.Attributes.Add(normalsAttribute);
                subdivisionMesh.Normals = normalsAttribute.Values;
            }

            if ((vertexAttributes & SubdivisionEllipsoidVertexAttributes.TextureCoordinate) == SubdivisionEllipsoidVertexAttributes.TextureCoordinate)
            {
                VertexAttributeHalfFloatVector2 textureCoordinateAttribute = new VertexAttributeHalfFloatVector2("textureCoordinate", numberOfVertices);
                mesh.Attributes.Add(textureCoordinateAttribute);
                subdivisionMesh.TextureCoordinate = textureCoordinateAttribute.Values;
            }

            //
            // Initial tetrahedron
            //
            double negativeRootTwoOverThree = -Math.Sqrt(2.0) / 3.0;
            const double negativeOneThird = -1.0 / 3.0;
            double rootSixOverThree = Math.Sqrt(6.0) / 3.0;

            Vector3D n0 = new Vector3D(0, 0, 1);
            Vector3D n1 = new Vector3D(0, (2.0 * Math.Sqrt(2.0)) / 3.0, negativeOneThird);
            Vector3D n2 = new Vector3D(-rootSixOverThree, negativeRootTwoOverThree, negativeOneThird);
            Vector3D n3 = new Vector3D(rootSixOverThree, negativeRootTwoOverThree, negativeOneThird);

            Vector3D p0 = n0.MultiplyComponents(ellipsoid.Radii);
            Vector3D p1 = n1.MultiplyComponents(ellipsoid.Radii);
            Vector3D p2 = n2.MultiplyComponents(ellipsoid.Radii);
            Vector3D p3 = n3.MultiplyComponents(ellipsoid.Radii);
            
            subdivisionMesh.Positions.Add(p0);
            subdivisionMesh.Positions.Add(p1);
            subdivisionMesh.Positions.Add(p2);
            subdivisionMesh.Positions.Add(p3);

            if ((subdivisionMesh.Normals != null) || (subdivisionMesh.TextureCoordinate != null))
            {
                Vector3D d0 = ellipsoid.GeodeticSurfaceNormal(p0);
                Vector3D d1 = ellipsoid.GeodeticSurfaceNormal(p1);
                Vector3D d2 = ellipsoid.GeodeticSurfaceNormal(p2);
                Vector3D d3 = ellipsoid.GeodeticSurfaceNormal(p3);

                if (subdivisionMesh.Normals != null)
                {
                    subdivisionMesh.Normals.Add(d0.ToVector3H());
                    subdivisionMesh.Normals.Add(d1.ToVector3H());
                    subdivisionMesh.Normals.Add(d2.ToVector3H());
                    subdivisionMesh.Normals.Add(d3.ToVector3H());
                }

                if (subdivisionMesh.TextureCoordinate != null)
                {
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d0));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d1));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d2));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d3));
                }
            }

            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 1, 2), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 2, 3), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(0, 3, 1), numberOfSubdivisions);
            Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(1, 3, 2), numberOfSubdivisions);

            return mesh;
        }
        private static void Subdivide(SubdivisionMesh subdivisionMesh, TriangleIndicesUnsignedInt triangle, int level)
        {
            if (level > 0)
            {
                IList<Vector3D> positions = subdivisionMesh.Positions;
                Vector3D p01 = ((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize();
                Vector3D p12 = ((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize();
                Vector3D p20 = ((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize();

                positions.Add(p01);
                positions.Add(p12);
                positions.Add(p20);

                int i01 = positions.Count - 3;
                int i12 = positions.Count - 2;
                int i20 = positions.Count - 1;

                if (subdivisionMesh.Normals != null)
                {
                    subdivisionMesh.Normals.Add(p01.ToVector3H());
                    subdivisionMesh.Normals.Add(p12.ToVector3H());
                    subdivisionMesh.Normals.Add(p20.ToVector3H());
                }

                if (subdivisionMesh.TextureCoordinate != null)
                {
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p01));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p12));
                    subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p20));
                }

                //
                // Subdivide input triangle into four triangles
                //
                --level;
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, i12, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level);
            }
            else
            {
                subdivisionMesh.Indices.AddTriangle(triangle);
            }
        }
        private static void Subdivide(SubdivisionMesh subdivisionMesh, TriangleIndicesUnsignedInt triangle, int level)
        {
            if (level > 0)
            {
                IList<Vector3D> positions = subdivisionMesh.Positions;
                Vector3D n01 = ((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize();
                Vector3D n12 = ((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize();
                Vector3D n20 = ((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize();

                Vector3D p01 = n01.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii);
                Vector3D p12 = n12.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii);
                Vector3D p20 = n20.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii);

                positions.Add(p01);
                positions.Add(p12);
                positions.Add(p20);

                int i01 = positions.Count - 3;
                int i12 = positions.Count - 2;
                int i20 = positions.Count - 1;

                if ((subdivisionMesh.Normals != null) || (subdivisionMesh.TextureCoordinate != null))
                {
                    Vector3D d01 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p01);
                    Vector3D d12 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p12);
                    Vector3D d20 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p20);

                    if (subdivisionMesh.Normals != null)
                    {
                        subdivisionMesh.Normals.Add(d01.ToVector3H());
                        subdivisionMesh.Normals.Add(d12.ToVector3H());
                        subdivisionMesh.Normals.Add(d20.ToVector3H());
                    }

                    if (subdivisionMesh.TextureCoordinate != null)
                    {
                        subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d01));
                        subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d12));
                        subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d20));
                    }
                }

                //
                // Subdivide input triangle into four triangles
                //
                --level;
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, i12, i20), level);
                Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level);
            }
            else
            {
                subdivisionMesh.Indices.AddTriangle(triangle);
            }
        }
 public RefinementResult(SubdivisionMesh mesh, SubdivisionTopologyInfo topologyInfo, int[] controlFaceMap)
 {
     Mesh           = mesh;
     TopologyInfo   = topologyInfo;
     ControlFaceMap = controlFaceMap;
 }