两种方法获取平截头体6个面方程

方法一: 可以根据视口四个角坐标计算出平截头体8个角坐标:

根据视口获取平截头体6面方程
        //获取视口宽高
	double dWidth = pCamera->getViewport()->width();
	double dHeight =pCamera->getViewport()->height();

	//平截头体近裁剪面左上角坐标
	osg::Vec3d windowPosLeftUp1(0.0,dHeight, -1.0 );
	osg::Vec3d wordPLeftUpNear = OsgMathUtility::windowPos2WorldPos(pCamera, windowPosLeftUp1);
      //平截头体远裁剪面左上角坐标
	osg::Vec3d windowPosLeftUp2(0.0, dHeight, 1.0);
	osg::Vec3d wordPLeftUpFar = OsgMathUtility::windowPos2WorldPos(pCamera, windowPosLeftUp2);

	平截头体近裁剪左下角
	osg::Vec3d windowPosLeftBottom1(0.0, 0.0, -1.0);
	osg::Vec3d wordPLeftBottomNear = OsgMathUtility::windowPos2WorldPos(pCamera, windowPosLeftBottom1);
       平截头体远裁剪左下角
	osg::Vec3d windowPosLeftBottom2(0.0,0.0, 1.0);
	osg::Vec3d wordPLeftBottomFar = OsgMathUtility::windowPos2WorldPos(pCamera, windowPosLeftBottom2);

	平截头体近裁剪右上角
	osg::Vec3d windowPosRightUp1(dWidth, dHeight, -1.0);
	osg::Vec3d wordPRightUpNear = OsgMathUtility::windowPos2WorldPos(pCamera, windowPosRightUp1);

	osg::Vec3d windowPosRightUp2(dWidth, dHeight, 1.0);
	osg::Vec3d wordPRightUpFar = OsgMathUtility::windowPos2WorldPos(pCamera, windowPosRightUp2);

	平截头体近裁剪右下角
	osg::Vec3d windowPosRightBottom1(dWidth, 0.0, -1.0);
	osg::Vec3d wordPRightBottomNear = OsgMathUtility::windowPos2WorldPos(pCamera, windowPosRightBottom1);

	osg::Vec3d windowPosRightBottom2(dWidth, 0.0, 1.0);
	osg::Vec3d wordPRightBottomFar = OsgMathUtility::windowPos2WorldPos(pCamera, windowPosRightBottom2);
    
    ///再根据坐标转成向量坐标(注:根据右手向量相乘判断向量方向)
    //计算平截头体远平面
	OsgPlane* pPlaneFar1 = new OsgPlane();
	if (pPlaneFar1)
		pPlaneFar1->redeFine(wordPRightUpFar,wordPLeftUpFar, wordPRightBottomFar );
	//计算平截头体近平面
	OsgPlane* pPlaneNear1 = new OsgPlane();
	if (pPlaneNear1)
		pPlaneNear1->redeFine(wordPRightUpNear, wordPRightBottomNear, wordPLeftUpNear);
	//计算平截头体左平面
	OsgPlane* pPlaneLeft1 = new OsgPlane();
	if (pPlaneLeft1)
		pPlaneLeft1->redeFine(wordPLeftUpNear, wordPLeftBottomNear, wordPLeftUpFar );
	//计算平截头右平面
	OsgPlane* pPlaneRight1 = new OsgPlane();
	if (pPlaneRight1)
		pPlaneRight1->redeFine(wordPRightUpNear, wordPRightUpFar, wordPRightBottomNear);
	//计算平截头上平面
	OsgPlane* pPlaneUp1 = new OsgPlane();
	if (pPlaneUp1)
		pPlaneUp1->redeFine(wordPRightUpNear, wordPLeftUpFar, wordPRightUpFar);
	//计算平截头下平面
	OsgPlane* pPlaneBotom1 = new OsgPlane();
	if (pPlaneBotom1)
		pPlaneBotom1->redeFine(wordPRightBottomNear, wordPRightBottomFar, wordPLeftBottomNear);

方法二:根据视口矩阵和投影矩阵,相乘获取裁剪空间矩阵,最后再根据矩阵值求出平截头体6个面方程:

1、 裁剪矩阵 = 视图矩阵 × 投影矩阵
2、3D世界上的点p =(x,y,z,1)。还考虑一个模型视图矩阵中号和投影矩阵P。使用以下公式,通过矩阵视图矩阵V和投影矩阵P将点p转换为剪辑空间中的点pc =(xc,yc,zc,wc):
pc = pVP
点pc是 齐次坐标,当归一化时变为pcn:
pcn = (xc/wc,yc/wc zc/wc) = (x’, y’, z’)
3、在标准化的剪辑空间中,视锥体是以原点为中心的轴对齐框,并由以下平面限定:

                             左平面:x'= -1
                             右平面:x'= 1
                             顶部平面:y'= 1
                             底部平面:y'= -1
                             近平面:z'= -1
                             远平面:z'= 1

