OpenGL with OpenTK wrapper cannot get projections to work

删除回忆录丶 提交于 2019-12-12 04:56:30

问题


I have created a simple program that creates a cube and makes its rear plane move in a circle.

When i use GL.Ortho() to view it it works fine, I can see the cube but to my belief GL.Ortho() is for 2D projections and i want to make a 3D game, so I've moved on to attempting projection matrices. Heres my code so far:

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);
            }
        }
    }
}

When i remove

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();

and replace it with

GL.Ortho(0.0f, window.Width, 0.0f, window.Height, 0.0f, 1000.0f);

it renders fine, but if i try and use the matrices I just get a black window.

What is it i am doing wrong?


回答1:


The problem is that you are not setting up the matrices correctly.

First declare these variables somewhere:

private Matrix4 projectionMatrix;
private Matrix4 modelViewMatrix;
private Vector3 cameraPosition;
private Vector3 cameraTarget;
private Vector3 cameraUp = Vector3.UnitY; // which way is up for the camera

And then use these functions to control your basic 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);
}

Finally, before drawing anything:

SetPerspectiveProjection(viewWidth, viewHeight, 45); // 45 is in degrees
SetLookAtCamera(cameraPosition, cameraTarget, cameraUp);

// draw 3D models here

SetOrthographicProjection();

// draw user interface elements here


来源:https://stackoverflow.com/questions/28676300/opengl-with-opentk-wrapper-cannot-get-projections-to-work

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!