Пример #1
0
        internal ModelMesh(W3dMesh w3dMesh, AssetLoadContext loadContext)
        {
            SetNameAndInstanceId("W3DMesh", w3dMesh.Header.MeshName);

            W3dShaderMaterial   w3dShaderMaterial;
            ShaderResourcesBase shaderResources;

            if (w3dMesh.MaterialPasses.Count == 1 && w3dMesh.MaterialPasses[0].ShaderMaterialIds != null)
            {
                if (w3dMesh.MaterialPasses[0].ShaderMaterialIds.Items.Length > 1)
                {
                    throw new NotSupportedException();
                }
                var shaderMaterialID = w3dMesh.MaterialPasses[0].ShaderMaterialIds.Items[0];
                w3dShaderMaterial = w3dMesh.ShaderMaterials.Items[(int)shaderMaterialID];
                var effectName = w3dShaderMaterial.Header.TypeName.Replace(".fx", string.Empty);

                shaderResources = loadContext.ShaderResources.GetShaderMaterialResources(effectName);
            }
            else
            {
                w3dShaderMaterial = null;
                shaderResources   = loadContext.ShaderResources.FixedFunction;
            }

            _depthPipeline = loadContext.ShaderResources.MeshDepth.Pipeline;

            MeshParts = new List <ModelMeshPart>();
            if (w3dShaderMaterial != null)
            {
                MeshParts.Add(CreateModelMeshPartShaderMaterial(
                                  loadContext,
                                  w3dMesh,
                                  w3dMesh.MaterialPasses[0],
                                  w3dShaderMaterial,
                                  (ShaderMaterialShaderResources)shaderResources));
            }
            else
            {
                var vertexMaterials = CreateMaterials(w3dMesh);

                var shadingConfigurations = new FixedFunctionShaderResources.ShadingConfiguration[w3dMesh.Shaders.Items.Count];
                for (var i = 0; i < shadingConfigurations.Length; i++)
                {
                    shadingConfigurations[i] = CreateShadingConfiguration(w3dMesh.Shaders.Items[i]);
                }

                for (var i = 0; i < w3dMesh.MaterialPasses.Count; i++)
                {
                    CreateModelMeshPartsFixedFunction(
                        loadContext,
                        w3dMesh,
                        w3dMesh.MaterialPasses[i],
                        vertexMaterials,
                        shadingConfigurations,
                        MeshParts);
                }
            }

            BoundingBox = new AxisAlignedBoundingBox(
                w3dMesh.Header.Min,
                w3dMesh.Header.Max);

            _shaderSet = shaderResources.ShaderSet;

            Skinned        = w3dMesh.IsSkinned;
            Hidden         = w3dMesh.Header.Attributes.HasFlag(W3dMeshFlags.Hidden);
            CameraOriented = (w3dMesh.Header.Attributes & W3dMeshFlags.GeometryTypeMask) == W3dMeshFlags.GeometryTypeCameraOriented;

            _vertexBuffer = AddDisposable(loadContext.GraphicsDevice.CreateStaticBuffer(
                                              MemoryMarshal.AsBytes(new ReadOnlySpan <MeshShaderResources.MeshVertex.Basic>(CreateVertices(w3dMesh, w3dMesh.IsSkinned))),
                                              BufferUsage.VertexBuffer));

            _indexBuffer = AddDisposable(loadContext.GraphicsDevice.CreateStaticBuffer(
                                             CreateIndices(w3dMesh),
                                             BufferUsage.IndexBuffer));

            var hasHouseColor = w3dMesh.Header.MeshName.StartsWith("HOUSECOLOR");

            _meshConstantsResourceSet = loadContext.ShaderResources.Mesh.GetCachedMeshResourceSet(
                Skinned,
                hasHouseColor);

            PostInitialize(loadContext);
        }
