예제 #1
0
        public (int VertexOffset, int VertexCount) AddVertices(ReadOnlySpan <Byte> vertexData, VertexDeclaration vertexFormat)
        {
            var count = vertexData.Length / vertexFormat.VertexStride;

            if (count == 0)
            {
                return(_VertexCount, 0);
            }

            if (_VertexCount == 0)
            {
                _VertexElements = vertexFormat.GetVertexElements();
                _VertexStride   = vertexFormat.VertexStride;
            }
            else
            {
                var thisVD = new VertexDeclaration(_VertexStride, _VertexElements);
                if (!thisVD.Equals(vertexFormat))
                {
                    throw new ArgumentException(nameof(vertexFormat));
                }
            }

            vertexData = vertexData.Slice(0, count * _VertexStride);

            int offset = _VertexCount;

            Array.Resize(ref _VertexData, (offset + count) * _VertexStride);
            vertexData.CopyTo(_VertexData.AsSpan().Slice(offset * _VertexStride));

            _VertexCount += count;

            return(offset, count);
        }
예제 #2
0
        public static Byte[] ToXnaVertices(this IMeshPrimitiveDecoder src, VertexDeclaration decl)
        {
            var dst = new Byte[src.VertexCount * decl.VertexStride];

            var elements = decl.GetVertexElements();

            for (int i = 0; i < src.VertexCount; ++i)
            {
                var vrt = new VertexEncoder(dst, decl.VertexStride, i);

                var jw = src.GetSkinWeights(i);

                foreach (var e in elements)
                {
                    switch (e.VertexElementUsage)
                    {
                    case VertexElementUsage.Position: vrt.Encode(e, src.GetPosition(i)); break;

                    case VertexElementUsage.Normal: vrt.Encode(e, src.GetNormal(i)); break;

                    case VertexElementUsage.Tangent: vrt.Encode(e, src.GetTangent(i)); break;

                    case VertexElementUsage.Color: vrt.Encode(e, src.GetColor(i, e.UsageIndex)); break;

                    case VertexElementUsage.TextureCoordinate: vrt.Encode(e, src.GetTextureCoord(i, e.UsageIndex)); break;

                    case VertexElementUsage.BlendIndices: vrt.Encode(e, jw.Indices); break;

                    case VertexElementUsage.BlendWeight: vrt.Encode(e, jw.Weights); break;
                    }
                }
            }

            return(dst);
        }
예제 #3
0
        private static BoundingBox?GetBoundingBox(ModelMeshPart meshPart, Matrix transform)
        {
            if (meshPart.VertexBuffer == null)
            {
                return(null);
            }

            VertexDeclaration vd = meshPart.VertexBuffer.VertexDeclaration;

            VertexElement[]    elements = vd.GetVertexElements();
            VertexElementUsage usage    = VertexElementUsage.Position;

            Func <VertexElement, bool> elementPredicate = ve => ve.VertexElementUsage == usage && ve.VertexElementFormat == VertexElementFormat.Vector3;

            if (!elements.Any(elementPredicate))
            {
                return(null);
            }

            VertexElement element = elements.First(elementPredicate);

            Vector3[] positions = new Vector3[meshPart.NumVertices];
            meshPart.VertexBuffer.GetData((meshPart.VertexOffset * vd.VertexStride) + element.Offset, positions, 0, positions.Length, vd.VertexStride);

            if (positions == null)
            {
                return(null);
            }

            Vector3[] transformedPositions = new Vector3[positions.Length];
            Vector3.Transform(positions, ref transform, transformedPositions);

            return(BoundingBox.CreateFromPoints(transformedPositions));
        }
        private List <VertexPositionNormalColor> _GetVerticesFromPart(ModelMeshPart part,
                                                                      Func <VertexPositionNormalColor[], short[], List <VertexPositionNormalColor> > prepareTriangles)
        {
            VertexDeclaration declaration = part.VertexBuffer.VertexDeclaration;

            VertexElement[] vertexElements = declaration.GetVertexElements();
            VertexElement   vertexPosition = new VertexElement();

            VertexPositionNormalColor[] vertices = new VertexPositionNormalColor[part.NumVertices];

            part.VertexBuffer.GetData <VertexPositionNormalColor>(
                part.VertexOffset * declaration.VertexStride + vertexPosition.Offset,
                vertices,
                0,
                part.NumVertices,
                declaration.VertexStride);

            short[] indices = new short[part.PrimitiveCount * 3];
            part.IndexBuffer.GetData <short>(
                part.StartIndex * 2,
                indices,
                0,
                part.PrimitiveCount * 3);

            return(prepareTriangles(vertices, indices));
        }
