|
@@ -2262,108 +2262,6 @@ ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount)
|
|
|
return animations;
|
|
|
}
|
|
|
|
|
|
-// Update model animated vertex data (positions and normals) for a given frame
|
|
|
-// NOTE: Updated data is uploaded to GPU
|
|
|
-void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
|
|
|
-{
|
|
|
- if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL))
|
|
|
- {
|
|
|
- if (frame >= anim.frameCount) frame = frame%anim.frameCount;
|
|
|
-
|
|
|
- for (int m = 0; m < model.meshCount; m++)
|
|
|
- {
|
|
|
- Mesh mesh = model.meshes[m];
|
|
|
-
|
|
|
- if (mesh.boneIds == NULL || mesh.boneWeights == NULL)
|
|
|
- {
|
|
|
- TRACELOG(LOG_WARNING, "MODEL: UpdateModelAnimation(): Mesh %i has no connection to bones", m);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- bool updated = false; // Flag to check when anim vertex information is updated
|
|
|
- Vector3 animVertex = { 0 };
|
|
|
- Vector3 animNormal = { 0 };
|
|
|
-
|
|
|
- Vector3 inTranslation = { 0 };
|
|
|
- Quaternion inRotation = { 0 };
|
|
|
- // Vector3 inScale = { 0 };
|
|
|
-
|
|
|
- Vector3 outTranslation = { 0 };
|
|
|
- Quaternion outRotation = { 0 };
|
|
|
- Vector3 outScale = { 0 };
|
|
|
-
|
|
|
- int boneId = 0;
|
|
|
- int boneCounter = 0;
|
|
|
- float boneWeight = 0.0;
|
|
|
-
|
|
|
- const int vValues = mesh.vertexCount*3;
|
|
|
- for (int vCounter = 0; vCounter < vValues; vCounter += 3)
|
|
|
- {
|
|
|
- mesh.animVertices[vCounter] = 0;
|
|
|
- mesh.animVertices[vCounter + 1] = 0;
|
|
|
- mesh.animVertices[vCounter + 2] = 0;
|
|
|
-
|
|
|
- if (mesh.animNormals != NULL)
|
|
|
- {
|
|
|
- mesh.animNormals[vCounter] = 0;
|
|
|
- mesh.animNormals[vCounter + 1] = 0;
|
|
|
- mesh.animNormals[vCounter + 2] = 0;
|
|
|
- }
|
|
|
-
|
|
|
- // Iterates over 4 bones per vertex
|
|
|
- for (int j = 0; j < 4; j++, boneCounter++)
|
|
|
- {
|
|
|
- boneWeight = mesh.boneWeights[boneCounter];
|
|
|
-
|
|
|
- // Early stop when no transformation will be applied
|
|
|
- if (boneWeight == 0.0f) continue;
|
|
|
-
|
|
|
- boneId = mesh.boneIds[boneCounter];
|
|
|
- //int boneIdParent = model.bones[boneId].parent;
|
|
|
- inTranslation = model.bindPose[boneId].translation;
|
|
|
- inRotation = model.bindPose[boneId].rotation;
|
|
|
- //inScale = model.bindPose[boneId].scale;
|
|
|
- outTranslation = anim.framePoses[frame][boneId].translation;
|
|
|
- outRotation = anim.framePoses[frame][boneId].rotation;
|
|
|
- outScale = anim.framePoses[frame][boneId].scale;
|
|
|
-
|
|
|
- // Vertices processing
|
|
|
- // NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position)
|
|
|
- animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
|
|
|
- animVertex = Vector3Subtract(animVertex, inTranslation);
|
|
|
- animVertex = Vector3Multiply(animVertex, outScale);
|
|
|
- animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
|
|
|
- animVertex = Vector3Add(animVertex, outTranslation);
|
|
|
- //animVertex = Vector3Transform(animVertex, model.transform);
|
|
|
- mesh.animVertices[vCounter] += animVertex.x*boneWeight;
|
|
|
- mesh.animVertices[vCounter + 1] += animVertex.y*boneWeight;
|
|
|
- mesh.animVertices[vCounter + 2] += animVertex.z*boneWeight;
|
|
|
- updated = true;
|
|
|
-
|
|
|
- // Normals processing
|
|
|
- // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
|
|
|
- if (mesh.normals != NULL)
|
|
|
- {
|
|
|
- animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
|
|
|
- animNormal = Vector3RotateByQuaternion(animNormal, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
|
|
|
- mesh.animNormals[vCounter] += animNormal.x*boneWeight;
|
|
|
- mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
|
|
|
- mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Upload new vertex data to GPU for model drawing
|
|
|
- // NOTE: Only update data when values changed
|
|
|
- if (updated)
|
|
|
- {
|
|
|
- rlUpdateVertexBuffer(mesh.vboId[0], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); // Update vertex position
|
|
|
- rlUpdateVertexBuffer(mesh.vboId[2], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0); // Update vertex normals
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
// Update model animated bones transform matrices for a given frame
|
|
|
// NOTE: Updated data is not uploaded to GPU but kept at model.meshes[i].boneMatrices[boneId],
|
|
|
// to be uploaded to shader at drawing, in case GPU skinning is enabled
|
|
@@ -2411,6 +2309,66 @@ void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// at least 2x speed up vs the old method
|
|
|
+// Update model animated vertex data (positions and normals) for a given frame
|
|
|
+// NOTE: Updated data is uploaded to GPU
|
|
|
+void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
|
|
|
+{
|
|
|
+ UpdateModelAnimationBones(model,anim,frame);
|
|
|
+ for (int m = 0; m < model.meshCount; m++)
|
|
|
+ {
|
|
|
+ Mesh mesh = model.meshes[m];
|
|
|
+ Vector3 animVertex = { 0 };
|
|
|
+ Vector3 animNormal = { 0 };
|
|
|
+ int boneId = 0;
|
|
|
+ int boneCounter = 0;
|
|
|
+ float boneWeight = 0.0;
|
|
|
+ bool updated = false; // Flag to check when anim vertex information is updated
|
|
|
+ const int vValues = mesh.vertexCount*3;
|
|
|
+ for (int vCounter = 0; vCounter < vValues; vCounter += 3)
|
|
|
+ {
|
|
|
+ mesh.animVertices[vCounter] = 0;
|
|
|
+ mesh.animVertices[vCounter + 1] = 0;
|
|
|
+ mesh.animVertices[vCounter + 2] = 0;
|
|
|
+ if (mesh.animNormals != NULL)
|
|
|
+ {
|
|
|
+ mesh.animNormals[vCounter] = 0;
|
|
|
+ mesh.animNormals[vCounter + 1] = 0;
|
|
|
+ mesh.animNormals[vCounter + 2] = 0;
|
|
|
+ }
|
|
|
+ // Iterates over 4 bones per vertex
|
|
|
+ for (int j = 0; j < 4; j++, boneCounter++)
|
|
|
+ {
|
|
|
+ boneWeight = mesh.boneWeights[boneCounter];
|
|
|
+ boneId = mesh.boneIds[boneCounter];
|
|
|
+ // Early stop when no transformation will be applied
|
|
|
+ if (boneWeight == 0.0f) continue;
|
|
|
+ animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
|
|
|
+ animVertex = Vector3Transform(animVertex,model.meshes[m].boneMatrices[boneId]);
|
|
|
+ mesh.animVertices[vCounter] += animVertex.x * boneWeight;
|
|
|
+ mesh.animVertices[vCounter+1] += animVertex.y * boneWeight;
|
|
|
+ mesh.animVertices[vCounter+2] += animVertex.z * boneWeight;
|
|
|
+ updated = true;
|
|
|
+ // Normals processing
|
|
|
+ // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
|
|
|
+ if (mesh.normals != NULL)
|
|
|
+ {
|
|
|
+ animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
|
|
|
+ animNormal = Vector3Transform(animNormal,model.meshes[m].boneMatrices[boneId]);
|
|
|
+ mesh.animNormals[vCounter] += animNormal.x*boneWeight;
|
|
|
+ mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
|
|
|
+ mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (updated)
|
|
|
+ {
|
|
|
+ rlUpdateVertexBuffer(mesh.vboId[0], mesh.animVertices, mesh.vertexCount*3*sizeof(float), 0); // Update vertex position
|
|
|
+ rlUpdateVertexBuffer(mesh.vboId[2], mesh.animNormals, mesh.vertexCount*3*sizeof(float), 0); // Update vertex normals
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// Unload animation array data
|
|
|
void UnloadModelAnimations(ModelAnimation *animations, int animCount)
|
|
|
{
|