如何在OpenGL中绘制一个Frustum

时间:2015-03-03 00:52:38

标签: c# opentk

我使用C#和OpenTK创建了一个平截头体课程,它完美无缺。但是,我希望能够绘制平截头体的边界以进行调试。我不知道如何从Matrix数据中获取顶点数据以进行绘制。我只是想知道是否有人知道该怎么做。

这是我的Frustum课程:

using System;
using GrimoireGDK.GameDevelopmentKit.Math.Geometry;
using OpenTK;

namespace GrimoireGameClient.Client.Window.Bindings {
    public class Frustum {
        private float[] _clipMatrix = new float[ 16 ];
        private float[ , ] _frustum = new float[ 6 , 4 ];

        public const int A = 0;
        public const int B = 1;
        public const int C = 2;
        public const int D = 3;

        public enum ClippingPlane : int {
            Right = 0 ,
            Left = 1 ,
            Bottom = 2 ,
            Top = 3 ,
            Back = 4 ,
            Front = 5
        }

        private void NormalizePlane( float[ , ] frustum , int side ) {
            float magnitude = ( float )Math.Sqrt( ( frustum[ side , 0 ] * frustum[ side , 0 ] ) + ( frustum[ side , 1 ] * frustum[ side , 1 ] )
                                                + ( frustum[ side , 2 ] * frustum[ side , 2 ] ) );
            frustum[ side , 0 ] /= magnitude;
            frustum[ side , 1 ] /= magnitude;
            frustum[ side , 2 ] /= magnitude;
            frustum[ side , 3 ] /= magnitude;
        }

        public bool PointVsFrustum( float x , float y , float z ) {
            for( int i = 0 ; i < 6 ; i++ ) {
                if( this._frustum[ i , 0 ] * x + this._frustum[ i , 1 ] * y + this._frustum[ i , 2 ] * z + this._frustum[ i , 3 ] <= 0.0f ) {
                    return false;
                }
            }
            return true;
        }

        public bool PointVsFrustum( Vector3 location ) {
            for( int i = 0 ; i < 6 ; i++ ) {
                if( this._frustum[ i , 0 ] * location.X + this._frustum[ i , 1 ] * location.Y + this._frustum[ i , 2 ] * location.Z + this._frustum[ i , 3 ] <= 0.0f ) {
                    return false;
                }
            }
            return true;
        }

        public bool SphereVsFrustum( float x , float y , float z , float radius ) {
            float d = 0;
            for( int p = 0 ; p < 6 ; p++ ) {
                d = _frustum[ p , 0 ] * x + _frustum[ p , 1 ] * y + _frustum[ p , 2 ] * z + _frustum[ p , 3 ];
                if( d <= -radius ) {
                    return false;
                }
            }
            return true;
        }

        public bool SphereVsFrustum( Vector3 location , float radius ) {
            float d = 0;
            for( int p = 0 ; p < 6 ; p++ ) {
                d = _frustum[ p , 0 ] * location.X + _frustum[ p , 1 ] * location.Y + _frustum[ p , 2 ] * location.Z + _frustum[ p , 3 ];
                if( d <= -radius ) {
                    return false;
                }
            }
            return true;
        }

        public bool VolumeVsFrustum( float x , float y , float z , float width , float height , float length ) {
            for( int i = 0 ; i < 6 ; i++ ) {
                if( _frustum[ i , A ] * ( x - width ) + _frustum[ i , B ] * ( y - height ) + _frustum[ i , C ] * ( z - length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x + width ) + _frustum[ i , B ] * ( y - height ) + _frustum[ i , C ] * ( z - length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x - width ) + _frustum[ i , B ] * ( y + height ) + _frustum[ i , C ] * ( z - length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x + width ) + _frustum[ i , B ] * ( y + height ) + _frustum[ i , C ] * ( z - length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x - width ) + _frustum[ i , B ] * ( y - height ) + _frustum[ i , C ] * ( z + length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x + width ) + _frustum[ i , B ] * ( y - height ) + _frustum[ i , C ] * ( z + length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x - width ) + _frustum[ i , B ] * ( y + height ) + _frustum[ i , C ] * ( z + length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x + width ) + _frustum[ i , B ] * ( y + height ) + _frustum[ i , C ] * ( z + length ) + _frustum[ i , D ] > 0 )
                    continue;
                return false;
            }
            return true;
        }

