1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-01-17 21:09:00 +01:00

#16 transform meshes by quaternion & pos instead of matrix

This commit is contained in:
XProger 2016-12-28 01:18:12 +03:00
parent d1bd39abfd
commit 687db8a01a
12 changed files with 113 additions and 59 deletions

Binary file not shown.

View File

@ -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) {

View File

@ -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);
}

View File

@ -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];

View File

@ -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;

View File

@ -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();

View File

@ -557,14 +557,13 @@ struct Level {
if (Core::pass != Core::passShadow) {
setRoomParams(room, intensityf(room.ambient));
Basis qTemp = Core::basis;
Core::basis.translate(offset);
Shader *sh = Core::active.shader;
sh->setParam(uType, Shader::ROOM);
mat4 mTemp = Core::mModel;
Core::mModel.translate(offset);
sh->setParam(uModel, Core::mModel);
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();

View File

@ -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));
}
}
};

View File

@ -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;

View File

@ -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

View File

@ -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);
}
};

View File

@ -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;
};