Search code examples
javascriptglslwebgl

How WebGL convert floating point coordinates to clipspace?


I test this program but can understand why only max 4 points can render?

This's vertex shader program:

attribute vec4 position;
void main() {
   gl_Position = position;
   gl_PointSize = 20.0;
}

And Fragment program:

precision mediump float;
void main() {
   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

And then, i use dynamic_draw to pass data to this program using buffer, and update using bufferSubData:

gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Uint8Array([
     0, 0,
     128, 191,
     0, 0,
     128, 191,
     0, 0,
     128, 63,
     0, 0,
     128, 191,
     0, 0,
     128, 191,
     0, 0,
     128, 63,
     0, 0,
     128, 63,
     0, 0,
     128, 63
  ]));
// Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
  var size = 2;          // 2 components per iteration
  var type = gl.FLOAT;   // the data is 32bit floats
  var normalize = false; // don't normalize the data
  var stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
  var offset = 0;        // start at the beginning of the buffer
  gl.vertexAttribPointer(
      positionLocation, size, type, normalize, stride, offset);

Then, i using

gl.drawArrays(gl.POINTS, 0, 4);

max 4 points can render ? WHY ?

Link to this program: https://codepen.io/nguyendinhlam88/pen/abajaJZ

// WebGL - 2D Image
// from https://webglfundamentals.org/webgl/webgl-2d-image.html


"use strict";

function main() {
  var image = new Image();
  requestCORSIfNotSameOrigin(image, "https://webglfundamentals.org/webgl/resources/leaves.jpg")
  image.src = "https://webglfundamentals.org/webgl/resources/leaves.jpg";
  image.onload = function() {
    render(image);
  };
}

function render(image) {
  // Get A WebGL context
  /** @type {HTMLCanvasElement} */
  var canvas = document.querySelector("#canvas");
  var gl = canvas.getContext("webgl");
  if (!gl) {
    return;
  }

  // setup GLSL program
  var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-2d", "fragment-shader-2d"]);

  // look up where the vertex data needs to go.
  var positionLocation = gl.getAttribLocation(program, "position");

  var positionBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, 32, gl.DYNAMIC_DRAW);

  webglUtils.resizeCanvasToDisplaySize(gl.canvas);
  // console.log(gl.canvas.width, gl.canvas.height);
  gl.viewport(0, 0, 240, 180);
  gl.clearColor(0, 0, 0, 0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.useProgram(program);

  gl.enableVertexAttribArray(positionLocation);
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Uint8Array([
     0, 0,
     128, 191,
     0, 0,
     128, 191,
     0, 0,
     128, 63,
     0, 0,
     128, 191,
     0, 0,
     128, 191,
     0, 0,
     128, 63,
     0, 0,
     128, 63,
     0, 0,
     128, 63
  ]));

  // Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
  var size = 2;          // 2 components per iteration
  var type = gl.FLOAT;   // the data is 32bit floats
  var normalize = false; // don't normalize the data
  var stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
  var offset = 0;        // start at the beginning of the buffer
  gl.vertexAttribPointer(
      positionLocation, size, type, normalize, stride, offset);

  // Draw the rectangle.
  var primitiveType = gl.POINTS;
  var offset = 0
  var count = 4;
  gl.drawArrays(primitiveType, offset, count);
}

main();


// This is needed if the images are not on the same domain
// NOTE: The server providing the images must give CORS permissions
// in order to be able to use the image with WebGL. Most sites
// do NOT give permission.
// See: https://webglfundamentals.org/webgl/lessons/webgl-cors-permission.html
function requestCORSIfNotSameOrigin(img, url) {
  if ((new URL(url, window.location.href)).origin !== window.location.origin) {
    img.crossOrigin = "";
  }
}
@import url("https://webglfundamentals.org/webgl/resources/webgl-tutorials.css");
body {
  margin: 0;
}
canvas {
  width: 100vw;
  height: 100vh;
  display: block;
}
<canvas id="canvas"></canvas>
<!-- vertex shader -->
<script  id="vertex-shader-2d" type="x-shader/x-vertex">
attribute vec4 position;


void main() {
   gl_Position = position;
   gl_PointSize = 20.0;
}
</script>
<!-- fragment shader -->
<script  id="fragment-shader-2d" type="x-shader/x-fragment">
precision mediump float;
void main() {
   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
</script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>


Solution

  • Since there are only 4 coordinates in the buffer, only a maximum of 4 points can be drawn.

    The buffer consists only of 4 coordinates coded in bytes. Every 4 bytes form a floating point value:

    gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Uint8Array([
         0, 0, 128, 191,  // x0
         0, 0, 128, 191,  // y0
         
         0, 0, 128, 63,   // x1
         0, 0, 128, 191,  // y1
         
         0, 0, 128, 191,  // x2
         0, 0, 128, 63,   // y2
         
         0, 0, 128, 63,   // x3
         0, 0, 128, 63    // y3
      ]));
    

    This can be seen in the vertexAttribPointer specification. The size is 2 and the type is gl.FLOAT. Therefore 1 attribute consists of 2 components of type float. The buffer is always just a series of bytes. How the bytes are to be interpreted is defined in the attribute specification.