Пример #2
0
        private ModelMeshPart CreateModelMeshPartShaderMaterial(
            AssetLoadContext context,
            W3dMesh w3dMesh,
            W3dMaterialPass w3dMaterialPass,
            W3dShaderMaterial w3dShaderMaterial,
            ShaderMaterialShaderResources shaderResources)
        {
            var texCoords = new MeshShaderResources.MeshVertex.TexCoords[w3dMesh.Header.NumVertices];

            if (w3dMaterialPass.TexCoords != null)
            {
                for (var i = 0; i < texCoords.Length; i++)
                {
                    texCoords[i].UV0 = w3dMaterialPass.TexCoords.Items[i];
                }
            }

            // TODO: Extract state properties from shader material.

            var blendEnabled = false;

            var pipeline = shaderResources.Pipeline;

            var materialResourceSetBuilder = AddDisposable(new ShaderMaterialResourceSetBuilder(
                                                               context.GraphicsDevice,
                                                               shaderResources));

            foreach (var w3dShaderProperty in w3dShaderMaterial.Properties)
            {
                switch (w3dShaderProperty.PropertyType)
                {
                case W3dShaderMaterialPropertyType.Texture:
                    var texture = context.AssetStore.Textures.GetByName(w3dShaderProperty.StringValue) ?? context.StandardGraphicsResources.PlaceholderTexture;
                    materialResourceSetBuilder.SetTexture(w3dShaderProperty.PropertyName, texture);
                    break;

                case W3dShaderMaterialPropertyType.Bool:
                    materialResourceSetBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Bool);
                    break;

                case W3dShaderMaterialPropertyType.Float:
                    materialResourceSetBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Float);
                    break;

                case W3dShaderMaterialPropertyType.Vector2:
                    materialResourceSetBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector2);
                    break;

                case W3dShaderMaterialPropertyType.Vector3:
                    materialResourceSetBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector3);
                    break;

                case W3dShaderMaterialPropertyType.Vector4:
                    materialResourceSetBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector4);
                    break;

                case W3dShaderMaterialPropertyType.Int:
                    materialResourceSetBuilder.SetConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Int);
                    break;

                default:
                    throw new NotSupportedException();
                }
            }

            var materialResourceSet = materialResourceSetBuilder.CreateResourceSet();

            var texCoordsVertexBuffer = AddDisposable(context.GraphicsDevice.CreateStaticBuffer(
                                                          texCoords,
                                                          BufferUsage.VertexBuffer));

            return(new ModelMeshPart(
                       texCoordsVertexBuffer,
                       0,
                       (uint)w3dMesh.Triangles.Items.Length * 3,
                       blendEnabled,
                       pipeline,
                       pipeline, // TODO
                       materialResourceSet));
        }
Пример #3
0
        // One ModelMeshPart for each unique shader in a W3D_CHUNK_MATERIAL_PASS.
        private ModelMeshPart CreateModelMeshPart(
            AssetLoadContext context,
            DeviceBuffer texCoordsVertexBuffer,
            uint startIndex,
            uint indexCount,
            W3dMesh w3dMesh,
            FixedFunctionShaderResources.VertexMaterial[] vertexMaterials,
            FixedFunctionShaderResources.ShadingConfiguration[] shadingConfigurations,
            uint vertexMaterialID,
            uint shaderID,
            uint numTextureStages,
            uint?textureIndex0,
            uint?textureIndex1)
        {
            var w3dShader = w3dMesh.Shaders.Items[(int)shaderID];

            var cullMode = w3dMesh.Header.Attributes.HasFlag(W3dMeshFlags.TwoSided)
                ? FaceCullMode.None
                : FaceCullMode.Back;

            var depthWriteEnabled = w3dShader.DepthMask == W3dShaderDepthMask.WriteEnable;
            var depthComparison   = w3dShader.DepthCompare.ToComparison();

            var blendEnabled           = w3dShader.SrcBlend != W3dShaderSrcBlendFunc.One || w3dShader.DestBlend != W3dShaderDestBlendFunc.Zero;
            var sourceFactor           = w3dShader.SrcBlend.ToBlend();
            var destinationColorFactor = w3dShader.DestBlend.ToBlend(false);
            var destinationAlphaFactor = w3dShader.DestBlend.ToBlend(true);

            var pipeline = context.ShaderResources.FixedFunction.GetCachedPipeline(
                cullMode,
                depthWriteEnabled,
                depthComparison,
                blendEnabled,
                sourceFactor,
                destinationColorFactor,
                destinationAlphaFactor);

            var pipelineBlend = context.ShaderResources.FixedFunction.GetCachedPipeline(
                cullMode,
                depthWriteEnabled,
                depthComparison,
                true,
                BlendFactor.SourceAlpha,
                BlendFactor.InverseSourceAlpha,
                BlendFactor.InverseSourceAlpha);

            var materialConstantsBuffer = AddDisposable(context.GraphicsDevice.CreateStaticBuffer(
                                                            new FixedFunctionShaderResources.MaterialConstantsType
            {
                Material         = vertexMaterials[vertexMaterialID],
                Shading          = shadingConfigurations[shaderID],
                NumTextureStages = (int)numTextureStages
            },
                                                            BufferUsage.UniformBuffer));

            var materialResourceSet = AddDisposable(context.ShaderResources.FixedFunction.CreateMaterialResourceSet(
                                                        materialConstantsBuffer,
                                                        CreateTexture(context, w3dMesh, textureIndex0) ?? context.StandardGraphicsResources.NullTexture,
                                                        CreateTexture(context, w3dMesh, textureIndex1) ?? context.StandardGraphicsResources.NullTexture));

            return(new ModelMeshPart(
                       texCoordsVertexBuffer,
                       startIndex,
                       indexCount,
                       blendEnabled,
                       pipeline,
                       pipelineBlend,
                       materialResourceSet));
        }
