javascript - WebGL:将 8 位灰度图像加载到纹理时图像无效

标签 javascript webgl

我正在尝试将从服务器下载的 8 位灰度 JPG 渲染为纹理,以便使用 WebGL 渲染。

// Pretend for the sake of example that I have passed in an argument 
// 'img' that is an Image object that I used to download the jpg.
// See the EDIT below for how this happens...

// ...also presume that I have set up my WebGL context and assigned it 
// to the variable 'gl':
// const gl = canvas.getContext('experimental-webgl');

const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);

// Set the parameters so we can render any size image.
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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

// Upload the image into the texture.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, gl.LUMINANCE, gl.UNSIGNED_BYTE, img);

此时,WebGL 打了我一巴掌,拿走了我的午饭钱:

WebGL: INVALID_VALUE: texImage2D: invalid image

我要问:你想要什么 MOAR WebGL?你为什么不快乐???

我可能错过了一些基本的东西,但是互联网上充斥着无法回答我的问题的 WebGL 内容。这里有任何 WebGL 专家可以提供建议吗?

这是图片:

8-bit Grayscale JPGs 4LYFE!

编辑:

以下是有关如何获取图像的更多详细信息。 注意:这样做的原因是我需要一个可以随机播放、取消和重新启动的下载队列,令人恶心。因此使用了 fetch、blob 和对象 URL。整个事情是深度缩放图像查看器的一部分,它应该有效地仅加载视口(viewport)中可见的图像图 block (通常会随时变化)。无论如何,这是我获取图像的方式:

// Take care of vendor prefixes:
window.URL = window.URL || window.webkitURL;

// This is where we'll assign our final product
const imageTag = new Image();

imageTag.onerror = (err) => {
  console.error('IMG ERROR:', err);
};
imageTag.onload = () => {
  // Once the image tag has loaded the blob data, clean up our object url:
  window.URL.revokeObjectURL(imageTag.src);

  // imageTag is now passed into the code above as 'img'
};

// Grab the image data as a blob
fetch(`<url_of_image>`)
  .then(res => res.blob())
  .then(blob => {
    // When we get the image data, wrap it in an object url and assign
    // it to src. The onload event won't fire until the next tick.
    imageTag.src = window.URL.createObjectURL(blob);
  });

我应该指出,我最初是使用 canvas2D API 进行渲染的,并且它能够使用 drawImage() 方法很好地绘制图像。所以我很确定图像对象加载正常。我实现 WebGL 渲染器的原因是为更大的性能增强打开大门。

感谢您的浏览!

最佳答案

好吧,聚会的人,我想出了这个(至少是一种方法)。

我永远无法开始工作的原始流程是:

  1. 以 blob 形式获取图像数据
  2. 使用 ObjectURL 能够将 blob 传递到 src 属性上的图像标记
  3. 将图像标签传递到texImage2D(旧方法签名)

对我有用的新流程是:

  1. 获取图像数据作为数组缓冲区
  2. 使用 jpeg-js 将 jpg 数据解码为 Uint8Array
  3. 将 Uint8Array 传递到 texImage2D(新方法签名)

看起来像这样:

// I am using the decode() method from jpeg-js. Passing true as a second parameter 
// causes the data to be returned wrapped in a Uint8Array. Even though the data
// was one channel going in, it's going to come out with all four (RGBA) channels.

import { decode } from 'jpeg-js';

// Like before, please presume a global gl variable to be my WebGL context.
const gl = '<my-webgl-context-that-I-set-up-elsewhere>';

fetch(`<url_of_image>`)
  .then(res => res.arrayBuffer())
  .then(buffer => {
    // When we get the image data, it's still encoded. We need to decode it
    // before we've got pixel data. We want it as a Uint8Array which will make
    // texImage2D() happy.
    const pixels = decode(buffer, true);

    // Set up a new texture where we'll capture and keep the image data
    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);

    // Set the parameters so we can render any size image.
    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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

    // Upload the image into the texture:

    // Here we are telling WebGL how many bytes each pixel will be (I think 
    // think the default is 4, but I thought that this step was important to show).
    gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4);

    // jpeg-js is kind enough to provide the dimensions of the image data in its
    // returned value. Since jpeg-js returns the data with all 4 channels, we use
    // gl.RGBA here.
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, pixels.width, pixels.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels.data);

    // Ready to draw!
  });

希望这对将来的人有用。感谢所有贡献想法和创意的人,感谢 jpeg-js 上的合作者!

关于javascript - WebGL:将 8 位灰度图像加载到纹理时图像无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47686078/

相关文章:

php - 如何改进图像抓取(使用 PHP 和 JS)以模仿 Facebook 预览器

javascript - Webpack bundling 如何减少 React 等流行库的重复下载?

webgl - 在 Three.js 中渲染具有大量对象的多个场景的最佳方式

javascript - 创建一个真正的 3D 网站

javascript - 使用 webgl 创建六 Angular 星

javascript - Angularjs Modal + 自动完成输入(附有 Plunker)

javascript - 根据元素的类显示工具提示文本

javascript - Pusher 是否允许非 ASCII (JSON) 格式的传输负载?

webgl - 调用 glDisableVertexAttribArray() 重要吗?

java - Three.js:如何将场景转换为 MPG4 视频?