关于c#:OpenTK / OpenGL视锥消隐裁剪很快

OpenTK/OpenGL Frustum Culling Clipping Too Soon

我最近在我的体素游戏中添加了平截锥体剔除功能;乍一看效果很好。但是,我立即注意到,视锥看起来似乎有点变了,因为窗口边缘附近的一些体素被过早切除,然后完全脱离了视觉范围。这是说明我的努力的图像:

Frustum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
using System;
using OpenTK;

namespace GameProject.Game.Client.Widgets {

    public class FrustumWidget {
        private float[] _clipMatrix = new float[ 16 ];
        private float[ , ] _frustum = new float[ 6 , 4 ];
        const 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 SphereInFrustum( 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 VoxelWithinFrustum( float x1 , float y1 , float z1 , float x2 , float y2 , float z2 ) {
            for( int i = 0; i < 6; i++ ) {
                if( ( this._frustum[ i , 0 ] * x1 + this._frustum[ i , 1 ] * y1 + this._frustum[ i , 2 ] * z1 + this._frustum[ i, 3 ] <= 0.0F ) &&
                  ( this._frustum[ i , 0 ] * x2 + this._frustum[ i , 1 ] * y1 + this._frustum[ i , 2 ] * z1 + this._frustum[ i , 3 ] <= 0.0F ) &&
                  ( this._frustum[ i , 0 ] * x1 + this._frustum[ i , 1 ] * y2 + this._frustum[ i , 2 ] * z1 + this._frustum[ i , 3 ] <= 0.0F ) &&
                  ( this._frustum[ i , 0 ] * x2 + this._frustum[ i , 1 ] * y2 + this._frustum[ i , 2 ] * z1 + this._frustum[ i , 3 ] <= 0.0F ) &&
                  ( this._frustum[ i , 0 ] * x1 + this._frustum[ i , 1 ] * y1 + this._frustum[ i , 2 ] * z2 + this._frustum[ i , 3 ] <= 0.0F ) &&
                  ( this._frustum[ i , 0 ] * x2 + this._frustum[ i , 1 ] * y1 + this._frustum[ i , 2 ] * z2 + this._frustum[ i , 3 ] <= 0.0F ) &&
                  ( this._frustum[ i , 0 ] * x1 + this._frustum[ i , 1 ] * y2 + this._frustum[ i , 2 ] * z2 + this._frustum[ i , 3 ] <= 0.0F ) &&
                  ( this._frustum[ i , 0 ] * x2 + this._frustum[ i , 1 ] * y2 + this._frustum[ i , 2 ] * z2 + this._frustum[ i , 3 ] <= 0.0F ) ) {
                    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[ RIGHT , 0 ] = _clipMatrix[ 3 ] - _clipMatrix[ 0 ];
            _frustum[ RIGHT , 1 ] = _clipMatrix[ 7 ] - _clipMatrix[ 4 ];
            _frustum[ RIGHT , 2 ] = _clipMatrix[ 11 ] - _clipMatrix[ 8 ];
            _frustum[ RIGHT , 3 ] = _clipMatrix[ 15 ] - _clipMatrix[ 12 ];
            NormalizePlane( _frustum , RIGHT );

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

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

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

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

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

我的FirstPersonCameraWidget类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using System;
using System.Drawing;
using OpenTK;
using GameProject.Game.Framework.OpenTKExtensions;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;

namespace GameProject.Game.Client.Widgets {
    public class FirstPersonCameraWidget {

        public Matrix4 CameraMatrix;
        public Vector3 Location;
        public FrustumWidget Frustum;
        public float Pitch;
        public float Yaw;
        public float MoveSpeed;
        public float LookSpeed;
        public Vector2 MouseSpeed;
        public bool IsLooking;
        public float NearZ;
        public float FarZ;

        public FirstPersonCameraWidget(Vector3 cameraOrigin , float pitch , float yaw , float movementSpeed , float lookSpeed ) {
            CameraMatrix = Matrix4.Identity;
            this.Location = cameraOrigin;
            this.Pitch = pitch;
            this.Yaw = yaw;
            this.LookSpeed = lookSpeed;
            this.MoveSpeed = movementSpeed;
            Frustum = new FrustumWidget();
        }

        public void Update() {
            if( IsLooking ) {
                // Possible redundant method?
            }
        }

        public void ProcessMovement( KeyboardState keyboardState , FrameEventArgs e ) {
            if( keyboardState[ Key.W ] ) {
                MoveForward( e );
            }
            if( keyboardState[ Key.S ] ) {
                MoveBackward( e );
            }
            if( keyboardState[ Key.A ] ) {
                StrafeLeft( e );
            }
            if( keyboardState[ Key.D ] ) {
                StrafeRight( e );
            }
            if( keyboardState[ Key.Space ] ) {
                FlyUp( e );
            }
            if( keyboardState[ Key.LShift ] || keyboardState[ Key.RShift ] ) {
                FlyDown( e );
            }
        }

        public void MoveForward( FrameEventArgs e ) {
            Location.X += ( float )Math.Cos( Yaw ) * MoveSpeed * ( float )e.Time;
            //CameraPosition.Y += ( float )Math.Tan( Pitch ) * MoveSpeed * ( float )e.Time;
            Location.Z += ( float )Math.Sin( Yaw ) * MoveSpeed * ( float )e.Time;
        }

        public void MoveBackward( FrameEventArgs e ) {
            Location.X -= ( float )Math.Cos( Yaw ) * MoveSpeed * ( float )e.Time;
            //CameraPosition.Y -= ( float )Math.Tan( Pitch ) * MoveSpeed * ( float )e.Time;
            Location.Z -= ( float )Math.Sin( Yaw ) * MoveSpeed * ( float )e.Time;
        }

        public void StrafeLeft( FrameEventArgs e ) {
            Location.X -= ( float )Math.Cos( Yaw + Math.PI / 2 ) * MoveSpeed * ( float )e.Time;
            Location.Z -= ( float )Math.Sin( Yaw + Math.PI / 2 ) * MoveSpeed * ( float )e.Time;
        }

        public void StrafeRight( FrameEventArgs e ) {
            Location.X += ( float )Math.Cos( Yaw + Math.PI / 2 ) * MoveSpeed * ( float )e.Time;
            Location.Z += ( float )Math.Sin( Yaw + Math.PI / 2 ) * MoveSpeed * ( float )e.Time;
        }

        public void FlyUp( FrameEventArgs e ) {
            Location.Y += MoveSpeed * ( float )e.Time;
        }

        public void FlyDown( FrameEventArgs e ) {
            Location.Y -= MoveSpeed * ( float )e.Time;
        }

        public void LookThrough( GameWindow window , Point mouseLocation , FrameEventArgs e ) {
            if( IsLooking ) {
                Point windowCenter = new Point( window.Bounds.Left + window.Bounds.Width / 2 , window.Bounds.Top + window.Bounds.Height / 2 );
                Vector2 MouseDelta = new Vector2( mouseLocation.X - window.PointToClient( windowCenter ).X , mouseLocation.Y - window.PointToClient( windowCenter ).Y );
                System.Windows.Forms.Cursor.Position = windowCenter;
                MouseSpeed.X *= LookSpeed;
                MouseSpeed.Y *= LookSpeed;
                MouseSpeed.X += MouseDelta.X / 40.0f * ( float )e.Time;
                MouseSpeed.Y += MouseDelta.Y / 40.0f * ( float )e.Time;
                Yaw += MouseSpeed.X;
                Pitch -= MouseSpeed.Y;
                if( Pitch <= -( ( OpenTKExtensions.HalfPI * 2 ) * 0.5f ) + 0.01f ) {
                    Pitch = -( ( OpenTKExtensions.HalfPI * 2 ) * 0.5f ) + 0.01f;
                }
                if( Pitch >= ( ( OpenTKExtensions.HalfPI * 2 ) * 0.5f ) - 0.01f ) {
                    Pitch = ( ( OpenTKExtensions.HalfPI * 2 ) * 0.5f ) - 0.01f;
                }
            }
            Vector3 LookAtPoint = new Vector3( ( float )Math.Cos( Yaw ) , ( float )Math.Tan( Pitch ) , ( float )Math.Sin( Yaw ) );
            CameraMatrix = Matrix4.LookAt( Location , Location + LookAtPoint , Vector3.UnitY );

            /**
             * Recalculate the Viewport Frustum
             */

            Matrix4 projection = new Matrix4();
            GL.GetFloat(GetPName.ProjectionMatrix, out projection);
            Matrix4 modelview = new Matrix4();
            GL.GetFloat(GetPName.ModelviewMatrix, out modelview);
            Frustum.CalculateFrustum(projection,modelview);
        }
    }
}

最后,我的GameClient类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading.Tasks;
using GameProject.Game.Framework.DataStructure;
using GameProject.Game.Framework.Generators;
using GameProject.Game.Framework.Geometry;
using System.Diagnostics;
using GameProject.Game.Framework.OpenGLExtensions;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using GameProject.Game.Client.Widgets;
using QuickFont;

namespace GameProject.Game.Client {
    public class GameClient : GameWindow {

        /**
         * Client Variables
         */

        public const String CLIENT_VERSION ="v0.0.1";
        public const String GAME_NAME ="Voxelbyte";
        public FirstPersonCameraWidget GameCamera;
        private Point _mousePosition;
        private Point _lastMousePosition;
        private bool _centerCursorAfterRelease = false;
        /**
         * Game Variables
         */

        public VoxelWorld World;
        public List<GameSelection> SelectionMemory;
        public QFont DeveloperText;

        public GameClient()
            : base( 800 , 600 , GraphicsMode.Default , GAME_NAME ) {
            GL.Enable( EnableCap.DepthTest );
            GL.ClearColor( 0.3f , 0.3f , 0.3f , 0.0f );

        }

        protected override void OnLoad( EventArgs e ) {
            base.OnLoad( e );

            DeveloperText = new QFont("Resources/Fonts/times.ttf" , 14 , FontStyle.Regular );
            //TestFont.Options.UseDefaultBlendFunction = false;
            //this.VSync = VSyncMode.On;
            SelectionMemory = new List<GameSelection>();
            GameCamera = new FirstPersonCameraWidget(
                new Vector3( 30.0f , 8.0f , 30.0f ) ,
                0.0f ,
                0.0f ,
                15.0f ,
                0.4f );
            //this.WindowState = WindowState.Fullscreen;
            GL.CullFace( CullFaceMode.Back );
            GL.Enable( EnableCap.CullFace );
            GL.BlendFunc( BlendingFactorSrc.SrcAlpha , BlendingFactorDest.OneMinusSrcAlpha );
            GL.Enable( EnableCap.Blend );
            // Generate Map And Log the Time
            World = BattleWorldReader.ReadFromImage("ColoredPyramid.png" );
            Stopwatch sw = new Stopwatch();
            sw.Start();
            World.Rebuild();
            sw.Stop();
            Console.WriteLine("World Generation+Optimization took: {0}ms" , sw.ElapsedMilliseconds );
            //GLExtensions.EnableWireframe();
        }

        protected override void OnMouseMove( MouseMoveEventArgs e ) {
            base.OnMouseMove( e );
            _mousePosition = new Point( e.X , e.Y );
            if( e.Mouse.IsButtonDown( MouseButton.Right ) ) {

            }
        }

        protected override void OnMouseDown( MouseButtonEventArgs e ) {
            base.OnMouseDown( e );
            if( e.Mouse.IsButtonDown( MouseButton.Right ) ) {
                Point nativeMouse = System.Windows.Forms.Cursor.Position;
                _lastMousePosition = nativeMouse;
                Point windowCenter = new Point( Bounds.Left + Bounds.Width / 2 , Bounds.Top + Bounds.Height / 2 );
                System.Windows.Forms.Cursor.Position = windowCenter;
                GameCamera.IsLooking = true;
                this.CursorVisible = false;
            }
        }

        protected override void OnMouseUp( MouseButtonEventArgs e ) {
            base.OnMouseUp( e );
            if( e.Button == MouseButton.Right ) {
                GameCamera.IsLooking = false;
                if( !_centerCursorAfterRelease ) {
                    System.Windows.Forms.Cursor.Position = _lastMousePosition;
                }
                this.CursorVisible = true;
            }
        }

        protected override void OnRenderFrame( FrameEventArgs e ) {
            base.OnRenderFrame( e );
            GameCamera.LookThrough( this , _mousePosition , e );
            GL.MatrixMode( MatrixMode.Modelview );
            GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
            GL.LoadMatrix( ref GameCamera.CameraMatrix );
            //
            //
            GL.EnableClientState( ArrayCap.VertexArray );
            GL.EnableClientState( ArrayCap.TextureCoordArray );
            GL.DisableClientState( ArrayCap.ColorArray );
            int numberOfVoxelsRendered = 0;
            foreach( Voxel voxel in World.Voxels ) {

                if( GameCamera.Frustum.VoxelWithinFrustum( voxel.Location.X, voxel.Location.Y, voxel.Location.Z, 1.0f,1.0f,1.0f ) ) {
                    voxel.Render( GameCamera );
                    numberOfVoxelsRendered++;
                }

            }
            GL.DisableClientState( ArrayCap.VertexArray );
            GL.DisableClientState( ArrayCap.TextureCoordArray );
            GL.DisableClientState( ArrayCap.ColorArray );

            // Render Dev Hud
            RenderDeveloperHud();
            //


            SwapBuffers();
            this.Title = GAME_NAME +" FPS:" + ( int )this.RenderFrequency +" Voxels:" + numberOfVoxelsRendered;
        }

        private void RenderDeveloperHud() {
            QFont.Begin();
            GL.PushMatrix();
            GL.Translate( 0.0f , 5 , 0f );
            DeveloperText.Print("Voxelbyte" );
            GL.Translate( 0f , 30 , 0f );
            DeveloperText.Print("X:" + ( int )GameCamera.Location.X );
            GL.Translate( 0f , 24 , 0f );
            DeveloperText.Print("Y:" + ( int )GameCamera.Location.Y );
            GL.Translate( 0.0f , 24 , 0f );
            DeveloperText.Print("Z:" + ( int )GameCamera.Location.Z );
            GL.PopMatrix();
            QFont.End();
        }

        private void CheckKeyboardInput( FrameEventArgs eventArgs ) {
            KeyboardState keyboardState = OpenTK.Input.Keyboard.GetState();
            GameCamera.ProcessMovement( keyboardState , eventArgs );
            if( keyboardState[ Key.Escape ] ) {
                Exit();
            }
        }

        protected override void OnUpdateFrame( FrameEventArgs e ) {
            CheckKeyboardInput( e );
        }

        protected override void OnResize( EventArgs e ) {
            base.OnResize( e );
            GL.Viewport( ClientRectangle.X , ClientRectangle.Y , ClientRectangle.Width , ClientRectangle.Height );
            Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView( ( float )Math.PI / 4 , Width / ( float )Height , 0.1f , 1000.0f );
            GL.MatrixMode( MatrixMode.Projection );
            GL.LoadMatrix( ref projection );
        }
    }
}

有人知道这笔交易吗?因为我很沮丧。

编辑:

我刚刚注意到,如果我使用其他检测方法(SphereInFrustum),一切似乎都可以正常工作。什么都不会被过早裁剪。这是我的新renderloop:

1
2
3
4
5
6
7
8
9
10
    foreach( Voxel voxel in World.Voxels ) {
        if( voxel.IsVisible() ) {
            if( GameCamera.Frustum.SphereInFrustum(
                voxel.Location.X , voxel.Location.Y , voxel.Location.Z , 1.5f ) ) {
                voxel.Render( GameCamera );
                numberOfVoxelsRendered++;
            }
        }

    }

如您所见,我经过的球体半径为1.5f,并且基本上假装我的所有体素都是球体。它有效,并且没有过早的裁剪,但是我想使用我的VoxelWithinFrustum方法。如果我用该方法做错了什么,谁能发现?还是我使用的参数不正确?


我注意到这篇文章是有关google截锥体的首批Google热门文章之一,因此我想提供适当的有效代码作为新的答案。这是我更新的视锥类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
public class Frustum
    {
        private readonly float[] _clipMatrix = new float[ 16 ];
        private readonly 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 )
        {
            for( int p = 0; p < 6; p++ )
            {
                float 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 )
        {
            for( int p = 0; p < 6; p++ )
            {
                float 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( BoundingVolume volume )
        {
            for( int i = 0; i < 6; i++ )
            {
                if( _frustum[ i , A ] * ( volume.X - volume.Width ) + _frustum[ i , B ] * ( volume.Y - volume.Height ) + _frustum[ i , C ] * ( volume.Z - volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( volume.X + volume.Width ) + _frustum[ i , B ] * ( volume.Y - volume.Height ) + _frustum[ i , C ] * ( volume.Z - volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( volume.X - volume.Width ) + _frustum[ i , B ] * ( volume.Y + volume.Height ) + _frustum[ i , C ] * ( volume.Z - volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( volume.X + volume.Width ) + _frustum[ i , B ] * ( volume.Y + volume.Height ) + _frustum[ i , C ] * ( volume.Z - volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( volume.X - volume.Width ) + _frustum[ i , B ] * ( volume.Y - volume.Height ) + _frustum[ i , C ] * ( volume.Z + volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( volume.X + volume.Width ) + _frustum[ i , B ] * ( volume.Y - volume.Height ) + _frustum[ i , C ] * ( volume.Z + volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( volume.X - volume.Width ) + _frustum[ i , B ] * ( volume.Y + volume.Height ) + _frustum[ i , C ] * ( volume.Z + volume.Length ) + _frustum[ i , D ] > 0 )
                    continue;
                if( _frustum[ i , A ] * ( volume.X + volume.Width ) + _frustum[ i , B ] * ( volume.Y + volume.Height ) + _frustum[ i , C ] * ( volume.Z + volume.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 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 );
        }
    }

我希望有人觉得它有用,而不是像他们那样得到这个死页链接。


可能您设置的高度值(y)错误。我遇到了同样的问题,这有点愚蠢,我在glsl中生成了Y值,对于球体检查来说就像(x,0.0,z)一样。