/**Calculate a slice plane given the defined parameters. */ SlicePlane SliceComputer::getPlane() const { std::pair<Vector3D,Vector3D> basis = generateBasisVectors(); SlicePlane plane; plane.i = basis.first; plane.j = basis.second; plane.c = Vector3D(0,0,mToolOffset); // transform position from tool to reference space plane.c = m_rMt.coord(plane.c); // transform orientation from tool to reference space for the oblique case only if (mOrientType==otOBLIQUE) { plane.i = m_rMt.vector(plane.i); plane.j = m_rMt.vector(plane.j); } // orient planes so that gravity is down plane = orientToGravity(plane); // try to to this also for oblique views, IF the ftFIXED_CENTER is set. // use special acs centermod algo plane.c = generateFixedIJCenter(mFixedCenter, plane.c, plane.i, plane.j); // set center so that it is a fixed distance from viewport top plane = applyViewOffset(plane); return plane; }
// rotate bone's y-axis with target. AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone) { glm::vec3 u, v, w; generateBasisVectors(target - bone.trans(), bone.rot() * Vectors::UNIT_X, u, v, w); glm::mat4 lookAt(glm::vec4(v, 0.0f), glm::vec4(u, 0.0f), // AJT: TODO REVISIT THIS, this could be -w. glm::vec4(glm::normalize(glm::cross(v, u)), 0.0f), glm::vec4(bone.trans(), 1.0f)); return AnimPose(lookAt); }
// This will attempt to determine the proper body facing of a characters body // assumes headRot is z-forward and y-up. // and returns a bodyRot that is also z-forward and y-up glm::quat computeBodyFacingFromHead(const glm::quat& headRot, const glm::vec3& up) { glm::vec3 bodyUp = glm::normalize(up); // initially take the body facing from the head. glm::vec3 headUp = headRot * Vectors::UNIT_Y; glm::vec3 headForward = headRot * Vectors::UNIT_Z; glm::vec3 headLeft = headRot * Vectors::UNIT_X; const float NOD_THRESHOLD = cosf(glm::radians(45.0f)); const float TILT_THRESHOLD = cosf(glm::radians(30.0f)); glm::vec3 bodyForward = headForward; float nodDot = glm::dot(headForward, bodyUp); float tiltDot = glm::dot(headLeft, bodyUp); if (fabsf(tiltDot) < TILT_THRESHOLD) { // if we are not tilting too much if (nodDot < -NOD_THRESHOLD) { // head is looking downward // the body should face in the same direction as the top the head. bodyForward = headUp; } else if (nodDot > NOD_THRESHOLD) { // head is looking upward // the body should face away from the top of the head. bodyForward = -headUp; } } // cancel out upward component bodyForward = glm::normalize(bodyForward - nodDot * bodyUp); glm::vec3 u, v, w; generateBasisVectors(bodyForward, bodyUp, u, v, w); // create matrix from orthogonal basis vectors glm::mat4 bodyMat(glm::vec4(w, 0.0f), glm::vec4(v, 0.0f), glm::vec4(u, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); return glmExtractRotation(bodyMat); }
void GLMHelpersTests::testGenerateBasisVectors() { { // very simple case: primary along X, secondary is linear combination of X and Y glm::vec3 u(1.0f, 0.0f, 0.0f); glm::vec3 v(1.0f, 1.0f, 0.0f); glm::vec3 w; generateBasisVectors(u, v, u, v, w); QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_X, EPSILON); QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_Y, EPSILON); QCOMPARE_WITH_ABS_ERROR(w, Vectors::UNIT_Z, EPSILON); } { // point primary along Y instead of X glm::vec3 u(0.0f, 1.0f, 0.0f); glm::vec3 v(1.0f, 1.0f, 0.0f); glm::vec3 w; generateBasisVectors(u, v, u, v, w); QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_Y, EPSILON); QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_X, EPSILON); QCOMPARE_WITH_ABS_ERROR(w, -Vectors::UNIT_Z, EPSILON); } { // pass bad data (both vectors along Y). The helper will guess X for secondary. glm::vec3 u(0.0f, 1.0f, 0.0f); glm::vec3 v(0.0f, 1.0f, 0.0f); glm::vec3 w; generateBasisVectors(u, v, u, v, w); QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_Y, EPSILON); QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_X, EPSILON); QCOMPARE_WITH_ABS_ERROR(w, -Vectors::UNIT_Z, EPSILON); } { // pass bad data (both vectors along X). The helper will guess X for secondary, fail, then guess Y. glm::vec3 u(1.0f, 0.0f, 0.0f); glm::vec3 v(1.0f, 0.0f, 0.0f); glm::vec3 w; generateBasisVectors(u, v, u, v, w); QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_X, EPSILON); QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_Y, EPSILON); QCOMPARE_WITH_ABS_ERROR(w, Vectors::UNIT_Z, EPSILON); } { // general case for arbitrary rotation float angle = 1.234f; glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); glm::quat rotation = glm::angleAxis(angle, axis); // expected values glm::vec3 x = rotation * Vectors::UNIT_X; glm::vec3 y = rotation * Vectors::UNIT_Y; glm::vec3 z = rotation * Vectors::UNIT_Z; // primary is along x // secondary is linear combination of x and y // tertiary is unknown glm::vec3 u = 1.23f * x; glm::vec3 v = 2.34f * x + 3.45f * y; glm::vec3 w; generateBasisVectors(u, v, u, v, w); QCOMPARE_WITH_ABS_ERROR(u, x, EPSILON); QCOMPARE_WITH_ABS_ERROR(v, y, EPSILON); QCOMPARE_WITH_ABS_ERROR(w, z, EPSILON); } }
static void addLink(const AnimPose& rootPose, const AnimPose& pose, const AnimPose& parentPose, float radius, const glm::vec4& colorVec, AnimDebugDrawData::Vertex*& v) { uint32_t color = toRGBA(colorVec); AnimPose pose0 = rootPose * parentPose; AnimPose pose1 = rootPose * pose; glm::vec3 boneAxisWorld = glm::normalize(pose1.trans() - pose0.trans()); glm::vec3 boneAxis0 = glm::normalize(pose0.inverse().xformVector(boneAxisWorld)); glm::vec3 boneAxis1 = glm::normalize(pose1.inverse().xformVector(boneAxisWorld)); glm::vec3 boneBase = pose0 * (boneAxis0 * radius); glm::vec3 boneTip = pose1 * (boneAxis1 * -radius); const int NUM_BASE_CORNERS = 4; // make sure there's room between the two bones to draw a nice bone link. if (glm::dot(boneTip - pose0.trans(), boneAxisWorld) > glm::dot(boneBase - pose0.trans(), boneAxisWorld)) { // there is room, so lets draw a nice bone glm::vec3 uAxis, vAxis, wAxis; generateBasisVectors(boneAxis0, glm::vec3(1.0f, 0.0f, 0.0f), uAxis, vAxis, wAxis); glm::vec3 boneBaseCorners[NUM_BASE_CORNERS]; boneBaseCorners[0] = pose0 * ((uAxis * radius) + (vAxis * radius) + (wAxis * radius)); boneBaseCorners[1] = pose0 * ((uAxis * radius) - (vAxis * radius) + (wAxis * radius)); boneBaseCorners[2] = pose0 * ((uAxis * radius) - (vAxis * radius) - (wAxis * radius)); boneBaseCorners[3] = pose0 * ((uAxis * radius) + (vAxis * radius) - (wAxis * radius)); for (int i = 0; i < NUM_BASE_CORNERS; i++) { v->pos = boneBaseCorners[i]; v->rgba = color; v++; v->pos = boneBaseCorners[(i + 1) % NUM_BASE_CORNERS]; v->rgba = color; v++; } for (int i = 0; i < NUM_BASE_CORNERS; i++) { v->pos = boneBaseCorners[i]; v->rgba = color; v++; v->pos = boneTip; v->rgba = color; v++; } } else { // There's no room between the bones to draw the link. // just draw a line between the two bone centers. // We add the same line multiple times, so the vertex count is correct. for (int i = 0; i < NUM_BASE_CORNERS * 2; i++) { v->pos = pose0.trans(); v->rgba = color; v++; v->pos = pose1.trans(); v->rgba = color; v++; } } }