GLControl 采摘问题
GLControl Picking Issue
我又一次在选择 OpenGL/OpenTK 时遇到了一个小问题。这一次,与我之前启动的线程不同,它实际上正在运行。唯一的问题是 "tiles" 没有正确选择。我的意思是,如果我单击网格上的某个位置,它会 select 紧挨着它的网格块。但是,如果我稍微移动鼠标,它就会 select 正确地显示网格图块。这很难解释,所以我将上传两张图片、代码和可执行文件本身。
这是我的视图:
这是一个基本的网格-select离子系统。它有效。但是,selection 例程似乎有点偏离。
这里是底层视图的图片,用户实际看不到。这是当用户点击时绘制到后台缓冲区的场景,这只是为了帮助揭示拾取系统的实际情况。
红色圆圈和x表示我刚刚点击但没有正确注册的位置;没有体素被添加到该位置的集合中。但是,如果我将鼠标稍微向右移动,或靠近图块的中心,则会为该位置正确添加体素。
这是代码的主要部分;我将添加任何其他必要的内容。哦,很抱歉它有多乱,我还没来得及清理它。
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 );
}
}
}
}
这里是可执行文件本身的下载 link,这样你们就可以直接看到问题,而不是通过我含糊不清、不充分的口头描述。
EDIT/Update
我想我刚刚发现了这个问题。控件本身在调整大小时返回(宽度 518,高度 537)。但是,我在 GIMP 中对此进行了测量,发现我只获得了 (518,512) 的可视区域,这意味着该控件被相邻的工具条和较低的显示条控件部分覆盖。考虑到这种情况,我尝试将拾取例程的 y 值偏移 -25(其中一个控件的高度),它神奇地开始工作得更好。我认为这实际上解决了问题,我只需要更好地定位控件并将 opengl 上下文置于最前面。这应该解决它;如果是这样的话,我会尽快在下面提供答案。
我想通了!这不是控件的问题,而是我如何重新创建 opengl 视口本身。这个问题只不过是一个小疏忽。我不得不改变:
GL.Viewport( ClientRectangle.X , ClientRectangle.Y , ClientRectangle.Width , ClientRectangle.Height );
收件人:
GL.Viewport( this.OpenGlLayer.ClientRectangle.X , this.OpenGlLayer.ClientRectangle.Y , this.OpenGlLayer.ClientRectangle.Width , this.OpenGlLayer.ClientRectangle.Height );
现在采摘工作很顺利!吸取教训,确保在使用 GLControl 时没有将 wrong/or 映射到错误的控件!
我又一次在选择 OpenGL/OpenTK 时遇到了一个小问题。这一次,与我之前启动的线程不同,它实际上正在运行。唯一的问题是 "tiles" 没有正确选择。我的意思是,如果我单击网格上的某个位置,它会 select 紧挨着它的网格块。但是,如果我稍微移动鼠标,它就会 select 正确地显示网格图块。这很难解释,所以我将上传两张图片、代码和可执行文件本身。
这是我的视图:
这是一个基本的网格-select离子系统。它有效。但是,selection 例程似乎有点偏离。
这里是底层视图的图片,用户实际看不到。这是当用户点击时绘制到后台缓冲区的场景,这只是为了帮助揭示拾取系统的实际情况。
红色圆圈和x表示我刚刚点击但没有正确注册的位置;没有体素被添加到该位置的集合中。但是,如果我将鼠标稍微向右移动,或靠近图块的中心,则会为该位置正确添加体素。
这是代码的主要部分;我将添加任何其他必要的内容。哦,很抱歉它有多乱,我还没来得及清理它。
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 );
}
}
}
}
这里是可执行文件本身的下载 link,这样你们就可以直接看到问题,而不是通过我含糊不清、不充分的口头描述。
EDIT/Update
我想我刚刚发现了这个问题。控件本身在调整大小时返回(宽度 518,高度 537)。但是,我在 GIMP 中对此进行了测量,发现我只获得了 (518,512) 的可视区域,这意味着该控件被相邻的工具条和较低的显示条控件部分覆盖。考虑到这种情况,我尝试将拾取例程的 y 值偏移 -25(其中一个控件的高度),它神奇地开始工作得更好。我认为这实际上解决了问题,我只需要更好地定位控件并将 opengl 上下文置于最前面。这应该解决它;如果是这样的话,我会尽快在下面提供答案。
我想通了!这不是控件的问题,而是我如何重新创建 opengl 视口本身。这个问题只不过是一个小疏忽。我不得不改变:
GL.Viewport( ClientRectangle.X , ClientRectangle.Y , ClientRectangle.Width , ClientRectangle.Height );
收件人:
GL.Viewport( this.OpenGlLayer.ClientRectangle.X , this.OpenGlLayer.ClientRectangle.Y , this.OpenGlLayer.ClientRectangle.Width , this.OpenGlLayer.ClientRectangle.Height );
现在采摘工作很顺利!吸取教训,确保在使用 GLControl 时没有将 wrong/or 映射到错误的控件!