带有 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