Пример #4
0
        // One ModelMeshMaterialPass for each W3D_CHUNK_MATERIAL_PASS
        private void CreateModelMeshPartsFixedFunction(
            AssetLoadContext context,
            W3dMesh w3dMesh,
            W3dMaterialPass w3dMaterialPass,
            FixedFunctionShaderResources.VertexMaterial[] vertexMaterials,
            FixedFunctionShaderResources.ShadingConfiguration[] shadingConfigurations,
            List <ModelMeshPart> meshParts)
        {
            var hasTextureStage0 = w3dMaterialPass.TextureStages.Count > 0;
            var textureStage0    = hasTextureStage0
                ? w3dMaterialPass.TextureStages[0]
                : null;

            var hasTextureStage1 = w3dMaterialPass.TextureStages.Count > 1 && w3dMaterialPass.TextureStages[1].TexCoords != null;
            var textureStage1    = hasTextureStage1
                ? w3dMaterialPass.TextureStages[1]
                : null;

            var numTextureStages = hasTextureStage0 && hasTextureStage1
                ? 2u
                : hasTextureStage0 ? 1u : 0u;

            var texCoords = new MeshShaderResources.MeshVertex.TexCoords[w3dMesh.Header.NumVertices];

            if (hasTextureStage0)
            {
                for (var i = 0; i < texCoords.Length; i++)
                {
                    // TODO: What to do when this is null?
                    if (textureStage0.TexCoords != null)
                    {
                        texCoords[i].UV0 = textureStage0.TexCoords.Items[i];
                    }

                    if (hasTextureStage1)
                    {
                        texCoords[i].UV1 = textureStage1.TexCoords.Items[i];
                    }
                }
            }

            var texCoordsVertexBuffer = AddDisposable(context.GraphicsDevice.CreateStaticBuffer(
                                                          texCoords,
                                                          BufferUsage.VertexBuffer));

            // Optimisation for a fairly common case.
            if (w3dMaterialPass.VertexMaterialIds.Items.Length == 1 &&
                w3dMaterialPass.ShaderIds.Items.Length == 1 &&
                w3dMaterialPass.TextureStages.Count == 1 &&
                w3dMaterialPass.TextureStages[0].TextureIds.Items.Count == 1)
            {
                meshParts.Add(CreateModelMeshPart(
                                  context,
                                  texCoordsVertexBuffer,
                                  0,
                                  w3dMesh.Header.NumTris * 3,
                                  w3dMesh,
                                  vertexMaterials,
                                  shadingConfigurations,
                                  w3dMaterialPass.VertexMaterialIds.Items[0],
                                  w3dMaterialPass.ShaderIds.Items[0],
                                  numTextureStages,
                                  w3dMaterialPass.TextureStages[0].TextureIds.Items[0],
                                  null));
            }
            else
            {
                // Expand ShaderIds and TextureIds, if they have a single entry
                // (which means same ID for all faces)

                IEnumerable <uint?> getExpandedTextureIds(List <uint?> ids)
                {
                    if (ids == null)
                    {
                        for (var i = 0; i < w3dMesh.Header.NumTris; i++)
                        {
                            yield return(null);
                        }
                    }
                    else if (ids.Count == 1)
                    {
                        var result = ids[0];
                        for (var i = 0; i < w3dMesh.Header.NumTris; i++)
                        {
                            yield return(result);
                        }
                    }
                    else
                    {
                        foreach (var id in ids)
                        {
                            yield return(id);
                        }
                    }
                }

                IEnumerable <uint> getExpandedShaderIds()
                {
                    var ids = w3dMaterialPass.ShaderIds.Items;

                    if (ids.Length == 1)
                    {
                        var result = ids[0];
                        for (var i = 0; i < w3dMesh.Header.NumTris; i++)
                        {
                            yield return(result);
                        }
                    }
                    else
                    {
                        foreach (var id in ids)
                        {
                            yield return(id);
                        }
                    }
                }

                IEnumerable <uint> getExpandedVertexMaterialIDs()
                {
                    var ids = w3dMaterialPass.VertexMaterialIds.Items;

                    if (ids.Length == 1)
                    {
                        var result = ids[0];
                        for (var i = 0; i < w3dMesh.Header.NumTris; i++)
                        {
                            yield return(result);
                        }
                    }
                    else
                    {
                        for (var i = 0; i < w3dMesh.Header.NumTris; i++)
                        {
                            var triangle    = w3dMesh.Triangles.Items[i];
                            var materialID0 = ids[(int)triangle.VIndex0];
                            var materialID1 = ids[(int)triangle.VIndex1];
                            var materialID2 = ids[(int)triangle.VIndex2];
                            if (materialID0 != materialID1 || materialID1 != materialID2)
                            {
                                throw new NotSupportedException();
                            }
                            yield return(materialID0);
                        }

                        foreach (var id in ids)
                        {
                            yield return(id);
                        }
                    }
                }

                var combinedIds = getExpandedVertexMaterialIDs()
                                  .Zip(getExpandedShaderIds(), (x, y) => new { VertexMaterialID = x, ShaderID = y })
                                  .Zip(getExpandedTextureIds(textureStage0?.TextureIds.Items), (x, y) => new { x.VertexMaterialID, x.ShaderID, TextureIndex0 = y })
                                  .Zip(getExpandedTextureIds(textureStage1?.TextureIds.Items), (x, y) => new CombinedMaterialPermutation {
                    VertexMaterialID = x.VertexMaterialID, ShaderID = x.ShaderID, TextureIndex0 = x.TextureIndex0, TextureIndex1 = y
                });

                var combinedId = combinedIds.First();
                var startIndex = 0u;
                var indexCount = 0u;

                foreach (var newCombinedId in combinedIds)
                {
                    if (combinedId != newCombinedId)
                    {
                        meshParts.Add(CreateModelMeshPart(
                                          context,
                                          texCoordsVertexBuffer,
                                          startIndex,
                                          indexCount,
                                          w3dMesh,
                                          vertexMaterials,
                                          shadingConfigurations,
                                          combinedId.VertexMaterialID,
                                          combinedId.ShaderID,
                                          numTextureStages,
                                          combinedId.TextureIndex0,
                                          combinedId.TextureIndex1));

                        startIndex = startIndex + indexCount;
                        indexCount = 0;
                    }

                    combinedId = newCombinedId;

                    indexCount += 3;
                }

                if (indexCount > 0)
                {
                    meshParts.Add(CreateModelMeshPart(
                                      context,
                                      texCoordsVertexBuffer,
                                      startIndex,
                                      indexCount,
                                      w3dMesh,
                                      vertexMaterials,
                                      shadingConfigurations,
                                      combinedId.VertexMaterialID,
                                      combinedId.ShaderID,
                                      numTextureStages,
                                      combinedId.TextureIndex0,
                                      combinedId.TextureIndex1));
                }
            }
        }
