Export glTF 2
authorjamesgk <jamesgk19@gmail.com>
Wed, 26 Jul 2017 00:26:18 +0000 (17:26 -0700)
committerjamesgk <jamesgk19@gmail.com>
Wed, 26 Jul 2017 01:05:18 +0000 (18:05 -0700)
code/glTF2Asset.h
code/glTF2Asset.inl
code/glTF2AssetWriter.inl
code/glTF2Exporter.cpp

index 3331c11..36caba2 100644 (file)
@@ -177,7 +177,7 @@ namespace glTF2
     struct GLB_Header
     {
         uint8_t magic[4];     //!< Magic number: "glTF"
-        uint32_t version;     //!< Version number (always 1 as of the last update)
+        uint32_t version;     //!< Version number
         uint32_t length;      //!< Total length of the Binary glTF, including header, scene, and body, in bytes
         uint32_t sceneLength; //!< Length, in bytes, of the glTF scene
         uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum)
@@ -381,6 +381,7 @@ namespace glTF2
     //! Base classe for all glTF top-level objects
     struct Object
     {
+        int index;        //!< The index of this object within its property container
         std::string id;   //!< The globally unique ID used to reference this object
         std::string name; //!< The user-defined name of this object
 
@@ -952,10 +953,10 @@ namespace glTF2
         };
 
         struct AnimChannel {
-            std::string sampler;         //!< The ID of one sampler present in the containing animation's samplers property.
+            int sampler;                 //!< The index of a sampler in the containing animation's samplers property.
 
             struct AnimTarget {
-                Ref<Node> id;            //!< The ID of the node to animate.
+                Ref<Node> node;          //!< The node to animate.
                 std::string path;        //!< The name of property of the node to animate ("translation", "rotation", or "scale").
             } target;
         };
@@ -977,6 +978,20 @@ namespace glTF2
 
         Animation() {}
         void Read(Value& obj, Asset& r);
+
+        //! Get accessor given an animation parameter name.
+        Ref<Accessor> GetAccessor(std::string name) {
+            if (name == "TIME") {
+                return Parameters.TIME;
+            } else if (name == "rotation") {
+                return Parameters.rotation;
+            } else if (name == "scale") {
+                return Parameters.scale;
+            } else if (name == "translation") {
+                return Parameters.translation;
+            }
+            return Ref<Accessor>();
+        }
     };
 
 
@@ -1058,7 +1073,7 @@ namespace glTF2
             std::string version; //!< Specifies the target rendering API (default: "1.0.3")
         } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
 
-        int version; //!< The glTF format version (should be 1)
+        int version; //!< The glTF format version
 
         void Read(Document& doc);
 
index 9065ced..33598e2 100644 (file)
@@ -242,6 +242,7 @@ Ref<T> LazyDict<T>::Create(const char* id)
     }
     T* inst = new T();
     inst->id = id;
+    inst->index = mObjs.size();
     return Add(inst);
 }
 
index 9bf1c56..2c3f2ff 100644 (file)
@@ -79,7 +79,7 @@ namespace glTF2 {
             lst.SetArray();
             lst.Reserve(unsigned(v.size()), al);
             for (size_t i = 0; i < v.size(); ++i) {
-                lst.PushBack(StringRef(v[i]->id), al);
+                lst.PushBack(v[i]->index, al);
             }
             obj.AddMember(StringRef(fieldId), lst, al);
         }
