Fixing animation bugs

This commit is contained in:
Vladislav Khorev 2025-03-01 19:44:15 +03:00
parent b5877a488d
commit 2a16970cde
6 changed files with 17529 additions and 113 deletions

View File

@ -251,7 +251,7 @@ namespace ZL
}
std::getline(f, tempLine);//=== Vertex Weights ===
std::vector<std::array<BoneWeight, 3>> localVerticesBoneWeight;
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> localVerticesBoneWeight;
localVerticesBoneWeight.resize(numberVertices);
for (int i = 0; i < numberVertices; i++)
@ -268,9 +268,9 @@ namespace ZL
throw std::runtime_error("No number found in the input string.");
}
if (boneCount > 3)
if (boneCount > MAX_BONE_COUNT)
{
throw std::runtime_error("more than 3 bones");
throw std::runtime_error("more than 5 bones");
}
float sumWeights = 0;
@ -464,6 +464,7 @@ namespace ZL
//std::vector<Matrix3f> skinningMatrixForEachBone;
skinningMatrixForEachBone.resize(currentBones.size());
for (int i = 0; i < currentBones.size(); i++)
{
currentBones[i].boneStartWorld.v[0] = oneFrameBones[i].boneStartWorld.v[0] + t * (nextFrameBones[i].boneStartWorld.v[0] - oneFrameBones[i].boneStartWorld.v[0]);
@ -472,8 +473,10 @@ namespace ZL
Vector4f q1 = MatrixToQuat(oneFrameBones[i].boneMatrixWorld);
Vector4f q2 = MatrixToQuat(nextFrameBones[i].boneMatrixWorld);
Vector4f q1_norm = q1.normalized();
Vector4f q2_norm = q2.normalized();
Vector4f result = slerp(q1, q2, t);
Vector4f result = slerp(q1_norm, q2_norm, t);
currentBones[i].boneMatrixWorld = QuatToMatrix(result);
@ -486,7 +489,20 @@ namespace ZL
skinningMatrixForEachBone[i] = MultMatrixMatrix(currentBoneMatrixWorld4, inverstedStartBoneMatrixWorld4);
}
/*
for (int i = 0; i < currentBones.size(); i++)
{
currentBones[i].boneStartWorld = oneFrameBones[i].boneStartWorld;
currentBones[i].boneMatrixWorld = oneFrameBones[i].boneMatrixWorld;
Matrix4f currentBoneMatrixWorld4 = MakeMatrix4x4(currentBones[i].boneMatrixWorld, currentBones[i].boneStartWorld);
Matrix4f startBoneMatrixWorld4 = MakeMatrix4x4(animations[0].keyFrames[0].bones[i].boneMatrixWorld, animations[0].keyFrames[0].bones[i].boneStartWorld);
Matrix4f inverstedStartBoneMatrixWorld4 = InverseMatrix(startBoneMatrixWorld4);
skinningMatrixForEachBone[i] = MultMatrixMatrix(currentBoneMatrixWorld4, inverstedStartBoneMatrixWorld4);
}
*/
for (int i = 0; i < mesh.PositionData.size(); i++)
{
Vector4f originalPos = {
@ -495,17 +511,30 @@ namespace ZL
startMesh.PositionData[i].v[2], 1.0};
Vector4f finalPos = Vector4f{0.f, 0.f, 0.f, 0.f};
bool vMoved = false;
//Vector3f finalPos = Vector3f{ 0.f, 0.f, 0.f };
for (int j = 0; j < 3; j++)
for (int j = 0; j < MAX_BONE_COUNT; j++)
{
if (verticesBoneWeight[i][j].weight != 0)
{
vMoved = true;
//finalPos = finalPos + MultVectorMatrix(originalPos, skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex]) * verticesBoneWeight[i][j].weight;
finalPos = finalPos + MultMatrixVector(skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex], originalPos) * verticesBoneWeight[i][j].weight;
}
}
if (abs(finalPos.v[0] - originalPos.v[0]) > 1 || abs(finalPos.v[1] - originalPos.v[1]) > 1 || abs(finalPos.v[2] - originalPos.v[2]) > 1)
{
std::cout << "Hello!" << std::endl;
}
if (!vMoved)
{
std::cout << "Hello!" << std::endl;
}
mesh.PositionData[i].v[0] = finalPos.v[0];
mesh.PositionData[i].v[1] = finalPos.v[1];
mesh.PositionData[i].v[2] = finalPos.v[2];

