void GLRenderSystemCommon::_applyObliqueDepthProjection(Matrix4& matrix,
                                                           const Plane& plane,
                                                           bool forGpuProgram)
    {
        // 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

        Vector4 q;
        q.x = (Math::Sign(plane.normal.x) + matrix[0][2]) / matrix[0][0];
        q.y = (Math::Sign(plane.normal.y) + matrix[1][2]) / matrix[1][1];
        q.z = -1.0F;
        q.w = (1.0F + matrix[2][2]) / matrix[2][3];

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

        // Replace the third row of the projection matrix
        matrix[2][0] = c.x;
        matrix[2][1] = c.y;
        matrix[2][2] = c.z + 1.0F;
        matrix[2][3] = c.w;
    }
示例#2
0
	void Frustum::updateFrustumImpl(void) const
	{
		// 通用计算
		Real left, right, bottom, top;

#if SAPPHIRE_NO_VIEWPORT_ORIENTATIONMODE == 0
		if (mOrientationMode != OR_PORTRAIT)
			calcProjectionParameters(bottom, top, left, right);
		else
#endif
			calcProjectionParameters(left, right, bottom, top);

		//自定义投影矩阵
		if (!mCustomProjMatrix)
		{

			// 这些代码下面要处理通用的投影参数, glFrustum和glOrtho相似
			// 除了除法不手动优化, 所以这些代码多数自我解释
			//宽度w的倒数
			Real inv_w = 1 / (right - left);
			//高度h的倒数
			Real inv_h = 1 / (top - bottom);
			//深度d的倒数
			Real inv_d = 1 / (mFarDist - mNearDist);

			// 如果视锥体参数改变,重新计算
			if (mProjType == PT_PERSPECTIVE)  //透视投影
			{
				// 计算矩阵元素
				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)
				{
					// 无限远平面
					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: 这创建'uniform'的透视投影矩阵,深度范围[-1,1],右手规则
				//
				// [ 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)  //深度投影
				{
					// 变换这个平面的观察空间

					// 如果通过相机和返回一个剔除视锥体观察矩阵重载,不能使用getViewMatrix
					updateView();
					Plane plane = mViewMatrix * mObliqueProjPlane;

					//计算剪切空间对于剪裁平面的角点
					// 如 (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) 并且通过乘投影矩阵的逆矩阵变换它到相机空间


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

					// 计算缩放平面向量
					Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
					Vector4 c = clipPlane4d * (2 / (clipPlane4d.dotProduct(qVec)));

					// 替换投影矩阵的第三行
					mProjMatrix[2][0] = c.x;
					mProjMatrix[2][1] = c.y;
					mProjMatrix[2][2] = c.z + 1;
					mProjMatrix[2][3] = c.w;
				}
			}
			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)
				{
					// 不能出来无限远平面,要避免除0
					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: 创建'uniform'正交投影矩阵,深度范围[-1,1], 右手规范
				//
				// [ 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;
			}
		} // 

#if SAPPHIRE_NO_VIEWPORT_ORIENTATIONMODE == 0
		// 处理朝向模式
		mProjMatrix = mProjMatrix * Quaternion(Degree(mOrientationMode * 90.f), Vector3::UNIT_Z);
#endif

		//RenderSystem* renderSystem = Root::getSingleton().getRenderSystem();
		//指定API
		//renderSystem->_convertProjectionMatrix(mProjMatrix, mProjMatrixRS);
		//指定GPU编程的API模式
		//renderSystem->_convertProjectionMatrix(mProjMatrix, mProjMatrixRSDepth, true);


		// 计算AABB碰撞盒子(本地)
		// 盒子是从0到-z, 最大范围到远裁平面
		// 视锥体最大值
		Real farDist = (mFarDist == 0) ? 100000 : mFarDist;
		// 近剪裁平面的边界
		Vector3 min(left, bottom, -farDist);
		Vector3 max(right, top, 0);

		if (mCustomProjMatrix)
		{
			//有些自定义的投影矩阵能够用不常用的相反设置
			// 所以确定AABB是开始就正确的设置
			Vector3 tmp = min;
			min.makeFloor(max);
			max.makeCeil(tmp);
		}

		if (mProjType == PT_PERSPECTIVE)
		{
			// 合并远裁平面边界
			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;

		//标记视锥体剪裁平面更新
		mRecalcFrustumPlanes = true;
	}
示例#3
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;
	}