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. =/
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.
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()
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. =/
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.
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()