protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var result = new GameSettings { PackageId = package.Id, DefaultSceneUrl = AssetParameters.DefaultScene != null?AttachedReferenceManager.GetUrl(AssetParameters.DefaultScene) : null, DefaultBackBufferWidth = AssetParameters.BackBufferWidth, DefaultBackBufferHeight = AssetParameters.BackBufferHeight, DefaultGraphicsProfileUsed = AssetParameters.DefaultGraphicsProfile, ColorSpace = AssetParameters.ColorSpace, EffectCompilation = package.UserSettings.GetValue(GameUserSettings.Effect.EffectCompilation), RecordUsedEffects = package.UserSettings.GetValue(GameUserSettings.Effect.RecordUsedEffects) }; // TODO: Platform-specific settings have priority //if (platform != PlatformType.Shared) //{ // var platformProfile = package.Profiles.FirstOrDefault(o => o.Platform == platform); // if (platformProfile != null && platformProfile.Properties.ContainsKey(DefaultGraphicsProfile)) // { // var customProfile = platformProfile.Properties.Get(DefaultGraphicsProfile); // result.DefaultGraphicsProfileUsed = customProfile; // } //} var assetManager = new AssetManager(); assetManager.Save(Url, result); return(Task.FromResult(ResultStatus.Successful)); }
public override IEnumerable <ObjectUrl> GetInputFiles(AssetItem assetItem) { var asset = (ColliderShapeAsset)assetItem.Asset; foreach (var desc in asset.ColliderShapes) { if (desc is ConvexHullColliderShapeDesc convexHullDesc) { if (convexHullDesc.Model is not null) { var url = AttachedReferenceManager.GetUrl(convexHullDesc.Model); if (!string.IsNullOrEmpty(url)) { yield return(new ObjectUrl(UrlType.Content, url)); } } } else if (desc is HeightfieldColliderShapeDesc heightfieldDesc) { if (heightfieldDesc.HeightStickArraySource is HeightStickArraySourceFromHeightmap heightmapSource && heightmapSource.Heightmap is not null) { var url = AttachedReferenceManager.GetUrl(heightmapSource.Heightmap); if (!string.IsNullOrEmpty(url)) { yield return(new ObjectUrl(UrlType.Content, url)); } } } } }
public void SimpleSaveData() { var b1 = new B(); b1.A = new A { I = 18 }; var databaseProvider = CreateDatabaseProvider(); var assetManager1 = new ContentManager(databaseProvider); var assetManager2 = new ContentManager(databaseProvider); assetManager1.Save("test", b1); Assert.NotNull(AttachedReferenceManager.GetUrl(b1.A)); var b2 = new B(); b2.A = new A(); var attachedReference = AttachedReferenceManager.GetOrCreateAttachedReference(b2.A); attachedReference.Url = AttachedReferenceManager.GetUrl(b1.A); attachedReference.IsProxy = true; assetManager1.Save("test2", b2); var b3 = assetManager2.Load <B>("test2"); Assert.Equal(b1.A.I, b3.A.I); }
public void SimpleLoadData() { var b1 = new B(); b1.A = new A { I = 18 }; var assetManager1 = new AssetManager(); var assetManager2 = new AssetManager(); var assetManager3 = new AssetManager(); assetManager1.Save("test", b1); // Use new asset manager var b2 = assetManager2.Load <B>("test"); Assert.That(b2, Is.Not.EqualTo(b1)); Assert.That(b2.A.I, Is.EqualTo(b1.A.I)); // Try to load without references var b3 = assetManager3.Load <B>("test", new AssetManagerLoaderSettings { LoadContentReferences = false }); Assert.That(b3, Is.Not.EqualTo(b1)); // b3.A should be default initialized Assert.That(b3.A.I, Is.EqualTo(0)); Assert.That(AttachedReferenceManager.GetUrl(b3.A), Is.Not.Null); }
protected override IEnumerable <ObjectUrl> GetInputFilesImpl() { // Add game settings asset URL yield return(new ObjectUrl(UrlType.Content, GameSettingsAsset.GameSettingsLocation)); var gameSettings = context.GetGameSettingsAsset(); var defaultSceneUrl = gameSettings.DefaultScene != null?AttachedReferenceManager.GetUrl(gameSettings.DefaultScene) : null; if (defaultSceneUrl == null) { yield break; } // Add scene yield return(new ObjectUrl(UrlType.Content, defaultSceneUrl)); // And all its dependencies (TODO: restrict ourselves on what affect rendering?) var sceneAssetItem = package.Session.FindAsset(defaultSceneUrl); var dependencies = package.Session.DependencyManager.ComputeDependencies(sceneAssetItem.Id, AssetDependencySearchOptions.Out | AssetDependencySearchOptions.Recursive, ContentLinkType.Reference); foreach (var dependency in dependencies.LinksOut) { yield return(new ObjectUrl(UrlType.Content, dependency.Item.Location)); } }
public void SimpleSaveData() { var b1 = new B(); b1.A = new A { I = 18 }; var assetManager1 = new AssetManager(); var assetManager2 = new AssetManager(); assetManager1.Save("test", b1); Assert.That(AttachedReferenceManager.GetUrl(b1.A), Is.Not.Null); var b2 = new B(); b2.A = new A(); var attachedReference = AttachedReferenceManager.GetOrCreateAttachedReference(b2.A); attachedReference.Url = AttachedReferenceManager.GetUrl(b1.A); attachedReference.IsProxy = true; assetManager1.Save("test2", b2); var b3 = assetManager2.Load <B>("test2"); Assert.That(b3.A.I, Is.EqualTo(b1.A.I)); }
/// <inheritdoc/> protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var gameSettings = context.GetGameSettingsAsset(); // Find default scene URL var defaultSceneUrl = gameSettings.DefaultScene != null?AttachedReferenceManager.GetUrl(gameSettings.DefaultScene) : null; if (defaultSceneUrl == null) { return(Task.FromResult(ResultStatus.Successful)); } var baseUrl = new UFile(defaultSceneUrl).GetParent(); try { commandContext.Logger.Info($"Trying to compile effects for scene '{defaultSceneUrl}'"); using (var sceneRenderer = new SceneRenderer(gameSettings)) { // Effect can be compiled asynchronously (since we don't have any fallback, they will have to be compiled in the same frame anyway) // Also set the file provider to the current transaction ((EffectCompilerCache)sceneRenderer.EffectSystem.Compiler).CompileEffectAsynchronously = true; ((EffectCompilerCache)sceneRenderer.EffectSystem.Compiler).FileProvider = MicrothreadLocalDatabases.DatabaseFileProvider; ((EffectCompilerCache)sceneRenderer.EffectSystem.Compiler).CurrentCache = EffectBytecodeCacheLoadSource.StartupCache; sceneRenderer.EffectSystem.EffectUsed += (effectCompileRequest, result) => compilerResult.BuildSteps.Add(EffectCompileCommand.FromRequest(context, package, baseUrl, effectCompileRequest)); sceneRenderer.GameSystems.LoadContent(); // Load the scene var scene = sceneRenderer.ContentManager.Load <Scene>(defaultSceneUrl); sceneRenderer.SceneSystem.SceneInstance = new SceneInstance(sceneRenderer.Services, scene, ExecutionMode.EffectCompile); // Disable culling sceneRenderer.SceneSystem.SceneInstance.VisibilityGroups.CollectionChanged += (sender, e) => { if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { ((VisibilityGroup)e.Item).DisableCulling = true; } }; // Update and draw // This will force effects to be generated and saved in the object database var time = new GameTime(); sceneRenderer.GameSystems.Update(time); sceneRenderer.GraphicsContext.ResourceGroupAllocator.Reset(sceneRenderer.GraphicsContext.CommandList); sceneRenderer.GameSystems.Draw(time); } } catch (Exception e) { commandContext.Logger.Warning($"Could not compile effects for scene '{defaultSceneUrl}': {e.Message + e.StackTrace}", e); } return(Task.FromResult(ResultStatus.Successful)); }
public override IEnumerable <ObjectUrl> GetInputFiles(AssetItem assetItem) { var asset = (NavigationMeshAsset)assetItem.Asset; if (asset.Scene != null) { string sceneUrl = AttachedReferenceManager.GetUrl(asset.Scene); var sceneAsset = (SceneAsset)assetItem.Package.Session.FindAsset(sceneUrl)?.Asset; if (sceneAsset == null) { yield break; } var sceneEntities = sceneAsset.Hierarchy.Parts.Select(x => x.Value.Entity).ToList(); foreach (var entity in sceneEntities) { var collider = entity.Get <StaticColliderComponent>(); // Only process enabled colliders bool colliderEnabled = collider != null && ((CollisionFilterGroupFlags)collider.CollisionGroup & asset.IncludedCollisionGroups) != 0 && collider.Enabled; if (colliderEnabled) // Removed or disabled { foreach (var desc in collider.ColliderShapes) { var shapeAssetDesc = desc as ColliderShapeAssetDesc; if (shapeAssetDesc?.Shape != null) { var assetReference = AttachedReferenceManager.GetAttachedReference(shapeAssetDesc.Shape); if (assetReference != null) { yield return(new ObjectUrl(UrlType.Content, assetReference.Url)); } } else if (desc is HeightfieldColliderShapeDesc) { var heightfieldDesc = desc as HeightfieldColliderShapeDesc; var heightmapSource = heightfieldDesc?.HeightStickArraySource as HeightStickArraySourceFromHeightmap; if (heightmapSource?.Heightmap != null) { var url = AttachedReferenceManager.GetUrl(heightmapSource.Heightmap); if (!string.IsNullOrEmpty(url)) { yield return(new ObjectUrl(UrlType.Content, url)); } } } } } } } }
private void EnsureClonedSceneAndHash() { if (!sceneCloned) { // Hash relevant scene objects if (asset.Scene != null) { string sceneUrl = AttachedReferenceManager.GetUrl(asset.Scene); var sceneAsset = (SceneAsset)package.Session.FindAsset(sceneUrl)?.Asset; // Clone scene asset because we update the world transformation matrices clonedSceneAsset = (SceneAsset)AssetCloner.Clone(sceneAsset); // Turn the entire entity hierarchy into a single list sceneEntities = clonedSceneAsset.Hierarchy.Parts.Select(x => x.Entity).ToList(); sceneHash = 0; foreach (var entity in sceneEntities) { StaticColliderComponent collider = entity.Get <StaticColliderComponent>(); // Only process enabled colliders bool colliderEnabled = collider != null && ((CollisionFilterGroupFlags)collider.CollisionGroup & asset.IncludedCollisionGroups) != 0 && collider.Enabled; if (colliderEnabled) // Removed or disabled { // Update world transform before hashing entity.Transform.UpdateWorldMatrix(); // Load collider shape assets since the scene asset is being used, which does not have these loaded by default foreach (var desc in collider.ColliderShapes) { var shapeAssetDesc = desc as ColliderShapeAssetDesc; if (shapeAssetDesc?.Shape != null) { var assetReference = AttachedReferenceManager.GetAttachedReference(shapeAssetDesc.Shape); PhysicsColliderShape loadedColliderShape; if (!loadedColliderShapes.TryGetValue(assetReference.Url, out loadedColliderShape)) { loadedColliderShape = contentManager.Load <PhysicsColliderShape>(assetReference.Url); loadedColliderShapes.Add(assetReference.Url, loadedColliderShape); // Store where we loaded the shapes from } shapeAssetDesc.Shape = loadedColliderShape; } } // Finally compute the hash for this collider sceneHash += NavigationMeshBuildUtils.HashEntityCollider(collider); } } } sceneCloned = true; } }
private IModelAsset GetReferencedModel() { var modelReference = entity.AssetSideEntity.Get <ModelComponent>()?.Model; if (modelReference == null) { return(null); } var modelUrl = AttachedReferenceManager.GetUrl(modelReference); return(entity.Editor.Session.AllAssets.FirstOrDefault(x => x.Url == modelUrl)?.Asset as IModelAsset); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var result = new GameSettings { PackageName = package.Meta.Name, DefaultSceneUrl = Parameters.DefaultScene != null?AttachedReferenceManager.GetUrl(Parameters.DefaultScene) : null, DefaultGraphicsCompositorUrl = Parameters.GraphicsCompositor != null?AttachedReferenceManager.GetUrl(Parameters.GraphicsCompositor) : null, SplashScreenUrl = Parameters.SplashScreenTexture != null && (compilationMode == CompilationMode.Release || compilationMode == CompilationMode.AppStore) ? AttachedReferenceManager.GetUrl(Parameters.SplashScreenTexture) : null, SplashScreenColor = Parameters.SplashScreenColor, DoubleViewSplashScreen = Parameters.DoubleViewSplashScreen, EffectCompilation = package.UserSettings.GetValue(GameUserSettings.Effect.EffectCompilation), RecordUsedEffects = package.UserSettings.GetValue(GameUserSettings.Effect.RecordUsedEffects), Configurations = new PlatformConfigurations(), CompilationMode = compilationMode }; //start from the default platform and go down overriding foreach (var configuration in Parameters.Defaults.Where(x => !x.OfflineOnly)) { result.Configurations.Configurations.Add(new ConfigurationOverride { Platforms = ConfigPlatforms.None, SpecificFilter = -1, Configuration = configuration }); } foreach (var configurationOverride in Parameters.Overrides.Where(x => x.Configuration != null && !x.Configuration.OfflineOnly)) { result.Configurations.Configurations.Add(configurationOverride); } result.Configurations.PlatformFilters = Parameters.PlatformFilters; //make sure we modify platform specific files to set the wanted orientation if (package.Container is SolutionProject solutionProject) { SetPlatformOrientation(solutionProject, Parameters.GetOrCreate <RenderingSettings>().DisplayOrientation); } var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); assetManager.Save(Url, result); return(Task.FromResult(ResultStatus.Successful)); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var result = new GameSettings { PackageId = package.Id, PackageName = package.Meta.Name, DefaultSceneUrl = AssetParameters.DefaultScene != null?AttachedReferenceManager.GetUrl(AssetParameters.DefaultScene) : null, EffectCompilation = package.UserSettings.GetValue(GameUserSettings.Effect.EffectCompilation), RecordUsedEffects = package.UserSettings.GetValue(GameUserSettings.Effect.RecordUsedEffects), Configurations = new PlatformConfigurations(), CompilationMode = compilationMode }; //start from the default platform and go down overriding foreach (var configuration in AssetParameters.Defaults.Where(x => !x.OfflineOnly)) { result.Configurations.Configurations.Add(new ConfigurationOverride { Platforms = ConfigPlatforms.None, SpecificFilter = -1, Configuration = configuration }); } foreach (var configurationOverride in AssetParameters.Overrides.Where(x => x.Configuration != null && !x.Configuration.OfflineOnly)) { result.Configurations.Configurations.Add(configurationOverride); } result.Configurations.PlatformFilters = AssetParameters.PlatformFilters; //make sure we modify platform specific files to set the wanted orientation SetPlatformOrientation(package, platform, AssetParameters.Get <RenderingSettings>().DisplayOrientation); var assetManager = new ContentManager(); assetManager.Save(Url, result); return(Task.FromResult(ResultStatus.Successful)); }
public override IEnumerable <ObjectUrl> GetInputFiles(AssetItem assetItem) { var asset = (ColliderShapeAsset)assetItem.Asset; foreach (var desc in asset.ColliderShapes) { if (desc is ConvexHullColliderShapeDesc) { var convexHullDesc = desc as ConvexHullColliderShapeDesc; if (convexHullDesc.Model != null) { var url = AttachedReferenceManager.GetUrl(convexHullDesc.Model); if (!string.IsNullOrEmpty(url)) { yield return(new ObjectUrl(UrlType.Content, url)); } } } } }
public override IEnumerable <ObjectUrl> GetInputFiles(AssetItem assetItem) { var asset = (NavigationMeshAsset)assetItem.Asset; if (asset.Scene != null) { string sceneUrl = AttachedReferenceManager.GetUrl(asset.Scene); var sceneAsset = (SceneAsset)assetItem.Package.Session.FindAsset(sceneUrl)?.Asset; if (sceneAsset == null) { yield break; } var sceneEntities = sceneAsset.Hierarchy.Parts.Select(x => x.Value.Entity).ToList(); foreach (var entity in sceneEntities) { var collider = entity.Get <StaticColliderComponent>(); // Only process enabled colliders // TODO: Update navmesh to use the new collision types bool colliderEnabled = collider != null && collider.Enabled; //((CollisionFilterGroupFlags)collider.CollisionGroup & asset.IncludedCollisionGroups) != 0 && collider.Enabled; if (colliderEnabled) // Removed or disabled { foreach (var desc in collider.ColliderShapes) { var shapeAssetDesc = desc as ColliderShapeAssetDesc; if (shapeAssetDesc?.Shape != null) { var assetReference = AttachedReferenceManager.GetAttachedReference(shapeAssetDesc.Shape); if (assetReference != null) { yield return(new ObjectUrl(UrlType.Content, assetReference.Url)); } } } } } } }
public override IEnumerable <ObjectUrl> GetInputFiles(AssetItem assetItem) { var asset = (ColliderShapeAsset)assetItem.Asset; foreach (var desc in asset.ColliderShapes) { if (desc is ConvexHullColliderShapeDesc) { var convexHullDesc = desc as ConvexHullColliderShapeDesc; if (convexHullDesc.Model != null) { var url = AttachedReferenceManager.GetUrl(convexHullDesc.Model); if (!string.IsNullOrEmpty(url)) { yield return(new ObjectUrl(UrlType.Content, url)); } } } else if (desc is HeightfieldColliderShapeDesc) { var heightfieldDesc = desc as HeightfieldColliderShapeDesc; var initialHeights = heightfieldDesc?.InitialHeights as HeightfieldHeightDataFromHeightmap; if (initialHeights?.Heightmap != null) { var url = AttachedReferenceManager.GetUrl(initialHeights.Heightmap); if (!string.IsNullOrEmpty(url)) { yield return(new ObjectUrl(UrlType.Content, url)); } } } } }
private void EnsureClonedSceneAndHash() { if (!sceneCloned) { // Hash relevant scene objects if (asset.Scene != null) { string sceneUrl = AttachedReferenceManager.GetUrl(asset.Scene); var sceneAsset = (SceneAsset)AssetFinder.FindAsset(sceneUrl)?.Asset; // Clone scene asset because we update the world transformation matrices clonedSceneAsset = (SceneAsset)AssetCloner.Clone(sceneAsset); // Turn the entire entity hierarchy into a single list var sceneEntities = clonedSceneAsset.Hierarchy.Parts.Select(x => x.Value.Entity).ToList(); sceneHash = 0; foreach (var entity in sceneEntities) { // Collect bounding box entities NavigationBoundingBoxComponent boundingBoxComponent = entity.Get <NavigationBoundingBoxComponent>(); // Collect static collider entities StaticColliderComponent colliderComponent = entity.Get <StaticColliderComponent>(); if (boundingBoxComponent == null && colliderComponent == null) { continue; } // Update world transform entity.Transform.UpdateWorldMatrix(); if (boundingBoxComponent != null) { Vector3 scale; Quaternion rotation; Vector3 translation; boundingBoxComponent.Entity.Transform.WorldMatrix.Decompose(out scale, out rotation, out translation); var boundingBox = new BoundingBox(translation - boundingBoxComponent.Size * scale, translation + boundingBoxComponent.Size * scale); boundingBoxes.Add(boundingBox); // Hash collider for ComputeParameterHash sceneHash = (sceneHash * 397) ^ boundingBox.GetHashCode(); } if (colliderComponent != null) { staticColliderDatas.Add(new StaticColliderData { Component = colliderComponent }); if (colliderComponent.Enabled && !colliderComponent.IsTrigger && ((int)asset.IncludedCollisionGroups & (int)colliderComponent.CollisionGroup) != 0) { // Load collider shape assets since the scene asset is being used, which does not have these loaded by default foreach (var desc in colliderComponent.ColliderShapes) { var shapeAssetDesc = desc as ColliderShapeAssetDesc; if (shapeAssetDesc?.Shape != null) { var assetReference = AttachedReferenceManager.GetAttachedReference(shapeAssetDesc.Shape); PhysicsColliderShape loadedColliderShape; if (!loadedColliderShapes.TryGetValue(assetReference.Url, out loadedColliderShape)) { loadedColliderShape = contentManager.Load <PhysicsColliderShape>(assetReference.Url); loadedColliderShapes.Add(assetReference.Url, loadedColliderShape); // Store where we loaded the shapes from } shapeAssetDesc.Shape = loadedColliderShape; } } } // Hash collider for ComputeParameterHash sceneHash = (sceneHash * 397) ^ Xenko.Navigation.NavigationMeshBuildUtils.HashEntityCollider(colliderComponent, asset.IncludedCollisionGroups); } } } sceneCloned = true; } }
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)); }
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)); }
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)); }