示例#1
0
//----------------------------------------------------------------------------
void AVector::Orthonormalize (AVector& vec0, AVector& vec1, AVector& vec2)
{
    // If the input vectors are v0, v1, and v2, then the Gram-Schmidt
    // orthonormalization produces vectors u0, u1, and u2 as follows,
    //
    //   u0 = v0/|v0|
    //   u1 = (v1-(u0*v1)u0)/|v1-(u0*v1)u0|
    //   u2 = (v2-(u0*v2)u0-(u1*v2)u1)/|v2-(u0*v2)u0-(u1*v2)u1|
    //
    // where |A| indicates length of vector A and A*B indicates dot
    // product of vectors A and B.

    // Compute u0.
    vec0.Normalize();

    // Compute u1.
    float dot0 = vec0.Dot(vec1);
    vec1 -= dot0*vec0;
    vec1.Normalize();

    // Compute u2.
    float dot1 = vec1.Dot(vec2);
    dot0 = vec0.Dot(vec2);
    vec2 -= dot0*vec0 + dot1*vec1;
    vec2.Normalize();
}
//----------------------------------------------------------------------------
void EditRenderView_Scene::_RolateCamera(float horz, float vert)
{
	Scene *scene = PX2_PROJ.GetScene();
	CameraActor *camActor = scene->GetUseCameraActor();

	if (VT_PERSPECTIVE == mViewType)
	{
		AVector rVector;
		AVector dVector;
		AVector uVector;
		camActor->GetRDUVector(rVector, dVector, uVector);

		// horz
		HMatrix incrH(AVector::UNIT_Z, -horz*0.5f);
		dVector = incrH * dVector;
		uVector = incrH * uVector;
		rVector = incrH * rVector;

		// vert
		Matrix3f kIncrV(rVector, -vert*0.5f);
		dVector = kIncrV * dVector;
		uVector = kIncrV * uVector;

		dVector.Normalize();
		float dVectorAdj = dVector.Dot(AVector::UNIT_Z);
		float dVectorAdj1 = dVector.Dot(-AVector::UNIT_Z);
		if (dVectorAdj > 0.9f || dVectorAdj1 > 0.9f)
			return;

		AVector::Orthonormalize(dVector, uVector, rVector);
		camActor->LocalTransform.SetRotate(HMatrix(rVector, dVector,
			uVector, AVector::ZERO, true));
	}
}
示例#3
0
//----------------------------------------------------------------------------
AVector CurveSegment::Normal (float u) const
{
    AVector velocity = PU(u);
    AVector acceleration = PUU(u);
    float VDotV = velocity.Dot(velocity);
    float VDotA = velocity.Dot(acceleration);
    AVector normal = VDotV*acceleration - VDotA*velocity;
    normal.Normalize();
    return normal;
}
示例#4
0
//----------------------------------------------------------------------------
void CurveSegment::GetFrame (float u, APoint& position, AVector& tangent,
    AVector& normal, AVector& binormal) const
{
    position = P(u);
    AVector velocity = PU(u);
    AVector acceleration = PUU(u);
    float VDotV = velocity.Dot(velocity);
    float VDotA = velocity.Dot(acceleration);
    normal = VDotV*acceleration - VDotA*velocity;
    normal.Normalize();
    tangent = velocity;
    tangent.Normalize();
    binormal = tangent.Cross(normal);
}
示例#5
0
//----------------------------------------------------------------------------
bool Bound::TestIntersection (const Bound& bound, float tmax,
							  const AVector& velocity0, const AVector& velocity1) const
{
	if (bound.GetRadius() == 0.0f || GetRadius() == 0.0f)
	{
		return false;
	}

	AVector relVelocity = velocity1 - velocity0; // 相对速度
	AVector cenDiff = bound.mCenter - mCenter; // 相对位移
	float a = relVelocity.SquaredLength();
	float c = cenDiff.SquaredLength();
	float rSum = bound.mRadius + mRadius;
	float rSumSqr = rSum*rSum;

	if (a > 0.0f)
	{
		float b = cenDiff.Dot(relVelocity);
		if (b <= 0.0f)
		{
			if (-tmax*a <= b)
			{
				return a*c - b*b <= a*rSumSqr;
			}
			else
			{
				return tmax*(tmax*a + 2.0f*b) + c <= rSumSqr;
			}
		}
	}

	return c <= rSumSqr;
}
示例#6
0
//----------------------------------------------------------------------------
void HMatrix::MakePerspectiveProjection (const APoint& origin,
    const AVector& normal, const APoint& eye)
{
    //     +-                                                 -+
    // M = | Dot(N,E-P)*I - E*N^T    -(Dot(N,E-P)*I - E*N^T)*E |
    //     |        -N^t                      Dot(N,E)         |
    //     +-                                                 -+
    //
    // where E is the eye point, P is a point on the plane, and N is a
    // unit-length plane normal.

    float dotND = normal.Dot(eye - origin);

    mEntry[ 0] = dotND - eye[0]*normal[0];
    mEntry[ 1] = -eye[0]*normal[1];
    mEntry[ 2] = -eye[0]*normal[2];
    mEntry[ 3] = -(mEntry[0]*eye[0] + mEntry[1]*eye[1] + mEntry[2]*eye[2]);
    mEntry[ 4] = -eye[1]*normal[0];
    mEntry[ 5] = dotND - eye[1]*normal[1];
    mEntry[ 6] = -eye[1]*normal[2];
    mEntry[ 7] = -(mEntry[4]*eye[0] + mEntry[5]*eye[1] + mEntry[6]*eye[2]);
    mEntry[ 8] = -eye[2]*normal[0];
    mEntry[ 9] = -eye[2]*normal[1];
    mEntry[10] = dotND- eye[2]*normal[2];
    mEntry[11] = -(mEntry[8]*eye[0] + mEntry[9]*eye[1] + mEntry[10]*eye[2]);
    mEntry[12] = -normal[0];
    mEntry[13] = -normal[1];
    mEntry[14] = -normal[2];
    mEntry[15] = eye.Dot(normal);
}
//----------------------------------------------------------------------------
void ClodMeshes::UpdateClods ()
{
    // Adjust the triangle quantities for the clod meshes.  The distance along
    // the camera direction controls the triangle quantities.  A nonlinear
    // drop-off is used.
    for (int i = 0; i < 2; ++i)
    {
        AVector diff =
            mClod[i]->WorldBound.GetCenter() - mCamera->GetPosition();

        float depth = diff.Dot(mCamera->GetDVector());
        int targetRecord;
        if (depth <= mCamera->GetDMin())
        {
            targetRecord = 0;
        }
        else if (depth >= mCamera->GetDMax())
        {
            targetRecord = mClod[i]->GetNumRecords() - 1;
        }
        else
        {
            float dmin = mCamera->GetDMin();
            float dmax = mCamera->GetDMax();
            float ratio = Mathf::Pow((depth - dmin)/(dmax - dmin), 0.5f);
            targetRecord = (int)((mClod[i]->GetNumRecords() - 1)*ratio);
        }

        mClod[i]->TargetRecord() = targetRecord;
    }
}
//----------------------------------------------------------------------------
bool PlanarShadowEffect::GetProjectionMatrix (int i, HMatrix& projection)
{
	// Compute the equation for the shadow plane in world coordinates.
	APoint vertex[3];
	mPlanes[i]->GetWorldTriangle(0, vertex);
	HPlane worldPlane(vertex[0], vertex[1], vertex[2]);

	// This is a conservative test to see whether a shadow should be cast.
	// This can cause incorrect results if the caster is large and intersects
	// the plane, but ordinarily we are not trying to cast shadows in such
	// situations.
	if (mShadowCaster->WorldBound.WhichSide(worldPlane) < 0)
	{
		// The shadow caster is on the far side of plane, so it cannot cast
		// a shadow.
		return false;
	}

	// Compute the projection matrix for the light source.
	Light* projector = mProjectors[i];
	AVector normal = worldPlane.GetNormal();
	if (projector->GetType() == Light::LT_DIRECTIONAL)
	{
		float NdD = normal.Dot(projector->DVector);
		if (NdD >= 0.0f)
		{
			// The projection must be onto the "positive side" of the plane.
			return false;
		}

		projection.MakeObliqueProjection(vertex[0], normal,
		                                 projector->DVector);
	}
	else if (projector->GetType() == Light::LT_POINT
	         ||  projector->GetType() == Light::LT_SPOT)
	{
		float NdE = projector->Position.Dot(normal);
		if (NdE <= 0.0f)
		{
			// The projection must be onto the "positive side" of the plane.
			return false;
		}

		projection.MakePerspectiveProjection(vertex[0], normal,
		                                     projector->Position);
	}
	else
	{
		assertion(false, "Light type not supported.\n");
		return false;
	}

	return true;
}
//----------------------------------------------------------------------------
void AmbientRegionActor::_UpdateDirLightCamera()
{
	AVector dir = AVector::AnglesToDirection(Mathf::DEG_TO_RAD*mHorAngle,
		Mathf::DEG_TO_RAD*mVerAngle);
	dir.Normalize();

	Scene *scene = DynamicCast<Scene>(GetTopestParent());
	if (scene)
	{
		EnvirParam *envirParam = scene->GetEnvirParam();

		Light *lightDir = envirParam->GetLight_Dir();
		Projector *projector = envirParam->GetLight_Dir_Projector();

		lightDir->Ambient = Float4(mAmbientColor[0], mAmbientColor[1],
			mAmbientColor[2], mIntensity);
		lightDir->Intensity = mIntensity;
		lightDir->Diffuse = Float4(mDiffuseColor[0], mDiffuseColor[1],
			mDiffuseColor[2], 1.0f);
		lightDir->Specular = Float4(mSpecularColor[0], mSpecularColor[1],
			mSpecularColor[2], mSpecularPow);

		float upDot = dir.Dot(-AVector::UNIT_Z);
		if (upDot >= 0.99f)
		{
		}
		else
		{
			AVector upTemp = AVector::UNIT_Z;
			AVector right = dir.UnitCross(upTemp);
			AVector up = right.UnitCross(dir);

			lightDir->DVector = dir;
			lightDir->UVector = up;
			lightDir->RVector = right;

			APoint camPos = mLightCameraLookPosition - dir*mLightCameraLookDistance;
			projector->SetFrame(camPos, lightDir->DVector,
				lightDir->UVector, lightDir->RVector);
		}

		if (!projector->IsPerspective())
		{
			projector->SetFrustum(0.1f, 100.0f,
				-mLightCameraExtent, mLightCameraExtent, -mLightCameraExtent,
				mLightCameraExtent);
		}
		else
		{
			projector->SetFrustum(mLightCameraExtent, 1.0f, 1.0f, 100.0f);
		}
	}
}
示例#10
0
//----------------------------------------------------------------------------
void Renderable::GetVisibleSet (Culler& culler, bool)
{
	AdjustTransparent();

	const Camera *camera = culler.GetCamera();

	assertion(camera!=0, "camera must not be 0.");

	AVector cameraDir = camera->GetDVector();
	AVector diff = WorldBound.GetCenter() - camera->GetPosition();

	mEyeDistance = cameraDir.Dot(diff);

	culler.Insert(this);
}
示例#11
0
//----------------------------------------------------------------------------
void AVector::Orthonormalize (AVector& vec0, AVector& vec1, AVector& vec2)
{
	// 输入的向量为v0,v1,v2,按照下面的方式进行Gram-Schmidt正交化
	//
	//   u0 = v0/|v0|
	//   u1 = (v1-(u0*v1)u0)/|v1-(u0*v1)u0|
	//   u2 = (v2-(u0*v2)u0-(u1*v2)u1)/|v2-(u0*v2)u0-(u1*v2)u1|
	//
	// |A|代表向量A的长度;A*B代表两个向量“点乘”

	// 单位化
	vec0.Normalize();

	// 计算 u1
	float dot0 = vec0.Dot(vec1); 
	vec1 -= dot0*vec0;
	vec1.Normalize();

	// 计算 u2
	float dot1 = vec1.Dot(vec2);
	dot0 = vec0.Dot(vec2);
	vec2 -= dot0*vec0 + dot1*vec1;
	vec2.Normalize();
}
//----------------------------------------------------------------------------
void EU_CanvasStage::_RolateCamera(float horz, float vert)
{
	Scene *scene = PX2_PROJ.GetScene();

	horz *= 0.4f;
	vert *= 0.25f;

	if (VT_PERSPECTIVE == mViewType)
	{
		AVector rVector;
		AVector dVector;
		AVector uVector;
		mStageCameraNode->LocalTransform.GetRDUVector(rVector, dVector, uVector);

		// horz
		HMatrix incrH(AVector::UNIT_Z, -horz);
		dVector = incrH * dVector;
		uVector = incrH * uVector;
		rVector = incrH * rVector;

		// vert
		Matrix3f kIncrV(rVector, -vert);
		dVector = kIncrV * dVector;
		uVector = kIncrV * uVector;

		dVector.Normalize();
		float dVectorAdj = dVector.Dot(AVector::UNIT_Z);
		float dVectorAdj1 = dVector.Dot(-AVector::UNIT_Z);
		if (dVectorAdj > 0.9f || dVectorAdj1 > 0.9f)
			return;

		AVector::Orthonormalize(dVector, uVector, rVector);
		mStageCameraNode->LocalTransform.SetRotate(HMatrix(rVector, dVector,
			uVector, AVector::ZERO, true));
	}
}
示例#13
0
//----------------------------------------------------------------------------
int FramesMesh::_GetDirIndex(const AVector &dir)
{
	AVector animVec = dir;
	animVec.Normalize();

	AVector up = AVector::UNIT_Y;
	float dotVal = up.Dot(animVec);

	float rad = Mathf::ACos(dotVal);
	float degree = Mathf::RAD_TO_DEG * rad;
	bool isRight = (dir.X() > 0.0f);

	if (0 <= degree && degree < 22.5f)
	{
		return 0;
	}
	else if (22.5f <= degree && degree < 67.5f)
	{
		if (isRight)
			return 1;
		else
			return 7;
	}
	else if (67.5 <= degree && degree < 112.5f)
	{
		if (isRight)
			return 2;
		else
			return 6;
	}
	else if (112.5f <= degree && degree < 157.5f)
	{
		if (isRight)
			return 3;
		else
			return 5;
	}
	else if (157.5f <= degree && degree <= 180.0f)
	{
		return 4;
	}

	return 0;
}
示例#14
0
//----------------------------------------------------------------------------
float CurveSegment::Torsion (float u) const
{
    AVector velocity = PU(u);
    AVector acceleration = PUU(u);
    AVector cross = velocity.Cross(acceleration);
    float denom = cross.SquaredLength();

    if (denom >= Mathf::ZERO_TOLERANCE)
    {
        AVector jerk = PUUU(u);
        float numer = cross.Dot(jerk);
        return numer/denom;
    }
    else
    {
        // Torsion is indeterminate, just return 0.
        return 0.0f;
    }
}
示例#15
0
//----------------------------------------------------------------------------
void HMatrix::MakeObliqueProjection (const APoint& origin,
    const AVector& normal, const AVector& direction)
{
    // The projection plane is Dot(N,X-P) = 0 where N is a 3-by-1 unit-length
    // normal vector and P is a 3-by-1 point on the plane.  The projection
    // is oblique to the plane, in the direction of the 3-by-1 vector D.
    // Necessarily Dot(N,D) is not zero for this projection to make sense.
    // Given a 3-by-1 point U, compute the intersection of the line U+t*D
    // with the plane to obtain t = -Dot(N,U-P)/Dot(N,D).  Then
    //
    //   projection(U) = P + [I - D*N^T/Dot(N,D)]*(U-P)
    //
    // A 4-by-4 homogeneous transformation representing the projection is
    //
    //       +-                               -+
    //   M = | D*N^T - Dot(N,D)*I   -Dot(N,P)D |
    //       |          0^T          -Dot(N,D) |
    //       +-                               -+
    //
    // where M applies to [U^T 1]^T by M*[U^T 1]^T.  The matrix is chosen so
    // that M[3][3] > 0 whenever Dot(N,D) < 0 (projection is onto the
    // "positive side" of the plane).

    float dotND = normal.Dot(direction);
    float dotNO = origin.Dot(normal);

    mEntry[ 0] = direction[0]*normal[0] - dotND;
    mEntry[ 1] = direction[0]*normal[1];
    mEntry[ 2] = direction[0]*normal[2];
    mEntry[ 3] = -dotNO*direction[0];
    mEntry[ 4] = direction[1]*normal[0];
    mEntry[ 5] = direction[1]*normal[1] - dotND;
    mEntry[ 6] = direction[1]*normal[2];
    mEntry[ 7] = -dotNO*direction[1];
    mEntry[ 8] = direction[2]*normal[0];
    mEntry[ 9] = direction[2]*normal[1];
    mEntry[10] = direction[2]*normal[2] - dotND;
    mEntry[11] = -dotNO*direction[2];
    mEntry[12] = 0.0f;
    mEntry[13] = 0.0f;
    mEntry[14] = 0.0f;
    mEntry[15] = -dotND;
}
示例#16
0
//----------------------------------------------------------------------------
bool Bound::TestIntersection (const APoint& origin, const AVector& direction,
							  float tmin, float tmax) const
{
	if (GetRadius() == 0.0f)
	{
		return false;
	}

	AVector diff;
	float a0, a1, discr;

	if (tmin == -Mathf::MAX_REAL)
	{
		assertion(tmax == Mathf::MAX_REAL,
			"tmax must be infinity for a line.\n");

		// Test for sphere-line intersection.
		diff = origin - mCenter;
		a0 = diff.Dot(diff) - mRadius*mRadius;
		a1 = direction.Dot(diff);
		discr = a1*a1 - a0;
		return discr >= 0.0f;
	}

	if (tmax == Mathf::MAX_REAL)
	{
		assertion(tmin == 0.0f, "tmin must be zero for a ray.\n");

		// Test for sphere-ray intersection.
		AVector diff = origin - mCenter;
		a0 = diff.Dot(diff) - mRadius*mRadius;
		if (a0 <= 0.0f)
		{
			// The ray origin is inside the sphere.
			return true;
		}
		// else: The ray origin is outside the sphere.

		a1 = direction.Dot(diff);
		if (a1 >= 0.0f)
		{
			// The ray forms an acute angle with diff, and so the ray is
			// directed from the sphere.  Thus, the ray origin is outside
			// the sphere, and points P+t*D for t >= 0 are even farther
			// away from the sphere.
			return false;
		}

		discr = a1*a1 - a0;
		return discr >= 0.0f;
	}

	assertion(tmax > tmin, "tmin < tmax is required for a segment.\n");

	// Test for sphere-segment intersection.
	float segExtent = 0.5f*(tmin + tmax);
	APoint segOrigin = origin + segExtent*direction;

	diff = segOrigin - mCenter;
	a0 = diff.Dot(diff) - mRadius*mRadius;
	a1 = direction.Dot(diff);
	discr = a1*a1 - a0;
	if (discr < 0.0f)
	{
		return false;
	}

	float tmp0 = segExtent*segExtent + a0;
	float tmp1 = 2.0f*a1*segExtent;
	float qm = tmp0 - tmp1;
	float qp = tmp0 + tmp1;
	if (qm*qp <= 0.0f)
	{
		return true;
	}

	return qm > 0.0f && Mathf::FAbs(a1) < segExtent;
}
示例#17
0
//----------------------------------------------------------------------------
void SceneNodeCtrl::OnMotion(bool leftDown, RenderStep *renderStep,
	PX2::APoint posNow, PX2::APoint posBefore)
{
	PX2_UNUSED(leftDown);
	PX2_UNUSED(renderStep);

	Renderer *renderer = renderStep->GetRenderer();
	Camera *camera = renderStep->GetCamera();

	// 光标移动更新
	if (DT_NONE == mDragType)
	{
		GeoObjFactory factory;

		DragType dt = GetDragType(renderStep, posNow);
		Movable *ctrlMov = 0;
		Float4 colorYellowAlpha = Float4(1.0f, 1.0f, 0.0f, 0.3f);

		if (DT_X == dt)
		{
			ctrlMov = GetCurrentCtrlX();
			factory.UpdateCtrlColor(renderer, ctrlMov, Float4::YELLOW);
		}
		else if (DT_Y == dt)
		{
			ctrlMov = GetCurrentCtrlY();
			factory.UpdateCtrlColor(renderer, ctrlMov, Float4::YELLOW);
		}
		else if (DT_Z == dt)
		{
			ctrlMov = GetCurrentCtrlZ();
			factory.UpdateCtrlColor(renderer, ctrlMov, Float4::YELLOW);
		}
		else if (DT_XY == dt)
		{
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXY(), colorYellowAlpha);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlYZ(), Float4::ZERO);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXZ(), Float4::ZERO);
		}
		else if (DT_YZ == dt)
		{
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlYZ(), colorYellowAlpha);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXY(), Float4::ZERO);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXZ(), Float4::ZERO);
		}
		else if (DT_XZ == dt)
		{
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXZ(), colorYellowAlpha);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXY(), Float4::ZERO);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlYZ(), Float4::ZERO);
		}
		else if (DT_XYZ == dt)
		{
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXYZ(), Float4::YELLOW);
		}
		else if (DT_NONE == dt)
		{
			factory.UpdateCtrlColor(renderer, GetCurrentCtrlX(), Float4::RED);
			factory.UpdateCtrlColor(renderer, GetCurrentCtrlY(), Float4::GREEN);
			factory.UpdateCtrlColor(renderer, GetCurrentCtrlZ(), Float4::BLUE);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXY(), Float4::ZERO);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlYZ(), Float4::ZERO);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXZ(), Float4::ZERO);
			factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXYZ(), Float4::WHITE);
		}

		if (DT_NONE == dt)
		{
			Event *ent = EditEventSpace::CreateEventX(EditEventSpace::SceneNodeDrag);
			ent->SetData<int>(0);
			EventWorld::GetSingleton().BroadcastingLocalEvent(ent);
		}
		else
		{
			Event *ent = EditEventSpace::CreateEventX(EditEventSpace::SceneNodeDrag);
			ent->SetData<int>(1);
			EventWorld::GetSingleton().BroadcastingLocalEvent(ent);
		}
	}

	if (DT_NONE == mDragType) return;
	else
	{
		Event *ent = EditEventSpace::CreateEventX(EditEventSpace::SceneNodeDrag);
		ent->SetData<int>(1);
		EventWorld::GetSingleton().BroadcastingLocalEvent(ent);
	}

	int numObjs = PX2_SELECTION.GetNumObjects();
	if (0 == numObjs) 
		return;

	// get pickPoint with the plane
	TriMesh *meshHelp = PX2_GR.GetXYPlane();
	if (DT_X == mDragType)
	{
		if (LT_PERSPECTIVE == mLookType || LT_TOP == mLookType)
			meshHelp = PX2_GR.GetXYPlane();
		else if (LT_FRONT == mLookType)
			meshHelp = PX2_GR.GetXZPlane();
	}
	else if (DT_Y == mDragType)
	{
		meshHelp = PX2_GR.GetXYPlane();
	}
	else if (DT_Z == mDragType)
	{
		AVector cameraDir = camera->GetDVector();
		cameraDir.Normalize();
		float dotVal = Mathf::FAbs(cameraDir.Dot(AVector::UNIT_X));
		if (dotVal > 0.7f)
		{
			meshHelp = PX2_GR.GetYZPlane();
		}
		else
		{
			meshHelp = PX2_GR.GetXZPlane();
		}
	}
	else if (DT_XY == mDragType)
	{
		meshHelp = PX2_GR.GetXYPlane();
	}
	else if (DT_YZ == mDragType)
	{
		meshHelp = PX2_GR.GetYZPlane();
	}
	else if (DT_XZ == mDragType)
	{
		meshHelp = PX2_GR.GetXZPlane();
	}
	else if (DT_XYZ == mDragType)
	{
		meshHelp = PX2_GR.GetXYPlane();
	}
	meshHelp->WorldTransform.SetTranslate(GetPosition());

	// get pick ray
	APoint rayOrigin_Now;
	AVector rayDir_Now;
	renderStep->GetPickRay(posNow.X(), posNow.Z(), rayOrigin_Now, rayDir_Now);

	APoint rayOrigin_Before;
	AVector rayDir_Before;
	renderStep->GetPickRay(posBefore.X(), posBefore.Z(), rayOrigin_Before, rayDir_Before);

	// pick
	Picker pickerNow;
	pickerNow.Execute(meshHelp, rayOrigin_Now, rayDir_Now, 0.0f, Mathf::MAX_REAL);
	float lengthNow = pickerNow.GetClosestToZero().T;
	APoint positionNow(rayOrigin_Now + rayDir_Now*lengthNow);

	Picker pickerOrigin;
	pickerOrigin.Execute(meshHelp, rayOrigin_Before, rayDir_Before, 0.0f, Mathf::MAX_REAL);
	float lengthBefore = pickerOrigin.GetClosestToZero().T;
	APoint positionBefore(rayOrigin_Before + rayDir_Before*lengthBefore);

	if (pickerNow.Records.empty() || pickerOrigin.Records.empty()) return;

	AVector transMoved = positionNow - positionBefore;
	AVector transDir = transMoved;
	transDir.Normalize();

	float transValue = 0.0f;
	float transValue1 = 0.0f;
	AVector transVec;
	AVector rolateVec;

	AVector dirX = mDirX;
	AVector dirY = mDirY;
	AVector dirZ = mDirZ;

	if (DT_X == mDragType)
	{
		transValue = transMoved.Dot(dirX);
		transVec = dirX * transValue;

		rolateVec.X() = transMoved.Length() *(1.0f - Mathf::FAbs(transDir.Dot(dirX)));

		AVector vec = transDir.Cross(dirX);
		rolateVec.X() *= Mathf::Sign(vec.Z());
	}
	else if (DT_Y == mDragType)
	{
		transValue = transMoved.Dot(dirY);
		transVec = dirY * transValue;

		rolateVec.Y() = transMoved.Length() *(1.0f - Mathf::FAbs(transDir.Dot(dirY)));

		AVector vec = transDir.Cross(dirY);
		rolateVec.Y() *= Mathf::Sign(vec.Z());
	}
	else if (DT_Z == mDragType)
	{
		transValue = transMoved.Dot(dirZ);
		transVec = dirZ * transValue;

		rolateVec.Z() = transMoved.Length() *(1.0f - Mathf::FAbs(transDir.Dot(dirZ)));

		rolateVec.Z() *= Mathf::Sign(posNow.X() - posBefore.X());
	}
	else if (DT_XY == mDragType)
	{
		transValue = transMoved.Dot(dirX);
		transValue1 = transMoved.Dot(dirY);
		transVec = dirX * transValue + dirY * transValue1;
	}
	else if (DT_YZ == mDragType)
	{
		transValue = transMoved.Dot(dirY);
		transValue1 = transMoved.Dot(dirZ);
		transVec = dirY * transValue + dirZ * transValue1;
	}
	else if (DT_XZ == mDragType)
	{
		transValue = transMoved.Dot(dirX);
		transValue1 = transMoved.Dot(dirZ);
		transVec = dirX * transValue + dirZ * transValue1;
	}
	else if (DT_XYZ == mDragType)
	{
		float transValue0 = Mathf::FAbs(transMoved.Dot(dirX));
		float transValue1 = Mathf::FAbs(transMoved.Dot(dirY));
		float transValue2 = Mathf::FAbs(transMoved.Dot(dirZ));

		float trans = (transValue0 + transValue1 + transValue2) / 3.0f;
		trans *= Mathf::Sign(transMoved.Y());

		transVec = AVector(trans, trans, trans);
	}

	if (CT_SCALE == mCtrlType)
		transVec *= 0.5f;

	HMatrix parentMat = mParentRotateMat.Inverse();
	transVec = parentMat * transVec;

	if (CT_TRANSLATE == mCtrlType)
	{
		PX2_SELECTION.Translate(transVec);

		UpdateCtrlTrans();
	}
	else if (CT_ROLATE == mCtrlType)
	{
		PX2_SELECTION.AddRolate(rolateVec);
	}
	else if (CT_SCALE == mCtrlType)
	{
		if (DT_XYZ == mDragType)
			PX2_SELECTION.AddScale(transVec);
	}

	Object *obj = PX2_SELECTION.GetFirstObject();
	if (obj)
	{
		Event *ent = EditEventSpace::CreateEventX(
			EditEventSpace::ObjectTransformChanged);
		ent->SetData<Object*>(obj);
		EventWorld::GetSingleton().BroadcastingLocalEvent(ent);
	}

	mCtrlsGroup->Update(Time::GetTimeInSeconds(), false);
}
示例#18
0
//----------------------------------------------------------------------------
void SurfacePatch::ComputePrincipalCurvatureInfo (float u, float v,
    float& curv0, float& curv1, AVector& dir0, AVector& dir1)
{
    // Tangents:  T0 = dP/du = (x_u,y_u,z_u), T1 = dP/dv = (x_v,y_v,z_v)
    // Normal:    N = Cross(T0,T1)/Length(Cross(T0,T1))
    // Metric Tensor:    G = +-                      -+
    //                       | Dot(T0,T0)  Dot(T0,T1) |
    //                       | Dot(T1,T0)  Dot(T1,T1) |
    //                       +-                      -+
    //
    // Curvature Tensor:  B = +-                          -+
    //                        | -Dot(N,T0_u)  -Dot(N,T0_v) |
    //                        | -Dot(N,T1_u)  -Dot(N,T1_v) |
    //                        +-                          -+
    //
    // Principal curvatures k are the generalized eigenvalues of
    //
    //     Bw = kGw
    //
    // If k is a curvature and w=(a,b) is the corresponding solution to
    // Bw = kGw, then the principal direction as a 3D vector is d = a*U+b*V.
    //
    // Let k1 and k2 be the principal curvatures.  The mean curvature
    // is (k1+k2)/2 and the Gaussian curvature is k1*k2.

    // Compute the derivatives.
    AVector derU = PU(u, v);
    AVector derV = PV(u, v);
    AVector derUU = PUU(u, v);
    AVector derUV = PUV(u, v);
    AVector derVV = PVV(u, v);

    // Compute the metric tensor.
    float metricTensor[2][2];
    metricTensor[0][0] = derU.Dot(derU);
    metricTensor[0][1] = derU.Dot(derV);
    metricTensor[1][0] = metricTensor[0][1];
    metricTensor[1][1] = derV.Dot(derV);

    // Compute the curvature tensor.
    AVector normal = derU.UnitCross(derV);
    float curvatureTensor[2][2];
    curvatureTensor[0][0] = -normal.Dot(derUU);
    curvatureTensor[0][1] = -normal.Dot(derUV);
    curvatureTensor[1][0] = curvatureTensor[0][1];
    curvatureTensor[1][1] = -normal.Dot(derVV);

    // Characteristic polynomial is 0 = det(B-kG) = c2*k^2+c1*k+c0.
    float c0 = curvatureTensor[0][0]*curvatureTensor[1][1] -
        curvatureTensor[0][1]*curvatureTensor[1][0];
    float c1 = 2.0f*curvatureTensor[0][1]* metricTensor[0][1] -
        curvatureTensor[0][0]*metricTensor[1][1] -
        curvatureTensor[1][1]*metricTensor[0][0];
    float c2 = metricTensor[0][0]*metricTensor[1][1] -
        metricTensor[0][1]*metricTensor[1][0];

    // Principal curvatures are roots of characteristic polynomial.
    float temp = Mathf::Sqrt(Mathf::FAbs(c1*c1 - 4.0f*c0*c2));
    curv0 = -0.5f*(c1+temp);
    curv1 = 0.5f*(-c1+temp);

    // Principal directions are solutions to (B-kG)w = 0,
    // w1 = (b12-k1*g12,-(b11-k1*g11)) OR (b22-k1*g22,-(b12-k1*g12))
    float a0 = curvatureTensor[0][1] - curv0*metricTensor[0][1];
    float a1 = curv0*metricTensor[0][0] - curvatureTensor[0][0];
    float length = Mathf::Sqrt(a0*a0 + a1*a1);
    if (length >= Mathf::ZERO_TOLERANCE)
    {
        dir0 = a0*derU + a1*derV;
    }
    else
    {
        a0 = curvatureTensor[1][1] - curv0*metricTensor[1][1];
        a1 = curv0*metricTensor[0][1] - curvatureTensor[0][1];
        length = Mathf::Sqrt(a0*a0 + a1*a1);
        if (length >= Mathf::ZERO_TOLERANCE)
        {
            dir0 = a0*derU + a1*derV;
        }
        else
        {
            // Umbilic (surface is locally sphere, any direction principal).
            dir0 = derU;
        }
    }
    dir0.Normalize();

    // Second tangent is cross product of first tangent and normal.
    dir1 = dir0.Cross(normal);
}
示例#19
0
//----------------------------------------------------------------------------
bool Portal::ReducedFrustum (const Culler& culler,
                             float reducedFrustum[6])
{
    // The portal polygon is transformed into the camera coordinate system
    // and projected onto the near plane.  An axis-aligned bounding rectangle
    // is computed for the projected points and clipped against the left,
    // right, bottom, and top frustum planes.  The result is itself an
    // axis-aligned bounding rectangle that is used to define a "reduced
    // frustum" to be used for drawing what is visible through the portal
    // polygon.
    //
    // The algorithm must handle the situation when portal polygon vertices
    // are behind the observer.  Imagine standing in a room with a doorway
    // immediately to your left.  Part of the doorway frame is in front of
    // you (and visible) and part of it is behind you (and not visible).
    // A portal point is represented by P = E + d*D + u*U + r*R, where E is
    // the world location for the eye point, D is the camera's world direction
    // vector, U is the camera's world up vector, and R is the camera's world
    // right vector.  The camera coordinates for the portal point are (d,u,r).
    // If d > 0, P is in front of the eye point and has a projection onto the
    // near plane d = n.  If d < 0, P is behind the eye point and does not
    // have a projection onto the near plane.  If d = 0, P projects to
    // "infinity" on the near plane, a problematic case to deal with.
    //
    // To avoid dealing with d = 0, choose a small value e such that
    // 0 < e < n.  The portal polygon is clipped against the plane d = e,
    // keeping only that portion whose points satisfy d >= e.  The clipped
    // polygon always has a projection onto the near plane.  The axis-aligned
    // bounding box for this projection is computed; clipped against the
    // left, right, bottom, and top of the frustum; and the result used to
    // define the reduced frustum.  All this is designed for an inexact
    // culling of the objects in the adjacent room, so it is useful to avoid
    // preserving the topology of the portal polygon as it is clipped.
    // Instead, the portal polygon vertices with d > e are projected and
    // the intersection points of portal polygon edges with d = e are
    // computed and projected.  The axis-aligned bounding box is computed for
    // the projections, a process that does not require knowing the polygon
    // topology.  The algorithm is essentially the one used for clipping a
    // convex polygon against the view frustum in the software renderer.  The
    // polygon vertices are traversed in-order and the signs of the d values
    // are updated accordingly.  This avoids computing d-signs twice per
    // vertex.

    const Camera* camera = culler.GetCamera();
    const float* frustum = culler.GetFrustum();
    float rmin = +Mathf::MAX_REAL;  // left
    float rmax = -Mathf::MAX_REAL;  // right
    float umin = +Mathf::MAX_REAL;  // bottom
    float umax = -Mathf::MAX_REAL;  // top

    AVector diff;
    APoint vertexCam;
    int i;

    if (camera->IsPerspective())
    {
        const float epsilon = 1e-6f, invEpsilon = 1e+6f;
        int firstSign = 0, lastSign = 0;  // in {-1,0,1}
        bool signChange = false;
        APoint firstVertex = APoint::ORIGIN;
        APoint lastVertex = APoint::ORIGIN;
        float NdD, UdD, RdD, t;

        for (i = 0; i < mNumVertices; i++)
        {
            diff = mWorldVertices[i] - camera->GetPosition();
            vertexCam[0] = diff.Dot(camera->GetDVector());
            vertexCam[1] = diff.Dot(camera->GetUVector());
            vertexCam[2] = diff.Dot(camera->GetRVector());
            vertexCam[3] = 1.0f;

            if (vertexCam[0] > epsilon)
            {
                if (firstSign == 0)
                {
                    firstSign = 1;
                    firstVertex = vertexCam;
                }

                NdD = frustum[Camera::VF_DMIN]/vertexCam[0];
                UdD = vertexCam[1]*NdD;
                RdD = vertexCam[2]*NdD;

                if (UdD < umin)
                {
                    umin = UdD;
                }
                if (UdD > umax)
                {
                    umax = UdD;
                }

                if (RdD < rmin)
                {
                    rmin = RdD;
                }
                if (RdD > rmax)
                {
                    rmax = RdD;
                }

                if (lastSign < 0)
                {
                    signChange = true;
                }

                lastSign = 1;
            }
            else
            {
                if (firstSign == 0)
                {
                    firstSign = -1;
                    firstVertex = vertexCam;
                }

                if (lastSign > 0)
                {
                    signChange = true;
                }

                lastSign = -1;
            }

            if (signChange)
            {
                diff = vertexCam - lastVertex;
                t = (epsilon - lastVertex[0])/diff[0];
                NdD = frustum[Camera::VF_DMIN]*invEpsilon;
                UdD = (lastVertex[1] + t*diff[1])*NdD;
                RdD = (lastVertex[2] + t*diff[2])*NdD;

                if (UdD < umin)
                {
                    umin = UdD;
                }
                if (UdD > umax)
                {
                    umax = UdD;
                }

                if (RdD < rmin)
                {
                    rmin = RdD;
                }
                if (RdD > rmax)
                {
                    rmax = RdD;
                }

                signChange = false;
            }

            lastVertex = vertexCam;
        }

        if (firstSign*lastSign < 0)
        {
            // Process the last polygon edge.
            diff = firstVertex - lastVertex;
            t = (epsilon - lastVertex[0])/diff[0];
            UdD = (lastVertex[1] + t*diff[1])*invEpsilon;
            RdD = (lastVertex[2] + t*diff[2])*invEpsilon;

            if (UdD < umin)
            {
                umin = UdD;
            }
            if (UdD > umax)
            {
                umax = UdD;
            }

            if (RdD < rmin)
            {
                rmin = RdD;
            }
            if (RdD > rmax)
            {
                rmax = RdD;
            }
        }
    }
    else
    {
        for (i = 0; i < mNumVertices; i++)
        {
            diff = mWorldVertices[i] - camera->GetPosition();
            vertexCam[1] = diff.Dot(camera->GetUVector());
            vertexCam[2] = diff.Dot(camera->GetRVector());

            if (vertexCam[1] < umin)
            {
                umin = vertexCam[1];
            }
            if (vertexCam[1] > umax)
            {
                umax = vertexCam[1];
            }

            if (vertexCam[2] < rmin)
            {
                rmin = vertexCam[2];
            }
            if (vertexCam[2] > rmax)
            {
                rmax = vertexCam[2];
            }
        }
    }

    // Test whether the axis-aligned bounding rectangle is outside the current
    // frustum.  If it is, the adjoining room need not be visited.
    if (frustum[Camera::VF_RMIN] >= rmax ||
            frustum[Camera::VF_RMAX] <= rmin ||
            frustum[Camera::VF_UMIN] >= umax ||
            frustum[Camera::VF_UMAX] <= umin)
    {
        return false;
    }

    // The axis-aligned bounding rectangle intersects the current frustum.
    // Reduce the frustum for use in drawing the adjoining room.
    for (int j = 0; j < 6; ++j)
    {
        reducedFrustum[j] = frustum[j];
    }

    if (reducedFrustum[Camera::VF_RMIN] < rmin)
    {
        reducedFrustum[Camera::VF_RMIN] = rmin;
    }

    if (reducedFrustum[Camera::VF_RMAX] > rmax)
    {
        reducedFrustum[Camera::VF_RMAX] = rmax;
    }

    if (reducedFrustum[Camera::VF_UMIN] < umin)
    {
        reducedFrustum[Camera::VF_UMIN] = umin;
    }

    if (reducedFrustum[Camera::VF_UMAX] > umax)
    {
        reducedFrustum[Camera::VF_UMAX] = umax;
    }

    return true;
}
示例#20
0
//----------------------------------------------------------------------------
void SimpleBumpMapEffect::ComputeLightVectors (Triangles* mesh,
    const AVector& worldLightDirection)
{
    // The tangent-space coordinates for the light direction vector at each
    // vertex is stored in the color0 channel.  The computations use the
    // vertex normals and the texture coordinates for the base mesh, which
    // are stored in the tcoord0 channel.  Thus, the mesh must have positions,
    // normals, colors (unit 0), and texture coordinates (unit 0).

    // The light direction D is in world-space coordinates.  Negate it,
    // transform it to model-space coordinates, and then normalize it.  The
    // world-space direction is unit-length, but the geometric primitive
    // might have non-unit scaling in its model-to-world transformation, in
    // which case the normalization is necessary.
    AVector modelLightDirection =
        -mesh->WorldTransform.Inverse()*worldLightDirection;

    // Set the light vectors to (0,0,0) as a flag that the quantity has not
    // yet been computed.  The probability that a light vector is actually
    // (0,0,0) should be small, so the flag system should save computation
    // time overall.
    VertexBufferAccessor vba(mesh);
    Float3 black(0.0f, 0.0f, 0.0f);
    int i;
    for (i = 0; i < vba.GetNumVertices(); ++i)
    {
        vba.Color<Float3>(0, i) = black;
    }

    int numTriangles = mesh->GetNumTriangles();
    for (int t = 0; t < numTriangles; ++t)
    {
        // Get the triangle vertices and attributes.
        int v0, v1, v2;
        if (!mesh->GetTriangle(t, v0, v1, v2))
        {
            continue;
        }

        APoint position[3] =
        {
            vba.Position<Float3>(v0),
            vba.Position<Float3>(v1),
            vba.Position<Float3>(v2)
        };

        AVector normal[3] =
        {
            vba.Normal<Float3>(v0),
            vba.Normal<Float3>(v1),
            vba.Normal<Float3>(v2)
        };

        Float3* color[3] =
        {
            &vba.Color<Float3>(0, v0),
            &vba.Color<Float3>(0, v1),
            &vba.Color<Float3>(0, v2)
        };

        Float2 tcoord[3] =
        {
            vba.TCoord<Float2>(0, v0),
            vba.TCoord<Float2>(0, v1),
            vba.TCoord<Float2>(0, v2)
        };

        for (i = 0; i < 3; ++i)
        {
            Float3& colorref = *color[i];
            if (colorref != black)
            {
                continue;
            }

            int iP = (i == 0) ? 2 : i - 1;
            int iN = (i + 1) % 3;

            AVector tangent;
            if (!ComputeTangent(position[i], tcoord[i], position[iN],
                tcoord[iN], position[iP], tcoord[iP], tangent))
            {
                // The texture coordinate mapping is not properly defined for
                // this.  Just say that the tangent space light vector points
                // in the same direction as the surface normal.
                colorref[0] = normal[i][0];
                colorref[1] = normal[i][1];
                colorref[2] = normal[i][2];
                continue;
            }

            // Project T into the tangent plane by projecting out the surface
            // normal N, and then make it unit length.
            tangent -= normal[i].Dot(tangent)*(normal[i]);
            tangent.Normalize();

            // Compute the bitangent B, another tangent perpendicular to T.
            AVector bitangent = normal[i].UnitCross(tangent);

            // The set {T,B,N} is a right-handed orthonormal set.  The
            // negated light direction U = -D is represented in this
            // coordinate system as
            //   U = Dot(U,T)*T + Dot(U,B)*B + Dot(U,N)*N
            float dotUT = modelLightDirection.Dot(tangent);
            float dotUB = modelLightDirection.Dot(bitangent);
            float dotUN = modelLightDirection.Dot(normal[i]);

            // Transform the light vector into [0,1]^3 to make it a valid
            // Float3 object.
            colorref[0] = 0.5f*(dotUT + 1.0f);
            colorref[1] = 0.5f*(dotUB + 1.0f);
            colorref[2] = 0.5f*(dotUN + 1.0f);
        }
    }
}
示例#21
0
//----------------------------------------------------------------------------
void Triangles::UpdateModelTangentsUseTCoords (VertexBufferAccessor& vba)
{
    // Each vertex can be visited multiple times, so compute the tangent
    // space only on the first visit.  Use the zero vector as a flag for the
    // tangent vector not being computed.
    const int numVertices = vba.GetNumVertices();
    bool hasTangent = vba.HasTangent();
    Float3 zero(0.0f, 0.0f, 0.0f);
    int i;
    if (hasTangent)
    {
        for (i = 0; i < numVertices; ++i)
        {
            vba.Tangent<Float3>(i) = zero;
        }
    }
    else
    {
        for (i = 0; i < numVertices; ++i)
        {
            vba.Binormal<Float3>(i) = zero;
        }
    }

    const int numTriangles = GetNumTriangles();
    for (i = 0; i < numTriangles; i++)
    {
        // Get the triangle vertices' positions, normals, tangents, and
        // texture coordinates.
        int v0, v1, v2;
        if (!GetTriangle(i, v0, v1, v2))
        {
            continue;
        }

        APoint locPosition[3] =
        {
            vba.Position<Float3>(v0),
            vba.Position<Float3>(v1),
            vba.Position<Float3>(v2)
        };

        AVector locNormal[3] =
        {
            vba.Normal<Float3>(v0),
            vba.Normal<Float3>(v1),
            vba.Normal<Float3>(v2)
        };

        AVector locTangent[3] =
        {
            (hasTangent ? vba.Tangent<Float3>(v0) : vba.Binormal<Float3>(v0)),
            (hasTangent ? vba.Tangent<Float3>(v1) : vba.Binormal<Float3>(v1)),
            (hasTangent ? vba.Tangent<Float3>(v2) : vba.Binormal<Float3>(v2))
        };

        Float2 locTCoord[3] =
        {
            vba.TCoord<Float2>(0, v0),
            vba.TCoord<Float2>(0, v1),
            vba.TCoord<Float2>(0, v2)
        };

        for (int curr = 0; curr < 3; ++curr)
        {
            Float3 currLocTangent = (Float3)locTangent[curr];
            if (currLocTangent != zero)
            {
                // This vertex has already been visited.
                continue;
            }

            // Compute the tangent space at the vertex.
            AVector norvec = locNormal[curr];
            int prev = ((curr + 2) % 3);
            int next = ((curr + 1) % 3);
            AVector tanvec = ComputeTangent(
                locPosition[curr], locTCoord[curr],
                locPosition[next], locTCoord[next],
                locPosition[prev], locTCoord[prev]);

            // Project T into the tangent plane by projecting out the surface
            // normal N, and then making it unit length.
            tanvec -= norvec.Dot(tanvec)*norvec;
            tanvec.Normalize();

            // Compute the bitangent B, another tangent perpendicular to T.
            AVector binvec = norvec.UnitCross(tanvec);

            if (vba.HasTangent())
            {
                locTangent[curr] = tanvec;
                if (vba.HasBinormal())
                {
                    vba.Binormal<Float3>(curr) = binvec;
                }
            }
            else
            {
                vba.Binormal<Float3>(curr) = tanvec;
            }
        }
    }
}
示例#22
0
//----------------------------------------------------------------------------
void Triangles::UpdateModelTangentsUseGeometry (VertexBufferAccessor& vba)
{
    // Compute the matrix of normal derivatives.
    const int numVertices = vba.GetNumVertices();
    HMatrix* dNormal = new1<HMatrix>(numVertices);
    HMatrix* wwTrn = new1<HMatrix>(numVertices);
    HMatrix* dwTrn = new1<HMatrix>(numVertices);
    memset(wwTrn, 0, numVertices*sizeof(HMatrix));
    memset(dwTrn, 0, numVertices*sizeof(HMatrix));

    const int numTriangles = GetNumTriangles();
    int i, row, col;
    for (i = 0; i < numTriangles; ++i)
    {
        // Get the vertex indices for the triangle.
        int v[3];
        if (!GetTriangle(i, v[0], v[1], v[2]))
        {
            continue;
        }

        for (int j = 0; j < 3; j++)
        {
            // Get the vertex positions and normals.
            int v0 = v[j];
            int v1 = v[(j + 1) % 3];
            int v2 = v[(j + 2) % 3];
            APoint pos0 = vba.Position<Float3>(v0);
            APoint pos1 = vba.Position<Float3>(v1);
            APoint pos2 = vba.Position<Float3>(v2);
            AVector nor0 = vba.Normal<Float3>(v0);
            AVector nor1 = vba.Normal<Float3>(v1);
            AVector nor2 = vba.Normal<Float3>(v2);

            // Compute the edge from pos0 to pos1, project it to the tangent
            // plane of the vertex, and compute the difference of adjacent
            // normals.
            AVector edge = pos1 - pos0;
            AVector proj = edge - edge.Dot(nor0)*nor0;
            AVector diff = nor1 - nor0;
            for (row = 0; row < 3; ++row)
            {
                for (col = 0; col < 3; ++col)
                {
                    wwTrn[v0][row][col] += proj[row]*proj[col];
                    dwTrn[v0][row][col] += diff[row]*proj[col];
                }
            }

            // Compute the edge from pos0 to pos2, project it to the tangent
            // plane of the vertex, and compute the difference of adjacent
            // normals.
            edge = pos2 - pos0;
            proj = edge - edge.Dot(nor0)*nor0;
            diff = nor2 - nor0;
            for (row = 0; row < 3; ++row)
            {
                for (col = 0; col < 3; ++col)
                {
                    wwTrn[v0][row][col] += proj[row]*proj[col];
                    dwTrn[v0][row][col] += diff[row]*proj[col];
                }
            }
        }
    }

    // Add N*N^T to W*W^T for numerical stability.  In theory 0*0^T is added
    // to D*W^T, but of course no update is needed in the implementation.
    // Compute the matrix of normal derivatives.
    for (i = 0; i < numVertices; ++i)
    {
        AVector nor = vba.Normal<Float3>(i);
        for (row = 0; row < 3; ++row)
        {
            for (col = 0; col < 3; ++col)
            {
                wwTrn[i][row][col] =
                    0.5f*wwTrn[i][row][col] + nor[row]*nor[col];
                dwTrn[i][row][col] *= 0.5f;
            }
        }

        wwTrn[i].SetColumn(3, APoint::ORIGIN);
        dNormal[i] = dwTrn[i]*wwTrn[i].Inverse();
    }

    delete1(wwTrn);
    delete1(dwTrn);

    // If N is a unit-length normal at a vertex, let U and V be unit-length
    // tangents so that {U, V, N} is an orthonormal set.  Define the matrix
    // J = [U | V], a 3-by-2 matrix whose columns are U and V.  Define J^T
    // to be the transpose of J, a 2-by-3 matrix.  Let dN/dX denote the
    // matrix of first-order derivatives of the normal vector field.  The
    // shape matrix is
    //   S = (J^T * J)^{-1} * J^T * dN/dX * J = J^T * dN/dX * J
    // where the superscript of -1 denotes the inverse.  (The formula allows
    // for J built from non-perpendicular vectors.) The matrix S is 2-by-2.
    // The principal curvatures are the eigenvalues of S.  If k is a principal
    // curvature and W is the 2-by-1 eigenvector corresponding to it, then
    // S*W = k*W (by definition).  The corresponding 3-by-1 tangent vector at
    // the vertex is called the principal direction for k, and is J*W.  The
    // principal direction for the minimum principal curvature is stored as
    // the mesh tangent.  The principal direction for the maximum principal
    // curvature is stored as the mesh bitangent.
    for (i = 0; i < numVertices; ++i)
    {
        // Compute U and V given N.
        AVector norvec = vba.Normal<Float3>(i);
        AVector uvec, vvec;
        AVector::GenerateComplementBasis(uvec, vvec, norvec);

        // Compute S = J^T * dN/dX * J.  In theory S is symmetric, but
        // because we have estimated dN/dX, we must slightly adjust our
        // calculations to make sure S is symmetric.
        float s01 = uvec.Dot(dNormal[i]*vvec);
        float s10 = vvec.Dot(dNormal[i]*uvec);
        float sAvr = 0.5f*(s01 + s10);
        float smat[2][2] =
        {
            { uvec.Dot(dNormal[i]*uvec), sAvr },
            { sAvr, vvec.Dot(dNormal[i]*vvec) }
        };

        // Compute the eigenvalues of S (min and max curvatures).
        float trace = smat[0][0] + smat[1][1];
        float det = smat[0][0]*smat[1][1] - smat[0][1]*smat[1][0];
        float discr = trace*trace - 4.0f*det;
        float rootDiscr = Mathf::Sqrt(Mathf::FAbs(discr));
        float minCurvature = 0.5f*(trace - rootDiscr);
        // float maxCurvature = 0.5f*(trace + rootDiscr);

        // Compute the eigenvectors of S.
        AVector evec0(smat[0][1], minCurvature - smat[0][0], 0.0f);
        AVector evec1(minCurvature - smat[1][1], smat[1][0], 0.0f);
        AVector tanvec, binvec;
        if (evec0.SquaredLength() >= evec1.SquaredLength())
        {
            evec0.Normalize();
            tanvec = evec0.X()*uvec + evec0.Y()*vvec;
            binvec = norvec.Cross(tanvec);
        }
        else
        {
            evec1.Normalize();
            tanvec = evec1.X()*uvec + evec1.Y()*vvec;
            binvec = norvec.Cross(tanvec);
        }

        if (vba.HasTangent())
        {
            vba.Tangent<Float3>(i) = tanvec;
        }

        if (vba.HasBinormal())
        {
            vba.Binormal<Float3>(i) = binvec;
        }
    }

    delete1(dNormal);
}
示例#23
0
//----------------------------------------------------------------------------
int Culler::WhichSide (const HPlane& plane) const
{
    // The plane is N*(X-C) = 0 where the * indicates dot product.  The signed
    // distance from the camera location E to the plane is N*(E-C).
    float NdEmC = plane.DistanceTo(mCamera->GetPosition());

    AVector normal = plane.GetNormal();
    float NdD = normal.Dot(mCamera->GetDVector());
    float NdU = normal.Dot(mCamera->GetUVector());
    float NdR = normal.Dot(mCamera->GetRVector());
    float FdN = mFrustum[Camera::VF_DMAX]/mFrustum[Camera::VF_DMIN];

    int positive = 0, negative = 0;
    float sgnDist;

    // Check near-plane vertices.
    float PDMin = mFrustum[Camera::VF_DMIN]*NdD;
    float NUMin = mFrustum[Camera::VF_UMIN]*NdU;
    float NUMax = mFrustum[Camera::VF_UMAX]*NdU;
    float NRMin = mFrustum[Camera::VF_RMIN]*NdR;
    float NRMax = mFrustum[Camera::VF_RMAX]*NdR;

    // V = E + dmin*D + umin*U + rmin*R
    // N*(V-C) = N*(E-C) + dmin*(N*D) + umin*(N*U) + rmin*(N*R)
    sgnDist = NdEmC + PDMin + NUMin + NRMin;
    if (sgnDist > 0.0f)
    {
        positive++;
    }
    else if (sgnDist < 0.0f)
    {
        negative++;
    }

    // V = E + dmin*D + umin*U + rmax*R
    // N*(V-C) = N*(E-C) + dmin*(N*D) + umin*(N*U) + rmax*(N*R)
    sgnDist = NdEmC + PDMin + NUMin + NRMax;
    if (sgnDist > 0.0f)
    {
        positive++;
    }
    else if (sgnDist < 0.0f)
    {
        negative++;
    }

    // V = E + dmin*D + umax*U + rmin*R
    // N*(V-C) = N*(E-C) + dmin*(N*D) + umax*(N*U) + rmin*(N*R)
    sgnDist = NdEmC + PDMin + NUMax + NRMin;
    if (sgnDist > 0.0f)
    {
        positive++;
    }
    else if (sgnDist < 0.0f)
    {
        negative++;
    }

    // V = E + dmin*D + umax*U + rmax*R
    // N*(V-C) = N*(E-C) + dmin*(N*D) + umax*(N*U) + rmax*(N*R)
    sgnDist = NdEmC + PDMin + NUMax + NRMax;
    if (sgnDist > 0.0f)
    {
        positive++;
    }
    else if (sgnDist < 0.0f)
    {
        negative++;
    }

    // check far-plane vertices (s = dmax/dmin)
    float PDMax = mFrustum[Camera::VF_DMAX]*NdD;
    float FUMin = FdN*NUMin;
    float FUMax = FdN*NUMax;
    float FRMin = FdN*NRMin;
    float FRMax = FdN*NRMax;

    // V = E + dmax*D + umin*U + rmin*R
    // N*(V-C) = N*(E-C) + dmax*(N*D) + s*umin*(N*U) + s*rmin*(N*R)
    sgnDist = NdEmC + PDMax + FUMin + FRMin;
    if (sgnDist > 0.0f)
    {
        positive++;
    }
    else if (sgnDist < 0.0f)
    {
        negative++;
    }

    // V = E + dmax*D + umin*U + rmax*R
    // N*(V-C) = N*(E-C) + dmax*(N*D) + s*umin*(N*U) + s*rmax*(N*R)
    sgnDist = NdEmC + PDMax + FUMin + FRMax;
    if (sgnDist > 0.0f)
    {
        positive++;
    }
    else if (sgnDist < 0.0f)
    {
        negative++;
    }

    // V = E + dmax*D + umax*U + rmin*R
    // N*(V-C) = N*(E-C) + dmax*(N*D) + s*umax*(N*U) + s*rmin*(N*R)
    sgnDist = NdEmC + PDMax + FUMax + FRMin;
    if (sgnDist > 0.0f)
    {
        positive++;
    }
    else if (sgnDist < 0.0f)
    {
        negative++;
    }

    // V = E + dmax*D + umax*U + rmax*R
    // N*(V-C) = N*(E-C) + dmax*(N*D) + s*umax*(N*U) + s*rmax*(N*R)
    sgnDist = NdEmC + PDMax + FUMax + FRMax;
    if (sgnDist > 0.0f)
    {
        positive++;
    }
    else if (sgnDist < 0.0f)
    {
        negative++;
    }

    if (positive > 0)
    {
        if (negative > 0)
        {
            // Frustum straddles the plane.
            return 0;
        }

        // Frustum is fully on the positive side.
        return +1;
    }

    // Frustum is fully on the negative side.
    return -1;
}