Search code examples
c#openglmatrixglslopentk

Not sure how to properly use Matrix4.LookAt in this situation


I am experimenting with ray marching, and have been following Jamie Wong's tutorial.

When the moving the camera section comes, they use the function

mat4 viewMatrix(vec3 eye, vec3 center, vec3 up) {
    vec3 f = normalize(center - eye);
    vec3 s = normalize(cross(f, up));
    vec3 u = cross(s, f);
    return mat4(
        vec4(s, 0.0),
        vec4(u, 0.0),
        vec4(-f, 0.0),
        vec4(0.0, 0.0, 0.0, 1)
    );
}

To generate a matrix that can be used to transform the direction vector so that the camera looks at the right object.

I wanted to move the matrix calculation out of the shader though, since it would be a better fit as a uniform, and so I did, but OpenTK's function Matrix4.LookAt() produces very different results, and I'm not sure how to apply them to the ray with the simple multiplication that Jamie's function gave.

I have confirmed that the matrix is being loaded into the uniform correctly, it just doesn't apply to the direction vector in the same way.

Edit: I am aware that I can translate Jamie Wong's function from GLSL into C#, but I want to know the correct usage of Matrix4.LookAt.


Solution

  • OpenTK offers the data types Vector3, Vector4 and Matrix4 in the OpenTK.Mathematics namespace.

    Assuming you have the vectors:

    Vector3 center;
    Vector3 eye;
    Vector3 up;
    

    Calculate the view matrix as follows

    var f = Vector3.Normalize(center - eye);
    var s = Vector3.Normalize(Vector3.Cross(f, up));
    var u = Vector3.cross(s, f);
    var viewMatrix = new Matrix4(
        new Vector4(s, 0.0f),
        new Vector4(u, 0.0f),
        new Vector4(-f, 0.0f),
        new Vector4(0.0f, 0.0f, 0,0f, 1.0f),
    );
    

    A uniform of type mat4 can be set with GL.UniformMatrix4. For example:

    uniform mat4 viewMatrix;
    
    int viewMatrixLoc = GL.GetUniformLocation(0, "viewMatrix");
    GL.UniformMatrix4(viewMatrixLoc, false, ref viewMatrix);
    

    Your "view matrix" transforms from view space into world space. It transforms a "view" ray into the world.
    Matrix4.LookAt does the opposite. It computes a matrix that transforms world space to view space. It generates a matrix for rasterization, in which an object must be transformed from the world into the view.
    So you need to invert the matrix that you get from Matrix4.LookAt:

    Matrix4 viewMatrix = Matrix4.LookAt(
        new Vector3(0.0f),
        center - eye,
        up
    ).Inverted();