View File

@ -6,6 +6,7 @@
namespace ZL
{
constexpr int MAX_BONE_COUNT = 6;
struct Bone
{
Vector3f boneStartWorld;
@ -39,7 +40,9 @@ namespace ZL
{
VertexDataStruct mesh;
VertexDataStruct startMesh;
std::vector<std::array<BoneWeight, 3>> verticesBoneWeight;
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> verticesBoneWeight;
Matrix4f armatureMatrix;
std::vector<Bone> startBones;
std::vector<Bone> currentBones;

166
Math.cpp
View File

@ -247,68 +247,42 @@ namespace ZL {
Vector4f MatrixToQuat(const Matrix3f& m)
{
Vector4f r;
float f;
float trace = m.m[0] + m.m[4] + m.m[8];
if (m.m[0] >= m.m[4] && m.m[0] >= m.m[8])
if (trace > 0)
{
f = sqrtf(1.0 + m.m[0] - m.m[4] - m.m[8]);
if (f != 0)
{
r.v[3] = (m.m[5] - m.m[7]) / (f + f);
r.v[0] = f / 2;
r.v[1] = (m.m[3] + m.m[1]) / (f + f);
r.v[2] = (m.m[6] + m.m[2]) / (f + f);
}
else
{
r.v[3] = 1;
r.v[2] = 0;
r.v[1] = 0;
r.v[0] = 0;
}
float s = 0.5f / sqrtf(trace + 1.0f);
r.v[3] = 0.25f / s;
r.v[0] = (m.m[5] - m.m[7]) * s;
r.v[1] = (m.m[6] - m.m[2]) * s;
r.v[2] = (m.m[1] - m.m[3]) * s;
}
else if (m.m[0] > m.m[4] && m.m[0] > m.m[8])
{
float s = 2.0f * sqrtf(1.0f + m.m[0] - m.m[4] - m.m[8]);
r.v[3] = (m.m[5] - m.m[7]) / s;
r.v[0] = 0.25f * s;
r.v[1] = (m.m[1] + m.m[3]) / s;
r.v[2] = (m.m[6] + m.m[2]) / s;
}
else if (m.m[4] > m.m[8])
{
float s = 2.0f * sqrtf(1.0f + m.m[4] - m.m[0] - m.m[8]);
r.v[3] = (m.m[6] - m.m[2]) / s;
r.v[0] = (m.m[1] + m.m[3]) / s;
r.v[1] = 0.25f * s;
r.v[2] = (m.m[5] + m.m[7]) / s;
}
else
{
float s = 2.0f * sqrtf(1.0f + m.m[8] - m.m[0] - m.m[4]);
r.v[3] = (m.m[1] - m.m[3]) / s;
r.v[0] = (m.m[6] + m.m[2]) / s;
r.v[1] = (m.m[5] + m.m[7]) / s;
r.v[2] = 0.25f * s;
}
if (m.m[4] >= m.m[0] && m.m[4] >= m.m[8])
{
f = sqrtf(1 + m.m[4] - m.m[0] - m.m[8]);
if (f != 0)
{
r.v[3] = (m.m[6] - m.m[2]) / (f + f);
r.v[1] = f / 2;
r.v[0] = (m.m[1] + m.m[3]) / (f + f);
r.v[2] = (m.m[7] + m.m[5]) / (f + f);
}
else
{
r.v[3] = 1;
r.v[2] = 0;
r.v[1] = 0;
r.v[0] = 0;
}
}
if (m.m[8] >= m.m[4] && m.m[8] >= m.m[0])
{
f = sqrtf(1 + m.m[8] - m.m[2]);
if (f != 0)
{
r.v[3] = (m.m[1] - m.m[3]) / (f + f);
r.v[2] = f / 2;
r.v[1] = (m.m[5] + m.m[7]) / (f + f);
r.v[0] = (m.m[6] + m.m[2]) / (f + f);
}
else
{
r.v[3] = 1;
r.v[2] = 0;
r.v[1] = 0;
r.v[0] = 0;
}
}
return r;
return r.normalized();
}
Vector4f QuatFromRotateAroundX(float angle)
@ -681,65 +655,51 @@ namespace ZL {
return r;
}
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, double t)
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t)
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
double cosTheta = q1.dot(q2);
const float epsilon = 1e-6f;
// <20><><EFBFBD><EFBFBD> cosTheta < 0, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
Vector4f q2Adjusted = q2;
if (cosTheta < 0.0) {
//q2Adjusted = { -q2.w, -q2.x, -q2.y, -q2.z };
q2Adjusted.v[0] = -q2.v[0];
q2Adjusted.v[1] = -q2.v[1];
q2Adjusted.v[2] = -q2.v[2];
q2Adjusted.v[3] = -q2.v[3];
// Нормализация входных кватернионов
Vector4f q1_norm = q1.normalized();
Vector4f q2_norm = q2.normalized();
float cosTheta = q1_norm.dot(q2_norm);
// Если q1 и q2 близки к противоположным направлениям, корректируем q2
Vector4f q2_adjusted = q2_norm;
if (cosTheta < 0.0f) {
q2_adjusted.v[0] = -q2_adjusted.v[0];
q2_adjusted.v[1] = -q2_adjusted.v[1];
q2_adjusted.v[2] = -q2_adjusted.v[2];
q2_adjusted.v[3] = -q2_adjusted.v[3];
cosTheta = -cosTheta;
}
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
const double epsilon = 1e-6;
if (cosTheta > 1.0 - epsilon) {
// Если кватернионы близки, используем линейную интерполяцию
if (cosTheta > 1.0f - epsilon) {
Vector4f result;
result.v[0] = q1.v[0] + t * (q2Adjusted.v[0] - q1.v[0]);
result.v[1] = q1.v[1] + t * (q2Adjusted.v[1] - q1.v[1]);
result.v[2] = q1.v[2] + t * (q2Adjusted.v[2] - q1.v[2]);
result.v[3] = q1.v[3] + t * (q2Adjusted.v[3] - q1.v[3]);
/*Quaternion result = {
q1.w + t * (q2Adjusted.w - q1.w),
q1.x + t * (q2Adjusted.x - q1.x),
q1.y + t * (q2Adjusted.y - q1.y),
q1.z + t * (q2Adjusted.z - q1.z)
};*/
result.v[0] = q1_norm.v[0] + t * (q2_adjusted.v[0] - q1_norm.v[0]);
result.v[1] = q1_norm.v[1] + t * (q2_adjusted.v[1] - q1_norm.v[1]);
result.v[2] = q1_norm.v[2] + t * (q2_adjusted.v[2] - q1_norm.v[2]);
result.v[3] = q1_norm.v[3] + t * (q2_adjusted.v[3] - q1_norm.v[3]);
return result.normalized();
}
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> theta
double theta = std::acos(cosTheta);
double sinTheta = std::sin(theta);
// Иначе используем сферическую интерполяцию
float theta = std::acos(cosTheta);
float sinTheta = std::sin(theta);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
double coeff1 = std::sin((1.0 - t) * theta) / sinTheta;
double coeff2 = std::sin(t * theta) / sinTheta;
float coeff1 = std::sin((1.0f - t) * theta) / sinTheta;
float coeff2 = std::sin(t * theta) / sinTheta;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/*
Quaternion result = {
coeff1 * q1.w + coeff2 * q2Adjusted.w,
coeff1 * q1.x + coeff2 * q2Adjusted.x,
coeff1 * q1.y + coeff2 * q2Adjusted.y,
coeff1 * q1.z + coeff2 * q2Adjusted.z
};*/
Vector4f result;
result.v[0] = coeff1 * q1.v[0] + coeff2 * q2Adjusted.v[0];
result.v[1] = coeff1 * q1.v[1] + coeff2 * q2Adjusted.v[1];
result.v[2] = coeff1 * q1.v[2] + coeff2 * q2Adjusted.v[2];
result.v[3] = coeff1 * q1.v[3] + coeff2 * q2Adjusted.v[3];
result.v[0] = coeff1 * q1_norm.v[0] + coeff2 * q2_adjusted.v[0];
result.v[1] = coeff1 * q1_norm.v[1] + coeff2 * q2_adjusted.v[1];
result.v[2] = coeff1 * q1_norm.v[2] + coeff2 * q2_adjusted.v[2];
result.v[3] = coeff1 * q1_norm.v[3] + coeff2 * q2_adjusted.v[3];
return result.normalized();
}

2
Math.h
View File

@ -100,7 +100,7 @@ namespace ZL {
Vector4f MultVectorMatrix(Vector4f v, Matrix4f mt);
Vector4f MultMatrixVector(Matrix4f mt, Vector4f v);
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, double t);
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t);
Matrix3f InverseMatrix(const Matrix3f& m);
Matrix4f InverseMatrix(const Matrix4f& m);
Matrix3f MultMatrixMatrix(const Matrix3f& m1, const Matrix3f& m2);

View File

@ -144,6 +144,34 @@ namespace ZL
glViewport(0, 0, Env::width, Env::height);
renderer.shaderManager.PushShader(colorShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, static_cast<float>(Env::width) / static_cast<float>(Env::height), 50, 10000);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -100 * Env::zoom });
float t = 0.3;
renderer.RotateMatrix(QuatFromRotateAroundX(t * M_PI / 2.0));
GameObjects::bxMutable.AssignFrom(GameObjects::bx.mesh);
GameObjects::bxMutable.RefreshVBO();
renderer.DrawVertexRenderStruct(GameObjects::bxMutable);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader();
#if 0
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
@ -217,6 +245,7 @@ namespace ZL
renderer.shaderManager.PopShader();
#endif
CheckGlError();
}
@ -318,7 +347,8 @@ namespace ZL
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./defaultColor.vertex", "./defaultColor.fragment");
std::cout << "Hello test 2x" << std::endl;
GameObjects::bx.LoadFromFile("mesh_armature_and_animation_data.txt");
//GameObjects::bx.LoadFromFile("mesh_armature_and_animation_data.txt");
GameObjects::bx.LoadFromFile("via004.txt");
std::cout << "Hello test 3" << std::endl;
@ -337,6 +367,7 @@ namespace ZL
GameObjects::testObjMeshMutable.data = GameObjects::testObjMesh;
GameObjects::testObjMeshMutable.RefreshVBO();
/*
GameObjects::textMesh = LoadFromTextFile("./mesh001.txt");
GameObjects::coneMesh = LoadFromTextFile("./cone001.txt");
@ -347,7 +378,7 @@ namespace ZL
GameObjects::textMeshMutable.RefreshVBO();
GameObjects::coneMeshMutable.AssignFrom(GameObjects::coneMesh);
GameObjects::coneMeshMutable.RefreshVBO();
*/
ActiveObject ao1;
@ -425,7 +456,7 @@ namespace ZL
static int x = 0;
GameObjects::bx.Interpolate(x);
x = x + 2;
x = x + 3;
}
if (event.type == SDL_MOUSEWHEEL) {

17393
via004.txt Normal file

File diff suppressed because it is too large Load Diff