        public bool VolumeVsFrustum( Vector3 location, float width , float height , float length ) {
            for( int i = 0 ; i < 6 ; i++ ) {
                if( _frustum[ i , A ] * ( location.X - width ) + _frustum[ i , B ] * ( location.Y - height ) + _frustum[ i , C ] * ( location.Z - length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X + width ) + _frustum[ i , B ] * ( location.Y - height ) + _frustum[ i , C ] * ( location.Z - length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X - width ) + _frustum[ i , B ] * ( location.Y + height ) + _frustum[ i , C ] * ( location.Z - length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X + width ) + _frustum[ i , B ] * ( location.Y + height ) + _frustum[ i , C ] * ( location.Z - length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X - width ) + _frustum[ i , B ] * ( location.Y - height ) + _frustum[ i , C ] * ( location.Z + length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X + width ) + _frustum[ i , B ] * ( location.Y - height ) + _frustum[ i , C ] * ( location.Z + length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X - width ) + _frustum[ i , B ] * ( location.Y + height ) + _frustum[ i , C ] * ( location.Z + length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X + width ) + _frustum[ i , B ] * ( location.Y + height ) + _frustum[ i , C ] * ( location.Z + length ) + _frustum[ i , D ] > 0 )
                    continue;
                return false;
            }
            return true;
        }