Пример #5
0
        // One ModelMeshPart for each unique shader in a W3D_CHUNK_MATERIAL_PASS.
        private ModelMeshPart CreateModelMeshPart(
            ContentManager contentManager,
            uint startIndex,
            uint indexCount,
            W3dMesh w3dMesh,
            FixedFunction.VertexMaterial[] vertexMaterials,
            FixedFunction.ShadingConfiguration[] shadingConfigurations,
            uint vertexMaterialID,
            uint shaderID,
            uint numTextureStages,
            uint?textureIndex0,
            uint?textureIndex1)
        {
            var w3dShader = w3dMesh.Shaders[shaderID];

            var rasterizerState = RasterizerStateDescriptionUtility.DefaultFrontIsCounterClockwise;

            rasterizerState.CullMode = w3dMesh.Header.Attributes.HasFlag(W3dMeshFlags.TwoSided)
                ? FaceCullMode.None
                : FaceCullMode.Back;

            var depthState = DepthStencilStateDescription.DepthOnlyLessEqual;

            depthState.DepthWriteEnabled = w3dShader.DepthMask == W3dShaderDepthMask.WriteEnable;
            depthState.DepthComparison   = w3dShader.DepthCompare.ToComparison();

            var blendState = new BlendStateDescription(
                RgbaFloat.White,
                new BlendAttachmentDescription(
                    w3dShader.SrcBlend != W3dShaderSrcBlendFunc.One || w3dShader.DestBlend != W3dShaderDestBlendFunc.Zero,
                    w3dShader.SrcBlend.ToBlend(),
                    w3dShader.DestBlend.ToBlend(false),
                    BlendFunction.Add,
                    w3dShader.SrcBlend.ToBlend(),
                    w3dShader.DestBlend.ToBlend(true),
                    BlendFunction.Add));

            var effectMaterial = new FixedFunctionMaterial(contentManager, contentManager.EffectLibrary.FixedFunction)
            {
                PipelineState = new EffectPipelineState(
                    rasterizerState,
                    depthState,
                    blendState,
                    RenderPipeline.GameOutputDescription)
            };

            var materialConstantsBuffer = AddDisposable(contentManager.GraphicsDevice.CreateStaticBuffer(
                                                            new FixedFunction.MaterialConstantsType
            {
                Material         = vertexMaterials[vertexMaterialID],
                Shading          = shadingConfigurations[shaderID],
                NumTextureStages = numTextureStages
            },
                                                            BufferUsage.UniformBuffer));

            effectMaterial.SetMaterialConstants(materialConstantsBuffer);
            effectMaterial.SetTexture0(CreateTexture(contentManager, w3dMesh, textureIndex0));
            effectMaterial.SetTexture1(CreateTexture(contentManager, w3dMesh, textureIndex1));

            return(new ModelMeshPart(
                       startIndex,
                       indexCount,
                       effectMaterial));
        }
