Search code examples
webglslwebglwebgl2

Why isn't this drawing a triangle?


I don't know why my WebGL code is not drawing a simple triangle on the screen and I'm not sure how to debug it. The shaders are able to compile so I believe that's not the problem.

main.js:

const canvas = document.querySelector("#gl-canvas")
const gl = canvas.getContext('webgl2')

const consoleShaderCompilationErrors = (name, shader) => {
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        console.log(`${name} debug:`, gl.getShaderInfoLog(shader))
    }
}

const vertexData = [
    0, 0,
    -0.5, 0.5,
    0.5, 0.5
]

const vertexDataBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, vertexDataBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW)


const vertexShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertexShader, `
    attribute vec3 position;

    void main() {
        gl_Position = vec4(position, 1);
    }

`)
gl.compileShader(vertexShader)
consoleShaderCompilationErrors("vertexShader", vertexShader)

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragmentShader, `
    void main() {
        gl_FragColor = vec4(1, 1, 1, 1);
    }
`)
gl.compileShader(fragmentShader)
consoleShaderCompilationErrors("fragmentShader", fragmentShader)

const program = gl.createProgram()
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.linkProgram(program)
gl.useProgram(program)

const positionLocation = gl.getAttribLocation(program, "position")
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0)
gl.enableVertexAttribArray(positionLocation)


gl.drawArrays(gl.LINES, 0, 3)

index.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Prod WebGL</title>
    <style>
        #gl-canvas {
            border: 1px solid black;
        }
    </style>
    <script src="./main.js" defer></script>
</head>
<body>
    <canvas id="gl-canvas" width="400" height="400"></canvas>
</body>
</html>

Can you point me in the right direction? I have been trying to figure out the problems for hours now...


Solution

  • Use gl.LINE_LOOP instead of gl.LINES:

    gl.drawArrays(gl.LINES, 0, 3)

    gl.drawArrays(gl.LINE_LOOP, 0, 3)
    

    gl.LINES is for line segments, where 2 vertices define a line. gl.LINE_LOOP is for a line strip with a connection from the last to the first vertex. See Primitives.


    You need to create a Vertex Array Object when you using a WebGL 2.0 context:

    let vao = gl.createVertexArray();
    gl.bindVertexArray(vao);
    const vertexDataBuffer = gl.createBuffer()
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexDataBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW)
    

    Actually you are drawing a white rectangle on a white background. Change the color in the fragment shader:

    void main() {
        gl_FragColor = vec4(1, 0, 0, 1);
    }
    

    const canvas = document.querySelector("#gl-canvas")
    const gl = canvas.getContext('webgl2')
    
    const consoleShaderCompilationErrors = (name, shader) => {
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
            console.log(`${name} debug:`, gl.getShaderInfoLog(shader))
        }
    }
    
    const vertexData = [
        0, 0,
        -0.5, 0.5,
        0.5, 0.5
    ]
    
    let vao = gl.createVertexArray();
    gl.bindVertexArray(vao);
    const vertexDataBuffer = gl.createBuffer()
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexDataBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW)
    
    
    const vertexShader = gl.createShader(gl.VERTEX_SHADER)
    gl.shaderSource(vertexShader, `
        attribute vec3 position;
    
        void main() {
            gl_Position = vec4(position, 1);
        }
    
    `)
    gl.compileShader(vertexShader)
    consoleShaderCompilationErrors("vertexShader", vertexShader)
    
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
    gl.shaderSource(fragmentShader, `
        void main() {
            gl_FragColor = vec4(1, 0, 0, 1);
        }
    `)
    gl.compileShader(fragmentShader)
    consoleShaderCompilationErrors("fragmentShader", fragmentShader)
    
    const program = gl.createProgram()
    gl.attachShader(program, vertexShader)
    gl.attachShader(program, fragmentShader)
    gl.linkProgram(program)
    gl.useProgram(program)
    
    const positionLocation = gl.getAttribLocation(program, "position")
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0)
    gl.enableVertexAttribArray(positionLocation)
    
    gl.drawArrays(gl.LINE_LOOP, 0, 3)
    #gl-canvas {
        border: 1px solid black;
    }
    <canvas id="gl-canvas" width="400" height="400"></canvas>