/// <summary> /// Adds a mesh to this transform /// </summary> /// <param name="_Mesh">The mesh to add</param> /// <remarks>This will transform into referenced shapes in the JSON file</remarks> public void AddMesh( LoaderTempMesh _Mesh ) { m_Meshes.Add( _Mesh ); }
/// <summary> /// Creates a Cirrus mesh node /// </summary> /// <param name="_Scene"></param> /// <param name="_FBXMesh"></param> /// <returns></returns> protected Scene.Nodes.Mesh CreateMesh( FBXImporter.NodeMesh _FBXMesh, Scene.Nodes.Node _Parent ) { // Create a temporary mesh that will be optimized later, when all meshes have been loaded LoaderTempMesh TempMesh = new LoaderTempMesh( this, _FBXMesh.Name ); if ( m_bGenerateBoundingBoxes ) TempMesh.BoundingBox = new WMath.BoundingBox( m_ScaleFactor * _FBXMesh.BoundingBox.m_Min, m_ScaleFactor * _FBXMesh.BoundingBox.m_Max ); // Handle pivot & reset X-Form if ( m_bResetXForm ) TempMesh.Pivot = _FBXMesh.Pivot; // Storing the mesh's pivot will have the effect of composing vertices with that matrix, actually performing the "reset X-Form" operation // else // Transform.Pivot = _FBXNode.Pivot; // Storing the mesh's pivot here will simply compose the mesh's transform with its pivot // Setup compulsory vertices and triangles Point[] SourceVertices = _FBXMesh.Vertices; Point[] ScaledVertices = new Point[SourceVertices.Length]; for ( int VertexIndex=0; VertexIndex < _FBXMesh.VerticesCount; VertexIndex++ ) ScaledVertices[VertexIndex] = m_ScaleFactor * SourceVertices[VertexIndex]; TempMesh.SetVertices( ScaledVertices ); TempMesh.SetFaces( _FBXMesh.Triangles ); // Setup all the possible recognized layers foreach ( FBXImporter.Layer Layer in _FBXMesh.Layers ) foreach ( FBXImporter.LayerElement LE in Layer.Elements ) { switch ( LE.ElementType ) { case FBXImporter.LayerElement.ELEMENT_TYPE.MATERIAL: case FBXImporter.LayerElement.ELEMENT_TYPE.UV: case FBXImporter.LayerElement.ELEMENT_TYPE.NORMAL: case FBXImporter.LayerElement.ELEMENT_TYPE.TANGENT: case FBXImporter.LayerElement.ELEMENT_TYPE.BINORMAL: case FBXImporter.LayerElement.ELEMENT_TYPE.VERTEX_COLOR: case FBXImporter.LayerElement.ELEMENT_TYPE.SMOOTHING: TempMesh.AddLayerElement( LE ); break; default: break; // Other types are not supported (or irrelevant)... } } // Build un-optimized primitives TempMesh.BuildPrimitives(); // Create the final scene mesh and tie it to our temporary mesh FBX.Scene.Nodes.Mesh Mesh = m_Scene.CreateMesh( _FBXMesh.Name, _Parent, _FBXMesh.LocalTransform ); m_TempMesh2FinalMesh[TempMesh] = Mesh; // Add some properties Mesh.Visible = _FBXMesh.Visible; // FBXImporter.ObjectProperty PropertyCastShadow = _FBXMesh.FindUserProperty( "CastShadow" ); // Mesh.CastShadow = PropertyCastShadow != null ? (bool) PropertyCastShadow.Value : true; Mesh.CastShadow = true; Mesh.ReceiveShadow = true; return Mesh; }
/// <summary> /// Replaces a layer element from this mesh by a reference to another element from another mesh /// </summary> /// <param name="_LayerElementSource">The source layer element to replace</param> /// <param name="_OwnerMesh">The mesh that owns the referenced layer element</param> /// <param name="_LayerElementReference">The layer element to reference in place of our own layer element</param> public void ReplaceLayerElementByAReference( FBXImporter.LayerElement _LayerElementSource, LoaderTempMesh _OwnerMesh, FBXImporter.LayerElement _LayerElementReference ) { m_LayerElements.Remove( _LayerElementSource ); ReferenceLayerElement RLE = new ReferenceLayerElement(); RLE.m_Owner = _OwnerMesh; RLE.m_LayerElement = _LayerElementReference; m_LayerElementsReference.Add( RLE ); }
/// <summary> /// Attempts to merge this mesh with the provided master mesh /// If the provided mesh can be used as a master for this mesh then the identical layer elements are "shared by reference" /// and the layer elements that differ are kept in this mesh and added as external elements to the master mesh. /// /// In the end, only the master meshes will be optimized, and this mesh's data along with them so all is left is to retrieve /// the optimized referenced data from the master mesh and make them our own. /// </summary> /// <returns>True if the merge was successful</returns> public bool MergeWithMasterMesh( LoaderTempMesh _Master ) { if ( !_Master.IsMaster ) return false; // Not a master mesh... // 1] Compare vertex, faces & primitives counts (easy comparisons first) if ( m_Vertices.Length != _Master.m_Vertices.Length ) return false; // Not identical ! if ( m_Faces.Length != _Master.m_Faces.Length ) return false; // Not identical ! if ( m_Primitives.Count != _Master.m_Primitives.Count ) return false; // Not identical ! // 2] Compare each primitive's vertex & faces count for ( int PrimitiveIndex=0; PrimitiveIndex < m_Primitives.Count; PrimitiveIndex++ ) { Primitive P0 = m_Primitives[PrimitiveIndex]; Primitive P1 = _Master.m_Primitives[PrimitiveIndex]; if ( P0.FacesCount != P1.FacesCount ) return false; // Not identical ! } // 3] Compare the vertices one by one for ( int VertexIndex=0; VertexIndex < m_Vertices.Length; VertexIndex++ ) { Point V0 = m_Vertices[VertexIndex]; Point V1 = _Master.m_Vertices[VertexIndex]; if ( V0 != V1 ) return false; } // 4] Compare the faces one by one for ( int FaceIndex=0; FaceIndex < m_Faces.Length; FaceIndex++ ) { FBXImporter.NodeMesh.Triangle F0 = m_Faces[FaceIndex]; FBXImporter.NodeMesh.Triangle F1 = _Master.m_Faces[FaceIndex]; if ( F0.Vertex0 != F1.Vertex0 || F0.Vertex1 != F1.Vertex1 || F0.Vertex2 != F1.Vertex2 ) return false; } ////////////////////////////////////////////////////////////////////////// // At this point, the 2 meshes are deemed identical (up to the point of Vertices and Faces at least) ////////////////////////////////////////////////////////////////////////// // Make this mesh a slave m_MasterMesh = _Master; // 5] Compare each of our Layer Elements to the master's and merge them // _ Layer Elements that are identical to the master will be replaced by references to the master's // _ Layer Elements that are different will be kept and will be added as external elements to the master // FBXImporter.LayerElement[] LayerElements = m_LayerElements.ToArray(); foreach ( FBXImporter.LayerElement LE0 in LayerElements ) { FBXImporter.LayerElement LE1 = null; foreach ( FBXImporter.LayerElement MasterLE in _Master.m_LayerElements ) if ( LE0.Compare( MasterLE ) ) { // Found a match ! LE1 = MasterLE; break; } if ( LE1 != null ) { // We found a matching layer element in the master mesh! // Now, we simply replace our own element by a reference to the master's element ReplaceLayerElementByAReference( LE0, _Master, LE1 ); } else { // We couldn't find a matching layer element! // That means this layer element is unique to our instance so we add it as an external element in the master mesh // When the master mesh will be consolidated, it will take our elements into account as well... _Master.AddExternalLayerElement( this, LE0 ); } } return true; }
/// <summary> /// Adds a layer element from another (slave) mesh /// </summary> /// <param name="_OwnerMesh">The mesh owning the layer element to add</param> /// <param name="_LayerElement">The external layer element</param> public void AddExternalLayerElement( LoaderTempMesh _OwnerMesh, FBXImporter.LayerElement _LayerElement ) { ExternalLayerElement ELE = new ExternalLayerElement(); ELE.m_Owner = _OwnerMesh; ELE.m_LayerElement = _LayerElement; m_LayerElementsExternal.Add( ELE ); // Add this mesh to our list of slave meshes if ( m_SlaveMesh2Registered.ContainsKey( _OwnerMesh ) ) return; // Already registered! m_SlaveMeshes.Add( _OwnerMesh ); m_SlaveMesh2Registered[_OwnerMesh] = true; }
public Primitive( LoaderTempMesh _OwnerMesh, SceneLoader _Owner, string _Name, FBXImporter.Material _Material ) : base(_Owner, _Name) { m_OwnerMesh = _OwnerMesh; m_Material = _Material; // if ( m_Material == null ) // throw new Exception( "Invalid material for primitive \"" + _Name + "\"!" ); }
public Scene.Nodes.Mesh.Primitive CreatePrimitive( LoaderTempMesh.Primitive _SourcePrimitive, Scene.Nodes.Mesh _ParentMesh, string _Name, Scene.Materials.MaterialParameters _MatParams ) { m_SourcePrimitive = _SourcePrimitive; Scene.Nodes.Mesh.Primitive Target = _ParentMesh.AddPrimitive( _Name, _MatParams, _SourcePrimitive.VerticesCount, _SourcePrimitive.FacesCount ); // Build the primitive's triangles for ( int FaceIndex=0; FaceIndex < _SourcePrimitive.FacesCount; FaceIndex++ ) { Target.Faces[FaceIndex].V0 = _SourcePrimitive.Faces[FaceIndex].V0.m_Index; Target.Faces[FaceIndex].V1 = _SourcePrimitive.Faces[FaceIndex].V1.m_Index; Target.Faces[FaceIndex].V2 = _SourcePrimitive.Faces[FaceIndex].V2.m_Index; } // Build the primitive's vertex streams int[] StreamIndices = new int[8]; foreach ( LoaderTempMesh.Primitive.VertexStream Stream in m_SourcePrimitive.VertexStreams ) { Scene.Nodes.Mesh.Primitive.VertexStream.USAGE Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.UNKNOWN; Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.UNKNOWN; object Content = null; switch ( Stream.StreamType ) { case LoaderTempMesh.VERTEX_INFO_TYPE.POSITION: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.POSITION; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for ( int i=0; i < _SourcePrimitive.VerticesCount; i++ ) { T[i] = (Vector) (Stream.Stream[i] as WMath.Point); } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.NORMAL: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.NORMAL; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for ( int i=0; i < _SourcePrimitive.VerticesCount; i++ ) { T[i] = Stream.Stream[i] as WMath.Vector; } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.TANGENT: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TANGENT; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for ( int i=0; i < _SourcePrimitive.VerticesCount; i++ ) { T[i] = Stream.Stream[i] as WMath.Vector; } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.BINORMAL: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.BITANGENT; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for ( int i=0; i < _SourcePrimitive.VerticesCount; i++ ) { T[i] = Stream.Stream[i] as WMath.Vector; } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.TEXCOORD1D: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TEXCOORDS; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT; float[] T = new float[_SourcePrimitive.VerticesCount]; Content = T; for ( int i=0; i < _SourcePrimitive.VerticesCount; i++ ) { T[i] = (float) Stream.Stream[i]; } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.TEXCOORD2D: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TEXCOORDS; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT2; Vector2D[] T = new Vector2D[_SourcePrimitive.VerticesCount]; Content = T; for ( int i=0; i < _SourcePrimitive.VerticesCount; i++ ) { T[i] = Stream.Stream[i] as WMath.Vector2D; T[i].Y = 1.0f - T[i].Y; // Here we must complement the V coordinate as MAX has the bad habit of inverting the Y axis of images! } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.TEXCOORD3D: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TEXCOORDS; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for ( int i=0; i < _SourcePrimitive.VerticesCount; i++ ) { T[i] = Stream.Stream[i] as WMath.Vector; T[i].Y = 1.0f - T[i].Y; // Here we must complement the V coordinate as MAX has the bad habit of inverting the Y axis of images! } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.COLOR_HDR: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.COLOR_HDR; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT4; Vector4D[] T = new Vector4D[_SourcePrimitive.VerticesCount]; Content = T; for ( int i=0; i < _SourcePrimitive.VerticesCount; i++ ) { T[i] = Stream.Stream[i] as WMath.Vector4D; } } break; } if ( Usage == Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.UNKNOWN || FieldType == Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.UNKNOWN ) continue; // Unsupported... Should we throw? if ( Content == null ) throw new Exception( "Invalid content!" ); int StreamIndexIndex = (int) Usage - 1; // Skip UNKNOWN usage and use the value as "stream type" int StreamIndex = StreamIndices[StreamIndexIndex]; StreamIndices[StreamIndexIndex]++; // Increase stream index Target.AddVertexStream( Usage, FieldType, StreamIndex, Content ); StreamIndex++; } return Target; }