public override void Init(ResourceManager resourceManager) { Material pbrMat = new Rendering.Material(resourceManager.Shaders.GetFromAlias("PBR").Shader); Material uiMat = new Rendering.Material(resourceManager.Shaders.GetFromAlias("UI").Shader); pbrMat.AddTexture((int)Rendering.TextureMap.Albedo, resourceManager.Textures.GetFromAlias("Diffuse").Texture); pbrMat.AddTexture((int)Rendering.TextureMap.Normal, resourceManager.Textures.GetFromAlias("Normal").Texture); pbrMat.AddTexture((int)Rendering.TextureMap.Roughness, resourceManager.Textures.GetFromAlias("Roughness").Texture); pbrMat.AddTexture((int)Rendering.TextureMap.Metallic, resourceManager.Textures.GetFromAlias("Metallic").Texture); uiMat.AddTexture((int)Rendering.TextureMap.Normal, resourceManager.Textures.GetFromAlias("Normal").Texture); uiMat.AddTexture((int)Rendering.TextureMap.Albedo, resourceManager.Textures.GetFromAlias("Diffuse").Texture); uiMat.AddTexture((int)Rendering.TextureMap.Roughness, resourceManager.Textures.GetFromAlias("Roughness").Texture); uiMat.AddTexture((int)Rendering.TextureMap.Metallic, resourceManager.Textures.GetFromAlias("Metallic").Texture); Rendering.Model monkeyModel = new Rendering.Model(resourceManager.Meshes.GetFromAlias("Barrel").Mesh, pbrMat); Rendering.Model sphereModel = new Rendering.Model(resourceManager.Meshes.GetFromAlias("Sphere").Mesh, pbrMat); Rendering.Model planeModel = new Rendering.Model(resourceManager.Meshes.GetFromAlias("Plane").Mesh, pbrMat); sphere.Components.Create <ComponentSystem._ModelComponent>(); sphere.Components.Get <ComponentSystem._ModelComponent>().Model = sphereModel; testObject.Components.Create <ComponentSystem._ModelComponent>(); testObject.Components.Get <ComponentSystem._ModelComponent>().Model = monkeyModel; testUI.Components.Create <ComponentSystem._ModelComponent>(); testUI.Components.Get <ComponentSystem._ModelComponent>().Model = new Rendering.UI.UIRect(new RectangleF(3, 0, 256, 256), uiMat); groundPlane.Components.Create <ComponentSystem._ModelComponent>(); groundPlane.Components.Get <ComponentSystem._ModelComponent>().Model = planeModel; }
/// <summary> /// Refine the mesh groups based on the result of the delegate test method. /// </summary> /// <param name="meshList">The list of mesh groups.</param> /// <param name="sameGroupDelegate">The test delegate.</param> /// <returns>The new list of mesh groups.</returns> private List <GroupList <int, Mesh> > RefineGroups(Rendering.Model model, List <GroupList <int, Mesh> > meshList, SameGroup sameGroupDelegate) { var finalGroups = new List <GroupList <int, Mesh> >(); foreach (var meshGroup in meshList) { var updatedGroups = new List <GroupList <int, Mesh> >(); foreach (var mesh in meshGroup) { var createNewGroup = true; foreach (var sameParamsMeshes in updatedGroups) { if (sameGroupDelegate(model, sameParamsMeshes[0], mesh)) { sameParamsMeshes.Add(mesh); createNewGroup = false; break; } } if (createNewGroup) { var newGroup = new GroupList <int, Mesh> { Key = meshGroup.Key }; newGroup.Add(mesh); updatedGroups.Add(newGroup); } } finalGroups.AddRange(updatedGroups); } return(finalGroups); }
/// <summary> /// Compares the shadow options between the two meshes. /// </summary> /// <param name="baseMesh">The base mesh.</param> /// <param name="newMesh">The mesh to compare.</param> /// <param name="extra">Unused parameter.</param> /// <returns>True if the options are the same, false otherwise.</returns> private static bool CompareShadowOptions(Rendering.Model model, Mesh baseMesh, Mesh newMesh) { // TODO: Check is Model the same for the two mesh? var material1 = model.Materials.GetItemOrNull(baseMesh.MaterialIndex); var material2 = model.Materials.GetItemOrNull(newMesh.MaterialIndex); return(material1 == material2 || (material1 != null && material2 != null && material1.IsShadowCaster == material2.IsShadowCaster && material1.IsShadowReceiver == material2.IsShadowReceiver)); }
/// <summary> /// Compares the parameters of the two meshes. /// </summary> /// <param name="baseMesh">The base mesh.</param> /// <param name="newMesh">The mesh to compare.</param> /// <param name="extra">Unused parameter.</param> /// <returns>True if all the parameters are the same, false otherwise.</returns> private static bool CompareParameters(Rendering.Model model, Mesh baseMesh, Mesh newMesh) { var localParams = baseMesh.Parameters; if (localParams == null && newMesh.Parameters == null) { return(true); } if (localParams == null || newMesh.Parameters == null) { return(false); } return(IsSubsetOf(localParams, newMesh.Parameters) && IsSubsetOf(newMesh.Parameters, localParams)); }
/// <summary> /// Compares the parameters of the two meshes. /// </summary> /// <param name="baseMesh">The base mesh.</param> /// <param name="newMesh">The mesh to compare.</param> /// <param name="extra">Unused parameter.</param> /// <returns>True if all the parameters are the same, false otherwise.</returns> private static bool CompareParameters(Rendering.Model model, Mesh baseMesh, Mesh newMesh) { var localParams = baseMesh.Parameters; if (localParams == null && newMesh.Parameters == null) { return(true); } if (localParams == null || newMesh.Parameters == null) { return(false); } return(AreCollectionsEqual(localParams, newMesh.Parameters)); }
/// <summary> /// Create groups of mergeable meshes. /// </summary> /// <param name="model">The current model.</param> /// <param name="index">The index of the currently visited node.</param> /// <param name="nodeBlackList">List of the nodes that should be kept.</param> /// <param name="meshes">The meshes and their node index.</param> /// <param name="finalLists">List of mergeable meshes and their root node.</param> /// <returns>A list of mergeable meshes in progress.</returns> private Dictionary <int, List <Mesh> > GroupFromIndex(Rendering.Model model, int index, HashSet <int> nodeBlackList, List <Mesh> meshes, List <GroupList <int, Mesh> > finalLists) { var children = GetChildren(model.Hierarchy.Nodes, index); var materialGroups = new Dictionary <int, List <Mesh> >(); // Get the group from each child foreach (var child in children) { var newMaterialGroups = GroupFromIndex(model, child, nodeBlackList, meshes, finalLists); foreach (var group in newMaterialGroups) { if (!materialGroups.ContainsKey(group.Key)) { materialGroups.Add(group.Key, new List <Mesh>()); } materialGroups[group.Key].AddRange(group.Value); } } // Add the current node if it has a mesh foreach (var nodeMesh in meshes.Where(x => x.NodeIndex == index)) { var matId = nodeMesh.MaterialIndex; if (!materialGroups.ContainsKey(matId)) { materialGroups.Add(matId, new List <Mesh>()); } materialGroups[matId].Add(nodeMesh); } // Store the generated list as final if the node should be kept if (nodeBlackList.Contains(index) || index == 0) { foreach (var materialGroup in materialGroups) { var groupList = new GroupList <int, Mesh>(); groupList.Key = index; groupList.AddRange(materialGroup.Value); finalLists.Add(groupList); } materialGroups.Clear(); } return(materialGroups); }
public static void DrawModel(Rendering.Renderer rend) { Rendering.Model mtm = rend.model; Vector euler = rend.matrix.eulerAngles; Quaternion q = Quaternion.RotationYawPitchRoll(euler.y * Mathf.Deg2Rad, euler.x * Mathf.Deg2Rad, euler.z * Mathf.Deg2Rad); Matrix matrix = new Matrix(); matrix.AffineTransformation(rend.matrix.scale.y, Vector.zero, q, rend.matrix.position); for (int i = 0; i < mtm.materials.Length; i++) { device.SetTransform(TransformType.World, matrix); device.Material = mtm.materials[i].material; device.SetTexture(0, mtm.materials[i].texture); mtm.mesh.DrawSubset(i); } }
internal void Load() { Rendering.Model model = new Rendering.Model("Baby", "Phong"); objects.Add(model); }
private static void ProcessMaterial(ContentManager manager, ICollection <EntityChunk> chunks, MaterialInstance material, Rendering.Model prefabModel) { //we need to futher group by VertexDeclaration var meshes = new Dictionary <VertexDeclaration, MeshData>(); //actually create the mesh foreach (var chunk in chunks) { foreach (var modelMesh in chunk.Model.Meshes) { //process only right material if (modelMesh.MaterialIndex == chunk.MaterialIndex) { MeshData mesh; if (!meshes.TryGetValue(modelMesh.Draw.VertexBuffers[0].Declaration, out mesh)) { mesh = new MeshData { VertexStride = modelMesh.Draw.VertexBuffers[0].Stride }; meshes.Add(modelMesh.Draw.VertexBuffers[0].Declaration, mesh); } //vertexes var vertexBufferRef = AttachedReferenceManager.GetAttachedReference(modelMesh.Draw.VertexBuffers[0].Buffer); byte[] vertexData; if (vertexBufferRef.Data != null) { vertexData = ((BufferData)vertexBufferRef.Data).Content; } else if (!vertexBufferRef.Url.IsNullOrEmpty()) { var dataAsset = manager.Load <Graphics.Buffer>(vertexBufferRef.Url); vertexData = dataAsset.GetSerializationData().Content; } else { throw new Exception($"Failed to get Vertex BufferData for entity {chunk.Entity.Name}'s model."); } //transform the vertexes according to the entity var vertexDataCopy = vertexData.ToArray(); chunk.Entity.Transform.UpdateWorldMatrix(); //make sure matrix is computed modelMesh.Draw.VertexBuffers[0].TransformBuffer(vertexDataCopy, ref chunk.Entity.Transform.WorldMatrix); //add to the big single array var vertexes = vertexDataCopy .Skip(modelMesh.Draw.VertexBuffers[0].Offset) .Take(modelMesh.Draw.VertexBuffers[0].Count * modelMesh.Draw.VertexBuffers[0].Stride) .ToArray(); mesh.VertexData.AddRange(vertexes); //indices var indexBufferRef = AttachedReferenceManager.GetAttachedReference(modelMesh.Draw.IndexBuffer.Buffer); byte[] indexData; if (indexBufferRef.Data != null) { indexData = ((BufferData)indexBufferRef.Data).Content; } else if (!indexBufferRef.Url.IsNullOrEmpty()) { var dataAsset = manager.Load <Graphics.Buffer>(indexBufferRef.Url); indexData = dataAsset.GetSerializationData().Content; } else { throw new Exception("Failed to get Indices BufferData for entity {chunk.Entity.Name}'s model."); } var indexSize = modelMesh.Draw.IndexBuffer.Is32Bit ? sizeof(uint) : sizeof(ushort); var indices = indexData .Skip(modelMesh.Draw.IndexBuffer.Offset) .Take(modelMesh.Draw.IndexBuffer.Count * indexSize) .ToArray(); //todo this code is not optimal, use unsafe //must convert to 32bits if (indexSize == sizeof(ushort)) { var uintIndex = new List <byte>(); for (var i = 0; i < indices.Length; i += sizeof(ushort)) { var index = BitConverter.ToUInt16(indices, i); var bi = BitConverter.GetBytes((uint)index); uintIndex.Add(bi[0]); uintIndex.Add(bi[1]); uintIndex.Add(bi[2]); uintIndex.Add(bi[3]); } indices = uintIndex.ToArray(); } //need to offset the indices for (var i = 0; i < indices.Length; i += sizeof(uint)) { var index = BitConverter.ToUInt32(indices, i) + mesh.IndexOffset; var bi = BitConverter.GetBytes(index); indices[i + 0] = bi[0]; indices[i + 1] = bi[1]; indices[i + 2] = bi[2]; indices[i + 3] = bi[3]; } mesh.IndexOffset += modelMesh.Draw.VertexBuffers[0].Count; mesh.IndexData.AddRange(indices); } } } //Sort out material var matIndex = prefabModel.Materials.Count; prefabModel.Materials.Add(material); foreach (var meshData in meshes) { //todo need to take care of short index var vertexArray = meshData.Value.VertexData.ToArray(); var indexArray = meshData.Value.IndexData.ToArray(); var vertexCount = vertexArray.Length / meshData.Value.VertexStride; var indexCount = indexArray.Length / 4; var gpuMesh = new Mesh { Draw = new MeshDraw { PrimitiveType = PrimitiveType.TriangleList, DrawCount = indexCount, StartLocation = 0 }, MaterialIndex = matIndex }; var vertexBuffer = new BufferData(BufferFlags.VertexBuffer, new byte[vertexArray.Length]); var indexBuffer = new BufferData(BufferFlags.IndexBuffer, new byte[indexArray.Length]); var vertexBufferSerializable = vertexBuffer.ToSerializableVersion(); var indexBufferSerializable = indexBuffer.ToSerializableVersion(); Array.Copy(vertexArray, vertexBuffer.Content, vertexArray.Length); Array.Copy(indexArray, indexBuffer.Content, indexArray.Length); gpuMesh.Draw.VertexBuffers = new VertexBufferBinding[1]; gpuMesh.Draw.VertexBuffers[0] = new VertexBufferBinding(vertexBufferSerializable, meshData.Key, vertexCount); gpuMesh.Draw.IndexBuffer = new IndexBufferBinding(indexBufferSerializable, true, indexCount); prefabModel.Meshes.Add(gpuMesh); } }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var contentManager = new ContentManager(); var device = GraphicsDevice.New(); var fallbackMaterial = Material.New(device, new MaterialDescriptor { Attributes = { Diffuse = new MaterialDiffuseMapFeature(new ComputeTextureColor()), DiffuseModel = new MaterialDiffuseLambertModelFeature() } }); var loadSettings = new AssetManagerLoaderSettings { ContentFilter = AssetManagerLoaderSettings.NewContentFilterByType(typeof(Mesh), typeof(Skeleton), typeof(Material), typeof(Prefab)) }; Prefab prefab; if (AssetParameters.Prefab == null) { prefab = new Prefab(); } else { prefab = contentManager.Load <Prefab>(AssetParameters.Prefab.Location, loadSettings); if (prefab == null) { throw new Exception("Failed to load prefab."); } } var prefabModel = new Rendering.Model(); //The objective is to create 1 mesh per material/shadow params //1. We group by materials //2. Create a mesh per material (might need still more meshes if 16bit indexes or more then 32bit) var materials = new Dictionary <MaterialInstance, List <EntityChunk> >(); var validEntities = new List <Entity>(); foreach (var rootEntity in prefab.Entities) { //collect sub entities as well var collected = IterateTree(rootEntity, subEntity => subEntity.GetChildren()).ToArray(); //first pass, check if compatible with prefabmodel foreach (var subEntity in collected) { //todo for now we collect everything with a model component var modelComponent = subEntity.Get <ModelComponent>(); if (modelComponent == null || modelComponent.Skeleton.Nodes.Length != 1) { continue; } var modelAsset = contentManager.Load <Rendering.Model>(AttachedReferenceManager.GetUrl(modelComponent.Model), loadSettings); if (modelAsset == null || modelAsset.Meshes.Any(x => x.Draw.PrimitiveType != PrimitiveType.TriangleList || x.Draw.VertexBuffers == null || x.Draw.VertexBuffers.Length != 1) || modelAsset.Materials.Any(x => x.Material != null && x.Material.HasTransparency) || modelComponent.Materials.Any(x => x != null && x.HasTransparency)) //For now we limit only to TriangleList types and interleaved vertex buffers, also we skip transparent { commandContext.Logger.Info($"Skipped entity {subEntity.Name} since it's not compatible with PrefabModel."); continue; } validEntities.Add(subEntity); } } foreach (var subEntity in validEntities) { var modelComponent = subEntity.Get <ModelComponent>(); var modelAsset = contentManager.Load <Rendering.Model>(AttachedReferenceManager.GetUrl(modelComponent.Model), loadSettings); for (var index = 0; index < modelAsset.Materials.Count; index++) { var material = modelAsset.Materials[index]; var mat = ExtractMaterialInstance(material, index, modelComponent, fallbackMaterial); var chunk = new EntityChunk { Entity = subEntity, Model = modelAsset, MaterialIndex = index }; List <EntityChunk> entities; if (materials.TryGetValue(mat, out entities)) { entities.Add(chunk); } else { materials.Add(mat, new List <EntityChunk> { chunk }); } } } foreach (var material in materials) { ProcessMaterial(contentManager, material.Value, material.Key, prefabModel); } // split the meshes if necessary prefabModel.Meshes = SplitExtensions.SplitMeshes(prefabModel.Meshes, renderingSettings.DefaultGraphicsProfile > GraphicsProfile.Level_9_3); //handle boundng box/sphere var modelBoundingBox = prefabModel.BoundingBox; var modelBoundingSphere = prefabModel.BoundingSphere; foreach (var mesh in prefabModel.Meshes) { var vertexBuffers = mesh.Draw.VertexBuffers; if (vertexBuffers.Length > 0) { // Compute local mesh bounding box (no node transformation) var matrix = Matrix.Identity; mesh.BoundingBox = vertexBuffers[0].ComputeBounds(ref matrix, out mesh.BoundingSphere); // Compute model bounding box (includes node transformation) BoundingSphere meshBoundingSphere; var meshBoundingBox = vertexBuffers[0].ComputeBounds(ref matrix, out meshBoundingSphere); BoundingBox.Merge(ref modelBoundingBox, ref meshBoundingBox, out modelBoundingBox); BoundingSphere.Merge(ref modelBoundingSphere, ref meshBoundingSphere, out modelBoundingSphere); } mesh.Draw.CompactIndexBuffer(); } prefabModel.BoundingBox = modelBoundingBox; prefabModel.BoundingSphere = modelBoundingSphere; //save contentManager.Save(Url, prefabModel); device.Dispose(); return(Task.FromResult(ResultStatus.Successful)); }