带有 OpenTK 包装器的 OpenGL 无法使投影正常工作
OpenGL with OpenTK wrapper cannot get projections to work
我创建了一个简单的程序,可以创建一个立方体并使其后平面沿圆周运动。
当我使用 GL.Ortho()
查看时效果很好,我可以看到立方体,但我认为 GL.Ortho()
用于 2D 投影,我想制作 3D 游戏,所以我'我们继续尝试投影矩阵。到目前为止,这是我的代码:
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Shifted
{
class Program
{
public static double Offset = 0;
public static Vector3 m_eye;
public static Vector3 m_target;
static void Main(string[] args)
{
using (GameWindow window = new GameWindow())
{
window.Load += (sender, e) =>
{
//Vertical Sync on or off
window.VSync = VSyncMode.On;
//Set window title
window.Title = "Test";
//set the "clear color", the colour displayed when nothing is drawn and were looking to infinity
GL.ClearColor(Color4.Black);
//Set the viewport to match the screen width/height
GL.Viewport(0, 0, window.Width, window.Height);
m_eye = new Vector3(0, 0, 1f);
m_target = new Vector3(0, 0, 0);
};
window.Resize += (sender, e) =>
{
//on window resize, resize the viewport. (the "window" were looking into the OpenGL "world" with)
GL.Viewport(0, 0, window.Width, window.Height);
};
//heres where all game logic should be stored
window.UpdateFrame += (sender, e) =>
{
Offset += e.Time;
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Key.W))
{
m_eye = m_eye + new Vector3(0f, 0f, .1f);
m_target = m_target + new Vector3(0f, 0f, .1f);
}
if (keyState.IsKeyDown(Key.S))
{
m_eye = m_eye - new Vector3(0f, 0f, .1f);
m_target = m_target - new Vector3(0f, 0f, .1f);
}
Console.WriteLine(m_eye);
};
//heres where everything that draws should go
window.RenderFrame += (sender, e) =>
{
//Clear the buffer to draw a fresh image
GL.Enable(EnableCap.DepthTest);
GL.DepthFunc(DepthFunction.Less);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
//Set draw mode to lines (wiremesh)
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
//GL.LoadIdentity();
//GL.Ortho(0.0f, window.Width, 0.0f, window.Height, 0.0f, 1000.0f);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
Matrix4 perspective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)window.Width / (float)window.Height, 0.1f, 100f);
GL.LoadMatrix(ref perspective);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
Matrix4 lookat = Matrix4.LookAt(m_eye,m_target,Vector3.UnitY);
GL.LoadMatrix(ref lookat);
GL.LoadIdentity();
//Set what colour to draw in
GL.Translate(-m_eye);
GL.Color3(1.0f, 1.0f, 1.0f);
//8 Vertices for a cube
double[] vertices = new double[]{100,100,0,
100,200,0,
200,200,0,
200,100,0,
200+(Math.Sin(Offset)*10),100+(Math.Cos(Offset)*10),-100,
200+(Math.Sin(Offset)*10),200+(Math.Cos(Offset)*10),-100,
100+(Math.Sin(Offset)*10),200+(Math.Cos(Offset)*10),-100,
100+(Math.Sin(Offset)*10),100+(Math.Cos(Offset)*10),-100};
//Indice order to draw the cube in, shouldnt have to call this every frame but whatever for now
byte[] indices = new byte[] { 0, 1, 2, 2, 3, 0, 2, 3, 4, 4, 5, 2, 2, 1, 6, 6, 5, 2, 0, 1, 7, 7, 6, 1, 7, 6, 5, 5, 4, 7 };
//Enable the use of vertex arrays
GL.EnableClientState(ArrayCap.VertexArray);
//Tell it where to find the vertices
GL.Translate(m_eye.X * -1, m_eye.Y * -1, m_eye.Z * -1);
GL.VertexPointer(3, VertexPointerType.Double, 0, vertices);
//Draw them
GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedByte, indices);
//Flush it to the buffer
GL.Flush();
//swap the back buffer we're drawing to to be the front buffer thats displayed
window.SwapBuffers();
};
//Run at X frames per second. Null = 60 FPS, 200 = no cap, anything in between = that cap.
window.Run(200);
}
}
}
}
当我删除
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
Matrix4 perspective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)window.Width / (float)window.Height, 0.1f, 100f);
GL.LoadMatrix(ref perspective);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
Matrix4 lookat = Matrix4.LookAt(m_eye,m_target,Vector3.UnitY);
GL.LoadMatrix(ref lookat);
GL.LoadIdentity();
并将其替换为
GL.Ortho(0.0f, window.Width, 0.0f, window.Height, 0.0f, 1000.0f);
渲染效果很好,但如果我尝试使用矩阵,我只会得到黑色 window。
我做错了什么?
问题是您没有正确设置矩阵。
首先在某处声明这些变量:
private Matrix4 projectionMatrix;
private Matrix4 modelViewMatrix;
private Vector3 cameraPosition;
private Vector3 cameraTarget;
private Vector3 cameraUp = Vector3.UnitY; // which way is up for the camera
然后使用这些功能来控制您的基本相机:
private void SetPerspectiveProjection (int width, int height, float FOV)
{
projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI * (FOV/180f), width / (float)height, 0.2f, 256.0f);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projectionMatrix); // this replaces the old matrix, no need for GL.LoadIdentity()
}
private void SetOrthographicProjection ()
{
projectionMatrix = Matrix4.Identity;
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity(); // reset matrix
GL.Ortho (-1f, 1f, -1f, 1f, 1000f, -1000f);
}
private void SetLookAtCamera(Vector3 position, Vector3 target, Vector3 up)
{
modelViewMatrix = Matrix4.LookAt(position, target, up);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref modelViewMatrix);
}
最后,在画任何东西之前:
SetPerspectiveProjection(viewWidth, viewHeight, 45); // 45 is in degrees
SetLookAtCamera(cameraPosition, cameraTarget, cameraUp);
// draw 3D models here
SetOrthographicProjection();
// draw user interface elements here
我创建了一个简单的程序,可以创建一个立方体并使其后平面沿圆周运动。
当我使用 GL.Ortho()
查看时效果很好,我可以看到立方体,但我认为 GL.Ortho()
用于 2D 投影,我想制作 3D 游戏,所以我'我们继续尝试投影矩阵。到目前为止,这是我的代码:
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Shifted
{
class Program
{
public static double Offset = 0;
public static Vector3 m_eye;
public static Vector3 m_target;
static void Main(string[] args)
{
using (GameWindow window = new GameWindow())
{
window.Load += (sender, e) =>
{
//Vertical Sync on or off
window.VSync = VSyncMode.On;
//Set window title
window.Title = "Test";
//set the "clear color", the colour displayed when nothing is drawn and were looking to infinity
GL.ClearColor(Color4.Black);
//Set the viewport to match the screen width/height
GL.Viewport(0, 0, window.Width, window.Height);
m_eye = new Vector3(0, 0, 1f);
m_target = new Vector3(0, 0, 0);
};
window.Resize += (sender, e) =>
{
//on window resize, resize the viewport. (the "window" were looking into the OpenGL "world" with)
GL.Viewport(0, 0, window.Width, window.Height);
};
//heres where all game logic should be stored
window.UpdateFrame += (sender, e) =>
{
Offset += e.Time;
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Key.W))
{
m_eye = m_eye + new Vector3(0f, 0f, .1f);
m_target = m_target + new Vector3(0f, 0f, .1f);
}
if (keyState.IsKeyDown(Key.S))
{
m_eye = m_eye - new Vector3(0f, 0f, .1f);
m_target = m_target - new Vector3(0f, 0f, .1f);
}
Console.WriteLine(m_eye);
};
//heres where everything that draws should go
window.RenderFrame += (sender, e) =>
{
//Clear the buffer to draw a fresh image
GL.Enable(EnableCap.DepthTest);
GL.DepthFunc(DepthFunction.Less);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
//Set draw mode to lines (wiremesh)
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
//GL.LoadIdentity();
//GL.Ortho(0.0f, window.Width, 0.0f, window.Height, 0.0f, 1000.0f);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
Matrix4 perspective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)window.Width / (float)window.Height, 0.1f, 100f);
GL.LoadMatrix(ref perspective);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
Matrix4 lookat = Matrix4.LookAt(m_eye,m_target,Vector3.UnitY);
GL.LoadMatrix(ref lookat);
GL.LoadIdentity();
//Set what colour to draw in
GL.Translate(-m_eye);
GL.Color3(1.0f, 1.0f, 1.0f);
//8 Vertices for a cube
double[] vertices = new double[]{100,100,0,
100,200,0,
200,200,0,
200,100,0,
200+(Math.Sin(Offset)*10),100+(Math.Cos(Offset)*10),-100,
200+(Math.Sin(Offset)*10),200+(Math.Cos(Offset)*10),-100,
100+(Math.Sin(Offset)*10),200+(Math.Cos(Offset)*10),-100,
100+(Math.Sin(Offset)*10),100+(Math.Cos(Offset)*10),-100};
//Indice order to draw the cube in, shouldnt have to call this every frame but whatever for now
byte[] indices = new byte[] { 0, 1, 2, 2, 3, 0, 2, 3, 4, 4, 5, 2, 2, 1, 6, 6, 5, 2, 0, 1, 7, 7, 6, 1, 7, 6, 5, 5, 4, 7 };
//Enable the use of vertex arrays
GL.EnableClientState(ArrayCap.VertexArray);
//Tell it where to find the vertices
GL.Translate(m_eye.X * -1, m_eye.Y * -1, m_eye.Z * -1);
GL.VertexPointer(3, VertexPointerType.Double, 0, vertices);
//Draw them
GL.DrawElements(PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedByte, indices);
//Flush it to the buffer
GL.Flush();
//swap the back buffer we're drawing to to be the front buffer thats displayed
window.SwapBuffers();
};
//Run at X frames per second. Null = 60 FPS, 200 = no cap, anything in between = that cap.
window.Run(200);
}
}
}
}
当我删除
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
Matrix4 perspective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)window.Width / (float)window.Height, 0.1f, 100f);
GL.LoadMatrix(ref perspective);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
Matrix4 lookat = Matrix4.LookAt(m_eye,m_target,Vector3.UnitY);
GL.LoadMatrix(ref lookat);
GL.LoadIdentity();
并将其替换为
GL.Ortho(0.0f, window.Width, 0.0f, window.Height, 0.0f, 1000.0f);
渲染效果很好,但如果我尝试使用矩阵,我只会得到黑色 window。
我做错了什么?
问题是您没有正确设置矩阵。
首先在某处声明这些变量:
private Matrix4 projectionMatrix;
private Matrix4 modelViewMatrix;
private Vector3 cameraPosition;
private Vector3 cameraTarget;
private Vector3 cameraUp = Vector3.UnitY; // which way is up for the camera
然后使用这些功能来控制您的基本相机:
private void SetPerspectiveProjection (int width, int height, float FOV)
{
projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI * (FOV/180f), width / (float)height, 0.2f, 256.0f);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projectionMatrix); // this replaces the old matrix, no need for GL.LoadIdentity()
}
private void SetOrthographicProjection ()
{
projectionMatrix = Matrix4.Identity;
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity(); // reset matrix
GL.Ortho (-1f, 1f, -1f, 1f, 1000f, -1000f);
}
private void SetLookAtCamera(Vector3 position, Vector3 target, Vector3 up)
{
modelViewMatrix = Matrix4.LookAt(position, target, up);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref modelViewMatrix);
}
最后,在画任何东西之前:
SetPerspectiveProjection(viewWidth, viewHeight, 45); // 45 is in degrees
SetLookAtCamera(cameraPosition, cameraTarget, cameraUp);
// draw 3D models here
SetOrthographicProjection();
// draw user interface elements here