void LLViewerObjectList::shiftObjects(const LLVector3 &offset) { // This is called when we shift our origin when we cross region boundaries... // We need to update many object caches, I'll document this more as I dig through the code // cleaning things out... if (gNoRender || 0 == offset.magVecSquared()) { return; } LLViewerObject *objectp; S32 i; for (i = 0; i < mObjects.count(); i++) { objectp = getObject(i); // There could be dead objects on the object list, so don't update stuff if the object is dead. if (objectp) { objectp->updatePositionCaches(); if (objectp->mDrawable.notNull() && !objectp->mDrawable->isDead()) { gPipeline.markShift(objectp->mDrawable); } } } gPipeline.shiftObjects(offset); gWorldPointer->mPartSim.shift(offset); }
void LLViewerObjectList::shiftObjects(const LLVector3 &offset) { // This is called when we shift our origin when we cross region boundaries... // We need to update many object caches, I'll document this more as I dig through the code // cleaning things out... if (gNoRender || 0 == offset.magVecSquared()) { return; } LLViewerObject *objectp; for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { objectp = *iter; // There could be dead objects on the object list, so don't update stuff if the object is dead. if (objectp && !objectp->isDead()) { objectp->updatePositionCaches(); if (objectp->mDrawable.notNull() && !objectp->mDrawable->isDead()) { gPipeline.markShift(objectp->mDrawable); } } } gPipeline.shiftObjects(offset); LLWorld::getInstance()->shiftRegions(offset); }
// Saves space by using the fact that our quaternions are normalized void LLQuaternion::unpackFromVector3( const LLVector3& vec ) { mQ[VX] = vec.mV[VX]; mQ[VY] = vec.mV[VY]; mQ[VZ] = vec.mV[VZ]; F32 t = 1.f - vec.magVecSquared(); if( t > 0 ) { mQ[VW] = sqrt( t ); } else { // Need this to avoid trying to find the square root of a negative number due // to floating point error. mQ[VW] = 0; } }
//----------------------------------------------------------------------------- // solve() //----------------------------------------------------------------------------- void LLJointSolverRP3::solve() { // llinfos << llendl; // llinfos << "LLJointSolverRP3::solve()" << llendl; //------------------------------------------------------------------------- // setup joints in their base rotations //------------------------------------------------------------------------- mJointA->setRotation( mJointABaseRotation ); mJointB->setRotation( mJointBBaseRotation ); //------------------------------------------------------------------------- // get joint positions in world space //------------------------------------------------------------------------- LLVector3 aPos = mJointA->getWorldPosition(); LLVector3 bPos = mJointB->getWorldPosition(); LLVector3 cPos = mJointC->getWorldPosition(); LLVector3 gPos = mJointGoal->getWorldPosition(); // llinfos << "bPosLocal = " << mJointB->getPosition() << llendl; // llinfos << "cPosLocal = " << mJointC->getPosition() << llendl; // llinfos << "bRotLocal = " << mJointB->getRotation() << llendl; // llinfos << "cRotLocal = " << mJointC->getRotation() << llendl; // llinfos << "aPos : " << aPos << llendl; // llinfos << "bPos : " << bPos << llendl; // llinfos << "cPos : " << cPos << llendl; // llinfos << "gPos : " << gPos << llendl; //------------------------------------------------------------------------- // get the poleVector in world space //------------------------------------------------------------------------- LLVector3 poleVec = mPoleVector; if ( mJointA->getParent() ) { LLVector4a pole_veca; pole_veca.load3(mPoleVector.mV); mJointA->getParent()->getWorldMatrix().rotate(pole_veca,pole_veca); poleVec.set(pole_veca.getF32ptr()); } //------------------------------------------------------------------------- // compute the following: // vector from A to B // vector from B to C // vector from A to C // vector from A to G (goal) //------------------------------------------------------------------------- LLVector3 abVec = bPos - aPos; LLVector3 bcVec = cPos - bPos; LLVector3 acVec = cPos - aPos; LLVector3 agVec = gPos - aPos; // llinfos << "abVec : " << abVec << llendl; // llinfos << "bcVec : " << bcVec << llendl; // llinfos << "acVec : " << acVec << llendl; // llinfos << "agVec : " << agVec << llendl; //------------------------------------------------------------------------- // compute needed lengths of those vectors //------------------------------------------------------------------------- F32 abLen = abVec.magVec(); F32 bcLen = bcVec.magVec(); F32 agLen = agVec.magVec(); // llinfos << "abLen : " << abLen << llendl; // llinfos << "bcLen : " << bcLen << llendl; // llinfos << "agLen : " << agLen << llendl; //------------------------------------------------------------------------- // compute component vector of (A->B) orthogonal to (A->C) //------------------------------------------------------------------------- LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec)); // llinfos << "abacCompOrthoVec : " << abacCompOrthoVec << llendl; //------------------------------------------------------------------------- // compute the normal of the original ABC plane (and store for later) //------------------------------------------------------------------------- LLVector3 abcNorm; if (!mbUseBAxis) { if( are_parallel(abVec, bcVec, 0.001f) ) { // the current solution is maxed out, so we use the axis that is // orthogonal to both poleVec and A->B if ( are_parallel(poleVec, abVec, 0.001f) ) { // ACK! the problem is singular if ( are_parallel(poleVec, agVec, 0.001f) ) { // the solutions is also singular return; } else { abcNorm = poleVec % agVec; } } else { abcNorm = poleVec % abVec; } } else { abcNorm = abVec % bcVec; } } else { abcNorm = mBAxis * mJointB->getWorldRotation(); } //------------------------------------------------------------------------- // compute rotation of B //------------------------------------------------------------------------- // angle between A->B and B->C F32 abbcAng = angle_between(abVec, bcVec); // vector orthogonal to A->B and B->C LLVector3 abbcOrthoVec = abVec % bcVec; if (abbcOrthoVec.magVecSquared() < 0.001f) { abbcOrthoVec = poleVec % abVec; abacCompOrthoVec = poleVec; } abbcOrthoVec.normVec(); F32 agLenSq = agLen * agLen; // angle arm for extension F32 cosTheta = (agLenSq - abLen*abLen - bcLen*bcLen) / (2.0f * abLen * bcLen); if (cosTheta > 1.0f) cosTheta = 1.0f; else if (cosTheta < -1.0f) cosTheta = -1.0f; F32 theta = acos(cosTheta); LLQuaternion bRot(theta - abbcAng, abbcOrthoVec); // llinfos << "abbcAng : " << abbcAng << llendl; // llinfos << "abbcOrthoVec : " << abbcOrthoVec << llendl; // llinfos << "agLenSq : " << agLenSq << llendl; // llinfos << "cosTheta : " << cosTheta << llendl; // llinfos << "theta : " << theta << llendl; // llinfos << "bRot : " << bRot << llendl; // llinfos << "theta abbcAng theta-abbcAng: " << theta*180.0/F_PI << " " << abbcAng*180.0f/F_PI << " " << (theta - abbcAng)*180.0f/F_PI << llendl; //------------------------------------------------------------------------- // compute rotation that rotates new A->C to A->G //------------------------------------------------------------------------- // rotate B->C by bRot bcVec = bcVec * bRot; // update A->C acVec = abVec + bcVec; LLQuaternion cgRot; cgRot.shortestArc( acVec, agVec ); // llinfos << "bcVec : " << bcVec << llendl; // llinfos << "acVec : " << acVec << llendl; // llinfos << "cgRot : " << cgRot << llendl; // update A->B and B->C with rotation from C to G abVec = abVec * cgRot; bcVec = bcVec * cgRot; abcNorm = abcNorm * cgRot; acVec = abVec + bcVec; //------------------------------------------------------------------------- // compute the normal of the APG plane //------------------------------------------------------------------------- if (are_parallel(agVec, poleVec, 0.001f)) { // the solution plane is undefined ==> we're done return; } LLVector3 apgNorm = poleVec % agVec; apgNorm.normVec(); if (!mbUseBAxis) { //--------------------------------------------------------------------- // compute the normal of the new ABC plane // (only necessary if we're NOT using mBAxis) //--------------------------------------------------------------------- if( are_parallel(abVec, bcVec, 0.001f) ) { // G is either too close or too far away // we'll use the old ABCnormal } else { abcNorm = abVec % bcVec; } abcNorm.normVec(); } //------------------------------------------------------------------------- // calcuate plane rotation //------------------------------------------------------------------------- LLQuaternion pRot; if ( are_parallel( abcNorm, apgNorm, 0.001f) ) { if (abcNorm * apgNorm < 0.0f) { // we must be PI radians off ==> rotate by PI around agVec pRot.setQuat(F_PI, agVec); } else { // we're done } } else { pRot.shortestArc( abcNorm, apgNorm ); } // llinfos << "abcNorm = " << abcNorm << llendl; // llinfos << "apgNorm = " << apgNorm << llendl; // llinfos << "pRot = " << pRot << llendl; //------------------------------------------------------------------------- // compute twist rotation //------------------------------------------------------------------------- LLQuaternion twistRot( mTwist, agVec ); // llinfos << "twist : " << mTwist*180.0/F_PI << llendl; // llinfos << "agNormVec: " << agNormVec << llendl; // llinfos << "twistRot : " << twistRot << llendl; //------------------------------------------------------------------------- // compute rotation of A //------------------------------------------------------------------------- LLQuaternion aRot = cgRot * pRot * twistRot; //------------------------------------------------------------------------- // apply the rotations //------------------------------------------------------------------------- mJointB->setWorldRotation( mJointB->getWorldRotation() * bRot ); mJointA->setWorldRotation( mJointA->getWorldRotation() * aRot ); }
BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_PARTICLES); LLVector3 at; LLVector3 position_agent; LLVector3 camera_agent = gCamera->getOrigin(); S32 num_parts = mViewerPartGroupp->getCount(); LLFace *facep; LLSpatialGroup* group = drawable->getSpatialGroup(); if (!group && num_parts) { drawable->movePartition(); group = drawable->getSpatialGroup(); } if (!num_parts) { if (group && drawable->getNumFaces()) { group->dirtyGeom(); } drawable->setNumFaces(0, NULL, getTEImage(0)); LLPipeline::sCompiles++; return TRUE; } if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES))) { return TRUE; } if (num_parts > drawable->getNumFaces()) { drawable->setNumFacesFast(num_parts+num_parts/4, NULL, getTEImage(0)); } F32 tot_area = 0; F32 max_area = LLViewerPartSim::getMaxPartCount() * MAX_PARTICLE_AREA_SCALE; F32 pixel_meter_ratio = gCamera->getPixelMeterRatio(); pixel_meter_ratio *= pixel_meter_ratio; S32 count=0; S32 i; mDepth = 0.f; for (i = 0; i < num_parts; i++) { const LLViewerPart &part = *((LLViewerPart*) mViewerPartGroupp->mParticles[i]); LLVector3 part_pos_agent(part.mPosAgent); at = part_pos_agent - camera_agent; F32 camera_dist_squared = at.magVecSquared(); F32 inv_camera_dist_squared; if (camera_dist_squared > 1.f) inv_camera_dist_squared = 1.f / camera_dist_squared; else inv_camera_dist_squared = 1.f; F32 area = part.mScale.mV[0] * part.mScale.mV[1] * inv_camera_dist_squared; tot_area += area; if (tot_area > max_area) { break; } count++; facep = drawable->getFace(i); if (!facep) { llwarns << "No face found for index " << i << "!" << llendl; continue; } facep->setTEOffset(i); const F32 NEAR_PART_DIST_SQ = 5.f*5.f; // Only discard particles > 5 m from the camera const F32 MIN_PART_AREA = .005f*.005f; // only less than 5 mm x 5 mm at 1 m from camera if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA) { facep->setSize(0, 0); continue; } facep->setSize(4, 6); facep->setViewerObject(this); if (part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK) { facep->setState(LLFace::FULLBRIGHT); } else { facep->clearState(LLFace::FULLBRIGHT); } facep->mCenterLocal = part.mPosAgent; facep->setFaceColor(part.mColor); facep->setTexture(part.mImagep); mPixelArea = tot_area * pixel_meter_ratio; const F32 area_scale = 10.f; // scale area to increase priority a bit facep->setVirtualSize(mPixelArea*area_scale); } for (i = count; i < drawable->getNumFaces(); i++) { LLFace* facep = drawable->getFace(i); if (!facep) { llwarns << "No face found for index " << i << "!" << llendl; continue; } facep->setTEOffset(i); facep->setSize(0, 0); } mDrawable->movePartition(); LLPipeline::sCompiles++; return TRUE; }