4 using System.Collections.Generic;
6 using System.Threading;
7 using System.Threading.Tasks;
9 using SiliconStudio.Core.Mathematics;
10 using SiliconStudio.Paradox.DataModel;
11 using SiliconStudio.Paradox.Effects;
12 using SiliconStudio.Paradox.Effects.Data;
13 using SiliconStudio.Paradox.Extensions;
14 using SiliconStudio.Core.Serialization;
15 using SiliconStudio.Core.Serialization.Assets;
16 using SiliconStudio.Paradox.Graphics;
17 using SiliconStudio.Paradox.Graphics.Data;
18 using SiliconStudio.Paradox.Shaders;
20 namespace SiliconStudio.BuildEngine
29 private static int spawnedFbxCommands;
32 public string TextureTag {
get; set; }
34 public string ExportType {
get; set; }
35 public bool TessellationAEN {
get; set; }
36 public string EffectName {
get; set; }
39 public Dictionary<string, Tuple<Guid, string>> Materials {
get; set; }
40 public Dictionary<string, Tuple<Guid, string>> Lightings {
get; set; }
41 public Dictionary<string, ParameterCollectionData>
Parameters;
43 public bool Compact {
get; set; }
44 public List<string> PreservedNodes {
get; set; }
46 public bool Allow32BitIndex {
get; set; }
47 public bool AllowUnsignedBlendIndices {
get; set; }
48 public Vector3 ViewDirectionForTransparentZSort {
get; set; }
54 TextureTag =
"fbx-texture";
55 TextureTagSymbol = RegisterTag(
"Texture", () => TextureTag);
59 private string ContextAsString
63 return string.Format(
"model [{0}] from import [{1}]", Location, SourcePath);
71 while (Interlocked.Increment(ref spawnedFbxCommands) >= 2)
73 Interlocked.Decrement(ref spawnedFbxCommands);
74 await Task.Delay(1, CancellationToken);
79 object exportedObject;
81 if (ExportType ==
"animation")
84 var animationClip = LoadAnimation(commandContext, assetManager);
85 exportedObject = animationClip;
86 if (animationClip == null)
88 commandContext.Logger.Info(
"File {0} has an empty animation.", SourcePath);
90 else if (animationClip.Duration.Ticks == 0)
92 commandContext.Logger.Warning(
"File {0} has a 0 tick long animation.", SourcePath);
97 animationClip.Optimize();
100 else if (ExportType ==
"model")
103 var model = LoadModel(commandContext, assetManager);
105 model.BoundingBox = BoundingBox.Empty;
107 hierarchyUpdater.UpdateMatrices();
109 bool hasErrors =
false;
110 foreach (var mesh
in model.Meshes)
115 commandContext.Logger.Error(
"TessellationAEN is not supported in {0}", ContextAsString);
120 if (!Materials.ContainsKey(mesh.Name))
122 commandContext.Logger.Error(
"Mesh material [{0}] was not found in {1}", mesh.Name, ContextAsString);
128 var materialReference = Materials[mesh.Name];
132 if (Parameters.ContainsKey(mesh.Name) && Parameters[mesh.Name] != null)
134 if (mesh.Parameters == null)
136 foreach (var keyValue
in Parameters[mesh.Name])
137 mesh.Parameters.Set(keyValue.Key, keyValue.Value);
142 Tuple<Guid, string> lightingReference;
143 if (Lightings.TryGetValue(mesh.Name, out lightingReference))
148 model.Meshes = SplitExtensions.SplitMeshes(model.Meshes, Allow32BitIndex);
153 var indicesBlackList =
new HashSet<int>();
154 if (PreservedNodes != null)
156 for (var index = 0; index < model.Hierarchy.Nodes.Length; ++index)
158 var node = model.Hierarchy.Nodes[index];
159 if (PreservedNodes.Contains(node.Name))
160 indicesBlackList.Add(index);
165 var sameMaterialMeshes =
new List<GroupList<int, MeshData>>();
166 GroupFromIndex(model, 0, indicesBlackList, model.Meshes, sameMaterialMeshes);
169 var excludedMeshes =
new List<MeshData>();
170 var finalMeshGroups =
new List<GroupList<int, MeshData>>();
171 foreach (var meshList
in sameMaterialMeshes)
173 var mergeList =
new GroupList<int, MeshData> { Key = meshList.Key };
175 foreach (var mesh
in meshList)
177 if (mesh.Skinning != null || indicesBlackList.Contains(mesh.NodeIndex))
178 excludedMeshes.Add(mesh);
183 if (mergeList.Count <= 1)
184 excludedMeshes.AddRange(mergeList);
186 finalMeshGroups.Add(mergeList);
189 var finalMeshes =
new List<MeshData>();
191 finalMeshes.AddRange(excludedMeshes);
193 foreach (var meshList
in finalMeshGroups)
196 foreach (var mesh
in meshList)
198 var transformationMatrix = GetMatrixFromIndex(model.Hierarchy.Nodes, hierarchyUpdater, meshList.Key, mesh.NodeIndex);
199 mesh.Draw.VertexBuffers[0].TransformBuffer(ref transformationMatrix);
203 var newMeshGroups =
new List<GroupList<int, MeshData>> { meshList };
205 newMeshGroups = RefineGroups(newMeshGroups, CompareParameters);
207 newMeshGroups = RefineGroups(newMeshGroups, CompareShadowOptions);
209 newMeshGroups = RefineGroups(newMeshGroups, CompareLightingConfigurations);
213 foreach (var sameParamsMeshes
in newMeshGroups)
215 var baseMesh = sameParamsMeshes[0];
216 var newMeshList = sameParamsMeshes.Select(x => x.Draw).ToList().GroupDrawData(Allow32BitIndex);
217 foreach (var generatedMesh
in newMeshList)
221 Parameters = baseMesh.Parameters,
222 Name = baseMesh.Name,
223 Draw = generatedMesh,
224 NodeIndex = meshList.Key,
232 var keptNodes =
new bool[model.Hierarchy.Nodes.Length];
233 for (var i = 0; i < keptNodes.Length; ++i)
235 keptNodes[i] =
false;
237 foreach (var keepIndex
in indicesBlackList)
239 var nodeIndex = keepIndex;
240 while (nodeIndex != -1 && !keptNodes[nodeIndex])
242 keptNodes[nodeIndex] =
true;
243 nodeIndex = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
246 foreach (var mesh
in finalMeshes)
248 var nodeIndex = mesh.NodeIndex;
249 while (nodeIndex != -1 && !keptNodes[nodeIndex])
251 keptNodes[nodeIndex] =
true;
252 nodeIndex = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
255 if (mesh.Skinning != null)
257 foreach (var bone
in mesh.Skinning.Bones)
259 nodeIndex = bone.NodeIndex;
260 while (nodeIndex != -1 && !keptNodes[nodeIndex])
262 keptNodes[nodeIndex] =
true;
263 nodeIndex = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
269 var newNodes =
new List<ModelNodeDefinition>();
270 var newMapping =
new int[model.Hierarchy.Nodes.Length];
271 for (var i = 0; i < keptNodes.Length; ++i)
275 var parentIndex = model.Hierarchy.Nodes[i].ParentIndex;
276 if (parentIndex != -1)
277 model.Hierarchy.Nodes[i].ParentIndex = newMapping[parentIndex];
278 newMapping[i] = newNodes.Count;
279 newNodes.Add(model.Hierarchy.Nodes[i]);
283 foreach (var mesh
in finalMeshes)
285 mesh.NodeIndex = newMapping[mesh.NodeIndex];
287 if (mesh.Skinning != null)
289 for (var i = 0; i < mesh.Skinning.Bones.Length; ++i)
291 mesh.Skinning.Bones[i].NodeIndex = newMapping[mesh.Skinning.Bones[i].NodeIndex];
296 model.Meshes = finalMeshes;
297 model.Hierarchy.Nodes = newNodes.ToArray();
300 hierarchyUpdater.UpdateMatrices();
304 foreach (var mesh
in model.Meshes)
306 var vertexBuffers = mesh.Draw.VertexBuffers;
307 if (vertexBuffers.Length > 0)
310 Matrix matrix = Matrix.Identity;
311 mesh.BoundingBox = vertexBuffers[0].ComputeBoundingBox(ref matrix);
314 hierarchyUpdater.GetWorldMatrix(mesh.NodeIndex, out matrix);
315 var meshBoundingBox = vertexBuffers[0].ComputeBoundingBox(ref matrix);
316 BoundingBox.Merge(ref model.BoundingBox, ref meshBoundingBox, out model.BoundingBox);
320 mesh.Draw.CompactIndexBuffer();
324 var sizeVertexBuffer = model.Meshes.SelectMany(x => x.Draw.VertexBuffers).Select(x => x.Buffer.Value.Content.Length).Sum();
325 var sizeIndexBuffer = model.Meshes.Select(x => x.Draw.IndexBuffer).Select(x => x.Buffer.Value.Content.Length).Sum();
328 var vertexBufferNextIndex = 0;
329 var indexBufferNextIndex = 0;
330 foreach (var drawMesh
in model.Meshes.Select(x => x.Draw))
333 var oldIndexBuffer = drawMesh.IndexBuffer.Buffer.Value.Content;
335 Array.Copy(oldIndexBuffer, 0, indexBuffer.Content, indexBufferNextIndex, oldIndexBuffer.Length);
337 drawMesh.IndexBuffer.Offset = indexBufferNextIndex;
338 drawMesh.IndexBuffer.Buffer = indexBuffer;
340 indexBufferNextIndex += oldIndexBuffer.Length;
343 foreach (var vertexBufferBinding
in drawMesh.VertexBuffers)
345 var oldVertexBuffer = vertexBufferBinding.Buffer.Value.Content;
347 Array.Copy(oldVertexBuffer, 0, vertexBuffer.Content, vertexBufferNextIndex, oldVertexBuffer.Length);
349 vertexBufferBinding.Offset = vertexBufferNextIndex;
350 vertexBufferBinding.Buffer = vertexBuffer;
352 vertexBufferNextIndex += oldVertexBuffer.Length;
360 return ResultStatus.Failed;
364 exportedObject = model;
368 commandContext.Logger.Error(
"Unknown export type [{0}] {1}", ExportType, ContextAsString);
369 return ResultStatus.Failed;
372 if (exportedObject != null)
373 assetManager.Save(Location, exportedObject);
375 commandContext.Logger.Info(
"The {0} has been successfully imported.", ContextAsString);
377 return ResultStatus.Successful;
381 commandContext.Logger.Error(
"Unexpected error while importing {0}", ex, ContextAsString);
382 return ResultStatus.Failed;
386 Interlocked.Decrement(ref spawnedFbxCommands);
396 private List<GroupList<int, MeshData>> RefineGroups(List<GroupList<int, MeshData>> meshList, SameGroup sameGroupDelegate)
398 var finalGroups =
new List<GroupList<int, MeshData>>();
399 foreach (var meshGroup
in meshList)
401 var updatedGroups =
new List<GroupList<int, MeshData>>();
402 foreach (var mesh
in meshGroup)
404 var createNewGroup =
true;
405 foreach (var sameParamsMeshes
in updatedGroups)
407 if (sameGroupDelegate(sameParamsMeshes[0], mesh))
409 sameParamsMeshes.Add(mesh);
410 createNewGroup =
false;
417 var newGroup =
new GroupList<int, MeshData> { Key = meshGroup.Key };
419 updatedGroups.Add(newGroup);
422 finalGroups.AddRange(updatedGroups);
436 private Dictionary<Guid, List<MeshData>> GroupFromIndex(
ModelData model,
int index, HashSet<int> nodeBlackList, List<MeshData> meshes, List<GroupList<int, MeshData>> finalLists)
440 var materialGroups =
new Dictionary<Guid, List<MeshData>>();
443 foreach (var child
in children)
445 var newMaterialGroups = GroupFromIndex(model, child, nodeBlackList, meshes, finalLists);
447 foreach (var group
in newMaterialGroups)
449 if (!materialGroups.ContainsKey(group.Key))
450 materialGroups.Add(group.Key,
new List<MeshData>());
451 materialGroups[group.Key].AddRange(group.Value);
456 foreach (var nodeMesh
in meshes.Where(x => x.NodeIndex == index))
458 var matId = nodeMesh.Material.Id;
459 if (!materialGroups.ContainsKey(matId))
460 materialGroups.Add(matId,
new List<MeshData>());
461 materialGroups[matId].Add(nodeMesh);
465 if (nodeBlackList.Contains(index) || index == 0)
467 foreach (var materialGroup
in materialGroups)
469 var groupList =
new GroupList<int, MeshData>();
470 groupList.Key = index;
471 groupList.AddRange(materialGroup.Value);
472 finalLists.Add(groupList);
474 materialGroups.Clear();
477 return materialGroups;
490 if (index == -1 || index == rootIndex)
491 return Matrix.Identity;
494 updater.GetLocalMatrix(index, out outMatrix);
496 if (index != rootIndex)
498 var topMatrix = GetMatrixFromIndex(hierarchy, updater, rootIndex, hierarchy[index].ParentIndex);
499 outMatrix = Matrix.Multiply(outMatrix, topMatrix);
513 var result =
new List<int>();
514 for (var i = 0; i < hierarchy.Length; ++i)
516 if (hierarchy[i].ParentIndex == index)
528 base.ComputeParameterHash(writer);
530 writer.SerializeExtended(
this, ArchiveMode.Serialize);
545 var sources = shaderSource.Split(
new[] {
",",
";" }, StringSplitOptions.RemoveEmptyEntries);
547 if (sources.Length == 1)
553 foreach (var source
in sources)
570 var localParams = baseMesh.Parameters;
571 if (localParams == null && newMesh.
Parameters == null)
573 if (localParams == null || newMesh.
Parameters == null)
575 return AreCollectionsEqual(localParams, newMesh.
Parameters);
585 private static bool CompareShadowOptions(
MeshData baseMesh,
MeshData newMesh)
600 var value0 = parameters0.ContainsKey(key) ? parameters0[key] : key.DefaultMetadataT.DefaultValue;
601 var value1 = parameters1.ContainsKey(key) ? parameters1[key] : key.DefaultMetadataT.DefaultValue;
602 return value0 == value1;
611 private static bool CompareLightingConfigurations(
MeshData baseMesh,
MeshData newMesh)
613 var config0Content = GetLightingConfigurations(baseMesh);
614 var config1Content = GetLightingConfigurations(newMesh);
615 if (config0Content == null && config1Content == null)
617 if (config0Content == null || config1Content == null)
619 return config0Content.Id == config1Content.Id;
631 var config = mesh.Parameters[LightingKeys.LightingConfigurations];
647 foreach (var paramKey
in parameters0)
649 result &= parameters1.ContainsKey(paramKey.Key) && parameters1[paramKey.Key].Equals(paramKey.Value);
651 foreach (var paramKey
in parameters1)
653 result &= parameters0.ContainsKey(paramKey.Key) && parameters0[paramKey.Key].Equals(paramKey.Value);
660 return (SourcePath ??
"[File]") + (ExportType != null ?
" (" + ExportType +
")" :
"") +
" > " + (Location ??
"[Location]");
670 public class GroupList<TK,T> : List<T>, IGrouping<TK,T>
672 public TK Key {
get; set; }
Dictionary< string, ParameterCollectionData > Parameters
override async Task< ResultStatus > DoCommandOverride(ICommandContext commandContext)
The method to override containing the actual command code. It is called by the DoCommand function ...
ModelNodeDefinition[] Nodes
The nodes in this hierarchy.
SiliconStudio.Paradox.Effects.Data.ParameterCollectionData Parameters
Data field for SiliconStudio.Paradox.Effects.Mesh.Parameters.
override void ComputeParameterHash(BinarySerializationWriter writer)
A mixin performing a combination of ShaderClassSource and other mixins.
override string ToString()
Key of an gereric effect parameter.
Represents a three dimensional mathematical vector.
Implements SerializationStream as a binary writer.
Data type for SiliconStudio.Paradox.Effects.ParameterCollection.
An aggregation of AnimationCurve with their channel names.
AnimationRepeatMode
Enumeration describing how an animation should be repeated.
static ShaderSource ParseShaderSource(string shaderSource)
Parses a shader source definition
static readonly ParameterKey< bool > ReceiveShadows
Flag stating if the mesh receives shadows.
TagSymbol TextureTagSymbol
Data type for SiliconStudio.Paradox.Effects.Mesh.
static readonly ParameterKey< bool > CastShadows
Flag stating if the mesh casts shadows.
Data type for SiliconStudio.Paradox.Effects.Model.
Performs hierarchical updates for a given Model.
Describes a single transformation node, usually in a Model node hierarchy.
static readonly ParameterKey< LightingConfigurationsSet > LightingConfigurations
Supported lighting configurations.
Content of a GPU buffer (vertex buffer, index buffer, etc...).
SiliconStudio.Paradox.Effects.ModelViewHierarchyDefinition Hierarchy
Data field for SiliconStudio.Paradox.Effects.Model.Hierarchy.
override IEnumerable< ObjectUrl > GetInputFiles()
Gets the list of input files (that can be deduced without running the command, only from command para...
A shader class used for mixin.
Represents a 4x4 mathematical matrix.