C++ 为什么我的截锥剔除不是在某些角度剔除?
我的截锥剔除实现工作不正常;当我将相机向左旋转而不是向右旋转时,会发生消隐。如果我向后移动摄影机,它也会“剔除”,尽管对象消失和未渲染的距离非常短,使用对象(球体)的中心和摄影机的位置计算距离时,大约为C++ 为什么我的截锥剔除不是在某些角度剔除?,c++,opengl,linear-algebra,frustum,culling,C++,Opengl,Linear Algebra,Frustum,Culling,我的截锥剔除实现工作不正常;当我将相机向左旋转而不是向右旋转时,会发生消隐。如果我向后移动摄影机,它也会“剔除”,尽管对象消失和未渲染的距离非常短,使用对象(球体)的中心和摄影机的位置计算距离时,大约为6.0f单位。向上或向下移动/旋转实际上没有任何作用 我的投影远平面高:500.0f,我的近平面为0.1f。诚然,降低/升高远平面似乎并不真正影响剔除 代码 这是平面计算代码: void Frustum::UpdateCamParams( Camera* camera ) { vec3
6.0f
单位。向上或向下移动/旋转实际上没有任何作用
我的投影远平面高:500.0f
,我的近平面为0.1f
。诚然,降低/升高远平面似乎并不真正影响剔除
代码 这是平面计算代码:
void Frustum::UpdateCamParams( Camera* camera )
{
vec3 fartl, fartr, farbl, farbr;
vec3 neartl, neartr, nearbl, nearbr;
const vec3& camLook = camera->GetLook();
const vec3& camUp = camera->GetUp();
const vec3& camRight = camera->GetRight();
const vec3& camPos = camera->GetPosition();
const float zFar = camera->GetFarZ();
const float zNear = camera->GetNearZ();
float halfFarWidth = camera->GetFarWindowWidth() * 0.5f;
float halfFarHeight = camera->GetFarWindowHeight() * 0.5f;
float halfNearWidth = camera->GetNearWindowWidth() * 0.5f;
float halfNearHeight = camera->GetNearWindowHeight() * 0.5f;
const vec3& farClip = camPos + camLook * zFar;
fartl = farClip + ( camUp * halfFarHeight ) - ( camRight * halfFarWidth );
fartr = farClip + ( camUp * halfFarHeight ) + ( camRight * halfFarWidth );
farbl = farClip - ( camUp * halfFarHeight ) - ( camRight * halfFarWidth );
farbr = farClip - ( camUp * halfFarHeight ) + ( camRight * halfFarWidth );
const vec3& nearClip = camPos + camLook * zNear;
neartl = nearClip + ( camUp * halfNearHeight ) - ( camRight * halfNearWidth );
neartr = nearClip + ( camUp * halfNearHeight ) + ( camRight * halfNearWidth );
nearbl = nearClip - ( camUp * halfNearHeight ) - ( camRight * halfNearWidth );
nearbr = nearClip - ( camUp * halfNearHeight ) + ( camRight * halfNearWidth );
////viewRay = camLook - camPos;
// Points are set in a counter-clockwise order, for each plane
planes[ FRUST_LEFT ].points[ 0 ] = nearbl;
planes[ FRUST_LEFT ].points[ 1 ] = farbl;
planes[ FRUST_LEFT ].points[ 2 ] = fartl;
M_ComputePlane( &planes[ FRUST_LEFT ] );
planes[ FRUST_RIGHT ].points[ 0 ] = nearbr;
planes[ FRUST_RIGHT ].points[ 1 ] = farbr;
planes[ FRUST_RIGHT ].points[ 2 ] = fartr;
M_ComputePlane( &planes[ FRUST_RIGHT ] );
planes[ FRUST_TOP ].points[ 0 ] = neartl;
planes[ FRUST_TOP ].points[ 1 ] = neartr;
planes[ FRUST_TOP ].points[ 2 ] = fartr;
M_ComputePlane( &planes[ FRUST_TOP ] );
planes[ FRUST_BOTTOM ].points[ 0 ] = nearbl;
planes[ FRUST_BOTTOM ].points[ 1 ] = nearbr;
planes[ FRUST_BOTTOM ].points[ 2 ] = farbr;
M_ComputePlane( &planes[ FRUST_BOTTOM ] );
planes[ FRUST_FAR ].points[ 0 ] = farbl;
planes[ FRUST_FAR ].points[ 1 ] = farbr;
planes[ FRUST_FAR ].points[ 2 ] = fartr;
M_ComputePlane( &planes[ FRUST_FAR ] );
planes[ FRUST_NEAR ].points[ 0 ] = nearbl;
planes[ FRUST_NEAR ].points[ 1 ] = nearbr;
planes[ FRUST_NEAR ].points[ 2 ] = neartr;
M_ComputePlane( &planes[ FRUST_NEAR ] );
}
简而言之,首先计算远剪裁和近剪裁平面中心,然后计算平截头体两侧的四个角,以便在平面
阵列内进行点设置,如下所示。平面
阵列用于表示平截头体的6个面
M_ComputePlane
计算平面的法线和到原点的距离,d
:
void M_ComputePlane( plane_t* p )
{
vec3 e1 = p->points[ 2 ] - p->points[ 1 ];
vec3 e3 = p->points[ 1 ] - p->points[ 0 ];
vec3 normal = glm::cross( e1, e3 );
p->normal = glm::length( normal ) > 1.0f ? glm::normalize( normal ) : normal;
p->d = glm::dot( p->points[ 0 ], p->normal );
}
以下是进行的交叉测试,每个交叉测试都经过测试,基本上产生相同的结果:
/*
=============================
Frustum::BoundsInSphere
returns true in the event that the given center and radius
are within the view frustum
=============================
*/
bool Frustum::BoundsInSphere( const vec3& center, float radius )
{
for ( uint32_t i = 0; i < 6; ++i )
{
// center dot planes[ i ].normal = magnitude of projecting sphere center position onto plane normal
// plane[ i ].d = distance from origin to plane
float test = glm::dot( center, planes[ i ].normal ) + planes[ i ].d + radius;
if ( test <= 0 )
return false; // object is outside of this plane - reject!
}
return true;
}
/*
=============================
Frustum::BoundsInAABB_AllPoints
Tests each vertex of the AABB and only
returns false if all points are outside of one of
the frustum planes. Otherwise, the object
is considered renderable.
=============================
*/
bool Frustum::BoundsInAABB_AllPoints( const AABB& box )
{
for ( uint32_t i = 0; i < 6; ++i )
{
int out = 0;
for ( uint32_t k = 0; k < 8; ++k )
{
float test = glm::dot( box.Corner( k ), planes[ i ].normal ) + planes[ i ].d;
if ( test < 0 )
++out;
}
if ( out == 8 ) // all points rejected for this plane - bail
return false;
}
return true;
}
/*
=============================
Frustum::BoundsInAABB_Closest
Find the closest boint of the AABB
to frustum plane[ i ]. If that point
has a signed distance less than 0
to the plane, we reject it.
Otherwise, we continue to test with the farthest
point of the AABB to the given plane, and update
our intersection enum accordingly.
=============================
*/
bool Frustum::BoundsInAABB_Closest( const AABB& box, frustumPlane_t* intersection )
{
*intersection = FRUST_NONE;
for ( uint32_t i = 0; i < 6; ++i )
{
const vec3& positive = box.GetPointRelativeToNormal( planes[ i ].normal, true );
if ( M_SignedPlaneDistance( &planes[ i ], positive ) < 0 )
return false; // closest point is outside; reject.
const vec3& negative = box.GetPointRelativeToNormal( planes[ i ].normal, false );
if ( M_SignedPlaneDistance( &planes[ i ], negative ) < 0 )
*intersection = ( frustumPlane_t ) i;
}
return true;
}
/*
=============================
平截头体::边界球面
如果给定的中心和半径
在视锥中
=============================
*/
布尔平截头体::BoundsInSphere(常量向量3和中心,浮动半径)
{
对于(uint32_t i=0;i<6;++i)
{
//圆心点平面[i]。法线=将球体中心位置投影到法线平面上的大小
//平面[i].d=从原点到平面的距离
浮动测试=glm::点(中心,平面[i]。法线)+平面[i]。d+半径;
如果(在M_ComputePlane中测试你有一个问题,你检查法线的长度是否大于1.0,看看它是否已经被归一化,但是如果向量的大小/长度小于1.0呢?那么它也需要被归一化。我会取消检查,只是一直归一化。这可能是我糟糕的数学技能,但你的d方程似乎是off对我来说,它不是相当于| point0 |*1*cosθ
(1,因为它是单位向量)?如果点0与法线共向,这会给你距离,但它看起来不像?@Skurmedel我的理解是,只要长度不超过1,规范化向量就会被规范化。我在这里错了吗?也许你对d方程的分析错了(我的数学技能也需要提高),但我相信您的解决方案执行相同的计算,因为向量a和b的点积等于| | | | | | | | | | | | | b | | | | cosT,其中T是θ(很抱歉,在移动atm上格式不好)@Skurmedal我的错误,看起来您是对的。谢谢您的观察/建议:)