示例#1
0
        private void BuildVisualizationsOfNode(SCNNode node, ref SCNNode verticesNode, ref SCNNode normalsNode)
        {
            // A material that will prevent the nodes from being lit
            var noLightingMaterial = SCNMaterial.Create();

            noLightingMaterial.LightingModelName = SCNLightingModel.Constant;

            var normalMaterial = SCNMaterial.Create();

            normalMaterial.LightingModelName = SCNLightingModel.Constant;
            normalMaterial.Diffuse.Contents  = NSColor.Red;

            // Create nodes to represent the vertex and normals
            var positionVisualizationNode = SCNNode.Create();
            var normalsVisualizationNode  = SCNNode.Create();

            // Retrieve the vertices and normals from the model
            var positionSource = node.Geometry.GetGeometrySourcesForSemantic(SCNGeometrySourceSemantic.Vertex) [0];
            var normalSource   = node.Geometry.GetGeometrySourcesForSemantic(SCNGeometrySourceSemantic.Normal) [0];

            // Get vertex and normal bytes
            var vertexBufferByte = (byte[])positionSource.Data.ToArray();
            var vertexBuffer     = new float[vertexBufferByte.Length / 4];

            Buffer.BlockCopy(vertexBufferByte, 0, vertexBuffer, 0, vertexBufferByte.Length);

            var normalBufferByte = (byte[])normalSource.Data.ToArray();
            var normalBuffer     = new float[normalBufferByte.Length / 4];

            Buffer.BlockCopy(normalBufferByte, 0, normalBuffer, 0, normalBufferByte.Length);

            // Iterate and create geometries to represent the positions and normals
            for (var i = 0; i < positionSource.VectorCount; i++)
            {
                // One new node per normal/vertex
                var vertexNode = SCNNode.Create();
                var normalNode = SCNNode.Create();

                // Attach one sphere per vertex
                var sphere = SCNSphere.Create(0.5f);
                sphere.SegmentCount  = 4;                // use a small segment count for better performances
                sphere.FirstMaterial = noLightingMaterial;
                vertexNode.Geometry  = sphere;

                // And one pyramid per normal
                var pyramid = SCNPyramid.Create(0.1f, 0.1f, 8);
                pyramid.FirstMaterial = normalMaterial;
                normalNode.Geometry   = pyramid;

                // Place the position node
                var componentsPerVector = positionSource.ComponentsPerVector;
                vertexNode.Position = new SCNVector3(vertexBuffer [i * componentsPerVector], vertexBuffer [i * componentsPerVector + 1], vertexBuffer [i * componentsPerVector + 2]);

                // Place the normal node
                normalNode.Position = vertexNode.Position;

                // Orientate the normal
                var up         = new Vector3(0, 0, 1);
                var normalVec  = new Vector3(normalBuffer [i * 3], normalBuffer [i * 3 + 1], normalBuffer [i * 3 + 2]);
                var axis       = Vector3.Normalize(Vector3.Cross(up, normalVec));
                var dotProduct = Vector3.Dot(up, normalVec);
                normalNode.Rotation = new SCNVector4(axis.X, axis.Y, axis.Z, NMath.Acos(dotProduct));

                // Add the nodes to their parent
                positionVisualizationNode.AddChildNode(vertexNode);
                normalsVisualizationNode.AddChildNode(normalNode);
            }

            // We must flush the transaction in order to make sure that the parametric geometries (sphere and pyramid)
            // are up-to-date before flattening the nodes
            SCNTransaction.Flush();

            // Flatten the visualization nodes so that they can be rendered with 1 draw call
            verticesNode = positionVisualizationNode.FlattenedClone();
            normalsNode  = normalsVisualizationNode.FlattenedClone();
        }