Пример #6
0
        // One ModelMeshMaterialPass for each W3D_CHUNK_MATERIAL_PASS
        private static ModelMeshMaterialPass CreateModelMeshMaterialPass(
            GraphicsDevice graphicsDevice,
            ResourceUploadBatch uploadBatch,
            W3dMesh w3dMesh,
            W3dMaterialPass w3dMaterialPass)
        {
            var hasTextureStage0 = w3dMaterialPass.TextureStages.Count > 0;
            var textureStage0    = hasTextureStage0
                ? w3dMaterialPass.TextureStages[0]
                : null;

            var hasTextureStage1 = w3dMaterialPass.TextureStages.Count > 1;
            var textureStage1    = hasTextureStage1
                ? w3dMaterialPass.TextureStages[1]
                : null;

            var numTextureStages = hasTextureStage0 && hasTextureStage1
                ? 2u
                : hasTextureStage0 ? 1u : 0u;

            var texCoords = new MeshTexCoords[w3dMesh.Header.NumVertices];

            if (hasTextureStage0)
            {
                for (var i = 0; i < texCoords.Length; i++)
                {
                    // TODO: What to do when this is null?
                    if (textureStage0.TexCoords != null)
                    {
                        texCoords[i].UV0 = textureStage0.TexCoords[i];
                    }

                    if (hasTextureStage1)
                    {
                        texCoords[i].UV1 = textureStage1.TexCoords[i];
                    }
                }
            }

            var textureIndices = new MeshTextureIndex[w3dMesh.Header.NumTris];

            if (hasTextureStage0)
            {
                if (textureStage0.TextureIds.Length == 1)
                {
                    var textureID = textureStage0.TextureIds[0];
                    for (var i = 0; i < textureIndices.Length; i++)
                    {
                        textureIndices[i].IndexStage0 = textureID;
                    }
                }
                else
                {
                    for (var i = 0; i < textureIndices.Length; i++)
                    {
                        textureIndices[i].IndexStage0 = textureStage0.TextureIds[i];
                    }
                }
            }

            if (hasTextureStage1)
            {
                if (textureStage1.TextureIds.Length == 1)
                {
                    var textureID = textureStage1.TextureIds[0];
                    for (var i = 0; i < textureIndices.Length; i++)
                    {
                        textureIndices[i].IndexStage1 = textureID;
                    }
                }
                else
                {
                    for (var i = 0; i < textureIndices.Length; i++)
                    {
                        textureIndices[i].IndexStage1 = textureStage1.TextureIds[i];
                    }
                }
            }

            var materialIndices = w3dMaterialPass.VertexMaterialIds;

            if (materialIndices.Length == 1)
            {
                var materialID = materialIndices[0];
                materialIndices = new uint[w3dMesh.Header.NumVertices];
                for (var i = 0; i < w3dMesh.Header.NumVertices; i++)
                {
                    materialIndices[i] = materialID;
                }
            }

            var meshParts = new List <ModelMeshPart>();

            if (w3dMaterialPass.ShaderIds.Length == 1)
            {
                meshParts.Add(CreateModelMeshPart(
                                  0,
                                  w3dMesh.Header.NumTris * 3,
                                  w3dMesh,
                                  w3dMesh.Shaders[w3dMaterialPass.ShaderIds[0]]));
            }
            else
            {
                var shaderID   = w3dMaterialPass.ShaderIds[0];
                var startIndex = 0u;
                var indexCount = 0u;
                for (var i = 0; i < w3dMaterialPass.ShaderIds.Length; i++)
                {
                    var newShaderID = w3dMaterialPass.ShaderIds[i];

                    if (shaderID != newShaderID)
                    {
                        meshParts.Add(CreateModelMeshPart(
                                          startIndex,
                                          indexCount,
                                          w3dMesh,
                                          w3dMesh.Shaders[shaderID]));

                        startIndex = (uint)(i * 3);
                        indexCount = 0;
                    }

                    shaderID = newShaderID;

                    indexCount += 3;
                }

                if (indexCount > 0)
                {
                    meshParts.Add(CreateModelMeshPart(
                                      startIndex,
                                      indexCount,
                                      w3dMesh,
                                      w3dMesh.Shaders[shaderID]));
                }
            }

            return(new ModelMeshMaterialPass(
                       graphicsDevice,
                       uploadBatch,
                       numTextureStages,
                       texCoords,
                       textureIndices,
                       materialIndices,
                       meshParts));
        }
