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]; } } var blendEnabled = false; var texCoordsVertexBuffer = AddDisposable(context.GraphicsDevice.CreateStaticBuffer( texCoords, BufferUsage.VertexBuffer)); var material = shaderResources.GetCachedMaterial(w3dShaderMaterial, context); var materialPass = new MaterialPass(material, context.ShaderResources.MeshDepth.Material); return(new ModelMeshPart( this, texCoordsVertexBuffer, 0, (uint)w3dMesh.Triangles.Items.Length * 3, blendEnabled, materialPass, materialPass)); // TODO }
// 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)); } } }
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); 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)); }