Search code examples
javascriptpositionwebglvertex-shadervertex

WebGL Position vertex inside vertex shader?


My goal is to specify custom positions for vertices within the shader vertex rather than relying on a JavaScript "new Float32Array(positions)" for defining vertex positions. The data should represent a simple triangle shape. Additionally, I aim to ensure that the vertices are positioned precisely as intended to achieve the desired visual outcome.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL Example</title>
    <style>
        canvas {
            border: 1px solid black;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="400" height="400"></canvas>
    <script>
        window.onload = function() {
            var canvas = document.getElementById('canvas');
            var gl = canvas.getContext('webgl');

            const shaderSource = {
                vertex: `
                 
                          uniform vec2 screenSize; // Screen size uniform

                          void main(void) {
                              // Define combined vertices
                              vec3 vertices[3];
                              vertices[0] = vec3(0.0, 1.0, 0.0);
                              vertices[1] = vec3(-1.0, -1.0, 0.0);
                              vertices[2] = vec3(1.0, -1.0, 0.0);

                              // Adjust vertices based on screen size
                              for (int i = 0; i < 3; i++) {
                                  vertices[i].x *= screenSize.x / screenSize.y; // Adjust x coordinate based on aspect ratio
                              }

                              // Create another vec3 to store the vertices
                              vec3 finalPosition = vec3(0.0);

                              // Add the selected vertex to finalPosition
                              finalPosition vec3(vertices[0],vertices[1],vertices[2]);

                              // Calculate final position
                              gl_Position = vec4(finalPosition, 1.0);
                          }


                `,
                fragment: `
                    void main(void) {
                        gl_FragColor = vec4(0, 0.8, 0, 1);
                    }
                `
            };

            var vertShader = gl.createShader(gl.VERTEX_SHADER);
            gl.shaderSource(vertShader, shaderSource.vertex);
            gl.compileShader(vertShader);

            var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
            gl.shaderSource(fragShader, shaderSource.fragment);
            gl.compileShader(fragShader);

            var shaderProgram = gl.createProgram();
            gl.attachShader(shaderProgram, vertShader);
            gl.attachShader(shaderProgram, fragShader);
            gl.linkProgram(shaderProgram);
            gl.useProgram(shaderProgram);

            // Clear the canvas
            gl.clearColor(1.0, 1.0, 1.0, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);

            // Draw the triangle
            gl.drawArrays(gl.TRIANGLES, 0, 3);
        };
    </script>
</body>
</html>

Solution

  • the solution is to use the gl_VertexID which creates a virtual point based on the numverts you want to set. the gl_VertexID will start from 0 - numverts and will require some math formula to calculate the shape you desire.

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>WebGL Triangle</title>
      <canvas id="c"></canvas>
      <script src="https://webgl2fundamentals.org/webgl/resources/webgl-utils.js"></script>
      <script>
        // WebGL2 - No Data - Point Circle
    // from https://webgl2fundamentals.org/webgl/webgl-no-data-point-circle.html
    
    
    'use strict';
    const gl = document.querySelector('#c').getContext('webgl2');
    
    const vs = `#version 300 es
    uniform int numVerts;
    uniform vec2 resolution;
    
    #define PI radians(180.0)
    
    void main() {
    float u = float(gl_VertexID) / float(numVerts);  // goes from 0 to 1
    
    // Define the vertices of the triangle
    vec2 vertex1 = vec2(0.0, 0.0);  // Define the coordinates of the first vertex
    vec2 vertex2 = vec2(0.0, 2.0);  // Define the coordinates of the second vertex
    vec2 vertex3 = vec2(1.0, -0.7);  // Define the coordinates of the third vertex
    
    // Interpolate between the vertices to get the position of the current point
    vec2 pos = mix(mix(vertex1, vertex2, u), vertex3, u);
    
      //float angle = u * PI * 2.0;                      // goes from 0 to 2PI
      //float radius = 0.2;
      //vec2 pos = vec2(cos(angle), sin(angle)) * radius;
    
    
    
    
      gl_Position = vec4(pos, 0, 1);
      gl_PointSize = 10.0;
    }
    `;
    
    const fs = `#version 300 es
    precision highp float;
    
    out vec4 outColor;
    
    void main() {
      outColor = vec4(0, 0, 1, 1);
    }
    `;
    
    // setup GLSL program
    const program = webglUtils.createProgramFromSources(gl, [vs, fs]);
    const numVertsLoc = gl.getUniformLocation(program, 'numVerts');
    const resolutionLoc = gl.getUniformLocation(program, 'resolution');
    
    const numVerts = 3;
    
    // draw
    webglUtils.resizeCanvasToDisplaySize(gl.canvas);
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    
    gl.useProgram(program);
    
    // tell the shader the number of verts
    gl.uniform1i(numVertsLoc, numVerts);
    // tell the shader the resolution
    gl.uniform2f(resolutionLoc, gl.canvas.width, gl.canvas.height);
    
    const offset = 0;
    gl.drawArrays(gl.TRIANGLES, offset, numVerts);
    
      </script>
    </head>
    <body>
      <canvas id="c" width="400" height="400"></canvas>
      <script src="webgl-utils.js"></script>
    </body>
    </html>