Пример #7
0
        private ModelMeshMaterialPass CreateModelMeshMaterialPassShaderMaterial(
            ContentManager contentManager,
            W3dMesh w3dMesh,
            W3dMaterialPass w3dMaterialPass,
            W3dShaderMaterial w3dShaderMaterial,
            Effect effect)
        {
            var texCoords = new MeshVertex.TexCoords[w3dMesh.Header.NumVertices];

            if (w3dMaterialPass.TexCoords != null)
            {
                for (var i = 0; i < texCoords.Length; i++)
                {
                    texCoords[i].UV0 = w3dMaterialPass.TexCoords[i];
                }
            }

            var meshParts = new List <ModelMeshPart>();

            // TODO: Extract state properties from shader material.
            var rasterizerState = RasterizerStateDescriptionUtility.DefaultFrontIsCounterClockwise;
            var depthState      = DepthStencilStateDescription.DepthOnlyLessEqual;
            var blendState      = BlendStateDescription.SingleDisabled;

            var material = new ShaderMaterial(contentManager, effect)
            {
                PipelineState = new EffectPipelineState(
                    rasterizerState,
                    depthState,
                    blendState,
                    RenderPipeline.GameOutputDescription)
            };

            var materialConstantsResourceBinding = effect.GetParameter("MaterialConstants").ResourceBinding;
            var materialConstantsBuffer          = AddDisposable(contentManager.GraphicsDevice.ResourceFactory.CreateBuffer(
                                                                     new BufferDescription(
                                                                         materialConstantsResourceBinding.Size,
                                                                         BufferUsage.UniformBuffer | BufferUsage.Dynamic)));

            var materialConstantsBytes = new byte[materialConstantsResourceBinding.Size];

            void setMaterialConstant <T>(string name, T value)
                where T : struct
            {
                var constantBufferField = materialConstantsResourceBinding.GetField(name);

                var valueBytes = StructInteropUtility.ToBytes(ref value);

                if (valueBytes.Length != constantBufferField.Size)
                {
                    throw new InvalidOperationException();
                }

                Buffer.BlockCopy(
                    valueBytes,
                    0,
                    materialConstantsBytes,
                    constantBufferField.Offset,
                    constantBufferField.Size);
            }

            foreach (var w3dShaderProperty in w3dShaderMaterial.Properties)
            {
                switch (w3dShaderProperty.PropertyType)
                {
                case W3dShaderMaterialPropertyType.Texture:
                    var texture = CreateTexture(contentManager, w3dShaderProperty.StringValue);
                    material.SetProperty(w3dShaderProperty.PropertyName, texture);
                    break;

                case W3dShaderMaterialPropertyType.Bool:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Bool);
                    break;

                case W3dShaderMaterialPropertyType.Color:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Color);
                    break;

                case W3dShaderMaterialPropertyType.Float:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Float);
                    break;

                case W3dShaderMaterialPropertyType.Vector2:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector2);
                    break;

                case W3dShaderMaterialPropertyType.Vector3:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector3);
                    break;

                case W3dShaderMaterialPropertyType.Int:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Int);
                    break;

                default:
                    throw new NotSupportedException();
                }
            }

            contentManager.GraphicsDevice.UpdateBuffer(materialConstantsBuffer, 0, materialConstantsBytes);
            material.SetProperty("MaterialConstants", materialConstantsBuffer);

            meshParts.Add(new ModelMeshPart(
                              0,
                              w3dMesh.Header.NumTris * 3,
                              material));

            return(new ModelMeshMaterialPass(
                       contentManager.GraphicsDevice,
                       texCoords,
                       meshParts));
        }
Пример #8
0
        private ModelMesh CreateModelMesh(
            ContentManager contentManager,
            W3dMesh w3dMesh,
            ModelBone parentBone,
            int numBones)
        {
            W3dShaderMaterial w3dShaderMaterial;
            Effect            effect = null;

            if (w3dMesh.MaterialPasses.Length == 1 && w3dMesh.MaterialPasses[0].ShaderMaterialId != null)
            {
                var shaderMaterialID = w3dMesh.MaterialPasses[0].ShaderMaterialId.Value;
                w3dShaderMaterial = w3dMesh.ShaderMaterials.Materials[(int)shaderMaterialID];
                var effectName = w3dShaderMaterial.Header.TypeName.Replace(".fx", string.Empty);

                effect = contentManager.EffectLibrary.GetEffect(
                    effectName,
                    MeshVertex.VertexDescriptors);
            }
            else
            {
                w3dShaderMaterial = null;
                effect            = contentManager.EffectLibrary.FixedFunction;
            }

            var vertexMaterials = CreateMaterials(w3dMesh);

            var shadingConfigurations = new FixedFunction.ShadingConfiguration[w3dMesh.Shaders.Length];

            for (var i = 0; i < shadingConfigurations.Length; i++)
            {
                shadingConfigurations[i] = CreateShadingConfiguration(w3dMesh.Shaders[i]);
            }

            var materialPasses = new ModelMeshMaterialPass[w3dMesh.MaterialPasses.Length];

            if (w3dShaderMaterial != null)
            {
                materialPasses[0] = CreateModelMeshMaterialPassShaderMaterial(
                    contentManager,
                    w3dMesh,
                    w3dMesh.MaterialPasses[0],
                    w3dShaderMaterial,
                    effect);
            }
            else
            {
                for (var i = 0; i < materialPasses.Length; i++)
                {
                    materialPasses[i] = CreateModelMeshMaterialPassFixedFunction(
                        contentManager,
                        w3dMesh,
                        w3dMesh.MaterialPasses[i],
                        vertexMaterials,
                        shadingConfigurations);
                }
            }

            var boundingBox = new BoundingBox(
                w3dMesh.Header.Min,
                w3dMesh.Header.Max);

            var isSkinned      = (w3dMesh.Header.Attributes & W3dMeshFlags.GeometryTypeMask) == W3dMeshFlags.GeometryTypeSkin;
            var cameraOriented = (w3dMesh.Header.Attributes & W3dMeshFlags.GeometryTypeMask) == W3dMeshFlags.GeometryTypeCameraOriented;

            return(new ModelMesh(
                       contentManager.GraphicsDevice,
                       w3dMesh.Header.MeshName,
                       CreateVertices(w3dMesh, isSkinned),
                       CreateIndices(w3dMesh),
                       effect,
                       materialPasses,
                       isSkinned,
                       parentBone,
                       (uint)numBones,
                       boundingBox,
                       w3dMesh.Header.Attributes.HasFlag(W3dMeshFlags.Hidden),
                       cameraOriented));
        }
