Exemple #1
0
        public unsafe override ProcessedModel ProcessT(Stream stream, string extension)
        {
            AssimpContext ac    = new AssimpContext();
            Scene         scene = ac.ImportFileFromStream(
                stream,
                PostProcessSteps.FlipWindingOrder | PostProcessSteps.GenerateNormals | PostProcessSteps.FlipUVs,
                extension);
            aiMatrix4x4 rootNodeInverseTransform = scene.RootNode.Transform;

            rootNodeInverseTransform.Inverse();

            List <ProcessedMeshPart>  parts      = new List <ProcessedMeshPart>();
            List <ProcessedAnimation> animations = new List <ProcessedAnimation>();

            HashSet <string> encounteredNames = new HashSet <string>();

            for (int meshIndex = 0; meshIndex < scene.MeshCount; meshIndex++)
            {
                Mesh   mesh     = scene.Meshes[meshIndex];
                string meshName = mesh.Name;
                if (string.IsNullOrEmpty(meshName))
                {
                    meshName = $"mesh_{meshIndex}";
                }
                int counter = 1;
                while (!encounteredNames.Add(meshName))
                {
                    meshName = mesh.Name + "_" + counter.ToString();
                    counter += 1;
                }
                int vertexCount = mesh.VertexCount;

                int positionOffset    = 0;
                int normalOffset      = 12;
                int texCoordsOffset   = -1;
                int boneWeightOffset  = -1;
                int boneIndicesOffset = -1;

                List <VertexElementDescription> elementDescs = new List <VertexElementDescription>();
                elementDescs.Add(new VertexElementDescription("Position", VertexElementSemantic.Position, VertexElementFormat.Float3));
                elementDescs.Add(new VertexElementDescription("Normal", VertexElementSemantic.Normal, VertexElementFormat.Float3));
                normalOffset = 12;

                int vertexSize = 24;

                bool hasTexCoords = mesh.HasTextureCoords(0);
                elementDescs.Add(new VertexElementDescription("TexCoords", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2));
                texCoordsOffset = vertexSize;
                vertexSize     += 8;

                bool hasBones = mesh.HasBones;
                if (hasBones)
                {
                    elementDescs.Add(new VertexElementDescription("BoneWeights", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float4));
                    elementDescs.Add(new VertexElementDescription("BoneIndices", VertexElementSemantic.TextureCoordinate, VertexElementFormat.UInt4));

                    boneWeightOffset = vertexSize;
                    vertexSize      += 16;

                    boneIndicesOffset = vertexSize;
                    vertexSize       += 16;
                }

                byte[]            vertexData = new byte[vertexCount * vertexSize];
                VertexDataBuilder builder    = new VertexDataBuilder(vertexData, vertexSize);
                Vector3           min        = vertexCount > 0 ? mesh.Vertices[0].ToSystemVector3() : Vector3.Zero;
                Vector3           max        = vertexCount > 0 ? mesh.Vertices[0].ToSystemVector3() : Vector3.Zero;

                for (int i = 0; i < vertexCount; i++)
                {
                    Vector3 position = mesh.Vertices[i].ToSystemVector3();
                    min = Vector3.Min(min, position);
                    max = Vector3.Max(max, position);

                    builder.WriteVertexElement(
                        i,
                        positionOffset,
                        position);

                    Vector3 normal = mesh.Normals[i].ToSystemVector3();
                    builder.WriteVertexElement(i, normalOffset, normal);

                    if (mesh.HasTextureCoords(0))
                    {
                        builder.WriteVertexElement(
                            i,
                            texCoordsOffset,
                            new Vector2(mesh.TextureCoordinateChannels[0][i].X, mesh.TextureCoordinateChannels[0][i].Y));
                    }
                    else
                    {
                        builder.WriteVertexElement(
                            i,
                            texCoordsOffset,
                            new Vector2());
                    }
                }

                List <int> indices = new List <int>();
                foreach (Face face in mesh.Faces)
                {
                    if (face.IndexCount == 3)
                    {
                        indices.Add(face.Indices[0]);
                        indices.Add(face.Indices[1]);
                        indices.Add(face.Indices[2]);
                    }
                }

                Dictionary <string, uint>   boneIDsByName = new Dictionary <string, uint>();
                System.Numerics.Matrix4x4[] boneOffsets   = new System.Numerics.Matrix4x4[mesh.BoneCount];

                if (hasBones)
                {
                    Dictionary <int, int> assignedBoneWeights = new Dictionary <int, int>();
                    for (uint boneID = 0; boneID < mesh.BoneCount; boneID++)
                    {
                        Bone   bone     = mesh.Bones[(int)boneID];
                        string boneName = bone.Name;
                        int    suffix   = 1;
                        while (boneIDsByName.ContainsKey(boneName))
                        {
                            boneName = bone.Name + "_" + suffix.ToString();
                            suffix  += 1;
                        }

                        boneIDsByName.Add(boneName, boneID);
                        foreach (VertexWeight weight in bone.VertexWeights)
                        {
                            int relativeBoneIndex = GetAndIncrementRelativeBoneIndex(assignedBoneWeights, weight.VertexID);
                            builder.WriteVertexElement(weight.VertexID, boneIndicesOffset + (relativeBoneIndex * sizeof(uint)), boneID);
                            builder.WriteVertexElement(weight.VertexID, boneWeightOffset + (relativeBoneIndex * sizeof(float)), weight.Weight);
                        }

                        System.Numerics.Matrix4x4 offsetMat = bone.OffsetMatrix.ToSystemMatrixTransposed();
                        System.Numerics.Matrix4x4.Decompose(offsetMat, out var scale, out var rot, out var trans);
                        offsetMat = System.Numerics.Matrix4x4.CreateScale(scale)
                                    * System.Numerics.Matrix4x4.CreateFromQuaternion(rot)
                                    * System.Numerics.Matrix4x4.CreateTranslation(trans);

                        boneOffsets[boneID] = offsetMat;
                    }
                }
                builder.FreeGCHandle();

                uint indexCount = (uint)indices.Count;

                int[]  int32Indices = indices.ToArray();
                byte[] indexData    = new byte[indices.Count * sizeof(uint)];
                fixed(byte *indexDataPtr = indexData)
                {
                    fixed(int *int32Ptr = int32Indices)
                    {
                        Buffer.MemoryCopy(int32Ptr, indexDataPtr, indexData.Length, indexData.Length);
                    }
                }

                ProcessedMeshPart part = new ProcessedMeshPart(
                    vertexData,
                    elementDescs.ToArray(),
                    indexData,
                    IndexFormat.UInt32,
                    (uint)indices.Count,
                    boneIDsByName,
                    boneOffsets);
                parts.Add(part);
            }

            // Nodes
            Node rootNode = scene.RootNode;
            List <ProcessedNode> processedNodes = new List <ProcessedNode>();

            ConvertNode(rootNode, -1, processedNodes);

            ProcessedNodeSet nodes = new ProcessedNodeSet(processedNodes.ToArray(), 0, rootNodeInverseTransform.ToSystemMatrixTransposed());

            for (int animIndex = 0; animIndex < scene.AnimationCount; animIndex++)
            {
                Animation animation = scene.Animations[animIndex];
                Dictionary <string, ProcessedAnimationChannel> channels = new Dictionary <string, ProcessedAnimationChannel>();
                for (int channelIndex = 0; channelIndex < animation.NodeAnimationChannelCount; channelIndex++)
                {
                    NodeAnimationChannel nac = animation.NodeAnimationChannels[channelIndex];
                    channels[nac.NodeName] = ConvertChannel(nac);
                }

                string baseAnimName = animation.Name;
                if (string.IsNullOrEmpty(baseAnimName))
                {
                    baseAnimName = "anim_" + animIndex;
                }

                string animationName = baseAnimName;


                int counter = 1;
                while (!encounteredNames.Add(animationName))
                {
                    animationName = baseAnimName + "_" + counter.ToString();
                    counter      += 1;
                }
            }

            return(new ProcessedModel()
            {
                MeshParts = parts.ToArray(),
                Animations = animations.ToArray(),
                Nodes = nodes
            });
        }
        protected override void CreateResources(ResourceFactory factory)
        {
            _projectionBuffer = factory.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer | BufferUsage.Dynamic));
            _viewBuffer       = factory.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer | BufferUsage.Dynamic));
            _worldBuffer      = factory.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer | BufferUsage.Dynamic));
            Matrix4x4 worldMatrix =
                Matrix4x4.CreateTranslation(0, 15000, -5000)
                * Matrix4x4.CreateRotationX(3 * (float)Math.PI / 2)
                * Matrix4x4.CreateScale(0.05f);

            GraphicsDevice.UpdateBuffer(_worldBuffer, 0, ref worldMatrix);

            ResourceLayout layout = factory.CreateResourceLayout(new ResourceLayoutDescription(
                                                                     new ResourceLayoutElementDescription("Projection", ResourceKind.UniformBuffer, ShaderStages.Vertex),
                                                                     new ResourceLayoutElementDescription("View", ResourceKind.UniformBuffer, ShaderStages.Vertex),
                                                                     new ResourceLayoutElementDescription("World", ResourceKind.UniformBuffer, ShaderStages.Vertex),
                                                                     new ResourceLayoutElementDescription("Bones", ResourceKind.UniformBuffer, ShaderStages.Vertex),
                                                                     new ResourceLayoutElementDescription("SurfaceTex", ResourceKind.TextureReadOnly, ShaderStages.Fragment),
                                                                     new ResourceLayoutElementDescription("SurfaceSampler", ResourceKind.Sampler, ShaderStages.Fragment)));

            Texture texture;

            using (Stream ktxStream = OpenEmbeddedAssetStream("goblin_bc3_unorm.ktx"))
            {
                texture = KtxFile.LoadTexture(
                    GraphicsDevice,
                    factory,
                    ktxStream,
                    PixelFormat.BC3_UNorm);
            }
            _texView = ResourceFactory.CreateTextureView(texture);

            VertexLayoutDescription vertexLayouts = new VertexLayoutDescription(
                new[]
            {
                new VertexElementDescription("Position", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float3),
                new VertexElementDescription("UV", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2),
                new VertexElementDescription("BoneWeights", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float4),
                new VertexElementDescription("BoneIndices", VertexElementSemantic.TextureCoordinate, VertexElementFormat.UInt4),
            });

            GraphicsPipelineDescription gpd = new GraphicsPipelineDescription(
                BlendStateDescription.SingleOverrideBlend,
                DepthStencilStateDescription.DepthOnlyLessEqual,
                new RasterizerStateDescription(FaceCullMode.Back, PolygonFillMode.Solid, FrontFace.CounterClockwise, true, false),
                PrimitiveTopology.TriangleList,
                new ShaderSetDescription(
                    new[] { vertexLayouts },
                    factory.CreateFromSpirv(
                        new ShaderDescription(ShaderStages.Vertex, Encoding.UTF8.GetBytes(VertexCode), "main"),
                        new ShaderDescription(ShaderStages.Fragment, Encoding.UTF8.GetBytes(FragmentCode), "main"))),
                layout,
                GraphicsDevice.SwapchainFramebuffer.OutputDescription);

            _pipeline = factory.CreateGraphicsPipeline(ref gpd);

            AssimpContext ac = new AssimpContext();

            using (Stream modelStream = OpenEmbeddedAssetStream("goblin.dae"))
            {
                _scene = ac.ImportFileFromStream(modelStream, "dae");
            }
            _rootNodeInverseTransform = _scene.RootNode.Transform;
            _rootNodeInverseTransform.Inverse();

            _firstMesh = _scene.Meshes[0];
            AnimatedVertex[] vertices = new AnimatedVertex[_firstMesh.VertexCount];
            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Position = new Vector3(_firstMesh.Vertices[i].X, _firstMesh.Vertices[i].Y, _firstMesh.Vertices[i].Z);
                vertices[i].UV       = new Vector2(_firstMesh.TextureCoordinateChannels[0][i].X, _firstMesh.TextureCoordinateChannels[0][i].Y);
            }

            _animation = _scene.Animations[0];

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

            foreach (Face face in _firstMesh.Faces)
            {
                if (face.IndexCount == 3)
                {
                    indices.Add(face.Indices[0]);
                    indices.Add(face.Indices[1]);
                    indices.Add(face.Indices[2]);
                }
            }

            for (uint boneID = 0; boneID < _firstMesh.BoneCount; boneID++)
            {
                Bone bone = _firstMesh.Bones[(int)boneID];
                _boneIDsByName.Add(bone.Name, boneID);
                foreach (VertexWeight weight in bone.VertexWeights)
                {
                    vertices[weight.VertexID].AddBone(boneID, weight.Weight);
                }
            }
            Array.Resize(ref _boneTransformations, _firstMesh.BoneCount);

            _bonesBuffer = ResourceFactory.CreateBuffer(new BufferDescription(
                                                            64 * 64, BufferUsage.UniformBuffer | BufferUsage.Dynamic));

            _rs = factory.CreateResourceSet(new ResourceSetDescription(layout,
                                                                       _projectionBuffer, _viewBuffer, _worldBuffer, _bonesBuffer, _texView, GraphicsDevice.Aniso4xSampler));

            _indexCount = (uint)indices.Count;

            _vertexBuffer = ResourceFactory.CreateBuffer(new BufferDescription(
                                                             (uint)(vertices.Length * Unsafe.SizeOf <AnimatedVertex>()), BufferUsage.VertexBuffer));
            GraphicsDevice.UpdateBuffer(_vertexBuffer, 0, vertices);

            _indexBuffer = ResourceFactory.CreateBuffer(new BufferDescription(
                                                            _indexCount * 4, BufferUsage.IndexBuffer));
            GraphicsDevice.UpdateBuffer(_indexBuffer, 0, indices.ToArray());

            _cl = factory.CreateCommandList();
            _camera.Position    = new Vector3(110, -87, -532);
            _camera.Yaw         = 0.45f;
            _camera.Pitch       = -0.55f;
            _camera.MoveSpeed   = 1000f;
            _camera.FarDistance = 100000;
        }