Three.js使用帧缓冲区作为纹理

Three.js使用帧缓冲区作为纹理,three.js,fragment-shader,Three.js,Fragment Shader,我使用canvas元素中的图像作为Three.js中的纹理,使用JavaScript在画布上执行图像操作,然后在纹理上调用needsUpdate()。这是可行的,但速度很慢 我想在片段着色器中执行图像计算。我发现了许多几乎可以做到这一点的例子: 着色器材质:此示例显示在片段着色器中执行的图像操作,但该着色器用作整个材质的片段着色器。我只想在纹理上使用着色器,然后将纹理用作第二种材质的组件 渲染到纹理:这显示将整个场景渲染到WebGLRenderTarget,并将其用作材质中的纹理。我只想预处理

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

我想在片段着色器中执行图像计算。我发现了许多几乎可以做到这一点的例子:

  • 着色器材质:此示例显示在片段着色器中执行的图像操作,但该着色器用作整个材质的片段着色器。我只想在纹理上使用着色器,然后将纹理用作第二种材质的组件


  • 渲染到纹理:这显示将整个场景渲染到WebGLRenderTarget,并将其用作材质中的纹理。我只想预处理图像,而不是渲染整个场景

  • Effects composer:这显示将着色器作为后期处理应用于整个场景

编辑:这里是另一个:

  • 渲染到另一个场景:中引用的此示例使用第二个场景及其自己的正交摄影机将动态纹理渲染到WebGLRenderTarget,然后将其用作主场景中的纹理。我想这是上面列出的第一个“渲染到纹理”示例的特例,可能对我有用,但似乎过于复杂
据我所知,理想情况下,我能够使用自己的片段着色器创建一个新的帧缓冲区对象,自己进行渲染,并将其输出用作其他材质片段着色器的统一纹理。这可能吗


编辑2:看起来我可能在问类似的问题:……尽管问题似乎还没有解决。

渲染到纹理渲染到另一个场景如上所述是同一回事,也是您想要的技术。解释:

在vanilla WebGL中,执行此类操作的方法是从头创建帧缓冲区对象(FBO),将纹理绑定到该对象,然后使用您选择的着色器进行渲染。像“场景”和“相机”这样的概念并不涉及,这是一个复杂的过程。下面是一个例子:

但这也恰好是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
将可用作主场景中其他材质的纹理。请注意,您可能希望使用
loadTexture()
调用中的回调函数触发第一个
render
,以便在加载源图像之前它不会尝试渲染。

在three.js的框架中,您想要做的是渲染(包含单个平面和正交摄影机的场景)使用自定义的
ShaderMaterial
创建纹理,然后将该纹理作为第二个
ShaderMaterial
的统一纹理;它有一些非常有用的链接,可以链接到好的例子。正交相机的近平面不应该在相机后面;它应该是一个正值。另外,什么是
3.RenderTargetWrapping
?在这种情况下,您使用
type=THREE.FloatType
的原因是什么?真的,没有冒犯的意思;谢谢你的帮助。我不知道那些台词是干什么用的。它们是退化的,从祖先那里继承而来,在编程和进化中,不明显抑制生存能力的代码倾向于保留我将编辑该示例,以减少对后代的混淆。