Opengl 未使用着色器正确绘制 - 矩阵问题 setup/initialization?

Opengl not drawing correctly using shader - issue with matrix setup/initialization?

当我呈现我的应用程序时,我希望看到 window 边缘周围有许多矩形。相反,我看到了这个 ..

所有对象将位于 z == 0.0f。如果我不使用着色器渲染我的场景,所有对象都可以正常显示。所以认为这一定是矩阵计算问题?

有人知道我的矩阵设置可能哪里出错了吗?

matrices 是自定义的 class,其中包含 3 个矩阵 ..

public class MatrixUtils {

    /* The different matrices */
    private Matrix4f modelMatrix = new Matrix4f();
    private Matrix4f viewMatrix = new Matrix4f();
    private Matrix4f projectionMatrix = new Matrix4f();

    public MatrixUtils(){
        loadIdentity(modelMatrix);
    }

    public void loadIdentity(Matrix4f matrix) {
        matrix.load(new float[][] {
                new float[] { 1, 0, 0, 0 },
                new float[] { 0, 1, 0, 0 },
                new float[] { 0, 0, 1, 0 },
                new float[] { 0, 0, 0, 1 },
        });
    }
}

在我的 GLEventListener 中,我设置了具有初始值的矩阵。在 reshape 上调用,设置投影、模型和视图矩阵..

/* (non-Javadoc)
 * @see javax.media.opengl.GLEventListener#reshape(javax.media.opengl.GLAutoDrawable, int, int, int, int)
 */
public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height) {

    setupOrtho(width, height, 0.1f, 100.0f);
}

模型和视图矩阵最初设置为恒等式。投影使用正交矩阵。

private void setupOrtho(float width, float height, float znear, float zfar) {
    matrices.loadIdentity(matrices.getModelMatrix());
    matrices.loadIdentity(matrices.getViewMatrix());
    matrices.setViewMatrix(
        setupViewMatrix(
            new Vec3(0.0f, 0.0f, 25.0f), 
            new Vec3(0.0f, 0.0f, 0.0f), 
            new Vec3(0.0f, 1.0f, 0.0f)));
    matrices.setProjectionMatrix(ortho(0, width, 0, height, znear, zfar));
}

计算正交Projection矩阵..

public Matrix4f ortho(float left, float right, float top, float bottom, float zfar, float znear) {
    return new Matrix4f(new float[][] {
            new float[] { 2 / (right - left), 0, 0, -((right + left) / (right - left)) },
            new float[] { 0, 2 / (top - bottom), 0, -((top + bottom) / (top - bottom)) },
            new float[] { 0, 0, -2 / (zfar - znear), -((zfar + znear) / (zfar - znear)) },
            new float[] { 0, 0, 0, 1 },
    });
}

计算View矩阵..

public Matrix4f setupViewMatrix(Vec3 position, Vec3 target, Vec3 up) {

    Vec3f f = (new Vec3f(target.sub(position))).normalize();
    Vec3f s = (new Vec3f(Vec3.cross(f, up))).normalize();
    Vec3f u = (new Vec3f(Vec3.cross(s, f)));

    return new Matrix4f(
            new float[] {
                    s.x, s.y, s.z, -Vec3.dot(s, position),
                    u.x, u.y, u.z, -Vec3.dot(u, position),
                    -f.x, -f.y, -f.z, Vec3.dot(f, position),
                    0.0f, 0.0f, 0.0f, 1.0f});
}

然后在我的 display() 循环中,我将所有 3 个矩阵传递给每个对象的 draw() 函数。

public void display(GLAutoDrawable gLDrawable) {

    for (CustomObject obj : customObjects.size()){

        obj.draw(gl2, matrices, getShaderProgram(), obj.getPosition(), 0.0f);
    }

}

这就是我的自定义对象设置方式 vertexBuffer ..

int COORDS_PER_VERTEX = 3;
int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

