void LLLMImpl::moveFlycam() { if(!mOverrideCamera) { return; } // simple feathering of the positional data mFlycamFeatheredDelta+=(mFlycamDelta-mFlycamFeatheredDelta)/10.0f; // simple feathering of the rotational data mFlycamFeatheredRot+=(mFlycamRot-mFlycamFeatheredRot)/10.0f; LLQuaternion final_flycam_rot=mayaQ( mFlycamFeatheredRot.mV[VX], mFlycamFeatheredRot.mV[VY], mFlycamFeatheredRot.mV[VZ], LLQuaternion::XYZ ); final_flycam_rot=final_flycam_rot*mayaQ( 0.0f, 0.0f, mFlycamFeatheredRot.mV[VZ], LLQuaternion::XYZ ); final_flycam_rot=final_flycam_rot*mFlycamInitialRot; mFlycamPos+=mFlycamFeatheredDelta*final_flycam_rot; LLViewerCamera::instance().setView(LLViewerCamera::instance().getView()); LLViewerCamera::instance().setOrigin(mFlycamPos); LLMatrix3 mat(final_flycam_rot); LLViewerCamera::instance().mXAxis=LLVector3(mat.mMatrix[0]); LLViewerCamera::instance().mYAxis=LLVector3(mat.mMatrix[1]); LLViewerCamera::instance().mZAxis=LLVector3(mat.mMatrix[2]); }
void llquat_test_object_t::test<17>() { //test case for LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) F32 x = 2.0f; F32 y = 1.0f; F32 z = 3.0f; LLQuaternion result = mayaQ(x, y, z, LLQuaternion::XYZ); ensure( "1. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for XYZ", is_approx_equal_fraction(0.0172174f, result.mQ[0], 16) && is_approx_equal_fraction(0.009179f, result.mQ[1], 16) && is_approx_equal_fraction(0.026020f, result.mQ[2], 16) && is_approx_equal_fraction(0.999471f, result.mQ[3], 16)); LLQuaternion result1 = mayaQ(x, y, z, LLQuaternion::YZX); ensure( "2. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for XYZ", is_approx_equal_fraction(0.017217f, result1.mQ[0], 16) && is_approx_equal_fraction(0.008265f, result1.mQ[1], 16) && is_approx_equal_fraction(0.026324f, result1.mQ[2], 16) && is_approx_equal_fraction(0.999471f, result1.mQ[3], 16)); LLQuaternion result2 = mayaQ(x, y, z, LLQuaternion::ZXY); ensure( "3. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for ZXY", is_approx_equal_fraction(0.017674f, result2.mQ[0], 16) && is_approx_equal_fraction(0.008265f, result2.mQ[1], 16) && is_approx_equal_fraction(0.026020f, result2.mQ[2], 16) && is_approx_equal_fraction(0.999471f, result2.mQ[3], 16)); LLQuaternion result3 = mayaQ(x, y, z, LLQuaternion::XZY); ensure( "4. TLLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for XZY", is_approx_equal_fraction(0.017674f, result3.mQ[0], 16) && is_approx_equal_fraction(0.009179f, result3.mQ[1], 16) && is_approx_equal_fraction(0.026020f, result3.mQ[2], 16) && is_approx_equal_fraction(0.999463f, result3.mQ[3], 16)); LLQuaternion result4 = mayaQ(x, y, z, LLQuaternion::YXZ); ensure( "5. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for YXZ", is_approx_equal_fraction(0.017217f, result4.mQ[0], 16) && is_approx_equal_fraction(0.009179f, result4.mQ[1], 16) && is_approx_equal_fraction(0.026324f, result4.mQ[2], 16) && is_approx_equal_fraction(0.999463f, result4.mQ[3], 16)); LLQuaternion result5 = mayaQ(x, y, z, LLQuaternion::ZYX); ensure( "6. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for ZYX", is_approx_equal_fraction(0.017674f, result5.mQ[0], 16) && is_approx_equal_fraction(0.008265f, result5.mQ[1], 16) && is_approx_equal_fraction(0.026324f, result5.mQ[2], 16) && is_approx_equal_fraction(0.999463f, result5.mQ[3], 16)); }
//-------------------------------------------------------------------- // LLPolyMeshSharedData::loadMesh() //-------------------------------------------------------------------- BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) { //------------------------------------------------------------------------- // Open the file //------------------------------------------------------------------------- if(fileName.empty()) { LL_ERRS() << "Filename is Empty!" << LL_ENDL; return FALSE; } LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/ if (!fp) { LL_ERRS() << "can't open: " << fileName << LL_ENDL; return FALSE; } //------------------------------------------------------------------------- // Read a chunk //------------------------------------------------------------------------- char header[128]; /*Flawfinder: ignore*/ if (fread(header, sizeof(char), 128, fp) != 128) { LL_WARNS() << "Short read" << LL_ENDL; } //------------------------------------------------------------------------- // Check for proper binary header //------------------------------------------------------------------------- BOOL status = FALSE; if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/ { LL_DEBUGS() << "Loading " << fileName << LL_ENDL; //---------------------------------------------------------------- // File Header (seek past it) //---------------------------------------------------------------- fseek(fp, 24, SEEK_SET); //---------------------------------------------------------------- // HasWeights //---------------------------------------------------------------- U8 hasWeights; size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp); if (numRead != 1) { LL_ERRS() << "can't read HasWeights flag from " << fileName << LL_ENDL; return FALSE; } if (!isLOD()) { mHasWeights = (hasWeights==0) ? FALSE : TRUE; } //---------------------------------------------------------------- // HasDetailTexCoords //---------------------------------------------------------------- U8 hasDetailTexCoords; numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp); if (numRead != 1) { LL_ERRS() << "can't read HasDetailTexCoords flag from " << fileName << LL_ENDL; return FALSE; } //---------------------------------------------------------------- // Position //---------------------------------------------------------------- LLVector3 position; numRead = fread(position.mV, sizeof(float), 3, fp); llendianswizzle(position.mV, sizeof(float), 3); if (numRead != 3) { LL_ERRS() << "can't read Position from " << fileName << LL_ENDL; return FALSE; } setPosition( position ); //---------------------------------------------------------------- // Rotation //---------------------------------------------------------------- LLVector3 rotationAngles; numRead = fread(rotationAngles.mV, sizeof(float), 3, fp); llendianswizzle(rotationAngles.mV, sizeof(float), 3); if (numRead != 3) { LL_ERRS() << "can't read RotationAngles from " << fileName << LL_ENDL; return FALSE; } U8 rotationOrder; numRead = fread(&rotationOrder, sizeof(U8), 1, fp); if (numRead != 1) { LL_ERRS() << "can't read RotationOrder from " << fileName << LL_ENDL; return FALSE; } rotationOrder = 0; setRotation( mayaQ( rotationAngles.mV[0], rotationAngles.mV[1], rotationAngles.mV[2], (LLQuaternion::Order)rotationOrder ) ); //---------------------------------------------------------------- // Scale //---------------------------------------------------------------- LLVector3 scale; numRead = fread(scale.mV, sizeof(float), 3, fp); llendianswizzle(scale.mV, sizeof(float), 3); if (numRead != 3) { LL_ERRS() << "can't read Scale from " << fileName << LL_ENDL; return FALSE; } setScale( scale ); //------------------------------------------------------------------------- // Release any existing mesh geometry //------------------------------------------------------------------------- freeMeshData(); U16 numVertices = 0; //---------------------------------------------------------------- // NumVertices //---------------------------------------------------------------- if (!isLOD()) { numRead = fread(&numVertices, sizeof(U16), 1, fp); llendianswizzle(&numVertices, sizeof(U16), 1); if (numRead != 1) { LL_ERRS() << "can't read NumVertices from " << fileName << LL_ENDL; return FALSE; } allocateVertexData( numVertices ); for (U16 i = 0; i < numVertices; ++i) { //---------------------------------------------------------------- // Coords //---------------------------------------------------------------- numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp); llendianswizzle(&mBaseCoords[i], sizeof(float), 3); if (numRead != 3) { LL_ERRS() << "can't read Coordinates from " << fileName << LL_ENDL; return FALSE; } } for (U16 i = 0; i < numVertices; ++i) { //---------------------------------------------------------------- // Normals //---------------------------------------------------------------- numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp); llendianswizzle(&mBaseNormals[i], sizeof(float), 3); if (numRead != 3) { LL_ERRS() << " can't read Normals from " << fileName << LL_ENDL; return FALSE; } } for (U16 i = 0; i < numVertices; ++i) { //---------------------------------------------------------------- // Binormals //---------------------------------------------------------------- numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp); llendianswizzle(&mBaseBinormals[i], sizeof(float), 3); if (numRead != 3) { LL_ERRS() << " can't read Binormals from " << fileName << LL_ENDL; return FALSE; } } //---------------------------------------------------------------- // TexCoords //---------------------------------------------------------------- numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp); llendianswizzle(mTexCoords, sizeof(float), 2*numVertices); if (numRead != numVertices) { LL_ERRS() << "can't read TexCoords from " << fileName << LL_ENDL; return FALSE; } //---------------------------------------------------------------- // DetailTexCoords //---------------------------------------------------------------- if (mHasDetailTexCoords) { numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp); llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices); if (numRead != numVertices) { LL_ERRS() << "can't read DetailTexCoords from " << fileName << LL_ENDL; return FALSE; } } //---------------------------------------------------------------- // Weights //---------------------------------------------------------------- if (mHasWeights) { numRead = fread(mWeights, sizeof(float), numVertices, fp); llendianswizzle(mWeights, sizeof(float), numVertices); if (numRead != numVertices) { LL_ERRS() << "can't read Weights from " << fileName << LL_ENDL; return FALSE; } } } //---------------------------------------------------------------- // NumFaces //---------------------------------------------------------------- U16 numFaces; numRead = fread(&numFaces, sizeof(U16), 1, fp); llendianswizzle(&numFaces, sizeof(U16), 1); if (numRead != 1) { LL_ERRS() << "can't read NumFaces from " << fileName << LL_ENDL; return FALSE; } allocateFaceData( numFaces ); //---------------------------------------------------------------- // Faces //---------------------------------------------------------------- U32 i; U32 numTris = 0; for (i = 0; i < numFaces; i++) { S16 face[3]; numRead = fread(face, sizeof(U16), 3, fp); llendianswizzle(face, sizeof(U16), 3); if (numRead != 3) { LL_ERRS() << "can't read Face[" << i << "] from " << fileName << LL_ENDL; return FALSE; } if (mReferenceData) { llassert(face[0] < mReferenceData->mNumVertices); llassert(face[1] < mReferenceData->mNumVertices); llassert(face[2] < mReferenceData->mNumVertices); } if (isLOD()) { // store largest index in case of LODs for (S32 j = 0; j < 3; j++) { if (face[j] > mNumVertices - 1) { mNumVertices = face[j] + 1; } } } mFaces[i][0] = face[0]; mFaces[i][1] = face[1]; mFaces[i][2] = face[2]; // S32 j; // for(j = 0; j < 3; j++) // { // std::vector<S32> *face_list = mVertFaceMap.getIfThere(face[j]); // if (!face_list) // { // face_list = new std::vector<S32>; // mVertFaceMap.addData(face[j], face_list); // } // face_list->put(i); // } numTris++; } LL_DEBUGS() << "verts: " << numVertices << ", faces: " << numFaces << ", tris: " << numTris << LL_ENDL; //---------------------------------------------------------------- // NumSkinJoints //---------------------------------------------------------------- if (!isLOD()) { U16 numSkinJoints = 0; if ( mHasWeights ) { numRead = fread(&numSkinJoints, sizeof(U16), 1, fp); llendianswizzle(&numSkinJoints, sizeof(U16), 1); if (numRead != 1) { LL_ERRS() << "can't read NumSkinJoints from " << fileName << LL_ENDL; return FALSE; } allocateJointNames( numSkinJoints ); } //---------------------------------------------------------------- // SkinJoints //---------------------------------------------------------------- for (i=0; i < numSkinJoints; i++) { char jointName[64+1]; numRead = fread(jointName, sizeof(jointName)-1, 1, fp); jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination if (numRead != 1) { LL_ERRS() << "can't read Skin[" << i << "].Name from " << fileName << LL_ENDL; return FALSE; } std::string *jn = &mJointNames[i]; *jn = jointName; } //------------------------------------------------------------------------- // look for morph section //------------------------------------------------------------------------- char morphName[64+1]; morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination while(fread(&morphName, sizeof(char), 64, fp) == 64) { if (!strcmp(morphName, "End Morphs")) { // we reached the end of the morphs break; } LLPolyMorphData* morph_data = new LLPolyMorphData(std::string(morphName)); BOOL result = morph_data->loadBinary(fp, this); if (!result) { delete morph_data; continue; } mMorphData.insert(morph_data); if (!strcmp(morphName, "Breast_Female_Cleavage")) { mMorphData.insert(clone_morph_param_cleavage(morph_data, .75f, "Breast_Physics_LeftRight_Driven")); } if (!strcmp(morphName, "Breast_Female_Cleavage")) { mMorphData.insert(clone_morph_param_duplicate(morph_data, "Breast_Physics_InOut_Driven")); } if (!strcmp(morphName, "Breast_Gravity")) { mMorphData.insert(clone_morph_param_duplicate(morph_data, "Breast_Physics_UpDown_Driven")); } if (!strcmp(morphName, "Big_Belly_Torso")) { mMorphData.insert(clone_morph_param_direction(morph_data, LLVector3(0,0,0.05f), "Belly_Physics_Torso_UpDown_Driven")); } if (!strcmp(morphName, "Big_Belly_Legs")) { mMorphData.insert(clone_morph_param_direction(morph_data, LLVector3(0,0,0.05f), "Belly_Physics_Legs_UpDown_Driven")); } if (!strcmp(morphName, "skirt_belly")) { mMorphData.insert(clone_morph_param_direction(morph_data, LLVector3(0,0,0.05f), "Belly_Physics_Skirt_UpDown_Driven")); } if (!strcmp(morphName, "Small_Butt")) { mMorphData.insert(clone_morph_param_direction(morph_data, LLVector3(0,0,0.05f), "Butt_Physics_UpDown_Driven")); } if (!strcmp(morphName, "Small_Butt")) { mMorphData.insert(clone_morph_param_direction(morph_data, LLVector3(0,0.03f,0), "Butt_Physics_LeftRight_Driven")); } } S32 numRemaps; if (fread(&numRemaps, sizeof(S32), 1, fp) == 1) { llendianswizzle(&numRemaps, sizeof(S32), 1); for (S32 i = 0; i < numRemaps; i++) { S32 remapSrc; S32 remapDst; if (fread(&remapSrc, sizeof(S32), 1, fp) != 1) { LL_ERRS() << "can't read source vertex in vertex remap data" << LL_ENDL; break; } if (fread(&remapDst, sizeof(S32), 1, fp) != 1) { LL_ERRS() << "can't read destination vertex in vertex remap data" << LL_ENDL; break; } llendianswizzle(&remapSrc, sizeof(S32), 1); llendianswizzle(&remapDst, sizeof(S32), 1); mSharedVerts[remapSrc] = remapDst; } } } status = TRUE; } else { LL_ERRS() << "invalid mesh file header: " << fileName << LL_ENDL; status = FALSE; } if (0 == mNumJointNames) { allocateJointNames(1); } fclose( fp ); return status; }
// writes contents to datapacker BOOL LLBVHLoader::serialize(LLDataPacker& dp) { JointVector::iterator ji; KeyVector::iterator ki; F32 time; // count number of non-ignored joints S32 numJoints = 0; for (ji=mJoints.begin(); ji!=mJoints.end(); ++ji) { Joint *joint = *ji; if ( ! joint->mIgnore ) numJoints++; } // print header dp.packU16(KEYFRAME_MOTION_VERSION, "version"); dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version"); dp.packS32(mPriority, "base_priority"); dp.packF32(mDuration, "duration"); dp.packString(mEmoteName, "emote_name"); dp.packF32(mLoopInPoint, "loop_in_point"); dp.packF32(mLoopOutPoint, "loop_out_point"); dp.packS32(mLoop, "loop"); dp.packF32(mEaseIn, "ease_in_duration"); dp.packF32(mEaseOut, "ease_out_duration"); dp.packU32(mHand, "hand_pose"); dp.packU32(numJoints, "num_joints"); for ( ji = mJoints.begin(); ji != mJoints.end(); ++ji ) { Joint *joint = *ji; // if ignored, skip it if ( joint->mIgnore ) continue; LLQuaternion first_frame_rot; LLQuaternion fixup_rot; dp.packString(joint->mOutName, "joint_name"); dp.packS32(joint->mPriority, "joint_priority"); // compute coordinate frame rotation LLQuaternion frameRot( joint->mFrameMatrix ); LLQuaternion frameRotInv = ~frameRot; LLQuaternion offsetRot( joint->mOffsetMatrix ); // find mergechild and mergeparent joints, if specified LLQuaternion mergeParentRot; LLQuaternion mergeChildRot; Joint *mergeParent = NULL; Joint *mergeChild = NULL; JointVector::iterator mji; for (mji=mJoints.begin(); mji!=mJoints.end(); ++mji) { Joint *mjoint = *mji; if ( !joint->mMergeParentName.empty() && (mjoint->mName == joint->mMergeParentName) ) { mergeParent = *mji; } if ( !joint->mMergeChildName.empty() && (mjoint->mName == joint->mMergeChildName) ) { mergeChild = *mji; } } dp.packS32(joint->mNumRotKeys, "num_rot_keys"); LLQuaternion::Order order = bvhStringToOrder( joint->mOrder ); S32 outcount = 0; S32 frame = 1; for ( ki = joint->mKeys.begin(); ki != joint->mKeys.end(); ++ki ) { if ((frame == 1) && joint->mRelativeRotationKey) { first_frame_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order); fixup_rot.shortestArc(LLVector3::z_axis * first_frame_rot * frameRot, LLVector3::z_axis); } if (ki->mIgnoreRot) { frame++; continue; } time = (F32)frame * mFrameTime; if (mergeParent) { mergeParentRot = mayaQ( mergeParent->mKeys[frame-1].mRot[0], mergeParent->mKeys[frame-1].mRot[1], mergeParent->mKeys[frame-1].mRot[2], bvhStringToOrder(mergeParent->mOrder) ); LLQuaternion parentFrameRot( mergeParent->mFrameMatrix ); LLQuaternion parentOffsetRot( mergeParent->mOffsetMatrix ); mergeParentRot = ~parentFrameRot * mergeParentRot * parentFrameRot * parentOffsetRot; } else { mergeParentRot.loadIdentity(); } if (mergeChild) { mergeChildRot = mayaQ( mergeChild->mKeys[frame-1].mRot[0], mergeChild->mKeys[frame-1].mRot[1], mergeChild->mKeys[frame-1].mRot[2], bvhStringToOrder(mergeChild->mOrder) ); LLQuaternion childFrameRot( mergeChild->mFrameMatrix ); LLQuaternion childOffsetRot( mergeChild->mOffsetMatrix ); mergeChildRot = ~childFrameRot * mergeChildRot * childFrameRot * childOffsetRot; } else { mergeChildRot.loadIdentity(); } LLQuaternion inRot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order); LLQuaternion outRot = frameRotInv* mergeChildRot * inRot * mergeParentRot * ~first_frame_rot * frameRot * offsetRot; U16 time_short = F32_to_U16(time, 0.f, mDuration); dp.packU16(time_short, "time"); U16 x, y, z; LLVector3 rot_vec = outRot.packToVector3(); rot_vec.quantize16(-1.f, 1.f, -1.f, 1.f); x = F32_to_U16(rot_vec.mV[VX], -1.f, 1.f); y = F32_to_U16(rot_vec.mV[VY], -1.f, 1.f); z = F32_to_U16(rot_vec.mV[VZ], -1.f, 1.f); dp.packU16(x, "rot_angle_x"); dp.packU16(y, "rot_angle_y"); dp.packU16(z, "rot_angle_z"); outcount++; frame++; } // output position keys (only for 1st joint) if ( ji == mJoints.begin() && !joint->mIgnorePositions ) { dp.packS32(joint->mNumPosKeys, "num_pos_keys"); LLVector3 relPos = joint->mRelativePosition; LLVector3 relKey; frame = 1; for ( ki = joint->mKeys.begin(); ki != joint->mKeys.end(); ++ki ) { if ((frame == 1) && joint->mRelativePositionKey) { relKey.setVec(ki->mPos); } if (ki->mIgnorePos) { frame++; continue; } time = (F32)frame * mFrameTime; LLVector3 inPos = (LLVector3(ki->mPos) - relKey) * ~first_frame_rot;// * fixup_rot; LLVector3 outPos = inPos * frameRot * offsetRot; outPos *= INCHES_TO_METERS; outPos -= relPos; outPos.clamp(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); U16 time_short = F32_to_U16(time, 0.f, mDuration); dp.packU16(time_short, "time"); U16 x, y, z; outPos.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); x = F32_to_U16(outPos.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); y = F32_to_U16(outPos.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); z = F32_to_U16(outPos.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); dp.packU16(x, "pos_x"); dp.packU16(y, "pos_y"); dp.packU16(z, "pos_z"); frame++; } } else { dp.packS32(0, "num_pos_keys"); } } S32 num_constraints = (S32)mConstraints.size(); dp.packS32(num_constraints, "num_constraints"); for (ConstraintVector::iterator constraint_it = mConstraints.begin(); constraint_it != mConstraints.end(); constraint_it++) { U8 byte = constraint_it->mChainLength; dp.packU8(byte, "chain_length"); byte = constraint_it->mConstraintType; dp.packU8(byte, "constraint_type"); dp.packBinaryDataFixed((U8*)constraint_it->mSourceJointName, 16, "source_volume"); dp.packVector3(constraint_it->mSourceOffset, "source_offset"); dp.packBinaryDataFixed((U8*)constraint_it->mTargetJointName, 16, "target_volume"); dp.packVector3(constraint_it->mTargetOffset, "target_offset"); dp.packVector3(constraint_it->mTargetDir, "target_dir"); dp.packF32(constraint_it->mEaseInStart, "ease_in_start"); dp.packF32(constraint_it->mEaseInStop, "ease_in_stop"); dp.packF32(constraint_it->mEaseOutStart, "ease_out_start"); dp.packF32(constraint_it->mEaseOutStop, "ease_out_stop"); } return TRUE; }
//----------------------------------------------------------------------------- // LLBVHLoader::optimize() //----------------------------------------------------------------------------- void LLBVHLoader::optimize() { //RN: assumes motion blend, which is the default now if (!mLoop && mEaseIn + mEaseOut > mDuration && mDuration != 0.f) { F32 factor = mDuration / (mEaseIn + mEaseOut); mEaseIn *= factor; mEaseOut *= factor; } JointVector::iterator ji; for (ji = mJoints.begin(); ji != mJoints.end(); ++ji) { Joint *joint = *ji; BOOL pos_changed = FALSE; BOOL rot_changed = FALSE; if ( ! joint->mIgnore ) { joint->mNumPosKeys = 0; joint->mNumRotKeys = 0; LLQuaternion::Order order = bvhStringToOrder( joint->mOrder ); KeyVector::iterator first_key = joint->mKeys.begin(); // no keys? if (first_key == joint->mKeys.end()) { joint->mIgnore = TRUE; continue; } LLVector3 first_frame_pos(first_key->mPos); LLQuaternion first_frame_rot = mayaQ( first_key->mRot[0], first_key->mRot[1], first_key->mRot[2], order); // skip first key KeyVector::iterator ki = joint->mKeys.begin(); if (joint->mKeys.size() == 1) { // *FIX: use single frame to move pelvis // if only one keyframe force output for this joint rot_changed = TRUE; } else { // if more than one keyframe, use first frame as reference and skip to second first_key->mIgnorePos = TRUE; first_key->mIgnoreRot = TRUE; ++ki; } KeyVector::iterator ki_prev = ki; KeyVector::iterator ki_last_good_pos = ki; KeyVector::iterator ki_last_good_rot = ki; S32 numPosFramesConsidered = 2; S32 numRotFramesConsidered = 2; F32 rot_threshold = ROTATION_KEYFRAME_THRESHOLD / llmax((F32)joint->mChildTreeMaxDepth * 0.33f, 1.f); double diff_max = 0; KeyVector::iterator ki_max = ki; for (; ki != joint->mKeys.end(); ++ki) { if (ki_prev == ki_last_good_pos) { joint->mNumPosKeys++; if (dist_vec_squared(LLVector3(ki_prev->mPos), first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED) { pos_changed = TRUE; } } else { //check position for noticeable effect LLVector3 test_pos(ki_prev->mPos); LLVector3 last_good_pos(ki_last_good_pos->mPos); LLVector3 current_pos(ki->mPos); LLVector3 interp_pos = lerp(current_pos, last_good_pos, 1.f / (F32)numPosFramesConsidered); if (dist_vec_squared(current_pos, first_frame_pos) > POSITION_MOTION_THRESHOLD_SQUARED) { pos_changed = TRUE; } if (dist_vec_squared(interp_pos, test_pos) < POSITION_KEYFRAME_THRESHOLD_SQUARED) { ki_prev->mIgnorePos = TRUE; numPosFramesConsidered++; } else { numPosFramesConsidered = 2; ki_last_good_pos = ki_prev; joint->mNumPosKeys++; } } if (ki_prev == ki_last_good_rot) { joint->mNumRotKeys++; LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order); F32 x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot); F32 y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot); F32 rot_test = x_delta + y_delta; if (rot_test > ROTATION_MOTION_THRESHOLD) { rot_changed = TRUE; } } else { //check rotation for noticeable effect LLQuaternion test_rot = mayaQ( ki_prev->mRot[0], ki_prev->mRot[1], ki_prev->mRot[2], order); LLQuaternion last_good_rot = mayaQ( ki_last_good_rot->mRot[0], ki_last_good_rot->mRot[1], ki_last_good_rot->mRot[2], order); LLQuaternion current_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order); LLQuaternion interp_rot = lerp(1.f / (F32)numRotFramesConsidered, current_rot, last_good_rot); F32 x_delta; F32 y_delta; F32 rot_test; // Test if the rotation has changed significantly since the very first frame. If false // for all frames, then we'll just throw out this joint's rotation entirely. x_delta = dist_vec(LLVector3::x_axis * first_frame_rot, LLVector3::x_axis * test_rot); y_delta = dist_vec(LLVector3::y_axis * first_frame_rot, LLVector3::y_axis * test_rot); rot_test = x_delta + y_delta; if (rot_test > ROTATION_MOTION_THRESHOLD) { rot_changed = TRUE; } x_delta = dist_vec(LLVector3::x_axis * interp_rot, LLVector3::x_axis * test_rot); y_delta = dist_vec(LLVector3::y_axis * interp_rot, LLVector3::y_axis * test_rot); rot_test = x_delta + y_delta; // Draw a line between the last good keyframe and current. Test the distance between the last frame (current-1, i.e. ki_prev) // and the line. If it's greater than some threshold, then it represents a significant frame and we want to include it. if (rot_test >= rot_threshold || (ki+1 == joint->mKeys.end() && numRotFramesConsidered > 2)) { // Add the current test keyframe (which is technically the previous key, i.e. ki_prev). numRotFramesConsidered = 2; ki_last_good_rot = ki_prev; joint->mNumRotKeys++; // Add another keyframe between the last good keyframe and current, at whatever point was the most "significant" (i.e. // had the largest deviation from the earlier tests). Note that a more robust approach would be test all intermediate // keyframes against the line between the last good keyframe and current, but we're settling for this other method // because it's significantly faster. if (diff_max > 0) { if (ki_max->mIgnoreRot == TRUE) { ki_max->mIgnoreRot = FALSE; joint->mNumRotKeys++; } diff_max = 0; } } else { // This keyframe isn't significant enough, throw it away. ki_prev->mIgnoreRot = TRUE; numRotFramesConsidered++; // Store away the keyframe that has the largest deviation from the interpolated line, for insertion later. if (rot_test > diff_max) { diff_max = rot_test; ki_max = ki; } } } ki_prev = ki; } } // don't output joints with no motion if (!(pos_changed || rot_changed)) { //LL_INFOS() << "Ignoring joint " << joint->mName << LL_ENDL; joint->mIgnore = TRUE; } } }