Browse Source

Gltf model and animations exploring problems (#1635)

* Added bone binding to whole mesh and not only set vertices.
+ Also added missed setting of the animation count.
+ Removed double ; on one line

* Added more of the gltf sample models

https://github.com/KhronosGroup/glTF-Sample-Models
We need to make it working for all of them.

* Binding to initial bind pose added.

* Fix cube disappearing bug because lerpPercent could be Inf.

* Fixed for rigged figure also
Hristo Stamenov 4 years ago
parent
commit
5c2983f510

BIN
examples/models/resources/gltf/AnimatedMorphCube.glb


+ 118 - 0
examples/models/resources/gltf/AnimatedTriangle.gltf

@@ -0,0 +1,118 @@
+{
+  "scene" : 0,
+  "scenes" : [
+    {
+      "nodes" : [ 0 ]
+    }
+  ],
+  
+  "nodes" : [
+    {
+      "mesh" : 0,
+      "rotation" : [ 0.0, 0.0, 0.0, 1.0 ]
+    }
+  ],
+  
+  "meshes" : [
+    {
+      "primitives" : [ {
+        "attributes" : {
+          "POSITION" : 1
+        },
+        "indices" : 0
+      } ]
+    }
+  ],
+  
+  "animations": [
+    {
+      "samplers" : [
+        {
+          "input" : 2,
+          "interpolation" : "LINEAR",
+          "output" : 3
+        }
+      ],
+      "channels" : [ {
+        "sampler" : 0,
+        "target" : {
+          "node" : 0,
+          "path" : "rotation"
+        }
+      } ]
+    }
+  ],
+
+  "buffers" : [
+    {
+      "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=",
+      "byteLength" : 44
+    },
+    {
+      "uri" : "data:application/octet-stream;base64,AAAAAAAAgD4AAAA/AABAPwAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAPT9ND/0/TS/AAAAAAAAAAAAAAAAAACAPw==",
+      "byteLength" : 100
+    }
+  ],
+  "bufferViews" : [
+    {
+      "buffer" : 0,
+      "byteOffset" : 0,
+      "byteLength" : 6,
+      "target" : 34963
+    },
+    {
+      "buffer" : 0,
+      "byteOffset" : 8,
+      "byteLength" : 36,
+      "target" : 34962
+    },
+    {
+      "buffer" : 1,
+      "byteOffset" : 0,
+      "byteLength" : 100
+    }
+  ],
+  "accessors" : [
+    {
+      "bufferView" : 0,
+      "byteOffset" : 0,
+      "componentType" : 5123,
+      "count" : 3,
+      "type" : "SCALAR",
+      "max" : [ 2 ],
+      "min" : [ 0 ]
+    },
+    {
+      "bufferView" : 1,
+      "byteOffset" : 0,
+      "componentType" : 5126,
+      "count" : 3,
+      "type" : "VEC3",
+      "max" : [ 1.0, 1.0, 0.0 ],
+      "min" : [ 0.0, 0.0, 0.0 ]
+    },
+    {
+      "bufferView" : 2,
+      "byteOffset" : 0,
+      "componentType" : 5126,
+      "count" : 5,
+      "type" : "SCALAR",
+      "max" : [ 1.0 ],
+      "min" : [ 0.0 ]
+    },
+    {
+      "bufferView" : 2,
+      "byteOffset" : 20,
+      "componentType" : 5126,
+      "count" : 5,
+      "type" : "VEC4",
+      "max" : [ 0.0, 0.0, 1.0, 1.0 ],
+      "min" : [ 0.0, 0.0, 0.0, -0.707 ]
+    }
+  ],
+  
+  "asset" : {
+    "version" : "2.0"
+  }
+  
+}

BIN
examples/models/resources/gltf/BoxAnimated.glb


BIN
examples/models/resources/gltf/GearboxAssy.glb


+ 11 - 2
examples/models/resources/gltf/LICENSE

@@ -1,11 +1,20 @@
 Rigged Figure model has been created by Cesium (https://cesium.com/cesiumjs/),
 Rigged Figure model has been created by Cesium (https://cesium.com/cesiumjs/),
 and licensed as Creative Commons Attribution 4.0 International License.
 and licensed as Creative Commons Attribution 4.0 International License.
 
 
-Check for details: http://creativecommons.org/licenses/by/4.0/
+Box Animated model has been created by Cesium (https://cesium.com/cesiumjs/)
+and is licensed as Creative Commons Attribution 4.0 International License
 
 
 Avocado model is provided by Microsoft
 Avocado model is provided by Microsoft
 and licensed as CC0 Universal Public Domain
 and licensed as CC0 Universal Public Domain
 
 
-Check for details: https://creativecommons.org/publicdomain/zero/1.0/
+Animated Morph Cube model is provided by Microsoft
+and licensed as CC0 Universal Public Domain
+
+Animated Triangle model is licensed as CC0 Universal Public Domain
+
+Gearbox Assy model has been provided by Okino Computer Graphics, using Okino Polytrans Software.
+no license information was provided
 
 
+Check for details on CC0: https://creativecommons.org/publicdomain/zero/1.0/
+Check for details on CC4: http://creativecommons.org/licenses/by/4.0/
 GLTF sample models for testing are taken from: https://github.com/KhronosGroup/glTF-Sample-Models/
 GLTF sample models for testing are taken from: https://github.com/KhronosGroup/glTF-Sample-Models/

+ 73 - 5
src/models.c

@@ -754,7 +754,7 @@ Model LoadModel(const char *fileName)
 
 
         if (model.meshMaterial == NULL) model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
         if (model.meshMaterial == NULL) model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
     }
     }
-
+	
     return model;
     return model;
 }
 }
 
 
