Проблема выбора GLControl

У меня снова небольшая проблема с выбором в OpenGL/OpenTK. На этот раз, в отличие от темы, которую я начал некоторое время назад, она действительно работает. Единственная проблема в том, что «плитки» выбраны неправильно. Я имею в виду, что если я щелкну место в сетке, он выберет плитку сетки непосредственно рядом с ним. Однако, если я немного передвину мышь, она правильно выберет плитку сетки. Это довольно сложно объяснить, поэтому я буду загружать две картинки, код и сам исполняемый файл.

Вот как выглядит мой взгляд:

введите здесь описание изображения

Это базовая система выбора сетки. И это работает. Тем не менее, процедура выбора, кажется, немного не в порядке.

вот изображение базового вида, который на самом деле не виден пользователю. Это сцена, которая рисуется в резервном буфере, когда пользователь щелкает, это просто помогает показать, как на самом деле выглядит система выбора.

введите здесь описание изображения

Красный кружок и крестик показывают местоположение, которое я только что щелкнул, но которое не было правильно зарегистрировано; ни один воксель не был добавлен в коллекцию для этого местоположения. Однако, если я сдвину мышь немного вправо или ближе к центру тайла, воксель будет правильно добавлен для этого места.

Вот основная часть кода; Добавлю еще, что посчитаю нужным. О, и извините за то, как это грязно, у меня не было времени, чтобы очистить его.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using AnimusEngine.Engine.Datatypes;
using AnimusEngine.Engine.Editor.AnimusEditor.Widgets.GLRenderer.Widgets;
using AnimusEngine.Engine.Utilities;
using AnimusEngineRuntime.Runtime.CameraBindings;
using AnimusEngineRuntime.Runtime.Entities;
using AnimusEngineRuntime.Runtime.Utilities;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using MouseEventArgs = System.Windows.Forms.MouseEventArgs;

namespace AnimusEngine.Engine.Editor.AnimusEditor.Widgets.GLRenderer {
    public class AnimusRenderingModule : Panel {
        public enum CameraMode {
            FirstPerson ,
            Arcball ,
            Pan
        }
        public GLControl OpenGlLayer;
        public Camera Camera;
        public ToolStrip OpenGlLayerToolstrip;
        public RenderingModuleStatusStrip OpenGlLayerStatusStrip;
        private Point _mouseLocation;
        private Point _lastMousePosition;
        private Stopwatch _renderTimer;
        private FrameCounter _frameCounter;
        private bool _isLooking;
        private int _gridModelDisplayListHandle;
        private int _planeModelDisplayListHandle;
        private int _planeTileSelectionDisplayListHandle;
        private Random _clientRandomInstance;
        private bool _isRotating;
        public CameraMode ActiveCameraMode;
        private List<SelectableTile> _selectionTileList;
        public List<Vector3> VoxelLocations;


        public AnimusRenderingModule() {
            Initialize();
        }

        private void DrawGrid() {
            GL.PushMatrix();
            {
                GL.Translate( -1.0f , 0.0f , -1.0f );
                GL.Begin( PrimitiveType.Lines );
                for( float i = 0 ; i <= 130 ; i += 2 ) {
                    if( i == 0 ) {
                        GL.Color3( .6 , .3 , .3 );
                    } else {
                        GL.Color3( .25 , .25 , .25 );
                    }
                    GL.Vertex3( i , -1.0f , 0.0f );
                    GL.Vertex3( i , -1.0f , 130.0f );
                    if( i == 0 ) {
                        GL.Color3( .3 , .3 , .6 );
                    } else {
                        GL.Color3( .25 , .25 , .25 );
                    }
                    GL.Vertex3( 0.0f , -1.0f , i );
                    GL.Vertex3( 130.0f , -1.0f , i );
                }
                GL.End();
            }
            GL.PopMatrix();
        }

