예제 #1
0
 //-----------------------------------------------------------------------------
 const Matrix4& AutoParamDataSource::getProjectionMatrix(void) const
 {
     if (mProjMatrixDirty)
     {
         // NB use API-independent projection matrix since GPU programs
         // bypass the API-specific handedness and use right-handed coords
         if (mCurrentRenderable && mCurrentRenderable->getUseIdentityProjection())
         {
             // Use identity projection matrix, still need to take RS depth into account.
             RenderSystem* rs = Root::getSingleton().getRenderSystem();
             rs->_convertProjectionMatrix(Matrix4::IDENTITY, mProjectionMatrix, true);
         }
         else
         {
             mProjectionMatrix = mCurrentCamera->getProjectionMatrixWithRSDepth();
         }
         if (mCurrentRenderTarget && mCurrentRenderTarget->requiresTextureFlipping())
         {
             // Because we're not using setProjectionMatrix, this needs to be done here
             // Invert transformed y
             mProjectionMatrix[1][0] = -mProjectionMatrix[1][0];
             mProjectionMatrix[1][1] = -mProjectionMatrix[1][1];
             mProjectionMatrix[1][2] = -mProjectionMatrix[1][2];
             mProjectionMatrix[1][3] = -mProjectionMatrix[1][3];
         }
         mProjMatrixDirty = false;
     }
     return mProjectionMatrix;
 }
