Example #1
0
/*
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 &center, 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;
}
Example #3
0
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;
}
Example #5
0
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);
	}
}
Example #8
0
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;
}