From 687db8a01a0719b2f4f23b6aef27bddb8f23d31c Mon Sep 17 00:00:00 2001 From: XProger Date: Wed, 28 Dec 2016 01:18:12 +0300 Subject: [PATCH] #16 transform meshes by quaternion & pos instead of matrix --- bin/OpenLara.exe | Bin 134144 -> 136192 bytes src/animation.h | 22 +++++++++++----------- src/controller.h | 16 ++++++++-------- src/core.h | 3 ++- src/enemy.h | 4 ++-- src/lara.h | 20 ++++++++++---------- src/level.h | 17 ++++++++--------- src/mesh.h | 17 +++++++++-------- src/shader.glsl | 18 ++++++++++++++---- src/shader.h | 9 +++++++-- src/sprite.h | 6 +++--- src/utils.h | 40 +++++++++++++++++++++++++++++++++++++++- 12 files changed, 113 insertions(+), 59 deletions(-) diff --git a/bin/OpenLara.exe b/bin/OpenLara.exe index fe9329e315e7aee99edb2525b3a38322a9ff9678..c55c28aa3c205917646054d0c5963155dba8c49c 100644 GIT binary patch delta 28749 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 B9t{8h delta 26636 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 diff --git a/src/animation.h b/src/animation.h index 73274161..19a53cc4 100644 --- a/src/animation.h +++ b/src/animation.h @@ -200,46 +200,46 @@ struct Animation { return lerpAngle(frameA->getAngle(joint), frameB->getAngle(joint), delta); } - mat4 getJoints(mat4 matrix, int joint, bool postRot = false, mat4 *joints = NULL) { + Basis getJoints(Basis basis, int joint, bool postRot = false, Basis *joints = NULL) { ASSERT(model); vec3 offset = isPrepareToNext ? this->offset : vec3(0.0f); - matrix.translate(((vec3)frameA->pos).lerp(offset + frameB->pos, delta)); + basis.translate(((vec3)frameA->pos).lerp(offset + frameB->pos, delta)); TR::Node *node = (int)model->node < level->nodesDataSize ? (TR::Node*)&level->nodesData[model->node] : NULL; int sIndex = 0; - mat4 stack[16]; + Basis stack[16]; for (int i = 0; i < model->mCount; i++) { if (i > 0 && node) { TR::Node &t = node[i - 1]; - if (t.flags & 0x01) matrix = stack[--sIndex]; - if (t.flags & 0x02) stack[sIndex++] = matrix; + if (t.flags & 0x01) basis = stack[--sIndex]; + if (t.flags & 0x02) stack[sIndex++] = basis; ASSERT(sIndex >= 0 && sIndex < 16); - matrix.translate(vec3((float)t.x, (float)t.y, (float)t.z)); + basis.translate(vec3((float)t.x, (float)t.y, (float)t.z)); } if (i == joint && !postRot) - return matrix; + return basis; quat q; if (overrideMask & (1 << i)) q = overrides[i]; else q = getJointRot(i); - matrix = matrix * mat4(q, vec3(0.0f)); + basis.rotate(q); if (i == joint && postRot) - return matrix; + return basis; if (joints) - joints[i] = matrix; + joints[i] = basis; } - return matrix; + return basis; } Box getBoundingBox(const vec3 &pos, int dir) { diff --git a/src/controller.h b/src/controller.h index 4632b02d..98affeb9 100644 --- a/src/controller.h +++ b/src/controller.h @@ -22,7 +22,7 @@ struct Controller { vec3 pos; vec3 angle; - mat4 *joints; + Basis *joints; int frameIndex; vec3 ambient[6]; @@ -49,7 +49,7 @@ struct Controller { pos = vec3((float)e.x, (float)e.y, (float)e.z); angle = vec3(0.0f, e.rotation, 0.0f); TR::Model *m = getModel(); - joints = m ? new mat4[m->mCount] : NULL; + joints = m ? new Basis[m->mCount] : NULL; frameIndex = -1; specular = 0.0f; } @@ -85,8 +85,8 @@ struct Controller { Box box = ((Controller*)e.controller)->getBoundingBox(); vec3 t = (box.min + box.max) * 0.5f; - mat4 m = animation.getJoints(getMatrix(), joint); - vec3 delta = (m.inverse() * t).normal(); + Basis b = animation.getJoints(Basis(getMatrix()), joint); + vec3 delta = (b.inverse() * t).normal(); float angleY = clampAngle(atan2f(delta.x, delta.z)); float angleX = clampAngle(asinf(delta.y)); @@ -99,7 +99,7 @@ struct Controller { rot = ay * ax; if (rotAbs) - *rotAbs = m.getRot() * rot; + *rotAbs = b.rot * rot; return true; } } @@ -470,13 +470,13 @@ struct Controller { mask |= layers[i].mask; // set meshes visibility for (int j = 0; j < model->mCount; j++) - joints[j].e33 = (vmask & (1 << j)) ? 1.0f : -1.0f; + joints[j].w = (vmask & (1 << j)) ? 1.0f : -1.0f; // AHAHA // render - Core::active.shader->setParam(uModel, joints[0], model->mCount); + Core::active.shader->setParam(uBasis, joints[0], model->mCount); mesh->renderModel(layers[i].model); } } else { - Core::active.shader->setParam(uModel, joints[0], model->mCount); + Core::active.shader->setParam(uBasis, joints[0], model->mCount); mesh->renderModel(entity.modelIndex - 1); } diff --git a/src/core.h b/src/core.h index 903be280..42150b8a 100644 --- a/src/core.h +++ b/src/core.h @@ -135,7 +135,8 @@ namespace Core { int width, height; int frameIndex; float deltaTime; - mat4 mView, mProj, mViewProj, mViewInv, mModel, mLightProj; + mat4 mView, mProj, mViewProj, mViewInv, mLightProj; + Basis basis; vec3 viewPos; vec3 lightPos[MAX_LIGHTS]; vec4 lightColor[MAX_LIGHTS]; diff --git a/src/enemy.h b/src/enemy.h index 49236f4b..2a86d285 100644 --- a/src/enemy.h +++ b/src/enemy.h @@ -211,7 +211,7 @@ struct Wolf : Enemy { if ((state == STATE_JUMP || state == STATE_BITE) && !bitten) { float dist; if (getTargetInfo(0, NULL, NULL, NULL, &dist) && dist < 256.0f) - bite(animation.getJoints(getMatrix(), JOINT_HEAD, true).getPos(), state == STATE_BITE ? 100 : 50); + bite(animation.getJoints(getMatrix(), JOINT_HEAD, true).pos, state == STATE_BITE ? 100 : 50); } if (state == STATE_JUMP) @@ -300,7 +300,7 @@ struct Bear : Enemy { if ((state == STATE_ATTACK || state == STATE_BITE) && !bitten) { float dist; if (getTargetInfo(0, NULL, NULL, NULL, &dist) && dist < 256.0f) - bite(animation.getJoints(getMatrix(), JOINT_HEAD, true).getPos(), state == STATE_BITE ? 100 : 50); + bite(animation.getJoints(getMatrix(), JOINT_HEAD, true).pos, state == STATE_BITE ? 100 : 50); } return state; diff --git a/src/lara.h b/src/lara.h index 2fe0aa6a..2f5a1ebc 100644 --- a/src/lara.h +++ b/src/lara.h @@ -300,7 +300,7 @@ struct Lara : Character { */ updateEntity(); #endif - chestOffset = animation.getJoints(getMatrix(), 7).getPos(); + chestOffset = animation.getJoints(getMatrix(), 7).pos; if (getRoom().flags.water) animation.setAnim(ANIM_UNDERWATER); } @@ -561,7 +561,7 @@ struct Lara : Character { int joint = wpnCurrent == Weapon::SHOTGUN ? 8 : (i ? 11 : 8); - vec3 p = animation.getJoints(getMatrix(), joint, false).getPos(); + vec3 p = animation.getJoints(getMatrix(), joint, false).pos; vec3 d = arm->rotAbs * vec3(0, 0, 1); vec3 t = p + d * (24.0f * 1024.0f) + ((vec3(randf(), randf(), randf()) * 2.0f) - vec3(1.0f)) * 1024.0f; @@ -582,7 +582,7 @@ struct Lara : Character { } } - Core::lightPos[1 + armIndex] = animation.getJoints(getMatrix(), armIndex == 0 ? 10 : 13, false).getPos(); + Core::lightPos[1 + armIndex] = animation.getJoints(getMatrix(), armIndex == 0 ? 10 : 13, false).pos; Core::lightColor[1 + armIndex] = FLASH_LIGHT_COLOR; } @@ -1050,7 +1050,7 @@ struct Lara : Character { } vec3 getViewPoint() { - vec3 offset = chestOffset = animation.getJoints(getMatrix(), 7).getPos(); + vec3 offset = chestOffset = animation.getJoints(getMatrix(), 7).pos; if (stand != STAND_UNDERWATER) offset.y -= 256.0f; if (!emptyHands()) @@ -1768,23 +1768,23 @@ struct Lara : Character { } - void renderMuzzleFlash(MeshBuilder *mesh, const mat4 &matrix, const vec3 &offset, float time) { + void renderMuzzleFlash(MeshBuilder *mesh, const Basis &basis, const vec3 &offset, float time) { ASSERT(level->extra.muzzleFlash); if (time > MUZZLE_FLASH_TIME) return; float alpha = min(1.0f, (0.1f - time) * 20.0f); float lum = 3.0f; - mat4 m(matrix); - m.rotateX(-PI * 0.5f); - m.translate(offset); + Basis b(basis); + b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f)); + b.translate(offset); Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha)); - Core::active.shader->setParam(uModel, m); + Core::active.shader->setParam(uBasis, b); mesh->renderModel(level->extra.muzzleFlash); } virtual void render(Frustum *frustum, MeshBuilder *mesh) { Controller::render(frustum, mesh); - chestOffset = animation.getJoints(getMatrix(), 7).getPos(); // TODO: move to update func + chestOffset = animation.getJoints(getMatrix(), 7).pos; // TODO: move to update func if (wpnCurrent != Weapon::SHOTGUN && Core::pass != Core::passShadow && (arms[0].shotTimer < MUZZLE_FLASH_TIME || arms[1].shotTimer < MUZZLE_FLASH_TIME)) { mat4 matrix = getMatrix(); diff --git a/src/level.h b/src/level.h index 6816b0ee..cbca4623 100644 --- a/src/level.h +++ b/src/level.h @@ -557,14 +557,13 @@ struct Level { if (Core::pass != Core::passShadow) { setRoomParams(room, intensityf(room.ambient)); - Shader *sh = Core::active.shader; - - sh->setParam(uType, Shader::ROOM); - mat4 mTemp = Core::mModel; - Core::mModel.translate(offset); + Basis qTemp = Core::basis; + Core::basis.translate(offset); - sh->setParam(uModel, Core::mModel); + Shader *sh = Core::active.shader; + sh->setParam(uType, Shader::ROOM); + sh->setParam(uBasis, Core::basis); // render room geometry mesh->renderRoomGeometry(roomIndex); @@ -577,7 +576,7 @@ struct Level { mesh->renderRoomSprites(roomIndex); } - Core::mModel = mTemp; + Core::basis = qTemp; } } @@ -728,7 +727,7 @@ struct Level { sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount); sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount); - Core::mModel.identity(); + Core::basis.identity(); // clear visibility flag for rooms for (int i = 0; i < level.roomsCount; i++) @@ -786,7 +785,7 @@ struct Level { } bool setupLightCamera() { - vec3 pos = (lara->animation.getJoints(lara->getMatrix(), 0, false, NULL)).getPos(); + vec3 pos = (lara->animation.getJoints(lara->getMatrix(), 0, false, NULL)).pos; // omni-spot light shadows int room = lara->getRoomIndex(); diff --git a/src/mesh.h b/src/mesh.h index 20029f4b..5b7e1270 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -211,7 +211,8 @@ struct MeshBuilder { TR::Model &model = level.models[i]; for (int j = 0; j < model.mCount; j++) { int index = level.meshOffsets[model.mStart + j]; - if (!index && model.mCount == 1) continue; + if (!index && model.mStart + j > 0) + continue; aCount++; TR::Mesh &mesh = level.meshes[index]; iCount += mesh.rCount * 6 + mesh.tCount * 3; @@ -337,7 +338,7 @@ struct MeshBuilder { for (int j = 0; j < model.mCount; j++) { int index = level.meshOffsets[model.mStart + j]; - if (!index && model.mCount == 1) continue; + if (!index && model.mStart + j > 0) continue; TR::Mesh &mesh = level.meshes[index]; buildMesh(mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0); @@ -725,9 +726,9 @@ struct MeshBuilder { Core::active.shader->setParam(uColor, color); //text = "a: b"; - mat4 m; - m.identity(); - m.translate(vec3(pos.x, pos.y, 0.0f)); + Basis basis; + basis.identity(); + basis.translate(vec3(pos.x, pos.y, 0.0f)); // text = "A"; while (char c = *text++) { @@ -749,13 +750,13 @@ struct MeshBuilder { } */ if (c == ' ' || c == '_') { - m.translate(vec3(char_width[0], 0.0f, 0.0f)); + basis.translate(vec3(char_width[0], 0.0f, 0.0f)); continue; } - Core::active.shader->setParam(uModel, m); + Core::active.shader->setParam(uBasis, basis); renderSprite(15, frame); - m.translate(vec3(char_width[frame], 0.0f, 0.0f)); + basis.translate(vec3(char_width[frame], 0.0f, 0.0f)); } } }; diff --git a/src/shader.glsl b/src/shader.glsl index bf278db4..d40fb625 100644 --- a/src/shader.glsl +++ b/src/shader.glsl @@ -26,7 +26,7 @@ uniform int uType; #ifdef VERTEX uniform mat4 uViewProj; - uniform mat4 uModel[32]; + uniform vec4 uBasis[32 * 2]; #ifndef PASS_AMBIENT uniform mat4 uViewInv; @@ -51,11 +51,21 @@ uniform int uType; #endif #define TEXCOORD_SCALE (1.0 / 32767.0) + + vec3 mulQuat(vec4 q, vec3 v) { + return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + v * q.w); + } + + vec3 mulBasis(vec4 rot, vec4 pos, vec3 v) { + return mulQuat(rot, v) + pos.xyz; + } void main() { - mat4 rJoint = uModel[int(aCoord.w)]; + int index = int(aCoord.w) * 2; + vec4 rBasisRot = uBasis[index]; + vec4 rBasisPos = uBasis[index + 1]; - vec4 coord = rJoint * vec4(aCoord.xyz, 1.0); + vec4 coord = vec4(mulBasis(rBasisRot, rBasisPos, aCoord.xyz), rBasisPos.w); #ifdef PASS_COMPOSE if (uType != TYPE_SPRITE) { @@ -66,7 +76,7 @@ uniform int uType; vec2 offset = uAnimTexOffsets[int(range.x + f)]; // texCoord offset from first frame vTexCoord = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated - vNormal = vec4((rJoint * vec4(aNormal.xyz, 0.0)).xyz, aNormal.w); + vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w); } else { coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w; vTexCoord = aTexCoord.xy * TEXCOORD_SCALE; diff --git a/src/shader.h b/src/shader.h index 2152fbf3..34957f07 100644 --- a/src/shader.h +++ b/src/shader.h @@ -5,11 +5,11 @@ enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX }; enum SamplerType { sDiffuse, sShadow, sEnvironment, sMAX }; -enum UniformType { uType, uCaustics, uTime, uViewProj, uViewInv, uModel, uLightProj, uColor, uAmbient, uViewPos, uLightsCount, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uMAX }; +enum UniformType { uType, uCaustics, uTime, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightsCount, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uMAX }; const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" }; const char *SamplerName[sMAX] = { "sDiffuse", "sShadow", "sEnvironment" }; -const char *UniformName[uMAX] = { "uType", "uCaustics", "uTime", "uViewProj", "uViewInv", "uModel", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightsCount", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets" }; +const char *UniformName[uMAX] = { "uType", "uCaustics", "uTime", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightsCount", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets" }; struct Shader { GLuint ID; @@ -103,6 +103,11 @@ struct Shader { if (uID[uType] != -1) glUniformMatrix4fv(uID[uType], count, false, (GLfloat*)&value); } + + void setParam(UniformType uType, const Basis &value, int count = 1) { + if (uID[uType] != -1) + glUniform4fv(uID[uType], count * 2, (GLfloat*)&value); + } }; #endif \ No newline at end of file diff --git a/src/sprite.h b/src/sprite.h index 424ed6bc..259611b1 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -60,9 +60,9 @@ struct Sprite : Controller { } virtual void render(Frustum *frustum, MeshBuilder *mesh) { - mat4 m(Core::mModel); - m.translate(pos); - Core::active.shader->setParam(uModel, m); + Basis basis(Core::basis); + basis.translate(pos); + Core::active.shader->setParam(uBasis, basis); mesh->renderSprite(-(getEntity().modelIndex + 1), frame); } }; diff --git a/src/utils.h b/src/utils.h index 7c2f6552..85ca2a5c 100644 --- a/src/utils.h +++ b/src/utils.h @@ -126,7 +126,8 @@ struct vec3 { vec3 operator + (const vec3 &v) const { return vec3(x+v.x, y+v.y, z+v.z); } vec3 operator - (const vec3 &v) const { return vec3(x-v.x, y-v.y, z-v.z); } vec3 operator * (const vec3 &v) const { return vec3(x*v.x, y*v.y, z*v.z); } - vec3 operator * (float s) const { return vec3(x*s, y*s, z*s); } + vec3 operator * (float s) const { return vec3(x*s, y*s, z*s); } + vec3 operator - () const { return vec3(-x, -y, -z); } float dot(const vec3 &v) const { return x*v.x + y*v.y + z*v.z; } vec3 cross(const vec3 &v) const { return vec3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x); } @@ -509,6 +510,43 @@ struct mat4 { } }; +struct Basis { + quat rot; + vec3 pos; + float w; + + Basis() {} + Basis(const quat &rot, const vec3 &pos) : rot(rot), pos(pos), w(1.0f) {} + Basis(const mat4 &matrix) : rot(matrix.getRot()), pos(matrix.getPos()), w(1.0f) {} + + void identity() { + rot = quat(0, 0, 0, 1); + pos = vec3(0, 0, 0); + w = 1.0f; + } + + Basis operator * (const Basis &basis) const { + return Basis(rot * basis.rot, pos + rot * basis.pos); + } + + vec3 operator * (const vec3 &v) const { + return rot * v + pos; + } + + Basis inverse() const { + quat q = rot.conjugate(); + return Basis(q, -(q * pos)); + } + + void translate(const vec3 &v) { + pos += rot * v; + } + + void rotate(const quat &q) { + rot = rot * q; + } +}; + struct ubyte2 { uint8 x, y; };