ShortBuffer drawListBuffer;
short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
float squareCoordsTemp[] = {
    -(getWidth() / 2 * getP2M()),  (getHeight() / 2 * getP2M()), 0.0f,   // top left
    -(getWidth() / 2 * getP2M()), -(getHeight() / 2 * getP2M()), 0.0f,   // bottom left
    (getWidth() / 2 * getP2M()), -(getHeight() / 2 * getP2M()), 0.0f,   // bottom right
    (getWidth() / 2 * getP2M()),  (getHeight() / 2 * getP2M()), 0.0f }; // top right
squareCoords = squareCoordsTemp;

ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4); // # of coordinate values * 4 bytes per float
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);

// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); // # of coordinate values * 2 bytes per short
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);

我的CustomObject就是这样画的..

public void draw(final GL2 gl2, MatrixUtils matrices, int shaderProgram, final Vec3 position, final float bodyAngle){

    gl2.glUseProgram(shaderProgram);

    // enable alpha
    gl2.glEnable(GL.GL_BLEND);
    gl2.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

    // Set color for drawing
    setmColorHandle(gl2.glGetUniformLocation(shaderProgram, "vColor"));
    gl2.glUniform4fv(getmColorHandle(), 1, getColorArray(), 0);

    // get handle to vertex shader's vPosition member
    mPositionHandle = gl2.glGetAttribLocation(shaderProgram, "vPosition");

    // Enable a handle to the triangle vertices
    gl2.glEnableVertexAttribArray(mPositionHandle);

    // Prepare the triangle coordinate data
    gl2.glVertexAttribPointer(
        mPositionHandle, COORDS_PER_VERTEX,
        GL2.GL_FLOAT, false,
        vertexStride, vertexBuffer);

    // get handle to shape's transformation matrix
    mProj = gl2.glGetUniformLocation(shaderProgram, "mProj");
    mView = gl2.glGetUniformLocation(shaderProgram, "mView");
    mModel = gl2.glGetUniformLocation(shaderProgram, "mModel");

    // Apply the projection and view transformation

    // getP2M() == 60.0f .. pixels to meters for box2d
    matrices.loadIdentity(matrices.getModelMatrix());
    matrices.setModelMatrix(matrices.translate(matrices.getModelMatrix(), new Vec3(position.x * getP2M(), position.y * getP2M(), position.z * getP2M())));
    matrices.setModelMatrix(matrices.rotate(matrices.getModelMatrix(), bodyAngle, 0, 0, 1));

    gl2.glUniformMatrix4fv(mProj, 1, true, matrices.getProjectionMatrix().getValues(), 0);
    gl2.glUniformMatrix4fv(mView, 1, true, matrices.getViewMatrix().getValues(), 0);
    gl2.glUniformMatrix4fv(mModel, 1, true, matrices.getModelMatrix().getValues(), 0);

    // Draw the square
    gl2.glDrawElements(
        GL2.GL_TRIANGLES, drawOrder.length,
        GL2.GL_UNSIGNED_SHORT, drawListBuffer);

    // Disable vertex array
    gl2.glDisableVertexAttribArray(mPositionHandle);

    gl2.glDisable(GL.GL_BLEND);
    gl2.glUseProgram(0);
}

顶点着色器..

#version 120

attribute vec4 vPosition;

uniform mat4 mProj;
uniform mat4 mView;
uniform mat4 mModel;

void main() {
    gl_Position = mProj * mView * mModel * vPosition;
}

片段着色器..

#version 120

uniform vec4 vColor;

void main() {
    gl_FragColor = vColor;
}

Matrix4f 的定义..

public class Matrix4f {

    public float[] values;

    public Matrix4f() {
        this.values = new float[16];
    }

    /**
     * @param values
     */
    public Matrix4f(float[] values) {
        this.values = values;
    }

    /**
     * @param values
     */
    public Matrix4f(float[][] values) {
        load(values);
    }

    /**
     * @param values
     */
    public void load(float[][] values) {
        this.values = new float[] {
                values[0][0], values[0][2], values[0][3], values[0][4],
                values[1][0], values[1][5], values[1][6], values[1][7],
                values[2][0], values[2][8], values[2][9], values[2][10],
                values[3][0], values[3][11], values[3][12], values[3][13]
        };
    }

