gl.texImage2D适用于Image,但不适用于ImageData

时间:2018-06-03 06:59:45

标签: javascript image canvas webgl

当我使用gl.texImage2D和javascript的Image对象指定像素数据时,我有一个正确渲染的纹理。但是,如果我将Image渲染到屏幕外的画布,然后从中取出ImageData个对象,然后将其反馈给gl.texImage2D,则纹理无法正确绘制。当我检查ImageData对象时,像素数据是正确的。对于gl.texImage2D对象而言ImageImageData对象的作用可能与[0,1]对象有什么不同?

图像只是32位,每个组件8位,RGBA。我的片段着色器获取并期望这些组件为ImageData中的值。可能是因为当我传入[0,255]对象时,我的着色器现在正在let perm_image = new Image(); ... let canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); canvas.width = perm_image.width; canvas.height = perm_image.height; context.drawImage(perm_image, 0, 0); let perm_image_data = context.getImageData(0, 0, perm_image.width, perm_image.height); 范围内获取它们?我将不得不测试这个假设。无论如何,我完全失去了。

编辑:经过多次努力,我发现OpenGL和着色器管道的东西没有任何问题。我面临的问题与从Image到ImageData的转换有关。这是一些代码...

Image

我已将返回的图像数据与实际图像数据进行比较,而缓冲区的第一部分看起来是正确的,其余部分是错误的。我以前做过这个检查,但是很快就停了。

无论如何,我要去看看如何更改/修复上述代码。

最终编辑:我决定放弃。我知道没有防弹方法可以从JS _.templateSettings = { evaluate: /\<\#(.+?)\#\>/g, interpolate: /\{\{=(.+?)\}\}/g, escape: /\{\{-(.+?)\}\}/g }; 对象中获取原始的,未改变的RGBA数据,我认为发明该死的对象的人完全失败了。我要做的就是不使用PNG文件,而是使用我自己的二进制格式。

1 个答案:

答案 0 :(得分:1)

似乎适合我。也许比较一下,看看你的做法可能与众不同?

&#13;
&#13;
const img = new Image();
img.addEventListener('load', render);
img.crossOrigin = "";
img.src = "https://i.imgur.com/ZKMnXce.png";

function render() {
  const vs = `
  attribute vec4 position;
  void main() {
    gl_PointSize = 80.0;
    gl_Position = position;
  }
  `;

  const fs = `
  precision mediump float;
  uniform sampler2D tex;
  void main() {
    gl_FragColor = texture2D(tex, gl_PointCoord);
  }
  `;

  const gl = document.querySelector("canvas").getContext("webgl");
  const program = twgl.createProgram(gl, [vs, fs]);
  const positionLoc = gl.getAttribLocation(program, "position");
  
  const ctx = document.createElement("canvas").getContext("2d");
  ctx.canvas.width = img.width;
  ctx.canvas.height = img.height;
  ctx.fillStyle = '#FFF'
  ctx.drawImage(img, 0, 0);
  ctx.font = "bold 48px sans-serif";
  ctx.fillText("imageData", 10, 200);

  const imgData = ctx.getImageData(0, 0, img.width, img.height);

  ctx.drawImage(img, 0, 0);
  ctx.fillText("canvas", 10, 200);

  gl.useProgram(program);

  createTextureAndDraw(img, -.6);
  createTextureAndDraw(ctx.canvas, 0);
  createTextureAndDraw(imgData, .6);
  
  function createTextureAndDraw(src, x) {
  
    const tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    {
      const level = 0;
      const internalFormat = gl.RGBA;
      const width = 1;
      const height = 1;
      const border = 0;
      const format = gl.RGBA;
      const type = gl.UNSIGNED_BYTE;
      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
                    format, type, src);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    }
    
    gl.vertexAttrib1f(positionLoc, x);

    const primitiveType = gl.POINTS;
    const offset = 0;
    const count = 1;
    gl.drawArrays(primitiveType, offset, count);
  }
}
&#13;
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
&#13;
&#13;
&#13;

阅读您问题的更新时,您应该提出一个新问题,因为您的实际问题与您提出的问题完全无关。

首先,Canvas 始终是可预测的。这意味着它有损。

在这个答案中详细介绍了这一点:https://stackoverflow.com/a/50566789/128511

因为你要去Image(png) - &gt;画布 - &gt; ImageData然后,如果您的PNG有任何非255 alpha,那么您将丢失数据。

其次你提到伽马校正。是的,浏览器将对图像进行伽玛校正和/或应用其他颜色转换。这样,在WebGL中绘制的图像将匹配绘制到Canvas中的图像以及页面上显示的图像。

为了避免颜色转换,您需要设置gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE),告诉WebGL做任何事情来从图像中获取原始数据(这可能包括从图像开始重新解码图像&#39} ; s默认数据是浏览器在HTML中绘制图像标记所需的任何格式。

这是一个不应用颜色转换的示例。它从同一图像创建2个纹理。一旦使用默认颜色转换,一次没有。

&#13;
&#13;
const img = new Image();
img.addEventListener('load', render);
img.crossOrigin = "";
img.src = "https://cdn.rawgit.com/KhronosGroup/WebGL/8ea92581/sdk/tests/resources/small-square-with-colorspin-profile.png";

function render() {
  const vs = `
  attribute vec4 position;
  void main() {
    gl_PointSize = 130.0;
    gl_Position = position;
  }
  `;

  const fs = `
  precision mediump float;
  uniform sampler2D tex;
  void main() {
    gl_FragColor = texture2D(tex, gl_PointCoord);
  }
  `;

  const gl = document.querySelector("canvas").getContext("webgl");
  const program = twgl.createProgram(gl, [vs, fs]);
  const positionLoc = gl.getAttribLocation(program, "position");
  
  gl.useProgram(program);

  createTextureAndDraw(img, -.5, true);   // default (with COLOR CONVERSION)
  createTextureAndDraw(img,  .5, false);  // color conversion OFF
  
  function createTextureAndDraw(src, x, colorConversion) {
  
    const tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    const mode = colorConversion ? gl.BROWSER_DEFAULT_WEBGL : gl.NONE;
    gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, mode);
    {
      const level = 0;
      const internalFormat = gl.RGBA;
      const width = 1;
      const height = 1;
      const border = 0;
      const format = gl.RGBA;
      const type = gl.UNSIGNED_BYTE;
      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
                    format, type, src);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    }
    
    gl.vertexAttrib1f(positionLoc, x);

    const primitiveType = gl.POINTS;
    const offset = 0;
    const count = 1;
    gl.drawArrays(primitiveType, offset, count);
  }
}
&#13;
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
&#13;
&#13;
&#13;

注意:这是一个极端的例子,因为纹理是红色的颜色转换而蓝色没有。如果你在photoshop中打开文件,你会看到原始数据是蓝色的,但根据颜色配置文件显示为红色。

enter image description here

WebGL conformance test for this feature中有几个极端的例子可以测试你是否可以从WebGL中的PNG中获取原始数据。