Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.1k views
in Technique[技术] by (71.8m points)

c# - OpenGL 4.2 LookAt matrix only works with -z value for eye position

I am trying to understand and apply modern OpenGL matrix transformations. I already read a lot of different sources but I am not sure what I am actually doing wrong.

The issue I have is also commented in the code: If I set the eye coordinates of the Matrix4.LookAt to a z value that is greater or equal 0 or lower -2 the triangle is not visible anymore.

Can someone explain why? As far as I understood the method the triangle should just be visible just from the other side (explicitly disabling face culling does not change anything).

Another thing is strange: if i rotate the triangle it seems to get clipped if I use eye-z = -2; if I use -1 it looks "smoother". Any ideas?

Here is the complete program:

using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL4;

namespace OGL420_Matrices
{
    // OpenTK version 3.1.0
    internal class Program
    {
        public static void Main(string[] args)
        {
            var program = new Program();
            program.Run();
        }

        private GameWindow _gameWindow;
        private Matrix4 _projectionMatrix;
        private Matrix4 _viewMatrix;
        private Matrix4 _viewProjectionMatrix;
        private Matrix4 _modelMatrix;
        private int _vbaId, _programId, _viewProjectionUniformId, _modelMatrixUniformId;

        private void Run()
        {
            // 4, 2 is OpenGL 4.2
            using (_gameWindow = new GameWindow(800, 600, GraphicsMode.Default, "", GameWindowFlags.Default,
                DisplayDevice.Default, 4, 2, GraphicsContextFlags.Default))
            {
                _gameWindow.Load += OnLoad;
                _gameWindow.Resize += OnResize;
                _gameWindow.RenderFrame += OnRenderFrame;

                _gameWindow.Run();
            }
        }

        private void OnResize(object sender, EventArgs e)
        {
            var clientArea = _gameWindow.ClientRectangle;
            GL.Viewport(0, 0, clientArea.Width, clientArea.Height);
        }

        private void OnLoad(object sender, EventArgs e)
        {
            _projectionMatrix = Matrix4.CreateOrthographic(3, 3, 0.001f, 50);

            // change -1 to -2.1f you dont see anything
            // change -1 to -2f you still see the same
            // change -1 to >= 0 you dont see anything; of course 0 doesn't make sense but 1 would
            _viewMatrix = Matrix4.LookAt(
                new Vector3(0, 0, -1f), // eye
                new Vector3(0, 0, 0), // target
                new Vector3(0, 1, 0)); // up
            _modelMatrix = Matrix4.Identity;

            var data = new float[]
            {
                0, 0, 0,
                1, 0, 0,
                0, 1, 0
            };

            var vboId = GL.GenBuffer();

            GL.BindBuffer(BufferTarget.ArrayBuffer, vboId);
            GL.BufferData(BufferTarget.ArrayBuffer, data.Length * sizeof(float), data, BufferUsageHint.StaticDraw);

            _vbaId = GL.GenVertexArray();

            GL.BindVertexArray(_vbaId);
            GL.BindBuffer(BufferTarget.ArrayBuffer, vboId);

            GL.EnableVertexAttribArray(0);
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);

            var vertexShaderId = GL.CreateShader(ShaderType.VertexShader);
            GL.ShaderSource(vertexShaderId, @"#version 420

layout(location = 0) in vec3 position;

uniform mat4 viewProjection;
uniform mat4 model;

out vec3 outColor;

void main()
{
    gl_Position = viewProjection * model * vec4(position, 1);
    outColor = vec3(1,1,1);
}");

            GL.CompileShader(vertexShaderId);
            GL.GetShader(vertexShaderId, ShaderParameter.CompileStatus, out var result);

            if (result != 1)
                throw new Exception("compilation error: " + GL.GetShaderInfoLog(vertexShaderId));

            var fragShaderId = GL.CreateShader(ShaderType.FragmentShader);
            GL.ShaderSource(fragShaderId, @"#version 420

in vec3 outColor;
out vec4 fragmentColor;

void main()
{
    fragmentColor = vec4(outColor, 1);
}");

            GL.CompileShader(fragShaderId);
            GL.GetShader(fragShaderId, ShaderParameter.CompileStatus, out result);

            if (result != 1)
                throw new Exception("compilation error: " + GL.GetShaderInfoLog(fragShaderId));

            _programId = GL.CreateProgram();
            GL.AttachShader(_programId, vertexShaderId);
            GL.AttachShader(_programId, fragShaderId);

            GL.LinkProgram(_programId);
            GL.GetProgram(_programId, GetProgramParameterName.LinkStatus, out var linkStatus);

            if (linkStatus != 1) // 1 for true
                throw new Exception("Shader program compilation error: " + GL.GetProgramInfoLog(_programId));

            GL.DeleteShader(vertexShaderId);
            GL.DeleteShader(fragShaderId);

            _viewProjectionUniformId = GL.GetUniformLocation(_programId, "viewProjection");
            _modelMatrixUniformId = GL.GetUniformLocation(_programId, "model");
        }

        private void OnRenderFrame(object sender, FrameEventArgs e)
        {
            GL.Clear(ClearBufferMask.ColorBufferBit);

            _viewProjectionMatrix = _projectionMatrix * _viewMatrix;

            GL.UniformMatrix4(_viewProjectionUniformId, false, ref _viewProjectionMatrix);
            GL.UniformMatrix4(_modelMatrixUniformId, false, ref _modelMatrix);

            GL.UseProgram(_programId);
            GL.BindVertexArray(_vbaId);
            GL.DrawArrays(PrimitiveType.Triangles, 0, 3);

            _gameWindow.SwapBuffers();
        }
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

First I'll quote a comment to the OpenTK issue: Problem with matrices #687:

Because of how matrices are treated in C# and OpenTK, multiplication order is inverted from what you might expect in C/C++ and GLSL. This is an old artefact in the library, and it's too late to change now, unfortunately.


In compare to glsl, where column major order matrices have to be multiplied form the right to the left, where the right matrix is the matrix which is applied "first", in OpenTK the matrices have to be multiplied from the left to the right.

This means, if you want to calculate the viewProjectionMatrix in glsl, which does the view transformation followed by the projection, then in glsl it is (for column major order matrices):

mat4 viewProjectionMatrix = projectionMatrix * viewMatrix;

If you want to do the same in in OpenTK, by the use of Matrix4, then you've to do:

_viewProjectionMatrix = _viewMatrix * _projectionMatrix;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
by (100 points)
I want to know if anyone tried this recommendation.
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...