Exemplo n.º 1
0
        private static VertexElement[] CreateElement(VertexShaderFlags flag)
        {
            switch (flag)
            {
            case VertexShaderFlags.Position:
                return(new[] { VertexElement.Position(Format.R32G32B32_Float) });

            case VertexShaderFlags.Normal:
                return(new[] { VertexElement.Normal(Format.R32G32B32_Float) });

            case VertexShaderFlags.TextureUV:
                return(new[] { VertexElement.TextureCoordinate(Format.R32G32_Float) });

            case VertexShaderFlags.TextureUVW:
                return(new[] { VertexElement.TextureCoordinate(Format.R32G32B32_Float) });

            case VertexShaderFlags.Color:
                return(new[] { VertexElement.Color(Format.R32G32B32A32_Float) });

            case VertexShaderFlags.Tangent:
                return(new[] { VertexElement.Tangent(Format.R32G32B32A32_Float) });

            case VertexShaderFlags.Barycentric:
                return(new[] { new VertexElement("BARYCENTRIC", Format.R32G32B32_Float) });

            case VertexShaderFlags.InstanceWorld:
                return(new[]
                {
                    new VertexElement("INSTANCEWORLD", 0, Format.R32G32B32A32_Float),
                    new VertexElement("INSTANCEWORLD", 1, Format.R32G32B32A32_Float),
                    new VertexElement("INSTANCEWORLD", 2, Format.R32G32B32A32_Float),
                    new VertexElement("INSTANCEWORLD", 3, Format.R32G32B32A32_Float),
                });

            default:
                throw new ArgumentOutOfRangeException(string.Format("[{0}]: VertexShaderFlag not valid", flag));
            }
        }