@@ -3979,10 +3979,75 @@ static Model LoadGLTF(const char *fileName)
                 }
                 }
                 else
                 else
                 {
                 {
-                    model.meshMaterial[primitiveIndex] = model.materialCount - 1;;
+                    model.meshMaterial[primitiveIndex] = model.materialCount - 1;
                 }
                 }
                 
                 
 //                if (data->meshes[i].)
 //                if (data->meshes[i].)
+
+                if (model.meshes[primitiveIndex].boneIds == NULL && data->nodes_count > 0)
+                {
+                    for (int nodeId = 0; nodeId < data->nodes_count; nodeId++)
+                    {
+                        if (data->nodes[nodeId].mesh == &(data->meshes[i]))
+                        {
+                            model.meshes[primitiveIndex].boneIds = RL_CALLOC(4 * model.meshes[primitiveIndex].vertexCount, sizeof(int));
+                            model.meshes[primitiveIndex].boneWeights = RL_CALLOC(4 * model.meshes[primitiveIndex].vertexCount, sizeof(float));
+
+                        	for (int b = 0; b < 4 * model.meshes[primitiveIndex].vertexCount; b++)
+                            {
+                        		if(b % 4 == 0)
+                        		{
+                                    model.meshes[primitiveIndex].boneIds[b] = nodeId;
+                                    model.meshes[primitiveIndex].boneWeights[b] = 1.0f;
+                        		}
+                        		else
+                        		{
+                                    model.meshes[primitiveIndex].boneIds[b] = 0;
+                                    model.meshes[primitiveIndex].boneWeights[b] = 0.0f;
+                        		}
+                            
+                            }
+    
+                            Vector3 boundVertex = { 0 };
+                            Vector3 boundNormal = { 0 };
+    
+                            Vector3 outTranslation = { 0 };
+                            Quaternion outRotation = { 0 };
+                            Vector3 outScale = { 0 };
+    
+                            int vCounter = 0;
+                            int boneCounter = 0;
+                            int boneId = 0;
+    
+                            for (int i = 0; i < model.meshes[primitiveIndex].vertexCount; i++)
+                            {
+                                boneId = model.meshes[primitiveIndex].boneIds[boneCounter];
+                                outTranslation = model.bindPose[boneId].translation;
+                                outRotation = model.bindPose[boneId].rotation;
+                                outScale = model.bindPose[boneId].scale;
+        
+                                // Vertices processing
+                                boundVertex = (Vector3){ model.meshes[primitiveIndex].vertices[vCounter], model.meshes[primitiveIndex].vertices[vCounter + 1], model.meshes[primitiveIndex].vertices[vCounter + 2] };
+                                boundVertex = Vector3Multiply(boundVertex, outScale);
+                                boundVertex = Vector3RotateByQuaternion(boundVertex, outRotation);
+                                boundVertex = Vector3Add(boundVertex, outTranslation);
+                                model.meshes[primitiveIndex].vertices[vCounter] = boundVertex.x;
+                                model.meshes[primitiveIndex].vertices[vCounter + 1] = boundVertex.y;
+                                model.meshes[primitiveIndex].vertices[vCounter + 2] = boundVertex.z;
+        
+                                // Normals processing
+                                boundNormal = (Vector3){ model.meshes[primitiveIndex].normals[vCounter], model.meshes[primitiveIndex].normals[vCounter + 1], model.meshes[primitiveIndex].normals[vCounter + 2] };
+                                boundNormal = Vector3RotateByQuaternion(boundNormal, outRotation);
+                                model.meshes[primitiveIndex].normals[vCounter] = boundNormal.x;
+                                model.meshes[primitiveIndex].normals[vCounter + 1] = boundNormal.y;
+                                model.meshes[primitiveIndex].normals[vCounter + 2] = boundNormal.z;
+                                vCounter += 3;
+        
+                                boneCounter += 4;
+                            }
+                        }
+                    }
+                }
                 
                 
                 primitiveIndex++;
                 primitiveIndex++;
             }
             }
@@ -4053,9 +4118,9 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
 
 
         result = cgltf_load_buffers(&options, data, fileName);
         result = cgltf_load_buffers(&options, data, fileName);
         if (result != cgltf_result_success) TRACELOG(LOG_WARNING, "MODEL: [%s] unable to load glTF animations data", fileName);
         if (result != cgltf_result_success) TRACELOG(LOG_WARNING, "MODEL: [%s] unable to load glTF animations data", fileName);
-        
         animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation));
         animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation));
-    
+        *animCount = data->animations_count;
+
         for (unsigned int a = 0; a < data->animations_count; a++)
         for (unsigned int a = 0; a < data->animations_count; a++)
         {
         {
             // gltf animation consists of the following structures:
             // gltf animation consists of the following structures:
@@ -4150,7 +4215,10 @@ static ModelAnimation *LoadGLTFModelAnimations(const char *fileName, int *animCo
                                 float previousInputTime = 0.0f;
                                 float previousInputTime = 0.0f;
                                 if (GltfReadFloat(sampler->input, outputMin, (float *)&previousInputTime, 1))
                                 if (GltfReadFloat(sampler->input, outputMin, (float *)&previousInputTime, 1))
                                 {
                                 {
-                                    lerpPercent = (frameTime - previousInputTime)/(inputFrameTime - previousInputTime);
+                                    if((inputFrameTime - previousInputTime) != 0)
+                                    {
+                                        lerpPercent = (frameTime - previousInputTime)/(inputFrameTime - previousInputTime);
+                                    }
                                 }
                                 }
                                 
                                 
                                 break;
                                 break;