/* For each vertex, given: B - binormal T - tangent N - normal P - position The resulting texture coordinate <u,v> is: u = 2(B dot P) v = 2(T dot P) */ void planarProjection(LLVector2 &tc, const LLVector4a& normal, const LLVector4a ¢er, const LLVector4a& vec) { LLVector4a binormal; F32 d = normal[0]; if (d >= 0.5f || d <= -0.5f) { if (d < 0) { binormal.set(0,-1,0); } else { binormal.set(0, 1, 0); } } else { if (normal[1] > 0) { binormal.set(-1,0,0); } else { binormal.set(1,0,0); } } LLVector4a tangent; tangent.setCross3(binormal,normal); tc.mV[1] = -((tangent.dot3(vec).getF32())*2 - 0.5f); tc.mV[0] = 1.0f+((binormal.dot3(vec).getF32())*2 - 0.5f); }
S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) { F32 d = 0.f; F32 t; LLVector4a origina; origina.load3(origin.mV); LLVector4a v; v.setSub(min, origina); if (v.dot3(v) < r) { v.setSub(max, origina); if (v.dot3(v) < r) { return 2; } } for (U32 i = 0; i < 3; i++) { if (origin.mV[i] < min[i]) { t = min[i] - origin.mV[i]; d += t*t; } else if (origin.mV[i] > max[i]) { t = origin.mV[i] - max[i]; d += t*t; } if (d > r) { return 0; } } return 1; }
BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) { //VECTORIZE THIS //get area of circle around face LLVector4a center; center.load3(getPositionAgent().mV); LLVector4a size; size.setSub(mExtents[1], mExtents[0]); size.mul(0.5f); LLViewerCamera* camera = LLViewerCamera::getInstance(); F32 size_squared = size.dot3(size).getF32(); LLVector4a lookAt; LLVector4a t; t.load3(camera->getOrigin().mV); lookAt.setSub(center, t); F32 dist = lookAt.getLength3().getF32(); dist = llmax(dist-size.getLength3().getF32(), 0.f); lookAt.normalize3fast() ; //get area of circle around node F32 app_angle = atanf((F32) sqrt(size_squared) / dist); radius = app_angle*LLDrawable::sCurPixelAngle; mPixelArea = radius*radius * 3.14159f; LLVector4a x_axis; x_axis.load3(camera->getXAxis().mV); cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32(); if(dist < mBoundingSphereRadius) //camera is very close { cos_angle_to_view_dir = 1.0f; mImportanceToCamera = 1.0f; } else { mImportanceToCamera = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist); } return true; }
bool LLViewerOctreeCull::checkProjectionArea(const LLVector4a& center, const LLVector4a& size, const LLVector3& shift, F32 pixel_threshold, F32 near_radius) { LLVector3 local_orig = mCamera->getOrigin() - shift; LLVector4a origin; origin.load3(local_orig.mV); LLVector4a lookAt; lookAt.setSub(center, origin); F32 distance = lookAt.getLength3().getF32(); if(distance <= near_radius) { return true; //always load close-by objects } // treat object as if it were near_radius meters closer than it actually was. // this allows us to get some temporal coherence on visibility...objects that can be reached quickly will tend to be visible distance -= near_radius; F32 squared_rad = size.dot3(size).getF32(); return squared_rad / distance > pixel_threshold; }
bool LLVOCacheEntry::isAnyVisible(const LLVector4a& camera_origin, const LLVector4a& local_camera_origin, F32 dist_threshold) { LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)getGroup(); if(!group) { return false; } //any visible bool vis = group->isAnyRecentlyVisible(); //not ready to remove if(!vis) { S32 cur_vis = llmax(group->getAnyVisible(), (S32)getVisible()); vis = (cur_vis + sMinFrameRange > LLViewerOctreeEntryData::getCurrentFrame()); } //within the back sphere if(!vis && !mParentID && !group->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED)) { LLVector4a lookAt; if(mBSphereRadius > 0.f) { lookAt.setSub(mBSphereCenter, local_camera_origin); dist_threshold += mBSphereRadius; } else { lookAt.setSub(getPositionGroup(), camera_origin); dist_threshold += getBinRadius(); } vis = (lookAt.dot3(lookAt).getF32() < dist_threshold * dist_threshold); } return vis; }
void LLVOPartGroup::getGeometry(const LLViewerPart& part, LLStrider<LLVector4a>& verticesp) { if (part.mFlags & LLPartData::LL_PART_RIBBON_MASK) { LLVector4a axis, pos, paxis, ppos; F32 scale, pscale; pos.load3(part.mPosAgent.mV); axis.load3(part.mAxis.mV); scale = part.mScale.mV[0]; if (part.mParent) { ppos.load3(part.mParent->mPosAgent.mV); paxis.load3(part.mParent->mAxis.mV); pscale = part.mParent->mScale.mV[0]; } else { //use source object as position if (part.mPartSourcep->mSourceObjectp.notNull()) { LLVector3 v = LLVector3(0,0,1); v *= part.mPartSourcep->mSourceObjectp->getRenderRotation(); paxis.load3(v.mV); ppos.load3(part.mPartSourcep->mPosAgent.mV); pscale = part.mStartScale.mV[0]; } else { //no source object, no parent, nothing to draw ppos = pos; pscale = scale; paxis = axis; } } LLVector4a p0, p1, p2, p3; scale *= 0.5f; pscale *= 0.5f; axis.mul(scale); paxis.mul(pscale); p0.setAdd(pos, axis); p1.setSub(pos,axis); p2.setAdd(ppos, paxis); p3.setSub(ppos, paxis); (*verticesp++) = p2; (*verticesp++) = p3; (*verticesp++) = p0; (*verticesp++) = p1; } else { LLVector4a part_pos_agent; part_pos_agent.load3(part.mPosAgent.mV); LLVector4a camera_agent; camera_agent.load3(getCameraPosition().mV); LLVector4a at; at.setSub(part_pos_agent, camera_agent); LLVector4a up(0, 0, 1); LLVector4a right; right.setCross3(at, up); right.normalize3fast(); up.setCross3(right, at); up.normalize3fast(); if (part.mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK) { LLVector4a normvel; normvel.load3(part.mVelocity.mV); normvel.normalize3fast(); LLVector2 up_fracs; up_fracs.mV[0] = normvel.dot3(right).getF32(); up_fracs.mV[1] = normvel.dot3(up).getF32(); up_fracs.normalize(); LLVector4a new_up; LLVector4a new_right; //new_up = up_fracs.mV[0] * right + up_fracs.mV[1]*up; LLVector4a t = right; t.mul(up_fracs.mV[0]); new_up = up; new_up.mul(up_fracs.mV[1]); new_up.add(t); //new_right = up_fracs.mV[1] * right - up_fracs.mV[0]*up; t = right; t.mul(up_fracs.mV[1]); new_right = up; new_right.mul(up_fracs.mV[0]); t.sub(new_right); up = new_up; right = t; up.normalize3fast(); right.normalize3fast(); } right.mul(0.5f*part.mScale.mV[0]); up.mul(0.5f*part.mScale.mV[1]); //HACK -- the verticesp->mV[3] = 0.f here are to set the texture index to 0 (particles don't use texture batching, maybe they should) // this works because there is actually a 4th float stored after the vertex position which is used as a texture index // also, somebody please VECTORIZE THIS LLVector4a ppapu; LLVector4a ppamu; ppapu.setAdd(part_pos_agent, up); ppamu.setSub(part_pos_agent, up); verticesp->setSub(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setSub(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; } }
void LLPolyMorphTarget::apply( ESex avatar_sex ) { if (!mMorphData || mNumMorphMasksPending > 0) { return; } LL_RECORD_BLOCK_TIME(FTM_APPLY_MORPH_TARGET); mLastSex = avatar_sex; // Check for NaN condition (NaN is detected if a variable doesn't equal itself. if (mCurWeight != mCurWeight) { mCurWeight = 0.0; } if (mLastWeight != mLastWeight) { mLastWeight = mCurWeight+.001; } // perform differential update of morph F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight); // store last weight mLastWeight += delta_weight; if (delta_weight != 0.f) { llassert(!mMesh->isLOD()); LLVector4a *coords = mMesh->getWritableCoords(); LLVector4a *scaled_normals = mMesh->getScaledNormals(); LLVector4a *normals = mMesh->getWritableNormals(); LLVector4a *scaled_binormals = mMesh->getScaledBinormals(); LLVector4a *binormals = mMesh->getWritableBinormals(); LLVector4a *clothing_weights = mMesh->getWritableClothingWeights(); LLVector2 *tex_coords = mMesh->getWritableTexCoords(); F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++) { S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph]; F32 maskWeight = 1.f; if (maskWeightArray) { maskWeight = maskWeightArray[vert_index_morph]; } LLVector4a pos = mMorphData->mCoords[vert_index_morph]; pos.mul(delta_weight*maskWeight); coords[vert_index_mesh].add(pos); if (getInfo()->mIsClothingMorph && clothing_weights) { LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph]; clothing_offset.mul(delta_weight * maskWeight); LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh]; clothing_weight->add(clothing_offset); clothing_weight->getF32ptr()[VW] = maskWeight; } // calculate new normals based on half angles LLVector4a norm = mMorphData->mNormals[vert_index_morph]; norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); scaled_normals[vert_index_mesh].add(norm); norm = scaled_normals[vert_index_mesh]; // guard against degenerate input data before we create NaNs below! // norm.normalize3fast(); normals[vert_index_mesh] = norm; // calculate new binormals LLVector4a binorm = mMorphData->mBinormals[vert_index_morph]; // guard against degenerate input data before we create NaNs below! // if (!binorm.isFinite3() || (binorm.dot3(binorm).getF32() <= F_APPROXIMATELY_ZERO)) { binorm.set(1,0,0,1); } binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); scaled_binormals[vert_index_mesh].add(binorm); LLVector4a tangent; tangent.setCross3(scaled_binormals[vert_index_mesh], norm); LLVector4a& normalized_binormal = binormals[vert_index_mesh]; normalized_binormal.setCross3(norm, tangent); normalized_binormal.normalize3fast(); tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight; } // now apply volume changes for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ ) { LLPolyVolumeMorph* volume_morph = &(*iter); LLVector3 scale_delta = volume_morph->mScale * delta_weight; LLVector3 pos_delta = volume_morph->mPos * delta_weight; volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); } } if (mNext) { mNext->apply(avatar_sex); } }
bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance) { // small area check { LLVector4a edge1; edge1.setSub( a, b ); LLVector4a edge2; edge2.setSub( a, c ); ////////////////////////////////////////////////////////////////////////// /// Linden Modified ////////////////////////////////////////////////////////////////////////// // If no one edge is more than 10x longer than any other edge, we weaken // the tolerance by a factor of 1e-4f. LLVector4a edge3; edge3.setSub( c, b ); const F32 len1sq = edge1.dot3(edge1).getF32(); const F32 len2sq = edge2.dot3(edge2).getF32(); const F32 len3sq = edge3.dot3(edge3).getF32(); bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq); bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq); bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq); if ( abOK && acOK && cbOK ) { tolerance *= 1e-4f; } ////////////////////////////////////////////////////////////////////////// /// End Modified ////////////////////////////////////////////////////////////////////////// LLVector4a cross; cross.setCross3( edge1, edge2 ); LLVector4a edge1b; edge1b.setSub( b, a ); LLVector4a edge2b; edge2b.setSub( b, c ); LLVector4a crossb; crossb.setCross3( edge1b, edge2b ); if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance )) { return true; } } // point triangle distance check { LLVector4a Q; Q.setSub(a, b); LLVector4a R; R.setSub(c, b); const F32 QQ = dot3fpu(Q, Q); const F32 RR = dot3fpu(R, R); const F32 QR = dot3fpu(R, Q); volatile F32 QQRR = QQ * RR; volatile F32 QRQR = QR * QR; F32 Det = (QQRR - QRQR); if( Det == 0.0f ) { return true; } } return false; }
void LLVOPartGroup::getGeometry(S32 idx, LLStrider<LLVector4a>& verticesp, LLStrider<LLVector3>& normalsp, LLStrider<LLVector2>& texcoordsp, LLStrider<LLColor4U>& colorsp, LLStrider<U16>& indicesp) { if (idx >= (S32) mViewerPartGroupp->mParticles.size()) { return; } const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx])); U32 vert_offset = mDrawable->getFace(idx)->getGeomIndex(); LLVector4a part_pos_agent; part_pos_agent.load3(part.mPosAgent.mV); LLVector4a camera_agent; camera_agent.load3(getCameraPosition().mV); LLVector4a at; at.setSub(part_pos_agent, camera_agent); LLVector4a up(0, 0, 1); LLVector4a right; right.setCross3(at, up); right.normalize3fast(); up.setCross3(right, at); up.normalize3fast(); if (part.mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK) { LLVector4a normvel; normvel.load3(part.mVelocity.mV); normvel.normalize3fast(); LLVector2 up_fracs; up_fracs.mV[0] = normvel.dot3(right).getF32(); up_fracs.mV[1] = normvel.dot3(up).getF32(); up_fracs.normalize(); LLVector4a new_up; LLVector4a new_right; //new_up = up_fracs.mV[0] * right + up_fracs.mV[1]*up; LLVector4a t = right; t.mul(up_fracs.mV[0]); new_up = up; new_up.mul(up_fracs.mV[1]); new_up.add(t); //new_right = up_fracs.mV[1] * right - up_fracs.mV[0]*up; t = right; t.mul(up_fracs.mV[1]); new_right = up; new_right.mul(up_fracs.mV[0]); t.sub(new_right); up = new_up; right = t; up.normalize3fast(); right.normalize3fast(); } right.mul(0.5f*part.mScale.mV[0]); up.mul(0.5f*part.mScale.mV[1]); LLVector3 normal = -LLViewerCamera::getInstance()->getXAxis(); //HACK -- the verticesp->mV[3] = 0.f here are to set the texture index to 0 (particles don't use texture batching, maybe they should) // this works because there is actually a 4th float stored after the vertex position which is used as a texture index // also, somebody please VECTORIZE THIS LLVector4a ppapu; LLVector4a ppamu; ppapu.setAdd(part_pos_agent, up); ppamu.setSub(part_pos_agent, up); verticesp->setSub(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setSub(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; //*verticesp++ = part_pos_agent + up - right; //*verticesp++ = part_pos_agent - up - right; //*verticesp++ = part_pos_agent + up + right; //*verticesp++ = part_pos_agent - up + right; *colorsp++ = part.mColor; *colorsp++ = part.mColor; *colorsp++ = part.mColor; *colorsp++ = part.mColor; *texcoordsp++ = LLVector2(0.f, 1.f); *texcoordsp++ = LLVector2(0.f, 0.f); *texcoordsp++ = LLVector2(1.f, 1.f); *texcoordsp++ = LLVector2(1.f, 0.f); *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *indicesp++ = vert_offset + 0; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 2; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 3; *indicesp++ = vert_offset + 2; }