2

錐台カリングの実装が正しく機能していません。カメラを左に回転させるとカリングされますが、右には回転しません。また、カメラを後方に移動すると「カリング」されますが、オブジェクトが消えてレンダリングされない距離は非常に短いです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 ] );
}

簡単に言えば、ファー クリップ プレーンとニア クリップ プレーンの中心が最初に計算され、次に両方の錐台側の 4 つのコーナーが計算され、次のようにplanes配列内のポイント設定が可能になります。planes配列は、錐台の 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;
}
4

0 に答える 0