【问题标题】:Use WebGL texture as a Three.js Texture map使用 WebGL 纹理作为 Three.js 纹理贴图
【发布时间】:2019-07-31 15:05:30
【问题描述】:

我有一个平面场景,它应该使用 WebGL 纹理(使用 gl.createTexture() 创建)作为材质贴图。基本上,如何使用这个纹理并不重要,我只需要找到一种方法将它传递给具有一定制服的ShaderMaterial。 WebGL 纹理每帧都会更新。

纹理在其他画布元素的上下文中呈现,并且可以在该上下文中使用,如下所示:

var imageLocation = gl.getUniformLocation(program, "u_image");
gl.uniform1i(imageLocation, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, targetTexture1);

我已经尝试过this solution。但似乎THREE.Texture() 没有从原始 WebGL 纹理中获取数据。

【问题讨论】:

  • @Rabbid76 当然,我可以使用 CanvasTexture 从 WebGL 绘制纹理,而不是使用画布数据创建 three.js 纹理。或者使用 DataTexture 并每帧更新数据。第一个解决方案显然会很慢,第二个可能会更快。我想做的是将WebGL纹理(不是THREE.Texture())传递给ShaderMaterial。我的问题现在够清楚了吗?
  • 我猜这是不可能的。为什么不首先使用三个纹理包装器?

标签: javascript three.js webgl


【解决方案1】:

如果您深入了解the source,这将从 r103 开始​​工作。当然,不能保证它会在将来起作用,但是nothing in three is guaranteed to work in the future

首先创建一个Texture 然后调用forceTextureInitialization 强制Three.js 初始化纹理。

  const forceTextureInitialization = function() {
    const material = new THREE.MeshBasicMaterial();
    const geometry = new THREE.PlaneBufferGeometry();
    const scene = new THREE.Scene();
    scene.add(new THREE.Mesh(geometry, material));
    const camera = new THREE.Camera();

    return function forceTextureInitialization(texture) {
      material.map = texture;
      renderer.render(scene, camera);
    };
  }();

然后像这样用你自己的替换 Texture 的 WebGL 纹理

const texProps = renderer.properties.get(someTexture);
texProps.__webglTexture = someGLTexture;

例子:

'use strict';

/* global THREE */

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({
    canvas: canvas
  });
  
  const fov = 75;
  const aspect = 2; // the canvas default
  const near = 0.1;
  const far = 5;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 2;

  const scene = new THREE.Scene();

  const boxWidth = 1;
  const boxHeight = 1;
  const boxDepth = 1;
  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
  
  const forceTextureInitialization = function() {
    const material = new THREE.MeshBasicMaterial();
    const geometry = new THREE.PlaneBufferGeometry();
    const scene = new THREE.Scene();
    scene.add(new THREE.Mesh(geometry, material));
    const camera = new THREE.Camera();

    return function forceTextureInitialization(texture) {
      material.map = texture;
      renderer.render(scene, camera);
    };
  }();
  
  const cubes = []; // just an array we can use to rotate the cubes

  {
    const gl = renderer.getContext();
    const glTex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, glTex);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0,
        gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([
          255, 0, 0, 255,
          0, 255, 0, 255,
          0, 0, 255, 255,
          255, 255, 0, 255,
        ]));
    gl.generateMipmap(gl.TEXTURE_2D);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  
    const texture = new THREE.Texture();
    forceTextureInitialization(texture);
    const texProps = renderer.properties.get(texture);
    texProps.__webglTexture = glTex;
    
    const material = new THREE.MeshBasicMaterial({
      map: texture,
    });
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    cubes.push(cube); // add to our list of cubes to rotate
  }

  function render(time) {
    time *= 0.001;

    cubes.forEach((cube, ndx) => {
      const speed = .2 + ndx * .1;
      const rot = time * speed;
      cube.rotation.x = rot;
      cube.rotation.y = rot;
    });

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
<canvas id="c"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/103/three.min.js"></script>

当然,除了使用自己的纹理之外,您还可以使用 Texture 已经在使用的纹理,然后使用 WebGL 对其进行操作

【讨论】:

  • 有趣,这暴露为.__webglTexture,并非所有内部都是:(
  • 问题是 gl.createTexture() 是在其他上下文中创建的:bindTexture: object not from this context。我决定使用 gl.readPixelsTHREE.DataTexture 但解析 1024x1024 纹理需要 3-4 毫秒。
  • 无法使用 WebGL 跨上下文共享纹理。在three.js 中,您可以使用CanvasTexture,这可能比使用gl.readPixels 更快。你也可以考虑使用virtual webgl contexts
  • 这仍然适用于 r136
猜你喜欢
  • 2014-04-02
  • 1970-01-01
  • 2014-05-25
  • 2014-05-31
  • 1970-01-01
  • 1970-01-01
  • 2016-08-28
  • 1970-01-01
  • 2014-08-07
相关资源
最近更新 更多