        private void DrawPlane() {
            GL.Begin( PrimitiveType.Triangles );
            // Triangle 1
            GL.Vertex3( -1.0 , -1.0 , -1.0 );
            GL.Vertex3( -1.0 , -1.0 , 1.0 );
            GL.Vertex3( 1.0 , -1.0 , -1.0 );
            // Triangle 2
            GL.Vertex3( -1.0 , -1.0 , 1.0 );
            GL.Vertex3( 1.0 , -1.0 , 1.0 );
            GL.Vertex3( 1.0 , -1.0 , -1.0 );
            GL.End();
        }

        private void PickGeometry( int x , int y ) {
            Console.WriteLine( "Picking..." );
            /**
             * Draw The Geometry As solid
             * colors
             */
            GL.ClearColor( 1.0f , 1.0f , 1.0f , 1.0f );
            GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
            Camera.LookThrough();
            GL.MatrixMode( MatrixMode.Modelview );
            GL.LoadMatrix( ref Camera.CameraMatrix );
            GL.PushMatrix();
            GL.CallList( _planeTileSelectionDisplayListHandle );
            GL.PopMatrix();
            byte[] pixel = new byte[ 3 ];
            int[] viewport = new int[ 4 ];
            GL.GetInteger( GetPName.Viewport , viewport );
            GL.ReadPixels( x , viewport[ 3 ] - y , 1 , 1 , PixelFormat.Rgba , PixelType.UnsignedByte , pixel );
            Color pickedColor = Color.FromArgb( pixel[ 0 ] , pixel[ 1 ] , pixel[ 2 ] );
            foreach( SelectableTile colorTest in _selectionTileList ) {
                if( colorTest.TileColor.R == pickedColor.R && colorTest.TileColor.G == pickedColor.G && colorTest.TileColor.B == pickedColor.B ) {
                    Console.WriteLine( "Tile Location: " + colorTest.Location );
                    VoxelLocations.Add( colorTest.Location );
                }
            }
            Console.WriteLine( pickedColor.ToString() );
            Console.WriteLine( "Picking Done" );
            GL.ClearColor( 0.3f , 0.3f , 0.3f , 0.0f );
        }


        private void DrawCube() {
            GL.Begin( PrimitiveType.Quads );
            GL.Color3( Color.Silver );
            GL.Vertex3( -1.0f , -1.0f , -1.0f );
            GL.Vertex3( -1.0f , 1.0f , -1.0f );
            GL.Vertex3( 1.0f , 1.0f , -1.0f );
            GL.Vertex3( 1.0f , -1.0f , -1.0f );
            GL.Color3( Color.Honeydew );
            GL.Vertex3( -1.0f , -1.0f , -1.0f );
            GL.Vertex3( 1.0f , -1.0f , -1.0f );
            GL.Vertex3( 1.0f , -1.0f , 1.0f );
            GL.Vertex3( -1.0f , -1.0f , 1.0f );
            GL.Color3( Color.Moccasin );
            GL.Vertex3( -1.0f , -1.0f , -1.0f );
            GL.Vertex3( -1.0f , -1.0f , 1.0f );
            GL.Vertex3( -1.0f , 1.0f , 1.0f );
            GL.Vertex3( -1.0f , 1.0f , -1.0f );
            GL.Color3( Color.IndianRed );
            GL.Vertex3( -1.0f , -1.0f , 1.0f );
            GL.Vertex3( 1.0f , -1.0f , 1.0f );
            GL.Vertex3( 1.0f , 1.0f , 1.0f );
            GL.Vertex3( -1.0f , 1.0f , 1.0f );
            GL.Color3( Color.PaleVioletRed );
            GL.Vertex3( -1.0f , 1.0f , -1.0f );
            GL.Vertex3( -1.0f , 1.0f , 1.0f );
            GL.Vertex3( 1.0f , 1.0f , 1.0f );
            GL.Vertex3( 1.0f , 1.0f , -1.0f );
            GL.Color3( Color.ForestGreen );
            GL.Vertex3( 1.0f , -1.0f , -1.0f );
            GL.Vertex3( 1.0f , 1.0f , -1.0f );
            GL.Vertex3( 1.0f , 1.0f , 1.0f );
            GL.Vertex3( 1.0f , -1.0f , 1.0f );
            GL.End();
        }