예제 #5
0
        internal static bool AreEqual(VertexDeclaration vertexDeclarationA, VertexDeclaration vertexDeclarationB)
        {
            // Compare vertex strides.
            if (vertexDeclarationA.VertexStride != vertexDeclarationB.VertexStride)
            {
                return(false);
            }

            // Compare vertex element count.
            var vertexElementsA = vertexDeclarationA.GetVertexElements();
            var vertexElementsB = vertexDeclarationB.GetVertexElements();

            if (vertexElementsA.Length != vertexElementsB.Length)
            {
                return(false);
            }

            // Compare each vertex element structure.
            for (int j = 0; j < vertexElementsA.Length; j++)
            {
                if (vertexElementsA[j] != vertexElementsB[j])
                {
                    return(false);
                }
            }

            return(true);
        }
        public static void WriteVertexDeclaration(TWXmlNode node, VertexDeclaration decl)
        {
            if (decl == null)
            {
                node.Value = "NULL"; return;
            }
            //TWXmlNode node = parentNode.CreateChildNode( name );

            VertexElement[] elements = decl.GetVertexElements();

            TWXmlNode elementsNode = node.CreateChildNode("Elements");

            elementsNode.AddAttribute("count", elements.Length.ToString());

            for (int i = 0; i < elements.Length; i++)
            {
                TWXmlNode elementNode = elementsNode.CreateChildNode("VertexElement");
                elementNode.AddChildNode("Offset", elements[i].Offset.ToString());
                elementNode.AddChildNode("Stream", elements[i].Stream.ToString());
                elementNode.AddChildNode("UsageIndex", elements[i].UsageIndex.ToString());
                elementNode.AddChildNode("VertexElementFormat", elements[i].VertexElementFormat.ToString());
                elementNode.AddChildNode("VertexElementMethod", elements[i].VertexElementMethod.ToString());
                elementNode.AddChildNode("VertexElementUsage", elements[i].VertexElementUsage.ToString());
            }
        }
        /// <summary>
        /// Extracts the model radius and center.
        /// </summary>
        /// <param name="bi">The bi.</param>
        /// <param name="radius">The radius.</param>
        /// <param name="center">The center.</param>
        public static void ExtractModelRadiusAndCenter(BatchInformation bi, out float radius, out Vector3 center)
        {
            // Read the format of the vertex buffer
            VertexDeclaration declaration = bi.VertexDeclaration;

            VertexElement[] vertexElements = declaration.GetVertexElements();
            // Find the element that holds the position
            VertexElement vertexPosition = new VertexElement();

            foreach (VertexElement vert in vertexElements)
            {
                if (vert.VertexElementUsage == VertexElementUsage.Position &&
                    vert.VertexElementFormat == VertexElementFormat.Vector3)
                {
                    vertexPosition = vert;
                    // There should only be one
                    break;
                }
            }
            // Check the position element found is valid
            if (vertexPosition == null ||
                vertexPosition.VertexElementUsage != VertexElementUsage.Position ||
                vertexPosition.VertexElementFormat != VertexElementFormat.Vector3)
            {
                throw new Exception("Model uses unsupported vertex format!");
            }
            // This where we store the vertices until transformed
            Vector3[] allVertex = new Vector3[bi.NumVertices];
            // Read the vertices from the buffer in to the array
            bi.VertexBuffer.GetData <Vector3>(
                bi.BaseVertex * declaration.VertexStride + vertexPosition.Offset,
                allVertex,
                0,
                bi.NumVertices,
                declaration.VertexStride);
            // Transform them based on the relative bone location and the world if provided
            for (int i = 0; i != allVertex.Length; ++i)
            {
                Vector3.Transform(ref allVertex[i], ref bi.ModelLocalTransformation, out allVertex[i]);
            }
            BoundingSphere bs = BoundingSphere.CreateFromPoints(allVertex);

            radius = bs.Radius;
            center = bs.Center;
        }
