Three.js使用framebuffer作为纹理

时间:2014-02-03 17:31:49

标签: three.js fragment-shader

我使用canvas元素中的图像作为Three.js中的纹理,使用JavaScript在画布上执行图像处理,然后在纹理上调用needsUpdate()。这有效,但速度很慢。

我想在片段着色器中执行图像计算。我发现了很多几乎这样做的例子:

编辑:这是另一个:

据我了解,理想情况下,我可以使用自己的片段着色器创建一个新的帧缓冲对象,自己渲染它,并将其输出用作另一个材质片段着色器的纹理均匀。这可能吗?

编辑2:看起来我可能会问这样的事情:Shader Materials and GL Framebuffers in THREE.js ......虽然问题似乎没有得到解决。

1 个答案:

答案 0 :(得分:22)

渲染到纹理渲染到另一个场景,如上所列是相同的,并且是您想要的技术。解释:

在vanilla WebGL中,你做这种事情的方法是从头开始创建一个帧缓冲对象(FBO),将纹理绑定到它,然后使用你选择的着色器渲染它。不涉及“场景”和“相机”等概念,这是一个复杂的过程。这是一个例子:

http://learningwebgl.com/blog/?p=1786

但这也恰好是Three.js在使用相机渲染场景时所做的事情:渲染器输出到帧缓冲区,其基本用法直接进入屏幕。因此,如果您指示它渲染到新的WebGLRenderTarget,您可以使用相机看到的任何内容作为第二种材质的输入纹理。所有复杂的东西仍在发生,但在幕后,这是Three.js的美丽。 :)

所以:要复制包含单个渲染纹理的FBO的WebGL设置,如评论中所述,只需创建一个包含正交相机的新场景和一个使用所需纹理的材质的单个平面,然后渲染到使用自定义着色器的新WebGLRenderTarget:

// new render-to-texture scene
myScene = new THREE.Scene();

// you may need to modify these parameters
var renderTargetParams = {
  minFilter:THREE.LinearFilter,
  stencilBuffer:false,
  depthBuffer:false
};

myImage = THREE.ImageUtils.loadTexture( 'path/to/texture.png',
  new THREE.UVMapping(), function() { myCallbackFunction(); } );

imageWidth = myImage.image.width;
imageHeight = myImage.image.height;

// create buffer
myTexture = new THREE.WebGLRenderTarget( width, height, renderTargetParams );

// custom RTT materials
myUniforms = {
  colorMap: { type: "t", value: myImage },
};
myTextureMat = new THREE.ShaderMaterial({
  uniforms: myUniforms,
  vertexShader: document.getElementById( 'my_custom_vs' ).textContent,
  fragmentShader: document.getElementById( 'my_custom_fs' ).textContent
});

// Setup render-to-texture scene
myCamera = new THREE.OrthographicCamera( imageWidth / - 2,
  imageWidth / 2,
  imageHeight / 2,
  imageHeight / - 2, -10000, 10000 );

var myTextureGeo = new THREE.PlaneGeometry( imageWidth, imageHeight );
myTextureMesh = new THREE.Mesh( myTextureGeo, myTextureMat );
myTextureMesh.position.z = -100;
myScene.add( myTextureMesh );

renderer.render( myScene, myCamera, myTexture, true );

一旦渲染了新场景,myTexture将可用作主场景中另一种材质的纹理。请注意,您可能希望在render调用中使用回调函数触发第一个loadTexture(),以便在源图像加载之前不会尝试渲染。