Planar Occlusion 平面遮挡(虽然方法老了但是还有保留的意义)
2009-08-25 16:28
295 查看
#include "PlanarOccluder.h"
NiImplementRTTI(PlanarOccluder, Occluder);
//---------------------------------------------------------------------------
PlanarOccluder::PlanarOccluder()
{
}
//---------------------------------------------------------------------------
PlanarOccluder::PlanarOccluder(NiGeometry* pkPlane)
{
assert (pkPlane != 0);
m_spGeometry = pkPlane; //暂存。在后面的测试点是否在平面的Extent内使用这个Geo的Bounding Box
m_iCameraWhichSide = 0;
FillData(); //使用提供的Geo来创建一个代表他的Plane
}
//---------------------------------------------------------------------------
PlanarOccluder::~PlanarOccluder()
{
m_spGeometry = 0;
}
//---------------------------------------------------------------------------
void PlanarOccluder::Update(NiCamera* pkCamera)
{
// Determine which side of the occlusion planes the camera is on for
// fast dismissal during occlusion testing.
if (m_kLastTransform != m_spGeometry->GetWorldTransform()) //如果Geo运动。By Dynamic Plane Geo
FillData(); //产生一个Plane。 build the occlusion plane <Normal, PointOnPlane>
//All Calc in World Sys
m_iCameraWhichSide = m_kOcclusionPlane.WhichSide(
pkCamera->GetWorldLocation());
return;
}
//---------------------------------------------------------------------------
/**
kBound: The Bounding Box of an Object to be checked
*/
bool PlanarOccluder::IsOccluded(NiCamera* pkCamera, const NiBound& kBound)
{
NiPoint3 kTestLocation;
bool bCull = false;
//看看在Plane的Normal方向的物体BB的点是否与照相机在同一侧。make a pos on BB of this object in the dir of Plane normal
kTestLocation = kBound.GetCenter() + kBound.GetRadius() *
m_kOcclusionPlane.GetNormal();
//check to see if this point is on the same side as cam
bCull = m_kOcclusionPlane.WhichSide(kTestLocation) != m_iCameraWhichSide;
if (bCull)
{
//for the case where cam is on the negative side
kTestLocation = kBound.GetCenter() -
kBound.GetRadius() * m_kOcclusionPlane.GetNormal();
if (m_kOcclusionPlane.WhichSide(kTestLocation) == m_iCameraWhichSide)
bCull = false;
}
if (!bCull)
return false;
return CheckPlaneExtents(pkCamera, kBound); //如果物体的BB的所有极限点都在此平面内放回TRUE
}
//---------------------------------------------------------------------------
bool PlanarOccluder::CheckPlaneExtents(NiCamera* pkCamera,
const NiBound& kBound)
{
// The full bound falls on the opposite side of the plane from the
// camera. We just need to check and see if each point intersects the
// plane within it's extents.
NiPoint3 kCenter = kBound.GetCenter();
float fRadius = kBound.GetRadius();
NiPoint3 kTestPoint;
//创建物体BB的上下左右的极限点
// Bound offset up.
kTestPoint = kCenter + fRadius * pkCamera->GetWorldUpVector(); //Up Loc in world sys
if (!TestExtent(pkCamera, kTestPoint))
return false;
// Bound offset down.
kTestPoint = kCenter - fRadius * pkCamera->GetWorldUpVector();
if (!TestExtent(pkCamera, kTestPoint))
return false;
// Bound offset right.
kTestPoint = kCenter + fRadius * pkCamera->GetWorldRightVector();
if (!TestExtent(pkCamera, kTestPoint))
return false;
// Bound offset left.
kTestPoint = kCenter - fRadius * pkCamera->GetWorldRightVector();
if (!TestExtent(pkCamera, kTestPoint))
return false;
// If we reach here, then all the offset bound points are within the
// plane extents so the object is occluded.
return true;
}
//---------------------------------------------------------------------------
// If Point in the plane extent return TRUE
bool PlanarOccluder::TestExtent(NiCamera* pkCamera,
const NiPoint3& kTestPoint)
{
// Find intersection with the geometric occlusion plane.
NiPoint3 kCameraLoc = pkCamera->GetWorldTranslate(); //in World
NiPoint3 kPlaneNormal = m_kOcclusionPlane.GetNormal(); //in World
float fPlaneConstant = m_kOcclusionPlane.GetConstant();
NiPoint3 kTemp = (kTestPoint - kCameraLoc);
float fBottomTerm = kTemp.Dot(kPlaneNormal); //从照相机到测试点在Plane的Normal上的长度
//由于此测试点与照相机在此平面的不同侧.所以出现此情况只要照相机和测试点非常靠近此PlanePoint on Plane
if (fBottomTerm < 0.001f && fBottomTerm > -0.001f)
return true;
//照相机到平面在法向的距离
float fTopTerm = fPlaneConstant - kPlaneNormal.Dot(kCameraLoc);
float fU = fTopTerm / fBottomTerm;
//通过简单的三角形计算出交点的位置(世界坐标)
NiPoint3 kIntersection = kCameraLoc + fU * (kTestPoint - kCameraLoc);
// Project a vector from the plane center to kIntersection onto right
// and up vectors to make sure that the projection length is not
// greater than the stored magnitude. Since the world up and right
// are normalized, we can do this with a dot product.
//Intersection to Plane Center
//获得Plane的中心点位置
//计算出交点到中心点的距离向量
kTemp = kIntersection - m_spGeometry->GetWorldBound().GetCenter();
//检测这个距离向量是否超出平面的右方,上方的大小
float fRightMag = kTemp.Dot(m_kWorldRight);
// If this passes, then we're outside the geometric plane extents.
if (NiAbs(fRightMag) > m_fRightMag)
return false;
float fUpMag = kTemp.Dot(m_kWorldUp);
// If this passes, then we're outside the geometric plane extents.
if (NiAbs(fUpMag) > m_fUpMag) //m_fUpMag stores half plane height
return false;
return true;
}
//---------------------------------------------------------------------------
void PlanarOccluder::FillData()
{
NiGeometryData* pkData = m_spGeometry->GetModelData(); //m_spGeometry holds Plane
assert (pkData->GetVertexCount() >= 3);
NiPoint3 kPoint[3];
kPoint[0] = *pkData->GetVertices();
kPoint[1] = *(pkData->GetVertices() + 1);
kPoint[2] = *(pkData->GetVertices() + 2);
//transform all Vertices into World Sys
kPoint[0] = m_spGeometry->GetWorldTransform() * kPoint[0];
kPoint[1] = m_spGeometry->GetWorldTransform() * kPoint[1];
kPoint[2] = m_spGeometry->GetWorldTransform() * kPoint[2];
// CW Triangle
m_kWorldUp = kPoint[1] - kPoint[0]; //平面的上方向量
m_kWorldRight = kPoint[2] - kPoint[0]; //平面的右方向量
//m_fUpMag stores half plane height
m_fUpMag = m_kWorldUp.Unitize() * 0.5f;
//NiPoint3::Unitize() makes NiPoint3 into Unit Length and returns original length
m_fRightMag = m_kWorldRight.Unitize() * 0.5f;
NiPoint3 kNormal = m_kWorldUp.Cross(m_kWorldRight); //Left Handed Sys
m_kOcclusionPlane = NiPlane(kNormal, kPoint[0]); //Use the given Geo to create a Plane
m_kLastTransform = m_spGeometry->GetWorldTransform();
}
//---------------------------------------------------------------------------
NiGeometry* PlanarOccluder::GetGeometry()
{
return m_spGeometry;
}
//---------------------------------------------------------------------------
NiImplementRTTI(PlanarOccluder, Occluder);
//---------------------------------------------------------------------------
PlanarOccluder::PlanarOccluder()
{
}
//---------------------------------------------------------------------------
PlanarOccluder::PlanarOccluder(NiGeometry* pkPlane)
{
assert (pkPlane != 0);
m_spGeometry = pkPlane; //暂存。在后面的测试点是否在平面的Extent内使用这个Geo的Bounding Box
m_iCameraWhichSide = 0;
FillData(); //使用提供的Geo来创建一个代表他的Plane
}
//---------------------------------------------------------------------------
PlanarOccluder::~PlanarOccluder()
{
m_spGeometry = 0;
}
//---------------------------------------------------------------------------
void PlanarOccluder::Update(NiCamera* pkCamera)
{
// Determine which side of the occlusion planes the camera is on for
// fast dismissal during occlusion testing.
if (m_kLastTransform != m_spGeometry->GetWorldTransform()) //如果Geo运动。By Dynamic Plane Geo
FillData(); //产生一个Plane。 build the occlusion plane <Normal, PointOnPlane>
//All Calc in World Sys
m_iCameraWhichSide = m_kOcclusionPlane.WhichSide(
pkCamera->GetWorldLocation());
return;
}
//---------------------------------------------------------------------------
/**
kBound: The Bounding Box of an Object to be checked
*/
bool PlanarOccluder::IsOccluded(NiCamera* pkCamera, const NiBound& kBound)
{
NiPoint3 kTestLocation;
bool bCull = false;
//看看在Plane的Normal方向的物体BB的点是否与照相机在同一侧。make a pos on BB of this object in the dir of Plane normal
kTestLocation = kBound.GetCenter() + kBound.GetRadius() *
m_kOcclusionPlane.GetNormal();
//check to see if this point is on the same side as cam
bCull = m_kOcclusionPlane.WhichSide(kTestLocation) != m_iCameraWhichSide;
if (bCull)
{
//for the case where cam is on the negative side
kTestLocation = kBound.GetCenter() -
kBound.GetRadius() * m_kOcclusionPlane.GetNormal();
if (m_kOcclusionPlane.WhichSide(kTestLocation) == m_iCameraWhichSide)
bCull = false;
}
if (!bCull)
return false;
return CheckPlaneExtents(pkCamera, kBound); //如果物体的BB的所有极限点都在此平面内放回TRUE
}
//---------------------------------------------------------------------------
bool PlanarOccluder::CheckPlaneExtents(NiCamera* pkCamera,
const NiBound& kBound)
{
// The full bound falls on the opposite side of the plane from the
// camera. We just need to check and see if each point intersects the
// plane within it's extents.
NiPoint3 kCenter = kBound.GetCenter();
float fRadius = kBound.GetRadius();
NiPoint3 kTestPoint;
//创建物体BB的上下左右的极限点
// Bound offset up.
kTestPoint = kCenter + fRadius * pkCamera->GetWorldUpVector(); //Up Loc in world sys
if (!TestExtent(pkCamera, kTestPoint))
return false;
// Bound offset down.
kTestPoint = kCenter - fRadius * pkCamera->GetWorldUpVector();
if (!TestExtent(pkCamera, kTestPoint))
return false;
// Bound offset right.
kTestPoint = kCenter + fRadius * pkCamera->GetWorldRightVector();
if (!TestExtent(pkCamera, kTestPoint))
return false;
// Bound offset left.
kTestPoint = kCenter - fRadius * pkCamera->GetWorldRightVector();
if (!TestExtent(pkCamera, kTestPoint))
return false;
// If we reach here, then all the offset bound points are within the
// plane extents so the object is occluded.
return true;
}
//---------------------------------------------------------------------------
// If Point in the plane extent return TRUE
bool PlanarOccluder::TestExtent(NiCamera* pkCamera,
const NiPoint3& kTestPoint)
{
// Find intersection with the geometric occlusion plane.
NiPoint3 kCameraLoc = pkCamera->GetWorldTranslate(); //in World
NiPoint3 kPlaneNormal = m_kOcclusionPlane.GetNormal(); //in World
float fPlaneConstant = m_kOcclusionPlane.GetConstant();
NiPoint3 kTemp = (kTestPoint - kCameraLoc);
float fBottomTerm = kTemp.Dot(kPlaneNormal); //从照相机到测试点在Plane的Normal上的长度
//由于此测试点与照相机在此平面的不同侧.所以出现此情况只要照相机和测试点非常靠近此PlanePoint on Plane
if (fBottomTerm < 0.001f && fBottomTerm > -0.001f)
return true;
//照相机到平面在法向的距离
float fTopTerm = fPlaneConstant - kPlaneNormal.Dot(kCameraLoc);
float fU = fTopTerm / fBottomTerm;
//通过简单的三角形计算出交点的位置(世界坐标)
NiPoint3 kIntersection = kCameraLoc + fU * (kTestPoint - kCameraLoc);
// Project a vector from the plane center to kIntersection onto right
// and up vectors to make sure that the projection length is not
// greater than the stored magnitude. Since the world up and right
// are normalized, we can do this with a dot product.
//Intersection to Plane Center
//获得Plane的中心点位置
//计算出交点到中心点的距离向量
kTemp = kIntersection - m_spGeometry->GetWorldBound().GetCenter();
//检测这个距离向量是否超出平面的右方,上方的大小
float fRightMag = kTemp.Dot(m_kWorldRight);
// If this passes, then we're outside the geometric plane extents.
if (NiAbs(fRightMag) > m_fRightMag)
return false;
float fUpMag = kTemp.Dot(m_kWorldUp);
// If this passes, then we're outside the geometric plane extents.
if (NiAbs(fUpMag) > m_fUpMag) //m_fUpMag stores half plane height
return false;
return true;
}
//---------------------------------------------------------------------------
void PlanarOccluder::FillData()
{
NiGeometryData* pkData = m_spGeometry->GetModelData(); //m_spGeometry holds Plane
assert (pkData->GetVertexCount() >= 3);
NiPoint3 kPoint[3];
kPoint[0] = *pkData->GetVertices();
kPoint[1] = *(pkData->GetVertices() + 1);
kPoint[2] = *(pkData->GetVertices() + 2);
//transform all Vertices into World Sys
kPoint[0] = m_spGeometry->GetWorldTransform() * kPoint[0];
kPoint[1] = m_spGeometry->GetWorldTransform() * kPoint[1];
kPoint[2] = m_spGeometry->GetWorldTransform() * kPoint[2];
// CW Triangle
m_kWorldUp = kPoint[1] - kPoint[0]; //平面的上方向量
m_kWorldRight = kPoint[2] - kPoint[0]; //平面的右方向量
//m_fUpMag stores half plane height
m_fUpMag = m_kWorldUp.Unitize() * 0.5f;
//NiPoint3::Unitize() makes NiPoint3 into Unit Length and returns original length
m_fRightMag = m_kWorldRight.Unitize() * 0.5f;
NiPoint3 kNormal = m_kWorldUp.Cross(m_kWorldRight); //Left Handed Sys
m_kOcclusionPlane = NiPlane(kNormal, kPoint[0]); //Use the given Geo to create a Plane
m_kLastTransform = m_spGeometry->GetWorldTransform();
}
//---------------------------------------------------------------------------
NiGeometry* PlanarOccluder::GetGeometry()
{
return m_spGeometry;
}
//---------------------------------------------------------------------------
相关文章推荐
- IOS通过经纬度进行反向地址解析(有些方法虽然过时了,但是依然很好用!)
- java中53个关键字(含2个保留字)的意义及使用方法
- 异步方法的意义何在,Async和await以及Task的爱恨情仇,还有多线程那一家子。
- MFC CListCtrl控件隐藏滚动条但是保留用鼠标滚轮滚动效果的方法
- 虽然AWS入华了,但是还有你不知道的事
- system调用虽然用了exec,但是fd, signal这些还是会保留父进程的,be careful
- leetcode -- Majority Element -- 简单,但是还有很多其他方法
- jsp页面中调用某个新写的或者修改的方法,虽然函数没任何问题,但是编译不通过
- 多线程(虽然是一篇.net的多线程文章,但是思想方法很不错)
- 虽然AWS入华了,但是还有你不知道的事
- 明明还有很大空间,但是却提示:“目标驱动器中的磁盘已满”的解决方法
- 研究一下TForm.WMPaint过程(也得研究WM_ERASEBKGND)——TForm虽然继承自TWinControl,但是自行模仿了TCustomControl的全部行为,一共三种自绘的覆盖方法,比TCustomControl还多一种
- 【经验】清除appIcon的推送数量(badgeNumber),但是在系统通知栏保留推送通知的方法
- sass文件转css时注释虽然支持中文,但是出现乱码的解决方法
- 孤傲苍狼 只为成功找方法,不为失败找借口! javaweb学习总结(十五)——JSP基础语法 任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依然有其自己扩充的语
- Android 进程常驻(使用第三方MarsDaemon)(虽然不可用,但是还是保留下。)
- 不在appIcon上显示推送数量,但是在系统通知栏保留推送通知的方法
- select回显示--这个方法虽然可以传值给后台,但是分页需要点击两次,才能提交,作为弯路
- 转载一篇nm命令使用的文章,虽然没用用这个方法解决但是文章很好
- 手机移动端web 禁止手机返回功能的最好方法,虽然很变态,但是很有效.