public override IEnumerable <CompilerParameters> Generate(AssetCompilerContext context, CompilerParameters baseParameters, ILogger log) { var allMaterialParameters = new List <ParameterCollection>(); if (baseParameters.Get(MaterialAssetKeys.GenerateShader)) { var assetManager = new AssetManager(); var settings = new AssetManagerLoaderSettings() { ContentFilter = AssetManagerLoaderSettings.NewContentFilterByType(typeof(MaterialData)), }; var hashParameters = new HashSet <ObjectId>(); foreach (var materialAssetItem in context.Package.Assets.Where(item => item.Asset is MaterialAsset)) { var assetPath = materialAssetItem.Location.GetDirectoryAndFileName(); try { var materialData = assetManager.Load <MaterialData>(assetPath, settings); if (materialData != null && materialData.Parameters != null && materialData.Parameters.Count > 0) { var materialParameters = new ParameterCollection(); AddToParameters(materialData.Parameters, materialParameters); if (materialParameters.Count > 0) { byte[] buffer1; var id = ObjectId.FromObject(materialParameters, out buffer1); if (!hashParameters.Contains(id)) { hashParameters.Add(id); allMaterialParameters.Add(materialParameters); } } } } catch (Exception ex) { log.Error("Error while loading material [{0}]", ex, assetPath); } } } if (allMaterialParameters.Count != 0) { foreach (var materialParams in allMaterialParameters) { var compilerParameters = baseParameters.Clone(); materialParams.CopyTo(compilerParameters); yield return(compilerParameters); } } else { yield return(baseParameters.Clone()); } }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new AssetManager(); AssetParameters.ColliderShapes = AssetParameters.ColliderShapes.Where(x => x != null && (x.GetType() != typeof(ConvexHullColliderShapeDesc) || ((ConvexHullColliderShapeDesc)x).Model != null)).ToList(); //pre process special types foreach (var convexHullDesc in (from shape in AssetParameters.ColliderShapes let type = shape.GetType() where type == typeof(ConvexHullColliderShapeDesc) select shape) .Cast <ConvexHullColliderShapeDesc>()) { //decompose and fill vertex data var loadSettings = new AssetManagerLoaderSettings { ContentFilter = AssetManagerLoaderSettings.NewContentFilterByType(typeof(Mesh)) }; var modelAsset = assetManager.Load <Model>(AttachedReferenceManager.GetUrl(convexHullDesc.Model), loadSettings); if (modelAsset == null) { continue; } convexHullDesc.ConvexHulls = new List <List <List <Vector3> > >(); convexHullDesc.ConvexHullsIndices = new List <List <List <uint> > >(); commandContext.Logger.Info("Processing convex hull generation, this might take a while!"); var nodeTransforms = new List <Matrix>(); //pre-compute all node transforms, assuming nodes are ordered... see ModelViewHierarchyUpdater var nodesLength = modelAsset.Hierarchy.Nodes.Length; for (var i = 0; i < nodesLength; i++) { Matrix localMatrix; TransformComponent.CreateMatrixTRS( ref modelAsset.Hierarchy.Nodes[i].Transform.Translation, ref modelAsset.Hierarchy.Nodes[i].Transform.Rotation, ref modelAsset.Hierarchy.Nodes[i].Transform.Scaling, out localMatrix); Matrix worldMatrix; if (modelAsset.Hierarchy.Nodes[i].ParentIndex != -1) { var nodeTransform = nodeTransforms[modelAsset.Hierarchy.Nodes[i].ParentIndex]; Matrix.Multiply(ref localMatrix, ref nodeTransform, out worldMatrix); } else { worldMatrix = localMatrix; } nodeTransforms.Add(worldMatrix); } for (var i = 0; i < nodesLength; i++) { var i1 = i; if (modelAsset.Meshes.All(x => x.NodeIndex != i1)) { continue; // no geometry in the node } var combinedVerts = new List <float>(); var combinedIndices = new List <uint>(); var hullsList = new List <List <Vector3> >(); convexHullDesc.ConvexHulls.Add(hullsList); var indicesList = new List <List <uint> >(); convexHullDesc.ConvexHullsIndices.Add(indicesList); foreach (var meshData in modelAsset.Meshes.Where(x => x.NodeIndex == i1)) { var indexOffset = (uint)combinedVerts.Count / 3; var stride = meshData.Draw.VertexBuffers[0].Declaration.VertexStride; var vertexDataAsset = assetManager.Load <Graphics.Buffer>(AttachedReferenceManager.GetUrl(meshData.Draw.VertexBuffers[0].Buffer)); var vertexData = vertexDataAsset.GetSerializationData().Content; var vertexIndex = meshData.Draw.VertexBuffers[0].Offset; for (var v = 0; v < meshData.Draw.VertexBuffers[0].Count; v++) { var posMatrix = Matrix.Translation(new Vector3(BitConverter.ToSingle(vertexData, vertexIndex + 0), BitConverter.ToSingle(vertexData, vertexIndex + 4), BitConverter.ToSingle(vertexData, vertexIndex + 8))); Matrix rotatedMatrix; var nodeTransform = nodeTransforms[i]; Matrix.Multiply(ref posMatrix, ref nodeTransform, out rotatedMatrix); combinedVerts.Add(rotatedMatrix.TranslationVector.X); combinedVerts.Add(rotatedMatrix.TranslationVector.Y); combinedVerts.Add(rotatedMatrix.TranslationVector.Z); vertexIndex += stride; } var indexDataAsset = assetManager.Load <Graphics.Buffer>(AttachedReferenceManager.GetUrl(meshData.Draw.IndexBuffer.Buffer)); var indexData = indexDataAsset.GetSerializationData().Content; var indexIndex = meshData.Draw.IndexBuffer.Offset; for (var v = 0; v < meshData.Draw.IndexBuffer.Count; v++) { if (meshData.Draw.IndexBuffer.Is32Bit) { combinedIndices.Add(BitConverter.ToUInt32(indexData, indexIndex) + indexOffset); indexIndex += 4; } else { combinedIndices.Add(BitConverter.ToUInt16(indexData, indexIndex) + indexOffset); indexIndex += 2; } } } var decompositionDesc = new ConvexHullMesh.DecompositionDesc { VertexCount = (uint)combinedVerts.Count / 3, IndicesCount = (uint)combinedIndices.Count, Vertexes = combinedVerts.ToArray(), Indices = combinedIndices.ToArray(), Depth = convexHullDesc.Depth, PosSampling = convexHullDesc.PosSampling, PosRefine = convexHullDesc.PosRefine, AngleSampling = convexHullDesc.AngleSampling, AngleRefine = convexHullDesc.AngleRefine, Alpha = convexHullDesc.Alpha, Threshold = convexHullDesc.Threshold, SimpleHull = convexHullDesc.SimpleWrap }; lock (this) { convexHullMesh = new ConvexHullMesh(); } convexHullMesh.Generate(decompositionDesc); var count = convexHullMesh.Count; commandContext.Logger.Info("Node generated " + count + " convex hulls"); var vertexCountHull = 0; for (uint h = 0; h < count; h++) { float[] points; convexHullMesh.CopyPoints(h, out points); var pointList = new List <Vector3>(); for (var v = 0; v < points.Length; v += 3) { var vert = new Vector3(points[v + 0], points[v + 1], points[v + 2]); pointList.Add(vert); vertexCountHull++; } hullsList.Add(pointList); uint[] indices; convexHullMesh.CopyIndices(h, out indices); for (var t = 0; t < indices.Length; t += 3) { Utilities.Swap(ref indices[t], ref indices[t + 2]); } var indexList = new List <uint>(indices); indicesList.Add(indexList); } lock (this) { convexHullMesh.Dispose(); convexHullMesh = null; } commandContext.Logger.Info("For a total of " + vertexCountHull + " vertexes"); } } var runtimeShape = new PhysicsColliderShape { Descriptions = AssetParameters.ColliderShapes }; assetManager.Save(Url, runtimeShape); return(Task.FromResult(ResultStatus.Successful)); }
public override IEnumerable <CompilerParameters> Generate(AssetCompilerContext context, CompilerParameters baseParameters, ILogger log) { // Cache all the entity parameters once List <EntityParameters> entityParametersList; var entityParametersSet = (ConcurrentDictionary <Guid, List <EntityParameters> >)context.Properties.GetOrAdd(EntityParametersKey, key => new ConcurrentDictionary <Guid, List <EntityParameters> >()); entityParametersList = entityParametersSet.GetOrAdd(context.Package.Id, key => { var assetManager = new AssetManager(); var settings = new AssetManagerLoaderSettings() { ContentFilter = AssetManagerLoaderSettings.NewContentFilterByType(typeof(ModelData), typeof(MeshData), typeof(MaterialData), typeof(LightingConfigurationsSetData)), }; var allEntityParameters = new List <EntityParameters>(); foreach (var entityAssetItem in context.Package.Assets.Where(item => item.Asset is EntityAsset)) { var assetPath = entityAssetItem.Location.GetDirectoryAndFileName(); try { var entity = assetManager.Load <EntityData>(assetPath, settings); foreach (var modelComponent in entity.Components.Select(x => x.Value).OfType <ModelComponentData>()) { foreach (var meshData in modelComponent.Model.Value.Meshes) { var lightingParameters = GetLightingParameters(meshData); var materialParameters = GetMeshMaterialParameters(meshData); if (lightingParameters == null || lightingParameters.Count == 0) { EntityParameters entityParameters; entityParameters.MaterialParameters = materialParameters; entityParameters.ModelParameters = modelComponent.Parameters; entityParameters.MeshParameters = meshData != null ? meshData.Parameters : null; entityParameters.LightingParameters = null; allEntityParameters.Add(entityParameters); } else { foreach (var lightConfig in lightingParameters) { EntityParameters entityParameters; entityParameters.MaterialParameters = materialParameters; entityParameters.ModelParameters = modelComponent.Parameters; entityParameters.MeshParameters = meshData != null ? meshData.Parameters : null; entityParameters.LightingParameters = lightConfig; allEntityParameters.Add(entityParameters); } } } } } catch (Exception ex) { log.Error("Error while loading model mesh [{0}]", ex, assetPath); } } return(allEntityParameters); }); var useMeshParameters = baseParameters.Get(MeshKeys.UseParameters); var useMaterialParameters = baseParameters.Get(MaterialAssetKeys.UseParameters) && !baseParameters.Get(MaterialAssetKeys.GenerateShader); if ((useMeshParameters || useMaterialParameters) && entityParametersList.Count != 0) { var hashParameters = new HashSet <ObjectId>(); foreach (var entityParameters in entityParametersList) { // Add parameters in this order // 1. Material // 2. ModelComponent (Entity) // 3. Mesh // 4. Lighting var newParameters = new ParameterCollection(); if (useMaterialParameters) { AddToParameters(entityParameters.MaterialParameters, newParameters); } AddToParameters(entityParameters.ModelParameters, newParameters); if (useMeshParameters) { AddToParameters(entityParameters.MeshParameters, newParameters); } AddToParameters(entityParameters.LightingParameters, newParameters); byte[] buffer1; var id = ObjectId.FromObject(newParameters, out buffer1); if (!hashParameters.Contains(id)) { hashParameters.Add(id); var compilerParameters = baseParameters.Clone(); newParameters.CopyTo(compilerParameters); yield return(compilerParameters); } } } else { yield return(baseParameters.Clone()); } }
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)); }