예제 #8
0
        public static Vector3[] GetVertexElement(ModelMeshPart meshPart, VertexElementUsage usage)
        {
            VertexDeclaration vd = meshPart.VertexBuffer.VertexDeclaration;

            VertexElement[] elements = vd.GetVertexElements();

            Func <VertexElement, bool> elementPredicate = ve => ve.VertexElementUsage == usage && ve.VertexElementFormat == VertexElementFormat.Vector3;

            if (!elements.Any(elementPredicate))
            {
                return(null);
            }

            VertexElement element = elements.First(elementPredicate);

            Vector3[] vertexData = new Vector3[meshPart.NumVertices];
            meshPart.VertexBuffer.GetData((meshPart.VertexOffset * vd.VertexStride) + element.Offset, vertexData, 0, vertexData.Length, vd.VertexStride);

            return(vertexData);
        }
        public static void ExtractData(List <JVector> vertices, List <TriangleVertexIndices> indices, Model model)
        {
            Matrix[] bones_ = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(bones_);
            foreach (ModelMesh modelmesh in model.Meshes)
            {
                JMatrix xform = Helper.ToJitterMatrix(bones_[modelmesh.ParentBone.Index]);
                foreach (ModelMeshPart meshPart in modelmesh.MeshParts)
                {
                    // Before we add any more where are we starting from
                    int offset = vertices.Count;

                    // Read the format of the vertex buffer
                    VertexDeclaration declaration    = meshPart.VertexBuffer.VertexDeclaration;
                    VertexElement[]   vertexElements = declaration.GetVertexElements();
                    // Find the element that holds the position
                    VertexElement vertexPosition = new VertexElement();
                    foreach (VertexElement vert in vertexElements)
                    {
                        if (vert.VertexElementUsage == VertexElementUsage.Position &&
                            vert.VertexElementFormat == VertexElementFormat.Vector3)
                        {
                            vertexPosition = vert;
                            // There should only be one
                            break;
                        }
                    }
                    // Check the position element found is valid
                    if (vertexPosition == null ||
                        vertexPosition.VertexElementUsage != VertexElementUsage.Position ||
                        vertexPosition.VertexElementFormat != VertexElementFormat.Vector3)
                    {
                        throw new Exception("Model uses unsupported vertex format!");
                    }
                    // This where we store the vertices until transformed
                    JVector[] allVertex = new JVector[meshPart.NumVertices];
                    // Read the vertices from the buffer in to the array
                    meshPart.VertexBuffer.GetData <JVector>(
                        meshPart.VertexOffset * declaration.VertexStride + vertexPosition.Offset,
                        allVertex,
                        0,
                        meshPart.NumVertices,
                        declaration.VertexStride);
                    // Transform them based on the relative bone location and the world if provided
                    for (int i = 0; i != allVertex.Length; ++i)
                    {
                        JVector.Transform(ref allVertex[i], ref xform, out allVertex[i]);
                    }
                    // Store the transformed vertices with those from all the other meshes in this model
                    vertices.AddRange(allVertex);

                    // Find out which vertices make up which triangles
                    if (meshPart.IndexBuffer.IndexElementSize != IndexElementSize.SixteenBits)
                    {
                        // This could probably be handled by using int in place of short but is unnecessary
                        throw new Exception("Model uses 32-bit indices, which are not supported.");
                    }
                    // Each primitive is a triangle
                    short[] indexElements = new short[meshPart.PrimitiveCount * 3];
                    meshPart.IndexBuffer.GetData <short>(
                        meshPart.StartIndex * 2,
                        indexElements,
                        0,
                        meshPart.PrimitiveCount * 3);
                    // Each TriangleVertexIndices holds the three indexes to each vertex that makes up a triangle
                    TriangleVertexIndices[] tvi = new TriangleVertexIndices[meshPart.PrimitiveCount];
                    for (int i = 0; i != tvi.Length; ++i)
                    {
                        // The offset is because we are storing them all in the one array and the
                        // vertices were added to the end of the array.
                        tvi[i].I0 = indexElements[i * 3 + 0] + offset;
                        tvi[i].I1 = indexElements[i * 3 + 1] + offset;
                        tvi[i].I2 = indexElements[i * 3 + 2] + offset;
                    }
                    // Store our triangles
                    indices.AddRange(tvi);
                }
            }
        }
        /// <summary>
        /// Get all the triangles from each mesh part (Changed for XNA 4)
        /// </summary>
        public void ExtractModelMeshPartData(ModelMeshPart meshPart, ref Matrix transform, StreamWriter writer)
        {
            List <Vector3> vertices = new List <Vector3>();
            List <int>     indices  = new List <int>();

            // Before we add any more where are we starting from
            int offset = 0;

            // == Vertices (Changed for XNA 4.0)

            // Read the format of the vertex buffer
            VertexDeclaration declaration = meshPart.VertexBuffer.VertexDeclaration;

            VertexElement[] vertexElements = declaration.GetVertexElements();
            // Find the element that holds the position
            VertexElement vertexPosition = new VertexElement();

            foreach (VertexElement vert in vertexElements)
            {
                if (vert.VertexElementUsage == VertexElementUsage.Position &&
                    vert.VertexElementFormat == VertexElementFormat.Vector3)
                {
                    vertexPosition = vert;
                    // There should only be one
                    break;
                }
            }
            // Check the position element found is valid
            if (vertexPosition == null ||
                vertexPosition.VertexElementUsage != VertexElementUsage.Position ||
                vertexPosition.VertexElementFormat != VertexElementFormat.Vector3)
            {
                throw new Exception("Model uses unsupported vertex format!");
            }
            // This where we store the vertices until transformed
            Vector3[] allVertex = new Vector3[meshPart.NumVertices];
            // Read the vertices from the buffer in to the array
            meshPart.VertexBuffer.GetData <Vector3>(
                meshPart.VertexOffset * declaration.VertexStride + vertexPosition.Offset,
                allVertex,
                0,
                meshPart.NumVertices,
                declaration.VertexStride);
            // Transform them based on the relative bone location and the world if provided
            for (int i = 0; i != allVertex.Length; ++i)
            {
                Vector3.Transform(ref allVertex[i], ref transform, out allVertex[i]);
            }
            // Store the transformed vertices with those from all the other meshes in this model
            vertices.AddRange(allVertex);

            // == Indices (Changed for XNA 4)

            // Find out which vertices make up which triangles
            if (meshPart.IndexBuffer.IndexElementSize != IndexElementSize.SixteenBits)
            {
                // This could probably be handled by using int in place of short but is unnecessary
                throw new Exception("Model uses 32-bit indices, which are not supported.");
            }
            // Each primitive is a triangle
            short[] indexElements = new short[meshPart.PrimitiveCount * 3];
            meshPart.IndexBuffer.GetData <short>(
                meshPart.StartIndex * 2,
                indexElements,
                0,
                meshPart.PrimitiveCount * 3);
            // Each TriangleVertexIndices holds the three indexes to each vertex that makes up a triangle
            //TriangleVertexIndices[] tvi = new TriangleVertexIndices[meshPart.PrimitiveCount];
            for (int i = 0; i != meshPart.PrimitiveCount; ++i)
            {
                // The offset is because we are storing them all in the one array and the
                // vertices were added to the end of the array.
                indices.Add(indexElements[i * 3 + 0] + offset);
                //tvi[i].B = indexElements[i * 3 + 1] + offset;
                //tvi[i].C = indexElements[i * 3 + 2] + offset;
            }
            // Store our triangles
            //indices.AddRange(tvi);

            for (int i = 0; i < indices.Count - 3; i += 3)
            {
                Matrix  correctionMatrix = Matrix.CreateRotationX(MathHelper.PiOver2);
                Vector3 Pt1 = vertices[i];
                Vector3 Pt2 = vertices[i + 1];
                Vector3 Pt3 = vertices[i + 2];

                Vector3 Normal = Vector3.Cross(Pt2, Pt1);
                Normal.Normalize();
                //Normal.Normalize();
                writer.WriteLine(string.Format("facet normal {0} {1} {2}", Normal.X, Normal.Y, Normal.Z));
                writer.WriteLine("outer loop");
                writer.WriteLine(string.Format("vertex {0} {1} {2}", Pt1.X, Pt1.Y, Pt1.Z));
                writer.WriteLine(string.Format("vertex {0} {1} {2}", Pt2.X, Pt2.Y, Pt2.Z));
                writer.WriteLine(string.Format("vertex {0} {1} {2}", Pt3.X, Pt3.Y, Pt3.Z));
                writer.WriteLine("endloop");
                writer.WriteLine("endfacet");
            }
        }