        private void Render() {
            if( _isLooking ) {
                Point windowCenter = WinFormsExtensions.FindCenterOfControl( this );
                Vector2 mouseDelta = new Vector2( _mouseLocation.X - this.PointToClient( windowCenter ).X , _mouseLocation.Y - this.PointToClient( windowCenter ).Y );
                Cursor.Position = windowCenter;
                Camera.MouseSpeed.X = ( ( mouseDelta.X / 40.0f * Camera.LookSpeed ) * ( float )_renderTimer.Elapsed.TotalMilliseconds );
                Camera.MouseSpeed.Y = ( ( mouseDelta.Y / 40.0f * Camera.LookSpeed ) * ( float )_renderTimer.Elapsed.TotalMilliseconds );
                Camera.Yaw += Camera.MouseSpeed.X;
                Camera.Pitch -= Camera.MouseSpeed.Y;
                if( Camera.Pitch <= -( ( MathHelper.Pi ) * 0.5f ) + 0.01f ) {
                    Camera.Pitch = -( ( MathHelper.Pi ) * 0.5f ) + 0.01f;
                }
                if( Camera.Pitch >= ( ( MathHelper.Pi ) * 0.5f ) - 0.01f ) {
                    Camera.Pitch = ( ( MathHelper.Pi ) * 0.5f ) - 0.01f;
                }
            }
            Camera.LookThrough();
            GL.MatrixMode( MatrixMode.Modelview );
            GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
            GL.LoadMatrix( ref Camera.CameraMatrix );
            //
            //GL.CallList( _planeTileSelectionDisplayListHandle );
            GL.CallList( _gridModelDisplayListHandle );
            foreach( Vector3 location in VoxelLocations ) {
                GL.PushMatrix();
                GL.Translate( location );
                DrawCube();
                GL.PopMatrix();
            }
            //
        }

        private void Initialize() {
            _renderTimer = new Stopwatch();
            this.OpenGlLayer = new GLControl();
            this._frameCounter = new FrameCounter();
            this.OpenGlLayer.Dock = DockStyle.Fill;
            this.OpenGlLayer.MouseDown += OpenGLLayer_MouseDown;
            this.OpenGlLayer.MouseMove += OpenGLLayer_MouseMove;
            this.OpenGlLayer.MouseUp += OpenGLLayer_MouseUp;
            this.OpenGlLayer.Resize += OpenGLLayer_Resize;
            this.OpenGlLayer.Paint += OpenGLLayer_Paint;
            this.OpenGlLayer.Load += OpenGLLayer_Load;
            Application.Idle += Application_Idle;
            this.OpenGlLayerToolstrip = new ToolStrip();
            this.OpenGlLayerToolstrip.Items.Add( new ToolStripButton() );
            this.OpenGlLayerToolstrip.Dock = DockStyle.Top;
            this.OpenGlLayerStatusStrip = new RenderingModuleStatusStrip();
            this.Controls.Add( this.OpenGlLayerToolstrip );
            this.Controls.Add( this.OpenGlLayer );
            this.Controls.Add( this.OpenGlLayerStatusStrip );
            this.OpenGlLayerStatusStrip.UpdateFramerateDisplay( 60 );
            this.OpenGlLayerStatusStrip.UpdateTotalVoxelDisplay( 2000 );
            this.ActiveCameraMode = CameraMode.FirstPerson;
            this._clientRandomInstance = new Random();
            this._selectionTileList = new List<SelectableTile>();
            for( int tileX = 0 ; tileX <= 128 ; tileX += 2 ) {
                for( int tileZ = 0 ; tileZ <= 128 ; tileZ += 2 ) {
                    byte red = ( byte )_clientRandomInstance.Next( 256 );
                    byte green = ( byte )_clientRandomInstance.Next( 256 );
                    byte blue = ( byte )_clientRandomInstance.Next( 256 );
                    this._selectionTileList.Add( new SelectableTile( Color.FromArgb( red , green , blue ) , new Vector3( tileX , 0.0f , tileZ ) ) );
                }
            }
            VoxelLocations = new List<Vector3>();
        }

