问题
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