Orthographic projection with origin at screen bott

2020-03-31 06:55发布

问题:

I'm using the python OpenGL bindings, and trying to only use modern opengl calls. I have a VBO with verticies, and I am trying to render with an orthographic projection matrix passed to the vertex shader.

At present I am calculating my projection matrix with the following values:

from numpy import array

w = float(width)
h = float(height)
n = 0.5
f = 3.0

matrix = array([
                   [2/w,        0,        0,        0],
                   [  0,      2/h,        0,        0],
                   [  0,        0,  1/(f-n), -n/(f-n)],
                   [  0,        0,        0,        1],
               ], 'f')


#later
projectionUniform = glGetUniformLocation(shader, 'projectionMatrix')
glUniformMatrix4fv(projectionUniform, 1, GL_FALSE, matrix)

That code I got from here:

Formula for a orthogonal projection matrix?

This seems to work fine, but I would like my Origin to be in the bottom left corner of the screen. Is this a function I can apply over my matrix so everything "just works", or must I translate every object by w/2 h/2 manually?

side note: Will the coordinates match pixel positions with this working correctly?

Because I'm using modern OpenGL techniques, I don't think I should be using gluOrtho2d or GL_PROJECTION calls.

回答1:

I'm not completely familiar with projections yet, as I've only started OpenGL programming recently, but your current matrix does not translate any points. The diagonal will apply scaling, but the right most column will apply translation. The link Dirk gave gives you a projection matrix that will make your origin (0,0 is what you want, yes?) the bottom-left corner of your screen.

A matrix I've used to do this (each row is actually a column to OpenGL):

OrthoMat = mat4(
        vec4(2.0/(screenDim.s - left),  0.0,    0.0,    0.0),
        vec4(0.0,   2.0/(screenDim.t - bottom),     0.0,    0.0),
        vec4(0.0,   0.0,    -1 * (2.0/(zFar - zNear)),  0.0),
        vec4(-1.0 * (screenDim.s + left)/(screenDim.s - left), -1.0 * (screenDim.t + bottom)/(screenDim.t - bottom), -1.0 * (zFar + zNear)/(zFar - zNear), 1.0)
 );

The screenDim math is effectively the width or height, since left and bottom are both set to 0. zFar and zNear are 1 and -1, respectively (since it's 2D, they're not extremely important).

This matrix takes values in pixels, and the vertex positions need to be in pixels as well. The point (0, 32) will always be at the same position when you resize the screen too.

Hope this helps.

Edit #1: To be clear, the left/bottom/zfar/znear values I stated are the ones I chose to make them. You can change these how you see fit.



回答2:

You can use a more general projection matrix which additionally uses left,right positions.

See Wikipedia for the definition.



回答3:

glUniformMatrix4fv(projectionUniform, 1, GL_FALSE, matrix)

Your matrix is stored in row-major ordering. So you should pass GL_TRUE, or you should change your matrix to column-major.