Misunderstanding the Model-View-Projection matrix in OpenGL

Question:

I am attempting to write a basic program in modern OpenGL using Python and pyglet. I am able to place a simple triangle on the screen with different colors for each of the corners. I am at the point where I am attempting to add the projection and view matrix so that I am able to move the “camera” around in 3D space, but it keeps black-screening when I add both matrices. I can add the projection matrix and it works as expected. I can simply just add the view matrix, and it still shows the triangle. However, when I multiply the view matrix and the projection matrix together it gives a black screen.

Since I am able to produce a colored triangle with the projection matrix, I think I can safely assume that all my OpenGL context is valid. So, maybe I must have misunderstood the mathematics.

Here is a summary of my relevant code:

import pyrr

fov = 60
aspect_ratio = 800 / 600 #width / height
near_clip = 0.1
far_clip = 100

#create a perspective matrix
projection_matrix = pyrr.matrix44.create_perspective_projection(
fov,
aspect_ratio,
near_clip,
far_clip
)

view_matrix = pyrr.matrix44.creat_look_at(
pyrr.vector3.create(0, 0, 1), #camera position
pyrr.vector3.create(0, 0, 0), #camera target
pyrr.vector3.create(0, 1, 0)  #camera up vector
)

mvp_matrix = projection_matrix * view_matrix

From here, I translate the mvp_matrix into a c_types array that OpenGL can understand. I don’t think the code that does the translation is relevant since it works with just the projection matrix correctly.

Here are the matrices that pyrr is giving me:

Projection Matrix:
[[ 1.15470054  0.          0.          0.        ]
 [ 0.          1.73205081  0.          0.        ]
 [ 0.          0.         -1.002002   -1.        ]
 [ 0.          0.         -0.2002002   0.        ]]

View Matrix:
[[1.  0.  0.  0.]
 [0.  1.  0.  0.]
 [0.  0.  1.  0.]
 [0.  0. -1.  1.]]

MVP Matrix:
[[ 1.15470054  0.          0.          0.        ]
 [ 0.          1.73205081  0.          0.        ]
 [ 0.          0.         -1.002002   -0.        ]
 [ 0.          0.         -0.          0.        ]]

Any ideas on why just the projection matrix is able to show the triangle, but when I add in the view matrix it just shows black screens?

I’ve tried making the triangle really big on all the x, y, and z-axis, but still just a black screen. =/

Asked By: Zachary Bohn

||

Answers:

After some more testing I’ve discovered that the pyrr module seems to be performing matrix multiplication strangely. Pyrr is built on numpy however, so after using:

numpy.matmul(projection_matrix, view_matrix)

Then, it was able to create the MVP matrix correctly.

Answered By: Zachary Bohn

Oh… my answer is voted as "not useful". I just want to show I use the exactly same view and projection matrix and I can see my objects (serval lines), not just black screen.

If you can provide the complete code, maybe I can provide more help. There could be many reasons why you can only see black screen (could be the normal/the view matrix/the projection matrix … problem). And I just start to use pyglet, so I face a strange problem "on_resize()" maybe not related with this topic. But I’m very familiar with view/projection matrix. You can learn more from my repo: https://github.com/bitlw/LearnProjMatrix

— below is my original answer —

What’re your vertices? I tried [0, 01, 0], [1, 0, 0] to draw a line and I can see it with your view and projection. And during my test, I noticed a very important function which is on_resize(), it can be empty (only return pyglet.event.EVENT_HANDLED), but it should be there, otherwise I can see nothing. Not sure if you have the same problem.

import pyglet
from pyglet.gl import *
import pyrr

window = pyglet.window.Window(width=800, height=600)

@window.event
def on_draw():
    window.clear()
    batch.draw()

# this function is very important, I can see nothing if I remove it
@window.event
def on_resize(width, height):
    return pyglet.event.EVENT_HANDLED

def setup():
    glClearColor(0, 0, 0, 1)
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_CULL_FACE)


def create_torus(shader, batch):
    # Create the vertex and normal arrays.
    O = [0, 0, 0]
    X = [1, 0, 0]
    Y = [0, 1, 0]
    Z = [0, 0, 1]

    red = [1, 0, 0, 1]
    green = [0, 1, 0, 1]
    blue = [0, 0, 1, 1]

    vertices = []
    vertices.extend(O)
    vertices.extend(X)
    vertices.extend(O)
    vertices.extend(Y)
    vertices.extend(O)
    vertices.extend(Z)

    normals = [0, 0, 1] * 6

    indices = [0, 1, 2, 3, 4, 5]
    colors = []
    colors.extend(red)
    colors.extend(red)
    colors.extend(green)
    colors.extend(green)
    colors.extend(blue)
    colors.extend(blue)

    # Create a Material and Group for the Model
    diffuse = [0.5, 0.0, 0.3, 1.0]
    ambient = [0.5, 0.0, 0.3, 1.0]
    specular = [1.0, 1.0, 1.0, 1.0]
    emission = [0.0, 0.0, 0.0, 1.0]
    shininess = 50

    material = pyglet.model.Material("custom", diffuse, ambient, specular, emission, shininess)
    group = pyglet.model.MaterialGroup(material=material, program=shader)

    vertex_list = shader.vertex_list_indexed(6, GL_LINES, indices, batch, group,
                                         position=('f', vertices),
                                         normals=('f', normals),
                                         colors=('f', colors))

    return pyglet.model.Model([vertex_list], [group], batch)


setup()

batch = pyglet.graphics.Batch()
shader = pyglet.model.get_default_shader()
torus_model = create_torus(shader, batch)

fov = 60
aspect_ratio = 800 / 600 #width / height
near_clip = 0.1
far_clip = 100

#create a perspective matrix
projection_matrix = pyrr.matrix44.create_perspective_projection(fov,aspect_ratio,near_clip,far_clip)

view_matrix = pyrr.matrix44.create_look_at(
pyrr.vector3.create(0, 0, 1), #camera position
pyrr.vector3.create(0, 0, 0), #camera target
pyrr.vector3.create(0, 1, 0)  #camera up vector
)
window.view = view_matrix.flatten()
window.projection = projection_matrix.flatten()

pyglet.app.run()
Answered By: Wei Liu
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.