        public bool VolumeVsFrustum( Vector3 location , BoundingVolume volume ) {
            for( int i = 0 ; i < 6 ; i++ ) {
                if( _frustum[ i , A ] * ( location.X - volume.Width ) + _frustum[ i , B ] * ( location.Y - volume.Height ) + _frustum[ i , C ] * ( location.Z - volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X + volume.Width ) + _frustum[ i , B ] * ( location.Y - volume.Height ) + _frustum[ i , C ] * ( location.Z - volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X - volume.Width ) + _frustum[ i , B ] * ( location.Y + volume.Height ) + _frustum[ i , C ] * ( location.Z - volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X + volume.Width ) + _frustum[ i , B ] * ( location.Y + volume.Height ) + _frustum[ i , C ] * ( location.Z - volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X - volume.Width ) + _frustum[ i , B ] * ( location.Y - volume.Height ) + _frustum[ i , C ] * ( location.Z + volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X + volume.Width ) + _frustum[ i , B ] * ( location.Y - volume.Height ) + _frustum[ i , C ] * ( location.Z + volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X - volume.Width ) + _frustum[ i , B ] * ( location.Y + volume.Height ) + _frustum[ i , C ] * ( location.Z + volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( location.X + volume.Width ) + _frustum[ i , B ] * ( location.Y + volume.Height ) + _frustum[ i , C ] * ( location.Z + volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                return false;
            }
            return true;
        }

        public bool CubeVsFrustum( float x , float y , float z , float size ) {
            for( int i = 0 ; i < 6 ; i++ ) {
                if( _frustum[ i , A ] * ( x - size ) + _frustum[ i , B ] * ( y - size ) + _frustum[ i , C ] * ( z - size ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x + size ) + _frustum[ i , B ] * ( y - size ) + _frustum[ i , C ] * ( z - size ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x - size ) + _frustum[ i , B ] * ( y + size ) + _frustum[ i , C ] * ( z - size ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x + size ) + _frustum[ i , B ] * ( y + size ) + _frustum[ i , C ] * ( z - size ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x - size ) + _frustum[ i , B ] * ( y - size ) + _frustum[ i , C ] * ( z + size ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x + size ) + _frustum[ i , B ] * ( y - size ) + _frustum[ i , C ] * ( z + size ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x - size ) + _frustum[ i , B ] * ( y + size ) + _frustum[ i , C ] * ( z + size ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( x + size ) + _frustum[ i , B ] * ( y + size ) + _frustum[ i , C ] * ( z + size ) + _frustum[ i , D ] > 0 )
                    continue;
                return false;
            }
            return true;
        }


        public void CalculateFrustum( Matrix4 projectionMatrix , Matrix4 modelViewMatrix ) {
            _clipMatrix[ 0 ] = ( modelViewMatrix.M11 * projectionMatrix.M11 ) + ( modelViewMatrix.M12 * projectionMatrix.M21 ) + ( modelViewMatrix.M13 * projectionMatrix.M31 ) + ( modelViewMatrix.M14 * projectionMatrix.M41 );
            _clipMatrix[ 1 ] = ( modelViewMatrix.M11 * projectionMatrix.M12 ) + ( modelViewMatrix.M12 * projectionMatrix.M22 ) + ( modelViewMatrix.M13 * projectionMatrix.M32 ) + ( modelViewMatrix.M14 * projectionMatrix.M42 );
            _clipMatrix[ 2 ] = ( modelViewMatrix.M11 * projectionMatrix.M13 ) + ( modelViewMatrix.M12 * projectionMatrix.M23 ) + ( modelViewMatrix.M13 * projectionMatrix.M33 ) + ( modelViewMatrix.M14 * projectionMatrix.M43 );
            _clipMatrix[ 3 ] = ( modelViewMatrix.M11 * projectionMatrix.M14 ) + ( modelViewMatrix.M12 * projectionMatrix.M24 ) + ( modelViewMatrix.M13 * projectionMatrix.M34 ) + ( modelViewMatrix.M14 * projectionMatrix.M44 );

            _clipMatrix[ 4 ] = ( modelViewMatrix.M21 * projectionMatrix.M11 ) + ( modelViewMatrix.M22 * projectionMatrix.M21 ) + ( modelViewMatrix.M23 * projectionMatrix.M31 ) + ( modelViewMatrix.M24 * projectionMatrix.M41 );
            _clipMatrix[ 5 ] = ( modelViewMatrix.M21 * projectionMatrix.M12 ) + ( modelViewMatrix.M22 * projectionMatrix.M22 ) + ( modelViewMatrix.M23 * projectionMatrix.M32 ) + ( modelViewMatrix.M24 * projectionMatrix.M42 );
            _clipMatrix[ 6 ] = ( modelViewMatrix.M21 * projectionMatrix.M13 ) + ( modelViewMatrix.M22 * projectionMatrix.M23 ) + ( modelViewMatrix.M23 * projectionMatrix.M33 ) + ( modelViewMatrix.M24 * projectionMatrix.M43 );
            _clipMatrix[ 7 ] = ( modelViewMatrix.M21 * projectionMatrix.M14 ) + ( modelViewMatrix.M22 * projectionMatrix.M24 ) + ( modelViewMatrix.M23 * projectionMatrix.M34 ) + ( modelViewMatrix.M24 * projectionMatrix.M44 );

            _clipMatrix[ 8 ] = ( modelViewMatrix.M31 * projectionMatrix.M11 ) + ( modelViewMatrix.M32 * projectionMatrix.M21 ) + ( modelViewMatrix.M33 * projectionMatrix.M31 ) + ( modelViewMatrix.M34 * projectionMatrix.M41 );
            _clipMatrix[ 9 ] = ( modelViewMatrix.M31 * projectionMatrix.M12 ) + ( modelViewMatrix.M32 * projectionMatrix.M22 ) + ( modelViewMatrix.M33 * projectionMatrix.M32 ) + ( modelViewMatrix.M34 * projectionMatrix.M42 );
            _clipMatrix[ 10 ] = ( modelViewMatrix.M31 * projectionMatrix.M13 ) + ( modelViewMatrix.M32 * projectionMatrix.M23 ) + ( modelViewMatrix.M33 * projectionMatrix.M33 ) + ( modelViewMatrix.M34 * projectionMatrix.M43 );
            _clipMatrix[ 11 ] = ( modelViewMatrix.M31 * projectionMatrix.M14 ) + ( modelViewMatrix.M32 * projectionMatrix.M24 ) + ( modelViewMatrix.M33 * projectionMatrix.M34 ) + ( modelViewMatrix.M34 * projectionMatrix.M44 );

            _clipMatrix[ 12 ] = ( modelViewMatrix.M41 * projectionMatrix.M11 ) + ( modelViewMatrix.M42 * projectionMatrix.M21 ) + ( modelViewMatrix.M43 * projectionMatrix.M31 ) + ( modelViewMatrix.M44 * projectionMatrix.M41 );
            _clipMatrix[ 13 ] = ( modelViewMatrix.M41 * projectionMatrix.M12 ) + ( modelViewMatrix.M42 * projectionMatrix.M22 ) + ( modelViewMatrix.M43 * projectionMatrix.M32 ) + ( modelViewMatrix.M44 * projectionMatrix.M42 );
            _clipMatrix[ 14 ] = ( modelViewMatrix.M41 * projectionMatrix.M13 ) + ( modelViewMatrix.M42 * projectionMatrix.M23 ) + ( modelViewMatrix.M43 * projectionMatrix.M33 ) + ( modelViewMatrix.M44 * projectionMatrix.M43 );
            _clipMatrix[ 15 ] = ( modelViewMatrix.M41 * projectionMatrix.M14 ) + ( modelViewMatrix.M42 * projectionMatrix.M24 ) + ( modelViewMatrix.M43 * projectionMatrix.M34 ) + ( modelViewMatrix.M44 * projectionMatrix.M44 );

            _frustum[ ( int )ClippingPlane.Right , 0 ] = _clipMatrix[ 3 ] - _clipMatrix[ 0 ];
            _frustum[ ( int )ClippingPlane.Right , 1 ] = _clipMatrix[ 7 ] - _clipMatrix[ 4 ];
            _frustum[ ( int )ClippingPlane.Right , 2 ] = _clipMatrix[ 11 ] - _clipMatrix[ 8 ];
            _frustum[ ( int )ClippingPlane.Right , 3 ] = _clipMatrix[ 15 ] - _clipMatrix[ 12 ];
            NormalizePlane( _frustum , ( int )ClippingPlane.Right );

            _frustum[ ( int )ClippingPlane.Left , 0 ] = _clipMatrix[ 3 ] + _clipMatrix[ 0 ];
            _frustum[ ( int )ClippingPlane.Left , 1 ] = _clipMatrix[ 7 ] + _clipMatrix[ 4 ];
            _frustum[ ( int )ClippingPlane.Left , 2 ] = _clipMatrix[ 11 ] + _clipMatrix[ 8 ];
            _frustum[ ( int )ClippingPlane.Left , 3 ] = _clipMatrix[ 15 ] + _clipMatrix[ 12 ];
            NormalizePlane( _frustum , ( int )ClippingPlane.Left );

            _frustum[ ( int )ClippingPlane.Bottom , 0 ] = _clipMatrix[ 3 ] + _clipMatrix[ 1 ];
            _frustum[ ( int )ClippingPlane.Bottom , 1 ] = _clipMatrix[ 7 ] + _clipMatrix[ 5 ];
            _frustum[ ( int )ClippingPlane.Bottom , 2 ] = _clipMatrix[ 11 ] + _clipMatrix[ 9 ];
            _frustum[ ( int )ClippingPlane.Bottom , 3 ] = _clipMatrix[ 15 ] + _clipMatrix[ 13 ];
            NormalizePlane( _frustum , ( int )ClippingPlane.Bottom );

            _frustum[ ( int )ClippingPlane.Top , 0 ] = _clipMatrix[ 3 ] - _clipMatrix[ 1 ];
            _frustum[ ( int )ClippingPlane.Top , 1 ] = _clipMatrix[ 7 ] - _clipMatrix[ 5 ];
            _frustum[ ( int )ClippingPlane.Top , 2 ] = _clipMatrix[ 11 ] - _clipMatrix[ 9 ];
            _frustum[ ( int )ClippingPlane.Top , 3 ] = _clipMatrix[ 15 ] - _clipMatrix[ 13 ];
            NormalizePlane( _frustum , ( int )ClippingPlane.Top );

            _frustum[ ( int )ClippingPlane.Back , 0 ] = _clipMatrix[ 3 ] - _clipMatrix[ 2 ];
            _frustum[ ( int )ClippingPlane.Back , 1 ] = _clipMatrix[ 7 ] - _clipMatrix[ 6 ];
            _frustum[ ( int )ClippingPlane.Back , 2 ] = _clipMatrix[ 11 ] - _clipMatrix[ 10 ];
            _frustum[ ( int )ClippingPlane.Back , 3 ] = _clipMatrix[ 15 ] - _clipMatrix[ 14 ];
            NormalizePlane( _frustum , ( int )ClippingPlane.Back );

            _frustum[ ( int )ClippingPlane.Front , 0 ] = _clipMatrix[ 3 ] + _clipMatrix[ 2 ];
            _frustum[ ( int )ClippingPlane.Front , 1 ] = _clipMatrix[ 7 ] + _clipMatrix[ 6 ];
            _frustum[ ( int )ClippingPlane.Front , 2 ] = _clipMatrix[ 11 ] + _clipMatrix[ 10 ];
            _frustum[ ( int )ClippingPlane.Front , 3 ] = _clipMatrix[ 15 ] + _clipMatrix[ 14 ];
            NormalizePlane( _frustum , ( int )ClippingPlane.Front );
        }

        /// <summary>
        /// Draw the frustum for debugging purposes.
        /// </summary>
        public void Draw() {
            // Implement drawing code here.
        }
    }
}

有谁知道如何绘制Frustum?而且我不在乎它是否以立即模式完成;事实上,我几乎更喜欢这样。这是我正在寻找的视觉输出:

enter image description here

2 个答案:

答案 0 :(得分:4)

看起来你有六个平面组成平截头体(顶部,底部,左,右,前,后)描述为四个分量,平面的法向量和从原点开始沿着该向量的距离(xyzD)

一种简单的方法:给定任意三个平面,您可以找到相关的角点(左上角,左上角,后左上角等等),带有一系列点和十字产品。一个很好的参考是MonoGame.BoundingFrustum.IntersectionPoint方法(麻省理工学院许可证),它(在最近的优化之前):

Vector3 IntersectionPoint(ref Plane a, ref Plane b, ref Plane c)
{
    // Formula used
    //                d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 )
    //P =   ---------------------------------------------------------------------
    //                             N1 . ( N2 * N3 )
    //
    // Note: N refers to the normal, d refers to the displacement. '.' means dot product. '*' means cross product

    Vector3 v1, v2, v3;
    float f = -Vector3.Dot(a.Normal, Vector3.Cross(b.Normal, c.Normal));

    v1 = (a.D * (Vector3.Cross(b.Normal, c.Normal)));
    v2 = (b.D * (Vector3.Cross(c.Normal, a.Normal)));
    v3 = (c.D * (Vector3.Cross(a.Normal, b.Normal)));

    Vector3 vec = new Vector3(v1.X + v2.X + v3.X, v1.Y + v2.Y + v3.Y, v1.Z + v2.Z + v3.Z);
    return vec / f;
}

您可以对所有八个角重复此操作,然后将角连接在一起以将平截头体绘制为一系列线条/边。

以上链接是一个相当不错的参考 - 实际上MonoGame代码及其XNA祖先都是几何处理的良好参考,足够快&#34;以及MonoGame的MIT许可证是very permissive。它们唯一的缺点往往是坐标系统手性,矩阵乘法次序(行与列矩阵)之类的假设等。

我确定不言而喻,为了获得完整的图片,您想要使用不同的相机查看结果,就像您提供的样本视觉输出一样。

答案 1 :(得分:3)

这些建议都不是你所要求的,但它们可能会帮助你思考它。

尽可能接近(假设代码有效,正如你所说的那样),_frustum数组定义了截锥体两侧的6个平面。

因此,您可以通过计算相应平面的交点来简单地计算体积拐角处的8个点(如下所述:Point of intersection of three planes 3D - C#

我怀疑当你计算出方程式时,它们会根据clipmatrix中的数据简化为一些相对简单的表达式。

或者,如果您知道您的perspectivematrix定义的平截头体(在相对于视点的简单规范坐标中,沿z轴居中),您可以简单地反转modelViewMatrix并将这些点乘以它,为您提供点数回到世界坐标。

相关问题