// ----------------------------------------- // DumpAnims // ----------------------------------------- void DumpAnims(GameObject _animPrefab, GLTF _gltf, BufferInfo _bufInfo) { // get animations GameObject prefabInst = PrefabUtility.InstantiatePrefab(_animPrefab) as GameObject; List <AnimationClip> clips = Utils.GetAnimationClips(prefabInst); // get joints List <GameObject> joints = new List <GameObject>(); Utils.RecurseNode(prefabInst, _go => { // this is not a joint if (_go.GetComponent <SkinnedMeshRenderer>() != null) { return(false); } joints.Add(_go); return(true); }); // if (clips != null) { // process AnimationClip(s) foreach (AnimationClip clip in clips) { int accOffset = _bufInfo.GetAccessorCount(); AnimData animData = DumpAnimData(prefabInst, clip); DumpBufferInfoFromAnimData(animData, _bufInfo); GLTF_AnimationEx gltfAnim = DumpGltfAnimationEx(animData, joints, accOffset); _gltf.animations.Add(gltfAnim); } } Object.DestroyImmediate(prefabInst); }
// ----------------------------------------- // DumpBufferInfoFromMesh // ----------------------------------------- void DumpBufferInfoFromMesh(Mesh _mesh, BufferInfo _bufInfo) { int vertexBytes = 0; byte[] vertexData; List <byte[]> indexDataList = new List <byte[]>(); byte[] bindposesData; Vector3[] vertices = _mesh.vertices; Vector3[] normals = _mesh.normals; Vector4[] tangents = _mesh.tangents; Color[] colors = _mesh.colors; Vector2[] uv = _mesh.uv; Vector2[] uv2 = _mesh.uv2; Vector2[] uv3 = _mesh.uv3; Vector2[] uv4 = _mesh.uv4; BoneWeight[] boneWeights = _mesh.boneWeights; int offsetNormal = 0; int offsetTangent = 0; int offsetColor = 0; int offsetUV = 0; int offsetUV2 = 0; int offsetUV3 = 0; int offsetUV4 = 0; int offsetJoint = 0; int offsetWeight = 0; int offsetBuffer = _bufInfo.data.Length; Vector3 minPos = Vector3.zero; Vector3 maxPos = Vector3.zero; Vector3 minNormal = Vector3.zero; Vector3 maxNormal = Vector3.zero; Vector4 minTangent = Vector4.zero; Vector4 maxTangent = Vector4.zero; if (vertices.Length > 0) { minPos = maxPos = vertices[0]; vertexBytes += 12; // float32 * 3 } if (normals.Length > 0) { offsetNormal = vertexBytes; vertexBytes += 12; // float32 * 3 } if (tangents.Length > 0) { offsetTangent = vertexBytes; vertexBytes += 16; // float32 * 4 } if (colors.Length > 0) { offsetColor = vertexBytes; vertexBytes += 16; // float32 * 4 } if (uv.Length > 0) { offsetUV = vertexBytes; vertexBytes += 8; // float32 * 2 } if (uv2.Length > 0) { offsetUV2 = vertexBytes; vertexBytes += 8; // float32 * 2 } if (uv3.Length > 0) { offsetUV3 = vertexBytes; vertexBytes += 8; // float32 * 2 } if (uv4.Length > 0) { offsetUV4 = vertexBytes; vertexBytes += 8; // float32 * 2 } if (boneWeights.Length > 0) { offsetJoint = vertexBytes; vertexBytes += 8; // uint16 * 4 offsetWeight = vertexBytes; vertexBytes += 16; // float32 * 4 } // vertexData using (MemoryStream stream = new MemoryStream(vertexBytes * _mesh.vertexCount)) { using (BinaryWriter writer = new BinaryWriter(stream)) { for (int i = 0; i < _mesh.vertexCount; ++i) { if (vertices.Length > 0) { Vector3 vert = vertices[i]; // NOTE: convert LH to RH vert.z = -vert.z; writer.Write(vert.x); writer.Write(vert.y); writer.Write(vert.z); if (vert.x < minPos.x) { minPos.x = vert.x; } if (vert.y < minPos.y) { minPos.y = vert.y; } if (vert.z < minPos.z) { minPos.z = vert.z; } if (vert.x > maxPos.x) { maxPos.x = vert.x; } if (vert.y > maxPos.y) { maxPos.y = vert.y; } if (vert.z > maxPos.z) { maxPos.z = vert.z; } } if (normals.Length > 0) { Vector3 normal = normals[i]; // NOTE: convert LH to RH normal.z = -normal.z; writer.Write(normal.x); writer.Write(normal.y); writer.Write(normal.z); if (normal.x < minNormal.x) { minNormal.x = normal.x; } if (normal.y < minNormal.y) { minNormal.y = normal.y; } if (normal.z < minNormal.z) { minNormal.z = normal.z; } if (normal.x > maxNormal.x) { maxNormal.x = normal.x; } if (normal.y > maxNormal.y) { maxNormal.y = normal.y; } if (normal.z > maxNormal.z) { maxNormal.z = normal.z; } } if (tangents.Length > 0) { Vector4 tangent = tangents[i]; // NOTE: convert LH to RH tangent.z = -tangent.z; writer.Write(tangent.x); writer.Write(tangent.y); writer.Write(tangent.z); writer.Write(tangent.w); if (tangent.x < minTangent.x) { minTangent.x = tangent.x; } if (tangent.y < minTangent.y) { minTangent.y = tangent.y; } if (tangent.z < minTangent.z) { minTangent.z = tangent.z; } if (tangent.w < minTangent.w) { minTangent.w = tangent.w; } if (tangent.x > maxTangent.x) { maxTangent.x = tangent.x; } if (tangent.y > maxTangent.y) { maxTangent.y = tangent.y; } if (tangent.z > maxTangent.z) { maxTangent.z = tangent.z; } if (tangent.w > maxTangent.w) { maxTangent.w = tangent.w; } } if (colors.Length > 0) { writer.Write(colors[i].r); writer.Write(colors[i].g); writer.Write(colors[i].b); writer.Write(colors[i].a); } if (uv.Length > 0) { writer.Write(uv[i].x); writer.Write(uv[i].y); } if (uv2.Length > 0) { writer.Write(uv2[i].x); writer.Write(uv2[i].y); } if (uv3.Length > 0) { writer.Write(uv3[i].x); writer.Write(uv3[i].y); } if (uv4.Length > 0) { writer.Write(uv4[i].x); writer.Write(uv4[i].y); } if (boneWeights.Length > 0) { writer.Write((ushort)boneWeights[i].boneIndex0); writer.Write((ushort)boneWeights[i].boneIndex1); writer.Write((ushort)boneWeights[i].boneIndex2); writer.Write((ushort)boneWeights[i].boneIndex3); writer.Write(boneWeights[i].weight0); writer.Write(boneWeights[i].weight1); writer.Write(boneWeights[i].weight2); writer.Write(boneWeights[i].weight3); } } } vertexData = stream.ToArray(); } // indexDataList for (int i = 0; i < _mesh.subMeshCount; ++i) { int[] subTriangles = _mesh.GetTriangles(i); if (subTriangles.Length > 0) { using (MemoryStream stream = new MemoryStream(2 * subTriangles.Length)) { using (BinaryWriter writer = new BinaryWriter(stream)) { // DISABLE // for ( int ii = 0; ii < subTriangles.Length; ++ii ) { // writer.Write((ushort)subTriangles[ii]); // } // NOTE: convert mesh winding order from CW (Unity3D's) to CCW (most webgl programs) for (int ii = 0; ii < subTriangles.Length / 3; ++ii) { writer.Write((ushort)subTriangles[3 * ii]); writer.Write((ushort)subTriangles[3 * ii + 2]); writer.Write((ushort)subTriangles[3 * ii + 1]); } } indexDataList.Add(stream.ToArray()); } } } // bindposesData using (MemoryStream stream = new MemoryStream(4 * 16 * _mesh.bindposes.Length)) { using (BinaryWriter writer = new BinaryWriter(stream)) { for (int i = 0; i < _mesh.bindposes.Length; ++i) { Matrix4x4 bindpose = _mesh.bindposes[i]; // NOTE: convert LH to RH writer.Write(bindpose[0]); writer.Write(bindpose[1]); writer.Write(-bindpose[2]); // a02 writer.Write(bindpose[3]); writer.Write(bindpose[4]); writer.Write(bindpose[5]); writer.Write(-bindpose[6]); // a12 writer.Write(bindpose[7]); writer.Write(-bindpose[8]); // a20 writer.Write(-bindpose[9]); // a21 writer.Write(bindpose[10]); writer.Write(bindpose[11]); writer.Write(bindpose[12]); writer.Write(bindpose[13]); writer.Write(-bindpose[14]); // b2 writer.Write(bindpose[15]); } } bindposesData = stream.ToArray(); } // bufferViews List <BufferViewInfo> bufferViews = new List <BufferViewInfo>(); // vbView BufferViewInfo vbView = new BufferViewInfo { name = "vb@" + _mesh.name, offset = offsetBuffer, length = vertexData.Length, stride = vertexBytes, type = BufferType.VERTEX, accessors = new List <AccessorInfo>(), }; if (vertices.Length > 0) { AccessorInfo acc = new AccessorInfo { name = "position@" + _mesh.name, offset = 0, count = _mesh.vertexCount, compType = ComponentType.FLOAT32, attrType = AttrType.VEC3, min = new object[3] { minPos.x, minPos.y, minPos.z }, max = new object[3] { maxPos.x, maxPos.y, maxPos.z }, }; vbView.accessors.Add(acc); } if (normals.Length > 0) { AccessorInfo acc = new AccessorInfo { name = "normal@" + _mesh.name, offset = offsetNormal, count = _mesh.vertexCount, compType = ComponentType.FLOAT32, attrType = AttrType.VEC3, min = new object[3] { minNormal.x, minNormal.y, minNormal.z }, max = new object[3] { maxNormal.x, maxNormal.y, maxNormal.z }, }; vbView.accessors.Add(acc); } if (tangents.Length > 0) { AccessorInfo acc = new AccessorInfo { name = "tangent@" + _mesh.name, offset = offsetTangent, count = _mesh.vertexCount, compType = ComponentType.FLOAT32, attrType = AttrType.VEC4, min = new object[4] { minTangent.x, minTangent.y, minTangent.z, minTangent.w }, max = new object[4] { maxTangent.x, maxTangent.y, maxTangent.z, maxTangent.w }, }; vbView.accessors.Add(acc); } if (colors.Length > 0) { AccessorInfo acc = new AccessorInfo { name = "color@" + _mesh.name, offset = offsetColor, count = _mesh.vertexCount, compType = ComponentType.FLOAT32, attrType = AttrType.VEC4, // TODO: min, max }; vbView.accessors.Add(acc); } if (uv.Length > 0) { AccessorInfo acc = new AccessorInfo { name = "uv0@" + _mesh.name, offset = offsetUV, count = _mesh.vertexCount, compType = ComponentType.FLOAT32, attrType = AttrType.VEC2, // TODO: min, max }; vbView.accessors.Add(acc); } if (uv2.Length > 0) { AccessorInfo acc = new AccessorInfo { name = "uv1@" + _mesh.name, offset = offsetUV2, count = _mesh.vertexCount, compType = ComponentType.FLOAT32, attrType = AttrType.VEC2, // TODO: min, max }; vbView.accessors.Add(acc); } if (uv3.Length > 0) { AccessorInfo acc = new AccessorInfo { name = "uv2@" + _mesh.name, offset = offsetUV3, count = _mesh.vertexCount, compType = ComponentType.FLOAT32, attrType = AttrType.VEC2, // TODO: min, max }; vbView.accessors.Add(acc); } if (uv4.Length > 0) { AccessorInfo acc = new AccessorInfo { name = "uv3@" + _mesh.name, offset = offsetUV4, count = _mesh.vertexCount, compType = ComponentType.FLOAT32, attrType = AttrType.VEC2, // TODO: min, max }; vbView.accessors.Add(acc); } if (boneWeights.Length > 0) { AccessorInfo acc = new AccessorInfo { name = "joints@" + _mesh.name, offset = offsetJoint, count = _mesh.vertexCount, compType = ComponentType.UINT16, attrType = AttrType.VEC4, // TODO: min, max }; vbView.accessors.Add(acc); acc = new AccessorInfo { name = "weights@" + _mesh.name, offset = offsetWeight, count = _mesh.vertexCount, compType = ComponentType.FLOAT32, attrType = AttrType.VEC4, // TODO: min, max }; vbView.accessors.Add(acc); } // bufferViews.Add(vbView); offsetBuffer += Utils.Align(vbView.length, 4); // ibView for (int i = 0; i < indexDataList.Count; ++i) { byte[] indexData = indexDataList[i]; BufferViewInfo ibView = new BufferViewInfo { name = "ib" + i + "@" + _mesh.name, offset = offsetBuffer, length = indexData.Length, type = BufferType.INDEX, accessors = new List <AccessorInfo>(), }; AccessorInfo acc = new AccessorInfo { name = "indices" + i + "@" + _mesh.name, offset = 0, count = indexData.Length / 2, compType = ComponentType.UINT16, attrType = AttrType.SCALAR, }; ibView.accessors.Add(acc); bufferViews.Add(ibView); offsetBuffer += Utils.Align(ibView.length, 4); } // bpView if (bindposesData.Length > 0) { BufferViewInfo bpView = new BufferViewInfo { name = "bp@" + _mesh.name, offset = offsetBuffer, length = bindposesData.Length, type = BufferType.NONE, accessors = new List <AccessorInfo>(), }; AccessorInfo acc = new AccessorInfo { name = "bindposes@" + _mesh.name, offset = 0, count = bindposesData.Length / (4 * 16), compType = ComponentType.FLOAT32, attrType = AttrType.MAT4, }; bpView.accessors.Add(acc); bufferViews.Add(bpView); offsetBuffer += Utils.Align(bpView.length, 4); } // data byte[] data = new byte[offsetBuffer]; int offset = 0; System.Buffer.BlockCopy(_bufInfo.data, 0, data, offset, _bufInfo.data.Length); offset += _bufInfo.data.Length; System.Buffer.BlockCopy(vertexData, 0, data, offset, vertexData.Length); offset += Utils.Align(vertexData.Length, 4); for (int i = 0; i < indexDataList.Count; ++i) { System.Buffer.BlockCopy(indexDataList[i], 0, data, offset, indexDataList[i].Length); offset += Utils.Align(indexDataList[i].Length, 4); } System.Buffer.BlockCopy(bindposesData, 0, data, offset, bindposesData.Length); offset += Utils.Align(bindposesData.Length, 4); // _bufInfo.data = data; _bufInfo.bufferViews.AddRange(bufferViews); }
Dictionary <string, JSON_Asset> saveAssets( string dest, List <Object> prefabs, List <Object> modelPrefabs, List <Mesh> meshes, List <Texture> textures, List <Texture> spriteTextures, List <Material> materials, List <Font> fonts ) { Dictionary <string, JSON_Asset> assetsJson = new Dictionary <string, JSON_Asset>(); // DELME { // // save meshes // var destMeshes = Path.Combine(dest, "meshes"); // foreach (Mesh mesh in meshes) { // string id = Utils.AssetID(mesh); // GLTF gltf = new GLTF(); // gltf.asset = new GLTF_Asset // { // version = "1.0.0", // generator = "u3d-exporter" // }; // BufferInfo bufInfo = new BufferInfo // { // id = id, // name = mesh.name // }; // DumpMesh(mesh, gltf, bufInfo, 0); // DumpBuffer(bufInfo, gltf); // Save( // destMeshes, // id, // gltf, // new List<BufferInfo> { bufInfo } // ); // // add asset to table // assetsJson.Add(id, new JSON_Asset { // type = "mesh", // urls = new Dictionary<string, string> { // { "gltf", "meshes/" + id + ".gltf" }, // { "bin", "meshes/" + id + ".bin" } // } // }); // } // } DELME // ======================================== // save animations // ======================================== var destAnims = Path.Combine(dest, "anims"); foreach (GameObject prefab in prefabs) { // skip ModelPrefab if (PrefabUtility.GetPrefabType(prefab) == PrefabType.ModelPrefab) { Debug.LogWarning("Can not export model prefab " + prefab.name + " in the scene"); continue; } // skip non-animation prefab bool isAnimPrefab = Utils.IsAnimPrefab(prefab); if (isAnimPrefab == false) { continue; } // get animations GameObject prefabInst = PrefabUtility.InstantiatePrefab(prefab) as GameObject; List <AnimationClip> clips = Utils.GetAnimationClips(prefabInst); // get joints List <GameObject> joints = new List <GameObject>(); Utils.RecurseNode(prefabInst, _go => { // this is not a joint if (_go.GetComponent <SkinnedMeshRenderer>() != null) { return(false); } joints.Add(_go); return(true); }); // dump animation clips if (clips != null) { // process AnimationClip(s) foreach (AnimationClip clip in clips) { string id = Utils.AssetID(clip); GLTF gltf = new GLTF(); gltf.asset = new GLTF_Asset { version = "1.0.0", generator = "u3d-exporter" }; BufferInfo bufInfo = new BufferInfo { id = id, name = prefab.name }; AnimData animData = DumpAnimData(prefabInst, clip); DumpBufferInfoFromAnimData(animData, bufInfo); GLTF_AnimationEx gltfAnim = DumpGltfAnimationEx(animData, joints, 0); gltf.animations.Add(gltfAnim); DumpBuffer(bufInfo, gltf); Save( destAnims, id + ".anim", gltf, new List <BufferInfo> { bufInfo } ); // add asset to table try { if (!assetsJson.ContainsKey(id)) { assetsJson.Add(id, new JSON_Asset { type = "animation", urls = new Dictionary <string, string> { { "anim", "anims/" + id + ".anim" }, { "bin", "anims/" + id + ".bin" } } }); } } catch (System.SystemException e) { Debug.LogError("Failed to add " + id + " to assets: " + e); } } } Object.DestroyImmediate(prefabInst); } // ======================================== // save prefabs // ======================================== var destMeshes = Path.Combine(dest, "meshes"); var destPrefabs = Path.Combine(dest, "prefabs"); // create dest directory if (!Directory.Exists(destMeshes)) { Directory.CreateDirectory(destMeshes); } if (!Directory.Exists(destPrefabs)) { Directory.CreateDirectory(destPrefabs); } foreach (GameObject prefab in prefabs) { string id = Utils.AssetID(prefab); // save prefabs if (PrefabUtility.GetPrefabType(prefab) == PrefabType.ModelPrefab) { Debug.LogWarning("Can not export model prefab " + prefab.name + " in the scene"); continue; } var prefabJson = DumpPrefab(prefab); string path; string json = JsonConvert.SerializeObject(prefabJson, Formatting.Indented); path = Path.Combine(destPrefabs, id + ".json"); StreamWriter writer = new StreamWriter(path); writer.Write(json); writer.Close(); // Debug.Log(Path.GetFileName(path) + " saved."); // add asset to table if (!assetsJson.ContainsKey(id)) { assetsJson.Add(id, new JSON_Asset { type = "prefab", urls = new Dictionary <string, string> { { "json", "prefabs/" + id + ".json" }, } }); } } // save model prefab (as gltf) foreach (GameObject modelPrefab in modelPrefabs) { string id = Utils.AssetID(modelPrefab); // save model prefabs GLTF gltf = new GLTF(); gltf.asset = new GLTF_Asset { version = "1.0.0", generator = "u3d-exporter" }; BufferInfo bufInfo = new BufferInfo { id = id, name = modelPrefab.name }; bool isAnimPrefab = Utils.IsAnimPrefab(modelPrefab); if (isAnimPrefab) { DumpSkinningModel(modelPrefab, gltf, bufInfo); DumpBuffer(bufInfo, gltf); } else { DumpModel(modelPrefab, gltf, bufInfo); DumpBuffer(bufInfo, gltf); } Save( destMeshes, id + ".gltf", gltf, new List <BufferInfo> { bufInfo } ); // add asset to table if (!assetsJson.ContainsKey(id)) { assetsJson.Add(id, new JSON_Asset { type = "gltf", urls = new Dictionary <string, string> { { "gltf", "meshes/" + id + ".gltf" }, { "bin", "meshes/" + id + ".bin" } } }); } } // save meshes (as gltf) foreach (Mesh mesh in meshes) { string id = Utils.AssetID(mesh); // save model prefabs GLTF gltf = new GLTF(); gltf.asset = new GLTF_Asset { version = "1.0.0", generator = "u3d-exporter" }; BufferInfo bufInfo = new BufferInfo { id = id, name = mesh.name }; DumpMesh(mesh, gltf, bufInfo, 0); DumpBuffer(bufInfo, gltf); Save( destMeshes, id + ".mesh", gltf, new List <BufferInfo> { bufInfo } ); // add asset to table if (!assetsJson.ContainsKey(id)) { assetsJson.Add(id, new JSON_Asset { type = "mesh", urls = new Dictionary <string, string> { { "mesh", "meshes/" + id + ".mesh" }, { "bin", "meshes/" + id + ".bin" } } }); } } // ======================================== // save textures // ======================================== var destTextures = Path.Combine(dest, "textures"); // create dest directory if (!Directory.Exists(destTextures)) { Directory.CreateDirectory(destTextures); } foreach (Texture tex in textures) { var textureJson = DumpTexture(tex); string path; string json = JsonConvert.SerializeObject(textureJson, Formatting.Indented); string id = Utils.AssetID(tex); // json path = Path.Combine(destTextures, id + ".json"); StreamWriter writer = new StreamWriter(path); writer.Write(json); writer.Close(); // image string assetPath = AssetDatabase.GetAssetPath(tex); path = Path.Combine(destTextures, id + Utils.AssetExt(tex)); File.Copy(assetPath, path, true); // Debug.Log(Path.GetFileName(path) + " saved."); // add asset to table if (!assetsJson.ContainsKey(id)) { assetsJson.Add(id, new JSON_Asset { type = "texture", urls = new Dictionary <string, string> { { "json", "textures/" + id + ".json" }, { "image", "textures/" + id + Utils.AssetExt(tex) }, } }); } } // ======================================== // save sprite textures // ======================================== var destSprites = Path.Combine(dest, "sprites"); // create dest directory if (!Directory.Exists(destSprites)) { Directory.CreateDirectory(destSprites); } foreach (Texture spriteTex in spriteTextures) { var spriteTextureJson = DumpSpriteTexture(spriteTex); string path; string json = JsonConvert.SerializeObject(spriteTextureJson, Formatting.Indented); string id = Utils.AssetID(spriteTex); // json path = Path.Combine(destSprites, id + ".json"); StreamWriter writer = new StreamWriter(path); writer.Write(json); writer.Close(); // image string assetPath = AssetDatabase.GetAssetPath(spriteTex); path = Path.Combine(destSprites, id + Utils.AssetExt(spriteTex)); File.Copy(assetPath, path); // add asset to table if (!assetsJson.ContainsKey(id)) { assetsJson.Add(id, new JSON_Asset { type = "texture", urls = new Dictionary <string, string> { { "json", "sprites/" + id + ".json" }, { "image", "sprites/" + id + Utils.AssetExt(spriteTex) }, } }); } } // ======================================== // save fonts // ======================================== var destFonts = Path.Combine(dest, "fonts"); if (!Directory.Exists(destFonts)) { Directory.CreateDirectory(destFonts); } foreach (Font font in fonts) { if (font.dynamic) { if (font.fontNames.Length > 1) // system font // do nothing { } else // opentype font { JSON_OpenTypeFont fontJson = DumpOpenTypeFont(font); // save font json string path; string json = JsonConvert.SerializeObject(fontJson, Formatting.Indented); string id = Utils.AssetID(font); path = Path.Combine(destFonts, id + ".json"); StreamWriter writer = new StreamWriter(path); writer.Write(json); writer.Close(); // save font file (ttf) Texture tex = font.material.mainTexture; string assetPath = AssetDatabase.GetAssetPath(font); path = Path.Combine(destFonts, id + Utils.AssetExt(font)); File.Copy(assetPath, path, true); if (!assetsJson.ContainsKey(id)) { assetsJson.Add(id, new JSON_Asset { type = "otfont", urls = new Dictionary <string, string> { { "json", "fonts/" + id + ".json" }, { "bin", "fonts/" + id + Utils.AssetExt(font) }, } }); } } } else // bitmapFont { JSON_BitmapFont fontJson = DumpBitmapFont(font); string path; string json = JsonConvert.SerializeObject(fontJson, Formatting.Indented); string id = Utils.AssetID(font); path = Path.Combine(destFonts, id + ".json"); StreamWriter writer = new StreamWriter(path); writer.Write(json); writer.Close(); if (!assetsJson.ContainsKey(id)) { assetsJson.Add(id, new JSON_Asset { type = "bmfont", urls = new Dictionary <string, string> { { "json", "fonts/" + id + ".json" }, } }); } } } // ======================================== // save materials // ======================================== var destMaterials = Path.Combine(dest, "materials"); // create dest directory if (!Directory.Exists(destMaterials)) { Directory.CreateDirectory(destMaterials); } foreach (Material mat in materials) { var materialJson = DumpMaterial(mat); if (materialJson == null) { continue; } string path; string json = JsonConvert.SerializeObject(materialJson, Formatting.Indented); string id = Utils.AssetID(mat); // json path = Path.Combine(destMaterials, id + ".json"); StreamWriter writer = new StreamWriter(path); writer.Write(json); writer.Close(); // Debug.Log(Path.GetFileName(path) + " saved."); // add asset to table if (!assetsJson.ContainsKey(id)) { assetsJson.Add(id, new JSON_Asset { type = "material", urls = new Dictionary <string, string> { { "json", "materials/" + id + ".json" }, } }); } } // ======================================== // save assets // ======================================== { string path = Path.Combine(dest, "assets.json"); string json = JsonConvert.SerializeObject(assetsJson, Formatting.Indented); StreamWriter writer = new StreamWriter(path); writer.Write(json); writer.Close(); } return(assetsJson); }
// ----------------------------------------- // DumpBufferInfoFromAnimData // ----------------------------------------- void DumpBufferInfoFromAnimData(AnimData _animData, BufferInfo _bufInfo) { List <AccessorInfo> accessors = new List <AccessorInfo>(); // calculate total length of animation-data int length = 0; AccessorInfo acc; // time0 acc = new AccessorInfo { name = "time0@" + _animData.name, offset = length, count = 1, compType = ComponentType.FLOAT32, attrType = AttrType.SCALAR }; accessors.Add(acc); length += 4; // times acc = new AccessorInfo { name = "times@" + _animData.name, offset = length, count = _animData.times.Count, compType = ComponentType.FLOAT32, attrType = AttrType.SCALAR }; accessors.Add(acc); length += _animData.times.Count * 4; // frames foreach (var entry in _animData.nameToFrames) { NodeFrames frames = entry.Value; if (frames.tlist.Count > 0) { acc = new AccessorInfo { name = frames.node.name + "_T@" + _animData.name, offset = length, count = frames.tlist.Count, compType = ComponentType.FLOAT32, attrType = AttrType.VEC3 }; accessors.Add(acc); length += frames.tlist.Count * 12; } if (frames.slist.Count > 0) { acc = new AccessorInfo { name = frames.node.name + "_S@" + _animData.name, offset = length, count = frames.slist.Count, compType = ComponentType.FLOAT32, attrType = AttrType.VEC3 }; accessors.Add(acc); length += frames.slist.Count * 12; } if (frames.rlist.Count > 0) { acc = new AccessorInfo { name = frames.node.name + "_R@" + _animData.name, offset = length, count = frames.rlist.Count, compType = ComponentType.FLOAT32, attrType = AttrType.VEC4 }; accessors.Add(acc); length += frames.rlist.Count * 16; } } // write data byte[] clipData; using (MemoryStream stream = new MemoryStream(length)) { using (BinaryWriter writer = new BinaryWriter(stream)) { // time0 writer.Write(0.0f); // times for (int i = 0; i < _animData.times.Count; ++i) { writer.Write(_animData.times[i]); } foreach (var entry in _animData.nameToFrames) { NodeFrames frames = entry.Value; if (frames.tlist.Count > 0) { for (int i = 0; i < frames.tlist.Count; ++i) { // NOTE: convert LH to RH writer.Write(frames.tlist[i].x); writer.Write(frames.tlist[i].y); writer.Write(-frames.tlist[i].z); } } if (frames.slist.Count > 0) { for (int i = 0; i < frames.slist.Count; ++i) { writer.Write(frames.slist[i].x); writer.Write(frames.slist[i].y); writer.Write(frames.slist[i].z); } } if (frames.rlist.Count > 0) { for (int i = 0; i < frames.rlist.Count; ++i) { // NOTE: convert LH to RH writer.Write(-frames.rlist[i].x); writer.Write(-frames.rlist[i].y); writer.Write(frames.rlist[i].z); writer.Write(frames.rlist[i].w); } } } } clipData = stream.ToArray(); } // buffer view BufferViewInfo bufView = new BufferViewInfo { name = _animData.name, offset = _bufInfo.data.Length, length = clipData.Length, type = BufferType.NONE, accessors = accessors }; // byte[] data = new byte[_bufInfo.data.Length + clipData.Length]; int offset = 0; System.Buffer.BlockCopy(_bufInfo.data, 0, data, offset, _bufInfo.data.Length); offset += _bufInfo.data.Length; System.Buffer.BlockCopy(clipData, 0, data, offset, clipData.Length); offset += clipData.Length; // _bufInfo.data = data; _bufInfo.bufferViews.Add(bufView); }
// ----------------------------------------- // DumpSkinningModel // ----------------------------------------- void DumpSkinningModel(GameObject _prefab, GLTF _gltf, BufferInfo _bufInfo) { // get joints List <GameObject> joints = new List <GameObject>(); Utils.RecurseNode(_prefab, _go => { // this is not a joint if (_go.GetComponent <SkinnedMeshRenderer>() != null) { return(false); } joints.Add(_go); return(true); }); // get nodes List <GameObject> nodes = new List <GameObject>(); Utils.RecurseNode(_prefab, _go => { // this is a joint, skip it. if (_go.GetComponents <Component>().Length == 1) { return(false); } nodes.Add(_go); return(true); }); // get skins & meshes List <Mesh> meshes = new List <Mesh>(); List <SkinnedMeshRenderer> smrList = new List <SkinnedMeshRenderer>(); Utils.RecurseNode(_prefab, _go => { SkinnedMeshRenderer smr = _go.GetComponent <SkinnedMeshRenderer>(); if (smr != null) { meshes.Add(smr.sharedMesh); smrList.Add(smr); } return(true); }); // dump nodes foreach (GameObject go in nodes) { GLTF_Node gltfNode = DumpGltfNode(go, nodes); SkinnedMeshRenderer smr = go.GetComponent <SkinnedMeshRenderer>(); if (smr != null) { gltfNode.mesh = meshes.IndexOf(smr.sharedMesh); gltfNode.skin = smrList.IndexOf(smr); } _gltf.nodes.Add(gltfNode); } // dump joints foreach (GameObject go in joints) { GLTF_Node gltfNode = DumpGltfNode(go, joints); _gltf.joints.Add(gltfNode); } // dump meshes & skin int accOffset = 0; foreach (SkinnedMeshRenderer smr in smrList) { // dump mesh accOffset = _bufInfo.GetAccessorCount(); DumpMesh(smr.sharedMesh, _gltf, _bufInfo, accOffset); // dump skin int accBindposesIdx = _bufInfo.GetAccessorCount() - 1; GameObject rootBone = Utils.GetRootBone(smr, _prefab).gameObject; GLTF_Skin gltfSkin = DumpGtlfSkin(smr, joints, rootBone, accBindposesIdx); if (gltfSkin != null) { _gltf.skins.Add(gltfSkin); } } }