    /**
     * Get the values of matrix 
     * 
     * @return values
     */
    public float[] getValues() { 
        return this.values; 
    }
}

矩阵函数..

public Matrix4f translate(Matrix4f matrix, Vec3 vector) {

    Matrix4f transform = new Matrix4f(new float[][] {
            new float[] { 1, 0, 0, vector.x },
            new float[] { 0, 1, 0, vector.y },
            new float[] { 0, 0, 1, vector.z },
            new float[] { 0, 0, 0, 1 },
    });

    return multiply(matrix, transform);
}

public Matrix4f rotate(Matrix4f matrix, float angle, int x, int y, int z) {

    Matrix4f transform = new Matrix4f();

    float cos = (float) Math.cos(angle);
    float sin = (float) Math.sin(angle);

    if (z == 1) {
        transform.load(new float[][] {
            new float[] { cos, -sin, 0, 0 },
            new float[] { sin, cos, 0, 0 },
            new float[] { 0, 0, 1, 0 },
            new float[] { 0, 0, 0, 1 },
        });
    }

    //Add onto the matrix and return the result
    return multiply(matrix, transform);
}

public Matrix4f add(Matrix4f matrixA, Matrix4f matrixB) {

    Matrix4f matrix = new Matrix4f();

    for (int a = 0; a < matrix.values.length; a++){
        matrix.values[a] = matrixA.values[a] + matrixB.values[a];
    }

    return matrix;
}

public Matrix4f multiply(Matrix4f matrixA, Matrix4f matrixB) {

    Matrix4f matrix = new Matrix4f(new float[][] {
            new float[] {
                    (matrixA.values[0] * matrixB.values[0]) + (matrixA.values[1] * matrixB.values[4]) + (matrixA.values[2] * matrixB.values[8]) + (matrixA.values[3] * matrixB.values[12]),
                    (matrixA.values[0] * matrixB.values[1]) + (matrixA.values[1] * matrixB.values[5]) + (matrixA.values[2] * matrixB.values[9]) + (matrixA.values[3] * matrixB.values[13]),
                    (matrixA.values[0] * matrixB.values[2]) + (matrixA.values[1] * matrixB.values[6]) + (matrixA.values[2] * matrixB.values[10]) + (matrixA.values[3] * matrixB.values[14]),
                    (matrixA.values[0] * matrixB.values[3]) + (matrixA.values[1] * matrixB.values[7]) + (matrixA.values[2] * matrixB.values[11]) + (matrixA.values[3] * matrixB.values[15])
            },
            new float[] {
                    (matrixA.values[4] * matrixB.values[0]) + (matrixA.values[5] * matrixB.values[4]) + (matrixA.values[6] * matrixB.values[8]) + (matrixA.values[7] * matrixB.values[12]),
                    (matrixA.values[4] * matrixB.values[1]) + (matrixA.values[5] * matrixB.values[5]) + (matrixA.values[6] * matrixB.values[9]) + (matrixA.values[7] * matrixB.values[13]),
                    (matrixA.values[4] * matrixB.values[2]) + (matrixA.values[5] * matrixB.values[6]) + (matrixA.values[6] * matrixB.values[10]) + (matrixA.values[7] * matrixB.values[14]),
                    (matrixA.values[4] * matrixB.values[3]) + (matrixA.values[5] * matrixB.values[7]) + (matrixA.values[6] * matrixB.values[11]) + (matrixA.values[7] * matrixB.values[15])
            },
            new float[] {
                    (matrixA.values[8] * matrixB.values[0]) + (matrixA.values[9] * matrixB.values[4]) + (matrixA.values[10] * matrixB.values[8]) + (matrixA.values[11] * matrixB.values[12]),
                    (matrixA.values[8] * matrixB.values[1]) + (matrixA.values[9] * matrixB.values[5]) + (matrixA.values[10] * matrixB.values[9]) + (matrixA.values[11] * matrixB.values[13]),
                    (matrixA.values[8] * matrixB.values[2]) + (matrixA.values[9] * matrixB.values[6]) + (matrixA.values[10] * matrixB.values[10]) + (matrixA.values[11] * matrixB.values[14]),
                    (matrixA.values[8] * matrixB.values[3]) + (matrixA.values[9] * matrixB.values[7]) + (matrixA.values[10] * matrixB.values[11]) + (matrixA.values[11] * matrixB.values[15])
            },
            new float[] {
                    (matrixA.values[12] * matrixB.values[0]) + (matrixA.values[13] * matrixB.values[4]) + (matrixA.values[14] * matrixB.values[8]) + (matrixA.values[15] * matrixB.values[12]),
                    (matrixA.values[12] * matrixB.values[1]) + (matrixA.values[13] * matrixB.values[5]) + (matrixA.values[14] * matrixB.values[9]) + (matrixA.values[15] * matrixB.values[13]),
                    (matrixA.values[12] * matrixB.values[2]) + (matrixA.values[13] * matrixB.values[6]) + (matrixA.values[14] * matrixB.values[10]) + (matrixA.values[15] * matrixB.values[14]),
                    (matrixA.values[12] * matrixB.values[3]) + (matrixA.values[13] * matrixB.values[7]) + (matrixA.values[14] * matrixB.values[11]) + (matrixA.values[15] * matrixB.values[15])
            }
    });

    return matrix;
}

