javascript - 为什么这样得不到对应的像素

标签 javascript webgl webgl2

画完三 Angular 形后,我想使用readPixels方法获取像素信息,但是用下面的代码无法获取。

const gl = document.querySelector("canvas").getContext("webgl2", {
  preserveDrawingBuffer: true
});

render();
read(); // read in other event

function render() {
  const fragment_center = `#version 300 es
    precision highp float;
    in vec3 HSV;
    out vec4 fragColor;

    vec3 hsv2rgb(vec3 c) {
      vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
      vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
      return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
    }

    void main() {
      vec3 color = hsv2rgb(HSV);
      fragColor = vec4(color, 1.0);
    }
  `;

  const vertex_center = `#version 300 es
    precision highp float;
    in vec2 position;
    in vec2 offset;
    in float hue;
    out vec3 HSV;

    void main() {
      float x = offset.x + position.x + 0.15;
      float y = offset.y + position.y + 0.3;
      HSV = vec3(hue, y, x);
      gl_Position = vec4(position, 1.0, 1.0);
    }
    `;
  const program = initProgram(gl, vertex_center, fragment_center);
  const radius = 1;
  const x1 = Math.cos((30 / 180) * Math.PI) * radius;
  const y1 = Math.sin((30 / 180) * Math.PI) * radius;
  const v_triangle = new Float32Array([0, radius, x1, -y1, -x1, -y1]);
  let buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, v_triangle, gl.STATIC_DRAW);
  let gl_position = gl.getAttribLocation(program, "position");
  gl.vertexAttribPointer(gl_position, 2, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(gl_position);
  
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, v_triangle.length / 2);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0.5, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(" ");
  document.body.appendChild(elem);
}

function initProgram(gl, v, f) {
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vertexShader, v);
  gl.compileShader(vertexShader);
  let status = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS);
  if (!status) alert(gl.getShaderInfoLog(vertexShader));

  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fragmentShader, f);
  gl.compileShader(fragmentShader);
  status = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS);
  if (!status) alert(gl.getShaderInfoLog(fragmentShader));

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

  return program;
}
<canvas></canvas>

上面的代码没有正确获取对应的像素。

但是,如果我将实现更改为不使用drawArrays并使用clearColor之类的方法,我就可以获得像素。

const gl = document.querySelector("canvas").getContext("webgl");

render();
read();  // read in same event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}
<canvas></canvas>

最佳答案

gl.readPixels 的坐标是窗口(帧缓冲区)坐标。这些坐标是整数,左上角是 (0, 0)。您实际上是从帧缓冲区的左上角读取像素。当您绘制三 Angular 形时,该片段不会改变并包含清晰的颜色。从不同位置读取片段:

gl.readPixels(0, 0.5, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 像素);

gl.readPixels(200, 100, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);

const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl2", {
  preserveDrawingBuffer: true
});

render();
read(); // read in other event

function render() {
  const fragment_center = `#version 300 es
    precision highp float;
    in vec3 HSV;
    out vec4 fragColor;

    vec3 hsv2rgb(vec3 c) {
      vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
      vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
      return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
    }

    void main() {
      vec3 color = hsv2rgb(HSV);
      fragColor = vec4(color, 1.0);
    }
  `;

  const vertex_center = `#version 300 es
    precision highp float;
    in vec2 position;
    in vec2 offset;
    in float hue;
    out vec3 HSV;

    void main() {
      float x = offset.x + position.x + 0.15;
      float y = offset.y + position.y + 0.3;
      HSV = vec3(hue, y, x);
      gl_Position = vec4(position, 1.0, 1.0);
    }
    `;
  const program = initProgram(gl, vertex_center, fragment_center);
  const radius = 1;
  const x1 = Math.cos((30 / 180) * Math.PI) * radius;
  const y1 = Math.sin((30 / 180) * Math.PI) * radius;
  const v_triangle = new Float32Array([0, radius, x1, -y1, -x1, -y1]);
  let buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, v_triangle, gl.STATIC_DRAW);
  let gl_position = gl.getAttribLocation(program, "position");
  gl.vertexAttribPointer(gl_position, 2, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(gl_position);
  
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, v_triangle.length / 2);
}

function read() {
  const pixel = new Uint8Array(4);
  const x = canvas.width/2;
  const y = canvas.height/2;
  gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log('(' + x + ', ' + y + '): ' + pixel);
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(" ");
  document.body.appendChild(elem);
}

function initProgram(gl, v, f) {
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vertexShader, v);
  gl.compileShader(vertexShader);
  let status = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS);
  if (!status) alert(gl.getShaderInfoLog(vertexShader));

  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fragmentShader, f);
  gl.compileShader(fragmentShader);
  status = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS);
  if (!status) alert(gl.getShaderInfoLog(fragmentShader));

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

  return program;
}
<canvas></canvas>

关于javascript - 为什么这样得不到对应的像素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74739176/

相关文章:

javascript - Vuetify.js 数据表固定标题通过 CSS 滚动

javascript - Vanilla JS 想在每次点击时创建一个新的进度条?

javascript - 从 2018 年开始在 WebGL 中加载着色器?

javascript - THREE.OrbitControl 中的 EPS 是什么?

webgl - 在 WebGL 中调试

javascript - 创建高效的早期实例剪辑 WebGL2 顶点着色器

javascript - jquery sortable 除了这个

javascript - 在 Microsoft 平板电脑/触摸屏显示器上使用 mozilla firefox 禁用默认捏合缩放

javascript - WebGl 片段着色器 channel 数组

javascript - GLSL 中阴影光线的平滑阴影无法正常工作