예제 #2
0
	//-----------------------------------------------------------------------
	void Frustum::updateFrustumImpl(void) const
	{
		// Common calcs
		Real left, right, bottom, top;
		calcProjectionParameters(left, right, bottom, top);

		if (!mCustomProjMatrix)
		{

			// The code below will dealing with general projection 
			// parameters, similar glFrustum and glOrtho.
			// Doesn't optimise manually except division operator, so the 
			// code more self-explaining.

			Real inv_w = 1 / (right - left);
			Real inv_h = 1 / (top - bottom);
			Real inv_d = 1 / (mFarDist - mNearDist);

			// Recalc if frustum params changed
			if (mProjType == PT_PERSPECTIVE)
			{
				// Calc matrix elements
				Real A = 2 * mNearDist * inv_w;
				Real B = 2 * mNearDist * inv_h;
				Real C = (right + left) * inv_w;
				Real D = (top + bottom) * inv_h;
				Real q, qn;
				if (mFarDist == 0)
				{
					// Infinite far plane
					q = Frustum::INFINITE_FAR_PLANE_ADJUST - 1;
					qn = mNearDist * (Frustum::INFINITE_FAR_PLANE_ADJUST - 2);
				}
				else
				{
					q = - (mFarDist + mNearDist) * inv_d;
					qn = -2 * (mFarDist * mNearDist) * inv_d;
				}

				// NB: This creates 'uniform' perspective projection matrix,
				// which depth range [-1,1], right-handed rules
				//
				// [ A   0   C   0  ]
				// [ 0   B   D   0  ]
				// [ 0   0   q   qn ]
				// [ 0   0   -1  0  ]
				//
				// A = 2 * near / (right - left)
				// B = 2 * near / (top - bottom)
				// C = (right + left) / (right - left)
				// D = (top + bottom) / (top - bottom)
				// q = - (far + near) / (far - near)
				// qn = - 2 * (far * near) / (far - near)

				mProjMatrix = Matrix4::ZERO;
				mProjMatrix[0][0] = A;
				mProjMatrix[0][2] = C;
				mProjMatrix[1][1] = B;
				mProjMatrix[1][2] = D;
				mProjMatrix[2][2] = q;
				mProjMatrix[2][3] = qn;
				mProjMatrix[3][2] = -1;

				if (mObliqueDepthProjection)
				{
					// Translate the plane into view space

					// Don't use getViewMatrix here, incase overrided by 
					// camera and return a cull frustum view matrix
					updateView();
					Plane plane = mViewMatrix * mObliqueProjPlane;

					// Thanks to Eric Lenyel for posting this calculation 
					// at www.terathon.com

					// Calculate the clip-space corner point opposite the 
					// clipping plane
					// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
					// transform it into camera space by multiplying it
					// by the inverse of the projection matrix

					/* generalised version
					Vector4 q = matrix.inverse() * 
					Vector4(Math::Sign(plane.normal.x), 
					Math::Sign(plane.normal.y), 1.0f, 1.0f);
					*/
					Vector4 q;
					q.x = (Math::Sign(plane.normal.x) + mProjMatrix[0][2]) / mProjMatrix[0][0];
					q.y = (Math::Sign(plane.normal.y) + mProjMatrix[1][2]) / mProjMatrix[1][1];
					q.z = -1;
					q.w = (1 + mProjMatrix[2][2]) / mProjMatrix[2][3];

					// Calculate the scaled plane vector
					Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
					Vector4 c = clipPlane4d * (2 / (clipPlane4d.dotProduct(q)));

					// Replace the third row of the projection matrix
					mProjMatrix[2][0] = c.x;
					mProjMatrix[2][1] = c.y;
					mProjMatrix[2][2] = c.z + 1;
					mProjMatrix[2][3] = c.w; 
				}
			} // perspective
			else if (mProjType == PT_ORTHOGRAPHIC)
			{
				Real A = 2 * inv_w;
				Real B = 2 * inv_h;
				Real C = - (right + left) * inv_w;
				Real D = - (top + bottom) * inv_h;
				Real q, qn;
				if (mFarDist == 0)
				{
					// Can not do infinite far plane here, avoid divided zero only
					q = - Frustum::INFINITE_FAR_PLANE_ADJUST / mNearDist;
					qn = - Frustum::INFINITE_FAR_PLANE_ADJUST - 1;
				}
				else
				{
					q = - 2 * inv_d;
					qn = - (mFarDist + mNearDist)  * inv_d;
				}

				// NB: This creates 'uniform' orthographic projection matrix,
				// which depth range [-1,1], right-handed rules
				//
				// [ A   0   0   C  ]
				// [ 0   B   0   D  ]
				// [ 0   0   q   qn ]
				// [ 0   0   0   1  ]
				//
				// A = 2 * / (right - left)
				// B = 2 * / (top - bottom)
				// C = - (right + left) / (right - left)
				// D = - (top + bottom) / (top - bottom)
				// q = - 2 / (far - near)
				// qn = - (far + near) / (far - near)

				mProjMatrix = Matrix4::ZERO;
				mProjMatrix[0][0] = A;
				mProjMatrix[0][3] = C;
				mProjMatrix[1][1] = B;
				mProjMatrix[1][3] = D;
				mProjMatrix[2][2] = q;
				mProjMatrix[2][3] = qn;
				mProjMatrix[3][3] = 1;
			} // ortho
		} // !mCustomProjMatrix

		RenderSystem* renderSystem = Root::getSingleton().getRenderSystem();
		// API specific
		renderSystem->_convertProjectionMatrix(mProjMatrix, mProjMatrixRS);
		// API specific for Gpu Programs
		renderSystem->_convertProjectionMatrix(mProjMatrix, mProjMatrixRSDepth, true);


		// Calculate bounding box (local)
		// Box is from 0, down -Z, max dimensions as determined from far plane
		// If infinite view frustum just pick a far value
		Real farDist = (mFarDist == 0) ? 100000 : mFarDist;
		// Near plane bounds
		Vector3 min(left, bottom, -farDist);
		Vector3 max(right, top, 0);

		if (mCustomProjMatrix)
		{
			// Some custom projection matrices can have unusual inverted settings
			// So make sure the AABB is the right way around to start with
			Vector3 tmp = min;
			min.makeFloor(max);
			max.makeCeil(tmp);
		}

		if (mProjType == PT_PERSPECTIVE)
		{
			// Merge with far plane bounds
			Real radio = farDist / mNearDist;
			min.makeFloor(Vector3(left * radio, bottom * radio, -farDist));
			max.makeCeil(Vector3(right * radio, top * radio, 0));
		}
		mBoundingBox.setExtents(min, max);

		mRecalcFrustum = false;

		// Signal to update frustum clipping planes
		mRecalcFrustumPlanes = true;
	}