├── README.md ├── GlTF_Camera.cs ├── GlTF_AmbientLight.cs ├── GlTF_DirectionalLight.cs ├── GlTF_ColorOrTexture.cs ├── GlTF_Light.cs ├── GlTF_Vector3.cs ├── GlTF_Orthographic.cs ├── GlTF_Translation.cs ├── GlTF_MaterialTexture.cs ├── GlTF_Scale.cs ├── GlTF_FloatArray4.cs ├── GlTF_Rotation.cs ├── GlTF_MaterialColor.cs ├── GlTF_Image.cs ├── GlTF_Target.cs ├── GlTF_ColorRGB.cs ├── GlTF_ColorRGBA.cs ├── GlTF_Channel.cs ├── GlTF_PointLight.cs ├── GlTF_Matrix.cs ├── GlTF_FloatArray.cs ├── GlTF_AnimSampler.cs ├── GlTF_SpotLight.cs ├── GlTF_Shader.cs ├── GlTF_Program.cs ├── GlTF_Primitive.cs ├── LICENSE ├── GlTF_Perspective.cs ├── GlTF_Texture.cs ├── GlTF_Mesh.cs ├── GlTF_Skin.cs ├── BoundsDouble.cs ├── GlTF_Material.cs ├── GlTF_Sampler.cs ├── GlTF_BufferView.cs ├── GlTF_Attributes.cs ├── GlTF_Node.cs ├── TextureScale.cs ├── GlTF_Parameters.cs ├── Preset.cs ├── GlTF_Technique.cs ├── GlTF_Accessor.cs ├── GlTF_Animation.cs ├── TextureUnpacker.cs ├── GlTF_Writer.cs ├── SimpleJSON.cs └── SceneToGlTFWiz.cs /README.md: -------------------------------------------------------------------------------- 1 | # Unity-glTF-Exporter 2 | Unity editor wizard that exports to glTF Format 3 | -------------------------------------------------------------------------------- /GlTF_Camera.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Camera : GlTF_Writer { 5 | public string type;// should be enum ": "perspective" 6 | } 7 | -------------------------------------------------------------------------------- /GlTF_AmbientLight.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_AmbientLight : GlTF_Light { 5 | public override void Write() 6 | { 7 | color.Write(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /GlTF_DirectionalLight.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_DirectionalLight : GlTF_Light { 5 | public override void Write() 6 | { 7 | color.Write(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /GlTF_ColorOrTexture.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_ColorOrTexture : GlTF_Writer { 5 | public GlTF_ColorOrTexture() {} 6 | public GlTF_ColorOrTexture (string n) { name = n; } 7 | } 8 | -------------------------------------------------------------------------------- /GlTF_Light.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Light : GlTF_Writer { 5 | public GlTF_ColorRGB color; 6 | public string type; 7 | // public override void Write () 8 | // { 9 | // } 10 | } 11 | -------------------------------------------------------------------------------- /GlTF_Vector3.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Vector3 : GlTF_FloatArray { 5 | public GlTF_Vector3() { minItems = 3; maxItems = 3; items = new float[] {0f, 0f, 0f}; } 6 | public GlTF_Vector3(Vector3 v) { minItems = 3; maxItems = 3; items = new float[] {v.x, v.y, v.z}; } 7 | } 8 | -------------------------------------------------------------------------------- /GlTF_Orthographic.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Orthographic : GlTF_Camera { 5 | public float xmag; 6 | public float ymag; 7 | public float zfar; 8 | public float znear; 9 | public GlTF_Orthographic() { type = "orthographic"; } 10 | public override void Write () 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /GlTF_Translation.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Translation : GlTF_Vector3 { 5 | public GlTF_Translation (Vector3 v) { items = new float[] {v.x, v.y, v.z }; } 6 | public override void Write() 7 | { 8 | Indent(); jsonWriter.Write ("\"translation\": [ "); 9 | WriteVals(); 10 | jsonWriter.Write ("]"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GlTF_MaterialTexture.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_MaterialTexture : GlTF_ColorOrTexture { 5 | public GlTF_MaterialTexture (string n, GlTF_Texture t) { name = n; texture = t; } 6 | public GlTF_Texture texture; 7 | public override void Write() 8 | { 9 | Indent(); jsonWriter.Write ("\"" + name + "\": \""+texture.name+"\""); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /GlTF_Scale.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Scale : GlTF_Vector3 { 5 | public GlTF_Scale() { items = new float[] {1f, 1f, 1f}; } 6 | public GlTF_Scale(Vector3 v) { items = new float[] {v.x, v.y, v.z }; } 7 | public override void Write() 8 | { 9 | Indent(); jsonWriter.Write ("\"scale\": [ "); 10 | WriteVals(); 11 | jsonWriter.Write ("]"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /GlTF_FloatArray4.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_FloatArray4 : GlTF_FloatArray { 5 | public GlTF_FloatArray4() { minItems = 4; maxItems = 4; items = new float[] { 1.0f, 0.0f, 0.0f, 0.0f }; } 6 | /* 7 | public override void Write() 8 | { 9 | Indent(); jsonWriter.Write ("\"rotation\": [ "); 10 | WriteVals(); 11 | jsonWriter.Write ("]"); 12 | } 13 | */ 14 | } 15 | -------------------------------------------------------------------------------- /GlTF_Rotation.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Rotation : GlTF_FloatArray4 { 5 | public GlTF_Rotation(Quaternion q) { name = "rotation"; minItems = 4; maxItems = 4; items = new float[] { q.x, q.y, q.z, q.w }; } 6 | /* 7 | public override void Write() 8 | { 9 | Indent(); jsonWriter.Write ("\"rotation\": [ "); 10 | WriteVals(); 11 | jsonWriter.Write ("]"); 12 | } 13 | */ 14 | } 15 | -------------------------------------------------------------------------------- /GlTF_MaterialColor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_MaterialColor : GlTF_ColorOrTexture { 5 | public GlTF_MaterialColor (string n, Color c) { name = n; color = new GlTF_ColorRGBA(name,c); } 6 | public GlTF_ColorRGBA color = new GlTF_ColorRGBA ("diffuse"); 7 | public override void Write() 8 | { 9 | // Indent(); jsonWriter.Write ("\"" + name + "\": "); 10 | color.Write (); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /GlTF_Image.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Image : GlTF_Writer { 5 | public string uri; 6 | 7 | public static string GetNameFromObject(Object o) 8 | { 9 | return "image_" + GlTF_Writer.GetNameFromObject(o, true); 10 | } 11 | 12 | public override void Write() 13 | { 14 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 15 | IndentIn(); 16 | Indent(); jsonWriter.Write ("\"uri\": \"" + uri + "\"\n"); 17 | IndentOut(); 18 | Indent(); jsonWriter.Write ("}"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /GlTF_Target.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Target : GlTF_Writer { 5 | public string id; 6 | public string path; 7 | public override void Write() 8 | { 9 | Indent(); jsonWriter.Write ("\"" + "target" + "\": {\n"); 10 | // Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 11 | IndentIn(); 12 | Indent(); jsonWriter.Write ("\"id\": \"" + id + "\",\n"); 13 | Indent(); jsonWriter.Write ("\"path\": \"" + path + "\"\n"); 14 | IndentOut(); 15 | Indent(); jsonWriter.Write ("}"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /GlTF_ColorRGB.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_ColorRGB : GlTF_Writer { 5 | Color color; 6 | public GlTF_ColorRGB (string n) { name = n; } 7 | public GlTF_ColorRGB (Color c) { color = c; } 8 | public GlTF_ColorRGB (string n, Color c) { name = n; color = c; } 9 | public override void Write () 10 | { 11 | Indent(); 12 | if (name.Length > 0) 13 | jsonWriter.Write ("\"" + name + "\": "); 14 | else 15 | jsonWriter.Write ("\"color\": ["); 16 | jsonWriter.Write (color.r.ToString() + ", " + color.g.ToString() + ", " +color.b.ToString()+"]"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /GlTF_ColorRGBA.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_ColorRGBA : GlTF_Writer { 5 | Color color; 6 | public GlTF_ColorRGBA (string n) { name = n; } 7 | public GlTF_ColorRGBA (Color c) { color = c; } 8 | public GlTF_ColorRGBA (string n, Color c) { name = n; color = c; } 9 | public override void Write () 10 | { 11 | Indent(); 12 | if (name.Length > 0) 13 | jsonWriter.Write ("\"" + name + "\": ["); 14 | else 15 | jsonWriter.Write ("\"color\": ["); 16 | jsonWriter.Write (color.r.ToString() + ", " + color.g.ToString() + ", " +color.b.ToString()+ ", " +color.a.ToString()+"]"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /GlTF_Channel.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Channel : GlTF_Writer { 5 | public GlTF_AnimSampler sampler; 6 | public GlTF_Target target; 7 | 8 | public GlTF_Channel (GlTF_AnimSampler s, GlTF_Target t) { 9 | sampler = s; 10 | target = t; 11 | } 12 | 13 | public override void Write() 14 | { 15 | IndentIn(); 16 | Indent(); jsonWriter.Write ("{\n"); 17 | IndentIn(); 18 | Indent(); jsonWriter.Write ("\"sampler\": \"" + sampler.name + "\",\n"); 19 | target.Write (); 20 | jsonWriter.WriteLine(); 21 | IndentOut(); 22 | Indent(); jsonWriter.Write ("}"); 23 | IndentOut(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GlTF_PointLight.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_PointLight : GlTF_Light { 5 | public float constantAttenuation = 1f; 6 | public float linearAttenuation = 0f; 7 | public float quadraticAttenuation = 0f; 8 | 9 | public GlTF_PointLight () { type = "point"; } 10 | 11 | public override void Write() 12 | { 13 | color.Write(); 14 | Indent(); jsonWriter.Write ("\"constantAttentuation\": "+constantAttenuation); 15 | Indent(); jsonWriter.Write ("\"linearAttenuation\": "+linearAttenuation); 16 | Indent(); jsonWriter.Write ("\"quadraticAttenuation\": "+quadraticAttenuation); 17 | jsonWriter.Write ("}"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /GlTF_Matrix.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Matrix : GlTF_FloatArray { 5 | public GlTF_Matrix() { name = "matrix"; minItems = 16; maxItems = 16; items = new float[] { 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 }; } 6 | public GlTF_Matrix(Matrix4x4 m) 7 | { 8 | name = "matrix"; 9 | minItems = 16; 10 | maxItems = 16; 11 | // unity: m[row][col] 12 | // gltf: column major 13 | items = new float[] { 14 | m.m00, m.m10, m.m20, m.m30, 15 | m.m01, m.m11, m.m21, m.m31, 16 | m.m02, m.m12, m.m22, m.m32, 17 | m.m03, m.m13, m.m23, m.m33 18 | }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /GlTF_FloatArray.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_FloatArray : GlTF_Writer { 5 | public float[] items; 6 | public int minItems = 0; 7 | public int maxItems = 0; 8 | 9 | public GlTF_FloatArray () { } 10 | public GlTF_FloatArray (string n) { name = n; } 11 | 12 | public override void Write() 13 | { 14 | if (name.Length > 0) 15 | { 16 | Indent(); jsonWriter.Write ("\"" + name + "\": ["); 17 | } 18 | WriteVals(); 19 | if (name.Length > 0) 20 | { 21 | jsonWriter.Write ("]"); 22 | } 23 | } 24 | 25 | public virtual void WriteVals () 26 | { 27 | for (int i = 0; i < maxItems; i++) 28 | { 29 | if (i > 0) 30 | jsonWriter.Write (", "); 31 | jsonWriter.Write (items[i].ToString ()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /GlTF_AnimSampler.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_AnimSampler : GlTF_Writer { 5 | public string input = "TIME"; 6 | public string interpolation = "LINEAR"; // only things in glTF as of today 7 | public string output = "translation"; // or whatever 8 | 9 | public GlTF_AnimSampler (string n, string o) { name = n; output = o; } 10 | 11 | public override void Write() 12 | { 13 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 14 | IndentIn(); 15 | Indent(); jsonWriter.Write ("\"input\": \"" + input + "\",\n"); 16 | Indent(); jsonWriter.Write ("\"interpolation\": \"" + interpolation + "\",\n"); 17 | Indent(); jsonWriter.Write ("\"output\": \"" + output + "\"\n"); 18 | IndentOut(); 19 | Indent(); jsonWriter.Write ("}"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /GlTF_SpotLight.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_SpotLight : GlTF_Light { 5 | public float constantAttenuation = 1f; 6 | public float fallOffAngle = 3.1415927f; 7 | public float fallOffExponent = 0f; 8 | public float linearAttenuation = 0f; 9 | public float quadraticAttenuation = 0f; 10 | 11 | public GlTF_SpotLight () { type = "spot"; } 12 | 13 | public override void Write() 14 | { 15 | color.Write(); 16 | Indent(); jsonWriter.Write ("\"constantAttentuation\": "+constantAttenuation); 17 | Indent(); jsonWriter.Write ("\"fallOffAngle\": "+fallOffAngle); 18 | Indent(); jsonWriter.Write ("\"fallOffExponent\": "+fallOffExponent); 19 | Indent(); jsonWriter.Write ("\"linearAttenuation\": "+linearAttenuation); 20 | Indent(); jsonWriter.Write ("\"quadraticAttenuation\": "+quadraticAttenuation); 21 | jsonWriter.Write ("}"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /GlTF_Shader.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Shader : GlTF_Writer { 5 | public enum Type { 6 | Vertex, 7 | Fragment 8 | } 9 | 10 | public Type type = Type.Vertex; 11 | public string uri = ""; 12 | 13 | public static string GetNameFromObject(Object o, Type type) 14 | { 15 | var name = GlTF_Writer.GetNameFromObject(o); 16 | var typeName = type == Type.Vertex ? "vertex" : "fragment"; 17 | return typeName + "_" + name; 18 | } 19 | 20 | public override void Write() 21 | { 22 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 23 | IndentIn(); 24 | Indent(); jsonWriter.Write ("\"type\": " + TypeStr() +",\n"); 25 | Indent(); jsonWriter.Write ("\"uri\": \"" + uri +"\"\n"); 26 | IndentOut(); 27 | Indent(); jsonWriter.Write ("}"); 28 | } 29 | 30 | int TypeStr() 31 | { 32 | if (type == Type.Vertex) 33 | { 34 | return 35633; 35 | } 36 | else if (type == Type.Fragment) 37 | { 38 | return 35632; 39 | } 40 | 41 | return 0; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /GlTF_Program.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class GlTF_Program : GlTF_Writer { 6 | public List attributes = new List(); 7 | public string vertexShader = ""; 8 | public string fragmentShader = ""; 9 | 10 | public static string GetNameFromObject(Object o) 11 | { 12 | return "program_" + GlTF_Writer.GetNameFromObject(o); 13 | } 14 | 15 | public override void Write() 16 | { 17 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 18 | IndentIn(); 19 | Indent(); jsonWriter.Write ("\"attributes\": [\n"); 20 | IndentIn(); 21 | foreach (var a in attributes) 22 | { 23 | CommaNL(); 24 | Indent(); jsonWriter.Write ("\"" + a + "\""); 25 | } 26 | Indent(); jsonWriter.Write ("\n"); 27 | IndentOut(); 28 | Indent(); jsonWriter.Write ("],\n"); 29 | Indent(); jsonWriter.Write ("\"vertexShader\": \"" + vertexShader + "\",\n"); 30 | Indent(); jsonWriter.Write ("\"fragmentShader\": \"" + fragmentShader + "\"\n"); 31 | IndentOut(); 32 | Indent(); jsonWriter.Write ("}"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /GlTF_Primitive.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Primitive : GlTF_Writer { 5 | public GlTF_Attributes attributes = new GlTF_Attributes(); 6 | public GlTF_Accessor indices; 7 | public string materialName; 8 | public int primitive = 4; 9 | public int semantics = 4; 10 | public int index = 0; 11 | 12 | public static string GetNameFromObject(Object o, int index) 13 | { 14 | return "primitive_" + index + "_" + GlTF_Writer.GetNameFromObject(o, true); 15 | } 16 | 17 | public void Populate (Mesh m) 18 | { 19 | // attributes.Populate (m); 20 | if (m.GetTopology(index) == MeshTopology.Triangles) { 21 | indices.Populate (m.GetTriangles(index), true); 22 | } 23 | } 24 | 25 | public override void Write () 26 | { 27 | IndentIn(); 28 | CommaNL(); 29 | if (attributes != null) 30 | attributes.Write(); 31 | CommaNL(); 32 | Indent(); jsonWriter.Write ("\"indices\": \"" + indices.name + "\",\n"); 33 | Indent(); jsonWriter.Write ("\"material\": \"" + materialName + "\",\n"); 34 | Indent(); jsonWriter.Write ("\"mode\": " + primitive + "\n"); 35 | // semantics 36 | IndentOut(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015, 2016 Tony Parisi. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /GlTF_Perspective.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Perspective : GlTF_Camera { 5 | public float aspect_ratio; 6 | public float yfov;//": 37.8492, 7 | public float zfar;//": 100, 8 | public float znear;//": 0.01 9 | public GlTF_Perspective() { type = "perspective"; } 10 | public override void Write () 11 | { 12 | /* 13 | "camera_0": { 14 | "perspective": { 15 | "yfov": 45, 16 | "zfar": 3162.76, 17 | "znear": 12.651 18 | }, 19 | "type": "perspective" 20 | } 21 | */ 22 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 23 | IndentIn(); 24 | Indent(); jsonWriter.Write ("\"perspective\": {\n"); 25 | IndentIn(); 26 | Indent(); jsonWriter.Write ("\"aspect_ratio\": "+aspect_ratio.ToString()+",\n"); 27 | Indent(); jsonWriter.Write ("\"yfov\": "+yfov.ToString()+",\n"); 28 | Indent(); jsonWriter.Write ("\"zfar\": "+zfar.ToString()+",\n"); 29 | Indent(); jsonWriter.Write ("\"znear\": "+znear.ToString()+"\n"); 30 | IndentOut(); 31 | Indent(); jsonWriter.Write ("},\n"); 32 | Indent(); jsonWriter.Write ("\"type\": \"perspective\"\n"); 33 | IndentOut(); 34 | Indent(); jsonWriter.Write ("}"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /GlTF_Texture.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Texture : GlTF_Writer { 5 | /* 6 | "texture_O21_jpg": { 7 | "format": 6408, 8 | "internalFormat": 6408, 9 | "sampler": "sampler_0", 10 | "source": "O21_jpg", 11 | "target": 3553, 12 | "type": 5121 13 | }, 14 | */ 15 | public int format = 6408; 16 | public int internalFormat = 6408; 17 | public string samplerName; 18 | public string source; 19 | public int target = 3553; 20 | public int tType = 5121; 21 | 22 | public static string GetNameFromObject(Object o) 23 | { 24 | return "texture_" + GlTF_Writer.GetNameFromObject(o, true); 25 | } 26 | 27 | public override void Write() 28 | { 29 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 30 | IndentIn(); 31 | Indent(); jsonWriter.Write ("\"format\": " + format + ",\n"); 32 | Indent(); jsonWriter.Write ("\"internalFormat\": " + internalFormat + ",\n"); 33 | Indent(); jsonWriter.Write ("\"sampler\": \"" + samplerName + "\",\n"); 34 | Indent(); jsonWriter.Write ("\"source\": \"" + source + "\",\n"); 35 | Indent(); jsonWriter.Write ("\"target\": " + target + ",\n"); 36 | Indent(); jsonWriter.Write ("\"type\": " + tType + "\n"); 37 | IndentOut(); 38 | Indent(); jsonWriter.Write ("}"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /GlTF_Mesh.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class GlTF_Mesh : GlTF_Writer { 6 | public List primitives; 7 | 8 | public GlTF_Mesh() { primitives = new List(); } 9 | 10 | public static string GetNameFromObject(Object o) 11 | { 12 | return "mesh_" + GlTF_Writer.GetNameFromObject(o, true); 13 | } 14 | 15 | public void Populate (Mesh m) 16 | { 17 | if (primitives.Count > 0) 18 | { 19 | // only populate first attributes because the data are shared between primitives 20 | primitives[0].attributes.Populate(m); 21 | } 22 | 23 | foreach (GlTF_Primitive p in primitives) 24 | { 25 | p.Populate (m); 26 | } 27 | } 28 | 29 | public override void Write () 30 | { 31 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 32 | IndentIn(); 33 | Indent(); jsonWriter.Write ("\"name\": \"" + name + "\",\n"); 34 | Indent(); jsonWriter.Write ("\"primitives\": [\n"); 35 | IndentIn(); 36 | foreach (GlTF_Primitive p in primitives) 37 | { 38 | CommaNL(); 39 | Indent(); jsonWriter.Write ("{\n"); 40 | p.Write (); 41 | Indent(); jsonWriter.Write ("}"); 42 | } 43 | jsonWriter.WriteLine(); 44 | IndentOut(); 45 | Indent(); jsonWriter.Write ("]\n"); 46 | IndentOut(); 47 | Indent(); jsonWriter.Write ("}"); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /GlTF_Skin.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class GlTF_Skin : GlTF_Writer { 6 | public List boneNames; 7 | GlTF_Matrix bindShape; 8 | GlTF_Accessor ibmAccessor; 9 | 10 | public static string GetNameFromObject(Object o) 11 | { 12 | return "skin_" + GlTF_Writer.GetNameFromObject(o, true); 13 | } 14 | 15 | public void Populate(SkinnedMeshRenderer smr, List skeletons) { 16 | name = GetNameFromObject(smr.transform); 17 | if (smr.rootBone != null) { 18 | boneNames = new List(); 19 | List boneMats = new List(); 20 | 21 | var parent = smr.rootBone.parent; 22 | if (parent != null) { 23 | var mat = Matrix4x4.TRS(parent.localPosition, parent.localRotation, parent.localScale); 24 | bindShape = new GlTF_Matrix(mat); 25 | } else { 26 | bindShape = new GlTF_Matrix(Matrix4x4.identity); 27 | } 28 | bindShape.name = "bindShapeMatrix"; 29 | 30 | skeletons.Add(smr.rootBone); 31 | for (var i = 0; i < smr.bones.Length; ++i) { 32 | var found = IsBoneInHierarchy(smr.rootBone, smr.bones[i]); 33 | if (!found) { 34 | // set as its own skeleton to prevent error if it doesn't get included in rootBone hierarchy 35 | skeletons.Add(smr.bones[i]); 36 | } 37 | boneNames.Add(GlTF_Node.GetNameFromObject(smr.bones[i])); 38 | boneMats.Add(smr.sharedMesh.bindposes[i]); 39 | } 40 | 41 | ibmAccessor = new GlTF_Accessor("accessor_ibm_" + name, GlTF_Accessor.Type.MAT4, GlTF_Accessor.ComponentType.FLOAT); 42 | ibmAccessor.bufferView = GlTF_Writer.mat4BufferView; 43 | ibmAccessor.Populate(boneMats.ToArray()); 44 | GlTF_Writer.accessors.Add(ibmAccessor); 45 | } 46 | } 47 | 48 | public bool IsBoneInHierarchy(Transform parent, Transform bone) { 49 | if (parent == bone) { 50 | return true; 51 | } 52 | for (var i = 0; i < parent.childCount; ++i) { 53 | if (IsBoneInHierarchy(parent.GetChild(i), bone)) { 54 | return true; 55 | }; 56 | } 57 | return false; 58 | } 59 | 60 | public override void Write() 61 | { 62 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 63 | IndentIn(); 64 | if (bindShape != null) 65 | { 66 | CommaNL(); 67 | bindShape.Write(); 68 | } 69 | 70 | if (ibmAccessor != null) 71 | { 72 | CommaNL(); 73 | Indent(); jsonWriter.Write("\"inverseBindMatrices\": \"" + ibmAccessor.name + "\""); 74 | } 75 | 76 | CommaNL(); 77 | Indent(); jsonWriter.Write ("\"jointNames\": [\n"); 78 | IndentIn(); 79 | foreach (var s in boneNames) 80 | { 81 | CommaNL(); 82 | Indent(); jsonWriter.Write("\"" + s + "\""); 83 | } 84 | IndentOut(); 85 | jsonWriter.WriteLine(); 86 | Indent(); jsonWriter.Write ("]\n"); 87 | 88 | IndentOut(); 89 | Indent(); jsonWriter.Write ("}"); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /BoundsDouble.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections; 4 | 5 | public class BoundsDouble { 6 | double[] min = new double[]{0, 0, 0}; 7 | double[] max = new double[]{0, 0, 0}; 8 | bool inited = false; 9 | 10 | public BoundsDouble() { 11 | } 12 | 13 | public BoundsDouble(BoundsDouble b) { 14 | for (int i = 0; i < 3; ++i) { 15 | min[i] = b.min[i]; 16 | max[i] = b.max[i]; 17 | } 18 | inited = true; 19 | } 20 | 21 | public BoundsDouble(double[] min, double[] max) { 22 | this.min[0] = min[0]; 23 | this.min[1] = min[1]; 24 | this.min[2] = min[2]; 25 | 26 | this.max[0] = max[0]; 27 | this.max[1] = max[1]; 28 | this.max[2] = max[2]; 29 | inited = true; 30 | } 31 | 32 | public BoundsDouble(Vector3 min, Vector3 max) { 33 | this.min[0] = min.x; 34 | this.min[1] = min.y; 35 | this.min[2] = min.z; 36 | 37 | this.max[0] = max.x; 38 | this.max[1] = max.y; 39 | this.max[2] = max.z; 40 | inited = true; 41 | } 42 | 43 | public void Encapsulate(BoundsDouble b) { 44 | if (inited) { 45 | min[0] = Math.Min(min[0], b.min[0]); 46 | min[1] = Math.Min(min[1], b.min[1]); 47 | min[2] = Math.Min(min[2], b.min[2]); 48 | 49 | max[0] = Math.Max(max[0], b.max[0]); 50 | max[1] = Math.Max(max[1], b.max[1]); 51 | max[2] = Math.Max(max[2], b.max[2]); 52 | } else { 53 | min[0] = b.min[0]; 54 | min[1] = b.min[1]; 55 | min[2] = b.min[2]; 56 | 57 | max[0] = b.max[0]; 58 | max[1] = b.max[1]; 59 | max[2] = b.max[2]; 60 | inited = true; 61 | } 62 | } 63 | 64 | public void Rotate(Matrix4x4 m) { 65 | if (inited) { 66 | double minx = m.m00 * min[0] + m.m01 * min[1] + m.m02 * min[2]; 67 | double miny = m.m10 * min[0] + m.m11 * min[1] + m.m12 * min[2]; 68 | double minz = m.m20 * min[0] + m.m21 * min[1] + m.m22 * min[2]; 69 | 70 | double maxx = m.m00 * max[0] + m.m01 * max[1] + m.m02 * max[2]; 71 | double maxy = m.m10 * max[0] + m.m11 * max[1] + m.m12 * max[2]; 72 | double maxz = m.m20 * max[0] + m.m21 * max[1] + m.m22 * max[2]; 73 | 74 | min[0] = Math.Min(minx, maxx); 75 | min[1] = Math.Min(miny, maxy); 76 | min[2] = Math.Min(minz, maxz); 77 | 78 | max[0] = Math.Max(minx, maxx); 79 | max[1] = Math.Max(miny, maxy); 80 | max[2] = Math.Max(minz, maxz); 81 | } 82 | } 83 | 84 | public void Translate(double x, double y, double z) { 85 | if (inited) { 86 | min[0] += x; 87 | min[1] += y; 88 | min[2] += z; 89 | 90 | max[0] += x; 91 | max[1] += y; 92 | max[2] += z; 93 | } 94 | } 95 | 96 | public bool Empty { 97 | get { 98 | return !inited; 99 | } 100 | } 101 | 102 | public double[] Min { 103 | get { 104 | return min; 105 | } 106 | } 107 | 108 | public double[] Max { 109 | get { 110 | return max; 111 | } 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /GlTF_Material.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class GlTF_Material : GlTF_Writer { 6 | 7 | public class Value : GlTF_Writer { 8 | } 9 | 10 | public class ColorValue : Value { 11 | public Color color; 12 | 13 | public override void Write() 14 | { 15 | jsonWriter.Write ("\"" + name + "\": ["); 16 | jsonWriter.Write (color.r.ToString() + ", " + color.g.ToString() + ", " +color.b.ToString() + ", " + color.a.ToString()); 17 | jsonWriter.Write ("]"); 18 | } 19 | } 20 | 21 | public class VectorValue : Value { 22 | public Vector4 vector; 23 | 24 | public override void Write() 25 | { 26 | jsonWriter.Write ("\"" + name + "\": ["); 27 | jsonWriter.Write (vector.x.ToString() + ", " + vector.y.ToString() + ", " + vector.z.ToString() + ", " + vector.w.ToString()); 28 | jsonWriter.Write ("]"); 29 | } 30 | } 31 | 32 | public class FloatValue : Value { 33 | public float value; 34 | 35 | public override void Write() 36 | { 37 | jsonWriter.Write ("\"" + name + "\": " + value + ""); 38 | } 39 | } 40 | 41 | public class StringValue : Value { 42 | public string value; 43 | 44 | public override void Write() 45 | { 46 | jsonWriter.Write ("\"" + name + "\": \"" + value + "\""); 47 | } 48 | } 49 | 50 | public string instanceTechniqueName = "technique1"; 51 | public GlTF_ColorOrTexture ambient;// = new GlTF_ColorRGBA ("ambient"); 52 | public GlTF_ColorOrTexture diffuse; 53 | public float shininess; 54 | public GlTF_ColorOrTexture specular;// = new GlTF_ColorRGBA ("specular"); 55 | public List values = new List(); 56 | 57 | public static string GetNameFromObject(Object o) 58 | { 59 | return "material_" + GlTF_Writer.GetNameFromObject(o, true); 60 | } 61 | 62 | public override void Write() 63 | { 64 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 65 | IndentIn(); 66 | CommaNL(); 67 | Indent(); jsonWriter.Write ("\"technique\": \"" + instanceTechniqueName + "\",\n"); 68 | Indent(); jsonWriter.Write ("\"values\": {\n"); 69 | IndentIn(); 70 | foreach (var v in values) 71 | { 72 | CommaNL(); 73 | Indent(); v.Write(); 74 | } 75 | 76 | 77 | // if (ambient != null) 78 | // { 79 | // CommaNL(); 80 | // ambient.Write (); 81 | // } 82 | // if (diffuse != null) 83 | // { 84 | // CommaNL(); 85 | // diffuse.Write (); 86 | // } 87 | // CommaNL(); 88 | // Indent(); jsonWriter.Write ("\"shininess\": " + shininess); 89 | // if (specular != null) 90 | // { 91 | // CommaNL(); 92 | // specular.Write (); 93 | // } 94 | // jsonWriter.WriteLine(); 95 | 96 | Indent(); jsonWriter.Write ("\n"); 97 | IndentOut(); 98 | Indent(); jsonWriter.Write ("}"); 99 | CommaNL(); 100 | Indent(); jsonWriter.Write ("\"name\": \"" + name + "\"\n"); 101 | IndentOut(); 102 | Indent(); jsonWriter.Write ("}"); 103 | 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /GlTF_Sampler.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Sampler : GlTF_Writer { 5 | public enum MagFilter { 6 | NEAREST = 9728, 7 | LINEAR = 9729 8 | } 9 | 10 | public enum MinFilter { 11 | NEAREST = 9728, 12 | LINEAR = 9729, 13 | NEAREST_MIPMAP_NEAREST = 9984, 14 | LINEAR_MIPMAP_NEAREST = 9985, 15 | NEAREST_MIPMAP_LINEAR = 9986, 16 | LINEAR_MIPMAP_LINEAR = 9987 17 | } 18 | 19 | public enum Wrap { 20 | CLAMP_TO_EDGE = 33071, 21 | MIRRORED_REPEAT = 33648, 22 | REPEAT = 10497 23 | } 24 | 25 | MagFilter magFilter = MagFilter.LINEAR; 26 | MinFilter minFilter = MinFilter.LINEAR; 27 | Wrap wrap = Wrap.REPEAT; 28 | 29 | public static string GetNameFromObject(Texture tex) 30 | { 31 | int fm = (int)tex.filterMode; 32 | int w = (int)tex.wrapMode; 33 | var n = "sampler_" + fm + "_" + w; 34 | Texture2D t = tex as Texture2D; 35 | if (t != null) 36 | { 37 | if (t.mipmapCount > 0) 38 | { 39 | n += "_m"; 40 | } 41 | } 42 | return n; 43 | } 44 | 45 | public GlTF_Sampler (Texture tex) 46 | { 47 | bool hasMipMap = false; 48 | Texture2D t = tex as Texture2D; 49 | if (t != null) 50 | { 51 | if (t.mipmapCount > 0) 52 | { 53 | hasMipMap = true; 54 | } 55 | } 56 | 57 | switch (tex.filterMode) 58 | { 59 | case FilterMode.Point: 60 | { 61 | magFilter = MagFilter.NEAREST; 62 | if (hasMipMap) 63 | { 64 | minFilter = MinFilter.NEAREST_MIPMAP_NEAREST; 65 | } 66 | else 67 | { 68 | minFilter = MinFilter.NEAREST; 69 | } 70 | } 71 | break; 72 | 73 | case FilterMode.Bilinear: 74 | { 75 | magFilter = MagFilter.LINEAR; 76 | if (hasMipMap) 77 | { 78 | minFilter = MinFilter.LINEAR_MIPMAP_NEAREST; 79 | } 80 | else 81 | { 82 | minFilter = MinFilter.LINEAR; 83 | } 84 | } 85 | break; 86 | 87 | case FilterMode.Trilinear: 88 | { 89 | magFilter = MagFilter.LINEAR; 90 | if (hasMipMap) 91 | { 92 | minFilter = MinFilter.LINEAR_MIPMAP_LINEAR; 93 | } 94 | else 95 | { 96 | minFilter = MinFilter.LINEAR; 97 | } 98 | } 99 | break; 100 | } 101 | 102 | switch (tex.wrapMode) 103 | { 104 | case TextureWrapMode.Clamp: 105 | { 106 | wrap = Wrap.CLAMP_TO_EDGE; 107 | } 108 | break; 109 | 110 | case TextureWrapMode.Repeat: 111 | { 112 | wrap = Wrap.REPEAT; 113 | } 114 | break; 115 | } 116 | } 117 | 118 | public override void Write() 119 | { 120 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 121 | IndentIn(); 122 | Indent(); jsonWriter.Write ("\"magFilter\": " + (int)magFilter + ",\n"); 123 | Indent(); jsonWriter.Write ("\"minFilter\": " + (int)minFilter + ",\n"); 124 | Indent(); jsonWriter.Write ("\"wrapS\": " + (int)wrap + ",\n"); 125 | Indent(); jsonWriter.Write ("\"wrapT\": " + (int)wrap + "\n"); 126 | IndentOut(); 127 | Indent(); jsonWriter.Write ("}"); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /GlTF_BufferView.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.IO; 4 | using System; 5 | 6 | public class GlTF_BufferView : GlTF_Writer { 7 | public string buffer;// ": "duck", 8 | public long byteLength;//": 25272, 9 | public long byteOffset;//": 0, 10 | public int target = 34962; 11 | // public string target = "ARRAY_BUFFER"; 12 | public int currentOffset = 0; 13 | public MemoryStream memoryStream = new MemoryStream(); 14 | public bool bin = false; 15 | 16 | public GlTF_BufferView (string n) { name = n; } 17 | public GlTF_BufferView (string n, int t) { name = n; target = t; } 18 | 19 | public void Align(int len) { 20 | var rem = (int)(byteLength % len); 21 | memoryStream.Write(new byte[rem], 0, rem); 22 | currentOffset += rem; 23 | byteLength = currentOffset; 24 | } 25 | 26 | public void Populate (int[] vs, bool flippedTriangle) 27 | { 28 | if (flippedTriangle) 29 | { 30 | for (int i = 0; i < vs.Length; i+=3) 31 | { 32 | ushort u = (ushort)vs[i]; 33 | memoryStream.Write (BitConverter.GetBytes(u), 0, 2); 34 | currentOffset += 2; 35 | 36 | u = (ushort)vs[i+2]; 37 | memoryStream.Write (BitConverter.GetBytes(u), 0, 2); 38 | currentOffset += 2; 39 | 40 | u = (ushort)vs[i+1]; 41 | memoryStream.Write (BitConverter.GetBytes(u), 0, 2); 42 | currentOffset += 2; 43 | } 44 | } 45 | else 46 | { 47 | for (int i = 0; i < vs.Length; i++) 48 | { 49 | ushort u = (ushort)vs[i]; 50 | memoryStream.Write (BitConverter.GetBytes(u), 0, 2); 51 | currentOffset += 2; 52 | } 53 | } 54 | byteLength = currentOffset; 55 | } 56 | 57 | public void Populate (float[] vs) 58 | { 59 | for (int i = 0; i < vs.Length; i++) 60 | { 61 | // memoryStream.Write (vs[i]); 62 | // memoryStream.Write ((byte[])vs, 0, vs.Length * sizeof(int)); 63 | float f = vs[i]; 64 | memoryStream.Write (BitConverter.GetBytes(f), 0, 4); 65 | currentOffset += 4; 66 | } 67 | byteLength = currentOffset; 68 | } 69 | 70 | public void Populate (float v) 71 | { 72 | memoryStream.Write (BitConverter.GetBytes(v), 0, 4); 73 | currentOffset += 4; 74 | byteLength = currentOffset; 75 | } 76 | 77 | public override void Write () 78 | { 79 | /* 80 | "bufferView_4642": { 81 | "buffer": "vc.bin", 82 | "byteLength": 630080, 83 | "byteOffset": 0, 84 | "target": "ARRAY_BUFFER" 85 | }, 86 | */ 87 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 88 | IndentIn(); 89 | var binName = binary ? "binary_glTF" : Path.GetFileNameWithoutExtension(GlTF_Writer.binFileName); 90 | CommaNL(); 91 | Indent(); jsonWriter.Write ("\"buffer\": \"" + binName +"\""); 92 | CommaNL(); 93 | Indent(); jsonWriter.Write ("\"byteLength\": " + byteLength); 94 | CommaNL(); 95 | Indent(); jsonWriter.Write ("\"byteOffset\": " + byteOffset); 96 | if (target != -1) { 97 | CommaNL(); 98 | Indent(); jsonWriter.Write ("\"target\": " + target); 99 | } 100 | jsonWriter.WriteLine(); 101 | IndentOut(); 102 | Indent(); jsonWriter.Write ("}"); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /GlTF_Attributes.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class GlTF_Attributes : GlTF_Writer { 6 | public GlTF_Accessor normalAccessor; 7 | public GlTF_Accessor positionAccessor; 8 | public GlTF_Accessor texCoord0Accessor; 9 | public GlTF_Accessor texCoord1Accessor; 10 | public GlTF_Accessor texCoord2Accessor; 11 | public GlTF_Accessor texCoord3Accessor; 12 | public GlTF_Accessor boneIndexAccessor; 13 | public GlTF_Accessor boneWeightAccessor; 14 | 15 | public void Populate (Mesh m) 16 | { 17 | positionAccessor.Populate (m.vertices); 18 | if (normalAccessor != null) 19 | { 20 | normalAccessor.Populate (m.normals); 21 | } 22 | if (texCoord0Accessor != null) 23 | { 24 | texCoord0Accessor.Populate (m.uv, true); 25 | } 26 | if (texCoord1Accessor != null) 27 | { 28 | texCoord1Accessor.Populate (m.uv2, true); 29 | } 30 | if (texCoord2Accessor != null) 31 | { 32 | texCoord2Accessor.Populate (m.uv3, true); 33 | } 34 | if (texCoord3Accessor != null) 35 | { 36 | texCoord3Accessor.Populate (m.uv4, true); 37 | } 38 | if (boneIndexAccessor != null) 39 | { 40 | List indices = new List(); 41 | foreach (var bw in m.boneWeights) 42 | { 43 | indices.Add(new Vector4(bw.boneIndex0, bw.boneIndex1, bw.boneIndex2, bw.boneIndex3)); 44 | } 45 | boneIndexAccessor.Populate(indices.ToArray()); 46 | } 47 | if (boneWeightAccessor != null) 48 | { 49 | List weights = new List(); 50 | foreach (var bw in m.boneWeights) 51 | { 52 | weights.Add(new Vector4(bw.weight0, bw.weight1, bw.weight2, bw.weight3)); 53 | } 54 | boneWeightAccessor.Populate(weights.ToArray()); 55 | } 56 | } 57 | 58 | public override void Write () 59 | { 60 | Indent(); jsonWriter.Write ("\"attributes\": {\n"); 61 | IndentIn(); 62 | if (positionAccessor != null) 63 | { 64 | CommaNL(); 65 | Indent(); jsonWriter.Write ("\"POSITION\": \"" + positionAccessor.name + "\""); 66 | } 67 | if (normalAccessor != null) 68 | { 69 | CommaNL(); 70 | Indent(); jsonWriter.Write ("\"NORMAL\": \"" + normalAccessor.name + "\""); 71 | } 72 | if (texCoord0Accessor != null) 73 | { 74 | CommaNL(); 75 | Indent(); jsonWriter.Write ("\"TEXCOORD_0\": \"" + texCoord0Accessor.name + "\""); 76 | } 77 | if (texCoord1Accessor != null) 78 | { 79 | CommaNL(); 80 | Indent(); jsonWriter.Write ("\"TEXCOORD_1\": \"" + texCoord1Accessor.name + "\""); 81 | } 82 | if (texCoord2Accessor != null) 83 | { 84 | CommaNL(); 85 | Indent(); jsonWriter.Write ("\"TEXCOORD_2\": \"" + texCoord2Accessor.name + "\""); 86 | } 87 | if (texCoord3Accessor != null) 88 | { 89 | CommaNL(); 90 | Indent(); jsonWriter.Write ("\"TEXCOORD_3\": \"" + texCoord3Accessor.name + "\""); 91 | } 92 | if (boneIndexAccessor != null) 93 | { 94 | CommaNL(); 95 | Indent(); jsonWriter.Write ("\"JOINT\": \"" + boneIndexAccessor.name + "\""); 96 | } 97 | if (boneWeightAccessor != null) 98 | { 99 | CommaNL(); 100 | Indent(); jsonWriter.Write ("\"WEIGHT\": \"" + boneWeightAccessor.name + "\""); 101 | } 102 | //CommaNL(); 103 | jsonWriter.WriteLine(); 104 | IndentOut(); 105 | Indent(); jsonWriter.Write ("}"); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /GlTF_Node.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class GlTF_Node : GlTF_Writer { 6 | public string cameraName; 7 | public bool hasParent = false; 8 | public List childrenNames = new List(); 9 | public bool uniqueItems = true; 10 | public string lightName; 11 | public ListbufferViewNames = new List(); 12 | public ListindexNames = new List(); 13 | public ListaccessorNames = new List(); 14 | public List meshNames = new List(); 15 | public GlTF_Matrix matrix; 16 | // public GlTF_Mesh mesh; 17 | public GlTF_Rotation rotation; 18 | public GlTF_Scale scale; 19 | public GlTF_Translation translation; 20 | public bool additionalProperties = false; 21 | public string skinName; 22 | public List skeletonNames = new List(); 23 | public string jointName; 24 | 25 | public static string GetNameFromObject(Object o) 26 | { 27 | return "node_" + GlTF_Writer.GetNameFromObject(o, true); 28 | } 29 | 30 | public override void Write () 31 | { 32 | Indent(); 33 | jsonWriter.Write ("\""+name+"\": {\n"); 34 | IndentIn(); 35 | Indent(); 36 | jsonWriter.Write ("\"name\": \""+name+"\",\n"); 37 | if (cameraName != null) 38 | { 39 | CommaNL(); 40 | Indent(); 41 | jsonWriter.Write ("\"camera\": \""+cameraName+"\""); 42 | } 43 | else if (lightName != null) 44 | { 45 | CommaNL(); 46 | Indent(); 47 | jsonWriter.Write ("\"light\": \""+lightName+"\""); 48 | } 49 | else if (meshNames.Count > 0) 50 | { 51 | CommaNL(); 52 | Indent(); 53 | jsonWriter.Write ("\"meshes\": [\n"); 54 | IndentIn(); 55 | foreach (string m in meshNames) 56 | { 57 | CommaNL(); 58 | Indent(); jsonWriter.Write ("\"" + m + "\""); 59 | } 60 | jsonWriter.WriteLine(); 61 | IndentOut(); 62 | Indent(); jsonWriter.Write ("]"); 63 | } 64 | 65 | if (childrenNames != null && childrenNames.Count > 0) 66 | { 67 | CommaNL(); 68 | Indent(); jsonWriter.Write ("\"children\": [\n"); 69 | IndentIn(); 70 | foreach (string ch in childrenNames) 71 | { 72 | CommaNL(); 73 | Indent(); jsonWriter.Write ("\""+ch+"\""); 74 | } 75 | jsonWriter.WriteLine(); 76 | IndentOut(); 77 | Indent(); jsonWriter.Write ("]"); 78 | } 79 | if (matrix != null) 80 | { 81 | CommaNL(); 82 | matrix.Write(); 83 | } 84 | if (translation != null && (translation.items[0] != 0f || translation.items[1] != 0f || translation.items[2] != 0f)) 85 | { 86 | CommaNL(); 87 | translation.Write (); 88 | } 89 | if (scale != null && (scale.items[0] != 1f || scale.items[1] != 1f || scale.items[2] != 1f)) 90 | { 91 | CommaNL(); 92 | scale.Write(); 93 | } 94 | if (rotation != null && (rotation.items[0] != 0f || rotation.items[1] != 0f || rotation.items[2] != 0f || rotation.items[3] != 0f)) 95 | { 96 | CommaNL(); 97 | rotation.Write (); 98 | } 99 | if (jointName != null) { 100 | CommaNL(); 101 | Indent(); jsonWriter.Write("\"jointName\": \"" + jointName + "\""); 102 | } 103 | if (skinName != null) { 104 | CommaNL(); 105 | Indent(); jsonWriter.Write("\"skin\": \"" + skinName + "\""); 106 | } 107 | if (skeletonNames.Count > 0) { 108 | CommaNL(); 109 | Indent(); jsonWriter.Write("\"skeletons\": [\n"); 110 | IndentIn(); 111 | foreach (var n in skeletonNames) { 112 | CommaNL(); 113 | Indent(); jsonWriter.Write("\"" + n + "\""); 114 | } 115 | IndentOut(); 116 | jsonWriter.WriteLine(); 117 | Indent(); jsonWriter.Write("]"); 118 | } 119 | jsonWriter.WriteLine(); 120 | IndentOut(); 121 | Indent(); jsonWriter.Write ("}"); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /TextureScale.cs: -------------------------------------------------------------------------------- 1 | // Only works on ARGB32, RGB24 and Alpha8 textures that are marked readable 2 | 3 | using System.Threading; 4 | using UnityEngine; 5 | 6 | public class TextureScale 7 | { 8 | public class ThreadData 9 | { 10 | public int start; 11 | public int end; 12 | public ThreadData (int s, int e) { 13 | start = s; 14 | end = e; 15 | } 16 | } 17 | 18 | private static Color[] texColors; 19 | private static Color[] newColors; 20 | private static int w; 21 | private static float ratioX; 22 | private static float ratioY; 23 | private static int w2; 24 | private static int finishCount; 25 | private static Mutex mutex; 26 | 27 | public static void Point (Texture2D tex, int newWidth, int newHeight) 28 | { 29 | ThreadedScale (tex, newWidth, newHeight, false); 30 | } 31 | 32 | public static void Bilinear (Texture2D tex, int newWidth, int newHeight) 33 | { 34 | ThreadedScale (tex, newWidth, newHeight, true); 35 | } 36 | 37 | private static void ThreadedScale (Texture2D tex, int newWidth, int newHeight, bool useBilinear) 38 | { 39 | texColors = tex.GetPixels(); 40 | newColors = new Color[newWidth * newHeight]; 41 | if (useBilinear) 42 | { 43 | ratioX = 1.0f / ((float)newWidth / (tex.width-1)); 44 | ratioY = 1.0f / ((float)newHeight / (tex.height-1)); 45 | } 46 | else { 47 | ratioX = ((float)tex.width) / newWidth; 48 | ratioY = ((float)tex.height) / newHeight; 49 | } 50 | w = tex.width; 51 | w2 = newWidth; 52 | var cores = Mathf.Min(SystemInfo.processorCount, newHeight); 53 | var slice = newHeight/cores; 54 | 55 | finishCount = 0; 56 | if (mutex == null) { 57 | mutex = new Mutex(false); 58 | } 59 | if (cores > 1) 60 | { 61 | int i = 0; 62 | ThreadData threadData; 63 | for (i = 0; i < cores-1; i++) { 64 | threadData = new ThreadData(slice * i, slice * (i + 1)); 65 | ParameterizedThreadStart ts = useBilinear ? new ParameterizedThreadStart(BilinearScale) : new ParameterizedThreadStart(PointScale); 66 | Thread thread = new Thread(ts); 67 | thread.Start(threadData); 68 | } 69 | threadData = new ThreadData(slice*i, newHeight); 70 | if (useBilinear) 71 | { 72 | BilinearScale(threadData); 73 | } 74 | else 75 | { 76 | PointScale(threadData); 77 | } 78 | while (finishCount < cores) 79 | { 80 | Thread.Sleep(1); 81 | } 82 | } 83 | else 84 | { 85 | ThreadData threadData = new ThreadData(0, newHeight); 86 | if (useBilinear) 87 | { 88 | BilinearScale(threadData); 89 | } 90 | else 91 | { 92 | PointScale(threadData); 93 | } 94 | } 95 | 96 | tex.Resize(newWidth, newHeight); 97 | tex.SetPixels(newColors); 98 | tex.Apply(); 99 | 100 | texColors = null; 101 | newColors = null; 102 | } 103 | 104 | public static void BilinearScale (System.Object obj) 105 | { 106 | ThreadData threadData = (ThreadData) obj; 107 | for (var y = threadData.start; y < threadData.end; y++) 108 | { 109 | int yFloor = (int)Mathf.Floor(y * ratioY); 110 | var y1 = yFloor * w; 111 | var y2 = (yFloor+1) * w; 112 | var yw = y * w2; 113 | 114 | for (var x = 0; x < w2; x++) { 115 | int xFloor = (int)Mathf.Floor(x * ratioX); 116 | var xLerp = x * ratioX-xFloor; 117 | newColors[yw + x] = ColorLerpUnclamped(ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor+1], xLerp), 118 | ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor+1], xLerp), 119 | y*ratioY-yFloor); 120 | } 121 | } 122 | 123 | mutex.WaitOne(); 124 | finishCount++; 125 | mutex.ReleaseMutex(); 126 | } 127 | 128 | public static void PointScale (System.Object obj) 129 | { 130 | ThreadData threadData = (ThreadData) obj; 131 | for (var y = threadData.start; y < threadData.end; y++) 132 | { 133 | var thisY = (int)(ratioY * y) * w; 134 | var yw = y * w2; 135 | for (var x = 0; x < w2; x++) { 136 | newColors[yw + x] = texColors[(int)(thisY + ratioX*x)]; 137 | } 138 | } 139 | 140 | mutex.WaitOne(); 141 | finishCount++; 142 | mutex.ReleaseMutex(); 143 | } 144 | 145 | private static Color ColorLerpUnclamped (Color c1, Color c2, float value) 146 | { 147 | return new Color (c1.r + (c2.r - c1.r)*value, 148 | c1.g + (c2.g - c1.g)*value, 149 | c1.b + (c2.b - c1.b)*value, 150 | c1.a + (c2.a - c1.a)*value); 151 | } 152 | } -------------------------------------------------------------------------------- /GlTF_Parameters.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using UnityEditor; 4 | 5 | public class GlTF_Parameters : GlTF_Writer { 6 | public GlTF_Accessor timeAccessor; 7 | public GlTF_Accessor translationAccessor; 8 | public GlTF_Accessor rotationAccessor; 9 | public GlTF_Accessor scaleAccessor; 10 | 11 | // seems like a bad place for this 12 | float[] times;// = new float[curve.keys.Length]; 13 | Vector3[] positions; 14 | Vector3[] scales; 15 | Vector4[] rotations; 16 | bool px, py, pz; 17 | bool sx, sy, sz; 18 | bool rx, ry, rz, rw; 19 | 20 | public GlTF_Parameters (string n) { name = n; } 21 | 22 | public void Populate (AnimationClipCurveData curveData) 23 | { 24 | string propName = curveData.propertyName; 25 | if (times == null) // allocate one array of times, assumes all channels have same number of keys 26 | { 27 | timeAccessor = new GlTF_Accessor(name+"TimeAccessor", GlTF_Accessor.Type.SCALAR, GlTF_Accessor.ComponentType.FLOAT); 28 | timeAccessor.bufferView = GlTF_Writer.floatBufferView; 29 | GlTF_Writer.accessors.Add (timeAccessor); 30 | times = new float[curveData.curve.keys.Length]; 31 | for (int i = 0; i < curveData.curve.keys.Length; i++) 32 | times[i] = curveData.curve.keys[i].time; 33 | timeAccessor.Populate (times); 34 | } 35 | 36 | if (propName.Contains("m_LocalPosition")) 37 | { 38 | if (positions == null) 39 | { 40 | translationAccessor = new GlTF_Accessor(name+"TranslationAccessor", GlTF_Accessor.Type.VEC3, GlTF_Accessor.ComponentType.FLOAT); 41 | translationAccessor.bufferView = GlTF_Writer.vec3BufferView; 42 | GlTF_Writer.accessors.Add (translationAccessor); 43 | positions = new Vector3[curveData.curve.keys.Length]; 44 | } 45 | 46 | if (propName.Contains (".x")) 47 | { 48 | px = true; 49 | for (int i = 0; i < curveData.curve.keys.Length; i++) 50 | positions[i].x = curveData.curve.keys[i].value; 51 | } 52 | else if (propName.Contains (".y")) 53 | { 54 | py = true; 55 | for (int i = 0; i < curveData.curve.keys.Length; i++) 56 | positions[i].y = curveData.curve.keys[i].value; 57 | } 58 | else if (propName.Contains (".z")) 59 | { 60 | pz = true; 61 | for (int i = 0; i < curveData.curve.keys.Length; i++) 62 | positions[i].z = curveData.curve.keys[i].value; 63 | } 64 | if (px && py && pz) 65 | translationAccessor.Populate (positions); 66 | } 67 | 68 | if (propName.Contains("m_LocalScale")) 69 | { 70 | if (scales == null) 71 | { 72 | scaleAccessor = new GlTF_Accessor(name+"ScaleAccessor", GlTF_Accessor.Type.VEC3, GlTF_Accessor.ComponentType.FLOAT); 73 | scaleAccessor.bufferView = GlTF_Writer.vec3BufferView; 74 | GlTF_Writer.accessors.Add (scaleAccessor); 75 | scales = new Vector3[curveData.curve.keys.Length]; 76 | } 77 | 78 | if (propName.Contains (".x")) 79 | { 80 | sx = true; 81 | for (int i = 0; i < curveData.curve.keys.Length; i++) 82 | scales[i].x = curveData.curve.keys[i].value; 83 | } 84 | else if (propName.Contains (".y")) 85 | { 86 | sy = true; 87 | for (int i = 0; i < curveData.curve.keys.Length; i++) 88 | scales[i].y = curveData.curve.keys[i].value; 89 | } 90 | else if (propName.Contains (".z")) 91 | { 92 | sz = true; 93 | for (int i = 0; i < curveData.curve.keys.Length; i++) 94 | scales[i].z = curveData.curve.keys[i].value; 95 | } 96 | if (sx && sy && sz) 97 | scaleAccessor.Populate (scales); 98 | } 99 | 100 | if (propName.Contains("m_LocalRotation")) 101 | { 102 | if (rotations == null) 103 | { 104 | rotationAccessor = new GlTF_Accessor(name+"RotationAccessor", GlTF_Accessor.Type.VEC4, GlTF_Accessor.ComponentType.FLOAT); 105 | rotationAccessor.bufferView = GlTF_Writer.vec4BufferView; 106 | GlTF_Writer.accessors.Add (rotationAccessor); 107 | rotations = new Vector4[curveData.curve.keys.Length]; 108 | } 109 | 110 | if (propName.Contains (".x")) 111 | { 112 | rx = true; 113 | for (int i = 0; i < curveData.curve.keys.Length; i++) 114 | rotations[i].x = curveData.curve.keys[i].value; 115 | } 116 | else if (propName.Contains (".y")) 117 | { 118 | ry = true; 119 | for (int i = 0; i < curveData.curve.keys.Length; i++) 120 | rotations[i].y = curveData.curve.keys[i].value; 121 | } 122 | else if (propName.Contains (".z")) 123 | { 124 | rz = true; 125 | for (int i = 0; i < curveData.curve.keys.Length; i++) 126 | rotations[i].z = curveData.curve.keys[i].value; 127 | } 128 | else if (propName.Contains (".w")) 129 | { 130 | rw = true; 131 | for (int i = 0; i < curveData.curve.keys.Length; i++) 132 | rotations[i].w = curveData.curve.keys[i].value; 133 | } 134 | if (rx && ry && rz && rw) 135 | rotationAccessor.Populate (scales); 136 | } 137 | } 138 | 139 | public override void Write() 140 | { 141 | Indent(); jsonWriter.Write ("\"" + "parameters" + "\": {\n"); 142 | IndentIn(); 143 | if (times != null) 144 | { 145 | CommaNL(); 146 | Indent(); jsonWriter.Write ("\"" + "TIME" + "\": \"" + timeAccessor.name +"\""); 147 | } 148 | if (rotations != null) 149 | { 150 | CommaNL(); 151 | Indent(); jsonWriter.Write ("\"" + "rotation" + "\": \"" + rotationAccessor.name +"\""); 152 | } 153 | if (scales != null) 154 | { 155 | CommaNL(); 156 | Indent(); jsonWriter.Write ("\"" + "scale" + "\": \"" + scaleAccessor.name +"\""); 157 | } 158 | if (positions != null) 159 | { 160 | CommaNL(); 161 | Indent(); jsonWriter.Write ("\"" + "translation" + "\": \"" + translationAccessor.name +"\""); 162 | } 163 | jsonWriter.WriteLine(); 164 | IndentOut(); 165 | Indent(); jsonWriter.Write ("}"); 166 | } 167 | 168 | /* 169 | public Dictionary parms = new Dictionary(); 170 | 171 | public void AddPararm (string key, string val) 172 | { 173 | parms.Add (key, val); 174 | } 175 | 176 | public override void Write() 177 | { 178 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 179 | IndentIn(); 180 | foreach (KeyValuePair p in parms) 181 | { 182 | CommaNL(); 183 | Indent(); jsonWriter.Write ("\"" + p.Key + "\": \"" + p.Value +"\""); 184 | } 185 | jsonWriter.WriteLine(); 186 | 187 | IndentOut(); 188 | Indent(); jsonWriter.Write ("}"); 189 | } 190 | */ 191 | } 192 | -------------------------------------------------------------------------------- /Preset.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using SimpleJSON; 6 | 7 | public class Preset { 8 | public class Shader { 9 | public string vertexShader; 10 | public string fragmentShader; 11 | } 12 | 13 | public class UnpackUV { 14 | public int index; // uv index 15 | public List textureIndex = new List(); 16 | } 17 | 18 | public string shaderDir = null; 19 | public Dictionary shaderMap = new Dictionary(); 20 | public Dictionary techniqueStates = new Dictionary(); 21 | public Dictionary> unpackUV = new Dictionary>(); 22 | 23 | const string DEFAULT_VERTEX_SHADER = "DefaultVS.glsl"; 24 | const string DEFAULT_ANIM_VERTEX_SHADER = "DefaultAnimVS.glsl"; 25 | const string DEFAULT_FRAGMENT_SHADER = "DefaultFS.glsl"; 26 | 27 | public string GetVertexShader(string shaderName, bool anim) 28 | { 29 | if (shaderMap.ContainsKey(shaderName)) 30 | { 31 | var s = shaderMap[shaderName]; 32 | return s.vertexShader; 33 | } 34 | return anim ? DEFAULT_ANIM_VERTEX_SHADER : DEFAULT_VERTEX_SHADER; 35 | } 36 | 37 | public string GetFragmentShader(string shaderName) 38 | { 39 | if (shaderMap.ContainsKey(shaderName)) 40 | { 41 | var s = shaderMap[shaderName]; 42 | return s.fragmentShader; 43 | } 44 | return DEFAULT_FRAGMENT_SHADER; 45 | } 46 | 47 | public List GetDefaultUnpackUVList() 48 | { 49 | // default is uv0 to tex0 50 | var ret = new List(); 51 | var uv = new UnpackUV(); 52 | uv.index = 0; 53 | uv.textureIndex.Add(0); 54 | ret.Add(uv); 55 | return ret; 56 | } 57 | 58 | public void Load(string path) 59 | { 60 | var text = File.ReadAllText(path); 61 | var obj = JSON.Parse(text); 62 | 63 | shaderDir = obj["ShaderDir"]; 64 | 65 | var sm = obj["ShaderMap"]; 66 | 67 | shaderMap.Clear(); 68 | foreach (var smc in sm.AsObject.Dict) 69 | { 70 | Shader shader = new Shader(); 71 | shader.vertexShader = smc.Value["shaders"]["vertexShader"]; 72 | shader.fragmentShader = smc.Value["shaders"]["fragmentShader"]; 73 | 74 | if (shader.vertexShader == null) { 75 | shader.vertexShader = DEFAULT_VERTEX_SHADER; 76 | } 77 | if (shader.fragmentShader == null) { 78 | shader.fragmentShader = DEFAULT_FRAGMENT_SHADER; 79 | } 80 | 81 | shaderMap[smc.Key] = shader; 82 | } 83 | 84 | var ts = obj["TechniqueStates"]; 85 | techniqueStates.Clear(); 86 | foreach (var t in ts.AsObject.Dict) 87 | { 88 | GlTF_Technique.States state = new GlTF_Technique.States(); 89 | techniqueStates[t.Key] = state; 90 | 91 | var s = t.Value["states"]; 92 | var enArr = s["enable"].AsArray; 93 | if (enArr.Count > 0) 94 | { 95 | state.enable = new int[enArr.Count]; 96 | for (var i = 0; i < enArr.Count; ++i) 97 | { 98 | state.enable[i] = enArr[i].AsInt; 99 | } 100 | } 101 | 102 | var f = t.Value["functions"]; 103 | var node = f["blendColor"]; 104 | if (node != null) 105 | { 106 | var nArr = node.AsArray; 107 | if (nArr != null && nArr.Count == 4) 108 | { 109 | state.functions["blendColor"] = new GlTF_Technique.Value(new Color(nArr[0].AsFloat, nArr[1].AsFloat, nArr[2].AsFloat, nArr[3].AsFloat)); 110 | } 111 | } 112 | 113 | node = f["blendEquationSeparate"]; 114 | if (node != null) 115 | { 116 | var nArr = node.AsArray; 117 | if (nArr != null && nArr.Count == 2) 118 | { 119 | state.functions["blendEquationSeparate"] = new GlTF_Technique.Value(new int[2]{nArr[0].AsInt, nArr[1].AsInt}); 120 | } 121 | } 122 | 123 | node = f["blendFuncSeparate"]; 124 | if (node != null) 125 | { 126 | var nArr = node.AsArray; 127 | if (nArr != null && nArr.Count == 4) 128 | { 129 | state.functions["blendFuncSeparate"] = new GlTF_Technique.Value(new int[4]{nArr[0].AsInt, nArr[1].AsInt, nArr[2].AsInt, nArr[3].AsInt}); 130 | } 131 | } 132 | 133 | node = f["colorMask"]; 134 | if (node != null) 135 | { 136 | var nArr = node.AsArray; 137 | if (nArr != null && nArr.Count == 4) 138 | { 139 | state.functions["colorMask"] = new GlTF_Technique.Value(new bool[4]{nArr[0].AsBool, nArr[1].AsBool, nArr[2].AsBool, nArr[3].AsBool}); 140 | } 141 | } 142 | 143 | node = f["cullFace"]; 144 | if (node != null) 145 | { 146 | var nArr = node.AsArray; 147 | if (nArr != null && nArr.Count == 1) 148 | { 149 | state.functions["cullFace"] = new GlTF_Technique.Value(nArr[0].AsInt); 150 | } 151 | } 152 | 153 | node = f["depthFunc"]; 154 | if (node != null) 155 | { 156 | var nArr = node.AsArray; 157 | if (nArr != null && nArr.Count == 1) 158 | { 159 | state.functions["depthFunc"] = new GlTF_Technique.Value(nArr[0].AsInt); 160 | } 161 | } 162 | 163 | node = f["depthMask"]; 164 | if (node != null) 165 | { 166 | var nArr = node.AsArray; 167 | if (nArr != null && nArr.Count == 1) 168 | { 169 | state.functions["depthMask"] = new GlTF_Technique.Value(nArr[0].AsBool); 170 | } 171 | } 172 | 173 | node = f["depthRange"]; 174 | if (node != null) 175 | { 176 | var nArr = node.AsArray; 177 | if (nArr != null && nArr.Count == 2) 178 | { 179 | state.functions["depthRange"] = new GlTF_Technique.Value(new Vector2(nArr[0].AsFloat, nArr[1].AsFloat)); 180 | } 181 | } 182 | 183 | node = f["frontFace"]; 184 | if (node != null) 185 | { 186 | var nArr = node.AsArray; 187 | if (nArr != null && nArr.Count == 1) 188 | { 189 | state.functions["frontFace"] = new GlTF_Technique.Value(nArr[0].AsInt); 190 | } 191 | } 192 | 193 | node = f["lineWidth"]; 194 | if (node != null) 195 | { 196 | var nArr = node.AsArray; 197 | if (nArr != null && nArr.Count == 1) 198 | { 199 | state.functions["lineWidth"] = new GlTF_Technique.Value(nArr[0].AsFloat); 200 | } 201 | } 202 | 203 | node = f["polygonOffset"]; 204 | if (node != null) 205 | { 206 | var nArr = node.AsArray; 207 | if (nArr != null && nArr.Count == 2) 208 | { 209 | state.functions["polygonOffset"] = new GlTF_Technique.Value(new Vector2(nArr[0].AsFloat, nArr[1].AsFloat)); 210 | } 211 | } 212 | 213 | node = f["scissor"]; 214 | if (node != null) 215 | { 216 | var nArr = node.AsArray; 217 | if (nArr != null && nArr.Count == 4) 218 | { 219 | state.functions["scissor"] = new GlTF_Technique.Value(new Vector4(nArr[0].AsFloat, nArr[1].AsFloat, nArr[2].AsFloat, nArr[3].AsFloat)); 220 | } 221 | } 222 | 223 | } 224 | 225 | LoadTextureUnpacker(obj); 226 | } 227 | 228 | void LoadTextureUnpacker(JSONNode obj) 229 | { 230 | unpackUV.Clear(); 231 | var tus = obj["TextureUnpacker"]; 232 | foreach (var tu in tus.AsObject.Dict) 233 | { 234 | var uvList = tu.Value.AsArray; 235 | var l = new List(); 236 | for (var i = 0; i < uvList.Count; ++i) { 237 | UnpackUV unpack = new UnpackUV(); 238 | var uv = uvList[i]; 239 | unpack.index = uv["uvIndex"].AsInt; 240 | var arr = uv["textureIndex"].AsArray; 241 | for (var j = 0; j < arr.Count; ++j) { 242 | unpack.textureIndex.Add(arr[j].AsInt); 243 | } 244 | l.Add(unpack); 245 | } 246 | unpackUV[tu.Key] = l; 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /GlTF_Technique.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class GlTF_Technique : GlTF_Writer { 6 | public enum Type { 7 | FLOAT = 5126, 8 | FLOAT_VEC2 = 35664, 9 | FLOAT_VEC3 = 35665, 10 | FLOAT_VEC4 = 35666, 11 | FLOAT_MAT3 = 35675, 12 | FLOAT_MAT4 = 35676, 13 | SAMPLER_2D = 35678 14 | } 15 | 16 | public enum Semantic { 17 | UNKNOWN, 18 | POSITION, 19 | NORMAL, 20 | TEXCOORD_0, 21 | TEXCOORD_1, 22 | TEXCOORD_2, 23 | TEXCOORD_3, 24 | MODELVIEW, 25 | PROJECTION, 26 | MODELVIEWINVERSETRANSPOSE, 27 | CESIUM_RTC_MODELVIEW, 28 | JOINT, 29 | WEIGHT, 30 | JOINTMATRIX 31 | } 32 | 33 | public class Parameter { 34 | public string name; 35 | public Type type; 36 | public Semantic semantic = Semantic.UNKNOWN; 37 | public int count = -1; // for joint matrix 38 | } 39 | 40 | public class Attribute { 41 | public string name; 42 | public string param; 43 | } 44 | 45 | public class Uniform { 46 | public string name; 47 | public string param; 48 | } 49 | 50 | public class States { 51 | public int[] enable; 52 | public Dictionary functions = new Dictionary(); 53 | } 54 | 55 | public class Value : GlTF_Writer { 56 | public enum Type { 57 | Unknown, 58 | Bool, 59 | Int, 60 | Float, 61 | Color, 62 | Vector2, 63 | Vector4, 64 | IntArr, 65 | BoolArr 66 | } 67 | 68 | bool boolValue; 69 | int intValue; 70 | float floatValue; 71 | Color colorValue; 72 | Vector2 vector2Value; 73 | Vector4 vector4Value; 74 | int[] intArrValue; 75 | bool[] boolArrvalue; 76 | Type type = Type.Unknown; 77 | 78 | public Value(bool value) 79 | { 80 | boolValue = value; 81 | type = Type.Bool; 82 | } 83 | 84 | public Value(int value) 85 | { 86 | intValue = value; 87 | type = Type.Int; 88 | } 89 | 90 | public Value(float value) 91 | { 92 | floatValue = value; 93 | type = Type.Float; 94 | } 95 | 96 | public Value(Color value) 97 | { 98 | colorValue = value; 99 | type = Type.Color; 100 | } 101 | 102 | public Value(Vector2 value) 103 | { 104 | vector2Value = value; 105 | type = Type.Vector2; 106 | } 107 | 108 | public Value(Vector4 value) 109 | { 110 | vector4Value = value; 111 | type = Type.Vector4; 112 | } 113 | 114 | public Value(int[] value) 115 | { 116 | intArrValue = value; 117 | type = Type.IntArr; 118 | } 119 | 120 | public Value(bool[] value) 121 | { 122 | boolArrvalue = value; 123 | type = Type.BoolArr; 124 | } 125 | 126 | void WriteArr(T arr) where T:ArrayList 127 | { 128 | jsonWriter.Write("["); 129 | for (var i = 0; i < arr.Count; ++i) 130 | { 131 | jsonWriter.Write(arr[i].ToString().ToLower()); 132 | if (i != arr.Count - 1) 133 | { 134 | jsonWriter.Write(", "); 135 | } 136 | } 137 | jsonWriter.Write("]"); 138 | } 139 | 140 | public override void Write() 141 | { 142 | switch(type) 143 | { 144 | case Type.Bool: 145 | jsonWriter.Write("[" + boolValue.ToString().ToLower() + "]"); 146 | break; 147 | 148 | case Type.Int: 149 | jsonWriter.Write("[" + intValue + "]"); 150 | break; 151 | 152 | case Type.Float: 153 | jsonWriter.Write("[" + floatValue + "]"); 154 | break; 155 | 156 | case Type.Color: 157 | jsonWriter.Write("[" + colorValue.r + ", " + colorValue.g + ", " + colorValue.b + ", " + colorValue.a + "]"); 158 | break; 159 | 160 | case Type.Vector2: 161 | jsonWriter.Write("[" + vector2Value.x + ", " + vector2Value.y + "]"); 162 | break; 163 | 164 | case Type.Vector4: 165 | jsonWriter.Write("[" + vector4Value.x + ", " + vector4Value.y + ", " + vector4Value.z + ", " + vector4Value.w + "]"); 166 | break; 167 | 168 | case Type.IntArr: 169 | WriteArr(new ArrayList(intArrValue)); 170 | break; 171 | 172 | case Type.BoolArr: 173 | WriteArr(new ArrayList(boolArrvalue)); 174 | break; 175 | 176 | } 177 | } 178 | } 179 | 180 | public string program; 181 | public List attributes = new List(); 182 | public List parameters = new List(); 183 | public List uniforms = new List(); 184 | public States states = new States(); 185 | 186 | public static string GetNameFromObject(Object o) 187 | { 188 | return "technique_" + GlTF_Writer.GetNameFromObject(o); 189 | } 190 | 191 | public void AddDefaultUniforms(bool rtc) 192 | { 193 | var tParam = new Parameter(); 194 | tParam.name = "modelViewMatrix"; 195 | tParam.type = Type.FLOAT_MAT4; 196 | tParam.semantic = rtc ? Semantic.CESIUM_RTC_MODELVIEW : Semantic.MODELVIEW; 197 | parameters.Add(tParam); 198 | var uni = new Uniform(); 199 | uni.name = "u_modelViewMatrix"; 200 | uni.param = tParam.name; 201 | uniforms.Add(uni); 202 | 203 | tParam = new Parameter(); 204 | tParam.name = "projectionMatrix"; 205 | tParam.type = Type.FLOAT_MAT4; 206 | tParam.semantic = Semantic.PROJECTION; 207 | parameters.Add(tParam); 208 | uni = new Uniform(); 209 | uni.name = "u_projectionMatrix"; 210 | uni.param = tParam.name; 211 | uniforms.Add(uni); 212 | 213 | tParam = new Parameter(); 214 | tParam.name = "normalMatrix"; 215 | tParam.type = Type.FLOAT_MAT3; 216 | tParam.semantic = Semantic.MODELVIEWINVERSETRANSPOSE; 217 | parameters.Add(tParam); 218 | uni = new Uniform(); 219 | uni.name = "u_normalMatrix"; 220 | uni.param = tParam.name; 221 | uniforms.Add(uni); 222 | } 223 | 224 | public override void Write() 225 | { 226 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 227 | IndentIn(); 228 | Indent(); jsonWriter.Write ("\"program\": \"" + program +"\",\n"); 229 | Indent(); jsonWriter.Write ("\"parameters\": {\n"); 230 | IndentIn(); 231 | foreach (var p in parameters) 232 | { 233 | CommaNL(); 234 | Indent(); jsonWriter.Write ("\"" + p.name + "\": {\n"); 235 | IndentIn(); 236 | 237 | CommaNL(); 238 | Indent(); jsonWriter.Write ("\"type\": " + (int)p.type); 239 | if (p.semantic != Semantic.UNKNOWN) 240 | { 241 | CommaNL(); 242 | Indent(); jsonWriter.Write ("\"semantic\": \"" + p.semantic + "\""); 243 | } 244 | if (p.count != -1) 245 | { 246 | CommaNL(); 247 | Indent(); jsonWriter.Write("\"count\": " + p.count); 248 | } 249 | jsonWriter.WriteLine(); 250 | 251 | IndentOut(); 252 | Indent(); jsonWriter.Write ("}"); 253 | } 254 | Indent(); jsonWriter.Write ("\n"); 255 | IndentOut(); 256 | Indent(); jsonWriter.Write ("},\n"); 257 | 258 | Indent(); jsonWriter.Write ("\"attributes\": {\n"); 259 | IndentIn(); 260 | foreach (var a in attributes) 261 | { 262 | CommaNL(); 263 | Indent(); jsonWriter.Write ("\"" + a.name + "\": \"" + a.param + "\""); 264 | } 265 | Indent(); jsonWriter.Write ("\n"); 266 | IndentOut(); 267 | Indent(); jsonWriter.Write ("},\n"); 268 | 269 | Indent(); jsonWriter.Write ("\"uniforms\": {\n"); 270 | IndentIn(); 271 | foreach (var u in uniforms) 272 | { 273 | CommaNL(); 274 | Indent(); jsonWriter.Write ("\"" + u.name + "\": \"" + u.param + "\""); 275 | } 276 | Indent(); jsonWriter.Write ("\n"); 277 | IndentOut(); 278 | Indent(); jsonWriter.Write ("},\n"); 279 | 280 | // states 281 | Indent(); jsonWriter.Write ("\"states\": {\n"); 282 | IndentIn(); 283 | 284 | if (states != null && states.enable != null) 285 | { 286 | Indent(); jsonWriter.Write("\"enable\": [\n"); 287 | IndentIn(); 288 | foreach (var en in states.enable) 289 | { 290 | CommaNL(); 291 | Indent(); jsonWriter.Write(en); 292 | } 293 | jsonWriter.Write("\n"); 294 | IndentOut(); 295 | Indent(); jsonWriter.Write("]"); 296 | } 297 | 298 | if (states != null && states.functions.Count > 0) 299 | { 300 | jsonWriter.Write(",\n"); 301 | Indent(); jsonWriter.Write("\"functions\": {\n"); 302 | IndentIn(); 303 | foreach (var fun in states.functions) 304 | { 305 | CommaNL(); 306 | Indent(); jsonWriter.Write("\"" + fun.Key + "\": "); 307 | fun.Value.Write(); 308 | } 309 | jsonWriter.Write("\n"); 310 | IndentOut(); 311 | Indent(); jsonWriter.Write("}"); 312 | jsonWriter.Write("\n"); 313 | } else { 314 | jsonWriter.Write("\n"); 315 | } 316 | 317 | IndentOut(); 318 | Indent(); jsonWriter.Write ("}\n"); 319 | 320 | IndentOut(); 321 | Indent(); jsonWriter.Write ("}"); 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /GlTF_Accessor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class GlTF_Accessor : GlTF_Writer { 5 | public enum Type { 6 | SCALAR, 7 | VEC2, 8 | VEC3, 9 | VEC4, 10 | MAT4 11 | } 12 | 13 | public enum ComponentType { 14 | USHORT = 5123, 15 | FLOAT = 5126 16 | } 17 | 18 | public GlTF_BufferView bufferView;// "bufferView": "bufferView_30", 19 | public long byteOffset; //": 0, 20 | public int byteStride;// ": 12, 21 | public ComponentType componentType; // GL enum vals ": BYTE (5120), UNSIGNED_BYTE (5121), SHORT (5122), UNSIGNED_SHORT (5123), FLOAT (5126) 22 | public int count;//": 2399, 23 | public Type type = Type.SCALAR; 24 | 25 | public Vector4 maxFloat; 26 | public Vector4 minFloat; 27 | public int minInt; 28 | public int maxInt; 29 | 30 | public GlTF_Accessor (string n) { name = n; } 31 | public GlTF_Accessor (string n, Type t, ComponentType c) { 32 | name = n; 33 | type = t; 34 | switch (t) 35 | { 36 | case Type.SCALAR: 37 | byteStride = 0; 38 | break; 39 | case Type.VEC2: 40 | byteStride = 8; 41 | break; 42 | case Type.VEC3: 43 | byteStride = 12; 44 | break; 45 | case Type.VEC4: 46 | byteStride = 16; 47 | break; 48 | case Type.MAT4: 49 | byteStride = 64; 50 | break; 51 | } 52 | componentType = c; 53 | } 54 | 55 | public static string GetNameFromObject(Object o, string name) 56 | { 57 | return "accessor_" + name + "_"+ GlTF_Writer.GetNameFromObject(o, true); 58 | } 59 | 60 | void InitMinMaxInt() 61 | { 62 | maxInt = int.MinValue; 63 | minInt = int.MaxValue; 64 | } 65 | 66 | void InitMinMaxFloat() 67 | { 68 | float min = float.MinValue; 69 | float max = float.MaxValue; 70 | maxFloat = new Vector4(min, min, min, min); 71 | minFloat = new Vector4(max, max, max, max); 72 | } 73 | 74 | public void Populate (int[] vs, bool flippedTriangle) 75 | { 76 | if (type != Type.SCALAR) 77 | throw (new System.Exception()); 78 | byteOffset = bufferView.currentOffset; 79 | bufferView.Populate (vs, flippedTriangle); 80 | count = vs.Length; 81 | if (count > 0) 82 | { 83 | InitMinMaxInt(); 84 | for (int i = 0; i < count; ++i) 85 | { 86 | minInt = Mathf.Min(vs[i], minInt); 87 | maxInt = Mathf.Max(vs[i], maxInt); 88 | } 89 | } 90 | } 91 | 92 | public void Populate (float[] vs) 93 | { 94 | if (type != Type.SCALAR) 95 | throw (new System.Exception()); 96 | byteOffset = bufferView.currentOffset; 97 | bufferView.Populate (vs); 98 | count = vs.Length; 99 | if (count > 0) 100 | { 101 | InitMinMaxFloat(); 102 | for (int i = 0; i < count; ++i) 103 | { 104 | minFloat.x = Mathf.Min(vs[i], minFloat.x); 105 | maxFloat.x = Mathf.Max(vs[i], maxFloat.x); 106 | } 107 | } 108 | } 109 | 110 | public void Populate (Vector2[] v2s, bool flip = false) 111 | { 112 | if (type != Type.VEC2) 113 | throw (new System.Exception()); 114 | byteOffset = bufferView.currentOffset; 115 | count = v2s.Length; 116 | if (count > 0) 117 | { 118 | InitMinMaxFloat(); 119 | 120 | if (flip) 121 | { 122 | for (int i = 0; i < v2s.Length; i++) 123 | { 124 | bufferView.Populate (v2s[i].x); 125 | float y = 1.0f - v2s[i].y; 126 | bufferView.Populate (y); 127 | minFloat.x = Mathf.Min(v2s[i].x, minFloat.x); 128 | minFloat.y = Mathf.Min(y, minFloat.y); 129 | maxFloat.x = Mathf.Max(v2s[i].x, maxFloat.x); 130 | maxFloat.y = Mathf.Max(y, maxFloat.y); 131 | } 132 | } else { 133 | for (int i = 0; i < v2s.Length; i++) 134 | { 135 | bufferView.Populate (v2s[i].x); 136 | bufferView.Populate (v2s[i].y); 137 | minFloat.x = Mathf.Min(v2s[i].x, minFloat.x); 138 | minFloat.y = Mathf.Min(v2s[i].y, minFloat.y); 139 | maxFloat.x = Mathf.Max(v2s[i].x, maxFloat.x); 140 | maxFloat.y = Mathf.Max(v2s[i].y, maxFloat.y); 141 | } 142 | } 143 | } 144 | } 145 | 146 | public void Populate (Vector3[] v3s) 147 | { 148 | if (type != Type.VEC3) 149 | throw (new System.Exception()); 150 | byteOffset = bufferView.currentOffset; 151 | count = v3s.Length; 152 | if (count > 0) 153 | { 154 | InitMinMaxFloat(); 155 | 156 | for (int i = 0; i < v3s.Length; i++) 157 | { 158 | bufferView.Populate (v3s[i].x); 159 | bufferView.Populate (v3s[i].y); 160 | bufferView.Populate (v3s[i].z); 161 | 162 | minFloat.x = Mathf.Min(v3s[i].x, minFloat.x); 163 | minFloat.y = Mathf.Min(v3s[i].y, minFloat.y); 164 | minFloat.z = Mathf.Min(v3s[i].z, minFloat.z); 165 | maxFloat.x = Mathf.Max(v3s[i].x, maxFloat.x); 166 | maxFloat.y = Mathf.Max(v3s[i].y, maxFloat.y); 167 | maxFloat.z = Mathf.Max(v3s[i].z, maxFloat.z); 168 | 169 | } 170 | } 171 | } 172 | 173 | public void Populate (Vector4[] v4s) 174 | { 175 | if (type != Type.VEC4) 176 | throw (new System.Exception()); 177 | byteOffset = bufferView.currentOffset; 178 | count = v4s.Length; 179 | if (count > 0) 180 | { 181 | InitMinMaxFloat(); 182 | for (int i = 0; i < v4s.Length; i++) 183 | { 184 | bufferView.Populate (v4s[i].x); 185 | bufferView.Populate (v4s[i].y); 186 | bufferView.Populate (v4s[i].z); 187 | bufferView.Populate (v4s[i].w); 188 | 189 | minFloat.x = Mathf.Min(v4s[i].x, minFloat.x); 190 | minFloat.y = Mathf.Min(v4s[i].y, minFloat.y); 191 | minFloat.z = Mathf.Min(v4s[i].z, minFloat.z); 192 | minFloat.w = Mathf.Min(v4s[i].w, minFloat.w); 193 | maxFloat.x = Mathf.Max(v4s[i].x, maxFloat.x); 194 | maxFloat.y = Mathf.Max(v4s[i].y, maxFloat.y); 195 | maxFloat.z = Mathf.Max(v4s[i].z, maxFloat.z); 196 | maxFloat.w = Mathf.Max(v4s[i].w, maxFloat.w); 197 | } 198 | } 199 | 200 | } 201 | 202 | public void Populate (Matrix4x4[] ms) 203 | { 204 | if (type != Type.MAT4) 205 | throw (new System.Exception()); 206 | byteOffset = bufferView.currentOffset; 207 | count = ms.Length; 208 | if (count > 0) 209 | { 210 | for (int i = 0; i < ms.Length; i++) 211 | { 212 | var m = ms[i]; 213 | bufferView.Populate (m.m00); 214 | bufferView.Populate (m.m10); 215 | bufferView.Populate (m.m20); 216 | bufferView.Populate (m.m30); 217 | bufferView.Populate (m.m01); 218 | bufferView.Populate (m.m11); 219 | bufferView.Populate (m.m21); 220 | bufferView.Populate (m.m31); 221 | bufferView.Populate (m.m02); 222 | bufferView.Populate (m.m12); 223 | bufferView.Populate (m.m22); 224 | bufferView.Populate (m.m32); 225 | bufferView.Populate (m.m03); 226 | bufferView.Populate (m.m13); 227 | bufferView.Populate (m.m23); 228 | bufferView.Populate (m.m33); 229 | } 230 | } 231 | } 232 | 233 | void WriteMin() 234 | { 235 | if (componentType == ComponentType.FLOAT) 236 | { 237 | switch (type) 238 | { 239 | case Type.SCALAR: 240 | jsonWriter.Write (minFloat.x); 241 | break; 242 | 243 | case Type.VEC2: 244 | jsonWriter.Write (minFloat.x + ", " + minFloat.y); 245 | break; 246 | 247 | case Type.VEC3: 248 | jsonWriter.Write (minFloat.x + ", " + minFloat.y + ", " + minFloat.z); 249 | break; 250 | 251 | case Type.VEC4: 252 | jsonWriter.Write (minFloat.x + ", " + minFloat.y + ", " + minFloat.z + ", " + minFloat.w); 253 | break; 254 | } 255 | } 256 | else if (componentType == ComponentType.USHORT) 257 | { 258 | if (type == Type.SCALAR) 259 | { 260 | jsonWriter.Write(minInt); 261 | } 262 | } 263 | } 264 | 265 | void WriteMax() 266 | { 267 | if (componentType == ComponentType.FLOAT) 268 | { 269 | switch (type) 270 | { 271 | case Type.SCALAR: 272 | jsonWriter.Write (maxFloat.x); 273 | break; 274 | 275 | case Type.VEC2: 276 | jsonWriter.Write (maxFloat.x + ", " + maxFloat.y); 277 | break; 278 | 279 | case Type.VEC3: 280 | jsonWriter.Write (maxFloat.x + ", " + maxFloat.y + ", " + maxFloat.z); 281 | break; 282 | 283 | case Type.VEC4: 284 | jsonWriter.Write (maxFloat.x + ", " + maxFloat.y + ", " + maxFloat.z + ", " + maxFloat.w); 285 | break; 286 | } 287 | } 288 | else if (componentType == ComponentType.USHORT) 289 | { 290 | if (type == Type.SCALAR) 291 | { 292 | jsonWriter.Write(maxInt); 293 | } 294 | } 295 | } 296 | 297 | public override void Write () 298 | { 299 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 300 | IndentIn(); 301 | Indent(); jsonWriter.Write ("\"bufferView\": \"" + bufferView.name+"\",\n"); 302 | Indent(); jsonWriter.Write ("\"byteOffset\": " + byteOffset + ",\n"); 303 | Indent(); jsonWriter.Write ("\"byteStride\": " + byteStride + ",\n"); 304 | Indent(); jsonWriter.Write ("\"componentType\": " + (int)componentType + ",\n"); 305 | Indent(); jsonWriter.Write ("\"count\": " + count + ",\n"); 306 | 307 | if (type != Type.MAT4) 308 | { 309 | Indent(); jsonWriter.Write ("\"max\": [ "); 310 | WriteMax(); 311 | jsonWriter.Write (" ],\n"); 312 | Indent(); jsonWriter.Write ("\"min\": [ "); 313 | WriteMin(); 314 | jsonWriter.Write (" ],\n"); 315 | } 316 | 317 | Indent(); jsonWriter.Write ("\"type\": \"" + type + "\"\n"); 318 | IndentOut(); 319 | Indent(); jsonWriter.Write (" }"); 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /GlTF_Animation.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEditor; 5 | 6 | public class GlTF_Animation : GlTF_Writer { 7 | public List channels = new List(); 8 | public List animSamplers = new List(); 9 | bool gotTranslation = false; 10 | bool gotRotation = false; 11 | bool gotScale = false; 12 | 13 | class BoneAnimPath { 14 | public enum Type { 15 | Translation, 16 | Scale, 17 | Rotation 18 | } 19 | 20 | public GlTF_Target target; 21 | public GlTF_AnimSampler sampler; 22 | public GlTF_Channel channel; 23 | public GlTF_Accessor accessor; 24 | 25 | Type type; 26 | Vector3[] v3; 27 | Vector4[] v4; 28 | bool wx, wy, wz, ww; 29 | 30 | public BoneAnimPath(Type type, string animName, string objectName) { 31 | this.type = type; 32 | var typeStr = TypeToString(type); 33 | target = new GlTF_Target(); 34 | target.id = objectName; 35 | target.path = typeStr; 36 | var subName = typeStr + "_" + animName + "_" + objectName; 37 | sampler = new GlTF_AnimSampler("sampler_" + subName, "param_" + subName); 38 | channel = new GlTF_Channel(sampler, target); 39 | accessor = new GlTF_Accessor("accessor_anim_" + subName, TypeToAccType(type), GlTF_Accessor.ComponentType.FLOAT); 40 | switch (type) { 41 | case Type.Translation: 42 | case Type.Scale: 43 | accessor.bufferView = GlTF_Writer.vec3BufferView; 44 | break; 45 | case Type.Rotation: 46 | accessor.bufferView = GlTF_Writer.vec4BufferView; 47 | break; 48 | } 49 | GlTF_Writer.accessors.Add(accessor); 50 | } 51 | 52 | public void PopulateAccessor(AnimationClipCurveData cd, Keyframe[] refKeyFrames) { 53 | string propName = cd.propertyName; 54 | if (type == Type.Translation || type == Type.Scale) { 55 | if (v3 == null) { 56 | v3 = new Vector3[refKeyFrames.Length]; 57 | } 58 | 59 | if (propName.Contains (".x")) { 60 | wx = true; 61 | for (var i = 0; i < refKeyFrames.Length; ++i) { 62 | v3[i].x = cd.curve.Evaluate(refKeyFrames[i].time); 63 | } 64 | } else if (propName.Contains (".y")) { 65 | wy = true; 66 | for (var i = 0; i < refKeyFrames.Length; ++i) { 67 | v3[i].y = cd.curve.Evaluate(refKeyFrames[i].time); 68 | } 69 | } else if (propName.Contains (".z")) { 70 | wz = true; 71 | for (var i = 0; i < refKeyFrames.Length; ++i) { 72 | v3[i].z = cd.curve.Evaluate(refKeyFrames[i].time); 73 | } 74 | } 75 | 76 | if (wx && wy && wz) { 77 | accessor.Populate(v3); 78 | } 79 | } else { 80 | if (v4 == null) { 81 | v4 = new Vector4[refKeyFrames.Length]; 82 | } 83 | 84 | if (propName.Contains (".x")) { 85 | wx = true; 86 | for (var i = 0; i < refKeyFrames.Length; ++i) { 87 | v4[i].x = cd.curve.Evaluate(refKeyFrames[i].time); 88 | } 89 | } else if (propName.Contains (".y")) { 90 | wy = true; 91 | for (var i = 0; i < refKeyFrames.Length; ++i) { 92 | v4[i].y = cd.curve.Evaluate(refKeyFrames[i].time); 93 | } 94 | } else if (propName.Contains (".z")) { 95 | wz = true; 96 | for (var i = 0; i < refKeyFrames.Length; ++i) { 97 | v4[i].z = cd.curve.Evaluate(refKeyFrames[i].time); 98 | } 99 | } else if (propName.Contains (".w")) { 100 | ww = true; 101 | for (var i = 0; i < refKeyFrames.Length; ++i) { 102 | v4[i].w = cd.curve.Evaluate(refKeyFrames[i].time); 103 | } 104 | } 105 | 106 | if (wx && wy && wz && ww) { 107 | accessor.Populate(v4); 108 | } 109 | } 110 | } 111 | 112 | string TypeToString(Type type) { 113 | switch (type) { 114 | case Type.Translation: return "translation"; 115 | case Type.Scale: return "scale"; 116 | case Type.Rotation: return "rotation"; 117 | } 118 | return ""; 119 | } 120 | 121 | GlTF_Accessor.Type TypeToAccType(Type type) { 122 | if (type == Type.Rotation) { 123 | return GlTF_Accessor.Type.VEC4; 124 | } 125 | return GlTF_Accessor.Type.VEC3; 126 | } 127 | } 128 | 129 | class BoneAnimData { 130 | public BoneAnimPath position; 131 | public BoneAnimPath scale; 132 | public BoneAnimPath rotation; 133 | 134 | public BoneAnimData(string animName, string objectName) { 135 | position = new BoneAnimPath(BoneAnimPath.Type.Translation, animName, objectName); 136 | scale = new BoneAnimPath(BoneAnimPath.Type.Scale, animName, objectName); 137 | rotation = new BoneAnimPath(BoneAnimPath.Type.Rotation, animName, objectName); 138 | } 139 | 140 | public void PopulateAccessor(AnimationClipCurveData cd, Keyframe[] refKeyFrames) { 141 | string propName = cd.propertyName; 142 | 143 | if (propName.Contains("m_LocalPosition")){ 144 | position.PopulateAccessor(cd, refKeyFrames); 145 | } else if (propName.Contains("m_LocalRotation")){ 146 | rotation.PopulateAccessor(cd, refKeyFrames); 147 | } else if (propName.Contains("m_LocalScale")){ 148 | scale.PopulateAccessor(cd, refKeyFrames); 149 | } 150 | } 151 | } 152 | 153 | Dictionary boneAnimData = new Dictionary(); 154 | GlTF_Accessor timeAccessor; 155 | 156 | public GlTF_Animation () { 157 | } 158 | 159 | public void Populate (AnimationClip c, Transform tr) 160 | { 161 | name = "anim_" + c.name + "_" + GlTF_Writer.GetNameFromObject(tr, true); 162 | // AnimationUtility.GetCurveBindings(c); 163 | // look at each curve 164 | // if position, rotation, scale detected for first time 165 | // create channel, sampler, param for it 166 | // populate this curve into proper component 167 | AnimationClipCurveData[] curveDatas = AnimationUtility.GetAllCurves(c, true); 168 | 169 | // Find curve which has most keyframes for time reference 170 | Keyframe[] refKeyFrames = null; 171 | for (int i = 0; i < curveDatas.Length; ++i) { 172 | var cd = curveDatas[i]; 173 | if (refKeyFrames == null || cd.curve.keys.Length > refKeyFrames.Length) { 174 | refKeyFrames = cd.curve.keys; 175 | } 176 | } 177 | PopulateTime(c.name, refKeyFrames); 178 | 179 | for (int i = 0; i < curveDatas.Length; i++) 180 | { 181 | var cd = curveDatas[i]; 182 | string propName = cd.propertyName; 183 | var boneTransform = GetTransformFromPath(cd.path, tr); 184 | if (boneTransform == null) { 185 | continue; 186 | } 187 | 188 | var boneName = GlTF_Node.GetNameFromObject(boneTransform); 189 | BoneAnimData bad; 190 | if (boneAnimData.ContainsKey(boneName)) { 191 | bad = boneAnimData[boneName]; 192 | } else { 193 | bad = new BoneAnimData(c.name, boneName); 194 | boneAnimData[boneName] = bad; 195 | } 196 | bad.PopulateAccessor(cd, refKeyFrames); 197 | } 198 | } 199 | 200 | void PopulateTime(string animName, Keyframe[] keyFrames) { 201 | timeAccessor = new GlTF_Accessor("accessor_anim_time_" + animName, GlTF_Accessor.Type.SCALAR, GlTF_Accessor.ComponentType.FLOAT); 202 | timeAccessor.bufferView = GlTF_Writer.floatBufferView; 203 | GlTF_Writer.accessors.Add (timeAccessor); 204 | var times = new float[keyFrames.Length]; 205 | for (int i = 0; i < keyFrames.Length; i++) 206 | times[i] = keyFrames[i].time; 207 | timeAccessor.Populate (times); 208 | } 209 | 210 | Transform GetTransformFromPath(string path, Transform tr) { 211 | var name = path; 212 | var parent = tr; 213 | while (true) { 214 | var idx = name.IndexOf("/"); 215 | if (idx != -1) { 216 | var cn = name.Substring(0, idx); 217 | var c = parent.FindChild(cn); 218 | if (c != null) { 219 | parent = c; 220 | } else { 221 | // invalid path 222 | return null; 223 | } 224 | name = name.Substring(idx + 1); 225 | } else { 226 | parent = parent.FindChild(name); 227 | break; 228 | } 229 | } 230 | return parent; 231 | } 232 | 233 | public override void Write() 234 | { 235 | Indent(); jsonWriter.Write ("\"" + name + "\": {\n"); 236 | IndentIn(); 237 | Indent(); jsonWriter.Write ("\"channels\": [\n"); 238 | foreach (BoneAnimData bad in boneAnimData.Values) 239 | { 240 | if (bad.position.accessor.count > 0) 241 | { 242 | CommaNL(); 243 | bad.position.channel.Write(); 244 | } 245 | if (bad.rotation.accessor.count > 0) 246 | { 247 | CommaNL(); 248 | bad.rotation.channel.Write(); 249 | } 250 | if (bad.scale.accessor.count > 0) 251 | { 252 | CommaNL(); 253 | bad.scale.channel.Write(); 254 | } 255 | } 256 | jsonWriter.WriteLine(); 257 | Indent(); jsonWriter.Write ("]"); 258 | CommaNL(); 259 | 260 | Indent(); jsonWriter.Write ("\"parameters\": {\n"); 261 | IndentIn(); 262 | 263 | CommaNL(); 264 | Indent(); jsonWriter.Write ("\"TIME\": \"" + timeAccessor.name + "\""); 265 | foreach (BoneAnimData bad in boneAnimData.Values) 266 | { 267 | if (bad.position.accessor.count > 0) 268 | { 269 | CommaNL(); 270 | Indent(); jsonWriter.Write ("\"" + bad.position.sampler.output + "\": \"" + bad.position.accessor.name + "\""); 271 | } 272 | if (bad.rotation.accessor.count > 0) 273 | { 274 | CommaNL(); 275 | Indent(); jsonWriter.Write ("\"" + bad.rotation.sampler.output + "\": \"" + bad.rotation.accessor.name + "\""); 276 | } 277 | if (bad.scale.accessor.count > 0) 278 | { 279 | CommaNL(); 280 | Indent(); jsonWriter.Write ("\"" + bad.scale.sampler.output + "\": \"" + bad.scale.accessor.name + "\""); 281 | } 282 | } 283 | jsonWriter.WriteLine(); 284 | 285 | IndentOut(); 286 | Indent(); jsonWriter.Write ("}"); 287 | CommaNL(); 288 | 289 | // parameters.Write (); 290 | // CommaNL(); 291 | 292 | Indent(); jsonWriter.Write ("\"samplers\": {\n"); 293 | IndentIn(); 294 | foreach (BoneAnimData bad in boneAnimData.Values) 295 | { 296 | if (bad.position.accessor.count > 0) 297 | { 298 | CommaNL(); 299 | bad.position.sampler.Write(); 300 | } 301 | if (bad.rotation.accessor.count > 0) 302 | { 303 | CommaNL(); 304 | bad.rotation.sampler.Write(); 305 | } 306 | if (bad.scale.accessor.count > 0) 307 | { 308 | CommaNL(); 309 | bad.scale.sampler.Write(); 310 | } 311 | } 312 | IndentOut(); 313 | jsonWriter.WriteLine(); 314 | Indent(); jsonWriter.Write ("}\n"); 315 | 316 | IndentOut(); 317 | Indent(); jsonWriter.Write ("}"); 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /TextureUnpacker.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | // NOTES: 7 | // - only checks first texture and first uv 8 | 9 | public class TextureUnpacker { 10 | 11 | class Entry { 12 | public int left; 13 | public int right; 14 | public int top; 15 | public int bottom; 16 | public int texWidth; 17 | public int texHeight; 18 | public Dictionary> subMeshMap = new Dictionary>(); 19 | } 20 | 21 | class UVTransform { 22 | public Vector2 offset; 23 | public Vector2 scale; 24 | } 25 | 26 | static Dictionary entries = new Dictionary(); // texture id->entry 27 | static Dictionary> meshMap = new Dictionary>(); 28 | 29 | static Renderer GetRenderer(Transform tr) { 30 | Renderer mr = tr.GetComponent(); 31 | if (mr == null) { 32 | mr = tr.GetComponent(); 33 | } 34 | return mr; 35 | } 36 | 37 | static Mesh GetMesh(Transform tr) { 38 | var mr = GetRenderer(tr); 39 | Mesh m = null; 40 | if (mr != null) { 41 | var t = mr.GetType(); 42 | if (t == typeof(MeshRenderer)) { 43 | MeshFilter mf = tr.GetComponent(); 44 | m = mf.sharedMesh; 45 | } else if (t == typeof(SkinnedMeshRenderer)) { 46 | SkinnedMeshRenderer smr = mr as SkinnedMeshRenderer; 47 | m = smr.sharedMesh; 48 | } 49 | } 50 | return m; 51 | } 52 | 53 | static List GetTexturesFromRenderer(Renderer r) { 54 | var ret = new List(); 55 | 56 | var mats = r.sharedMaterials; 57 | foreach (var mat in mats) { 58 | if (mat == null) { 59 | continue; 60 | } 61 | var s = mat.shader; 62 | 63 | int spCount = ShaderUtil.GetPropertyCount(s); 64 | for (var i = 0; i < spCount; ++i) { 65 | var pName = ShaderUtil.GetPropertyName(s, i); 66 | var pType = ShaderUtil.GetPropertyType(s, i); 67 | 68 | if (pType == ShaderUtil.ShaderPropertyType.TexEnv) { 69 | var td = ShaderUtil.GetTexDim(s, i); 70 | if (td == UnityEngine.Rendering.TextureDimension.Tex2D) { 71 | var t = mat.GetTexture(pName); 72 | if (t != null) { 73 | ret.Add(t); 74 | } 75 | } 76 | } 77 | } 78 | } 79 | 80 | return ret; 81 | } 82 | 83 | static List GetTexturesFromMaterial(Material mat) { 84 | var ret = new List(); 85 | if (mat == null) { 86 | return ret; 87 | } 88 | 89 | var s = mat.shader; 90 | 91 | int spCount = ShaderUtil.GetPropertyCount(s); 92 | for (var i = 0; i < spCount; ++i) { 93 | var pName = ShaderUtil.GetPropertyName(s, i); 94 | var pType = ShaderUtil.GetPropertyType(s, i); 95 | 96 | if (pType == ShaderUtil.ShaderPropertyType.TexEnv) { 97 | var td = ShaderUtil.GetTexDim(s, i); 98 | if (td == UnityEngine.Rendering.TextureDimension.Tex2D) { 99 | var t = mat.GetTexture(pName); 100 | if (t != null) { 101 | ret.Add(t); 102 | } 103 | } 104 | } 105 | } 106 | 107 | return ret; 108 | } 109 | 110 | public static void CheckPackedTexture(Transform t, Preset preset) { 111 | var m = GetMesh(t); 112 | var r = GetRenderer(t); 113 | 114 | if (m != null && r != null) { 115 | 116 | for (int i = 0; i < m.subMeshCount; ++i) { 117 | if (m.GetTopology(i) != MeshTopology.Triangles || 118 | i >= r.sharedMaterials.Length) { 119 | continue; 120 | } 121 | var mat = r.sharedMaterials[i]; 122 | if (mat == null) { 123 | Debug.LogWarning("Failed getting shader name from material on mesh " + m.name); 124 | continue; 125 | } 126 | List unpackUVList = null; 127 | preset.unpackUV.TryGetValue(mat.shader.name, out unpackUVList); 128 | if (unpackUVList == null) { 129 | unpackUVList = preset.GetDefaultUnpackUVList(); 130 | } 131 | 132 | var tris = m.GetTriangles(i); 133 | 134 | var uvsArr = new Vector2[][]{m.uv, m.uv2, m.uv3, m.uv4}; 135 | var mins = new Vector2[4]; 136 | var maxs = new Vector2[4]; 137 | var dxs = new float[4]; 138 | var dys = new float[4]; 139 | for (int k = 0; k < 4; ++k) { 140 | Vector2 min = new Vector2(float.MaxValue, float.MaxValue); 141 | Vector2 max = new Vector2(float.MinValue, float.MinValue); 142 | 143 | var uvs = uvsArr[k]; 144 | if (uvs != null && uvs.Length > 0) { 145 | for (int j = 0; j < tris.Length; ++j) { 146 | Vector2 uv = uvs[tris[j]]; 147 | float y = 1.0f - uv.y; // flipped y 148 | min.x = Mathf.Min(min.x, uv.x); 149 | min.y = Mathf.Min(min.y, y); 150 | max.x = Mathf.Max(max.x, uv.x); 151 | max.y = Mathf.Max(max.y, y); 152 | } 153 | 154 | var dx = max.x - min.x; 155 | var dy = max.y - min.y; 156 | dxs[k] = dx; 157 | dys[k] = dy; 158 | } 159 | 160 | mins[k] = min; 161 | maxs[k] = max; 162 | } 163 | 164 | var texs = GetTexturesFromMaterial(mat); 165 | 166 | foreach (var unpackUV in unpackUVList) { 167 | foreach (var texIdx in unpackUV.textureIndex) { 168 | if (texIdx < texs.Count) { 169 | var tex = texs[texIdx]; 170 | var name = GlTF_Texture.GetNameFromObject(tex); 171 | var dx = dxs[unpackUV.index]; 172 | var dy = dys[unpackUV.index]; 173 | var max = maxs[unpackUV.index]; 174 | var min = mins[unpackUV.index]; 175 | 176 | max.x = Mathf.Clamp01(max.x); 177 | max.y = Mathf.Clamp01(max.y); 178 | min.x = Mathf.Clamp01(min.x); 179 | min.y = Mathf.Clamp01(min.y); 180 | 181 | var tw = tex.width; 182 | var th = tex.height; 183 | 184 | var sx = Mathf.FloorToInt(min.x * tw); 185 | var fx = Mathf.CeilToInt(max.x * tw); 186 | var sy = Mathf.FloorToInt(min.y * th); 187 | var fy = Mathf.CeilToInt(max.y * th); 188 | int wx = fx - sx; 189 | int wy = fy - sy; 190 | 191 | wx = Mathf.NextPowerOfTwo(wx); 192 | wy = Mathf.NextPowerOfTwo(wy); 193 | 194 | var meshName = GlTF_Mesh.GetNameFromObject(m); 195 | Entry e; 196 | if (entries.ContainsKey(name)) { 197 | e = entries[name]; 198 | 199 | //merge 200 | var minX = Mathf.Min(e.left, sx); 201 | var maxX = Mathf.Max(e.right, fx); 202 | var minY = Mathf.Min(e.top, sy); 203 | var maxY = Mathf.Max(e.bottom, fy); 204 | 205 | var mw = maxX - minX; 206 | var mh = maxY - minY; 207 | 208 | mw = Mathf.NextPowerOfTwo(mw); 209 | mh = Mathf.NextPowerOfTwo(mh); 210 | 211 | e.left = minX; 212 | e.right = maxX; 213 | e.top = minY; 214 | e.bottom = maxY; 215 | } else { 216 | e = new Entry(); 217 | e.left = sx; 218 | e.right = fx; 219 | e.top = sy; 220 | e.bottom = fy; 221 | e.texWidth = tex.width; 222 | e.texHeight = tex.height; 223 | entries[name] = e; 224 | } 225 | 226 | List subMeshId = null; 227 | if (e.subMeshMap.ContainsKey(meshName)) { 228 | subMeshId = e.subMeshMap[meshName]; 229 | } else { 230 | subMeshId = new List(); 231 | e.subMeshMap[meshName] = subMeshId; 232 | } 233 | 234 | if (!subMeshId.Contains(i)) { 235 | subMeshId.Add(i); 236 | } 237 | } 238 | } 239 | } 240 | } 241 | } 242 | } 243 | 244 | public static void Reset() { 245 | entries.Clear(); 246 | meshMap.Clear(); 247 | } 248 | 249 | public static void Build() { 250 | var skipList = new List(); 251 | foreach (var i in entries) { 252 | var e = i.Value; 253 | var mw = e.right - e.left; 254 | var mh = e.bottom - e.top; 255 | var dx = (float)mw / (float)e.texWidth; 256 | var dy = (float)mh / (float)e.texHeight; 257 | 258 | if (dx >= 0.9 || dy >= 0.9) { 259 | skipList.Add(i.Key); 260 | } 261 | } 262 | 263 | foreach (var sl in skipList) { 264 | entries.Remove(sl); 265 | } 266 | 267 | foreach (var i in entries) { 268 | var e = i.Value; 269 | 270 | var mw = e.right - e.left; 271 | var mh = e.bottom - e.top; 272 | 273 | mw = Mathf.NextPowerOfTwo(mw); 274 | mh = Mathf.NextPowerOfTwo(mh); 275 | 276 | int left = e.left; 277 | int right = left + (mw - 1); 278 | if (right > e.texWidth - 1) { 279 | // shift left 280 | right = e.texWidth - 1; 281 | left = right - (mw - 1); 282 | } 283 | 284 | int top = e.top; 285 | int bottom = top + (mh - 1); 286 | if (bottom > e.texHeight - 1) { 287 | // shift up 288 | bottom = e.texHeight - 1; 289 | top = bottom - (mh - 1); 290 | } 291 | 292 | UVTransform uvt = new UVTransform(); 293 | uvt.offset = new Vector2(-(float)left / (float)e.texWidth, -(float)top / (float)e.texHeight); 294 | uvt.scale = new Vector2((float)e.texWidth / (float)mw, (float)e.texHeight / (float)mh); 295 | 296 | foreach (var j in e.subMeshMap) { 297 | var list = j.Value; 298 | Dictionary uvtMap = null; 299 | if (meshMap.ContainsKey(j.Key)) { 300 | uvtMap = meshMap[j.Key]; 301 | } else { 302 | uvtMap = new Dictionary(); 303 | meshMap[j.Key] = uvtMap; 304 | } 305 | 306 | foreach (var subMeshIdx in list) { 307 | uvtMap[subMeshIdx] = uvt; 308 | } 309 | } 310 | } 311 | } 312 | 313 | public static void ProcessMesh(GlTF_Mesh mesh) { 314 | if (meshMap.ContainsKey(mesh.name)) { 315 | var uvtMap = meshMap[mesh.name]; 316 | HashSet moddedIndex = new HashSet(); // keep track modified uv 317 | foreach (var i in uvtMap) { 318 | var idx = i.Key; 319 | var uvt = i.Value; 320 | 321 | if (idx < mesh.primitives.Count) { 322 | var prim = mesh.primitives[idx]; 323 | var ms = prim.indices.bufferView.memoryStream; 324 | int offset = (int)prim.indices.byteOffset; 325 | var len = prim.indices.count; 326 | var buffer = new byte[len * 2]; 327 | 328 | // read indices 329 | var pos = ms.Position; 330 | ms.Position = offset; 331 | ms.Read(buffer, 0, buffer.Length); 332 | 333 | ushort[] indices = new ushort[len]; 334 | for (int j = 0; j < len; ++j) { 335 | indices[j] = System.BitConverter.ToUInt16(buffer, j * 2); 336 | } 337 | ms.Position = pos; 338 | 339 | //read uvs 340 | ms = prim.attributes.texCoord0Accessor.bufferView.memoryStream; 341 | offset = (int)prim.attributes.texCoord0Accessor.byteOffset; 342 | len = prim.attributes.texCoord0Accessor.count; 343 | buffer = new byte[len * 8]; 344 | pos = ms.Position; 345 | ms.Position = offset; 346 | ms.Read(buffer, 0, buffer.Length); 347 | 348 | Vector2[] uvs = new Vector2[len]; 349 | for (int j = 0; j < len; ++j) { 350 | var u = System.BitConverter.ToSingle(buffer, j * 8); 351 | var v = System.BitConverter.ToSingle(buffer, j * 8 + 4); 352 | uvs[j] = new Vector2(u, v); 353 | } 354 | ms.Position = pos; 355 | 356 | // manipulate uvs 357 | for (int j = 0; j < indices.Length; ++j) { 358 | var ind = indices[j]; 359 | if (!moddedIndex.Contains(ind)) { 360 | var uv = uvs[ind]; 361 | uv += uvt.offset; 362 | uv.Scale(uvt.scale); 363 | uvs[indices[j]] = uv; 364 | moddedIndex.Add(ind); 365 | } 366 | } 367 | 368 | // write back 369 | prim.attributes.texCoord0Accessor.Populate(uvs); 370 | } 371 | 372 | } 373 | } 374 | } 375 | 376 | public static Texture2D ProcessTexture(string name, Texture2D tex) { 377 | if (entries.ContainsKey(name)) { 378 | Entry e = entries[name]; 379 | 380 | var mw = e.right - e.left; 381 | var mh = e.bottom - e.top; 382 | 383 | mw = Mathf.NextPowerOfTwo(mw); 384 | mh = Mathf.NextPowerOfTwo(mh); 385 | 386 | int left = e.left; 387 | int right = left + (mw - 1); 388 | if (right > e.texWidth - 1) { 389 | // shift left 390 | right = e.texWidth - 1; 391 | left = right - (mw - 1); 392 | } 393 | 394 | int top = e.top; 395 | int bottom = top + (mh - 1); 396 | if (bottom > e.texHeight - 1) { 397 | // shift up 398 | bottom = e.texHeight - 1; 399 | top = bottom - (mh - 1); 400 | } 401 | 402 | // flip top & bottom 403 | var ftop = e.texHeight - 1 - top; 404 | var fbottom = e.texHeight - 1 - bottom; 405 | top = fbottom; 406 | bottom = ftop; 407 | 408 | var src = tex.GetPixels32(); 409 | var dst = new Color32[mw * mh]; 410 | 411 | for (int i = 0; i < mh; ++i) { 412 | for (int j = 0; j < mw; ++j) { 413 | var dstIdx = i * mw + j; 414 | var srcIdx = (top + i) * tex.width + (left + j); 415 | dst[dstIdx] = src[srcIdx]; 416 | } 417 | } 418 | 419 | Texture2D t = new Texture2D(mw, mh, TextureFormat.RGBA32, false); 420 | t.SetPixels32(dst); 421 | t.Apply(); 422 | 423 | return t; 424 | } 425 | return tex; 426 | } 427 | } 428 | -------------------------------------------------------------------------------- /GlTF_Writer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.IO; 4 | using System.Collections.Generic; 5 | 6 | public class GlTF_Writer { 7 | public static FileStream fs; 8 | public static StreamWriter jsonWriter; 9 | public static BinaryWriter binWriter; 10 | public static Stream binFile; 11 | public static int indent = 0; 12 | public static string binFileName; 13 | public static bool binary; 14 | public static bool b3dm; 15 | static bool[] firsts = new bool[100]; 16 | public static GlTF_BufferView ushortBufferView = new GlTF_BufferView("ushortBufferView", 34963); 17 | public static GlTF_BufferView floatBufferView = new GlTF_BufferView("floatBufferView"); 18 | public static GlTF_BufferView vec2BufferView = new GlTF_BufferView("vec2BufferView"); 19 | public static GlTF_BufferView vec3BufferView = new GlTF_BufferView("vec3BufferView"); 20 | public static GlTF_BufferView vec4BufferView = new GlTF_BufferView("vec4BufferView"); 21 | public static GlTF_BufferView mat4BufferView = new GlTF_BufferView("mat4BufferView", -1); 22 | public static List bufferViews = new List(); 23 | public static List cameras = new List(); 24 | public static List lights = new List(); 25 | public static List meshes = new List(); 26 | public static List accessors = new List(); 27 | public static List nodes = new List(); 28 | public static Dictionary materials = new Dictionary(); 29 | public static Dictionary samplers = new Dictionary(); 30 | public static Dictionary textures = new Dictionary(); 31 | public static List images = new List(); 32 | public static List animations = new List(); 33 | public static List skins = new List(); 34 | public static Dictionary techniques = new Dictionary(); 35 | public static List programs = new List(); 36 | public static List shaders = new List(); 37 | 38 | const int B3DM_HEADER_SIZE = 24; 39 | 40 | public double[] RTCCenter; 41 | 42 | static public string GetNameFromObject(Object o, bool useId = false) 43 | { 44 | var ret = o.name; 45 | ret = ret.Replace(" ", "_"); 46 | ret = ret.Replace("/", "_"); 47 | ret = ret.Replace("\\", "_"); 48 | 49 | if (useId) 50 | { 51 | ret += "_" + o.GetInstanceID(); 52 | } 53 | return ret; 54 | } 55 | 56 | public void Init() 57 | { 58 | firsts = new bool[100]; 59 | ushortBufferView = new GlTF_BufferView("ushortBufferView", 34963); 60 | floatBufferView = new GlTF_BufferView("floatBufferView"); 61 | vec2BufferView = new GlTF_BufferView("vec2BufferView"); 62 | vec3BufferView = new GlTF_BufferView("vec3BufferView"); 63 | vec4BufferView = new GlTF_BufferView("vec4BufferView"); 64 | bufferViews = new List(); 65 | cameras = new List(); 66 | lights = new List(); 67 | meshes = new List(); 68 | accessors = new List(); 69 | nodes = new List(); 70 | materials = new Dictionary(); 71 | samplers = new Dictionary(); 72 | textures = new Dictionary(); 73 | images = new List(); 74 | animations = new List(); 75 | skins = new List(); 76 | techniques = new Dictionary(); 77 | programs = new List(); 78 | shaders = new List(); 79 | } 80 | 81 | public void Indent() { 82 | for (int i = 0; i < indent; i++) 83 | jsonWriter.Write ("\t"); 84 | } 85 | 86 | public void IndentIn() { 87 | indent++; 88 | firsts[indent] = true; 89 | } 90 | 91 | public void IndentOut() { 92 | indent--; 93 | } 94 | 95 | public void CommaStart() { 96 | firsts[indent] = false; 97 | } 98 | 99 | public void CommaNL() { 100 | if (!firsts[indent]) 101 | jsonWriter.Write (",\n"); 102 | // else 103 | // jsonWriter.Write ("\n"); 104 | firsts[indent] = false; 105 | } 106 | 107 | public string name; // name of this object 108 | 109 | public void OpenFiles (string filepath) { 110 | fs = File.Open(filepath, FileMode.Create); 111 | 112 | if (binary) 113 | { 114 | binWriter = new BinaryWriter(fs); 115 | binFile = fs; 116 | 117 | long offset = 20 + (b3dm ? B3DM_HEADER_SIZE : 0); 118 | fs.Seek(offset, SeekOrigin.Begin); // header skip 119 | } 120 | else 121 | { 122 | // separate bin file 123 | binFileName = Path.GetFileNameWithoutExtension (filepath) + ".bin"; 124 | var binPath = Path.Combine(Path.GetDirectoryName(filepath), binFileName); 125 | binFile = File.Open(binPath, FileMode.Create); 126 | } 127 | 128 | jsonWriter = new StreamWriter (fs); 129 | } 130 | 131 | public void CloseFiles() { 132 | if (binary) 133 | { 134 | binWriter.Close(); 135 | } 136 | else 137 | { 138 | binFile.Close(); 139 | } 140 | 141 | jsonWriter.Close (); 142 | fs.Close(); 143 | } 144 | 145 | public virtual void Write () { 146 | 147 | bufferViews.Add (ushortBufferView); 148 | bufferViews.Add (floatBufferView); 149 | bufferViews.Add (vec2BufferView); 150 | bufferViews.Add (vec3BufferView); 151 | bufferViews.Add (vec4BufferView); 152 | bufferViews.Add (mat4BufferView); 153 | 154 | ushortBufferView.bin = binary; 155 | floatBufferView.bin = binary; 156 | vec2BufferView.bin = binary; 157 | vec3BufferView.bin = binary; 158 | vec4BufferView.bin = binary; 159 | mat4BufferView.bin = binary; 160 | 161 | // write memory streams to binary file 162 | ushortBufferView.byteOffset = 0; 163 | ushortBufferView.Align(4); 164 | floatBufferView.byteOffset = ushortBufferView.byteLength; 165 | vec2BufferView.byteOffset = floatBufferView.byteOffset + floatBufferView.byteLength; 166 | vec3BufferView.byteOffset = vec2BufferView.byteOffset + vec2BufferView.byteLength; 167 | vec4BufferView.byteOffset = vec3BufferView.byteOffset + vec3BufferView.byteLength; 168 | mat4BufferView.byteOffset = vec4BufferView.byteOffset + vec4BufferView.byteLength; 169 | 170 | jsonWriter.Write ("{\n"); 171 | IndentIn(); 172 | 173 | // asset 174 | CommaNL(); 175 | Indent(); jsonWriter.Write ("\"asset\": {\n"); 176 | IndentIn(); 177 | Indent(); jsonWriter.Write ("\"version\": \"1\"\n"); 178 | IndentOut(); 179 | Indent(); jsonWriter.Write ("}"); 180 | 181 | if (!binary) 182 | { 183 | // FIX: Should support multiple buffers 184 | CommaNL(); 185 | Indent(); jsonWriter.Write ("\"buffers\": {\n"); 186 | IndentIn(); 187 | Indent(); jsonWriter.Write ("\"" + Path.GetFileNameWithoutExtension(GlTF_Writer.binFileName) +"\": {\n"); 188 | IndentIn(); 189 | Indent(); jsonWriter.Write ("\"byteLength\": "+ (vec4BufferView.byteOffset+vec4BufferView.byteLength)+",\n"); 190 | Indent(); jsonWriter.Write ("\"type\": \"arraybuffer\",\n"); 191 | Indent(); jsonWriter.Write ("\"uri\": \"" + GlTF_Writer.binFileName + "\"\n"); 192 | 193 | IndentOut(); 194 | Indent(); jsonWriter.Write ("}\n"); 195 | 196 | IndentOut(); 197 | Indent(); jsonWriter.Write ("}"); 198 | } 199 | else 200 | { 201 | CommaNL(); 202 | Indent(); jsonWriter.Write ("\"buffers\": {\n"); 203 | IndentIn(); 204 | Indent(); jsonWriter.Write ("\"binary_glTF\": {\n"); 205 | IndentIn(); 206 | Indent(); jsonWriter.Write ("\"byteLength\": "+ (vec4BufferView.byteOffset+vec4BufferView.byteLength)+",\n"); 207 | Indent(); jsonWriter.Write ("\"type\": \"arraybuffer\"\n"); 208 | 209 | IndentOut(); 210 | Indent(); jsonWriter.Write ("}\n"); 211 | 212 | IndentOut(); 213 | Indent(); jsonWriter.Write ("}"); 214 | } 215 | 216 | if (cameras != null && cameras.Count > 0) 217 | { 218 | CommaNL(); 219 | Indent(); jsonWriter.Write ("\"cameras\": {\n"); 220 | IndentIn(); 221 | foreach (GlTF_Camera c in cameras) 222 | { 223 | CommaNL(); 224 | c.Write (); 225 | } 226 | jsonWriter.WriteLine(); 227 | IndentOut(); 228 | Indent(); jsonWriter.Write ("}"); 229 | } 230 | 231 | if (accessors != null && accessors.Count > 0) 232 | { 233 | CommaNL(); 234 | Indent(); jsonWriter.Write ("\"accessors\": {\n"); 235 | IndentIn(); 236 | foreach (GlTF_Accessor a in accessors) 237 | { 238 | if (a.count > 0) 239 | { 240 | CommaNL(); 241 | a.Write (); 242 | } 243 | } 244 | jsonWriter.WriteLine(); 245 | IndentOut(); 246 | Indent(); jsonWriter.Write ("}"); 247 | } 248 | 249 | if (bufferViews != null && bufferViews.Count > 0) 250 | { 251 | CommaNL(); 252 | Indent(); jsonWriter.Write ("\"bufferViews\": {\n"); 253 | IndentIn(); 254 | foreach (GlTF_BufferView bv in bufferViews) 255 | { 256 | if (bv.byteLength > 0) 257 | { 258 | CommaNL(); 259 | bv.Write (); 260 | } 261 | } 262 | jsonWriter.WriteLine(); 263 | IndentOut(); 264 | Indent(); jsonWriter.Write ("}"); 265 | } 266 | 267 | if (meshes != null && meshes.Count > 0) 268 | { 269 | CommaNL(); 270 | Indent(); 271 | jsonWriter.Write ("\"meshes\": {\n"); 272 | IndentIn(); 273 | foreach (GlTF_Mesh m in meshes) 274 | { 275 | CommaNL(); 276 | m.Write (); 277 | } 278 | jsonWriter.WriteLine(); 279 | IndentOut(); 280 | Indent(); 281 | jsonWriter.Write ("}"); 282 | } 283 | 284 | if (shaders != null && shaders.Count > 0) 285 | { 286 | CommaNL(); 287 | Indent(); 288 | jsonWriter.Write ("\"shaders\": {\n"); 289 | IndentIn(); 290 | foreach (var s in shaders) 291 | { 292 | CommaNL(); 293 | s.Write(); 294 | } 295 | jsonWriter.WriteLine(); 296 | IndentOut(); 297 | Indent(); 298 | jsonWriter.Write ("}"); 299 | } 300 | 301 | if (programs != null && programs.Count > 0) 302 | { 303 | CommaNL(); 304 | Indent(); 305 | jsonWriter.Write ("\"programs\": {\n"); 306 | IndentIn(); 307 | foreach (var p in programs) 308 | { 309 | CommaNL(); 310 | p.Write(); 311 | } 312 | jsonWriter.WriteLine(); 313 | IndentOut(); 314 | Indent(); 315 | jsonWriter.Write ("}"); 316 | } 317 | 318 | if (techniques != null && techniques.Count > 0) 319 | { 320 | CommaNL(); 321 | Indent(); 322 | jsonWriter.Write ("\"techniques\": {\n"); 323 | IndentIn(); 324 | foreach (KeyValuePair k in techniques) 325 | { 326 | CommaNL(); 327 | k.Value.Write(); 328 | } 329 | jsonWriter.WriteLine(); 330 | IndentOut(); 331 | Indent(); 332 | jsonWriter.Write ("}"); 333 | } 334 | 335 | // CommaNL(); 336 | // string tqs = @" 337 | // 'techniques': { 338 | // 'technique1': { 339 | // 'parameters': { 340 | // 'ambient': { 341 | // 'type': 35666 342 | // }, 343 | // 'diffuse': { 344 | // 'type': 35678 345 | // }, 346 | // 'emission': { 347 | // 'type': 35666 348 | // }, 349 | // 'light0Color': { 350 | // 'type': 35665, 351 | // 'value': [ 352 | // 1, 353 | // 1, 354 | // 1 355 | // ] 356 | // }, 357 | // 'light0Transform': { 358 | // 'semantic': 'MODELVIEW', 359 | // 'source': 'directionalLight1', 360 | // 'type': 35676 361 | // }, 362 | // 'modelViewMatrix': { 363 | // 'semantic': 'MODELVIEW', 364 | // 'type': 35676 365 | // }, 366 | // 'normal': { 367 | // 'semantic': 'NORMAL', 368 | // 'type': 35665 369 | // }, 370 | // 'normalMatrix': { 371 | // 'semantic': 'MODELVIEWINVERSETRANSPOSE', 372 | // 'type': 35675 373 | // }, 374 | // 'position': { 375 | // 'semantic': 'POSITION', 376 | // 'type': 35665 377 | // }, 378 | // 'projectionMatrix': { 379 | // 'semantic': 'PROJECTION', 380 | // 'type': 35676 381 | // }, 382 | // 'shininess': { 383 | // 'type': 5126 384 | // }, 385 | // 'specular': { 386 | // 'type': 35666 387 | // }, 388 | // 'texcoord0': { 389 | // 'semantic': 'TEXCOORD_0', 390 | // 'type': 35664 391 | // } 392 | // }, 393 | // 'pass': 'defaultPass', 394 | // 'passes': { 395 | // 'defaultPass': { 396 | // 'details': { 397 | // 'commonProfile': { 398 | // 'extras': { 399 | // 'doubleSided': false 400 | // }, 401 | // 'lightingModel': 'Blinn', 402 | // 'parameters': [ 403 | // 'ambient', 404 | // 'diffuse', 405 | // 'emission', 406 | // 'light0Color', 407 | // 'light0Transform', 408 | // 'modelViewMatrix', 409 | // 'normalMatrix', 410 | // 'projectionMatrix', 411 | // 'shininess', 412 | // 'specular' 413 | // ], 414 | // 'texcoordBindings': { 415 | // 'diffuse': 'TEXCOORD_0' 416 | // } 417 | // }, 418 | // 'type': 'COLLADA-1.4.1/commonProfile' 419 | // }, 420 | // 'instanceProgram': { 421 | // 'attributes': { 422 | // 'a_normal': 'normal', 423 | // 'a_position': 'position', 424 | // 'a_texcoord0': 'texcoord0' 425 | // }, 426 | // 'program': 'program_0', 427 | // 'uniforms': { 428 | // 'u_ambient': 'ambient', 429 | // 'u_diffuse': 'diffuse', 430 | // 'u_emission': 'emission', 431 | // 'u_light0Color': 'light0Color', 432 | // 'u_light0Transform': 'light0Transform', 433 | // 'u_modelViewMatrix': 'modelViewMatrix', 434 | // 'u_normalMatrix': 'normalMatrix', 435 | // 'u_projectionMatrix': 'projectionMatrix', 436 | // 'u_shininess': 'shininess', 437 | // 'u_specular': 'specular' 438 | // } 439 | // }, 440 | // 'states': { 441 | // 'enable': [ 442 | // 2884, 443 | // 2929 444 | // ] 445 | // } 446 | // } 447 | // } 448 | // } 449 | // }"; 450 | // tqs = tqs.Replace ("'", "\""); 451 | // jsonWriter.Write (tqs); 452 | 453 | if (samplers.Count > 0) 454 | { 455 | CommaNL(); 456 | Indent(); jsonWriter.Write ("\"samplers\": {\n"); 457 | IndentIn(); 458 | foreach (KeyValuePair s in samplers) 459 | { 460 | CommaNL(); 461 | s.Value.Write (); 462 | } 463 | jsonWriter.WriteLine(); 464 | IndentOut(); 465 | Indent(); jsonWriter.Write ("}"); 466 | } 467 | 468 | if (textures.Count > 0) 469 | { 470 | CommaNL(); 471 | Indent(); jsonWriter.Write ("\"textures\": {\n"); 472 | IndentIn(); 473 | foreach (KeyValuePair t in textures) 474 | { 475 | CommaNL(); 476 | t.Value.Write (); 477 | } 478 | jsonWriter.WriteLine(); 479 | IndentOut(); 480 | Indent(); jsonWriter.Write ("}"); 481 | } 482 | 483 | if (images.Count > 0) 484 | { 485 | CommaNL(); 486 | Indent(); jsonWriter.Write ("\"images\": {\n"); 487 | IndentIn(); 488 | foreach (var i in images) 489 | { 490 | CommaNL(); 491 | i.Write (); 492 | } 493 | jsonWriter.WriteLine(); 494 | IndentOut(); 495 | Indent(); jsonWriter.Write ("}"); 496 | } 497 | 498 | if (materials.Count > 0) 499 | { 500 | CommaNL(); 501 | Indent(); jsonWriter.Write ("\"materials\": {\n"); 502 | IndentIn(); 503 | foreach (KeyValuePair m in materials) 504 | { 505 | CommaNL(); 506 | m.Value.Write (); 507 | } 508 | jsonWriter.WriteLine(); 509 | IndentOut(); 510 | Indent(); jsonWriter.Write ("}"); 511 | } 512 | 513 | if (animations.Count > 0) 514 | { 515 | CommaNL(); 516 | Indent(); jsonWriter.Write ("\"animations\": {\n"); 517 | IndentIn(); 518 | foreach (GlTF_Animation a in animations) 519 | { 520 | CommaNL(); 521 | a.Write (); 522 | } 523 | jsonWriter.WriteLine(); 524 | IndentOut(); 525 | Indent(); jsonWriter.Write ("}"); 526 | } 527 | if (skins.Count > 0) 528 | { 529 | CommaNL(); 530 | Indent(); jsonWriter.Write ("\"skins\": {\n"); 531 | IndentIn(); 532 | foreach (GlTF_Skin s in skins) 533 | { 534 | CommaNL(); 535 | s.Write (); 536 | } 537 | jsonWriter.WriteLine(); 538 | IndentOut(); 539 | Indent(); jsonWriter.Write ("}"); 540 | } 541 | 542 | if (nodes != null && nodes.Count > 0) 543 | { 544 | CommaNL(); 545 | /* 546 | "nodes": { 547 | "node-Alien": { 548 | "children": [], 549 | "matrix": [ 550 | */ 551 | Indent(); jsonWriter.Write ("\"nodes\": {\n"); 552 | IndentIn(); 553 | // bool first = true; 554 | foreach (GlTF_Node n in nodes) 555 | { 556 | CommaNL(); 557 | // if (!first) 558 | // jsonWriter.Write (",\n"); 559 | n.Write (); 560 | // first = false; 561 | } 562 | jsonWriter.WriteLine(); 563 | IndentOut(); 564 | Indent(); jsonWriter.Write ("}"); 565 | 566 | } 567 | CommaNL(); 568 | 569 | Indent(); jsonWriter.Write ("\"scene\": \"defaultScene\",\n"); 570 | Indent(); jsonWriter.Write ("\"scenes\": {\n"); 571 | IndentIn(); 572 | Indent(); jsonWriter.Write ("\"defaultScene\": {\n"); 573 | IndentIn(); 574 | CommaNL(); 575 | Indent(); jsonWriter.Write ("\"nodes\": [\n"); 576 | IndentIn(); 577 | foreach (GlTF_Node n in nodes) 578 | { 579 | if (!n.hasParent) 580 | { 581 | CommaNL(); 582 | Indent(); jsonWriter.Write ("\"" + n.name + "\""); 583 | } 584 | } 585 | jsonWriter.WriteLine(); 586 | IndentOut(); 587 | Indent(); jsonWriter.Write ("]\n"); 588 | IndentOut(); 589 | Indent(); jsonWriter.Write ("}\n"); 590 | IndentOut(); 591 | Indent(); jsonWriter.Write ("}"); 592 | 593 | List extUsed = new List(); 594 | if (binary) 595 | { 596 | extUsed.Add("KHR_binary_glTF"); 597 | } 598 | var rtc = RTCCenter != null && RTCCenter.Length == 3; 599 | if (rtc) 600 | { 601 | extUsed.Add("CESIUM_RTC"); 602 | } 603 | 604 | if (extUsed.Count > 0) 605 | { 606 | CommaNL(); 607 | Indent(); jsonWriter.Write ("\"extensionsUsed\": [\n"); 608 | IndentIn(); 609 | 610 | for (var i = 0; i < extUsed.Count; ++i) 611 | { 612 | CommaNL(); 613 | Indent(); jsonWriter.Write ("\"" + extUsed[i] + "\""); 614 | } 615 | 616 | jsonWriter.Write ("\n"); 617 | IndentOut(); 618 | Indent(); jsonWriter.Write ("]"); 619 | 620 | } 621 | 622 | if (rtc) { 623 | CommaNL(); 624 | Indent(); jsonWriter.Write ("\"extensions\": {\n"); 625 | IndentIn(); 626 | Indent(); jsonWriter.Write ("\"CESIUM_RTC\": {\n"); 627 | IndentIn(); 628 | Indent(); jsonWriter.Write ("\"center\": [\n"); 629 | IndentIn(); 630 | for (var i = 0; i < 3; ++i) 631 | { 632 | CommaNL(); 633 | Indent(); jsonWriter.Write (RTCCenter[i]); 634 | } 635 | jsonWriter.Write ("\n"); 636 | IndentOut(); 637 | Indent(); jsonWriter.Write ("]\n"); 638 | IndentOut(); 639 | Indent(); jsonWriter.Write ("}\n"); 640 | IndentOut(); 641 | Indent(); jsonWriter.Write ("}"); 642 | } 643 | 644 | jsonWriter.Write ("\n"); 645 | IndentOut(); 646 | Indent(); jsonWriter.Write ("}"); 647 | 648 | jsonWriter.Flush(); 649 | 650 | uint contentLength = 0; 651 | if (binary) 652 | { 653 | long curLen = fs.Position; 654 | var rem = curLen % 4; 655 | if (rem != 0) 656 | { 657 | // add padding if not aligned to 4 bytes 658 | var next = (curLen / 4 + 1) * 4; 659 | rem = next - curLen; 660 | for (int i = 0; i < rem; ++i) 661 | { 662 | jsonWriter.Write(" "); 663 | } 664 | } 665 | jsonWriter.Flush(); 666 | 667 | // current pos - header size 668 | int offset = 20 + (b3dm ? B3DM_HEADER_SIZE : 0); 669 | contentLength = (uint)(fs.Position - offset); 670 | } 671 | 672 | 673 | ushortBufferView.memoryStream.WriteTo(binFile); 674 | floatBufferView.memoryStream.WriteTo(binFile); 675 | vec2BufferView.memoryStream.WriteTo (binFile); 676 | vec3BufferView.memoryStream.WriteTo (binFile); 677 | vec4BufferView.memoryStream.WriteTo (binFile); 678 | mat4BufferView.memoryStream.WriteTo(binFile); 679 | 680 | binFile.Flush(); 681 | if (binary) 682 | { 683 | uint fileLength = (uint)fs.Length; 684 | 685 | // write header 686 | fs.Seek(0, SeekOrigin.Begin); 687 | 688 | if (b3dm) 689 | { 690 | jsonWriter.Write("b3dm"); // magic 691 | jsonWriter.Flush(); 692 | binWriter.Write(1); // version 693 | binWriter.Write(fileLength); 694 | binWriter.Write(0); // batchTableJSONByteLength 695 | binWriter.Write(0); // batchTableBinaryByteLength 696 | binWriter.Write(0); // batchLength 697 | binWriter.Flush(); 698 | } 699 | 700 | jsonWriter.Write("glTF"); // magic 701 | jsonWriter.Flush(); 702 | binWriter.Write(1); // version 703 | uint l = (uint)(fileLength - (b3dm ? B3DM_HEADER_SIZE : 0)); // min b3dm header 704 | binWriter.Write(l); 705 | binWriter.Write(contentLength); 706 | binWriter.Write(0); // format 707 | binWriter.Flush(); 708 | } 709 | } 710 | } 711 | -------------------------------------------------------------------------------- /SimpleJSON.cs: -------------------------------------------------------------------------------- 1 | //#define USE_SharpZipLib 2 | #if !UNITY_WEBPLAYER 3 | #define USE_FileIO 4 | #endif 5 | /* * * * * 6 | * A simple JSON Parser / builder 7 | * ------------------------------ 8 | * 9 | * It mainly has been written as a simple JSON parser. It can build a JSON string 10 | * from the node-tree, or generate a node tree from any valid JSON string. 11 | * 12 | * If you want to use compression when saving to file / stream / B64 you have to include 13 | * SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) in your project and 14 | * define "USE_SharpZipLib" at the top of the file 15 | * 16 | * Written by Bunny83 17 | * 2012-06-09 18 | * 19 | * Modified by oPless, 2014-09-21 to round-trip properly 20 | * 21 | * Features / attributes: 22 | * - provides strongly typed node classes and lists / dictionaries 23 | * - provides easy access to class members / array items / data values 24 | * - the parser ignores data types. Each value is a string. 25 | * - only double quotes (") are used for quoting strings. 26 | * - values and names are not restricted to quoted strings. They simply add up and are trimmed. 27 | * - There are only 3 types: arrays(JSONArray), objects(JSONClass) and values(JSONData) 28 | * - provides "casting" properties to easily convert to / from those types: 29 | * int / float / double / bool 30 | * - provides a common interface for each node so no explicit casting is required. 31 | * - the parser try to avoid errors, but if malformed JSON is parsed the result is undefined 32 | * 33 | * 34 | * 2012-12-17 Update: 35 | * - Added internal JSONLazyCreator class which simplifies the construction of a JSON tree 36 | * Now you can simple reference any item that doesn't exist yet and it will return a JSONLazyCreator 37 | * The class determines the required type by it's further use, creates the type and removes itself. 38 | * - Added binary serialization / deserialization. 39 | * - Added support for BZip2 zipped binary format. Requires the SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) 40 | * The usage of the SharpZipLib library can be disabled by removing or commenting out the USE_SharpZipLib define at the top 41 | * - The serializer uses different types when it comes to store the values. Since my data values 42 | * are all of type string, the serializer will "try" which format fits best. The order is: int, float, double, bool, string. 43 | * It's not the most efficient way but for a moderate amount of data it should work on all platforms. 44 | * 45 | * * * * */ 46 | using System; 47 | using System.Collections; 48 | using System.Collections.Generic; 49 | using System.Linq; 50 | 51 | 52 | namespace SimpleJSON 53 | { 54 | public enum JSONBinaryTag 55 | { 56 | Array = 1, 57 | Class = 2, 58 | Value = 3, 59 | IntValue = 4, 60 | DoubleValue = 5, 61 | BoolValue = 6, 62 | FloatValue = 7, 63 | } 64 | 65 | public abstract class JSONNode 66 | { 67 | #region common interface 68 | 69 | public virtual void Add (string aKey, JSONNode aItem) 70 | { 71 | } 72 | 73 | public virtual JSONNode this [int aIndex] { get { return null; } set { } } 74 | 75 | public virtual JSONNode this [string aKey] { get { return null; } set { } } 76 | 77 | public virtual string Value { get { return ""; } set { } } 78 | 79 | public virtual int Count { get { return 0; } } 80 | 81 | public virtual void Add (JSONNode aItem) 82 | { 83 | Add ("", aItem); 84 | } 85 | 86 | public virtual JSONNode Remove (string aKey) 87 | { 88 | return null; 89 | } 90 | 91 | public virtual JSONNode Remove (int aIndex) 92 | { 93 | return null; 94 | } 95 | 96 | public virtual JSONNode Remove (JSONNode aNode) 97 | { 98 | return aNode; 99 | } 100 | 101 | public virtual IEnumerable Children 102 | { 103 | get { 104 | yield break; 105 | } 106 | } 107 | 108 | public IEnumerable DeepChildren 109 | { 110 | get { 111 | foreach (var C in Children) 112 | foreach (var D in C.DeepChildren) 113 | yield return D; 114 | } 115 | } 116 | 117 | public override string ToString () 118 | { 119 | return "JSONNode"; 120 | } 121 | 122 | public virtual string ToString (string aPrefix) 123 | { 124 | return "JSONNode"; 125 | } 126 | 127 | public abstract string ToJSON (int prefix); 128 | 129 | #endregion common interface 130 | 131 | #region typecasting properties 132 | 133 | public virtual JSONBinaryTag Tag { get; set; } 134 | 135 | public virtual int AsInt 136 | { 137 | get { 138 | int v = 0; 139 | if (int.TryParse (Value, out v)) 140 | return v; 141 | return 0; 142 | } 143 | set { 144 | Value = value.ToString (); 145 | Tag = JSONBinaryTag.IntValue; 146 | } 147 | } 148 | 149 | public virtual float AsFloat 150 | { 151 | get { 152 | float v = 0.0f; 153 | if (float.TryParse (Value, out v)) 154 | return v; 155 | return 0.0f; 156 | } 157 | set { 158 | Value = value.ToString (); 159 | Tag = JSONBinaryTag.FloatValue; 160 | } 161 | } 162 | 163 | public virtual double AsDouble 164 | { 165 | get { 166 | double v = 0.0; 167 | if (double.TryParse (Value, out v)) 168 | return v; 169 | return 0.0; 170 | } 171 | set { 172 | Value = value.ToString (); 173 | Tag = JSONBinaryTag.DoubleValue; 174 | 175 | } 176 | } 177 | 178 | public virtual bool AsBool 179 | { 180 | get { 181 | bool v = false; 182 | if (bool.TryParse (Value, out v)) 183 | return v; 184 | return !string.IsNullOrEmpty (Value); 185 | } 186 | set { 187 | Value = (value) ? "true" : "false"; 188 | Tag = JSONBinaryTag.BoolValue; 189 | 190 | } 191 | } 192 | 193 | public virtual JSONArray AsArray 194 | { 195 | get { 196 | return this as JSONArray; 197 | } 198 | } 199 | 200 | public virtual JSONClass AsObject 201 | { 202 | get { 203 | return this as JSONClass; 204 | } 205 | } 206 | 207 | 208 | #endregion typecasting properties 209 | 210 | #region operators 211 | 212 | public static implicit operator JSONNode (string s) 213 | { 214 | return new JSONData (s); 215 | } 216 | 217 | public static implicit operator string (JSONNode d) 218 | { 219 | return (d == null) ? null : d.Value; 220 | } 221 | 222 | public static bool operator == (JSONNode a, object b) 223 | { 224 | if (b == null && a is JSONLazyCreator) 225 | return true; 226 | return System.Object.ReferenceEquals (a, b); 227 | } 228 | 229 | public static bool operator != (JSONNode a, object b) 230 | { 231 | return !(a == b); 232 | } 233 | 234 | public override bool Equals (object obj) 235 | { 236 | return System.Object.ReferenceEquals (this, obj); 237 | } 238 | 239 | public override int GetHashCode () 240 | { 241 | return base.GetHashCode (); 242 | } 243 | 244 | 245 | #endregion operators 246 | 247 | internal static string Escape (string aText) 248 | { 249 | string result = ""; 250 | foreach (char c in aText) { 251 | switch (c) { 252 | case '\\': 253 | result += "\\\\"; 254 | break; 255 | case '\"': 256 | result += "\\\""; 257 | break; 258 | case '\n': 259 | result += "\\n"; 260 | break; 261 | case '\r': 262 | result += "\\r"; 263 | break; 264 | case '\t': 265 | result += "\\t"; 266 | break; 267 | case '\b': 268 | result += "\\b"; 269 | break; 270 | case '\f': 271 | result += "\\f"; 272 | break; 273 | default : 274 | result += c; 275 | break; 276 | } 277 | } 278 | return result; 279 | } 280 | 281 | static JSONData Numberize (string token) 282 | { 283 | bool flag = false; 284 | int integer = 0; 285 | double real = 0; 286 | 287 | if (int.TryParse (token, out integer)) { 288 | return new JSONData (integer); 289 | } 290 | 291 | if (double.TryParse (token, out real)) { 292 | return new JSONData (real); 293 | } 294 | 295 | if (bool.TryParse (token, out flag)) { 296 | return new JSONData (flag); 297 | } 298 | 299 | throw new NotImplementedException (token); 300 | } 301 | 302 | static void AddElement (JSONNode ctx, string token, string tokenName, bool tokenIsString) 303 | { 304 | if (tokenIsString) { 305 | if (ctx is JSONArray) 306 | ctx.Add (token); 307 | else 308 | ctx.Add (tokenName, token); // assume dictionary/object 309 | } else { 310 | JSONData number = Numberize (token); 311 | if (ctx is JSONArray) 312 | ctx.Add (number); 313 | else 314 | ctx.Add (tokenName, number); 315 | 316 | } 317 | } 318 | 319 | public static JSONNode Parse (string aJSON) 320 | { 321 | Stack stack = new Stack (); 322 | JSONNode ctx = null; 323 | int i = 0; 324 | string Token = ""; 325 | string TokenName = ""; 326 | bool QuoteMode = false; 327 | bool TokenIsString = false; 328 | while (i < aJSON.Length) { 329 | switch (aJSON [i]) { 330 | case '{': 331 | if (QuoteMode) { 332 | Token += aJSON [i]; 333 | break; 334 | } 335 | stack.Push (new JSONClass ()); 336 | if (ctx != null) { 337 | TokenName = TokenName.Trim (); 338 | if (ctx is JSONArray) 339 | ctx.Add (stack.Peek ()); 340 | else if (TokenName != "") 341 | ctx.Add (TokenName, stack.Peek ()); 342 | } 343 | TokenName = ""; 344 | Token = ""; 345 | ctx = stack.Peek (); 346 | break; 347 | 348 | case '[': 349 | if (QuoteMode) { 350 | Token += aJSON [i]; 351 | break; 352 | } 353 | 354 | stack.Push (new JSONArray ()); 355 | if (ctx != null) { 356 | TokenName = TokenName.Trim (); 357 | 358 | if (ctx is JSONArray) 359 | ctx.Add (stack.Peek ()); 360 | else if (TokenName != "") 361 | ctx.Add (TokenName, stack.Peek ()); 362 | } 363 | TokenName = ""; 364 | Token = ""; 365 | ctx = stack.Peek (); 366 | break; 367 | 368 | case '}': 369 | case ']': 370 | if (QuoteMode) { 371 | Token += aJSON [i]; 372 | break; 373 | } 374 | if (stack.Count == 0) 375 | throw new Exception ("JSON Parse: Too many closing brackets"); 376 | 377 | stack.Pop (); 378 | if (Token != "") { 379 | TokenName = TokenName.Trim (); 380 | /* 381 | if (ctx is JSONArray) 382 | ctx.Add (Token); 383 | else if (TokenName != "") 384 | ctx.Add (TokenName, Token); 385 | */ 386 | AddElement (ctx, Token, TokenName, TokenIsString); 387 | TokenIsString = false; 388 | } 389 | TokenName = ""; 390 | Token = ""; 391 | if (stack.Count > 0) 392 | ctx = stack.Peek (); 393 | break; 394 | 395 | case ':': 396 | if (QuoteMode) { 397 | Token += aJSON [i]; 398 | break; 399 | } 400 | TokenName = Token; 401 | Token = ""; 402 | TokenIsString = false; 403 | break; 404 | 405 | case '"': 406 | QuoteMode ^= true; 407 | TokenIsString = QuoteMode == true ? true : TokenIsString; 408 | break; 409 | 410 | case ',': 411 | if (QuoteMode) { 412 | Token += aJSON [i]; 413 | break; 414 | } 415 | if (Token != "") { 416 | /* 417 | if (ctx is JSONArray) { 418 | ctx.Add (Token); 419 | } else if (TokenName != "") { 420 | ctx.Add (TokenName, Token); 421 | } 422 | */ 423 | AddElement (ctx, Token, TokenName, TokenIsString); 424 | TokenIsString = false; 425 | 426 | } 427 | TokenName = ""; 428 | Token = ""; 429 | TokenIsString = false; 430 | break; 431 | 432 | case '\r': 433 | case '\n': 434 | break; 435 | 436 | case ' ': 437 | case '\t': 438 | if (QuoteMode) 439 | Token += aJSON [i]; 440 | break; 441 | 442 | case '\\': 443 | ++i; 444 | if (QuoteMode) { 445 | char C = aJSON [i]; 446 | switch (C) { 447 | case 't': 448 | Token += '\t'; 449 | break; 450 | case 'r': 451 | Token += '\r'; 452 | break; 453 | case 'n': 454 | Token += '\n'; 455 | break; 456 | case 'b': 457 | Token += '\b'; 458 | break; 459 | case 'f': 460 | Token += '\f'; 461 | break; 462 | case 'u': 463 | { 464 | string s = aJSON.Substring (i + 1, 4); 465 | Token += (char)int.Parse ( 466 | s, 467 | System.Globalization.NumberStyles.AllowHexSpecifier); 468 | i += 4; 469 | break; 470 | } 471 | default : 472 | Token += C; 473 | break; 474 | } 475 | } 476 | break; 477 | 478 | default: 479 | Token += aJSON [i]; 480 | break; 481 | } 482 | ++i; 483 | } 484 | if (QuoteMode) { 485 | throw new Exception ("JSON Parse: Quotation marks seems to be messed up."); 486 | } 487 | return ctx; 488 | } 489 | 490 | public virtual void Serialize (System.IO.BinaryWriter aWriter) 491 | { 492 | } 493 | 494 | public void SaveToStream (System.IO.Stream aData) 495 | { 496 | var W = new System.IO.BinaryWriter (aData); 497 | Serialize (W); 498 | } 499 | 500 | #if USE_SharpZipLib 501 | public void SaveToCompressedStream(System.IO.Stream aData) 502 | { 503 | using (var gzipOut = new ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream(aData)) 504 | { 505 | gzipOut.IsStreamOwner = false; 506 | SaveToStream(gzipOut); 507 | gzipOut.Close(); 508 | } 509 | } 510 | 511 | public void SaveToCompressedFile(string aFileName) 512 | { 513 | 514 | #if USE_FileIO 515 | System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName); 516 | using(var F = System.IO.File.OpenWrite(aFileName)) 517 | { 518 | SaveToCompressedStream(F); 519 | } 520 | 521 | #else 522 | throw new Exception("Can't use File IO stuff in webplayer"); 523 | #endif 524 | } 525 | public string SaveToCompressedBase64() 526 | { 527 | using (var stream = new System.IO.MemoryStream()) 528 | { 529 | SaveToCompressedStream(stream); 530 | stream.Position = 0; 531 | return System.Convert.ToBase64String(stream.ToArray()); 532 | } 533 | } 534 | 535 | #else 536 | public void SaveToCompressedStream (System.IO.Stream aData) 537 | { 538 | throw new Exception ("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); 539 | } 540 | 541 | public void SaveToCompressedFile (string aFileName) 542 | { 543 | throw new Exception ("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); 544 | } 545 | 546 | public string SaveToCompressedBase64 () 547 | { 548 | throw new Exception ("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); 549 | } 550 | #endif 551 | 552 | public void SaveToFile (string aFileName) 553 | { 554 | #if USE_FileIO 555 | System.IO.Directory.CreateDirectory ((new System.IO.FileInfo (aFileName)).Directory.FullName); 556 | using (var F = System.IO.File.OpenWrite (aFileName)) { 557 | SaveToStream (F); 558 | } 559 | #else 560 | throw new Exception ("Can't use File IO stuff in webplayer"); 561 | #endif 562 | } 563 | 564 | public string SaveToBase64 () 565 | { 566 | using (var stream = new System.IO.MemoryStream ()) { 567 | SaveToStream (stream); 568 | stream.Position = 0; 569 | return System.Convert.ToBase64String (stream.ToArray ()); 570 | } 571 | } 572 | 573 | public static JSONNode Deserialize (System.IO.BinaryReader aReader) 574 | { 575 | JSONBinaryTag type = (JSONBinaryTag)aReader.ReadByte (); 576 | switch (type) { 577 | case JSONBinaryTag.Array: 578 | { 579 | int count = aReader.ReadInt32 (); 580 | JSONArray tmp = new JSONArray (); 581 | for (int i = 0; i < count; i++) 582 | tmp.Add (Deserialize (aReader)); 583 | return tmp; 584 | } 585 | case JSONBinaryTag.Class: 586 | { 587 | int count = aReader.ReadInt32 (); 588 | JSONClass tmp = new JSONClass (); 589 | for (int i = 0; i < count; i++) { 590 | string key = aReader.ReadString (); 591 | var val = Deserialize (aReader); 592 | tmp.Add (key, val); 593 | } 594 | return tmp; 595 | } 596 | case JSONBinaryTag.Value: 597 | { 598 | return new JSONData (aReader.ReadString ()); 599 | } 600 | case JSONBinaryTag.IntValue: 601 | { 602 | return new JSONData (aReader.ReadInt32 ()); 603 | } 604 | case JSONBinaryTag.DoubleValue: 605 | { 606 | return new JSONData (aReader.ReadDouble ()); 607 | } 608 | case JSONBinaryTag.BoolValue: 609 | { 610 | return new JSONData (aReader.ReadBoolean ()); 611 | } 612 | case JSONBinaryTag.FloatValue: 613 | { 614 | return new JSONData (aReader.ReadSingle ()); 615 | } 616 | 617 | default: 618 | { 619 | throw new Exception ("Error deserializing JSON. Unknown tag: " + type); 620 | } 621 | } 622 | } 623 | 624 | #if USE_SharpZipLib 625 | public static JSONNode LoadFromCompressedStream(System.IO.Stream aData) 626 | { 627 | var zin = new ICSharpCode.SharpZipLib.BZip2.BZip2InputStream(aData); 628 | return LoadFromStream(zin); 629 | } 630 | public static JSONNode LoadFromCompressedFile(string aFileName) 631 | { 632 | #if USE_FileIO 633 | using(var F = System.IO.File.OpenRead(aFileName)) 634 | { 635 | return LoadFromCompressedStream(F); 636 | } 637 | #else 638 | throw new Exception("Can't use File IO stuff in webplayer"); 639 | #endif 640 | } 641 | public static JSONNode LoadFromCompressedBase64(string aBase64) 642 | { 643 | var tmp = System.Convert.FromBase64String(aBase64); 644 | var stream = new System.IO.MemoryStream(tmp); 645 | stream.Position = 0; 646 | return LoadFromCompressedStream(stream); 647 | } 648 | #else 649 | public static JSONNode LoadFromCompressedFile (string aFileName) 650 | { 651 | throw new Exception ("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); 652 | } 653 | 654 | public static JSONNode LoadFromCompressedStream (System.IO.Stream aData) 655 | { 656 | throw new Exception ("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); 657 | } 658 | 659 | public static JSONNode LoadFromCompressedBase64 (string aBase64) 660 | { 661 | throw new Exception ("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); 662 | } 663 | #endif 664 | 665 | public static JSONNode LoadFromStream (System.IO.Stream aData) 666 | { 667 | using (var R = new System.IO.BinaryReader (aData)) { 668 | return Deserialize (R); 669 | } 670 | } 671 | 672 | public static JSONNode LoadFromFile (string aFileName) 673 | { 674 | #if USE_FileIO 675 | using (var F = System.IO.File.OpenRead (aFileName)) { 676 | return LoadFromStream (F); 677 | } 678 | #else 679 | throw new Exception ("Can't use File IO stuff in webplayer"); 680 | #endif 681 | } 682 | 683 | public static JSONNode LoadFromBase64 (string aBase64) 684 | { 685 | var tmp = System.Convert.FromBase64String (aBase64); 686 | var stream = new System.IO.MemoryStream (tmp); 687 | stream.Position = 0; 688 | return LoadFromStream (stream); 689 | } 690 | } 691 | // End of JSONNode 692 | 693 | public class JSONArray : JSONNode, IEnumerable 694 | { 695 | private List m_List = new List (); 696 | 697 | public override JSONNode this [int aIndex] 698 | { 699 | get { 700 | if (aIndex < 0 || aIndex >= m_List.Count) 701 | return new JSONLazyCreator (this); 702 | return m_List [aIndex]; 703 | } 704 | set { 705 | if (aIndex < 0 || aIndex >= m_List.Count) 706 | m_List.Add (value); 707 | else 708 | m_List [aIndex] = value; 709 | } 710 | } 711 | 712 | public override JSONNode this [string aKey] 713 | { 714 | get{ return new JSONLazyCreator (this); } 715 | set{ m_List.Add (value); } 716 | } 717 | 718 | public override int Count 719 | { 720 | get { return m_List.Count; } 721 | } 722 | 723 | public override void Add (string aKey, JSONNode aItem) 724 | { 725 | m_List.Add (aItem); 726 | } 727 | 728 | public override JSONNode Remove (int aIndex) 729 | { 730 | if (aIndex < 0 || aIndex >= m_List.Count) 731 | return null; 732 | JSONNode tmp = m_List [aIndex]; 733 | m_List.RemoveAt (aIndex); 734 | return tmp; 735 | } 736 | 737 | public override JSONNode Remove (JSONNode aNode) 738 | { 739 | m_List.Remove (aNode); 740 | return aNode; 741 | } 742 | 743 | public override IEnumerable Children 744 | { 745 | get { 746 | foreach (JSONNode N in m_List) 747 | yield return N; 748 | } 749 | } 750 | 751 | public IEnumerator GetEnumerator () 752 | { 753 | foreach (JSONNode N in m_List) 754 | yield return N; 755 | } 756 | 757 | public override string ToString () 758 | { 759 | string result = "[ "; 760 | foreach (JSONNode N in m_List) { 761 | if (result.Length > 2) 762 | result += ", "; 763 | result += N.ToString (); 764 | } 765 | result += " ]"; 766 | return result; 767 | } 768 | 769 | public override string ToString (string aPrefix) 770 | { 771 | string result = "[ "; 772 | foreach (JSONNode N in m_List) { 773 | if (result.Length > 3) 774 | result += ", "; 775 | result += "\n" + aPrefix + " "; 776 | result += N.ToString (aPrefix + " "); 777 | } 778 | result += "\n" + aPrefix + "]"; 779 | return result; 780 | } 781 | 782 | public override string ToJSON (int prefix) 783 | { 784 | string s = new string (' ', (prefix + 1) * 2); 785 | string ret = "[ "; 786 | foreach (JSONNode n in m_List) { 787 | if (ret.Length > 3) 788 | ret += ", "; 789 | ret += "\n" + s; 790 | ret += n.ToJSON (prefix + 1); 791 | 792 | } 793 | ret += "\n" + s + "]"; 794 | return ret; 795 | } 796 | 797 | public override void Serialize (System.IO.BinaryWriter aWriter) 798 | { 799 | aWriter.Write ((byte)JSONBinaryTag.Array); 800 | aWriter.Write (m_List.Count); 801 | for (int i = 0; i < m_List.Count; i++) { 802 | m_List [i].Serialize (aWriter); 803 | } 804 | } 805 | } 806 | // End of JSONArray 807 | 808 | public class JSONClass : JSONNode, IEnumerable 809 | { 810 | private Dictionary m_Dict = new Dictionary (); 811 | 812 | public Dictionary Dict { 813 | get { 814 | return m_Dict; 815 | } 816 | } 817 | 818 | public override JSONNode this [string aKey] 819 | { 820 | get { 821 | if (m_Dict.ContainsKey (aKey)) 822 | return m_Dict [aKey]; 823 | else 824 | return new JSONLazyCreator (this, aKey); 825 | } 826 | set { 827 | if (m_Dict.ContainsKey (aKey)) 828 | m_Dict [aKey] = value; 829 | else 830 | m_Dict.Add (aKey, value); 831 | } 832 | } 833 | 834 | public override JSONNode this [int aIndex] 835 | { 836 | get { 837 | if (aIndex < 0 || aIndex >= m_Dict.Count) 838 | return null; 839 | return m_Dict.ElementAt (aIndex).Value; 840 | } 841 | set { 842 | if (aIndex < 0 || aIndex >= m_Dict.Count) 843 | return; 844 | string key = m_Dict.ElementAt (aIndex).Key; 845 | m_Dict [key] = value; 846 | } 847 | } 848 | 849 | public override int Count 850 | { 851 | get { return m_Dict.Count; } 852 | } 853 | 854 | 855 | public override void Add (string aKey, JSONNode aItem) 856 | { 857 | if (!string.IsNullOrEmpty (aKey)) { 858 | if (m_Dict.ContainsKey (aKey)) 859 | m_Dict [aKey] = aItem; 860 | else 861 | m_Dict.Add (aKey, aItem); 862 | } else 863 | m_Dict.Add (Guid.NewGuid ().ToString (), aItem); 864 | } 865 | 866 | public override JSONNode Remove (string aKey) 867 | { 868 | if (!m_Dict.ContainsKey (aKey)) 869 | return null; 870 | JSONNode tmp = m_Dict [aKey]; 871 | m_Dict.Remove (aKey); 872 | return tmp; 873 | } 874 | 875 | public override JSONNode Remove (int aIndex) 876 | { 877 | if (aIndex < 0 || aIndex >= m_Dict.Count) 878 | return null; 879 | var item = m_Dict.ElementAt (aIndex); 880 | m_Dict.Remove (item.Key); 881 | return item.Value; 882 | } 883 | 884 | public override JSONNode Remove (JSONNode aNode) 885 | { 886 | try { 887 | var item = m_Dict.Where (k => k.Value == aNode).First (); 888 | m_Dict.Remove (item.Key); 889 | return aNode; 890 | } catch { 891 | return null; 892 | } 893 | } 894 | 895 | public override IEnumerable Children 896 | { 897 | get { 898 | foreach (KeyValuePair N in m_Dict) 899 | yield return N.Value; 900 | } 901 | } 902 | 903 | public IEnumerator GetEnumerator () 904 | { 905 | foreach (KeyValuePair N in m_Dict) 906 | yield return N; 907 | } 908 | 909 | public override string ToString () 910 | { 911 | string result = "{"; 912 | foreach (KeyValuePair N in m_Dict) { 913 | if (result.Length > 2) 914 | result += ", "; 915 | result += "\"" + Escape (N.Key) + "\":" + N.Value.ToString (); 916 | } 917 | result += "}"; 918 | return result; 919 | } 920 | 921 | public override string ToString (string aPrefix) 922 | { 923 | string result = "{ "; 924 | foreach (KeyValuePair N in m_Dict) { 925 | if (result.Length > 3) 926 | result += ", "; 927 | result += "\n" + aPrefix + " "; 928 | result += "\"" + Escape (N.Key) + "\" : " + N.Value.ToString (aPrefix + " "); 929 | } 930 | result += "\n" + aPrefix + "}"; 931 | return result; 932 | } 933 | 934 | public override string ToJSON (int prefix) 935 | { 936 | string s = new string (' ', (prefix + 1) * 2); 937 | string ret = "{ "; 938 | foreach (KeyValuePair n in m_Dict) { 939 | if (ret.Length > 3) 940 | ret += ", "; 941 | ret += "\n" + s; 942 | ret += string.Format ("\"{0}\": {1}", n.Key, n.Value.ToJSON (prefix + 1)); 943 | } 944 | ret += "\n" + s + "}"; 945 | return ret; 946 | } 947 | 948 | public override void Serialize (System.IO.BinaryWriter aWriter) 949 | { 950 | aWriter.Write ((byte)JSONBinaryTag.Class); 951 | aWriter.Write (m_Dict.Count); 952 | foreach (string K in m_Dict.Keys) { 953 | aWriter.Write (K); 954 | m_Dict [K].Serialize (aWriter); 955 | } 956 | } 957 | } 958 | // End of JSONClass 959 | 960 | public class JSONData : JSONNode 961 | { 962 | private string m_Data; 963 | 964 | 965 | public override string Value 966 | { 967 | get { return m_Data; } 968 | set { 969 | m_Data = value; 970 | Tag = JSONBinaryTag.Value; 971 | } 972 | } 973 | 974 | public JSONData (string aData) 975 | { 976 | m_Data = aData; 977 | Tag = JSONBinaryTag.Value; 978 | } 979 | 980 | public JSONData (float aData) 981 | { 982 | AsFloat = aData; 983 | Tag = JSONBinaryTag.FloatValue; 984 | } 985 | 986 | public JSONData (double aData) 987 | { 988 | AsDouble = aData; 989 | Tag = JSONBinaryTag.DoubleValue; 990 | } 991 | 992 | public JSONData (bool aData) 993 | { 994 | AsBool = aData; 995 | Tag = JSONBinaryTag.BoolValue; 996 | } 997 | 998 | public JSONData (int aData) 999 | { 1000 | AsInt = aData; 1001 | Tag = JSONBinaryTag.IntValue; 1002 | } 1003 | 1004 | public override string ToString () 1005 | { 1006 | return "\"" + Escape (m_Data) + "\""; 1007 | } 1008 | 1009 | public override string ToString (string aPrefix) 1010 | { 1011 | return "\"" + Escape (m_Data) + "\""; 1012 | } 1013 | 1014 | public override string ToJSON (int prefix) 1015 | { 1016 | switch (Tag) { 1017 | case JSONBinaryTag.DoubleValue: 1018 | case JSONBinaryTag.FloatValue: 1019 | case JSONBinaryTag.IntValue: 1020 | case JSONBinaryTag.BoolValue: 1021 | return m_Data; 1022 | case JSONBinaryTag.Value: 1023 | return string.Format ("\"{0}\"", Escape (m_Data)); 1024 | default: 1025 | throw new NotSupportedException ("This shouldn't be here: " + Tag.ToString ()); 1026 | } 1027 | } 1028 | 1029 | public override void Serialize (System.IO.BinaryWriter aWriter) 1030 | { 1031 | var tmp = new JSONData (""); 1032 | 1033 | tmp.AsInt = AsInt; 1034 | if (tmp.m_Data == this.m_Data) { 1035 | aWriter.Write ((byte)JSONBinaryTag.IntValue); 1036 | aWriter.Write (AsInt); 1037 | return; 1038 | } 1039 | tmp.AsFloat = AsFloat; 1040 | if (tmp.m_Data == this.m_Data) { 1041 | aWriter.Write ((byte)JSONBinaryTag.FloatValue); 1042 | aWriter.Write (AsFloat); 1043 | return; 1044 | } 1045 | tmp.AsDouble = AsDouble; 1046 | if (tmp.m_Data == this.m_Data) { 1047 | aWriter.Write ((byte)JSONBinaryTag.DoubleValue); 1048 | aWriter.Write (AsDouble); 1049 | return; 1050 | } 1051 | 1052 | tmp.AsBool = AsBool; 1053 | if (tmp.m_Data == this.m_Data) { 1054 | aWriter.Write ((byte)JSONBinaryTag.BoolValue); 1055 | aWriter.Write (AsBool); 1056 | return; 1057 | } 1058 | aWriter.Write ((byte)JSONBinaryTag.Value); 1059 | aWriter.Write (m_Data); 1060 | } 1061 | } 1062 | // End of JSONData 1063 | 1064 | internal class JSONLazyCreator : JSONNode 1065 | { 1066 | private JSONNode m_Node = null; 1067 | private string m_Key = null; 1068 | 1069 | public JSONLazyCreator (JSONNode aNode) 1070 | { 1071 | m_Node = aNode; 1072 | m_Key = null; 1073 | } 1074 | 1075 | public JSONLazyCreator (JSONNode aNode, string aKey) 1076 | { 1077 | m_Node = aNode; 1078 | m_Key = aKey; 1079 | } 1080 | 1081 | private void Set (JSONNode aVal) 1082 | { 1083 | if (m_Key == null) { 1084 | m_Node.Add (aVal); 1085 | } else { 1086 | m_Node.Add (m_Key, aVal); 1087 | } 1088 | m_Node = null; // Be GC friendly. 1089 | } 1090 | 1091 | public override JSONNode this [int aIndex] 1092 | { 1093 | get { 1094 | return new JSONLazyCreator (this); 1095 | } 1096 | set { 1097 | var tmp = new JSONArray (); 1098 | tmp.Add (value); 1099 | Set (tmp); 1100 | } 1101 | } 1102 | 1103 | public override JSONNode this [string aKey] 1104 | { 1105 | get { 1106 | return new JSONLazyCreator (this, aKey); 1107 | } 1108 | set { 1109 | var tmp = new JSONClass (); 1110 | tmp.Add (aKey, value); 1111 | Set (tmp); 1112 | } 1113 | } 1114 | 1115 | public override void Add (JSONNode aItem) 1116 | { 1117 | var tmp = new JSONArray (); 1118 | tmp.Add (aItem); 1119 | Set (tmp); 1120 | } 1121 | 1122 | public override void Add (string aKey, JSONNode aItem) 1123 | { 1124 | var tmp = new JSONClass (); 1125 | tmp.Add (aKey, aItem); 1126 | Set (tmp); 1127 | } 1128 | 1129 | public static bool operator == (JSONLazyCreator a, object b) 1130 | { 1131 | if (b == null) 1132 | return true; 1133 | return System.Object.ReferenceEquals (a, b); 1134 | } 1135 | 1136 | public static bool operator != (JSONLazyCreator a, object b) 1137 | { 1138 | return !(a == b); 1139 | } 1140 | 1141 | public override bool Equals (object obj) 1142 | { 1143 | if (obj == null) 1144 | return true; 1145 | return System.Object.ReferenceEquals (this, obj); 1146 | } 1147 | 1148 | public override int GetHashCode () 1149 | { 1150 | return base.GetHashCode (); 1151 | } 1152 | 1153 | public override string ToString () 1154 | { 1155 | return ""; 1156 | } 1157 | 1158 | public override string ToString (string aPrefix) 1159 | { 1160 | return ""; 1161 | } 1162 | 1163 | public override string ToJSON (int prefix) 1164 | { 1165 | return ""; 1166 | } 1167 | 1168 | public override int AsInt 1169 | { 1170 | get { 1171 | JSONData tmp = new JSONData (0); 1172 | Set (tmp); 1173 | return 0; 1174 | } 1175 | set { 1176 | JSONData tmp = new JSONData (value); 1177 | Set (tmp); 1178 | } 1179 | } 1180 | 1181 | public override float AsFloat 1182 | { 1183 | get { 1184 | JSONData tmp = new JSONData (0.0f); 1185 | Set (tmp); 1186 | return 0.0f; 1187 | } 1188 | set { 1189 | JSONData tmp = new JSONData (value); 1190 | Set (tmp); 1191 | } 1192 | } 1193 | 1194 | public override double AsDouble 1195 | { 1196 | get { 1197 | JSONData tmp = new JSONData (0.0); 1198 | Set (tmp); 1199 | return 0.0; 1200 | } 1201 | set { 1202 | JSONData tmp = new JSONData (value); 1203 | Set (tmp); 1204 | } 1205 | } 1206 | 1207 | public override bool AsBool 1208 | { 1209 | get { 1210 | JSONData tmp = new JSONData (false); 1211 | Set (tmp); 1212 | return false; 1213 | } 1214 | set { 1215 | JSONData tmp = new JSONData (value); 1216 | Set (tmp); 1217 | } 1218 | } 1219 | 1220 | public override JSONArray AsArray 1221 | { 1222 | get { 1223 | JSONArray tmp = new JSONArray (); 1224 | Set (tmp); 1225 | return tmp; 1226 | } 1227 | } 1228 | 1229 | public override JSONClass AsObject 1230 | { 1231 | get { 1232 | JSONClass tmp = new JSONClass (); 1233 | Set (tmp); 1234 | return tmp; 1235 | } 1236 | } 1237 | } 1238 | // End of JSONLazyCreator 1239 | 1240 | public static class JSON 1241 | { 1242 | public static JSONNode Parse (string aJSON) 1243 | { 1244 | return JSONNode.Parse (aJSON); 1245 | } 1246 | } 1247 | } -------------------------------------------------------------------------------- /SceneToGlTFWiz.cs: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | GlamExport 3 | - Unity3D Scriptable Wizard to export Hierarchy or Project objects as glTF 4 | 5 | 6 | ****************************************************************************/ 7 | 8 | using UnityEngine; 9 | using UnityEditor; 10 | using System; 11 | using System.Collections; 12 | using System.Collections.Generic; 13 | using System.IO; 14 | using System.Xml; 15 | using System.Text; 16 | using System.Reflection; 17 | 18 | 19 | public class SceneToGlTFWiz : EditorWindow 20 | { 21 | // static public List Accessors; 22 | // static public List BufferViews; 23 | static public GlTF_Writer writer; 24 | 25 | const string KEY_PATH = "GlTFPath"; 26 | const string KEY_FILE = "GlTFFile"; 27 | 28 | static public string path = "?"; 29 | static XmlDocument xdoc; 30 | static string savedPath; 31 | static string savedFile; 32 | 33 | static Preset preset = new Preset(); 34 | public static UnityEngine.TextAsset presetAsset; 35 | 36 | public interface RTCCallback 37 | { 38 | double[] GetCenter(Transform transform); 39 | } 40 | public interface RotationCallback 41 | { 42 | Matrix4x4 GetBoundsRotationMatrix(Transform transform); 43 | Matrix4x4 GetNodeRotationMatrix(Transform transform); 44 | } 45 | public static MonoScript rtcScript; 46 | public static MonoScript rotScript; 47 | public static bool unpackTexture = false; 48 | public static bool copyShaders = false; 49 | 50 | [MenuItem ("File/Export/glTF")] 51 | static void CreateWizard() 52 | { 53 | savedPath = EditorPrefs.GetString (KEY_PATH, "/"); 54 | savedFile = EditorPrefs.GetString (KEY_FILE, "test.gltf"); 55 | path = savedPath + "/"+ savedFile; 56 | // ScriptableWizard.DisplayWizard("Export Selected Stuff to glTF", typeof(SceneToGlTFWiz), "Export"); 57 | 58 | SceneToGlTFWiz window = (SceneToGlTFWiz)EditorWindow.GetWindow (typeof (SceneToGlTFWiz)); 59 | window.Show(); 60 | } 61 | 62 | void OnEnable() 63 | { 64 | savedPath = EditorPrefs.GetString (KEY_PATH, "/"); 65 | savedFile = EditorPrefs.GetString (KEY_FILE, "test.gltf"); 66 | } 67 | 68 | void OnWizardUpdate () 69 | { 70 | // Texture[] txs = Selection.GetFiltered(Texture, SelectionMode.Assets); 71 | // Debug.Log("found "+txs.Length); 72 | } 73 | 74 | void OnWizardCreate() // Create (Export) button has been hit (NOT wizard has been created!) 75 | { 76 | /* 77 | Object[] deps = EditorUtility.CollectDependencies (trs); 78 | foreach (Object o in deps) 79 | { 80 | Debug.Log("obj "+o.name+" "+o.GetType()); 81 | } 82 | */ 83 | var ext = GlTF_Writer.binary ? (GlTF_Writer.b3dm ? "b3dm" : "glb") : "gltf"; 84 | path = EditorUtility.SaveFilePanel("Save glTF file as", savedPath, savedFile, ext); 85 | if (path.Length != 0) 86 | { 87 | Transform[] trs = Selection.GetTransforms (SelectionMode.Deep); 88 | 89 | Transform root = null; 90 | // find root, the one with no parent 91 | for (var i = 0; i < trs.Length; ++i) 92 | { 93 | if (trs[i].parent == null) 94 | { 95 | root = trs[i]; 96 | break; 97 | } 98 | } 99 | 100 | Export(path, trs, root); 101 | } 102 | } 103 | 104 | void OnGUI () 105 | { 106 | GUILayout.Label("Export Options"); 107 | GlTF_Writer.binary = GUILayout.Toggle(GlTF_Writer.binary, "Binary GlTF"); 108 | if (GlTF_Writer.binary) 109 | { 110 | GlTF_Writer.b3dm = GUILayout.Toggle(GlTF_Writer.b3dm, "B3dm"); 111 | } 112 | else 113 | { 114 | GlTF_Writer.b3dm = false; 115 | } 116 | 117 | copyShaders = GUILayout.Toggle(copyShaders, "Copy shaders"); 118 | 119 | presetAsset = EditorGUILayout.ObjectField("Preset file", presetAsset, typeof(UnityEngine.TextAsset), false) as UnityEngine.TextAsset; 120 | rtcScript = EditorGUILayout.ObjectField("Cesium RTC Callback", rtcScript, typeof(MonoScript), false) as MonoScript; 121 | rotScript = EditorGUILayout.ObjectField("Rotation Callback", rotScript, typeof(MonoScript), false) as MonoScript; 122 | 123 | if (rtcScript != null) 124 | { 125 | var name = typeof(RTCCallback).FullName; 126 | var ci = rtcScript.GetClass().GetInterface(name); 127 | if (ci == null) 128 | { 129 | rtcScript = null; 130 | } 131 | } 132 | 133 | if (rotScript != null) 134 | { 135 | var name = typeof(RotationCallback).FullName; 136 | var ci = rotScript.GetClass().GetInterface(name); 137 | if (ci == null) 138 | { 139 | rotScript = null; 140 | } 141 | } 142 | 143 | if (GUILayout.Button("Export")) 144 | { 145 | OnWizardCreate(); 146 | } 147 | } 148 | 149 | public static BoundsDouble Export(string path, Transform[] trs, Transform root) 150 | { 151 | double minHeight = 0, maxHeight = 0; 152 | return Export(path, trs, root, out minHeight, out maxHeight); 153 | } 154 | 155 | public static BoundsDouble Export(string path, Transform[] trs, Transform root, out double minHeight, out double maxHeight) 156 | { 157 | minHeight = 0; 158 | maxHeight = 0; 159 | 160 | writer = new GlTF_Writer(); 161 | writer.Init (); 162 | 163 | if (presetAsset != null) 164 | { 165 | string psPath = AssetDatabase.GetAssetPath(presetAsset); 166 | if (psPath != null) 167 | { 168 | psPath = psPath.Remove(0, "Assets".Length); 169 | psPath = Application.dataPath + psPath; 170 | preset.Load(psPath); 171 | } 172 | } 173 | 174 | savedPath = Path.GetDirectoryName(path); 175 | savedFile = Path.GetFileNameWithoutExtension(path); 176 | 177 | EditorPrefs.SetString(KEY_PATH, savedPath); 178 | EditorPrefs.SetString(KEY_FILE, savedFile); 179 | 180 | Debug.Log ("attempting to save to "+path); 181 | writer.OpenFiles (path); 182 | 183 | if (rtcScript != null && root != null) 184 | { 185 | var instance = Activator.CreateInstance(rtcScript.GetClass()); 186 | var rtc = instance as RTCCallback; 187 | if (rtc != null) 188 | { 189 | writer.RTCCenter = rtc.GetCenter(root); 190 | } 191 | } 192 | 193 | RotationCallback rotCallback = null;; 194 | if (rotScript != null) 195 | { 196 | var instance = Activator.CreateInstance(rotScript.GetClass()); 197 | rotCallback = instance as RotationCallback; 198 | } 199 | 200 | if (unpackTexture) { 201 | // prepass, for texture unpacker 202 | TextureUnpacker.Reset(); 203 | foreach (Transform tr in trs) 204 | { 205 | TextureUnpacker.CheckPackedTexture(tr, preset); 206 | } 207 | TextureUnpacker.Build(); 208 | } 209 | 210 | BoundsDouble bb = new BoundsDouble(); 211 | 212 | List skins = new List(); 213 | // first, collect objects in the scene, add to lists 214 | foreach (Transform tr in trs) 215 | { 216 | if (tr.GetComponent() != null) 217 | { 218 | if (tr.GetComponent().orthographic) 219 | { 220 | GlTF_Orthographic cam; 221 | cam = new GlTF_Orthographic(); 222 | cam.type = "orthographic"; 223 | cam.zfar = tr.GetComponent().farClipPlane; 224 | cam.znear = tr.GetComponent().nearClipPlane; 225 | cam.name = tr.name; 226 | //cam.orthographic.xmag = tr.camera. 227 | GlTF_Writer.cameras.Add(cam); 228 | } 229 | else 230 | { 231 | GlTF_Perspective cam; 232 | cam = new GlTF_Perspective(); 233 | cam.type = "perspective"; 234 | cam.zfar = tr.GetComponent().farClipPlane; 235 | cam.znear = tr.GetComponent().nearClipPlane; 236 | cam.aspect_ratio = tr.GetComponent().aspect; 237 | cam.yfov = tr.GetComponent().fieldOfView; 238 | cam.name = tr.name; 239 | GlTF_Writer.cameras.Add(cam); 240 | } 241 | } 242 | 243 | if (tr.GetComponent() != null) 244 | { 245 | switch (tr.GetComponent().type) 246 | { 247 | case LightType.Point: 248 | GlTF_PointLight pl = new GlTF_PointLight(); 249 | pl.color = new GlTF_ColorRGB (tr.GetComponent().color); 250 | pl.name = tr.name; 251 | GlTF_Writer.lights.Add (pl); 252 | break; 253 | 254 | case LightType.Spot: 255 | GlTF_SpotLight sl = new GlTF_SpotLight(); 256 | sl.color = new GlTF_ColorRGB (tr.GetComponent().color); 257 | sl.name = tr.name; 258 | GlTF_Writer.lights.Add (sl); 259 | break; 260 | 261 | case LightType.Directional: 262 | GlTF_DirectionalLight dl = new GlTF_DirectionalLight(); 263 | dl.color = new GlTF_ColorRGB (tr.GetComponent().color); 264 | dl.name = tr.name; 265 | GlTF_Writer.lights.Add (dl); 266 | break; 267 | 268 | case LightType.Area: 269 | GlTF_AmbientLight al = new GlTF_AmbientLight(); 270 | al.color = new GlTF_ColorRGB (tr.GetComponent().color); 271 | al.name = tr.name; 272 | GlTF_Writer.lights.Add (al); 273 | break; 274 | } 275 | } 276 | 277 | Mesh m = GetMesh(tr); 278 | if (m != null) 279 | { 280 | GlTF_Mesh mesh = new GlTF_Mesh(); 281 | mesh.name = GlTF_Mesh.GetNameFromObject(m); 282 | 283 | GlTF_Accessor positionAccessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "position"), GlTF_Accessor.Type.VEC3, GlTF_Accessor.ComponentType.FLOAT); 284 | positionAccessor.bufferView = GlTF_Writer.vec3BufferView; 285 | GlTF_Writer.accessors.Add (positionAccessor); 286 | 287 | GlTF_Accessor normalAccessor = null; 288 | if (m.normals.Length > 0) 289 | { 290 | normalAccessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "normal"), GlTF_Accessor.Type.VEC3, GlTF_Accessor.ComponentType.FLOAT); 291 | normalAccessor.bufferView = GlTF_Writer.vec3BufferView; 292 | GlTF_Writer.accessors.Add (normalAccessor); 293 | } 294 | 295 | GlTF_Accessor uv0Accessor = null; 296 | if (m.uv.Length > 0) { 297 | uv0Accessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "uv0"), GlTF_Accessor.Type.VEC2, GlTF_Accessor.ComponentType.FLOAT); 298 | uv0Accessor.bufferView = GlTF_Writer.vec2BufferView; 299 | GlTF_Writer.accessors.Add (uv0Accessor); 300 | } 301 | 302 | GlTF_Accessor uv1Accessor = null; 303 | if (m.uv2.Length > 0) { 304 | uv1Accessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "uv1"), GlTF_Accessor.Type.VEC2, GlTF_Accessor.ComponentType.FLOAT); 305 | uv1Accessor.bufferView = GlTF_Writer.vec2BufferView; 306 | GlTF_Writer.accessors.Add (uv1Accessor); 307 | } 308 | 309 | GlTF_Accessor uv2Accessor = null; 310 | if (m.uv3.Length > 0) { 311 | uv2Accessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "uv2"), GlTF_Accessor.Type.VEC2, GlTF_Accessor.ComponentType.FLOAT); 312 | uv2Accessor.bufferView = GlTF_Writer.vec2BufferView; 313 | GlTF_Writer.accessors.Add (uv2Accessor); 314 | } 315 | 316 | GlTF_Accessor uv3Accessor = null; 317 | if (m.uv4.Length > 0) { 318 | uv3Accessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "uv3"), GlTF_Accessor.Type.VEC2, GlTF_Accessor.ComponentType.FLOAT); 319 | uv3Accessor.bufferView = GlTF_Writer.vec2BufferView; 320 | GlTF_Writer.accessors.Add (uv3Accessor); 321 | } 322 | 323 | GlTF_Accessor boneIndexAccessor = null; 324 | GlTF_Accessor boneWeightAccessor = null; 325 | if (m.boneWeights.Length > 0) { 326 | boneIndexAccessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "joint"), GlTF_Accessor.Type.VEC4, GlTF_Accessor.ComponentType.FLOAT); 327 | boneIndexAccessor.bufferView = GlTF_Writer.vec4BufferView; 328 | GlTF_Writer.accessors.Add (boneIndexAccessor); 329 | boneWeightAccessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "weight"), GlTF_Accessor.Type.VEC4, GlTF_Accessor.ComponentType.FLOAT); 330 | boneWeightAccessor.bufferView = GlTF_Writer.vec4BufferView; 331 | GlTF_Writer.accessors.Add (boneWeightAccessor); 332 | } 333 | 334 | var smCount = m.subMeshCount; 335 | for (var i = 0; i < smCount; ++i) 336 | { 337 | GlTF_Primitive primitive = new GlTF_Primitive(); 338 | primitive.name = GlTF_Primitive.GetNameFromObject(m, i); 339 | primitive.index = i; 340 | GlTF_Attributes attributes = new GlTF_Attributes(); 341 | attributes.positionAccessor = positionAccessor; 342 | attributes.normalAccessor = normalAccessor; 343 | attributes.texCoord0Accessor = uv0Accessor; 344 | attributes.texCoord1Accessor = uv1Accessor; 345 | attributes.texCoord2Accessor = uv2Accessor; 346 | attributes.texCoord3Accessor = uv3Accessor; 347 | attributes.boneIndexAccessor = boneIndexAccessor; 348 | attributes.boneWeightAccessor = boneWeightAccessor; 349 | primitive.attributes = attributes; 350 | GlTF_Accessor indexAccessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "indices_" + i), GlTF_Accessor.Type.SCALAR, GlTF_Accessor.ComponentType.USHORT); 351 | indexAccessor.bufferView = GlTF_Writer.ushortBufferView; 352 | GlTF_Writer.accessors.Add (indexAccessor); 353 | primitive.indices = indexAccessor; 354 | 355 | var mr = GetRenderer(tr); 356 | var sm = mr.sharedMaterials; 357 | if (i < sm.Length && sm[i] != null) { 358 | var mat = sm[i]; 359 | var matName = GlTF_Material.GetNameFromObject(mat); 360 | primitive.materialName = matName; 361 | if (!GlTF_Writer.materials.ContainsKey (matName)) 362 | { 363 | GlTF_Material material = new GlTF_Material(); 364 | material.name = matName; 365 | GlTF_Writer.materials.Add (material.name, material); 366 | 367 | //technique 368 | var s = mat.shader; 369 | var techName = GlTF_Technique.GetNameFromObject(s); 370 | material.instanceTechniqueName = techName; 371 | bool anim = boneIndexAccessor != null && boneWeightAccessor != null && m.bindposes.Length > 0; 372 | if (!GlTF_Writer.techniques.ContainsKey(techName)) 373 | { 374 | GlTF_Technique tech = new GlTF_Technique(); 375 | tech.name = techName; 376 | 377 | GlTF_Technique.States ts = null; 378 | if (preset.techniqueStates.ContainsKey(s.name)) 379 | { 380 | ts = preset.techniqueStates[s.name]; 381 | } 382 | else if (preset.techniqueStates.ContainsKey("*")) 383 | { 384 | ts = preset.techniqueStates["*"]; 385 | } 386 | 387 | tech.states = ts; 388 | 389 | GlTF_Technique.Parameter tParam = new GlTF_Technique.Parameter(); 390 | tParam.name = "position"; 391 | tParam.type = GlTF_Technique.Type.FLOAT_VEC3; 392 | tParam.semantic = GlTF_Technique.Semantic.POSITION; 393 | tech.parameters.Add(tParam); 394 | GlTF_Technique.Attribute tAttr = new GlTF_Technique.Attribute(); 395 | tAttr.name = "a_position"; 396 | tAttr.param = tParam.name; 397 | tech.attributes.Add(tAttr); 398 | 399 | if (normalAccessor != null) 400 | { 401 | tParam = new GlTF_Technique.Parameter(); 402 | tParam.name = "normal"; 403 | tParam.type = GlTF_Technique.Type.FLOAT_VEC3; 404 | tParam.semantic = GlTF_Technique.Semantic.NORMAL; 405 | tech.parameters.Add(tParam); 406 | tAttr = new GlTF_Technique.Attribute(); 407 | tAttr.name = "a_normal"; 408 | tAttr.param = tParam.name; 409 | tech.attributes.Add(tAttr); 410 | } 411 | 412 | if (uv0Accessor != null) 413 | { 414 | tParam = new GlTF_Technique.Parameter(); 415 | tParam.name = "texcoord0"; 416 | tParam.type = GlTF_Technique.Type.FLOAT_VEC2; 417 | tParam.semantic = GlTF_Technique.Semantic.TEXCOORD_0; 418 | tech.parameters.Add(tParam); 419 | tAttr = new GlTF_Technique.Attribute(); 420 | tAttr.name = "a_texcoord0"; 421 | tAttr.param = tParam.name; 422 | tech.attributes.Add(tAttr); 423 | } 424 | 425 | if (uv1Accessor != null) 426 | { 427 | tParam = new GlTF_Technique.Parameter(); 428 | tParam.name = "texcoord1"; 429 | tParam.type = GlTF_Technique.Type.FLOAT_VEC2; 430 | tParam.semantic = GlTF_Technique.Semantic.TEXCOORD_1; 431 | tech.parameters.Add(tParam); 432 | tAttr = new GlTF_Technique.Attribute(); 433 | tAttr.name = "a_texcoord1"; 434 | tAttr.param = tParam.name; 435 | tech.attributes.Add(tAttr); 436 | } 437 | 438 | if (uv2Accessor != null) 439 | { 440 | tParam = new GlTF_Technique.Parameter(); 441 | tParam.name = "texcoord2"; 442 | tParam.type = GlTF_Technique.Type.FLOAT_VEC2; 443 | tParam.semantic = GlTF_Technique.Semantic.TEXCOORD_2; 444 | tech.parameters.Add(tParam); 445 | tAttr = new GlTF_Technique.Attribute(); 446 | tAttr.name = "a_texcoord2"; 447 | tAttr.param = tParam.name; 448 | tech.attributes.Add(tAttr); 449 | } 450 | 451 | if (uv3Accessor != null) 452 | { 453 | tParam = new GlTF_Technique.Parameter(); 454 | tParam.name = "texcoord3"; 455 | tParam.type = GlTF_Technique.Type.FLOAT_VEC2; 456 | tParam.semantic = GlTF_Technique.Semantic.TEXCOORD_3; 457 | tech.parameters.Add(tParam); 458 | tAttr = new GlTF_Technique.Attribute(); 459 | tAttr.name = "a_texcoord3"; 460 | tAttr.param = tParam.name; 461 | tech.attributes.Add(tAttr); 462 | } 463 | 464 | if (boneIndexAccessor != null) 465 | { 466 | tParam = new GlTF_Technique.Parameter(); 467 | tParam.name = "joint"; 468 | tParam.type = GlTF_Technique.Type.FLOAT_VEC4; 469 | tParam.semantic = GlTF_Technique.Semantic.JOINT; 470 | tech.parameters.Add(tParam); 471 | tAttr = new GlTF_Technique.Attribute(); 472 | tAttr.name = "a_joint"; 473 | tAttr.param = tParam.name; 474 | tech.attributes.Add(tAttr); 475 | } 476 | 477 | if (boneWeightAccessor != null) 478 | { 479 | tParam = new GlTF_Technique.Parameter(); 480 | tParam.name = "weight"; 481 | tParam.type = GlTF_Technique.Type.FLOAT_VEC4; 482 | tParam.semantic = GlTF_Technique.Semantic.WEIGHT; 483 | tech.parameters.Add(tParam); 484 | tAttr = new GlTF_Technique.Attribute(); 485 | tAttr.name = "a_weight"; 486 | tAttr.param = tParam.name; 487 | tech.attributes.Add(tAttr); 488 | } 489 | 490 | tech.AddDefaultUniforms(writer.RTCCenter != null); 491 | 492 | GlTF_Writer.techniques.Add (techName, tech); 493 | 494 | GlTF_Technique.Uniform tUni; 495 | if (m.bindposes.Length > 0) 496 | { 497 | tParam = new GlTF_Technique.Parameter(); 498 | tParam.name = "jointMat"; 499 | tParam.type = GlTF_Technique.Type.FLOAT_MAT4; 500 | tParam.semantic = GlTF_Technique.Semantic.JOINTMATRIX; 501 | tParam.count = m.bindposes.Length; 502 | tech.parameters.Add(tParam); 503 | tUni = new GlTF_Technique.Uniform(); 504 | tUni.name = "u_jointMat"; 505 | tUni.param = tParam.name; 506 | tech.uniforms.Add(tUni); 507 | } 508 | 509 | int spCount = ShaderUtil.GetPropertyCount(s); 510 | for (var j = 0; j < spCount; ++j) 511 | { 512 | var pName = ShaderUtil.GetPropertyName(s, j); 513 | var pType = ShaderUtil.GetPropertyType(s, j); 514 | // Debug.Log(pName + " " + pType); 515 | 516 | if (pType == ShaderUtil.ShaderPropertyType.Color) 517 | { 518 | tParam = new GlTF_Technique.Parameter(); 519 | tParam.name = pName; 520 | tParam.type = GlTF_Technique.Type.FLOAT_VEC4; 521 | tech.parameters.Add(tParam); 522 | tUni = new GlTF_Technique.Uniform(); 523 | tUni.name = pName; 524 | tUni.param = tParam.name; 525 | tech.uniforms.Add(tUni); 526 | } 527 | else if (pType == ShaderUtil.ShaderPropertyType.Vector) 528 | { 529 | tParam = new GlTF_Technique.Parameter(); 530 | tParam.name = pName; 531 | tParam.type = GlTF_Technique.Type.FLOAT_VEC4; 532 | tech.parameters.Add(tParam); 533 | tUni = new GlTF_Technique.Uniform(); 534 | tUni.name = pName; 535 | tUni.param = tParam.name; 536 | tech.uniforms.Add(tUni); 537 | } 538 | else if (pType == ShaderUtil.ShaderPropertyType.Float || 539 | pType == ShaderUtil.ShaderPropertyType.Range) 540 | { 541 | tParam = new GlTF_Technique.Parameter(); 542 | tParam.name = pName; 543 | tParam.type = GlTF_Technique.Type.FLOAT; 544 | tech.parameters.Add(tParam); 545 | tUni = new GlTF_Technique.Uniform(); 546 | tUni.name = pName; 547 | tUni.param = tParam.name; 548 | tech.uniforms.Add(tUni); 549 | } 550 | else if (pType == ShaderUtil.ShaderPropertyType.TexEnv) 551 | { 552 | var td = ShaderUtil.GetTexDim(s, j); 553 | if (td == UnityEngine.Rendering.TextureDimension.Tex2D) 554 | { 555 | tParam = new GlTF_Technique.Parameter(); 556 | tParam.name = pName; 557 | tParam.type = GlTF_Technique.Type.SAMPLER_2D; 558 | tech.parameters.Add(tParam); 559 | tUni = new GlTF_Technique.Uniform(); 560 | tUni.name = pName; 561 | tUni.param = tParam.name; 562 | tech.uniforms.Add(tUni); 563 | } 564 | } 565 | 566 | } 567 | 568 | // create program 569 | GlTF_Program program = new GlTF_Program(); 570 | program.name = GlTF_Program.GetNameFromObject(s); 571 | tech.program = program.name; 572 | foreach (var attr in tech.attributes) 573 | { 574 | program.attributes.Add(attr.name); 575 | } 576 | GlTF_Writer.programs.Add(program); 577 | 578 | // shader 579 | GlTF_Shader vs = new GlTF_Shader(); 580 | vs.name = GlTF_Shader.GetNameFromObject(s, GlTF_Shader.Type.Vertex); 581 | program.vertexShader = vs.name; 582 | vs.type = GlTF_Shader.Type.Vertex; 583 | vs.uri = preset.GetVertexShader(s.name, anim); 584 | GlTF_Writer.shaders.Add(vs); 585 | 586 | GlTF_Shader fs = new GlTF_Shader(); 587 | fs.name = GlTF_Shader.GetNameFromObject(s, GlTF_Shader.Type.Fragment); 588 | program.fragmentShader = fs.name; 589 | fs.type = GlTF_Shader.Type.Fragment; 590 | fs.uri = preset.GetFragmentShader(s.name); 591 | GlTF_Writer.shaders.Add(fs); 592 | } 593 | else 594 | { 595 | if (anim) 596 | { 597 | // check if previous technique creation contains anim 598 | var tech = GlTF_Writer.techniques[techName]; 599 | bool jointFound = false; 600 | bool weightFound = false; 601 | bool jointMatFound = false; 602 | foreach (var param in tech.parameters) 603 | { 604 | if (param.name == "joint") 605 | { 606 | jointFound = true; 607 | } 608 | else if (param.name == "weight") 609 | { 610 | weightFound = true; 611 | } 612 | else if (param.name == "jointMat") 613 | { 614 | jointMatFound = true; 615 | } 616 | } 617 | 618 | var prog = GlTF_Writer.programs.Find(p => p.name == tech.program); 619 | Action injectAttr = (tAttr) => { 620 | if (prog != null && prog.attributes.Find(attr => attr == tAttr.name) == null) 621 | { 622 | prog.attributes.Add(tAttr.name); 623 | } 624 | }; 625 | 626 | if (!jointFound) 627 | { 628 | var tParam = new GlTF_Technique.Parameter(); 629 | tParam.name = "joint"; 630 | tParam.type = GlTF_Technique.Type.FLOAT_VEC4; 631 | tParam.semantic = GlTF_Technique.Semantic.JOINT; 632 | tech.parameters.Add(tParam); 633 | var tAttr = new GlTF_Technique.Attribute(); 634 | tAttr.name = "a_joint"; 635 | tAttr.param = tParam.name; 636 | tech.attributes.Add(tAttr); 637 | 638 | injectAttr(tAttr); 639 | } 640 | 641 | if (!weightFound) 642 | { 643 | var tParam = new GlTF_Technique.Parameter(); 644 | tParam.name = "weight"; 645 | tParam.type = GlTF_Technique.Type.FLOAT_VEC4; 646 | tParam.semantic = GlTF_Technique.Semantic.WEIGHT; 647 | tech.parameters.Add(tParam); 648 | var tAttr = new GlTF_Technique.Attribute(); 649 | tAttr.name = "a_weight"; 650 | tAttr.param = tParam.name; 651 | tech.attributes.Add(tAttr); 652 | 653 | injectAttr(tAttr); 654 | } 655 | 656 | if (!jointMatFound) 657 | { 658 | var tParam = new GlTF_Technique.Parameter(); 659 | tParam.name = "jointMat"; 660 | tParam.type = GlTF_Technique.Type.FLOAT_MAT4; 661 | tParam.semantic = GlTF_Technique.Semantic.JOINTMATRIX; 662 | tParam.count = m.bindposes.Length; 663 | tech.parameters.Add(tParam); 664 | var tUni = new GlTF_Technique.Uniform(); 665 | tUni.name = "u_jointMat"; 666 | tUni.param = tParam.name; 667 | tech.uniforms.Add(tUni); 668 | } 669 | 670 | //check shader type 671 | var vs = GlTF_Writer.shaders.Find(sh => sh.name == prog.vertexShader); 672 | if (vs != null) 673 | { 674 | vs.uri = preset.GetVertexShader(s.name, anim); 675 | } 676 | } 677 | } 678 | 679 | int spCount2 = ShaderUtil.GetPropertyCount(s); 680 | for (var j = 0; j < spCount2; ++j) 681 | { 682 | var pName = ShaderUtil.GetPropertyName(s, j); 683 | var pType = ShaderUtil.GetPropertyType(s, j); 684 | 685 | if (pType == ShaderUtil.ShaderPropertyType.Color) 686 | { 687 | var matCol = new GlTF_Material.ColorValue(); 688 | matCol.name = pName; 689 | matCol.color = mat.GetColor(pName); 690 | material.values.Add(matCol); 691 | } 692 | else if (pType == ShaderUtil.ShaderPropertyType.Vector) 693 | { 694 | var matVec = new GlTF_Material.VectorValue(); 695 | matVec.name = pName; 696 | matVec.vector = mat.GetVector(pName); 697 | material.values.Add(matVec); 698 | } 699 | else if (pType == ShaderUtil.ShaderPropertyType.Float || 700 | pType == ShaderUtil.ShaderPropertyType.Range) 701 | { 702 | var matFloat = new GlTF_Material.FloatValue(); 703 | matFloat.name = pName; 704 | matFloat.value = mat.GetFloat(pName); 705 | material.values.Add(matFloat); 706 | } 707 | else if (pType == ShaderUtil.ShaderPropertyType.TexEnv) 708 | { 709 | var td = ShaderUtil.GetTexDim(s, j); 710 | if (td == UnityEngine.Rendering.TextureDimension.Tex2D) 711 | { 712 | var t = mat.GetTexture(pName); 713 | var val = new GlTF_Material.StringValue(); 714 | val.name = pName; 715 | string texName = null; 716 | if (t != null) { 717 | texName = GlTF_Texture.GetNameFromObject(t); 718 | val.value = texName; 719 | } else { 720 | val.value = ""; 721 | } 722 | 723 | material.values.Add(val); 724 | 725 | if (t != null) 726 | { 727 | if (!GlTF_Writer.textures.ContainsKey (texName)) 728 | { 729 | var texPath = ExportTexture(t, savedPath); 730 | GlTF_Image img = new GlTF_Image(); 731 | img.name = GlTF_Image.GetNameFromObject(t); 732 | img.uri = texPath; 733 | GlTF_Writer.images.Add(img); 734 | 735 | GlTF_Sampler sampler; 736 | var samplerName = GlTF_Sampler.GetNameFromObject(t); 737 | if (GlTF_Writer.samplers.ContainsKey(samplerName)) 738 | { 739 | sampler = GlTF_Writer.samplers[samplerName]; 740 | } 741 | else 742 | { 743 | sampler = new GlTF_Sampler(t); 744 | sampler.name = samplerName; 745 | GlTF_Writer.samplers[samplerName] = sampler; 746 | } 747 | 748 | GlTF_Texture texture = new GlTF_Texture (); 749 | texture.name = texName; 750 | texture.source = img.name; 751 | texture.samplerName = samplerName; 752 | 753 | GlTF_Writer.textures.Add (texName, texture); 754 | } 755 | } 756 | } 757 | } 758 | } 759 | } 760 | } 761 | 762 | mesh.primitives.Add (primitive); 763 | } 764 | 765 | mesh.Populate (m); 766 | GlTF_Writer.meshes.Add (mesh); 767 | if (unpackTexture) { 768 | TextureUnpacker.ProcessMesh(mesh); 769 | } 770 | 771 | // calculate bounding box transform 772 | if (root != null) 773 | { 774 | Matrix4x4 brot = Matrix4x4.identity; 775 | if (rotCallback != null) 776 | { 777 | brot = rotCallback.GetBoundsRotationMatrix(root); 778 | } 779 | 780 | var pos = tr.position - root.position; // relative to parent 781 | var objMat = Matrix4x4.TRS(pos, tr.rotation, tr.lossyScale); 782 | 783 | //read vertices 784 | var ms = positionAccessor.bufferView.memoryStream; 785 | var offset = (int)positionAccessor.byteOffset; 786 | var len = positionAccessor.count; 787 | var buffer = new byte[len * 12]; 788 | var mspos = ms.Position; 789 | ms.Position = offset; 790 | ms.Read(buffer, 0, buffer.Length); 791 | 792 | minHeight = double.MaxValue; 793 | maxHeight = double.MinValue; 794 | 795 | double[] c = writer.RTCCenter; 796 | 797 | double[] minPos = new double[3]; 798 | minPos[0] = double.MaxValue; 799 | minPos[1] = double.MaxValue; 800 | minPos[2] = double.MaxValue; 801 | 802 | double[] maxPos = new double[3]; 803 | maxPos[0] = double.MinValue; 804 | maxPos[1] = double.MinValue; 805 | maxPos[2] = double.MinValue; 806 | 807 | for (int j = 0; j < len; ++j) 808 | { 809 | var x = System.BitConverter.ToSingle(buffer, j * 12); 810 | var y = System.BitConverter.ToSingle(buffer, j * 12 + 4); 811 | var z = System.BitConverter.ToSingle(buffer, j * 12 + 8); 812 | 813 | // local rotation 814 | var lx = objMat.m00 * x + objMat.m01 * y + objMat.m02 * z; 815 | var ly = objMat.m10 * x + objMat.m11 * y + objMat.m12 * z; 816 | var lz = objMat.m20 * x + objMat.m21 * y + objMat.m22 * z; 817 | 818 | minHeight = Math.Min(minHeight, ly); 819 | maxHeight = Math.Max(maxHeight, ly); 820 | 821 | // to world 822 | double wx = brot.m00 * lx + brot.m01 * ly + brot.m02 * lz; 823 | double wy = brot.m10 * lx + brot.m11 * ly + brot.m12 * lz; 824 | double wz = brot.m20 * lx + brot.m21 * ly + brot.m22 * lz; 825 | 826 | // local translation to world 827 | double tx = brot.m00 * pos.x + brot.m01 * pos.y + brot.m02 * pos.z; 828 | double ty = brot.m10 * pos.x + brot.m11 * pos.y + brot.m12 * pos.z; 829 | double tz = brot.m20 * pos.x + brot.m21 * pos.y + brot.m22 * pos.z; 830 | 831 | wx += tx; 832 | wy += ty; 833 | wz += tz; 834 | 835 | if (c != null) 836 | { 837 | wx += c[0]; 838 | wy += c[1]; 839 | wz += c[2]; 840 | } 841 | 842 | minPos[0] = Math.Min(minPos[0], wx); 843 | minPos[1] = Math.Min(minPos[1], wy); 844 | minPos[2] = Math.Min(minPos[2], wz); 845 | 846 | maxPos[0] = Math.Max(maxPos[0], wx); 847 | maxPos[1] = Math.Max(maxPos[1], wy); 848 | maxPos[2] = Math.Max(maxPos[2], wz); 849 | } 850 | 851 | ms.Position = mspos; 852 | 853 | BoundsDouble tbb = new BoundsDouble(); 854 | tbb.Encapsulate(new BoundsDouble(minPos, maxPos)); 855 | bb.Encapsulate(tbb); 856 | } 857 | } 858 | 859 | Animation a = tr.GetComponent(); 860 | 861 | // Animator a = tr.GetComponent(); 862 | if (a != null) 863 | { 864 | AnimationClip[] clips = AnimationUtility.GetAnimationClips(tr.gameObject); 865 | int nClips = clips.Length; 866 | // int nClips = a.GetClipCount(); 867 | for (int i = 0; i < nClips; i++) 868 | { 869 | GlTF_Animation anim = new GlTF_Animation(); 870 | anim.Populate (clips[i], tr); 871 | GlTF_Writer.animations.Add (anim); 872 | } 873 | } 874 | 875 | // next, build hierarchy of nodes 876 | GlTF_Node node = new GlTF_Node(); 877 | 878 | var smr = tr.GetComponent(); 879 | if (smr != null) 880 | { 881 | List skeletons = new List(); 882 | var skin = new GlTF_Skin(); 883 | skin.Populate(smr, skeletons); 884 | GlTF_Writer.skins.Add(skin); 885 | node.skinName = skin.name; 886 | skins.Add(skin); 887 | 888 | foreach (var st in skeletons) { 889 | node.skeletonNames.Add(GlTF_Node.GetNameFromObject(st)); 890 | } 891 | } 892 | 893 | Matrix4x4 rotMat = Matrix4x4.identity; 894 | if (root != null && rotCallback != null) 895 | { 896 | rotMat = rotCallback.GetNodeRotationMatrix(root); 897 | } 898 | 899 | if (tr == root) 900 | { 901 | Matrix4x4 mat = Matrix4x4.identity; 902 | mat.m22 = -1; // flip z axis 903 | 904 | if (rotMat != Matrix4x4.identity) 905 | { 906 | mat = rotMat; 907 | } 908 | 909 | // do not use global position if rtc is defined 910 | Vector3 pos = Vector3.zero; 911 | // if (writer.RTCCenter == null) 912 | // { 913 | // pos = tr.localPosition; 914 | // } 915 | 916 | mat = mat * Matrix4x4.TRS(pos, tr.localRotation, tr.localScale); 917 | node.matrix = new GlTF_Matrix(mat); 918 | } 919 | else 920 | { 921 | node.hasParent = true; 922 | // do not set if has animation, will be modified by skin transforms 923 | if (smr == null) 924 | { 925 | if (tr.localPosition != Vector3.zero) 926 | node.translation = new GlTF_Translation (tr.localPosition); 927 | if (tr.localScale != Vector3.one) 928 | node.scale = new GlTF_Scale (tr.localScale); 929 | if (tr.localRotation != Quaternion.identity) 930 | node.rotation = new GlTF_Rotation (tr.localRotation); 931 | } 932 | } 933 | 934 | node.name = GlTF_Node.GetNameFromObject(tr); 935 | if (tr.GetComponent() != null) 936 | { 937 | node.cameraName = tr.name; 938 | } 939 | else if (tr.GetComponent() != null) 940 | node.lightName = tr.name; 941 | else if (m != null) 942 | { 943 | node.meshNames.Add (GlTF_Mesh.GetNameFromObject(m)); 944 | } 945 | 946 | foreach (Transform t in tr.transform) { 947 | var found = false; 948 | foreach (var check in trs) { 949 | if (t == check) { 950 | found = true; 951 | break; 952 | } 953 | } 954 | if (found) 955 | { 956 | node.childrenNames.Add (GlTF_Node.GetNameFromObject(t)); 957 | } 958 | } 959 | 960 | GlTF_Writer.nodes.Add (node); 961 | } 962 | 963 | // set joint name property on skinned node 964 | if (skins.Count > 0) { 965 | foreach (var skin in skins) { 966 | foreach (var boneName in skin.boneNames) { 967 | foreach (var node in GlTF_Writer.nodes) { 968 | if (node.name == boneName) { 969 | node.jointName = boneName; 970 | } 971 | } 972 | } 973 | } 974 | } 975 | 976 | if (copyShaders && preset.shaderDir != null) { 977 | var sd = Path.Combine(Application.dataPath, preset.shaderDir); 978 | foreach (var shader in GlTF_Writer.shaders) { 979 | var srcPath = Path.Combine(sd, shader.uri); 980 | if (File.Exists(srcPath)) { 981 | var dstPath = Path.Combine(savedPath, shader.uri); 982 | File.Copy(srcPath, dstPath, true); 983 | } 984 | } 985 | } 986 | 987 | // third, add meshes etc to byte stream, keeping track of buffer offsets 988 | writer.Write (); 989 | writer.CloseFiles(); 990 | return bb; 991 | } 992 | 993 | static string toGlTFname(string name) 994 | { 995 | // remove spaces and illegal chars, replace with underscores 996 | string correctString = name.Replace(" ", "_"); 997 | // make sure it doesn't start with a number 998 | return correctString; 999 | } 1000 | 1001 | static bool isInheritedFrom (Type t, Type baseT) 1002 | { 1003 | if (t == baseT) 1004 | return true; 1005 | t = t.BaseType; 1006 | while (t != null && t != typeof(System.Object)) 1007 | { 1008 | if (t == baseT) 1009 | return true; 1010 | t = t.BaseType; 1011 | } 1012 | return false; 1013 | } 1014 | 1015 | static Renderer GetRenderer(Transform tr) 1016 | { 1017 | Renderer mr = tr.GetComponent(); 1018 | if (mr == null) { 1019 | mr = tr.GetComponent(); 1020 | } 1021 | return mr; 1022 | } 1023 | 1024 | static Mesh GetMesh(Transform tr) 1025 | { 1026 | var mr = GetRenderer(tr); 1027 | Mesh m = null; 1028 | if (mr != null) 1029 | { 1030 | var t = mr.GetType(); 1031 | if (t == typeof(MeshRenderer)) 1032 | { 1033 | MeshFilter mf = tr.GetComponent(); 1034 | m = mf.sharedMesh; 1035 | } else if (t == typeof(SkinnedMeshRenderer)) 1036 | { 1037 | SkinnedMeshRenderer smr = mr as SkinnedMeshRenderer; 1038 | m = smr.sharedMesh; 1039 | } 1040 | } 1041 | return m; 1042 | } 1043 | 1044 | static string ExportTexture(Texture texture, string path) 1045 | { 1046 | var assetPath = AssetDatabase.GetAssetPath(texture); 1047 | var fn = Path.GetFileName(assetPath); 1048 | var t = texture as Texture2D; 1049 | var name = GlTF_Texture.GetNameFromObject(t); 1050 | if (t != null) 1051 | { 1052 | var ext = Path.GetExtension(assetPath); 1053 | if (ext == ".dds") 1054 | { 1055 | var ct = Type.GetType("Imaging.DDSReader.DDS"); 1056 | if (ct != null) 1057 | { 1058 | var srcPath = GetAssetFullPath(assetPath); 1059 | // var srcTex = Imaging.DDSReader.DDS.LoadImage(srcPath, true); 1060 | Texture2D srcTex = ct.GetMethod("LoadImage", new Type[] {typeof(string), typeof(bool)}).Invoke(null, new object[]{srcPath, true}) as Texture2D; 1061 | fn = Path.GetFileNameWithoutExtension(assetPath) + ".png"; 1062 | var dstPath = Path.Combine(path, fn); 1063 | 1064 | Texture2D curTex = null; 1065 | if (unpackTexture) { 1066 | curTex = TextureUnpacker.ProcessTexture(name, srcTex); 1067 | } else { 1068 | curTex = srcTex; 1069 | } 1070 | 1071 | 1072 | var b = curTex.EncodeToPNG(); 1073 | File.WriteAllBytes(dstPath, b); 1074 | if (curTex != srcTex) { 1075 | Texture2D.DestroyImmediate(curTex); 1076 | } 1077 | Texture2D.DestroyImmediate(srcTex); 1078 | } 1079 | else 1080 | { 1081 | fn = Path.GetFileNameWithoutExtension(assetPath) + ".png"; 1082 | var dstPath = Path.Combine(path, fn); 1083 | Texture2D t2 = new Texture2D(t.width, t.height, TextureFormat.RGBA32, false); 1084 | t2.SetPixels(t.GetPixels()); 1085 | t2.Apply(); 1086 | 1087 | Texture2D curTex = null; 1088 | if (unpackTexture) { 1089 | curTex = TextureUnpacker.ProcessTexture(name, t2); 1090 | } else { 1091 | curTex = t2; 1092 | } 1093 | 1094 | var b = curTex.EncodeToPNG(); 1095 | File.WriteAllBytes(dstPath, b); 1096 | if (curTex != t2) { 1097 | Texture2D.DestroyImmediate(curTex); 1098 | } 1099 | Texture2D.DestroyImmediate(t2); 1100 | } 1101 | } 1102 | else 1103 | { 1104 | var dstPath = Path.Combine(path, fn); 1105 | if (unpackTexture) { 1106 | // load src texture from path to prevent access error 1107 | var read = File.ReadAllBytes(assetPath); 1108 | Texture2D copyTex = new Texture2D(t.width, t.height, TextureFormat.RGBA32, false); 1109 | copyTex.LoadImage(read); 1110 | copyTex.Apply(); 1111 | 1112 | // size could be different from import settings 1113 | if (t.width != copyTex.width || t.height != copyTex.height) { 1114 | TextureScale.Bilinear(copyTex, t.width, t.height); 1115 | } 1116 | 1117 | Texture2D curTex = TextureUnpacker.ProcessTexture(name, copyTex); 1118 | 1119 | byte[] b = null; 1120 | if (ext == ".jpg") 1121 | { 1122 | b = curTex.EncodeToJPG(); 1123 | } 1124 | else if (ext == ".png") 1125 | { 1126 | b = curTex.EncodeToPNG(); 1127 | } 1128 | 1129 | if (b != null) 1130 | { 1131 | File.WriteAllBytes(dstPath, b); 1132 | } 1133 | else 1134 | { 1135 | Debug.LogError("Unsupported file format for: " + fn); 1136 | } 1137 | 1138 | if (curTex != copyTex) { 1139 | Texture2D.DestroyImmediate(curTex); 1140 | } 1141 | Texture2D.DestroyImmediate(copyTex); 1142 | } else { 1143 | File.Copy(assetPath, dstPath, true); 1144 | } 1145 | } 1146 | } 1147 | return fn; 1148 | } 1149 | 1150 | static string GetAssetFullPath(string path) 1151 | { 1152 | if (path != null) 1153 | { 1154 | path = path.Remove(0, "Assets".Length); 1155 | path = Application.dataPath + path; 1156 | } 1157 | return path; 1158 | } 1159 | } 1160 | --------------------------------------------------------------------------------