        private void GenerateEngineResources() {
            _gridModelDisplayListHandle = MeshGenerator.Generate( DrawGrid );
            _planeModelDisplayListHandle = MeshGenerator.Generate( DrawPlane );
            _planeTileSelectionDisplayListHandle = MeshGenerator.Generate( delegate {
                foreach( SelectableTile tile in _selectionTileList ) {
                    GL.PushMatrix();
                    GL.Translate( tile.Location );
                    GL.Color3( tile.TileColor );
                    DrawPlane();
                    GL.PopMatrix();
                }
            } );
        }

        private void OpenGLLayer_Load( object sender , EventArgs e ) {
            _renderTimer.Start();
            GL.Enable( EnableCap.DepthTest );
            GL.ClearColor( 0.3f , 0.3f , 0.3f , 0.0f );
            GL.CullFace( CullFaceMode.Back );
            GL.Enable( EnableCap.CullFace );
            GL.BlendFunc( BlendingFactorSrc.SrcAlpha , BlendingFactorDest.OneMinusSrcAlpha );
            GL.Enable( EnableCap.Blend );
            Camera = new Camera();
            Camera.Location = new Vector3( -10.0f , 0.0f , 0.0f );
            Camera.Pitch = 0.0f;
            Camera.Yaw = 0.0f;
            Camera.MoveSpeed = 0.02f;
            Camera.LookSpeed = 0.4f;
            GenerateEngineResources();
        }

        private void Application_Idle( object sender , EventArgs e ) {
            KeyboardState keyboardState = Keyboard.GetState();
            ProcessMovement( keyboardState );
            this.OpenGlLayer.Invalidate();
            _renderTimer.Restart();
        }



        private void ProcessMovement( KeyboardState keyboardState ) {
            if( !this.OpenGlLayer.Focused ) {
                return;
            }
            if( keyboardState[ Key.W ] ) {
                Camera.MoveForward( ( float )_renderTimer.Elapsed.TotalMilliseconds );
            }
            if( keyboardState[ Key.S ] ) {
                Camera.MoveBackward( ( float )_renderTimer.Elapsed.TotalMilliseconds );
            }
            if( keyboardState[ Key.A ] ) {
                Camera.StrafeLeft( ( float )_renderTimer.Elapsed.TotalMilliseconds );
            }
            if( keyboardState[ Key.D ] ) {
                Camera.StrafeRight( ( float )_renderTimer.Elapsed.TotalMilliseconds );
            }
            if( keyboardState[ Key.Space ] ) {
                Camera.FlyUp( ( float )_renderTimer.Elapsed.TotalMilliseconds );
            }
            if( keyboardState[ Key.LShift ] || keyboardState[ Key.RShift ] ) {
                Camera.FlyDown( ( float )_renderTimer.Elapsed.TotalMilliseconds );
            }
            if( keyboardState[ Key.AltLeft ] ) {
                this._isRotating = true;
                this.ActiveCameraMode = CameraMode.Arcball;
                this.OpenGlLayerStatusStrip.UpdateCameraModeDisplay( this.ActiveCameraMode );

            } else {
                this._isRotating = false;
                this.ActiveCameraMode = CameraMode.FirstPerson;
                this.OpenGlLayerStatusStrip.UpdateCameraModeDisplay( this.ActiveCameraMode );
            }
        }

        private void OpenGLLayer_Resize( object sender , EventArgs e ) {
            if( !this.OpenGlLayer.IsHandleCreated ) {
                return;
            }
            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 );
        }

        private void OpenGLLayer_Paint( object sender , PaintEventArgs e ) {
            if( !this.OpenGlLayer.IsHandleCreated ) {
                return;
            }
            Render();
            this.OpenGlLayer.SwapBuffers();
        }