Пример #9
0
        private ModelMesh CreateModelMesh(
            ContentManager contentManager,
            W3dMesh w3dMesh)
        {
            W3dShaderMaterial   w3dShaderMaterial;
            ShaderResourcesBase shaderResources;
            Pipeline            depthPipeline;

            if (w3dMesh.MaterialPasses.Count == 1 && w3dMesh.MaterialPasses[0].ShaderMaterialIds != null)
            {
                if (w3dMesh.MaterialPasses[0].ShaderMaterialIds.Items.Length > 1)
                {
                    throw new NotSupportedException();
                }
                var shaderMaterialID = w3dMesh.MaterialPasses[0].ShaderMaterialIds.Items[0];
                w3dShaderMaterial = w3dMesh.ShaderMaterials.Items[(int)shaderMaterialID];
                var effectName = w3dShaderMaterial.Header.TypeName.Replace(".fx", string.Empty);

                shaderResources = contentManager.ShaderResources.GetShaderMaterialResources(effectName);
                depthPipeline   = contentManager.ShaderResources.MeshDepth.TriangleListPipeline;
            }
            else
            {
                w3dShaderMaterial = null;
                shaderResources   = contentManager.ShaderResources.FixedFunction;
                depthPipeline     = contentManager.ShaderResources.MeshDepth.TriangleStripPipeline;
            }

            var vertexMaterials = CreateMaterials(w3dMesh);

            var shadingConfigurations = new FixedFunctionShaderResources.ShadingConfiguration[w3dMesh.Shaders.Items.Count];

            for (var i = 0; i < shadingConfigurations.Length; i++)
            {
                shadingConfigurations[i] = CreateShadingConfiguration(w3dMesh.Shaders.Items[i]);
            }

            var meshParts = new List <ModelMeshPart>();

            if (w3dShaderMaterial != null)
            {
                meshParts.Add(CreateModelMeshPartShaderMaterial(
                                  contentManager,
                                  w3dMesh,
                                  w3dMesh.MaterialPasses[0],
                                  w3dShaderMaterial,
                                  (ShaderMaterialShaderResources)shaderResources));
            }
            else
            {
                for (var i = 0; i < w3dMesh.MaterialPasses.Count; i++)
                {
                    CreateModelMeshPartsFixedFunction(
                        contentManager,
                        w3dMesh,
                        w3dMesh.MaterialPasses[i],
                        vertexMaterials,
                        shadingConfigurations,
                        meshParts);
                }
            }

            var boundingBox = new BoundingBox(
                w3dMesh.Header.Min,
                w3dMesh.Header.Max);

            var cameraOriented = (w3dMesh.Header.Attributes & W3dMeshFlags.GeometryTypeMask) == W3dMeshFlags.GeometryTypeCameraOriented;

            var hasHouseColor = w3dMesh.Header.MeshName.StartsWith("HOUSECOLOR");

            return(new ModelMesh(
                       contentManager.GraphicsDevice,
                       contentManager.ShaderResources,
                       w3dMesh.Header.MeshName,
                       shaderResources.ShaderSet,
                       depthPipeline,
                       MemoryMarshal.AsBytes(new ReadOnlySpan <MeshShaderResources.MeshVertex.Basic>(CreateVertices(w3dMesh, w3dMesh.IsSkinned))),
                       CreateIndices(w3dMesh, w3dShaderMaterial != null),
                       meshParts,
                       w3dMesh.IsSkinned,
                       boundingBox,
                       w3dMesh.Header.Attributes.HasFlag(W3dMeshFlags.Hidden),
                       cameraOriented,
                       hasHouseColor));
        }
