我使用canvas元素中的图像作为Three.js中的纹理,使用JavaScript在画布上执行图像处理,然后在纹理上调用needsUpdate()。这有效,但速度很慢。
我想在片段着色器中执行图像计算。我发现了很多几乎这样做的例子:
着色器材质:http://mrdoob.github.io/three.js/examples/webgl_shader2.html此示例显示在片段着色器中执行的图像处理,但该着色器用作整个材质的片段着色器。我只想在纹理上使用着色器,然后将纹理用作第二种材质的组件。
渲染到纹理:https://threejsdoc.appspot.com/doc/three.js/examples/webgl_rtt.html这表示将整个场景渲染到WebGLRenderTarget并将其用作材质中的纹理。我只想预处理图像,而不是渲染整个场景。
效果作曲家:http://www.airtightinteractive.com/demos/js/shaders/preview/这表示将着色器应用为整个场景的后期处理。
编辑:这是另一个:
据我了解,理想情况下,我可以使用自己的片段着色器创建一个新的帧缓冲对象,自己渲染它,并将其输出用作另一个材质片段着色器的纹理均匀。这可能吗?
编辑2:看起来我可能会问这样的事情:Shader Materials and GL Framebuffers in THREE.js ......虽然问题似乎没有得到解决。
答案 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()
,以便在源图像加载之前不会尝试渲染。