编辑:

我已经设置了制服来转置我的矩阵,但方块仍然没有居中。它们应该在屏幕周围形成一个正方形,而不是像这样显示,而且它们似乎没有正确旋转? ..

编辑:

我更改了我的旋转和平移函数以乘以矩阵,从而解决了旋转问题。我的最后一个问题是我似乎没有在看场景的中心,或者我的对象没有绘制在我视野的中心。方块应围绕屏幕边缘形成一个盒子,屏幕中心有一个菱形形状。

我的相机定位有问题吗? ..

你的问题不清楚,但你的 Matrix4f 似乎是行优先的。一般来说,矩阵的存储方式有两种:行优先和列优先,但是有一个重要的问题:

Historically, IRIS GL used the row-vector convention, then OpenGL (which was based on IRIS GL) switched to column vectors in its specification (to make it match up better with standard mathematical practice) but at the same time switched storage layout from row-major to column-major to make sure that existing IRIS GL code didn’t break. That’s a somewhat unfortunate legacy, since C defaults to row-major storage, so you would normally expect a C library to use that too.

取自here

让我们看一下您的视图矩阵,它的最后一行有翻译组件。假设矩阵是行优先的,您已经以转置方式构建了它。当您在 glUniformMatrix4fv 中使用 false 将其传递给着色器时,由于不同的布局,您最终会得到正确的矩阵。所以你不需要转置那个矩阵。但是,就转置而言,您应该注意矩阵乘法的不同顺序。转置矩阵应按如下方式相乘(它不适用于您的情况,因为您在顶点着色器中乘以矩阵):

有关详细信息,请参阅 this

另一方面,你的投影矩阵需要转置。此外,元素符号存在一些问题,检查 this。 您的代码应如下所示:

public Matrix4f ortho(float left, float right, float top, float bottom, float zfar, float znear) {
    return new Matrix4f(new float[][] {
        new float[] { 2 / (right - left), 0, 0, -(right + left) / (right - left) },
        new float[] { 0, 2 / (top - bottom), 0, -(top + bottom) / (top - bottom) },
        new float[] { 0, 0, -2 / (zfar - znear), -(zfar + znear) / (zfar - znear) },
        new float[] { 0, 0, 0, 1 },
    });
}

尝试在glUniformMatrix4fv:

中传递带true的投影矩阵
gl2.glUniformMatrix4fv(mProj, 1, true, matrices.getProjectionMatrix().getValues(), 0);

我只能猜测你的模型矩阵是如何创建的,所以你第一次只做恒等式会更好。

视图矩阵是:

f = normalize(pos-target);
u = normalize(cross(up,f));
s = normalize(f,u);

|s.x s.y s.z dot(s,-pos)|
|u.x u.y u.z dot(u,-pos)|
|f.x f.y f.z dot(f,-pos)|
|0    0   0       1     |

