public void CombineFace(Face face) { ulong matHash = _objHasher.GetMaterialFaceHash(face.TextureFace); int matIdx; if (!_knownMaterials.TryGetValue(matHash, out matIdx)) { _knownMaterials.Add(matHash, Materials.Count); matIdx = Materials.Count; Materials.Add(face.TextureFace); } _sortedFaces.Add(matIdx, face); }
/// <summary> /// Serializes the combined faces and returns a mesh /// </summary> private Tuple <string, object, List <object> > SerializeCombinedFaces( string parent, PrimDisplayData data, string materialType, string tempPath, BabylonOutputs outputs, ExportStats stats) { stats.PrimCount++; BabylonJSONPrimFaceCombiner combiner = new BabylonJSONPrimFaceCombiner(); foreach (var face in data.Mesh.Faces) { combiner.CombineFace(face); } combiner.Complete(); List <string> materialsList = new List <string>(); for (int i = 0; i < combiner.Materials.Count; i++) { var material = combiner.Materials[i]; float shinyPercent = ShinyToPercent(material.Shiny); bool hasTexture = material.TextureID != OpenMetaverse.UUID.Zero; //check the material tracker, if we already have this texture, don't export it again TrackedTexture trackedTexture = null; if (hasTexture) { if (outputs.Textures.ContainsKey(material.TextureID)) { trackedTexture = outputs.Textures[material.TextureID]; } else { string materialMapName = $"tex_mat_{material.TextureID}.{materialType}"; var kvp = this.WriteMaterialTexture(material.TextureID, materialMapName, tempPath, outputs.TextureFiles); outputs.Textures.Add(kvp.Key, kvp.Value); trackedTexture = kvp.Value; } } var matHash = _objHasher.GetMaterialFaceHash(material); if (!outputs.Materials.ContainsKey(matHash)) { bool hasTransparent = material.RGBA.A < 1.0f || (trackedTexture != null && trackedTexture.HasAlpha); object texture = null; if (hasTexture) { texture = new { name = trackedTexture.Name, level = 1, hasAlpha = hasTransparent, getAlphaFromRGB = false, coordinatesMode = 0, uOffset = 0, vOffset = 0, uScale = 1, vScale = 1, uAng = 0, vAng = 0, wAng = 0, wrapU = true, wrapV = true, coordinatesIndex = 0 }; } var jsMaterial = new { name = matHash.ToString(), id = matHash.ToString(), ambient = new[] { material.RGBA.R, material.RGBA.G, material.RGBA.B }, diffuse = new[] { material.RGBA.R, material.RGBA.G, material.RGBA.B }, specular = new[] { material.RGBA.R *shinyPercent, material.RGBA.G *shinyPercent, material.RGBA.B *shinyPercent }, specularPower = 50, emissive = new[] { 0.01f, 0.01f, 0.01f }, alpha = material.RGBA.A, backFaceCulling = true, wireframe = false, diffuseTexture = hasTexture ? texture : null, useLightmapAsShadowmap = false, checkReadOnlyOnce = true }; outputs.Materials.Add(matHash, jsMaterial); } materialsList.Add(matHash.ToString()); } var multiMaterialName = data.MaterialHash + "_mm"; if (!outputs.MultiMaterials.ContainsKey(data.MaterialHash)) { //create the multimaterial var multiMaterial = new { name = multiMaterialName, id = multiMaterialName, materials = materialsList }; outputs.MultiMaterials[data.MaterialHash] = multiMaterial; } //finally serialize the mesh float[] identity4x4 = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; List <object> submeshes = new List <object>(); foreach (var subMesh in combiner.SubMeshes) { submeshes.Add(new { materialIndex = subMesh.MaterialIndex, verticesStart = subMesh.VerticesStart, verticesCount = subMesh.VerticesCount, indexStart = subMesh.IndexStart, indexCount = subMesh.IndexCount }); stats.SubmeshCount++; } List <object> instanceList = null; if (parent == null) { instanceList = new List <object>(); } //if this is a child prim, decouple its coordinate system from the parent //it seems like babylon loads the object, and then applies the parentage //after the object is already in world /*if (parent != null) * { * Quaternion parentRot = data.Parent.OffsetRotation; * * Vector3 axPos = data.OffsetPosition; * axPos *= parentRot; * Vector3 translationOffsetPosition = axPos; * * pos = data.Parent.OffsetPosition + translationOffsetPosition; * rot = data.Parent.OffsetRotation * data.OffsetRotation; * }*/ //if this is a child prim, divide out the scale of the parent var scale = data.Scale; if (parent != null) { scale /= data.Parent.Scale; } Vector3 pos = data.OffsetPosition; Quaternion rot = data.OffsetRotation; if (parent == null) { FixCoordinateSystem(ref pos, ref rot); } var primId = data.ShapeHash + "_" + data.MaterialHash + (parent == null ? "_P" : ""); var mesh = new { name = primId, id = primId, parentId = parent, materialId = multiMaterialName, position = new [] { pos.X, pos.Y, pos.Z }, rotationQuaternion = new[] { rot.X, rot.Y, rot.Z, rot.W }, scaling = new[] { scale.X, scale.Y, scale.Z }, pivotMatrix = identity4x4, infiniteDistance = false, showBoundingBox = false, showSubMeshesBoundingBox = false, isVisible = true, isEnabled = true, pickable = true, applyFog = false, checkCollisions = false, receiveShadows = false, positions = combiner.Vertices, normals = combiner.Normals, uvs = combiner.UVs, indices = combiner.Indices, subMeshes = submeshes, autoAnimate = false, billboardMode = 0, instances = instanceList }; return(new Tuple <string, object, List <object> >(primId, mesh, instanceList)); }
/// <summary> /// Serializes the combined faces and returns a mesh /// </summary> private Tuple <string, Mesh, List <MeshInstance> > SerializeCombinedFaces( string parent, PrimDisplayData data, string materialType, string tempPath, BabylonFlatBufferOutputs outputs, ExportStats stats) { stats.PrimCount++; BabylonPrimFaceCombiner combiner = new BabylonPrimFaceCombiner(); foreach (var face in data.Mesh.Faces) { combiner.CombineFace(face); } combiner.Complete(); List <string> materialsList = new List <string>(); for (int i = 0; i < combiner.Materials.Count; i++) { var material = combiner.Materials[i]; float shinyPercent = ShinyToPercent(material.Shiny); bool hasTexture = material.TextureID != OpenMetaverse.UUID.Zero; //check the material tracker, if we already have this texture, don't export it again TrackedTexture trackedTexture = null; if (hasTexture) { if (outputs.Textures.ContainsKey(material.TextureID)) { trackedTexture = outputs.Textures[material.TextureID]; } else { string materialMapName = $"tex_mat_{material.TextureID}.{materialType}"; var kvp = this.WriteMaterialTexture(material.TextureID, materialMapName, tempPath, outputs.TextureFiles); outputs.Textures.Add(kvp.Key, kvp.Value); trackedTexture = kvp.Value; } } var matHash = _objHasher.GetMaterialFaceHash(material); if (!outputs.Materials.ContainsKey(matHash)) { bool hasTransparent = material.RGBA.A < 1.0f || (trackedTexture != null && trackedTexture.HasAlpha); Texture texture = null; if (hasTexture) { texture = new Texture() { HasAlpha = hasTransparent, Name = trackedTexture.Name }; } BabylonFlatBufferIntermediates.Material jsMaterial = new BabylonFlatBufferIntermediates.Material() { Alpha = material.RGBA.A, Color = new[] { material.RGBA.R, material.RGBA.G, material.RGBA.B }, DiffuseTexture = hasTexture ? texture : null, Id = matHash.ToString(), Name = matHash.ToString(), ShinyPercent = shinyPercent }; outputs.Materials.Add(matHash, jsMaterial); } materialsList.Add(matHash.ToString()); } var multiMaterialName = data.MaterialHash + "_mm"; if (!outputs.MultiMaterials.ContainsKey(data.MaterialHash)) { //create the multimaterial var multiMaterial = new MultiMaterial() { Id = multiMaterialName, MaterialsList = materialsList, Name = multiMaterialName }; outputs.MultiMaterials[data.MaterialHash] = multiMaterial; } List <SubMesh> submeshes = new List <SubMesh>(); foreach (var subMesh in combiner.SubMeshes) { submeshes.Add(new SubMesh() { MaterialIndex = subMesh.MaterialIndex, VerticesStart = subMesh.VerticesStart, VerticesCount = subMesh.VerticesCount, IndexStart = subMesh.IndexStart, IndexCount = subMesh.IndexCount }); stats.SubmeshCount++; } List <MeshInstance> instanceList = null; if (parent == null) { instanceList = new List <MeshInstance>(); } //if this is a child prim, divide out the scale of the parent var scale = data.Scale; if (parent != null) { scale /= data.Parent.Scale; } Vector3 pos = data.OffsetPosition; Quaternion rot = data.OffsetRotation; if (parent == null) { FixCoordinateSystem(ref pos, ref rot); } var primId = data.ShapeHash + "_" + data.MaterialHash + (parent == null ? "_P" : ""); Mesh mesh = new Mesh() { Name = primId, Id = primId, ParentId = parent, MaterialId = multiMaterialName, Position = new [] { pos.X, pos.Y, pos.Z }, RotationQuaternion = new[] { rot.X, rot.Y, rot.Z, rot.W }, Scaling = new[] { scale.X, scale.Y, scale.Z }, Positions = combiner.Vertices, Normals = combiner.Normals, UVs = combiner.UVs, Indices = combiner.Indices, Submeshes = submeshes, Instances = instanceList }; return(new Tuple <string, Mesh, List <MeshInstance> >(primId, mesh, instanceList)); }