这意味着点pcn =(x’,y’,z’)在视锥体内,如果:

                            -1< x'<1 
                             -1<y'< 1
                            -1<z'< 1

在非标准化坐标中,点pc必须满足以下条件才能在视锥体内:

                            -wc<xc<wc
                            -wc<yc<wc      
                             -wc<zc<wc 

基于该信息,可以在世界坐标中提取限制视锥体的六个平面。如果点pc位于左平面的“右”侧: -wc<xc
在这里插入图片描述
其他各平面如上方法计算。

        //获取裁剪矩阵
	osg::Matrixd VPmat = pCamera->getViewMatrix()*pCamera->getProjectionMatrix();
	double XX(0.0),YY(0.0),ZZ(0.0),dd(0.0);
      //计算平截头左平面
	OsgPlane* pPlaneLeft = m_mapFrustumPlane[FrustumPlane::PLANE_LEFT];
	if (pPlaneLeft)
	{
		XX = VPmat(0,3)+ VPmat(0,0);      // 注(row, col)
		YY = VPmat(1,3)+ VPmat(1,0);     // 注(row, col)
		ZZ = VPmat(2,3)+ VPmat(2,0);     // 注(row, col)
		dd = VPmat(3,3)+ VPmat(3,0);      // 注(row, col)
		osg::Vec3d normal(XX, YY, ZZ);
		dd /= normal.normalize();
		pPlaneLeft->redeFine(normal, dd);
	}
	//计算平截头右平面
	OsgPlane* pPlaneRight = m_mapFrustumPlane[FrustumPlane::PLANE_RIGHT];
	if (pPlaneRight)
	{
		XX = VPmat(0,3) - VPmat(0,0);
		YY = VPmat(1,3) - VPmat(1,0);
		ZZ = VPmat(2,3) - VPmat(2,0);
		dd = VPmat(3,3) - VPmat(3,0);
		osg::Vec3d normal(XX, YY, ZZ);
		dd /= normal.normalize();
		pPlaneRight->redeFine(normal, dd);
	}
	//计算平截头上平面
	OsgPlane* pPlaneUp = m_mapFrustumPlane[FrustumPlane::PLANE_UP];
	if (pPlaneUp)		
	{
		XX = VPmat(0,3)- VPmat(0,1);
		YY = VPmat(1,3)- VPmat(1,1);
		ZZ = VPmat(2,3)- VPmat(2,1);
		dd = VPmat(3,3)- VPmat(3,1);
		osg::Vec3d normal(XX, YY, ZZ);
		dd /= normal.normalize();
		pPlaneUp->redeFine(normal, dd);
	}
	//计算平截头下平面
	OsgPlane* pPlaneBotom = m_mapFrustumPlane[FrustumPlane::PLANE_BOTTOM];
	if (pPlaneBotom)
	{
		XX = VPmat(0,3)+ VPmat(0,1);
		YY = VPmat(1,3)+ VPmat(1,1);
		ZZ = VPmat(2,3)+ VPmat(2,1);
		dd = VPmat(3,3)+ VPmat(3,1);
		osg::Vec3d normal(XX, YY, ZZ);
		dd /= normal.normalize();
		pPlaneBotom->redeFine(normal, dd);
	}
	//计算平截头体近平面
	OsgPlane* pPlaneNear = m_mapFrustumPlane[FrustumPlane::PLANE_NEAR];
	if (pPlaneNear)
	{
		XX = VPmat(0,3) + VPmat(0,2);
		YY = VPmat(1,3) + VPmat(1,2);
		ZZ = VPmat(2,3) + VPmat(2,2);
		dd = VPmat(3,3) + VPmat(3,2);
		osg::Vec3d normal(XX, YY, ZZ);
		dd /= normal.normalize();
		pPlaneNear->redeFine(normal, dd);
	}
	//计算平截头体远平面
	OsgPlane* pPlaneFar = m_mapFrustumPlane[FrustumPlane::PLANE_FAR];
	if (pPlaneFar)
	{
		XX = VPmat(0,3) - VPmat(0,2);
		YY = VPmat(1,3) - VPmat(1,2);
		ZZ = VPmat(2,3) - VPmat(2,2);
		dd = VPmat(3,3) - VPmat(3,2);
		osg::Vec3d normal(XX, YY, ZZ);
		dd /= normal.normalize();
		pPlaneFar->redeFine(normal, dd);
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值