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 ContentManagerLoaderSettings { ContentFilter = ContentManagerLoaderSettings.NewContentFilterByType(typeof(Mesh), typeof(Material)) }; IList <Entity> allEntities = new List <Entity>(); if (Parameters.Prefab != null) { var prefab = Package.Session.FindAssetFromProxyObject(Parameters.Prefab)?.Asset as PrefabAsset; if (prefab != null) { allEntities = prefab.Hierarchy.Parts.Values.Select(x => x.Entity).ToList(); } } var prefabModel = new 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 loadedModel = new List <Model>(); foreach (var subEntity in allEntities) { var modelComponent = subEntity.Get <ModelComponent>(); if (modelComponent?.Model == null || (modelComponent.Skeleton != null && modelComponent.Skeleton.Nodes.Length != 1) || !modelComponent.Enabled) { continue; } var modelAsset = Package.Session.FindAssetFromProxyObject(modelComponent.Model); if (modelAsset == null) { continue; } var model = contentManager.Load <Model>(modelAsset.Location, loadSettings); loadedModel.Add(model); if (model == null || model.Meshes.Any(x => x.Draw.PrimitiveType != PrimitiveType.TriangleList || x.Draw.VertexBuffers == null || x.Draw.VertexBuffers.Length != 1) || model.Materials.Any(x => x.Material != null && x.Material.Passes.Any(pass => pass.HasTransparency)) || modelComponent.Materials.Values.Any(x => x.Passes.Any(pass => pass.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; } for (var index = 0; index < model.Materials.Count; index++) { var material = model.Materials[index]; var mat = ExtractMaterialInstance(material, index, modelComponent, fallbackMaterial); var chunk = new EntityChunk { Entity = subEntity, Model = model, MaterialIndex = index }; if (materials.TryGetValue(mat, out var 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); foreach (var model in loadedModel.NotNull()) { contentManager.Unload(model); } device.Dispose(); return(Task.FromResult(ResultStatus.Successful)); }
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 ContentManagerLoaderSettings { ContentFilter = ContentManagerLoaderSettings.NewContentFilterByType(typeof(Mesh), typeof(Skeleton), typeof(Material), typeof(Prefab)) }; Prefab prefab; if (Parameters.Prefab == null) { prefab = new Prefab(); } else { prefab = contentManager.Load <Prefab>(Parameters.Prefab.Location, loadSettings); if (prefab == null) { throw new Exception("Failed to load prefab."); } } var prefabModel = new 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?.Model == null || (modelComponent.Skeleton != null && modelComponent.Skeleton.Nodes.Length != 1)) { continue; } var modelAsset = contentManager.Load <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.Values.Any(x => 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 <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)); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new ContentManager(); // Cloned list of collider shapes var descriptions = Parameters.ColliderShapes.ToList(); Parameters.ColliderShapes = Parameters.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 Parameters.ColliderShapes let type = shape.GetType() where type == typeof(ConvexHullColliderShapeDesc) select shape) .Cast <ConvexHullColliderShapeDesc>()) { // Clone the convex hull shape description so the fields that should not be serialized can be cleared (Model in this case) ConvexHullColliderShapeDesc convexHullDescClone = new ConvexHullColliderShapeDesc { Scaling = convexHullDesc.Scaling, LocalOffset = convexHullDesc.LocalOffset, LocalRotation = convexHullDesc.LocalRotation, Depth = convexHullDesc.Depth, PosSampling = convexHullDesc.PosSampling, AngleSampling = convexHullDesc.AngleSampling, PosRefine = convexHullDesc.PosRefine, AngleRefine = convexHullDesc.AngleRefine, Alpha = convexHullDesc.Alpha, Threshold = convexHullDesc.Threshold, }; // Replace shape in final result with cloned description int replaceIndex = descriptions.IndexOf(convexHullDesc); descriptions[replaceIndex] = convexHullDescClone; var loadSettings = new ContentManagerLoaderSettings { ContentFilter = ContentManagerLoaderSettings.NewContentFilterByType(typeof(Mesh), typeof(Skeleton)) }; var modelAsset = assetManager.Load <Model>(AttachedReferenceManager.GetUrl(convexHullDesc.Model), loadSettings); if (modelAsset == null) { continue; } convexHullDescClone.ConvexHulls = new List <List <List <Vector3> > >(); convexHullDescClone.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 if (modelAsset.Skeleton == null) { Matrix baseMatrix; Matrix.Transformation(ref convexHullDescClone.Scaling, ref convexHullDescClone.LocalRotation, ref convexHullDescClone.LocalOffset, out baseMatrix); nodeTransforms.Add(baseMatrix); } else { var nodesLength = modelAsset.Skeleton.Nodes.Length; for (var i = 0; i < nodesLength; i++) { Matrix localMatrix; Matrix.Transformation( ref modelAsset.Skeleton.Nodes[i].Transform.Scale, ref modelAsset.Skeleton.Nodes[i].Transform.Rotation, ref modelAsset.Skeleton.Nodes[i].Transform.Position, out localMatrix); Matrix worldMatrix; if (modelAsset.Skeleton.Nodes[i].ParentIndex != -1) { var nodeTransform = nodeTransforms[modelAsset.Skeleton.Nodes[i].ParentIndex]; Matrix.Multiply(ref localMatrix, ref nodeTransform, out worldMatrix); } else { worldMatrix = localMatrix; } if (i == 0) { Matrix baseMatrix; Matrix.Transformation(ref convexHullDescClone.Scaling, ref convexHullDescClone.LocalRotation, ref convexHullDescClone.LocalOffset, out baseMatrix); nodeTransforms.Add(baseMatrix * worldMatrix); } else { nodeTransforms.Add(worldMatrix); } } } for (var i = 0; i < nodeTransforms.Count; 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> >(); convexHullDescClone.ConvexHulls.Add(hullsList); var indicesList = new List <List <uint> >(); convexHullDescClone.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 vertexBufferRef = AttachedReferenceManager.GetAttachedReference(meshData.Draw.VertexBuffers[0].Buffer); byte[] vertexData; if (vertexBufferRef.Data != null) { vertexData = ((BufferData)vertexBufferRef.Data).Content; } else if (!vertexBufferRef.Url.IsNullOrEmpty()) { var dataAsset = assetManager.Load <Buffer>(vertexBufferRef.Url); vertexData = dataAsset.GetSerializationData().Content; } else { continue; } 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 indexBufferRef = AttachedReferenceManager.GetAttachedReference(meshData.Draw.IndexBuffer.Buffer); byte[] indexData; if (indexBufferRef.Data != null) { indexData = ((BufferData)indexBufferRef.Data).Content; } else if (!indexBufferRef.Url.IsNullOrEmpty()) { var dataAsset = assetManager.Load <Buffer>(indexBufferRef.Url); indexData = dataAsset.GetSerializationData().Content; } else { throw new Exception("Failed to find index buffer while building a convex hull."); } 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 }; var 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); } convexHullMesh.Dispose(); commandContext.Logger.Info("For a total of " + vertexCountHull + " vertexes"); } } var runtimeShape = new PhysicsColliderShape { Descriptions = descriptions }; assetManager.Save(Url, runtimeShape); return(Task.FromResult(ResultStatus.Successful)); }
public async Task Run() { Services = new ServiceRegistry(); // Database file provider Services.AddService <IDatabaseFileProviderService>(new DatabaseFileProviderService(new DatabaseFileProvider(ObjectDatabase.CreateDefaultDatabase()))); // Content manager Content = new ContentManager(Services); Services.AddService <IContentManager>(Content); Services.AddService(Content); //Services.AddService<IGraphicsDeviceService>(new GraphicsDeviceServiceLocal(null)); // Game systems var gameSystems = new GameSystemCollection(Services); Services.AddService <IGameSystemCollection>(gameSystems); gameSystems.Initialize(); // Load scene (physics only) var loadSettings = new ContentManagerLoaderSettings { // Ignore all references (Model, etc...) ContentFilter = ContentManagerLoaderSettings.NewContentFilterByType() }; var scene = await Content.LoadAsync <Scene>("MainScene", loadSettings); var sceneInstance = new SceneInstance(Services, scene, ExecutionMode.None); var sceneSystem = new SceneSystem(Services) { SceneInstance = sceneInstance, }; Services.AddService(sceneSystem); var physics = new PhysicsProcessor(); sceneInstance.Processors.Add(physics); var socket = new SimpleSocket(); socket.Connected += clientSocket => { Console.WriteLine("Client connected"); var reader = new BinarySerializationReader(clientSocket.ReadStream); while (true) { // Receive ray start/end var start = reader.Read <Vector3>(); var end = reader.Read <Vector3>(); // Raycast var result = physics.Simulation.Raycast(start, end); Console.WriteLine($"Performing raycast: {(result.Succeeded ? "hit" : "miss")}"); // Send result clientSocket.WriteStream.WriteByte((byte)(result.Succeeded ? 1 : 0)); clientSocket.WriteStream.Flush(); } }; await socket.StartServer(2655, false); Console.WriteLine("Server listening, press a key to exit"); Console.ReadKey(); }