예제 #11
0
        /// <summary>
        /// Calculates the minimum bounding box that fits this model.
        /// </summary>
        protected virtual void CalculateMinimumBoundingBox()
        {
            bool needTransform = false;
            int  baseVertex    = 0;

            foreach (ModelMesh modelMesh in mesh)
            {
                if (transforms != null)
                {
                    needTransform = !transforms[modelMesh.ParentBone.Index].Equals(Matrix.Identity);
                }

                foreach (ModelMeshPart part in modelMesh.MeshParts)
                {
                    baseVertex = vertices.Count;

                    Vector3[] data = new Vector3[part.NumVertices];

                    // Read the format of the vertex buffer
                    VertexDeclaration declaration    = part.VertexBuffer.VertexDeclaration;
                    VertexElement[]   vertexElements = declaration.GetVertexElements();
                    // Find the element that holds the position
                    VertexElement vertexPosition = new VertexElement();
                    foreach (VertexElement vert in vertexElements)
                    {
                        if (vert.VertexElementUsage == VertexElementUsage.Position &&
                            vert.VertexElementFormat == VertexElementFormat.Vector3)
                        {
                            vertexPosition = vert;
                            // There should only be one
                            break;
                        }
                    }

                    // Check the position element found is valid
                    if (vertexPosition == null ||
                        vertexPosition.VertexElementUsage != VertexElementUsage.Position ||
                        vertexPosition.VertexElementFormat != VertexElementFormat.Vector3)
                    {
                        throw new Exception("Model uses unsupported vertex format!");
                    }

                    part.VertexBuffer.GetData <Vector3>(part.VertexOffset * declaration.VertexStride + vertexPosition.Offset,
                                                        data, 0, part.NumVertices, declaration.VertexStride);

                    if (needTransform)
                    {
                        Matrix transform = transforms[modelMesh.ParentBone.Index];
                        for (int ndx = 0; ndx < data.Length; ndx++)
                        {
                            Vector3.Transform(ref data[ndx], ref transform, out data[ndx]);
                        }
                    }

                    vertices.AddRange(data);

                    int[] tmpIndices = new int[part.PrimitiveCount * 3];

                    if (part.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits)
                    {
                        ushort[] tmp = new ushort[part.PrimitiveCount * 3];
                        part.IndexBuffer.GetData <ushort>(part.StartIndex * 2, tmp, 0,
                                                          tmp.Length);
                        Array.Copy(tmp, 0, tmpIndices, 0, tmpIndices.Length);
                    }
                    else
                    {
                        part.IndexBuffer.GetData <int>(part.StartIndex * 2, tmpIndices, 0,
                                                       tmpIndices.Length);
                    }

                    if (baseVertex != 0)
                    {
                        for (int i = 0; i < tmpIndices.Length; i++)
                        {
                            tmpIndices[i] += baseVertex;
                        }
                    }

                    indices.AddRange(tmpIndices);
                }
            }

            if (vertices.Count == 0)
            {
                throw new GoblinException("Corrupted model vertices. Failed to calculate MBB.");
            }
            else
            {
                boundingBox    = BoundingBox.CreateFromPoints(vertices);
                boundingSphere = BoundingSphere.CreateFromPoints(vertices);
                if (offsetTransform.Equals(Matrix.Identity))
                {
                    offsetTransform.Translation = (boundingBox.Min + boundingBox.Max) / 2;
                }
                boundingBoxCalculated = true;
            }
        }
예제 #12
0
    private static void TransformVertices(byte[] buffer, int startVertex, int vertexCount,
                                          VertexDeclaration vertexDeclaration,
                                          Vector3 scale, Pose pose)
    {
      // If the transform does not have a scale/rotation/translation, we can abort.
      bool hasScale = Vector3.AreNumericallyEqual(scale, Vector3.One);
      if (!pose.HasRotation && !pose.HasTranslation && !hasScale)
        return;

      Matrix world = pose;
      world.M11 *= scale.X; world.M12 *= scale.X; world.M13 *= scale.X;
      world.M21 *= scale.Y; world.M22 *= scale.Y; world.M23 *= scale.Y;
      world.M31 *= scale.Z; world.M32 *= scale.Z; world.M33 *= scale.Z;

      Matrix worldInverseTranspose;
      bool scaleIsUniform = (Numeric.AreEqual(scale.X, scale.Y) && Numeric.AreEqual(scale.Y, scale.Z));
      if (scaleIsUniform)
      {
        // With a uniform scale we can use the normal world matrix to transform normals.
        worldInverseTranspose = world;
      }
      else
      {
        // We have to transform normals using the inverse transposed matrix.
        Matrix.Invert(ref world, out worldInverseTranspose);
        Matrix.Transpose(ref worldInverseTranspose, out worldInverseTranspose);
      }

      int vertexStride = vertexDeclaration.VertexStride;


      unsafe
      {
        fixed (byte* pBuffer = buffer)
        {
          foreach (var element in vertexDeclaration.GetVertexElements())
          {
            if (element.UsageIndex > 0)
              continue;

            var usage = element.VertexElementUsage;
            if (usage != VertexElementUsage.Position && usage != VertexElementUsage.Normal
                && usage != VertexElementUsage.Tangent && usage != VertexElementUsage.Binormal)
            {
              continue;
            }

            if (element.VertexElementFormat != VertexElementFormat.Vector3)
              throw new NotSupportedException(
                "Cannot merge meshes. Vertex elements with the semantic Position, Normal, Tangent or Binormal must use format Vector3.");

            int offset = element.Offset;
            if (usage == VertexElementUsage.Position)
            {
              for (int i = 0; i < vertexCount; i++)
              {
                Vector3* pVector3 = (Vector3*)(pBuffer + (startVertex + i) * vertexStride + offset);
                Vector3.Transform(ref *pVector3, ref world, out *pVector3);
              }
            }
            else
            {
              for (int i = 0; i < vertexCount; i++)
              {
                Vector3* pVector3 = (Vector3*)(pBuffer + (startVertex + i) * vertexStride + offset);
                Vector3.TransformNormal(ref *pVector3, ref worldInverseTranspose, out *pVector3);
                (*pVector3).Normalize();
              }
            }
          }
        }
      }
#else
      using (var stream = new MemoryStream(buffer))
      using (var reader = new BinaryReader(stream))
      using (var writer = new BinaryWriter(stream))
      {
        foreach (var element in vertexDeclaration.GetVertexElements())
        {
          if (element.UsageIndex > 0)
            continue;

          var usage = element.VertexElementUsage;
          if (usage != VertexElementUsage.Position && usage != VertexElementUsage.Normal
              && usage != VertexElementUsage.Tangent && usage != VertexElementUsage.Binormal)
          {
            continue;
          }

          if (element.VertexElementFormat != VertexElementFormat.Vector3)
            throw new NotSupportedException(
              "Cannot merge meshes. Vertex elements with the semantic Position, Normal, Tangent or Binormal must use format Vector3.");

          int offset = element.Offset;
          if (usage == VertexElementUsage.Position)
          {
            for (int i = 0; i < vertexCount; i++)
            {
              int startIndex = (startVertex + i) * vertexStride + offset;
              Vector3 vector3 = ReadVector3(reader, startIndex);
              Vector3.Transform(ref vector3, ref world, out vector3);
              WriteVector3(writer, vector3, startIndex);
            }
          }
          else
          {
            for (int i = 0; i < vertexCount; i++)
            {
              int startIndex = (startVertex + i) * vertexStride + offset;
              Vector3 vector3 = ReadVector3(reader, startIndex);
              Vector3.TransformNormal(ref vector3, ref worldInverseTranspose, out vector3);
              vector3.Normalize();
              WriteVector3(writer, vector3, startIndex);
            }
          }
        }
      }

    }
