Work around precision issues with multiplying matrices with high translation

magnitudes (by using relative translation).
This commit is contained in:
Andrzej Kapolka 2013-11-04 16:49:12 -08:00
parent 4cc650835d
commit b2ed29dbff
5 changed files with 37 additions and 19 deletions

View file

@ -2866,6 +2866,12 @@ void Application::setupWorldLight(Camera& whichCamera) {
glMateriali(GL_FRONT, GL_SHININESS, 96);
}
void Application::loadTranslatedViewMatrix(const glm::vec3& translation) {
glLoadMatrixf((const GLfloat*)&_untranslatedViewMatrix);
glTranslatef(translation.x + _viewMatrixTranslation.x, translation.y + _viewMatrixTranslation.y,
translation.z + _viewMatrixTranslation.z);
}
void Application::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& near,
float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const {
@ -2899,7 +2905,11 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
glm::vec3 axis = glm::axis(rotation);
glRotatef(-glm::angle(rotation), axis.x, axis.y, axis.z);
glTranslatef(-whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z);
// store view matrix without translation, which we'll use for precision-sensitive objects
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);
_viewMatrixTranslation = -whichCamera.getPosition();
glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z);
// Setup 3D lights (after the camera transform, so that they are positioned in world space)
setupWorldLight(whichCamera);

View file

@ -152,6 +152,10 @@ public:
void setupWorldLight(Camera& whichCamera);
/// Loads a view matrix that incorporates the specified model translation without the precision issues that can
/// result from matrix multiplication at high translation magnitudes.
void loadTranslatedViewMatrix(const glm::vec3& translation);
/// Computes the off-axis frustum parameters for the view frustum, taking mirroring into account.
void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& near,
float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
@ -337,6 +341,9 @@ private:
QRect _mirrorViewRect;
RearMirrorTools* _rearMirrorTools;
glm::mat4 _untranslatedViewMatrix;
glm::vec3 _viewMatrixTranslation;
Environment _environment;
int _headMouseX, _headMouseY;

View file

@ -62,7 +62,7 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation));
glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getOrientation() * IDENTITY_FRONT, 0.0f));
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
_owningHead->getSaccade(), 1.0f));
_owningHead->getSaccade() - _translation, 1.0f));
glm::quat between = rotationBetween(front, lookAt);
const float MAX_ANGLE = 30.0f;
state.rotation = glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) *

View file

@ -8,6 +8,7 @@
#include <glm/gtx/transform.hpp>
#include "Application.h"
#include "Avatar.h"
#include "SkeletonModel.h"
@ -47,7 +48,7 @@ bool SkeletonModel::render(float alpha) {
glm::vec3 position;
getJointPosition(i, position);
glTranslatef(position.x, position.y, position.z);
Application::getInstance()->loadTranslatedViewMatrix(position);
glm::quat rotation;
getJointRotation(i, rotation);
@ -85,9 +86,9 @@ void SkeletonModel::updateJointState(int index) {
if (index == _geometry->getFBXGeometry().rootJointIndex) {
JointState& state = _jointStates[index];
state.transform[3][0] = _translation.x;
state.transform[3][1] = _translation.y;
state.transform[3][2] = _translation.z;
state.transform[3][0] = 0.0f;
state.transform[3][1] = 0.0f;
state.transform[3][2] = 0.0f;
}
}

View file

@ -175,7 +175,7 @@ void Model::simulate(float deltaTime) {
}
sourceVertices = _blendedVertices.constData();
}
glm::mat4 transform;
glm::mat4 transform = glm::translate(_translation);
if (mesh.clusters.size() > 1) {
_blendedVertices.resize(max(_blendedVertices.size(), vertexCount));
@ -283,6 +283,9 @@ bool Model::render(float alpha) {
ProgramObject* activeProgram = program;
int tangentLocation = _normalMapTangentLocation;
if (state.worldSpaceVertices.isEmpty()) {
glPushMatrix();
Application::getInstance()->loadTranslatedViewMatrix(_translation);
if (state.clusterMatrices.size() > 1) {
skinProgram->bind();
glUniformMatrix4fvARB(skinLocations->clusterMatrices, state.clusterMatrices.size(), false,
@ -299,7 +302,6 @@ bool Model::render(float alpha) {
tangentLocation = skinLocations->tangent;
} else {
glPushMatrix();
glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]);
program->bind();
}
@ -428,10 +430,8 @@ bool Model::render(float alpha) {
if (state.clusterMatrices.size() > 1) {
skinProgram->disableAttributeArray(skinLocations->clusterIndices);
skinProgram->disableAttributeArray(skinLocations->clusterWeights);
} else {
glPopMatrix();
}
glPopMatrix();
}
activeProgram->release();
}
@ -513,8 +513,7 @@ void Model::updateJointState(int index) {
const FBXJoint& joint = geometry.joints.at(index);
if (joint.parentIndex == -1) {
glm::mat4 baseTransform = glm::translate(_translation) * glm::mat4_cast(_rotation) *
glm::scale(_scale) * glm::translate(_offset);
glm::mat4 baseTransform = glm::mat4_cast(_rotation) * glm::scale(_scale) * glm::translate(_offset);
glm::quat combinedRotation = joint.preRotation * state.rotation * joint.postRotation;
state.transform = baseTransform * geometry.offset * joint.preTransform *
@ -555,7 +554,7 @@ bool Model::getJointPosition(int jointIndex, glm::vec3& position) const {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return false;
}
position = extractTranslation(_jointStates[jointIndex].transform);
position = _translation + extractTranslation(_jointStates[jointIndex].transform);
return true;
}
@ -572,6 +571,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position) {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return false;
}
glm::vec3 relativePosition = position - _translation;
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage;
@ -583,7 +583,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position) {
glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].transform);
for (int j = 1; j < freeLineage.size(); j++) {
int index = freeLineage.at(j);
if (glm::distance(endPosition, position) < EPSILON) {
if (glm::distance(endPosition, relativePosition) < EPSILON) {
return true; // close enough to target position
}
const FBXJoint& joint = geometry.joints.at(index);
@ -593,7 +593,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position) {
JointState& state = _jointStates[index];
glm::vec3 jointPosition = extractTranslation(state.transform);
glm::vec3 jointVector = endPosition - jointPosition;
glm::quat deltaRotation = rotationBetween(jointVector, position - jointPosition);
glm::quat deltaRotation = rotationBetween(jointVector, relativePosition - jointPosition);
state.rotation = state.rotation * glm::inverse(state.combinedRotation) * deltaRotation * state.combinedRotation;
endPosition = deltaRotation * jointVector + jointPosition;
}