@@ -89,7 +89,7 @@ namespace glTF2 {
 
     inline void Write(Value& obj, Accessor& a, AssetWriter& w)
     {
-        obj.AddMember("bufferView", Value(a.bufferView->id, w.mAl).Move(), w.mAl);
+        obj.AddMember("bufferView", a.bufferView->index, w.mAl);
         obj.AddMember("byteOffset", a.byteOffset, w.mAl);
         obj.AddMember("byteStride", a.byteStride, w.mAl);
         obj.AddMember("componentType", int(a.componentType), w.mAl);
@@ -113,12 +113,13 @@ namespace glTF2 {
             Value valChannel;
             valChannel.SetObject();
             {
-                valChannel.AddMember("sampler", c.sampler, w.mAl);
+                Animation::AnimSampler& s = a.Samplers[c.sampler];
+                valChannel.AddMember("sampler", s.id, w.mAl);
 
                 Value valTarget;
                 valTarget.SetObject();
                 {
-                    valTarget.AddMember("id", StringRef(c.target.id->id), w.mAl);
+                    valTarget.AddMember("id", StringRef(c.target.node->id), w.mAl);
                     valTarget.AddMember("path", c.target.path, w.mAl);
                 }
                 valChannel.AddMember("target", valTarget, w.mAl);
@@ -127,61 +128,35 @@ namespace glTF2 {
         }
         obj.AddMember("channels", channels, w.mAl);
 
-        /****************** Parameters *******************/
-        Value valParameters;
-        valParameters.SetObject();
-        {
-            if (a.Parameters.TIME) {
-                valParameters.AddMember("TIME", StringRef(a.Parameters.TIME->id), w.mAl);
-            }
-            if (a.Parameters.rotation) {
-                valParameters.AddMember("rotation", StringRef(a.Parameters.rotation->id), w.mAl);
-            }
-            if (a.Parameters.scale) {
-                valParameters.AddMember("scale", StringRef(a.Parameters.scale->id), w.mAl);
-            }
-            if (a.Parameters.translation) {
-                valParameters.AddMember("translation", StringRef(a.Parameters.translation->id), w.mAl);
-            }
-        }
-        obj.AddMember("parameters", valParameters, w.mAl);
-
         /****************** Samplers *******************/
         Value valSamplers;
-        valSamplers.SetObject();
+        valSamplers.SetArray();
 
         for (size_t i = 0; i < unsigned(a.Samplers.size()); ++i) {
             Animation::AnimSampler& s = a.Samplers[i];
             Value valSampler;
             valSampler.SetObject();
             {
-                valSampler.AddMember("input", s.input, w.mAl);
+                Ref<Accessor> inputAccessor = a.GetAccessor(s.input);
+                Ref<Accessor> outputAccessor = a.GetAccessor(s.output);
+                valSampler.AddMember("input", inputAccessor->index, w.mAl);
                 valSampler.AddMember("interpolation", s.interpolation, w.mAl);
-                valSampler.AddMember("output", s.output, w.mAl);
+                valSampler.AddMember("output", outputAccessor->index, w.mAl);
             }
-            valSamplers.AddMember(StringRef(s.id), valSampler, w.mAl);
+            valSamplers.PushBack(valSampler, w.mAl);
         }
         obj.AddMember("samplers", valSamplers, w.mAl);
     }
 
     inline void Write(Value& obj, Buffer& b, AssetWriter& w)
     {
-        const char* type;
-        switch (b.type) {
-            case Buffer::Type_text:
-                type = "text"; break;
-            default:
-                type = "arraybuffer";
-        }
-
         obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl);
-        obj.AddMember("type", StringRef(type), w.mAl);
         obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl);
     }
 
     inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
     {
-        obj.AddMember("buffer", Value(bv.buffer->id, w.mAl).Move(), w.mAl);
+        obj.AddMember("buffer", bv.buffer->index, w.mAl);
         obj.AddMember("byteOffset", static_cast<uint64_t>(bv.byteOffset), w.mAl);
         obj.AddMember("byteLength", static_cast<uint64_t>(bv.byteLength), w.mAl);
         obj.AddMember("target", int(bv.target), w.mAl);
@@ -200,7 +175,7 @@ namespace glTF2 {
             exts.SetObject();
             ext.SetObject();
 
-            ext.AddMember("bufferView", StringRef(img.bufferView->id), w.mAl);
+            ext.AddMember("bufferView", img.bufferView->index, w.mAl);
 
             if (!img.mimeType.empty())
                 ext.AddMember("mimeType", StringRef(img.mimeType), w.mAl);
@@ -224,9 +199,12 @@ namespace glTF2 {
     namespace {
         inline void WriteColorOrTex(Value& obj, TexProperty& prop, const char* propName, MemoryPoolAllocator<>& al)
         {
-            if (prop.texture)
-                obj.AddMember(StringRef(propName), Value(prop.texture->id, al).Move(), al);
-            else {
+            if (prop.texture) {
+                Value tex;
+                tex.SetObject();
+                tex.AddMember("index", prop.texture->index, al);
+                obj.AddMember(StringRef(propName), tex, al);
+            } else {
                 Value col;
                 obj.AddMember(StringRef(propName), MakeValue(col, prop.color, al), al);
             }
@@ -238,17 +216,21 @@ namespace glTF2 {
         Value v;
         v.SetObject();
         {
-            WriteColorOrTex(v, m.ambient, "ambient", w.mAl);
-            WriteColorOrTex(v, m.diffuse, "diffuse", w.mAl);
-            WriteColorOrTex(v, m.specular, "specular", w.mAl);
-            WriteColorOrTex(v, m.emission, "emission", w.mAl);
+            WriteColorOrTex(v, m.ambient, m.ambient.texture ? "ambientTexture" : "ambientFactor", w.mAl);
+            WriteColorOrTex(v, m.diffuse, m.diffuse.texture ? "diffuseTexture" : "diffuseFactor", w.mAl);
+            WriteColorOrTex(v, m.specular, m.specular.texture ? "specularTexture" : "specularFactor", w.mAl);
+            WriteColorOrTex(v, m.emission, m.emission.texture ? "emissionTexture" : "emissionFactor", w.mAl);
 
             if (m.transparent)
                 v.AddMember("transparency", m.transparency, w.mAl);
 
-            v.AddMember("shininess", m.shininess, w.mAl);
+            v.AddMember("shininessFactor", m.shininess, w.mAl);
         }
-        obj.AddMember("values", v, w.mAl);
+        v.AddMember("type", "commonPhong", w.mAl);
+        Value ext;
+        ext.SetObject();
+        ext.AddMember("KHR_materials_common", v, w.mAl);
+        obj.AddMember("extensions", ext, w.mAl);
     }
 
     namespace {
@@ -257,13 +239,13 @@ namespace glTF2 {
         {
             if (lst.empty()) return;
             if (lst.size() == 1 && !forceNumber) {
-                attrs.AddMember(StringRef(semantic), Value(lst[0]->id, w.mAl).Move(), w.mAl);
+                attrs.AddMember(StringRef(semantic), lst[0]->index, w.mAl);
             }
             else {
                 for (size_t i = 0; i < lst.size(); ++i) {
                     char buffer[32];
                     ai_snprintf(buffer, 32, "%s_%d", semantic, int(i));
-                    attrs.AddMember(Value(buffer, w.mAl).Move(), Value(lst[i]->id, w.mAl).Move(), w.mAl);
+                    attrs.AddMember(Value(buffer, w.mAl).Move(), lst[i]->index, w.mAl);
                 }
             }
         }
@@ -337,10 +319,10 @@ namespace glTF2 {
                 prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl);
 
                 if (p.material)
-                    prim.AddMember("material", p.material->id, w.mAl);
+                    prim.AddMember("material", p.material->index, w.mAl);
 
                 if (p.indices)
-                    prim.AddMember("indices", Value(p.indices->id, w.mAl).Move(), w.mAl);
+                    prim.AddMember("indices", p.indices->index, w.mAl);
 
                 Value attrs;
                 attrs.SetObject();
@@ -390,7 +372,7 @@ namespace glTF2 {
         AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
 
         if (n.skin) {
-            obj.AddMember("skin", Value(n.skin->id, w.mAl).Move(), w.mAl);
+            obj.AddMember("skin", n.skin->index, w.mAl);
         }
 
         if (!n.jointName.empty()) {
@@ -437,9 +419,9 @@ namespace glTF2 {
         vJointNames.Reserve(unsigned(b.jointNames.size()), w.mAl);
 
         for (size_t i = 0; i < unsigned(b.jointNames.size()); ++i) {
-            vJointNames.PushBack(StringRef(b.jointNames[i]->jointName), w.mAl);
+            vJointNames.PushBack(b.jointNames[i]->index, w.mAl);
         }
-        obj.AddMember("jointNames", vJointNames, w.mAl);
+        obj.AddMember("joints", vJointNames, w.mAl);
 
         if (b.bindShapeMatrix.isPresent) {
             Value val;
@@ -447,7 +429,7 @@ namespace glTF2 {
         }
 
         if (b.inverseBindMatrices) {
-            obj.AddMember("inverseBindMatrices", Value(b.inverseBindMatrices->id, w.mAl).Move(), w.mAl);
+            obj.AddMember("inverseBindMatrices", b.inverseBindMatrices->index, w.mAl);
         }
 
     }
@@ -460,10 +442,10 @@ namespace glTF2 {
     inline void Write(Value& obj, Texture& tex, AssetWriter& w)
     {
         if (tex.source) {
-            obj.AddMember("source", Value(tex.source->id, w.mAl).Move(), w.mAl);
+            obj.AddMember("source", tex.source->index, w.mAl);
         }
         if (tex.sampler) {
-            obj.AddMember("sampler", Value(tex.sampler->id, w.mAl).Move(), w.mAl);
+            obj.AddMember("sampler", tex.sampler->index, w.mAl);
         }
     }
 
@@ -490,7 +472,7 @@ namespace glTF2 {
 
         // Add the target scene field
         if (mAsset.scene) {
-            mDoc.AddMember("scene", StringRef(mAsset.scene->id), mAl);
+            mDoc.AddMember("scene", mAsset.scene->index, mAl);
         }
     }
 
@@ -582,7 +564,7 @@ namespace glTF2 {
         GLB_Header header;
         memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic));
 
-        header.version = 1;
+        header.version = 2;
         AI_SWAP4(header.version);
 
         header.length = uint32_t(sizeof(header) + sceneLength + bodyLength);
@@ -624,8 +606,8 @@ namespace glTF2 {
             if (false)
                 exts.PushBack(StringRef("KHR_binary_glTF"), mAl);
 
-            if (false)
-                exts.PushBack(StringRef("KHR_materials_common"), mAl);
+            // This is used to export common materials with GLTF 2.
+            exts.PushBack(StringRef("KHR_materials_common"), mAl);
         }
 
         if (!exts.Empty())
@@ -653,9 +635,9 @@ namespace glTF2 {
         }
 
         Value* dict;
-        if (!(dict = FindObject(*container, d.mDictId))) {
-            container->AddMember(StringRef(d.mDictId), Value().SetObject().Move(), mDoc.GetAllocator());
-            dict = FindObject(*container, d.mDictId);
+        if (!(dict = FindArray(*container, d.mDictId))) {
+            container->AddMember(StringRef(d.mDictId), Value().SetArray().Move(), mDoc.GetAllocator());
+            dict = FindArray(*container, d.mDictId);
         }
 
         for (size_t i = 0; i < d.mObjs.size(); ++i) {
@@ -670,7 +652,7 @@ namespace glTF2 {
 
             Write(obj, *d.mObjs[i], *this);
 
-            dict->AddMember(StringRef(d.mObjs[i]->id), obj, mAl);
+            dict->PushBack(obj, mAl);
         }
     }
 
index e6dc2c4..ac72790 100644 (file)
@@ -434,7 +434,7 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref<Mesh>& meshRef, Ref<Buf
         // aib->mName   =====>  skinRef->jointNames
         // Find the node with id = mName.
         Ref<Node> nodeRef = mAsset.nodes.Get(aib->mName.C_Str());
-        nodeRef->jointName = nodeRef->id;
+        nodeRef->jointName = nodeRef->name;
 
         unsigned int jointNamesIndex;
         bool addJointToJointNames = true;
@@ -744,15 +744,27 @@ void glTF2Exporter::ExportMeshes()
         skinRef->bindShapeMatrix.isPresent = true;
         IdentityMatrix4(skinRef->bindShapeMatrix.value);
 
-        // Find node that contains this mesh and add "skeletons" and "skin" attributes to that node.
+        // Find nodes that contain a mesh with bones and add "skeletons" and "skin" attributes to those nodes.
         Ref<Node> rootNode = mAsset->nodes.Get(unsigned(0));
         Ref<Node> meshNode;
-        std::string meshID = mAsset->meshes.Get(unsigned(0))->id;
-        FindMeshNode(rootNode, meshNode, meshID);
-
-        Ref<Node> rootJoint = FindSkeletonRootJoint(skinRef);
-        meshNode->skeletons.push_back(rootJoint);
-        meshNode->skin = skinRef;
+        for (unsigned int meshIndex = 0; meshIndex < mAsset->meshes.Size(); ++meshIndex) {
+            Ref<Mesh> mesh = mAsset->meshes.Get(meshIndex);
+            bool hasBones = false;
+            for (unsigned int i = 0; i < mesh->primitives.size(); ++i) {
+                if (!mesh->primitives[i].attributes.weight.empty()) {
+                    hasBones = true;
+                    break;
+                }
+            }
+            if (!hasBones) {
+                continue;
+            }
+            std::string meshID = mesh->id;
+            FindMeshNode(rootNode, meshNode, meshID);
+            Ref<Node> rootJoint = FindSkeletonRootJoint(skinRef);
+            meshNode->skeletons.push_back(rootJoint);
+            meshNode->skin = skinRef;
+        }
     }
 }
 
@@ -787,9 +799,11 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode* n)
  */
 unsigned int glTF2Exporter::ExportNode(const aiNode* n, Ref<Node>& parent)
 {
-    Ref<Node> node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node"));
+    std::string name = mAsset->FindUniqueID(n->mName.C_Str(), "node");
+    Ref<Node> node = mAsset->nodes.Create(name);
 
     node->parent = parent;
+    node->name = name;
 
     if (!n->mTransformation.IsIdentity()) {
         node->matrix.isPresent = true;
@@ -826,7 +840,7 @@ void glTF2Exporter::ExportScene()
 void glTF2Exporter::ExportMetadata()
 {
     AssetMetadata& asset = mAsset->asset;
-    asset.version = 1;
+    asset.version = 2;
 
     char buffer[256];
     ai_snprintf(buffer, 256, "Open Asset Import Library (assimp v%d.%d.%d)",
@@ -970,12 +984,12 @@ void glTF2Exporter::ExportAnimations()
                 Animation::AnimChannel tmpAnimChannel;
                 Animation::AnimSampler tmpAnimSampler;
 
-                tmpAnimChannel.sampler = name + "_" + channelType;
+                tmpAnimChannel.sampler = animRef->Samplers.size();
                 tmpAnimChannel.target.path = channelType;
                 tmpAnimSampler.output = channelType;
                 tmpAnimSampler.id = name + "_" + channelType;
 
-                tmpAnimChannel.target.id = mAsset->nodes.Get(nodeChannel->mNodeName.C_Str());
+                tmpAnimChannel.target.node = mAsset->nodes.Get(nodeChannel->mNodeName.C_Str());
 
                 tmpAnimSampler.input = "TIME";
                 tmpAnimSampler.interpolation = "LINEAR";