예제 #13
0
        /// <summary>
        /// Calculates the bounding box that contains the sum of the bounding boxes
        /// of the model node's mesh parts
        /// </summary>
        public BoundingBox CreateBoundingBox2(Model mModel)
        {
            // no model, no bounds
            if (mModel == null)
            {
                return(new BoundingBox());
            }

            // NOTE: we could use ModelMesh's built in BoundingSphere property
            // to create a bounding box with BoundingBox.CreateFromSphere,
            // but the source spheres are already overestimates and
            // box from sphere is an additional overestimate, resulting
            // in an unnecessarily huge bounding box

            // assume the worst case ;)
            Vector3 min = Vector3.One * float.MaxValue;
            Vector3 max = Vector3.One * float.MinValue;

            foreach (ModelMesh mesh in mModel.Meshes)
            {
                // grab the raw vertex data from the mesh's vertex buffer
                byte[] data = new byte[mesh.VertexBuffer.SizeInBytes];
                mesh.VertexBuffer.GetData(data);

                // iterate over each part, comparing all vertex positions with
                // the current min and max, updating as necessary
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    VertexDeclaration decl = part.VertexDeclaration;
                    VertexElement[]   elem = decl.GetVertexElements();

                    int stride = decl.GetVertexStrideSize(0);

                    // find the vertex stream offset of the vertex data's position element
                    short pos_at = -1;
                    for (int i = 0; i < elem.Length; ++i)
                    {
                        // not interested...
                        if (elem[i].VertexElementUsage != VertexElementUsage.Position)
                        {
                            continue;
                        }

                        // save the offset
                        pos_at = elem[i].Offset;
                        break;
                    }

                    // didn't find the position element... not good
                    if (pos_at == -1)
                    {
                        throw new Exception("No position data?!?!");
                    }

                    // decode the position of each vertex in the stream and
                    // compare its value to the min/max of the bounding box
                    for (int i = 0; i < data.Length; i += stride)
                    {
                        int ind = i + pos_at;
                        int fs  = sizeof(float);

                        float x = BitConverter.ToSingle(data, ind);
                        float y = BitConverter.ToSingle(data, ind + fs);
                        float z = BitConverter.ToSingle(data, ind + (fs * 2));

                        // if position is outside bounding box, then update the
                        // bounding box min/max to fit it
                        if (x < min.X)
                        {
                            min.X = x;
                        }
                        if (x > max.X)
                        {
                            max.X = x;
                        }
                        if (y < min.Y)
                        {
                            min.Y = y;
                        }
                        if (y > max.Y)
                        {
                            max.Y = y;
                        }
                        if (z < min.Z)
                        {
                            min.Z = z;
                        }
                        if (z > max.Z)
                        {
                            max.Z = z;
                        }
                    }
                }
            }

            // update bounds
            return(new BoundingBox(min, max));
        }
        /// <summary>
        /// Helper to get the vertex and index List from the model.
        /// </summary>
        /// <param name="vert">The vert.</param>
        /// <param name="ind">The ind.</param>
        /// <param name="model">The model.</param>
        private void ExtractData(ref Vector3[] vert, ref int[] ind, IModelo model)
        {
            List <Vector3> vertices = new List <Vector3>();
            List <int>     indices  = new List <int>();

            for (int i = 0; i < model.MeshNumber; i++)
            {
                BatchInformation[] bi = model.GetBatchInformation(i);
                for (int j = 0; j < bi.Length; j++)
                {
                    BatchInformation info = bi[j];
                    int       offset      = vertices.Count;
                    Vector3[] a           = new Vector3[info.NumVertices];

                    // Read the format of the vertex buffer
                    VertexDeclaration declaration    = bi[j].VertexBuffer.VertexDeclaration;
                    VertexElement[]   vertexElements = declaration.GetVertexElements();
                    // Find the element that holds the position
                    VertexElement vertexPosition = new VertexElement();
                    foreach (VertexElement elem in vertexElements)
                    {
                        if (elem.VertexElementUsage == VertexElementUsage.Position &&
                            elem.VertexElementFormat == VertexElementFormat.Vector3)
                        {
                            vertexPosition = elem;
                            // There should only be one
                            break;
                        }
                    }
                    // Check the position element found is valid
                    if (vertexPosition == null ||
                        vertexPosition.VertexElementUsage != VertexElementUsage.Position ||
                        vertexPosition.VertexElementFormat != VertexElementFormat.Vector3)
                    {
                        throw new Exception("Model uses unsupported vertex format!");
                    }
                    // This where we store the vertices until transformed
                    // Read the vertices from the buffer in to the array
                    bi[j].VertexBuffer.GetData <Vector3>(
                        bi[j].BaseVertex * declaration.VertexStride + vertexPosition.Offset,
                        a,
                        0,
                        bi[j].NumVertices,
                        declaration.VertexStride);

                    for (int k = 0; k != a.Length; ++k)
                    {
                        Vector3.Transform(ref a[k], ref info.ModelLocalTransformation, out a[k]);
                    }
                    vertices.AddRange(a);

                    if (info.IndexBuffer.IndexElementSize != IndexElementSize.SixteenBits)
                    {
                        int[] s = new int[info.PrimitiveCount * 3];
                        info.IndexBuffer.GetData <int>(info.StartIndex * 2, s, 0, info.PrimitiveCount * 3);
                        for (int k = 0; k != info.PrimitiveCount; ++k)
                        {
                            indices.Add(s[k * 3 + 2] + offset);
                            indices.Add(s[k * 3 + 1] + offset);
                            indices.Add(s[k * 3 + 0] + offset);
                        }
                    }
                    else
                    {
                        short[] s = new short[info.PrimitiveCount * 3];
                        info.IndexBuffer.GetData <short>(info.StartIndex * 2, s, 0, info.PrimitiveCount * 3);
                        for (int k = 0; k != info.PrimitiveCount; ++k)
                        {
                            indices.Add(s[k * 3 + 2] + offset);
                            indices.Add(s[k * 3 + 1] + offset);
                            indices.Add(s[k * 3 + 0] + offset);
                        }
                    }
                }
            }

            ind  = indices.ToArray();
            vert = vertices.ToArray();
        }
