简体   繁体   中英

Perspective projection (using gl-matrix) in Webgl 2 shows nothing, but without it shows fine

I have the following javascript code:

// convenience function.
function v(x, y, z){
    var v = vec3.create();
    vec3.set(v, x, y, z);
    return v;
}

window.onload = function() {
    gl = get_gl('c', {antialias: true})
    var vert_shader = make_vertex_shader(gl,
        `
        in vec3 a_pos;
        uniform mat4 u_transform;
        uniform mat4 u_camera;
        uniform mat4 u_projection;
        void main(){
            gl_Position = vec4(a_pos.xyz, 1) * u_transform * u_camera * u_projection;
        }  
        `);
    var frag_shader = make_fragment_shader(gl,
        `
        uniform vec4 u_color;
        out vec4 frag_color;
        void main(){
            frag_color = u_color;
        }
        `)
    var program = make_program(gl, vert_shader, frag_shader);
    // Triangle
    var points = [1, 0, 0,
                -1, 0, 0,
                0, 1, 0]
    var pos_buffer = gl.createBuffer()
    gl.bindBuffer(gl.ARRAY_BUFFER, pos_buffer)
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.STATIC_DRAW)

    // ---------- create a transform matrix..
    var point_transform = mat4.create();
    mat4.scale(point_transform, point_transform, v(0.5, 1, 1))

    // ---------- create a camera matrix
    var camera = mat4.create();
    mat4.lookAt(camera, v(0, 0, 10), v(0, 0, 0), v(0, 1, 0))

    // ---------- create a projection matrix
    var proj = mat4.create();
    var c = document.querySelector('#c')
    mat4.perspective(proj, 0.5, c.width / c.height, 1, 1000)

    // ---------- set attribs
    var attrib_location = gl.getAttribLocation(program, "a_pos")
    gl.vertexAttribPointer(attrib_location, 3, gl.FLOAT, false, 0, 0)

    // ---------- set uniforms
    gl.useProgram(program) 
    var color_location = gl.getUniformLocation(program, "u_color")
    gl.uniform4fv(color_location, new Float32Array([0.9, 0.9, 0.8, 1]))
    var transform_location = gl.getUniformLocation(program, "u_transform")
    gl.uniformMatrix4fv(transform_location, false, point_transform)
    var camera_location = gl.getUniformLocation(program, "u_camera")
    gl.uniformMatrix4fv(camera_location, false, camera)
    var proj_location = gl.getUniformLocation(program, "u_projection")
    gl.uniformMatrix4fv(proj_location, false, mat4.identity(mat4.create()))

    // ---------- setup pre drawing
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)
    gl.clearColor(0, 0, 0, 0)
    gl.clear(gl.COLOR_BUFFER_BIT)

    // ---------- do the drawing
    gl.enableVertexAttribArray(attrib_location)
    gl.drawArrays(gl.TRIANGLES, 0, 3)

}

This outputs a triangle on screen correctly as expected:

Screenshot of canvas
画布截图

Note I'm not actually doing any multiplication with the perspective matrix here. I'm just passing an identity matrix to show that it works correctly without it.

Now when I change the line:

gl.uniformMatrix4fv(proj_location, false, mat4.identity(mat4.create()))

to:

gl.uniformMatrix4fv(proj_location, false, proj)

I get an empty canvas.

I went through posts online, and tried out some of the suggestions, like inverting the Z. And fiddled with the near and far planes etc. But it's always empty output.

What is wrong with the perspective matrix? Namely here:

mat4.perspective(proj, 0.5, c.width / c.height, 1, 1000)

Note: I'm using gl-matrix 's mat4 and vec3 modules for the matrix operations.

In the vertex shader, you have to change the line:

gl_Position = vec4(a_pos.xyz, 1) * u_transform * u_camera * u_projection;

to

gl_Position = u_projection * u_camera * u_transform * vec4(a_pos.xyz, 1);

because, GLSL operations between matrices and vectors are not commutative.

See the Khronos GLSL ES Specification (chapter 5.10 Vector and Matrix Operations) which clearly says:

The exceptions are matrix multiplied by vector, vector multiplied by matrix, and matrix multiplied by matrix. These do not operate component-wise, but rather perform the correct linear algebraic multiply

vec3 v, u;
mat3 m;
u = v * m;

is equivalent to

ux = dot(v, m[0]); // m[0] is the left column of m
uy = dot(v, m[1]); // dot(a,b) is the inner (dot) product of a and b
uz = dot(v, m[2]);

And

u = m * v;

is equivalent to

ux = m[0].x * vx + m[1].x * vy + m[2].x * vz;
uy = m[0].y * vx + m[1].y * vy + m[2].y * vz;
uz = m[0].z * vx + m[1].z * vy + m[2].z * vz;

See also

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM