Planar Occlusion 平面遮挡(虽然方法老了但是还有保留的意义)

#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;
}
//---------------------------------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值