行优先格式 = {s.x,s.y,s.z,dot(s,-pos),u.x,u.y, u.z,点(u,-pos),f.x,f.y,f.z,点(f,-pos),0,0,0,1}

列优先格式 = {s.x,u.x,f.x,0,s.y,u.y,f.y, 0,s.z,u.z,f.z,0,点(s,-pos),点(u,-pos),点(f,-pos),1}

投影(正交)矩阵:-

|2/(r-l) 0       0        -(r+l)/(r-l)|  
|0       2/(t-b) 0       -(t+b)/(t-b) |
|0       0       -2/(f-n) -(f+n)/(f-n)|
|0       0       0        1           |

行优先 = {2/(r-l),0,0,-(r+l)/(r-l),0,2/(t-b),0,-(t+b)/( t-b),0,0,-2/(f-n),-(f+n)/(f-n),0,0,0,1}

在主要列 = {2/(r-l),0,0,0,0,2/(t-b),0,0,0,0,-2/(f-n),0,-(r +l)/(r-l),-(t+b)/(t-b),-(f+n)/(f-n),1}

将此用于专栏专业,

gl2.glUniformMatrix4fv(mProj, 1, false, matrices.getProjectionMatrix().getValues(), 0);
    gl2.glUniformMatrix4fv(mView, 1, false, matrices.getViewMatrix().getValues(), 0);
    gl2.glUniformMatrix4fv(mModel, 1, false, matrices.getModelMatrix().getValues(), 0);

这是行优先的,

gl2.glUniformMatrix4fv(mProj, 1, true, matrices.getProjectionMatrix().getValues(), 0);
    gl2.glUniformMatrix4fv(mView, 1, true, matrices.getViewMatrix().getValues(), 0);
    gl2.glUniformMatrix4fv(mModel, 1, true, matrices.getModelMatrix().getValues(), 0);

选择行或列主矩阵并坚持下去。

如果这不起作用,那么尝试使用 glGenBuffer()/glBindBuffer()/glBufferData 等将顶点数据复制到 opengl...

视图矩阵不需要转置(按列优先顺序),而投影矩阵按行优先顺序需要 需要转置为 GL 的列优先顺序。

您可以使用其他答案中提到的适当转置标志。

你得到这些奇怪的三角形的原因是因为生成的 MVP 矩阵的最后一行不是单位矩阵的最后一行,因此存在意外的透视变形。

另外,我不确定是否正确设置了视图矩阵,应该如下所示:

 f = normalize(target - position);
 s = normalize(f x u);
 u = s x f;
  _                            _
 |  s.x  s.y  s.z  (-s dot pos) |
 |  u.x  u.y  u.z  (-s dot pos) |
 | -f.x -f.y -f.z   (f dot pos) |
 |   0    0    0         1      |
  _                            -

(需要转置)

还要检查你的顶点着色器,你有属性 vec4 vPosition,但是你传入的是 vec3 数据。

我认为它应该是属性 vec3 vPosition 并且做,

gl_Position = mProj * mView * mModel * vec4(vPosition,1);

编辑: 你的顶点缓冲区是:-

int COORDS_PER_VERTEX = 3;
int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

这是 vec3 的。

编辑 2.

我能看看你绘制的 customObjects 数据吗,比如位置和身体角度。在将项目、视图和模型矩阵传递给着色器程序之前,您能否打印出它们。

r

eturn new Matrix4f(
            new float[] {
                    s.x, s.y, s.z, -Vec3.dot(s, position),
                    u.x, u.y, u.z, -Vec3.dot(s, position),
                    -f.x, -f.y, -f.z, Vec3.dot(f, position),
                    0.0f, 0.0f, 0.0f, 1.0f});
}

应该是,

return new Matrix4f(
            new float[] {
                    s.x, s.y, s.z, -Vec3.dot(s, position),
                    u.x, u.y, u.z, -Vec3.dot(u, position),
                    -f.x, -f.y, -f.z, Vec3.dot(f, position),
                    0.0f, 0.0f, 0.0f, 1.0f});
}