        private void OpenGLLayer_MouseUp( object sender , MouseEventArgs e ) {
            if( e.Button == MouseButtons.Right ) {
                _isLooking = false;
                Cursor.Position = _lastMousePosition;
                Cursor.Show();
            }
        }

        private void OpenGLLayer_MouseMove( object sender , MouseEventArgs e ) {
            _mouseLocation = new Point( e.X , e.Y );
        }

        private void OpenGLLayer_MouseDown( object sender , MouseEventArgs e ) {
            if( e.Button == MouseButtons.Right && e.Button != MouseButtons.Left ) {
                Point nativeMouse = Cursor.Position;
                _lastMousePosition = nativeMouse;
                Point windowCenter = WinFormsExtensions.FindCenterOfControl( this );
                Cursor.Position = windowCenter;
                _isLooking = true;
                Cursor.Hide();
            }
            if( e.Button == MouseButtons.Left && e.Button != MouseButtons.Right ) {
                PickGeometry( e.X , e.Y );
            }
        }
    }
}

И вот ссылка для скачивания самого исполняемого файла, чтобы вы, ребята, могли увидеть проблему из первых рук, а не через мои расплывчатые, неадекватные словесные описания.

Ссылка для скачивания

ИЗМЕНИТЬ/обновить

Я думаю, что только что обнаружил проблему. Сам элемент управления возвращается (ширина 518, высота 537) во время изменения размера. Тем не менее, я измерил это в GIMP и обнаружил, что я получаю только визуальную область (518 512), а это означает, что элемент управления частично закрыт соседней полосой инструментов и нижним элементом управления полосой дисплея. Думая, что это так, я попытался сместить значение y процедуры выбора на -25 (высота одного из элементов управления), и это волшебным образом начало работать лучше. Я думаю, что это на самом деле решает проблему, мне просто нужно лучше сориентировать элементы управления и вывести контекст opengl на передний план. Это должно исправить это; если это так, я скоро дам ответ ниже.


person Krythic    schedule 14.04.2015    source источник
comment
Вы уверены, что ваши координаты x и y рассчитаны правильно? Если вы хотите выбрать только расположение сетки, почему вы также визуализируете кубы? Я бы, вероятно, также использовал последовательные цвета, а не случайные, чтобы предотвратить возможные дубликаты.   -  person vesan    schedule 15.04.2015
comment
@vesan Я почти уверен, что все рассчитано просто отлично. На картинке, где я визуализирую цветные плитки, они находятся в тех же координатах, что и в обычном режиме. Вы пробовали демо? Если вы находитесь прямо перед плиткой (там, где она занимает большую часть экрана), проблем с выбором нет.   -  person Krythic    schedule 15.04.2015
comment
Я сижу в постели и читаю свой собственный код построчно... думаю, я вижу проблему. Но в то же время это не имеет смысла. Я думаю, что тайлы отрисовываются в 0.0f в бэкбуфере, что поместит их немного выше сетки. Мне нужно явно указать -1.0f, когда я их выделяю. Или я могу просто ошибаться. Работать с кодом становится довольно сложно по мере роста самой кодовой базы. Я попробую это завтра и вернусь к вам, ребята.   -  person Krythic    schedule 15.04.2015


Ответы (1)


Я понял! Проблема была не в элементах управления, а в том, как я воссоздавал саму область просмотра opengl. Проблема заключалась не более чем в незначительной оплошности. Мне пришлось изменить:

GL.Viewport( ClientRectangle.X , ClientRectangle.Y , ClientRectangle.Width , ClientRectangle.Height );

To:

GL.Viewport( this.OpenGlLayer.ClientRectangle.X , this.OpenGlLayer.ClientRectangle.Y , this.OpenGlLayer.ClientRectangle.Width , this.OpenGlLayer.ClientRectangle.Height );

Выбор работает как шарм сейчас! Извлеченный урок: убедитесь, что вы не используете неправильный/или сопоставление с неправильным элементом управления при использовании GLControl!

person Krythic    schedule 16.04.2015