예제 #15
0
        public void ExtractModelMeshPartData(ModelMeshPart meshPart, ref Matrix transform, List <Vector3> vertices, List <Display3D.TriangleVertexIndices> indices)
        {
            int offset = vertices.Count;

            /* Vertices */
            VertexDeclaration declaration = meshPart.VertexBuffer.VertexDeclaration;

            VertexElement[] vertexElements = declaration.GetVertexElements();
            VertexElement   vertexPosition = new VertexElement();

            foreach (VertexElement vert in vertexElements)
            {
                if (vert.VertexElementUsage == VertexElementUsage.Position && vert.VertexElementFormat == VertexElementFormat.Vector3)
                {
                    vertexPosition = vert;
                    break;
                }
            }

            if (vertexPosition == null ||
                vertexPosition.VertexElementUsage != VertexElementUsage.Position ||
                vertexPosition.VertexElementFormat != VertexElementFormat.Vector3)
            {
                throw new Exception("Model uses unsupported vertex format!");
            }

            Vector3[] allVertex = new Vector3[meshPart.NumVertices];

            meshPart.VertexBuffer.GetData <Vector3>(
                meshPart.VertexOffset * declaration.VertexStride + vertexPosition.Offset,
                allVertex,
                0,
                meshPart.NumVertices,
                declaration.VertexStride);

            for (int i = 0; i != allVertex.Length; ++i)
            {
                Vector3.Transform(ref allVertex[i], ref transform, out allVertex[i]);
            }

            vertices.AddRange(allVertex);

            /* Indices */

            if (meshPart.IndexBuffer.IndexElementSize != IndexElementSize.SixteenBits)
            {
                throw new Exception("Model uses 32-bit indices, which are not supported.");
            }

            short[] indexElements = new short[meshPart.PrimitiveCount * 3];
            meshPart.IndexBuffer.GetData <short>(
                meshPart.StartIndex * 2,
                indexElements,
                0,
                meshPart.PrimitiveCount * 3);

            Display3D.TriangleVertexIndices[] tvi = new Display3D.TriangleVertexIndices[meshPart.PrimitiveCount];
            for (int i = 0; i != tvi.Length; ++i)
            {
                tvi[i].A = indexElements[i * 3 + 0] + offset;
                tvi[i].B = indexElements[i * 3 + 1] + offset;
                tvi[i].C = indexElements[i * 3 + 2] + offset;
            }

            indices.AddRange(tvi);
        }
