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, CacheSettings = new StaticColliderCacheSettings(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; } else if (desc is HeightfieldColliderShapeDesc) { var heightfieldDesc = desc as HeightfieldColliderShapeDesc; var initialHeights = heightfieldDesc?.InitialHeights as HeightfieldHeightDataFromHeightmap; if (initialHeights?.Heightmap != null) { var assetReference = AttachedReferenceManager.GetAttachedReference(initialHeights.Heightmap); object loadedHeightfieldInitialData; if (!loadedHeightfieldInitialDatas.TryGetValue(assetReference.Url, out loadedHeightfieldInitialData)) { loadedHeightfieldInitialData = contentManager.Load(typeof(Heightmap), assetReference.Url); loadedHeightfieldInitialDatas.Add(assetReference.Url, loadedHeightfieldInitialData); } initialHeights.Heightmap = loadedHeightfieldInitialData as Heightmap; } } } } // Hash collider for ComputeParameterHash sceneHash = (sceneHash * 397) ^ Xenko.Navigation.NavigationMeshBuildUtils.HashEntityCollider(colliderComponent, asset.IncludedCollisionGroups); } } } sceneCloned = true; } }
/// <summary> /// Gets the serialized data version of this <see cref="Texture"/>. /// </summary> /// <param name="texture">The texture.</param> /// <returns></returns> public static Image GetSerializationData(this Texture texture) { var attachedReference = AttachedReferenceManager.GetAttachedReference(texture); return((Image)attachedReference?.Data); }
private async void OpenDefaultScene(SessionViewModel session) { var startupPackage = session.LocalPackages.OfType <ProjectViewModel>().SingleOrDefault(x => x.IsCurrentProject); if (startupPackage == null) { return; } var gameSettingsAsset = startupPackage.Assets.FirstOrDefault(x => x.Url == Assets.GameSettingsAsset.GameSettingsLocation); if (gameSettingsAsset == null) { // Scan dependencies for game settings // TODO: Scanning order? (direct dependencies first) // TODO: Switch to using startupPackage.Dependencies view model instead foreach (var dependency in startupPackage.PackageContainer.FlattenedDependencies) { if (dependency.Package == null) { continue; } var dependencyPackageViewModel = session.AllPackages.First(x => x.Package == dependency.Package); if (dependencyPackageViewModel == null) { continue; } gameSettingsAsset = dependencyPackageViewModel.Assets.FirstOrDefault(x => x.Url == Assets.GameSettingsAsset.GameSettingsLocation); if (gameSettingsAsset != null) { break; } } } if (gameSettingsAsset == null) { return; } var defaultScene = ((Assets.GameSettingsAsset)gameSettingsAsset?.Asset)?.DefaultScene; if (defaultScene is null) { return; } var defaultSceneReference = AttachedReferenceManager.GetAttachedReference(defaultScene); if (defaultSceneReference is null) { return; } var asset = session.GetAssetById(defaultSceneReference.Id); if (asset is null) { return; } Editor.Session.ActiveAssetView.SelectAssets(asset.Yield()); await assetEditorsManager.OpenAssetEditorWindow(asset); }
private object ExportModel(ICommandContext commandContext, ContentManager contentManager) { // Read from model file var modelSkeleton = LoadSkeleton(commandContext, contentManager); // we get model skeleton to compare it to real skeleton we need to map to AdjustSkeleton(modelSkeleton); var model = LoadModel(commandContext, contentManager); if (!CheckInputSlots(commandContext, model)) { return(null); } // Apply materials foreach (var modelMaterial in Materials) { if (modelMaterial.MaterialInstance?.Material == null) { commandContext.Logger.Verbose($"The material [{modelMaterial.Name}] is null in the list of materials."); } model.Materials.Add(modelMaterial.MaterialInstance); } model.BoundingBox = BoundingBox.Empty; Skeleton skeleton; if (SkeletonUrl != null) { // Load skeleton and process it skeleton = contentManager.Load <Skeleton>(SkeletonUrl); // Assign skeleton to model model.Skeleton = AttachedReferenceManager.CreateProxyObject <Skeleton>(AssetId.Empty, SkeletonUrl); } else { skeleton = null; } var skeletonMapping = new SkeletonMapping(skeleton, modelSkeleton); // Refresh skeleton updater with model skeleton var hierarchyUpdater = new SkeletonUpdater(modelSkeleton); hierarchyUpdater.UpdateMatrices(); // Move meshes in the new nodes foreach (var mesh in model.Meshes) { // Apply scale import on meshes if (!MathUtil.NearEqual(ScaleImport, 1.0f)) { var transformationMatrix = Matrix.Scaling(ScaleImport); for (int vbIdx = 0; vbIdx < mesh.Draw.VertexBuffers.Length; vbIdx++) { mesh.Draw.VertexBuffers[vbIdx].TransformBuffer(ref transformationMatrix); } } var skinning = mesh.Skinning; if (skinning != null) { // Update node mapping // Note: we only remap skinning matrices, but we could directly remap skinning bones instead for (int i = 0; i < skinning.Bones.Length; ++i) { var linkNodeIndex = skinning.Bones[i].NodeIndex; var newLinkNodeIndex = skeletonMapping.SourceToSource[linkNodeIndex]; var nodeIndex = mesh.NodeIndex; var newNodeIndex = skeletonMapping.SourceToSource[mesh.NodeIndex]; skinning.Bones[i].NodeIndex = skeletonMapping.SourceToTarget[linkNodeIndex]; // Adjust scale import if (!MathUtil.NearEqual(ScaleImport, 1.0f)) { skinning.Bones[i].LinkToMeshMatrix.TranslationVector = skinning.Bones[i].LinkToMeshMatrix.TranslationVector * ScaleImport; } // If it was remapped, we also need to update matrix if (nodeIndex != newNodeIndex) { // Update mesh part var transformMatrix = CombineMatricesFromNodeIndices(hierarchyUpdater.NodeTransformations, newNodeIndex, nodeIndex); transformMatrix.Invert(); skinning.Bones[i].LinkToMeshMatrix = Matrix.Multiply(transformMatrix, skinning.Bones[i].LinkToMeshMatrix); } if (newLinkNodeIndex != linkNodeIndex) { // Update link part var transformLinkMatrix = CombineMatricesFromNodeIndices(hierarchyUpdater.NodeTransformations, newLinkNodeIndex, linkNodeIndex); skinning.Bones[i].LinkToMeshMatrix = Matrix.Multiply(skinning.Bones[i].LinkToMeshMatrix, transformLinkMatrix); } } } // Check if there was a remap using model skeleton if (skeletonMapping.SourceToSource[mesh.NodeIndex] != mesh.NodeIndex) { // Transform vertices var transformationMatrix = CombineMatricesFromNodeIndices(hierarchyUpdater.NodeTransformations, skeletonMapping.SourceToSource[mesh.NodeIndex], mesh.NodeIndex); for (int vbIdx = 0; vbIdx < mesh.Draw.VertexBuffers.Length; vbIdx++) { mesh.Draw.VertexBuffers[vbIdx].TransformBuffer(ref transformationMatrix); } // Check if geometry is inverted, to know if we need to reverse winding order // TODO: What to do if there is no index buffer? We should create one... (not happening yet) if (mesh.Draw.IndexBuffer == null) { throw new InvalidOperationException(); } Matrix rotation; Vector3 scale, translation; if (transformationMatrix.Decompose(out scale, out rotation, out translation) && scale.X * scale.Y * scale.Z < 0) { mesh.Draw.ReverseWindingOrder(); } } // Update new node index using real asset skeleton mesh.NodeIndex = skeletonMapping.SourceToTarget[mesh.NodeIndex]; } // Merge meshes with same parent nodes, material and skinning var meshesByNodes = model.Meshes.GroupBy(x => x.NodeIndex).ToList(); foreach (var meshesByNode in meshesByNodes) { // This logic to detect similar material is kept from old code; this should be reviewed/improved at some point foreach (var meshesPerDrawCall in meshesByNode.GroupBy(x => x, new AnonymousEqualityComparer <Mesh>((x, y) => x.MaterialIndex == y.MaterialIndex && // Same material ArrayExtensions.ArraysEqual(x.Skinning?.Bones, y.Skinning?.Bones) && // Same bones CompareParameters(model, x, y) && // Same parameters CompareShadowOptions(model, x, y), // Same shadow parameters x => 0)).ToList()) { if (meshesPerDrawCall.Count() == 1) { // Nothing to group, skip to next entry continue; } // Remove old meshes foreach (var mesh in meshesPerDrawCall) { model.Meshes.Remove(mesh); } // Add new combined mesh(es) var baseMesh = meshesPerDrawCall.First(); var newMeshList = meshesPerDrawCall.Select(x => x.Draw).ToList().GroupDrawData(Allow32BitIndex); foreach (var generatedMesh in newMeshList) { model.Meshes.Add(new Mesh(generatedMesh, baseMesh.Parameters) { MaterialIndex = baseMesh.MaterialIndex, Name = baseMesh.Name, Draw = generatedMesh, NodeIndex = baseMesh.NodeIndex, Skinning = baseMesh.Skinning, }); } } } // split the meshes if necessary model.Meshes = SplitExtensions.SplitMeshes(model.Meshes, Allow32BitIndex); // Refresh skeleton updater with asset skeleton hierarchyUpdater = new SkeletonUpdater(skeleton); hierarchyUpdater.UpdateMatrices(); // bounding boxes var modelBoundingBox = model.BoundingBox; var modelBoundingSphere = model.BoundingSphere; foreach (var mesh in model.Meshes) { var vertexBuffers = mesh.Draw.VertexBuffers; for (int vbIdx = 0; vbIdx < vertexBuffers.Length; vbIdx++) { // Compute local mesh bounding box (no node transformation) Matrix matrix = Matrix.Identity; mesh.BoundingBox = vertexBuffers[vbIdx].ComputeBounds(ref matrix, out mesh.BoundingSphere); // Compute model bounding box (includes node transformation) hierarchyUpdater.GetWorldMatrix(mesh.NodeIndex, out matrix); BoundingSphere meshBoundingSphere; var meshBoundingBox = vertexBuffers[vbIdx].ComputeBounds(ref matrix, out meshBoundingSphere); BoundingBox.Merge(ref modelBoundingBox, ref meshBoundingBox, out modelBoundingBox); BoundingSphere.Merge(ref modelBoundingSphere, ref meshBoundingSphere, out modelBoundingSphere); } // TODO: temporary Always try to compact mesh.Draw.CompactIndexBuffer(); } model.BoundingBox = modelBoundingBox; model.BoundingSphere = modelBoundingSphere; // Count unique meshes (they can be shared) var uniqueDrawMeshes = model.Meshes.Select(x => x.Draw).Distinct(); // Count unique vertex buffers and squish them together in a single buffer var uniqueVB = uniqueDrawMeshes.SelectMany(x => x.VertexBuffers).Distinct().ToList(); var vbMap = new Dictionary <VertexBufferBinding, VertexBufferBinding>(); var sizeVertexBuffer = uniqueVB.Select(x => x.Buffer.GetSerializationData().Content.Length).Sum(); var vertexBuffer = new BufferData(BufferFlags.VertexBuffer, new byte[sizeVertexBuffer]); var vertexBufferSerializable = vertexBuffer.ToSerializableVersion(); var vertexBufferNextIndex = 0; foreach (var vbBinding in uniqueVB) { var oldVertexBuffer = vbBinding.Buffer.GetSerializationData().Content; Array.Copy(oldVertexBuffer, 0, vertexBuffer.Content, vertexBufferNextIndex, oldVertexBuffer.Length); vbMap.Add(vbBinding, new VertexBufferBinding(vertexBufferSerializable, vbBinding.Declaration, vbBinding.Count, vbBinding.Stride, vertexBufferNextIndex)); vertexBufferNextIndex += oldVertexBuffer.Length; } // Count unique index buffers and squish them together in a single buffer var uniqueIB = uniqueDrawMeshes.Select(x => x.IndexBuffer).Distinct().ToList(); var sizeIndexBuffer = 0; foreach (var ibBinding in uniqueIB) { // Make sure 32bit indices are properly aligned to 4 bytes in case the last alignment was 2 bytes if (ibBinding.Is32Bit && sizeIndexBuffer % 4 != 0) { sizeIndexBuffer += 2; } sizeIndexBuffer += ibBinding.Buffer.GetSerializationData().Content.Length; } var ibMap = new Dictionary <IndexBufferBinding, IndexBufferBinding>(); var indexBuffer = new BufferData(BufferFlags.IndexBuffer, new byte[sizeIndexBuffer]); var indexBufferSerializable = indexBuffer.ToSerializableVersion(); var indexBufferNextIndex = 0; foreach (var ibBinding in uniqueIB) { var oldIndexBuffer = ibBinding.Buffer.GetSerializationData().Content; // Make sure 32bit indices are properly aligned to 4 bytes in case the last alignment was 2 bytes if (ibBinding.Is32Bit && indexBufferNextIndex % 4 != 0) { indexBufferNextIndex += 2; } Array.Copy(oldIndexBuffer, 0, indexBuffer.Content, indexBufferNextIndex, oldIndexBuffer.Length); ibMap.Add(ibBinding, new IndexBufferBinding(indexBufferSerializable, ibBinding.Is32Bit, ibBinding.Count, indexBufferNextIndex)); indexBufferNextIndex += oldIndexBuffer.Length; } // Assign new vertex and index buffer bindings foreach (var drawMesh in uniqueDrawMeshes) { for (int i = 0; i < drawMesh.VertexBuffers.Length; i++) { drawMesh.VertexBuffers[i] = vbMap[drawMesh.VertexBuffers[i]]; } drawMesh.IndexBuffer = ibMap[drawMesh.IndexBuffer]; } vbMap.Clear(); ibMap.Clear(); // Convert to Entity return(model); }
/// <summary> /// Gets the serialized data version of this <see cref="Buffer"/>. /// </summary> /// <param name="buffer">The buffer.</param> /// <returns></returns> public static BufferData GetSerializationData(this Buffer buffer) { var attachedReference = AttachedReferenceManager.GetAttachedReference(buffer); return(attachedReference != null ? (BufferData)attachedReference.Data : null); }
/// <summary> /// Finds an asset from its attached reference. /// It will first try by id, then location. /// </summary> /// <param name="package">The package.</param> /// <param name="obj">The object containing the attached reference.</param> /// <returns>An <see cref="AssetItem" /> or <c>null</c> if not found.</returns> public static AssetItem FindAssetFromAttachedReference(this Package package, object obj) { var attachedReference = AttachedReferenceManager.GetAttachedReference(obj); return(attachedReference != null?package.FindAsset(attachedReference) : null); }
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, 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.GetOrDefault <RenderingSettings>().DisplayOrientation); } var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); assetManager.Save(Url, result); return(Task.FromResult(ResultStatus.Successful)); }
/// <summary> /// Checks if a default scene exists for this game package. /// </summary> /// <param name="log">The log to output the result of the validation.</param> public override void Run(ILogger log) { if (log == null) { throw new ArgumentNullException(nameof(log)); } foreach (var package in Session.Packages) { // Make sure package has its assets loaded if (package.State < PackageState.AssetsReady) { continue; } var hasGameExecutable = package.Profiles.SelectMany(profile => profile.ProjectReferences).Any(projectRef => projectRef.Type == ProjectType.Executable); if (!hasGameExecutable) { continue; } // Find game settings var gameSettingsAssetItem = package.Assets.Find(GameSettingsAsset.GameSettingsLocation); AssetItem defaultScene = null; // If game settings is found, try to find default scene inside var defaultSceneRuntime = ((GameSettingsAsset)gameSettingsAssetItem?.Asset)?.DefaultScene; var defaultSceneReference = AttachedReferenceManager.GetAttachedReference(defaultSceneRuntime); if (defaultSceneReference != null) { // Find it either by Url or Id defaultScene = package.Assets.Find(defaultSceneReference.Id) ?? package.Assets.Find(defaultSceneReference.Url); // Check it is actually a scene asset if (defaultScene != null && !(defaultScene.Asset is SceneAsset)) { defaultScene = null; } } // Find or create default scene if (defaultScene == null) { defaultScene = package.Assets.Find(GameSettingsAsset.DefaultSceneLocation); if (defaultScene != null && !(defaultScene.Asset is SceneAsset)) { defaultScene = null; } } // Otherwise, try to find any scene if (defaultScene == null) { defaultScene = package.Assets.FirstOrDefault(x => x.Asset is SceneAsset); } // Create game settings if not done yet if (gameSettingsAssetItem == null) { log.Error(package, null, AssetMessageCode.AssetForPackageNotFound, GameSettingsAsset.GameSettingsLocation, package.FullPath.GetFileNameWithoutExtension()); var gameSettingsAsset = GameSettingsFactory.Create(); if (defaultScene != null) { gameSettingsAsset.DefaultScene = AttachedReferenceManager.CreateProxyObject <Scene>(defaultScene.Id, defaultScene.Location); } gameSettingsAssetItem = new AssetItem(GameSettingsAsset.GameSettingsLocation, gameSettingsAsset); package.Assets.Add(gameSettingsAssetItem); gameSettingsAssetItem.IsDirty = true; } } }
public override void VisitDictionaryKeyValue(object dictionaryObj, DictionaryDescriptor descriptor, object key, ITypeDescriptor keyDescriptor, object value, ITypeDescriptor valueDescriptor) { base.VisitDictionaryKeyValue(dictionaryObj, descriptor, key, keyDescriptor, value, valueDescriptor); var assetReference = value as AssetReference; var attachedReference = AttachedReferenceManager.GetAttachedReference(value); if (assetReference != null) { AddLink(assetReference, (guid, location) => { var newValue = AssetReference.New(guid ?? assetReference.Id, location); descriptor.SetValue(dictionaryObj, key, newValue); return(newValue); }); } else if (attachedReference != null) { AddLink(attachedReference, (guid, location) => { object newValue = guid.HasValue && guid.Value != AssetId.Empty ? AttachedReferenceManager.CreateProxyObject(descriptor.ValueType, guid.Value, location) : null; descriptor.SetValue(dictionaryObj, key, newValue); return(newValue); }); } else if (value is UFile) { AddLink(value, (guid, location) => { var newValue = new UFile(location); descriptor.SetValue(dictionaryObj, key, newValue); return(newValue); }); } else if (value is UDirectory) { AddLink(value, (guid, location) => { var newValue = new UDirectory(location); descriptor.SetValue(dictionaryObj, key, newValue); return(newValue); }); } }
public override void VisitCollectionItem(IEnumerable collection, CollectionDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor) { base.VisitCollectionItem(collection, descriptor, index, item, itemDescriptor); var assetReference = item as AssetReference; var assetBase = item as AssetBase; var attachedReference = AttachedReferenceManager.GetAttachedReference(item); // We cannot set links if we do not have indexer accessor if (!descriptor.HasIndexerAccessors) { return; } if (assetReference != null) { AddLink(assetReference, (guid, location) => { var link = AssetReference.New(descriptor.ElementType, guid ?? assetReference.Id, location); descriptor.SetValue(collection, index, link); return(link); }); } else if (assetBase != null) { AddLink(assetBase, (guid, location) => { var link = new AssetBase(location, assetBase.Asset); descriptor.SetValue(collection, index, link); return(link); }); } else if (attachedReference != null) { AddLink(attachedReference, (guid, location) => { var link = guid.HasValue && guid.Value != Guid.Empty ? AttachedReferenceManager.CreateProxyObject(descriptor.ElementType, guid.Value, location) : null; if (link != null) { IdentifiableHelper.SetId(link, IdentifiableHelper.GetId(item)); } descriptor.SetValue(collection, index, link); return(link); }); } else if (item is UFile) { AddLink(item, (guid, location) => { var link = new UFile(location); descriptor.SetValue(collection, index, link); return(link); }); } else if (item is UDirectory) { AddLink(item, (guid, location) => { var link = new UDirectory(location); descriptor.SetValue(collection, index, link); return(link); }); } }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); // Cloned list of collider shapes var descriptions = Parameters.ColliderShapes.ToList(); var validShapes = 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 validShapes 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, Decomposition = convexHullDesc.Decomposition, }; // 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 (!string.IsNullOrEmpty(vertexBufferRef.Url)) { 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 (!string.IsNullOrEmpty(indexBufferRef.Url)) { 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.Decomposition.Depth, PosSampling = convexHullDesc.Decomposition.PosSampling, PosRefine = convexHullDesc.Decomposition.PosRefine, AngleSampling = convexHullDesc.Decomposition.AngleSampling, AngleRefine = convexHullDesc.Decomposition.AngleRefine, Alpha = convexHullDesc.Decomposition.Alpha, Threshold = convexHullDesc.Decomposition.Threshold, SimpleHull = !convexHullDesc.Decomposition.Enabled, }; 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) { Core.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); assetManager.Save(Url, runtimeShape); return(Task.FromResult(ResultStatus.Successful)); }
protected override async Task <bool> PrepareAssetCreation(AssetTemplateGeneratorParameters parameters) { var result = await base.PrepareAssetCreation(parameters); if (!result) { return(false); } var files = parameters.Tags.Get(SourceFilesPathKey); if (files == null) { return(true); } var showDeduplicateMaterialsCheckBox = files.Any(x => ImportAssimpCommand.IsSupportingExtensions(x.GetFileExtension())); var showFbxDedupeNotSupportedWarning = showDeduplicateMaterialsCheckBox && files.Any(x => ImportFbxCommand.IsSupportingExtensions(x.GetFileExtension())); // Load settings from the last time this template was used for this project var profile = parameters.Package.UserSettings.Profile; var window = new ModelAssetTemplateWindow { Parameters = { ImportMaterials = ModelFromFileTemplateSettings.ImportMaterials.GetValue(profile, true), ShowDeduplicateMaterialsCheckBox = showDeduplicateMaterialsCheckBox, ShowFbxDedupeNotSupportedWarning = showFbxDedupeNotSupportedWarning, DeduplicateMaterials = ModelFromFileTemplateSettings.DeduplicateMaterials.GetValue(profile, true), ImportTextures = ModelFromFileTemplateSettings.ImportTextures.GetValue(profile, true), ImportSkeleton = ModelFromFileTemplateSettings.ImportSkeleton.GetValue(profile, true) } }; var skeletonId = ModelFromFileTemplateSettings.DefaultSkeleton.GetValue(); var skeleton = SessionViewModel.Instance?.GetAssetById(skeletonId); if (skeleton != null) { window.Parameters.ReuseSkeleton = true; window.Parameters.SkeletonToReuse = ContentReferenceHelper.CreateReference <Skeleton>(skeleton); } await window.ShowModal(); if (window.Result == DialogResult.Cancel) { return(false); } // Apply settings var skeletonToReuse = window.Parameters.ReuseSkeleton ? window.Parameters.SkeletonToReuse : null; parameters.Tags.Set(ImportMaterialsKey, window.Parameters.ImportMaterials); parameters.Tags.Set(DeduplicateMaterialsKey, window.Parameters.DeduplicateMaterials); parameters.Tags.Set(ImportTexturesKey, window.Parameters.ImportTextures); parameters.Tags.Set(ImportSkeletonKey, window.Parameters.ImportSkeleton); parameters.Tags.Set(SkeletonToUseKey, skeletonToReuse); // Save settings ModelFromFileTemplateSettings.ImportMaterials.SetValue(window.Parameters.ImportMaterials, profile); ModelFromFileTemplateSettings.DeduplicateMaterials.SetValue(window.Parameters.DeduplicateMaterials, profile); ModelFromFileTemplateSettings.ImportTextures.SetValue(window.Parameters.ImportTextures, profile); ModelFromFileTemplateSettings.ImportSkeleton.SetValue(window.Parameters.ImportSkeleton, profile); skeletonId = AttachedReferenceManager.GetAttachedReference(skeletonToReuse)?.Id ?? AssetId.Empty; ModelFromFileTemplateSettings.DefaultSkeleton.SetValue(skeletonId, profile); parameters.Package.UserSettings.Save(); return(true); }
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); } }
private ObjectId GetHashId() { // This methods use the stream that is already filled-up by the standard binary serialization of the object // Here we add ids and overrides metadata informations to the stream in order to calculate an accurate id var stream = streamOrValueType as MemoryStream; if (stream != null) { // ------------------------------------------------------ // Un-comment the following code to debug the ObjectId of the serialized version without taking into account overrides // ------------------------------------------------------ //var savedPosition = stream.Position; //stream.Position = 0; //var intermediateHashId = ObjectId.FromBytes(stream.ToArray()); //stream.Position = savedPosition; var writer = new BinarySerializationWriter(stream); Dictionary <string, OverrideType> overrides = null; List <string> orderedNames = null; foreach (var objectRef in objectReferences) { // If the object is actually a reference to another asset, we can skip it as their won't be any overrides if (AttachedReferenceManager.GetAttachedReference(objectRef) != null) { continue; } // Else gets the id if there are any (including shadows that are not part of the standard serialization) var shadowObject = ShadowObject.GetOrCreate(objectRef); if (shadowObject.IsIdentifiable) { // Get the shadow id (may be a non-shadow, so we may duplicate it in the stream (e.g Entity) // but it should not be a big deal var id = shadowObject.GetId(objectRef); writer.Write(id); } // Dump all members with overrides informations foreach (var item in shadowObject) { if (item.Key.Item2 == Override.OverrideKey) { // Use the member name to ensure a stable id var memberName = ((IMemberDescriptor)item.Key.Item1).Name; // Only creates the overrides dictionary if needed if (overrides == null) { overrides = new Dictionary <string, OverrideType>(); } overrides.Add(memberName, (OverrideType)item.Value); } } // Write any overrides information to the stream if (overrides != null) { // Collect names and order them by alphabetical order in order to make sure that we will get a stable id // (Dictionary doesn't ensure order) if (orderedNames == null) { orderedNames = new List <string>(); } orderedNames.Clear(); foreach (var entry in overrides) { orderedNames.Add(entry.Key); } orderedNames.Sort(); // Write all overrides for the current object reference foreach (var name in orderedNames) { writer.Write(name); // Write the override as an int writer.Write((int)overrides[name]); } // Clear overrides for next entry overrides.Clear(); } } writer.Flush(); stream.Position = 0; return(ObjectId.FromBytes(stream.ToArray())); } return(ObjectId.Empty); }
private void SerializeObject(Queue <SerializeOperation> serializeOperations, string url, object obj, bool publicReference) { // Don't create context in case we don't want to serialize referenced objects //if (!SerializeReferencedObjects && obj != RootObject) // return null; // Already saved? // TODO: Ref counting? Should we change it on save? Probably depends if we cache or not. if (LoadedAssetReferences.ContainsKey(obj)) { return; } var serializer = Serializer.GetSerializer(null, obj.GetType()); if (serializer == null) { throw new InvalidOperationException(string.Format("Content serializer for {0} could not be found.", obj.GetType())); } var contentSerializerContext = new ContentSerializerContext(url, ArchiveMode.Serialize, this); using (var stream = FileProvider.OpenStream(url, VirtualFileMode.Create, VirtualFileAccess.Write)) { var streamWriter = new BinarySerializationWriter(stream); PrepareSerializerContext(contentSerializerContext, streamWriter.Context); ChunkHeader header = null; // Allocate space in the stream, and also include header version in the hash computation, which is better // If serialization type is null, it means there should be no header. var serializationType = serializer.SerializationType; if (serializationType != null) { header = new ChunkHeader(); header.Type = serializer.SerializationType.AssemblyQualifiedName; header.Write(streamWriter); header.OffsetToObject = (int)streamWriter.NativeStream.Position; } contentSerializerContext.SerializeContent(streamWriter, serializer, obj); // Write references and updated header if (header != null) { header.OffsetToReferences = (int)streamWriter.NativeStream.Position; contentSerializerContext.SerializeReferences(streamWriter); // Move back to the pre-allocated header position in the steam stream.Seek(0, SeekOrigin.Begin); // Write actual header. header.Write(new BinarySerializationWriter(stream)); } } var assetReference = new Reference(url, publicReference); SetAssetObject(assetReference, obj); // Process content references // TODO: Should we work at ChunkReference level? foreach (var contentReference in contentSerializerContext.ContentReferences) { if (contentReference.ObjectValue != null) { var attachedReference = AttachedReferenceManager.GetAttachedReference(contentReference.ObjectValue); if (attachedReference == null || attachedReference.IsProxy) { continue; } serializeOperations.Enqueue(new SerializeOperation(contentReference.Location, contentReference.ObjectValue, false)); } } }
public override void VisitObjectMember(object container, ObjectDescriptor containerDescriptor, IMemberDescriptor member, object value) { base.VisitObjectMember(container, containerDescriptor, member, value); var assetReference = value as AssetReference; var attachedReference = AttachedReferenceManager.GetAttachedReference(value); if (assetReference != null) { AddLink(assetReference, (guid, location) => { var newValue = AssetReference.New(guid ?? assetReference.Id, location); member.Set(container, newValue); return(newValue); }); } else if (attachedReference != null) { AddLink(attachedReference, (guid, location) => { object newValue = guid.HasValue && guid.Value != AssetId.Empty ? AttachedReferenceManager.CreateProxyObject(member.Type, guid.Value, location) : null; member.Set(container, newValue); return(newValue); }); } else if (value is UFile) { AddLink(value, (guid, location) => { var newValue = new UFile(location); member.Set(container, newValue); return(newValue); }); } else if (value is UDirectory) { AddLink(value, (guid, location) => { var newValue = new UDirectory(location); member.Set(container, newValue); return(newValue); }); } }
/// <summary> /// Checks if a default scene exists for this game package. /// </summary> /// <param name="log">The log to output the result of the validation.</param> public override void Run(ILogger log) { if (log == null) { throw new ArgumentNullException("log"); } foreach (var package in Session.Packages) { // Make sure package has its assets loaded if (package.State < PackageState.AssetsReady) { continue; } var hasGameExecutable = package.Profiles.SelectMany(profile => profile.ProjectReferences).Any(projectRef => projectRef.Type == ProjectType.Executable); if (!hasGameExecutable) { continue; } // Find game settings var gameSettingsAssetItem = package.Assets.Find(GameSettingsAsset.GameSettingsLocation); AssetItem defaultScene = null; // If game settings is found, try to find default scene inside if (gameSettingsAssetItem != null) { var defaultSceneRuntime = ((GameSettingsAsset)gameSettingsAssetItem.Asset).DefaultScene; if (defaultSceneRuntime != null) { var defaultSceneReference = AttachedReferenceManager.GetAttachedReference(defaultSceneRuntime); if (defaultSceneReference != null) { // Find it either by Url or Id defaultScene = package.Assets.Find(defaultSceneReference.Id) ?? package.Assets.Find(defaultSceneReference.Url); // Check it is actually a scene asset if (defaultScene != null && !(defaultScene.Asset is SceneAsset)) { defaultScene = null; } } } } // Find or create default scene if (defaultScene == null) { defaultScene = package.Assets.Find(GameSettingsAsset.DefaultSceneLocation); if (defaultScene != null && !(defaultScene.Asset is SceneAsset)) { defaultScene = null; } } // Otherwise, try to find any scene if (defaultScene == null) { defaultScene = package.Assets.FirstOrDefault(x => x.Asset is SceneAsset); } // Nothing found, let's create an empty one if (defaultScene == null) { log.Error(package, null, AssetMessageCode.DefaultSceneNotFound, null); var defaultSceneName = NamingHelper.ComputeNewName(GameSettingsAsset.DefaultSceneLocation, package.Assets, a => a.Location); var defaultSceneAsset = SceneAsset.Create(); defaultScene = new AssetItem(defaultSceneName, defaultSceneAsset); package.Assets.Add(defaultScene); defaultScene.IsDirty = true; } // Create game settings if not done yet if (gameSettingsAssetItem == null) { log.Error(package, null, AssetMessageCode.AssetNotFound, GameSettingsAsset.GameSettingsLocation); var gameSettingsAsset = new GameSettingsAsset(); gameSettingsAsset.DefaultScene = AttachedReferenceManager.CreateSerializableVersion <Scene>(defaultScene.Id, defaultScene.Location); gameSettingsAssetItem = new AssetItem(GameSettingsAsset.GameSettingsLocation, gameSettingsAsset); package.Assets.Add(gameSettingsAssetItem); gameSettingsAssetItem.IsDirty = true; } } }
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 == 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.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 <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)); }
public static SkyboxResult Compile(SkyboxAsset asset, SkyboxGeneratorContext context) { if (asset == null) { throw new ArgumentNullException("asset"); } if (context == null) { throw new ArgumentNullException("context"); } var result = new SkyboxResult { Skybox = new Skybox() }; var parameters = context.Parameters; var skybox = result.Skybox; skybox.Parameters = parameters; if (asset.Model != null) { var cubemap = ((SkyboxCubeMapModel)asset.Model).CubeMap; if (cubemap == null) { return(result); } // load the skybox texture from the asset. var reference = AttachedReferenceManager.GetAttachedReference(cubemap); var skyboxTexture = context.Content.Load <Texture>(BuildTextureForSkyboxGenerationLocation(reference.Url)); if (skyboxTexture.Dimension != TextureDimension.TextureCube) { result.Error("SkyboxGenerator: The texture used as skybox should be a Cubemap."); return(result); } var shaderSource = asset.Model.Generate(context); parameters.Set(SkyboxKeys.Shader, shaderSource); // If we are using the skybox asset for lighting, we can compute it // TODO: This following code should be pluggable (like asset.Model.Generate(context);) but it is currently not if (asset.Usage != SkyboxUsage.Background) { // ------------------------------------------------------------------- // Calculate Diffuse prefiltering // ------------------------------------------------------------------- var lamberFiltering = new LambertianPrefilteringSHNoCompute(context.RenderContext) { HarmonicOrder = (int)asset.DiffuseSHOrder, RadianceMap = skyboxTexture }; lamberFiltering.Draw(context.RenderDrawContext); var coefficients = lamberFiltering.PrefilteredLambertianSH.Coefficients; // TODO: MOVE THE COEFFICIENTS TO THE SphericalHarmonics type in Core.Mathematics var PI4 = 4 * Math.PI; var PI16 = 16 * Math.PI; var PI64 = 64 * Math.PI; var SQRT_PI = 1.77245385090551602729; var bases = new float[coefficients.Length]; bases[0] = (float)(1.0 / (2.0 * SQRT_PI)); bases[1] = (float)(-Math.Sqrt(3.0 / PI4)); bases[2] = (float)(Math.Sqrt(3.0 / PI4)); bases[3] = (float)(-Math.Sqrt(3.0 / PI4)); bases[4] = (float)(Math.Sqrt(15.0 / PI4)); bases[5] = (float)(-Math.Sqrt(15.0 / PI4)); bases[6] = (float)(Math.Sqrt(5.0 / PI16)); bases[7] = (float)(-Math.Sqrt(15.0 / PI4)); bases[8] = (float)(Math.Sqrt(15.0 / PI16)); if (asset.DiffuseSHOrder == SkyboxPreFilteringDiffuseOrder.Order5) { bases[9] = -(float)Math.Sqrt(7 / PI64); bases[10] = (float)Math.Sqrt(105 / PI4); bases[11] = -(float)Math.Sqrt(21 / PI16); bases[12] = (float)Math.Sqrt(7 / PI16); bases[13] = -(float)Math.Sqrt(42 / PI64); bases[14] = (float)Math.Sqrt(105 / PI16); bases[15] = -(float)Math.Sqrt(70 / PI64); bases[16] = 3 * (float)Math.Sqrt(35 / PI16); bases[17] = -3 * (float)Math.Sqrt(70 / PI64); bases[18] = 3 * (float)Math.Sqrt(5 / PI16); bases[19] = -3 * (float)Math.Sqrt(10 / PI64); bases[20] = (float)(1.0 / (16.0 * SQRT_PI)); bases[21] = -3 * (float)Math.Sqrt(10 / PI64); bases[22] = 3 * (float)Math.Sqrt(5 / PI64); bases[23] = -3 * (float)Math.Sqrt(70 / PI64); bases[24] = 3 * (float)Math.Sqrt(35 / (4 * PI64)); } for (int i = 0; i < coefficients.Length; i++) { coefficients[i] = coefficients[i] * bases[i]; } skybox.DiffuseLightingParameters.Set(SkyboxKeys.Shader, new ShaderClassSource("SphericalHarmonicsEnvironmentColor", lamberFiltering.HarmonicOrder)); skybox.DiffuseLightingParameters.Set(SphericalHarmonicsEnvironmentColorKeys.SphericalColors, coefficients); // ------------------------------------------------------------------- // Calculate Specular prefiltering // ------------------------------------------------------------------- var specularRadiancePrefilterGGX = new RadiancePrefilteringGGXNoCompute(context.RenderContext); var textureSize = asset.SpecularCubeMapSize <= 0 ? 64 : asset.SpecularCubeMapSize; textureSize = (int)Math.Pow(2, Math.Round(Math.Log(textureSize, 2))); if (textureSize < 64) { textureSize = 64; } // TODO: Add support for HDR 32bits var filteringTextureFormat = skyboxTexture.Format.IsHDR() ? skyboxTexture.Format : PixelFormat.R8G8B8A8_UNorm; //var outputTexture = Texture.New2D(graphicsDevice, 256, 256, skyboxTexture.Format, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess, 6); using (var outputTexture = Texture.New2D(context.GraphicsDevice, textureSize, textureSize, true, filteringTextureFormat, TextureFlags.ShaderResource | TextureFlags.RenderTarget, 6) ) { specularRadiancePrefilterGGX.RadianceMap = skyboxTexture; specularRadiancePrefilterGGX.PrefilteredRadiance = outputTexture; specularRadiancePrefilterGGX.Draw(context.RenderDrawContext); var cubeTexture = Texture.NewCube(context.GraphicsDevice, textureSize, true, skyboxTexture.Format); context.RenderDrawContext.CommandList.Copy(outputTexture, cubeTexture); cubeTexture.SetSerializationData(cubeTexture.GetDataAsImage(context.RenderDrawContext.CommandList)); skybox.SpecularLightingParameters.Set(SkyboxKeys.Shader, new ShaderClassSource("RoughnessCubeMapEnvironmentColor")); skybox.SpecularLightingParameters.Set(SkyboxKeys.CubeMap, cubeTexture); } } // TODO: cubeTexture is not deallocated } return(result); }
private static unsafe void ProcessMaterial(ContentManager manager, ICollection <EntityChunk> chunks, MaterialInstance material, 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 var worldMatrix = chunk.Entity.Transform.WorldMatrix; var up = Vector3.Cross(worldMatrix.Right, worldMatrix.Forward); bool isScalingNegative = Vector3.Dot(worldMatrix.Up, up) < 0.0f; modelMesh.Draw.VertexBuffers[0].TransformBuffer(vertexDataCopy, ref 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); byte[] indices; if (isScalingNegative) { // Get reversed winding order modelMesh.Draw.GetReversedWindingOrder(out indices); indices = indices.Skip(modelMesh.Draw.IndexBuffer.Offset) .Take(modelMesh.Draw.IndexBuffer.Count * indexSize) .ToArray(); } else { // Get indices normally indices = indexData .Skip(modelMesh.Draw.IndexBuffer.Offset) .Take(modelMesh.Draw.IndexBuffer.Count * indexSize) .ToArray(); } // Convert indices to 32 bits if (indexSize == sizeof(ushort)) { var uintIndices = new byte[indices.Length * 2]; fixed(byte *psrc = indices) fixed(byte *pdst = uintIndices) { var src = (ushort *)psrc; var dst = (uint *)pdst; int numIndices = indices.Length / sizeof(ushort); for (var i = 0; i < numIndices; i++) { dst[i] = src[i]; } } indices = uintIndices; } // Offset indices by mesh.IndexOffset fixed(byte *pdst = indices) { var dst = (uint *)pdst; int numIndices = indices.Length / sizeof(uint); for (var i = 0; i < numIndices; i++) { // Offset indices dst[i] += (uint)mesh.IndexOffset; } } 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); } }
public void TestMaterial() { var compiler = new EffectCompiler { UseFileSystem = true }; compiler.SourceDirectories.Add(@"..\..\sources\engine\SiliconStudio.Xenko.Graphics\Shaders"); compiler.SourceDirectories.Add(@"..\..\sources\engine\SiliconStudio.Xenko.Engine\Shaders"); compiler.SourceDirectories.Add(@"..\..\sources\shaders\Core"); compiler.SourceDirectories.Add(@"..\..\sources\shaders\Lights"); compiler.SourceDirectories.Add(@"..\..\sources\shaders\Materials"); compiler.SourceDirectories.Add(@"..\..\sources\shaders\Shadows"); compiler.SourceDirectories.Add(@"..\..\sources\shaders\ComputeColor"); compiler.SourceDirectories.Add(@"..\..\sources\shaders\Skinning"); compiler.SourceDirectories.Add(@"..\..\sources\shaders\Shading"); compiler.SourceDirectories.Add(@"..\..\sources\shaders\Transformation"); compiler.SourceDirectories.Add(@"..\..\sources\shaders\Utils"); var compilerParameters = new CompilerParameters { Platform = GraphicsPlatform.Direct3D11 }; var layers = new MaterialBlendLayers(); layers.Add(new MaterialBlendLayer { BlendMap = new ComputeFloat(0.5f), Material = AttachedReferenceManager.CreateSerializableVersion <Material>(Guid.Empty, "fake") }); var materialAsset = new MaterialAsset { Attributes = new MaterialAttributes() { Diffuse = new MaterialDiffuseMapFeature() { DiffuseMap = new ComputeColor(Color4.White) }, DiffuseModel = new MaterialDiffuseLambertModelFeature() }, Layers = layers }; var fakeAsset = new MaterialAsset { Attributes = new MaterialAttributes() { Diffuse = new MaterialDiffuseMapFeature() { DiffuseMap = new ComputeColor(Color.Blue) }, } }; var context = new MaterialGeneratorContext { FindAsset = reference => fakeAsset }; var result = MaterialGenerator.Generate(new MaterialDescriptor { Attributes = materialAsset.Attributes, Layers = materialAsset.Layers }, context, "TestMaterial"); compilerParameters.Set(MaterialKeys.PixelStageSurfaceShaders, result.Material.Parameters.Get(MaterialKeys.PixelStageSurfaceShaders)); var directionalLightGroup = new ShaderClassSource("LightDirectionalGroup", 1); compilerParameters.Set(LightingKeys.DirectLightGroups, new List <ShaderSource> { directionalLightGroup }); //compilerParameters.Set(LightingKeys.CastShadows, false); //compilerParameters.Set(MaterialParameters.HasSkinningPosition, true); //compilerParameters.Set(MaterialParameters.HasSkinningNormal, true); compilerParameters.Set(MaterialKeys.HasNormalMap, true); var results = compiler.Compile(new ShaderMixinGeneratorSource("XenkoEffectBase"), compilerParameters); Assert.IsFalse(results.HasErrors); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var nodes = new List <SpriteStudioNode>(); string modelName; if (!SpriteStudioXmlImport.ParseModel(Parameters.Source, nodes, out modelName)) { return(null); } var cells = new List <SpriteStudioCell>(); var textures = new List <UFile>(); if (!SpriteStudioXmlImport.ParseCellMaps(Parameters.Source, textures, cells)) { return(null); } var anims = new List <SpriteStudioAnim>(); if (!SpriteStudioXmlImport.ParseAnimations(Parameters.Source, anims)) { return(null); } var assetManager = new ContentManager(); var sheet = new SpriteSheet(); foreach (var cell in cells) { var sprite = new Sprite(cell.Name, AttachedReferenceManager.CreateProxyObject <Texture>(AssetId.Empty, Parameters.BuildTextures[cell.TextureIndex])) { Region = cell.Rectangle, Center = cell.Pivot, IsTransparent = true }; sheet.Sprites.Add(sprite); } var nodeMapping = nodes.Select((x, i) => new { Name = x.Name, Index = i }).ToDictionary(x => x.Name, x => x.Index); //fill up some basic data for our model using the first animation in the array var anim = anims[0]; foreach (var data in anim.NodesData) { int nodeIndex; if (!nodeMapping.TryGetValue(data.Key, out nodeIndex)) { continue; } var node = nodes[nodeIndex]; foreach (var pair in data.Value.Data) { var tag = pair.Key; if (pair.Value.All(x => x["time"] != "0")) { continue; } var value = pair.Value.First()["value"]; //do we always have a frame 0? should be the case actually switch (tag) { case "POSX": node.BaseState.Position.X = float.Parse(value, CultureInfo.InvariantCulture); break; case "POSY": node.BaseState.Position.Y = float.Parse(value, CultureInfo.InvariantCulture); break; case "ROTZ": node.BaseState.RotationZ = MathUtil.DegreesToRadians(float.Parse(value, CultureInfo.InvariantCulture)); break; case "PRIO": node.BaseState.Priority = int.Parse(value, CultureInfo.InvariantCulture); break; case "SCLX": node.BaseState.Scale.X = float.Parse(value, CultureInfo.InvariantCulture); break; case "SCLY": node.BaseState.Scale.Y = float.Parse(value, CultureInfo.InvariantCulture); break; case "ALPH": node.BaseState.Transparency = float.Parse(value, CultureInfo.InvariantCulture); break; case "HIDE": node.BaseState.Hide = int.Parse(value, CultureInfo.InvariantCulture); break; case "FLPH": node.BaseState.HFlipped = int.Parse(value, CultureInfo.InvariantCulture); break; case "FLPV": node.BaseState.VFlipped = int.Parse(value, CultureInfo.InvariantCulture); break; case "CELL": node.BaseState.SpriteId = int.Parse(value, CultureInfo.InvariantCulture); break; case "COLV": var color = new Color4(Color.FromBgra(int.Parse(value, CultureInfo.InvariantCulture))); node.BaseState.BlendColor = colorSpace == ColorSpace.Linear ? color.ToLinear() : color; break; case "COLB": node.BaseState.BlendType = (SpriteStudioBlending)int.Parse(value, CultureInfo.InvariantCulture); break; case "COLF": node.BaseState.BlendFactor = float.Parse(value, CultureInfo.InvariantCulture); break; } } } var spriteStudioSheet = new SpriteStudioSheet { NodesInfo = nodes, SpriteSheet = sheet }; assetManager.Save(Url, spriteStudioSheet); return(Task.FromResult(ResultStatus.Successful)); }
public void TestMaterial() { var compiler = new EffectCompiler(TestHelper.CreateDatabaseProvider().FileProvider) { UseFileSystem = true }; var currentPath = Core.PlatformFolders.ApplicationBinaryDirectory; compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Graphics\Shaders")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Shaders")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Core")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Lights")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Shadows")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Materials\Shaders")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Materials\ComputeColors\Shaders")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Skinning")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Shading")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Transformation")); compiler.SourceDirectories.Add(Path.Combine(currentPath, @"..\..\sources\engine\Xenko.Engine\Rendering\Utils")); var compilerParameters = new CompilerParameters { EffectParameters = { Platform = GraphicsPlatform.OpenGL } }; var layers = new MaterialBlendLayers(); layers.Add(new MaterialBlendLayer { BlendMap = new ComputeFloat(0.5f), Material = AttachedReferenceManager.CreateProxyObject <Material>(AssetId.Empty, "fake") }); var materialAsset = new MaterialAsset { Attributes = new MaterialAttributes() { Diffuse = new MaterialDiffuseMapFeature() { DiffuseMap = new ComputeColor(Color4.White) }, DiffuseModel = new MaterialDiffuseLambertModelFeature() }, Layers = layers }; var fakeAsset = new MaterialAsset { Attributes = new MaterialAttributes() { Diffuse = new MaterialDiffuseMapFeature() { DiffuseMap = new ComputeColor(Color.Blue) }, } }; var context = new MaterialGeneratorContext { FindAsset = reference => fakeAsset }; var result = MaterialGenerator.Generate(new MaterialDescriptor { Attributes = materialAsset.Attributes, Layers = materialAsset.Layers }, context, "TestMaterial"); compilerParameters.Set(MaterialKeys.PixelStageSurfaceShaders, result.Material.Passes[0].Parameters.Get(MaterialKeys.PixelStageSurfaceShaders)); var directionalLightGroup = new ShaderClassSource("LightDirectionalGroup", 1); compilerParameters.Set(LightingKeys.DirectLightGroups, new ShaderSourceCollection { directionalLightGroup }); //compilerParameters.Set(LightingKeys.CastShadows, false); //compilerParameters.Set(MaterialParameters.HasSkinningPosition, true); //compilerParameters.Set(MaterialParameters.HasSkinningNormal, true); compilerParameters.Set(MaterialKeys.HasNormalMap, true); var results = compiler.Compile(new ShaderMixinGeneratorSource("XenkoEffectBase"), compilerParameters); Assert.False(results.HasErrors); }
public void CompilerVisitRuntimeType() { PackageSessionPublicHelper.FindAndSetMSBuildVersion(); var package = new Package(); // ReSharper disable once UnusedVariable - we need a package session to compile var packageSession = new PackageSession(package); var otherAssets = new List <AssetItem> { new AssetItem("contentRB", new MyAssetContentType(0), package), new AssetItem("contentRA", new MyAssetContentType(1), package), new AssetItem("content0B", new MyAssetContentType(2), package), new AssetItem("content0M", new MyAssetContentType(3), package), new AssetItem("content0A", new MyAssetContentType(4), package), new AssetItem("content1B", new MyAssetContentType(5), package), new AssetItem("content1M", new MyAssetContentType(6), package), new AssetItem("content1A", new MyAssetContentType(7), package), new AssetItem("content2B", new MyAssetContentType(8), package), new AssetItem("content2M", new MyAssetContentType(9), package), new AssetItem("content2A", new MyAssetContentType(10), package), new AssetItem("content3B", new MyAssetContentType(11), package), new AssetItem("content3M", new MyAssetContentType(12), package), new AssetItem("content3A", new MyAssetContentType(13), package), new AssetItem("content4B", new MyAssetContentType(14), package), new AssetItem("content4M", new MyAssetContentType(15), package), new AssetItem("content4A", new MyAssetContentType(16), package), }; var assetToVisit = new MyAsset1(); assetToVisit.Before = AttachedReferenceManager.CreateProxyObject <MyContentType>(otherAssets[0].Id, otherAssets[0].Location); assetToVisit.Zafter = AttachedReferenceManager.CreateProxyObject <MyContentType>(otherAssets[1].Id, otherAssets[1].Location); assetToVisit.RuntimeTypes.Add(CreateRuntimeType(otherAssets[2], otherAssets[3], otherAssets[4])); assetToVisit.RuntimeTypes.Add(CreateRuntimeType(otherAssets[5], otherAssets[6], otherAssets[7])); assetToVisit.RuntimeTypes.Add(CreateRuntimeType(otherAssets[8], otherAssets[9], otherAssets[10])); assetToVisit.RuntimeTypes.Add(CreateRuntimeType(otherAssets[11], otherAssets[12], otherAssets[13])); assetToVisit.RuntimeTypes.Add(CreateRuntimeType(otherAssets[14], otherAssets[15], otherAssets[16])); assetToVisit.RuntimeTypes[0].A = assetToVisit.RuntimeTypes[1]; assetToVisit.RuntimeTypes[0].B = assetToVisit.RuntimeTypes[2]; assetToVisit.RuntimeTypes[1].A = assetToVisit.RuntimeTypes[3]; assetToVisit.RuntimeTypes[1].B = assetToVisit.RuntimeTypes[4]; otherAssets.ForEach(x => package.Assets.Add(x)); var assetItem = new AssetItem("asset", assetToVisit, package); package.Assets.Add(assetItem); package.RootAssets.Add(new AssetReference(assetItem.Id, assetItem.Location)); // Create context var context = new AssetCompilerContext { CompilationContext = typeof(AssetCompilationContext) }; // Builds the project var assetBuilder = new PackageCompiler(new RootPackageAssetEnumerator(package)); context.Properties.Set(BuildAssetNode.VisitRuntimeTypes, true); var assetBuildResult = assetBuilder.Prepare(context); Assert.Equal(16, assetBuildResult.BuildSteps.Count); }
/// <summary> /// Sets the serialized data version of this <see cref="Buffer" />. /// </summary> /// <param name="buffer">The buffer.</param> /// <param name="bufferData">The buffer data.</param> public static void SetSerializationData(this Buffer buffer, BufferData bufferData) { var attachedReference = AttachedReferenceManager.GetOrCreateAttachedReference(buffer); attachedReference.Data = bufferData; }
public static SkyboxResult Compile(SkyboxAsset asset, SkyboxGeneratorContext context) { if (asset == null) { throw new ArgumentNullException("asset"); } if (context == null) { throw new ArgumentNullException("context"); } var result = new SkyboxResult { Skybox = new Skybox() }; var parameters = context.Parameters; var skybox = result.Skybox; skybox.Parameters = parameters; var cubemap = asset.CubeMap; if (cubemap == null) { return(result); } // load the skybox texture from the asset. var reference = AttachedReferenceManager.GetAttachedReference(cubemap); var skyboxTexture = context.Content.Load <Texture>(BuildTextureForSkyboxGenerationLocation(reference.Url), ContentManagerLoaderSettings.StreamingDisabled); if (skyboxTexture.ViewDimension == TextureDimension.Texture2D) { var cubemapSize = (int)Math.Pow(2, Math.Ceiling(Math.Log(skyboxTexture.Width / 4) / Math.Log(2))); // maximum resolution is around horizontal middle line which composes 4 images. skyboxTexture = CubemapFromTextureRenderer.GenerateCubemap(context.Services, context.RenderDrawContext, skyboxTexture, cubemapSize); } else if (skyboxTexture.ViewDimension != TextureDimension.TextureCube) { result.Error($"SkyboxGenerator: The texture type ({skyboxTexture.ViewDimension}) used as skybox is not supported. Should be a Cubemap or a 2D texture."); return(result); } // If we are using the skybox asset for lighting, we can compute it // Specular lighting only? if (!asset.IsSpecularOnly) { // ------------------------------------------------------------------- // Calculate Diffuse prefiltering // ------------------------------------------------------------------- var lamberFiltering = new LambertianPrefilteringSHNoCompute(context.RenderContext) { HarmonicOrder = (int)asset.DiffuseSHOrder, RadianceMap = skyboxTexture }; lamberFiltering.Draw(context.RenderDrawContext); var coefficients = lamberFiltering.PrefilteredLambertianSH.Coefficients; for (int i = 0; i < coefficients.Length; i++) { coefficients[i] = coefficients[i] * SphericalHarmonics.BaseCoefficients[i]; } skybox.DiffuseLightingParameters.Set(SkyboxKeys.Shader, new ShaderClassSource("SphericalHarmonicsEnvironmentColor", lamberFiltering.HarmonicOrder)); skybox.DiffuseLightingParameters.Set(SphericalHarmonicsEnvironmentColorKeys.SphericalColors, coefficients); } // ------------------------------------------------------------------- // Calculate Specular prefiltering // ------------------------------------------------------------------- var specularRadiancePrefilterGGX = new RadiancePrefilteringGGXNoCompute(context.RenderContext); var textureSize = asset.SpecularCubeMapSize <= 0 ? 64 : asset.SpecularCubeMapSize; textureSize = (int)Math.Pow(2, Math.Round(Math.Log(textureSize, 2))); if (textureSize < 64) { textureSize = 64; } // TODO: Add support for HDR 32bits var filteringTextureFormat = skyboxTexture.Format.IsHDR() ? skyboxTexture.Format : PixelFormat.R8G8B8A8_UNorm; //var outputTexture = Texture.New2D(graphicsDevice, 256, 256, skyboxTexture.Format, TextureFlags.ShaderResource | TextureFlags.UnorderedAccess, 6); using (var outputTexture = Texture.New2D(context.GraphicsDevice, textureSize, textureSize, true, filteringTextureFormat, TextureFlags.ShaderResource | TextureFlags.RenderTarget, 6)) { specularRadiancePrefilterGGX.RadianceMap = skyboxTexture; specularRadiancePrefilterGGX.PrefilteredRadiance = outputTexture; specularRadiancePrefilterGGX.Draw(context.RenderDrawContext); var cubeTexture = Texture.NewCube(context.GraphicsDevice, textureSize, true, filteringTextureFormat); context.RenderDrawContext.CommandList.Copy(outputTexture, cubeTexture); cubeTexture.SetSerializationData(cubeTexture.GetDataAsImage(context.RenderDrawContext.CommandList)); skybox.SpecularLightingParameters.Set(SkyboxKeys.Shader, new ShaderClassSource("RoughnessCubeMapEnvironmentColor")); skybox.SpecularLightingParameters.Set(SkyboxKeys.CubeMap, cubeTexture); } // TODO: cubeTexture is not deallocated return(result); }
/// <summary> /// Sets the serialized data version of this <see cref="Texture" />. /// </summary> /// <param name="texture">The texture.</param> /// <param name="image">The image.</param> public static void SetSerializationData(this Texture texture, Image image) { var attachedReference = AttachedReferenceManager.GetOrCreateAttachedReference(texture); attachedReference.Data = image; }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); assetManager.Serializer.RegisterSerializer(new ImageTextureSerializer()); // Create atlas texture Dictionary <SpriteInfo, PackedSpriteInfo> spriteToPackedSprite = null; // Generate texture atlas var isPacking = Parameters.SheetAsset.Packing.Enabled; if (isPacking) { var resultStatus = CreateAtlasTextures(commandContext, out spriteToPackedSprite); if (resultStatus != ResultStatus.Successful) { return(Task.FromResult(resultStatus)); } } var imageGroupData = new SpriteSheet(); // add the sprite data to the sprite list. foreach (var image in Parameters.SheetAsset.Sprites) { string textureUrl; RectangleF region; ImageOrientation orientation; var borders = image.Borders; var center = image.Center + (image.CenterFromMiddle ? new Vector2(image.TextureRegion.Width, image.TextureRegion.Height) / 2 : Vector2.Zero); if (isPacking && spriteToPackedSprite.ContainsKey(image)) // ensure that unpackable elements (invalid because of null size/texture) are properly added in the sheet using the normal path { var packedSprite = spriteToPackedSprite[image]; var isOriginalSpriteRotated = image.Orientation == ImageOrientation.Rotated90; region = packedSprite.Region; orientation = (packedSprite.IsRotated ^ isOriginalSpriteRotated) ? ImageOrientation.Rotated90 : ImageOrientation.AsIs; textureUrl = SpriteSheetAsset.BuildTextureAtlasUrl(Url, spriteToPackedSprite[image].AtlasTextureIndex); // update the center and border info, if the packer rotated the sprite // note: X->Left, Y->Top, Z->Right, W->Bottom. if (packedSprite.IsRotated) { // turned the sprite CCW if (isOriginalSpriteRotated) { var oldCenterX = center.X; center.X = center.Y; center.Y = region.Height - oldCenterX; var oldBorderW = borders.W; borders.W = borders.X; borders.X = borders.Y; borders.Y = borders.Z; borders.Z = oldBorderW; } else // turned the sprite CW { var oldCenterX = center.X; center.X = region.Width - center.Y; center.Y = oldCenterX; var oldBorderW = borders.W; borders.W = borders.Z; borders.Z = borders.Y; borders.Y = borders.X; borders.X = oldBorderW; } } } else { region = image.TextureRegion; orientation = image.Orientation; Parameters.ImageToTextureUrl.TryGetValue(image, out textureUrl); } // Affect the texture Texture texture = null; if (textureUrl != null) { texture = AttachedReferenceManager.CreateProxyObject <Texture>(AssetId.Empty, textureUrl); } else { commandContext.Logger.Warning($"Image '{image.Name}' has an invalid image source file '{image.Source}', resulting texture will be null."); } imageGroupData.Sprites.Add(new Graphics.Sprite { Name = image.Name, Region = region, Orientation = orientation, Center = center, Borders = borders, PixelsPerUnit = new Vector2(image.PixelsPerUnit), Texture = texture, IsTransparent = false, }); } // set the transparency information to all the sprites if (Parameters.SheetAsset.Alpha != AlphaFormat.None) // Skip the calculation when format is forced without alpha. { var urlToTexImage = new Dictionary <string, Tuple <TexImage, Image> >(); using (var texTool = new TextureTool()) { foreach (var sprite in imageGroupData.Sprites) { if (sprite.Texture == null) // the sprite texture is invalid { continue; } var textureUrl = AttachedReferenceManager.GetOrCreateAttachedReference(sprite.Texture).Url; if (!urlToTexImage.ContainsKey(textureUrl)) { var image = assetManager.Load <Image>(textureUrl); var newTexImage = texTool.Load(image, false); // the sRGB mode does not impact on the alpha level texTool.Decompress(newTexImage, false); // the sRGB mode does not impact on the alpha level urlToTexImage[textureUrl] = Tuple.Create(newTexImage, image); } var texImage = urlToTexImage[textureUrl].Item1; var region = new Rectangle { X = (int)Math.Floor(sprite.Region.X), Y = (int)Math.Floor(sprite.Region.Y) }; region.Width = (int)Math.Ceiling(sprite.Region.Right) - region.X; region.Height = (int)Math.Ceiling(sprite.Region.Bottom) - region.Y; var alphaLevel = texTool.GetAlphaLevels(texImage, region, null, commandContext.Logger); // ignore transparent color key here because the input image has already been processed sprite.IsTransparent = alphaLevel != AlphaLevels.NoAlpha; } // free all the allocated images foreach (var tuple in urlToTexImage.Values) { tuple.Item1.Dispose(); assetManager.Unload(tuple.Item2); } } } // save the imageData into the data base assetManager.Save(Url, imageGroupData); return(Task.FromResult(ResultStatus.Successful)); }
public override void VisitArrayItem(Array array, ArrayDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor) { base.VisitArrayItem(array, descriptor, index, item, itemDescriptor); var assetReference = item as AssetReference; var assetBase = item as AssetBase; var attachedReference = AttachedReferenceManager.GetAttachedReference(item); if (assetReference != null) { AddLink(item, (guid, location) => { var newValue = AssetReference.New(descriptor.ElementType, guid ?? assetReference.Id, location); array.SetValue(newValue, index); return(newValue); }); } else if (assetBase != null) { AddLink(item, (guid, location) => { var newValue = new AssetBase(location, assetBase.Asset); array.SetValue(newValue, index); return(newValue); }); } else if (attachedReference != null) { AddLink(attachedReference, (guid, location) => { object newValue = guid.HasValue && guid.Value != Guid.Empty ? AttachedReferenceManager.CreateSerializableVersion(descriptor.ElementType, guid.Value, location) : null; if (newValue != null) { IdentifiableHelper.SetId(newValue, IdentifiableHelper.GetId(item)); } array.SetValue(newValue, index); return(newValue); }); } else if (item is UFile) { AddLink(item, (guid, location) => { var newValue = new UFile(location); array.SetValue(newValue, index); return(newValue); }); } else if (item is UDirectory) { AddLink(item, (guid, location) => { var newValue = new UFile(location); array.SetValue(newValue, index); return(newValue); }); } }
/// <summary> /// Creates default scene, with a ground plane, sphere, directional light and camera. /// If graphicsProfile is 10+, add cubemap light, otherwise ambient light. /// Also properly setup graphics pipeline depending on if HDR is set or not /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="package">The package in which to create these assets.</param> private void CreateAndSetNewScene(SessionTemplateGeneratorParameters parameters, Package package, string projectGameName) { var logger = parameters.Logger; var graphicsProfile = parameters.GetTag(GraphicsProfileKey); var isHDR = parameters.GetTag(IsHDRKey); if (graphicsProfile < GraphicsProfile.Level_10_0) { isHDR = false; } // Create the material for the sphere var sphereMaterial = new MaterialAsset { Attributes = { Diffuse = new MaterialDiffuseMapFeature(new ComputeColor(Color.FromBgra(0xFF8C8C8C))), DiffuseModel = new MaterialDiffuseLambertModelFeature(), } }; if (isHDR) { // Create HDR part of material sphereMaterial.Attributes.Specular = new MaterialMetalnessMapFeature(new ComputeFloat(1.0f)); sphereMaterial.Attributes.SpecularModel = new MaterialSpecularMicrofacetModelFeature(); sphereMaterial.Attributes.MicroSurface = new MaterialGlossinessMapFeature(new ComputeFloat(0.65f)); } var sphereMaterialAssetItem = new AssetItem("Sphere Material", sphereMaterial); package.Assets.Add(sphereMaterialAssetItem); sphereMaterialAssetItem.IsDirty = true; // Create the sphere model var sphereModel = new ProceduralModelAsset { Type = new SphereProceduralModel { MaterialInstance = { Material = AttachedReferenceManager.CreateProxyObject <Material>(sphereMaterialAssetItem.Id, sphereMaterialAssetItem.Location) }, Tessellation = 30, }, }; var sphereModelAssetItem = new AssetItem("Sphere", sphereModel); package.Assets.Add(sphereModelAssetItem); sphereModelAssetItem.IsDirty = true; // Create sphere entity var sphereEntity = new Entity("Sphere") { new ModelComponent(AttachedReferenceManager.CreateProxyObject <Model>(sphereModelAssetItem.Id, sphereModelAssetItem.Location)) }; sphereEntity.Transform.Position = new Vector3(0.0f, 0.5f, 0.0f); // Create the material for the ground var groundMaterial = new MaterialAsset { Attributes = { Diffuse = new MaterialDiffuseMapFeature(new ComputeColor(Color.FromBgra(0xFF242424))), DiffuseModel = new MaterialDiffuseLambertModelFeature(), } }; if (isHDR) { // Create HDR part of material groundMaterial.Attributes.Specular = new MaterialMetalnessMapFeature(new ComputeFloat(0.0f)); groundMaterial.Attributes.SpecularModel = new MaterialSpecularMicrofacetModelFeature(); groundMaterial.Attributes.MicroSurface = new MaterialGlossinessMapFeature(new ComputeFloat(0.1f)); } var groundMaterialAssetItem = new AssetItem("Ground Material", groundMaterial); package.Assets.Add(groundMaterialAssetItem); groundMaterialAssetItem.IsDirty = true; // Create the ground model var groundModel = new ProceduralModelAsset { Type = new PlaneProceduralModel { Size = new Vector2(10.0f, 10.0f), MaterialInstance = { Material = AttachedReferenceManager.CreateProxyObject <Material>(groundMaterialAssetItem.Id, groundMaterialAssetItem.Location) }, }, }; var groundModelAssetItem = new AssetItem("Ground", groundModel); package.Assets.Add(groundModelAssetItem); groundModelAssetItem.IsDirty = true; // Create the ground entity var groundEntity = new Entity("Ground") { new ModelComponent(AttachedReferenceManager.CreateProxyObject <Model>(groundModelAssetItem.Id, groundModelAssetItem.Location)) }; // Copy file in Resources var skyboxFilename = (UFile)(isHDR ? "skybox_texture_hdr.dds" : "skybox_texture_ldr.dds"); try { var resources = UPath.Combine(package.RootDirectory, (UDirectory)"Resources"); Directory.CreateDirectory(resources.ToWindowsPath()); // TODO: Hardcoded due to the fact that part of the template is in another folder in dev build // We might want to extend TemplateFolder to support those cases var dataDirectory = ProjectTemplateGeneratorHelper.GetTemplateDataDirectory(parameters.Description); var skyboxFullPath = UPath.Combine(dataDirectory, skyboxFilename).ToWindowsPath(); File.Copy(skyboxFullPath, UPath.Combine(resources, skyboxFilename).ToWindowsPath(), true); } catch (Exception ex) { logger.Error("Unexpected exception while copying cubemap", ex); } // Create the texture asset var skyboxTextureAsset = new TextureAsset { Source = Path.Combine(@"../Resources", skyboxFilename), IsCompressed = isHDR, Type = new ColorTextureType { UseSRgbSampling = false } }; var skyboxTextureAssetItem = new AssetItem("Skybox texture", skyboxTextureAsset); package.Assets.Add(skyboxTextureAssetItem); skyboxTextureAssetItem.IsDirty = true; // Create the skybox asset var skyboxAsset = new SkyboxAsset { CubeMap = AttachedReferenceManager.CreateProxyObject <Texture>(skyboxTextureAssetItem.Id, skyboxTextureAssetItem.Location) }; var skyboxAssetItem = new AssetItem("Skybox", skyboxAsset); package.Assets.Add(skyboxAssetItem); skyboxAssetItem.IsDirty = true; // Create the scene var defaultSceneAsset = isHDR ? SceneHDRFactory.Create() : SceneLDRFactory.Create(); defaultSceneAsset.Hierarchy.Parts.Add(new EntityDesign(groundEntity)); defaultSceneAsset.Hierarchy.RootParts.Add(groundEntity); defaultSceneAsset.Hierarchy.Parts.Add(new EntityDesign(sphereEntity)); defaultSceneAsset.Hierarchy.RootParts.Add(sphereEntity); var sceneAssetItem = new AssetItem(GameSettingsAsset.DefaultSceneLocation, defaultSceneAsset); package.Assets.Add(sceneAssetItem); sceneAssetItem.IsDirty = true; // Sets the scene created as default in the shared profile var gameSettingsAsset = package.Assets.Find(GameSettingsAsset.GameSettingsLocation); if (gameSettingsAsset != null) { ((GameSettingsAsset)gameSettingsAsset.Asset).DefaultScene = AttachedReferenceManager.CreateProxyObject <Scene>(sceneAssetItem.Id, sceneAssetItem.Location); gameSettingsAsset.IsDirty = true; } var skyboxEntity = defaultSceneAsset.Hierarchy.Parts.Select(x => x.Value.Entity).Single(x => x.Name == SceneBaseFactory.SkyboxEntityName); skyboxEntity.Get <BackgroundComponent>().Texture = skyboxAsset.CubeMap; if (isHDR) { skyboxEntity.Get <LightComponent>().Type = new LightSkybox { Skybox = AttachedReferenceManager.CreateProxyObject <Skybox>(skyboxAssetItem.Id, skyboxAssetItem.Location) }; } var cameraEntity = defaultSceneAsset.Hierarchy.Parts.Select(x => x.Value.Entity).Single(x => x.Name == SceneBaseFactory.CameraEntityName); var graphicsCompositor = package.Assets.Select(x => x.Asset).OfType <GraphicsCompositorAsset>().Single(); cameraEntity.Components.Get <CameraComponent>().Slot = graphicsCompositor.Cameras.Single().ToSlotId(); // Let's add camera script CreateCameraScript(parameters, package, projectGameName, cameraEntity, sceneAssetItem); }