Search code examples
glslwebglvertex-shader

Is it possible to run code once per draw call in WebGL?


I'm taking a course in WebGL at NTNU. I'm currently exploring what the shaders do and how I can use them.

An example we have shows us that we compute a projection matrix, then set it in the vertex shader, then make a draw call. I wanted to try to do this matrix computation in a shader.

This means I have to put the code somewhere else than the main() function in the vertex shader, since that one is invoked many times per draw call.

Vertex shader:

uniform vec3 camRotation;
attribute vec3 position;
void main() {

    // I want this code to run only once per draw call
    float rX = camRotation[0];
    float rY = camRotation[1];
    float rZ = camRotation[2];
    mat4 camMatrix = mat4(
        cos(rY) * cos(rZ), cos(rZ) * sin(rX) * sin(rY) - cos(rX) * sin(rZ), sin(rX) * sin(rZ) + cos(rX) * cos(rZ) * sin(rY), 0, //
        cos(rY) * sin(rZ), cos(rX) * cos(rZ) + sin(rX) * sin(rY) * sin(rZ), cos(rX) * sin(rY) * sin(rZ) - cos(rZ) * sin(rX), 0, //
        -sin(rY), cos(rY) * sin(rX), cos(rX) * cos(rY), 0, //
        0, 0, 0, 1
    );
    // End of code in question

    gl_Position = camMatrix * vec4(position, 1);
    gl_PointSize = 5.0;
}

Is it possible? Am I a fool for trying?


Solution

  • AFAIK, there's no way to do that. You should compute camMatrix in your JS code and pass it to the shader via uniform:

    uniform mat4 camMatrix;
    attribute vec3 position;
    void main() {
        gl_Position = camMatrix * vec4(position, 1);
        gl_PointSize = 5.0;
    }
    

    Now you need to compute matrix in JS:

    // assuming that program is your compiled shader program and
    // gl is your WebGL context.
    const cos = Math.cos;
    const sin = Math.sin;
    gl.uniformMatrix4fv(gl.getUniformLocation(program, 'camMatrix'), [
        cos(rY) * cos(rZ), cos(rZ) * sin(rX) * sin(rY) - cos(rX) * sin(rZ), sin(rX) * sin(rZ) + cos(rX) * cos(rZ) * sin(rY), 0,
        cos(rY) * sin(rZ), cos(rX) * cos(rZ) + sin(rX) * sin(rY) * sin(rZ), cos(rX) * sin(rY) * sin(rZ) - cos(rZ) * sin(rX), 0,
        -sin(rY), cos(rY) * sin(rX), cos(rX) * cos(rY), 0,
        0, 0, 0, 1
    ]);