예제 #16
0
        public void ValidateVertexDeclarationForShader(VertexDeclaration declaration, IShader shader, Type verticesType)
        {
            VertexUsage[] usage;

            if (vertexDeclarationUsage == null)
            {
                vertexDeclarationUsage = new Dictionary <VertexDeclaration, VertexUsage[]>();
            }

            if (!vertexDeclarationUsage.TryGetValue(declaration, out usage))
            {
                //build usage
                VertexElement[] elements = declaration.GetVertexElements();

                SortedList <VertexElementUsage, List <int> > usageIndices = new SortedList <VertexElementUsage, List <int> >();

                foreach (VertexElement ve in elements)
                {
                    List <int> inds;
                    if (!usageIndices.TryGetValue(ve.VertexElementUsage, out inds))
                    {
                        inds = new List <int>();
                        usageIndices.Add(ve.VertexElementUsage, inds);
                    }
                    inds.Add(ve.UsageIndex);
                }

                List <VertexUsage> usages = new List <VertexUsage>();
                foreach (KeyValuePair <VertexElementUsage, List <int> > kvp in usageIndices)
                {
                    VertexUsage vuse = new VertexUsage();
                    kvp.Value.Sort();
                    vuse.usage = kvp.Key;
                    foreach (int i in kvp.Value)
                    {
                        vuse.index = i;
                        usages.Add(vuse);
                    }
                }

                usage = usages.ToArray();
                vertexDeclarationUsage.Add(declaration, usage);
            }
            int shaderCount = shader.GetVertexInputCount();

            if (shaderCount == 0)
            {
                return;
            }

            VertexElementUsage use;
            int index;
            int sv = 0;

            for (int dv = 0; dv < usage.Length && sv < shaderCount;)
            {
                shader.GetVertexInput(sv, out use, out index);

                if (usage[dv].usage == use)
                {
                    if (usage[dv].index == index)
                    {
                        dv++;                        //all happy, elements match.
                        sv++;
                        continue;
                    }
                    if (usage[dv].index > index)
                    {
                        //bugger, missing element
                        break;
                    }
                    dv++;
                    continue;
                }
                if ((int)use > (int)usage[dv].usage)
                {
                    dv++;
                    continue;
                }
                break;                //bugger.
            }

            if (sv < shaderCount)
            {
                //problems..
                shader.GetVertexInput(sv, out use, out index);

                //generate an error describing the problem,

                //fill it in with details about the state
                string vertexType = "VerticesGroup";
                string vertexDecl = "vertex structure";
                string shaderType = string.Format("type {0}", shader.GetType());

                string errorFormat = @"Error: The current vertex shader is attempting to read data that is not present in the vertices being drawn.{5}The shader currently in use ({0}) has a vertex shader that reads '{1}{2}' from each vertex.{5}However, the {3} being drawn does not contain a '{1}{2}' value in it's {4}.";

                if (verticesType != null)
                {
                    vertexType = string.Format("Vertices<{0}> object", verticesType.FullName);
                }

                //add some helpers in some common situations...
                if (shader.GetType().IsPublic == false &&
                    shader.GetType().Namespace == "Xen.Ex.Material")
                {
                    shaderType = "MaterialShader";

                    if (use == VertexElementUsage.Tangent || use == VertexElementUsage.Binormal)
                    {
                        errorFormat += Environment.NewLine;
                        errorFormat += "NOTE: MaterialShader properties may change the vertex data it tries to access. Using a Normal Map requires the vertices have Tangents and Binormals.";
                    }
                    if (use == VertexElementUsage.Color)
                    {
                        errorFormat += Environment.NewLine;
                        errorFormat += "NOTE: MaterialShader properties may change the vertex data it tries to access. Setting 'UseVertexColour' to true requires the vertices have Color0 data.";
                    }
                    if (use == VertexElementUsage.Normal)
                    {
                        errorFormat += Environment.NewLine;
                        errorFormat += "NOTE: MaterialShader properties may change the vertex data it tries to access. Enabling lighting requires the vertices have Normals.";
                    }
                }

                if (verticesType == typeof(byte))
                {
                    vertexType = "XNA vertex data";
                    vertexDecl = "vertex declaration";

                    if (use == VertexElementUsage.Tangent || use == VertexElementUsage.Binormal)
                    {
                        errorFormat += Environment.NewLine;
                        errorFormat += "NOTE: If you are drawing a ModelInstance, the Xen Model Importer can generate Tangent/Binormal data by setting the 'Generate Tangent Frames' Content Processor property for the file to true.";
                    }
                }

                string error = string.Format(errorFormat, shaderType, use, index, vertexType, vertexDecl, Environment.NewLine);

                throw new InvalidOperationException(error);
            }
        }
        /// <summary>
        /// Extracts the model mesh part data.
        /// </summary>
        /// <param name="meshPart">The mesh part.</param>
        /// <param name="transform">The transform.</param>
        /// <param name="vertices">The vertices.</param>
        /// <param name="indices">The indices.</param>
        public static void ExtractModelMeshPartData(ModelMeshPart meshPart, ref Matrix transform,
                                                    List <Vector3> vertices, List <int> indices)
        {
            // Before we add any more where are we starting from
            int offset = vertices.Count;

            // == Vertices (Changed for XNA 4.0)

            // Read the format of the vertex buffer
            VertexDeclaration declaration = meshPart.VertexBuffer.VertexDeclaration;

            VertexElement[] vertexElements = declaration.GetVertexElements();
            // Find the element that holds the position
            VertexElement vertexPosition = new VertexElement();

            foreach (VertexElement vert in vertexElements)
            {
                if (vert.VertexElementUsage == VertexElementUsage.Position &&
                    vert.VertexElementFormat == VertexElementFormat.Vector3)
                {
                    vertexPosition = vert;
                    // There should only be one
                    break;
                }
            }
            // Check the position element found is valid
            if (vertexPosition == null ||
                vertexPosition.VertexElementUsage != VertexElementUsage.Position ||
                vertexPosition.VertexElementFormat != VertexElementFormat.Vector3)
            {
                throw new Exception("Model uses unsupported vertex format!");
            }
            // This where we store the vertices until transformed
            Vector3[] allVertex = new Vector3[meshPart.NumVertices];
            // Read the vertices from the buffer in to the array
            meshPart.VertexBuffer.GetData <Vector3>(
                meshPart.VertexOffset * declaration.VertexStride + vertexPosition.Offset,
                allVertex,
                0,
                meshPart.NumVertices,
                declaration.VertexStride);
            // Transform them based on the relative bone location and the world if provided
            for (int i = 0; i != allVertex.Length; ++i)
            {
                Vector3.Transform(ref allVertex[i], ref transform, out allVertex[i]);
            }
            // Store the transformed vertices with those from all the other meshes in this model
            vertices.AddRange(allVertex);

            // == Indices (Changed for XNA 4)

            // Find out which vertices make up which triangles
            if (meshPart.IndexBuffer.IndexElementSize != IndexElementSize.SixteenBits)
            {
                // This could probably be handled by using int in place of short but is unnecessary
                throw new Exception("Model uses 32-bit indices, which are not supported.");
            }
            // Each primitive is a triangle
            short[] indexElements = new short[meshPart.PrimitiveCount * 3];
            meshPart.IndexBuffer.GetData <short>(
                meshPart.StartIndex * 2,
                indexElements,
                0,
                meshPart.PrimitiveCount * 3);
            // Each TriangleVertexIndices holds the three indexes to each vertex that makes up a triangle
            if (meshPart.IndexBuffer.IndexElementSize != IndexElementSize.SixteenBits)
            {
                int[] s = new int[meshPart.PrimitiveCount * 3];
                meshPart.IndexBuffer.GetData <int>(meshPart.StartIndex * 2, s, 0, meshPart.PrimitiveCount * 3);
                for (int k = 0; k != meshPart.PrimitiveCount; ++k)
                {
                    indices.Add(s[k * 3 + 2] + offset);
                    indices.Add(s[k * 3 + 1] + offset);
                    indices.Add(s[k * 3 + 0] + offset);
                }
            }
            else
            {
                short[] s = new short[meshPart.PrimitiveCount * 3];
                meshPart.IndexBuffer.GetData <short>(meshPart.StartIndex * 2, s, 0, meshPart.PrimitiveCount * 3);
                for (int k = 0; k != meshPart.PrimitiveCount; ++k)
                {
                    indices.Add(s[k * 3 + 2] + offset);
                    indices.Add(s[k * 3 + 1] + offset);
                    indices.Add(s[k * 3 + 0] + offset);
                }
            }
        }