Пример #10
0
        // One ModelMeshPart for each unique shader in a W3D_CHUNK_MATERIAL_PASS.
        private ModelMeshPart CreateModelMeshPart(
            ContentManager contentManager,
            uint startIndex,
            uint indexCount,
            W3dMesh w3dMesh,
            FixedFunctionMaterial.VertexMaterial[] vertexMaterials,
            FixedFunctionMaterial.ShadingConfiguration[] shadingConfigurations,
            uint vertexMaterialID,
            uint shaderID,
            uint numTextureStages,
            uint?textureIndex0,
            uint?textureIndex1)
        {
            var w3dShader = w3dMesh.Shaders[shaderID];

            var rasterizerState = RasterizerStateDescription.CullBackSolid;

            rasterizerState.CullMode = w3dMesh.Header.Attributes.HasFlag(W3dMeshFlags.TwoSided)
                ? CullMode.None
                : CullMode.CullBack;

            var depthState = DepthStencilStateDescription.Default;

            depthState.IsDepthEnabled      = true;
            depthState.IsDepthWriteEnabled = w3dShader.DepthMask == W3dShaderDepthMask.WriteEnable;
            depthState.DepthComparison     = w3dShader.DepthCompare.ToComparison();

            var blendState = BlendStateDescription.Opaque;

            blendState.Enabled = w3dShader.SrcBlend != W3dShaderSrcBlendFunc.One ||
                                 w3dShader.DestBlend != W3dShaderDestBlendFunc.Zero;
            blendState.SourceBlend           = w3dShader.SrcBlend.ToBlend();
            blendState.SourceAlphaBlend      = w3dShader.SrcBlend.ToBlend();
            blendState.DestinationBlend      = w3dShader.DestBlend.ToBlend(false);
            blendState.DestinationAlphaBlend = w3dShader.DestBlend.ToBlend(true);

            var effectMaterial = new FixedFunctionMaterial(contentManager.EffectLibrary.FixedFunction);

            effectMaterial.PipelineState = new EffectPipelineState(
                rasterizerState,
                depthState,
                blendState);

            var materialConstantsBuffer = AddDisposable(Buffer <FixedFunctionMaterial.MaterialConstants> .CreateStatic(
                                                            contentManager.GraphicsDevice,
                                                            new FixedFunctionMaterial.MaterialConstants
            {
                Material         = vertexMaterials[vertexMaterialID],
                Shading          = shadingConfigurations[shaderID],
                NumTextureStages = numTextureStages
            },
                                                            BufferBindFlags.ConstantBuffer));

            effectMaterial.SetMaterialConstants(materialConstantsBuffer);
            effectMaterial.SetTexture0(CreateTexture(contentManager, w3dMesh, textureIndex0));
            effectMaterial.SetTexture1(CreateTexture(contentManager, w3dMesh, textureIndex1));

            return(new ModelMeshPart(
                       startIndex,
                       indexCount,
                       effectMaterial));
        }
Пример #11
0
        private ModelMeshMaterialPass CreateModelMeshMaterialPassShaderMaterial(
            ContentManager contentManager,
            W3dMesh w3dMesh,
            W3dMaterialPass w3dMaterialPass,
            W3dShaderMaterial w3dShaderMaterial,
            Effect effect)
        {
            var texCoords = new MeshVertex.TexCoords[w3dMesh.Header.NumVertices];

            if (w3dMaterialPass.TexCoords != null)
            {
                for (var i = 0; i < texCoords.Length; i++)
                {
                    texCoords[i].UV0 = w3dMaterialPass.TexCoords[i];
                }
            }

            var meshParts = new List <ModelMeshPart>();

            // TODO: Extract state properties from shader material.
            var rasterizerState = RasterizerStateDescription.CullBackSolid;
            var depthState      = DepthStencilStateDescription.Default;
            var blendState      = BlendStateDescription.Opaque;

            var material = new ShaderMaterial(effect);

            material.PipelineState = new EffectPipelineState(
                rasterizerState,
                depthState,
                blendState);

            var materialConstantsResourceBinding = effect.GetParameter("MaterialConstants").ResourceBinding;
            var materialConstantsBuffer          = AddDisposable(OpenSage.LowLevel.Graphics3D.Buffer.CreateDynamic(
                                                                     contentManager.GraphicsDevice,
                                                                     (uint)materialConstantsResourceBinding.ConstantBufferSizeInBytes,
                                                                     BufferBindFlags.ConstantBuffer));

            var materialConstantsBytes = new byte[materialConstantsResourceBinding.ConstantBufferSizeInBytes];

            void setMaterialConstant <T>(string name, T value)
                where T : struct
            {
                var constantBufferField = materialConstantsResourceBinding.GetConstantBufferField(name);

                var valueBytes = StructInteropUtility.ToBytes(ref value);

                if (valueBytes.Length != constantBufferField.Size)
                {
                    throw new InvalidOperationException();
                }

                System.Buffer.BlockCopy(
                    valueBytes,
                    0,
                    materialConstantsBytes,
                    constantBufferField.Offset,
                    constantBufferField.Size);
            }

            foreach (var w3dShaderProperty in w3dShaderMaterial.Properties)
            {
                switch (w3dShaderProperty.PropertyType)
                {
                case W3dShaderMaterialPropertyType.Texture:
                    var texture = CreateTexture(contentManager, w3dShaderProperty.StringValue);
                    material.SetProperty(w3dShaderProperty.PropertyName, texture);
                    break;

                case W3dShaderMaterialPropertyType.Bool:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Bool);
                    break;

                case W3dShaderMaterialPropertyType.Color:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Color);
                    break;

                case W3dShaderMaterialPropertyType.Float:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Float);
                    break;

                case W3dShaderMaterialPropertyType.Vector2:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector2);
                    break;

                case W3dShaderMaterialPropertyType.Vector3:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Vector3);
                    break;

                case W3dShaderMaterialPropertyType.Int:
                    setMaterialConstant(w3dShaderProperty.PropertyName, w3dShaderProperty.Value.Int);
                    break;

                default:
                    throw new NotSupportedException();
                }
            }

            materialConstantsBuffer.SetData(materialConstantsBytes);
            material.SetProperty("MaterialConstants", materialConstantsBuffer);

            meshParts.Add(new ModelMeshPart(
                              0,
                              w3dMesh.Header.NumTris * 3,
                              material));

            return(new ModelMeshMaterialPass(
                       contentManager.GraphicsDevice,
                       texCoords,
                       meshParts));
        }