Exemplo n.º 2
0
 public static (VertexElement, int) ConvertVertexElement(KeyValuePair <string, SharpGLTF.Schema2.Accessor> accessor, int offset)
 {
     return((accessor.Key, accessor.Value.Format.ByteSize) switch
     {
         ("POSITION", 12) => (VertexElement.Position <Vector3>(0, offset), Vector3.SizeInBytes),
         ("NORMAL", 12) => (VertexElement.Normal <Vector3>(0, offset), Vector3.SizeInBytes),
         ("TANGENT", 12) => (VertexElement.Tangent <Vector3>(0, offset), Vector3.SizeInBytes),
         ("COLOR", 16) => (VertexElement.Color <Vector4>(0, offset), Vector4.SizeInBytes),
         ("TEXCOORD_0", 8) => (VertexElement.TextureCoordinate <Vector2>(0, offset), Vector2.SizeInBytes),
         ("TEXCOORD_1", 8) => (VertexElement.TextureCoordinate <Vector2>(1, offset), Vector2.SizeInBytes),
         ("TEXCOORD_2", 8) => (VertexElement.TextureCoordinate <Vector2>(2, offset), Vector2.SizeInBytes),
         ("TEXCOORD_3", 8) => (VertexElement.TextureCoordinate <Vector2>(3, offset), Vector2.SizeInBytes),
         ("TEXCOORD_4", 8) => (VertexElement.TextureCoordinate <Vector2>(4, offset), Vector2.SizeInBytes),
         ("TEXCOORD_5", 8) => (VertexElement.TextureCoordinate <Vector2>(5, offset), Vector2.SizeInBytes),
         ("TEXCOORD_6", 8) => (VertexElement.TextureCoordinate <Vector2>(6, offset), Vector2.SizeInBytes),
         ("TEXCOORD_7", 8) => (VertexElement.TextureCoordinate <Vector2>(7, offset), Vector2.SizeInBytes),
         ("TEXCOORD_8", 8) => (VertexElement.TextureCoordinate <Vector2>(8, offset), Vector2.SizeInBytes),
         ("TEXCOORD_9", 8) => (VertexElement.TextureCoordinate <Vector2>(9, offset), Vector2.SizeInBytes),
         ("JOINTS_0", 8) => (new VertexElement(VertexElementUsage.BlendIndices, 0, PixelFormat.R16G16B16A16_UInt, offset), 8),
         ("JOINTS_0", 4) => (new VertexElement(VertexElementUsage.BlendIndices, 0, PixelFormat.R8G8B8A8_UInt, offset), 4),
         ("WEIGHTS_0", 16) => (new VertexElement(VertexElementUsage.BlendWeight, 0, PixelFormat.R32G32B32A32_Float, offset), Vector4.SizeInBytes),
         _ => throw new NotImplementedException(),
     });
Exemplo n.º 3
0
        /// <summary>
        /// Generates the tangents and binormals for this mesh data.
        /// Tangents and bitangents will be encoded as float4:
        /// float3 for tangent and an additional float for handedness (1 or -1),
        /// so that bitangent can be reconstructed.
        /// More info at http://www.terathon.com/code/tangent.html
        /// </summary>
        /// <param name="meshData">The mesh data.</param>
        public static unsafe void GenerateTangentBinormal(this MeshDrawData meshData)
        {
            if (!meshData.IsSimple())
            {
                throw new ArgumentException("meshData is not simple.");
            }

            if (meshData.PrimitiveType != PrimitiveType.TriangleList &&
                meshData.PrimitiveType != PrimitiveType.TriangleListWithAdjacency)
            {
                throw new NotImplementedException();
            }

            var vertexBufferBinding = meshData.VertexBuffers[0];
            var indexBufferBinding  = meshData.IndexBuffer;
            var indexData           = indexBufferBinding != null ? indexBufferBinding.Buffer.Value.Content : null;

            var oldVertexStride = vertexBufferBinding.Declaration.VertexStride;
            var bufferData      = vertexBufferBinding.Buffer.Value.Content;

            // TODO: Usage index in key
            var offsetMapping = vertexBufferBinding.Declaration
                                .EnumerateWithOffsets()
                                .ToDictionary(x => x.VertexElement.SemanticAsText, x => x.Offset);

            var positionOffset = offsetMapping["POSITION"];
            var uvOffset       = offsetMapping[VertexElementUsage.TextureCoordinate];
            var normalOffset   = offsetMapping[VertexElementUsage.Normal];

            // Add tangent to vertex declaration
            var vertexElements = vertexBufferBinding.Declaration.VertexElements.ToList();

            if (!offsetMapping.ContainsKey(VertexElementUsage.Tangent))
            {
                vertexElements.Add(VertexElement.Tangent <Vector4>());
            }
            vertexBufferBinding.Declaration = new VertexDeclaration(vertexElements.ToArray());
            var newVertexStride = vertexBufferBinding.Declaration.VertexStride;

            // Update mapping
            offsetMapping = vertexBufferBinding.Declaration
                            .EnumerateWithOffsets()
                            .ToDictionary(x => x.VertexElement.SemanticAsText, x => x.Offset);

            var tangentOffset = offsetMapping[VertexElementUsage.Tangent];

            var newBufferData = new byte[vertexBufferBinding.Count * newVertexStride];

            var tangents   = new Vector3[vertexBufferBinding.Count];
            var bitangents = new Vector3[vertexBufferBinding.Count];

            fixed(byte *indexBufferStart = indexData)
            fixed(byte *oldBuffer = &bufferData[vertexBufferBinding.Offset])
            fixed(byte *newBuffer = &newBufferData[0])
            {
                var indexBuffer32 = indexBufferBinding != null && indexBufferBinding.Is32Bit ? (int *)indexBufferStart : null;
                var indexBuffer16 = indexBufferBinding != null && !indexBufferBinding.Is32Bit ? (short *)indexBufferStart : null;

                var indexCount = indexBufferBinding != null ? indexBufferBinding.Count : vertexBufferBinding.Count;

                for (int i = 0; i < indexCount; i += 3)
                {
                    // Get indices
                    int index1 = i + 0;
                    int index2 = i + 1;
                    int index3 = i + 2;

                    if (indexBuffer32 != null)
                    {
                        index1 = indexBuffer32[index1];
                        index2 = indexBuffer32[index2];
                        index3 = indexBuffer32[index3];
                    }
                    else if (indexBuffer16 != null)
                    {
                        index1 = indexBuffer16[index1];
                        index2 = indexBuffer16[index2];
                        index3 = indexBuffer16[index3];
                    }

                    int vertexOffset1 = index1 * oldVertexStride;
                    int vertexOffset2 = index2 * oldVertexStride;
                    int vertexOffset3 = index3 * oldVertexStride;

                    // Get positions
                    var position1 = (Vector3 *)&oldBuffer[vertexOffset1 + positionOffset];
                    var position2 = (Vector3 *)&oldBuffer[vertexOffset2 + positionOffset];
                    var position3 = (Vector3 *)&oldBuffer[vertexOffset3 + positionOffset];

                    // Get texture coordinates
                    var uv1 = (Vector3 *)&oldBuffer[vertexOffset1 + uvOffset];
                    var uv2 = (Vector3 *)&oldBuffer[vertexOffset2 + uvOffset];
                    var uv3 = (Vector3 *)&oldBuffer[vertexOffset3 + uvOffset];

                    // Calculate position and UV vectors from vertex 1 to vertex 2 and 3
                    var edge1   = *position2 - *position1;
                    var edge2   = *position3 - *position1;
                    var uvEdge1 = *uv2 - *uv1;
                    var uvEdge2 = *uv3 - *uv1;

                    var t = Vector3.Normalize(uvEdge2.Y * edge1 - uvEdge1.Y * edge2);
                    var b = Vector3.Normalize(uvEdge1.X * edge2 - uvEdge2.X * edge1);

                    // Contribute to every vertex
                    tangents[index1] += t;
                    tangents[index2] += t;
                    tangents[index3] += t;

                    bitangents[index1] += b;
                    bitangents[index2] += b;
                    bitangents[index3] += b;
                }

                var oldVertexOffset = 0;
                var newVertexOffset = 0;

                for (int i = 0; i < vertexBufferBinding.Count; ++i)
                {
                    Utilities.CopyMemory(new IntPtr(&newBuffer[newVertexOffset]), new IntPtr(&oldBuffer[oldVertexOffset]), oldVertexStride);

                    var normal = *(Vector3 *)&oldBuffer[oldVertexOffset + normalOffset];
                    var target = ((float *)(&newBuffer[newVertexOffset + tangentOffset]));

                    var tangent   = -tangents[i];
                    var bitangent = bitangents[i];

                    // Gram-Schmidt orthogonalize
                    *((Vector3 *)target) = Vector3.Normalize(tangent - normal * Vector3.Dot(normal, tangent));

                    // Calculate handedness
                    target[3] = Vector3.Dot(Vector3.Cross(normal, tangent), bitangent) < 0.0f ? -1.0f : 1.0f;

                    oldVertexOffset += oldVertexStride;
                    newVertexOffset += newVertexStride;
                }
            }

            vertexBufferBinding.Offset = 0;
            vertexBufferBinding.Buffer = new BufferData(BufferFlags.VertexBuffer, newBufferData);
        }
Exemplo n.º 4
0
        private ModelData.MeshPart Process(ModelData.Mesh mesh, Mesh assimpMesh)
        {
            var meshPart = new ModelData.MeshPart
            {
                PrimitiveTopology = PrimitiveTopology.TriangleList,
                VertexBufferRange = new ModelData.BufferRange {
                    Slot = mesh.VertexBuffers.Count
                },
                IndexBufferRange = new ModelData.BufferRange {
                    Slot = mesh.IndexBuffers.Count
                }
            };

            var vertexBuffer = new ModelData.VertexBuffer
            {
                Layout = new List <VertexElement>()
            };

            mesh.VertexBuffers.Add(vertexBuffer);

            var indexBuffer = new ModelData.IndexBuffer();

            mesh.IndexBuffers.Add(indexBuffer);

            var layout = vertexBuffer.Layout;

            int vertexBufferElementSize = 0;

            // Add position
            layout.Add(VertexElement.PositionTransformed(Format.R32G32B32_Float, 0));
            vertexBufferElementSize += SharpDX.Utilities.SizeOf <Vector3>();

            // Add normals
            if (assimpMesh.HasNormals)
            {
                layout.Add(VertexElement.Normal(0, Format.R32G32B32_Float, vertexBufferElementSize));
                vertexBufferElementSize += SharpDX.Utilities.SizeOf <Vector3>();
            }

            // Add colors
            if (assimpMesh.VertexColorChannelCount > 0)
            {
                for (int localIndex = 0, i = 0; i < assimpMesh.VertexColorChannelCount; i++)
                {
                    if (assimpMesh.HasVertexColors(i))
                    {
                        layout.Add(VertexElement.Normal(localIndex, Format.R32G32B32A32_Float, vertexBufferElementSize));
                        vertexBufferElementSize += SharpDX.Utilities.SizeOf <Color4>();
                        localIndex++;
                    }
                }
            }

            // Add textures
            if (assimpMesh.TextureCoordsChannelCount > 0)
            {
                for (int localIndex = 0, i = 0; i < assimpMesh.TextureCoordsChannelCount; i++)
                {
                    if (assimpMesh.HasTextureCoords(i))
                    {
                        var uvCount = assimpMesh.GetUVComponentCount(i);

                        if (uvCount == 2)
                        {
                            layout.Add(VertexElement.TextureCoordinate(localIndex, Format.R32G32_Float, vertexBufferElementSize));
                            vertexBufferElementSize += SharpDX.Utilities.SizeOf <Vector2>();
                        }
                        else if (uvCount == 3)
                        {
                            layout.Add(VertexElement.TextureCoordinate(localIndex, Format.R32G32B32_Float, vertexBufferElementSize));
                            vertexBufferElementSize += SharpDX.Utilities.SizeOf <Vector3>();
                        }
                        else
                        {
                            throw new InvalidOperationException("Unexpected uv count");
                        }

                        localIndex++;
                    }
                }
            }

            if (options.ModelOperations.HasFlag(ModelOperation.CalculateBarycentricCoordinates))
            {
                layout.Add(new VertexElement("BARYCENTRIC", 0, Format.R32G32B32_Float, vertexBufferElementSize));
                vertexBufferElementSize += SharpDX.Utilities.SizeOf <Vector3>();
            }
            else
            // Add tangent / bitangent
            if (assimpMesh.HasTangentBasis)
            {
                if (!options.ExcludeElements.Contains("Tangent"))
                {
                    layout.Add(VertexElement.Tangent(Format.R32G32B32A32_Float, vertexBufferElementSize));
                    vertexBufferElementSize += SharpDX.Utilities.SizeOf <Vector4>();
                }

                if (!options.ExcludeElements.Contains("BiTangent"))
                {
                    layout.Add(VertexElement.BiTangent(Format.R32G32B32_Float, vertexBufferElementSize));
                    vertexBufferElementSize += SharpDX.Utilities.SizeOf <Vector3>();
                }
            }

            if (options.ModelOperations.HasFlag(ModelOperation.CalculateBarycentricCoordinates))
            {
                WriteBarycentricVertices(assimpMesh, meshPart, vertexBuffer, vertexBufferElementSize);
            }
            else
            {
                WriteVertices(assimpMesh, meshPart, vertexBuffer, vertexBufferElementSize);
            }
            WriteIndices(assimpMesh, meshPart, indexBuffer);
            return(meshPart);
        }