예제 #18
0
        private static VertexBuffer LoadVertexBuffer(
            ref VertexDeclaration declaration,
            int elementsPerRow,
            JArray data,
            out List <Vector3> positions)
        {
            var rowsCount = data.Count / elementsPerRow;
            var elements  = declaration.GetVertexElements();

            var blendWeightOffset = 0;
            var blendWeightCount  = (from e in elements
                                     where e.VertexElementUsage == VertexElementUsage.BlendWeight
                                     select e).Count();
            var hasBlendWeight = blendWeightCount > 0;

            if (blendWeightCount > 4)
            {
                throw new Exception("4 is maximum amount of weights per bone");
            }
            if (hasBlendWeight)
            {
                blendWeightOffset = (from e in elements
                                     where e.VertexElementUsage == VertexElementUsage.BlendWeight
                                     select e).First().Offset;

                var newElements = new List <VertexElement>();
                newElements.AddRange(from e in elements
                                     where e.VertexElementUsage != VertexElementUsage.BlendWeight
                                     select e);
                newElements.Add(new VertexElement(blendWeightOffset, VertexElementFormat.Byte4, VertexElementUsage.BlendIndices, 0));
                newElements.Add(new VertexElement(blendWeightOffset + 4, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 0));
                declaration = new VertexDeclaration(newElements.ToArray());
            }

            positions = new List <Vector3>();
            var byteData = new byte[rowsCount * declaration.VertexStride];

            for (var i = 0; i < rowsCount; ++i)
            {
                var destIdx      = i * declaration.VertexStride;
                var srcIdx       = i * elementsPerRow;
                var weightsCount = 0;
                for (var j = 0; j < elements.Length; ++j)
                {
                    var element = elements[j];

                    if (element.VertexElementUsage == VertexElementUsage.BlendWeight)
                    {
                        // Convert from libgdx multiple vector2 blendweight
                        // to single int4 blendindices/vector4 blendweight
                        if (element.VertexElementFormat != VertexElementFormat.Vector2)
                        {
                            throw new Exception("Only Vector2 format for BlendWeight supported.");
                        }

                        var offset = i * declaration.VertexStride + blendWeightOffset + weightsCount;
                        LoadByte(byteData, ref offset, (int)(float)data[srcIdx++]);

                        offset = i * declaration.VertexStride + blendWeightOffset + 4 + weightsCount * 4;
                        LoadFloat(byteData, ref offset, (float)data[srcIdx++]);
                        ++weightsCount;
                        continue;
                    }

                    switch (element.VertexElementFormat)
                    {
                    case VertexElementFormat.Vector2:
                        LoadFloat(byteData, ref destIdx, (float)data[srcIdx++]);
                        LoadFloat(byteData, ref destIdx, (float)data[srcIdx++]);
                        break;

                    case VertexElementFormat.Vector3:
                        var v = new Vector3((float)data[srcIdx++],
                                            (float)data[srcIdx++],
                                            (float)data[srcIdx++]);

                        if (element.VertexElementUsage == VertexElementUsage.Position)
                        {
                            positions.Add(v);
                        }

                        LoadFloat(byteData, ref destIdx, v.X);
                        LoadFloat(byteData, ref destIdx, v.Y);
                        LoadFloat(byteData, ref destIdx, v.Z);
                        break;

                    case VertexElementFormat.Vector4:
                        LoadFloat(byteData, ref destIdx, (float)data[srcIdx++]);
                        LoadFloat(byteData, ref destIdx, (float)data[srcIdx++]);
                        LoadFloat(byteData, ref destIdx, (float)data[srcIdx++]);
                        LoadFloat(byteData, ref destIdx, (float)data[srcIdx++]);
                        break;

                    case VertexElementFormat.Byte4:
                        LoadByte(byteData, ref destIdx, (int)data[srcIdx++]);
                        LoadByte(byteData, ref destIdx, (int)data[srcIdx++]);
                        LoadByte(byteData, ref destIdx, (int)data[srcIdx++]);
                        LoadByte(byteData, ref destIdx, (int)data[srcIdx++]);
                        break;

                    case VertexElementFormat.Color:
                        LoadFloat(byteData, ref destIdx, (float)data[srcIdx++]);
                        break;

                    default:
                        throw new Exception(string.Format("{0} not supported", element.VertexElementFormat));
                    }
                }
            }

            var result = new VertexBuffer(Nrs.GraphicsDevice, declaration, rowsCount, BufferUsage.None);

            result.SetData(byteData);

            return(result);
        }
예제 #19
0
        public static VertexBuffer ConvertVB(VertexBuffer vb,
                                             VertexDeclaration fromDecl,
                                             int fromStreamIndex,
                                             VertexDeclaration toDecl,
                                             int toStreamIndex)
        {
            byte[] fromData = new byte[vb.SizeInBytes];
            vb.GetData <byte>(fromData);

            int fromNumVertices = vb.SizeInBytes /
                                  fromDecl.GetVertexStrideSize(0);

            List <int> vertMap = new List <int>();

            //find mappings
            for (int x = 0; x < fromDecl.GetVertexElements().Length; x++)
            {
                VertexElement thisElem = fromDecl.GetVertexElements()[x];

                bool bFound = false;

                int i = 0;
                for (i = 0; i < toDecl.GetVertexElements().Length; i++)
                {
                    VertexElement elem = toDecl.GetVertexElements()[i];

                    if (elem.Stream == toStreamIndex)
                    {
                        if (thisElem.VertexElementUsage == elem.VertexElementUsage &&
                            thisElem.UsageIndex == elem.UsageIndex &&
                            thisElem.VertexElementFormat == elem.VertexElementFormat)
                        {
                            bFound = true;
                            break;
                        }
                    }
                }
                if (bFound)
                {
                    vertMap.Add(i);
                }
                else
                {
                    vertMap.Add(-1);
                }
            }


            int newBufferSize = fromNumVertices *
                                toDecl.GetVertexStrideSize(toStreamIndex);



            byte[] toData = new byte[newBufferSize];

            int toDeclVertexStride   = toDecl.GetVertexStrideSize(toStreamIndex);
            int fromDeclVertexStride = fromDecl.GetVertexStrideSize(fromStreamIndex);

            for (int x = 0; x < vertMap.Count; x++)
            {
                int i = vertMap[x];

                if (i != -1)
                {
                    VertexElement fromElem = fromDecl.GetVertexElements()[x];
                    VertexElement toElem   = toDecl.GetVertexElements()[i];

                    for (int k = 0; k < fromNumVertices; k++)
                    {
                        for (int j = 0;
                             j < Utility.GetVertexElementSize(fromDecl, x);
                             j++)
                        {
                            toData[k * toDeclVertexStride + toElem.Offset + j] =
                                fromData[k * fromDeclVertexStride + fromElem.Offset + j];
                        }
                    }
                }
            }

            VertexBuffer newVB = new VertexBuffer(
                Utility.GraphicsDevice,
                fromNumVertices * toDecl.GetVertexStrideSize(toStreamIndex),
                BufferUsage.None);                  // in xna 1.0 use vb.ResourceUsage instead

            newVB.SetData <byte>(toData);

            return(newVB);
        }