I'm trying to generate a textue using a Three.WebGLRenderTarget and then access it in a fragment shader in the next stage.
The idea is to run the first stage once to generate a complex and expensive SDF map and then access it in later stages as needed.
At the moment I can generate the test texture if I send it straight to the screen but when i send it to a texture and try to read it I just get a black screen.
I'm guessing it's something simple and appreciate any help.
The test code:
import * as Three from 'three'
const renderer = new Three.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
const buffer = new Three.WebGLRenderTarget(window.innerWidth, window.innerHeight, {
minFilter: Three.LinearFilter,
magFilter: Three.LinearFilter,
stencilBuffer: false,
depthBuffer: false,
type: Three.UnsignedByteType
});
buffer.texture.needsUpdate = false;
const camera = new Three.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
camera.position.set(0, 0, 1000);
//Buffer scene
const bufferScene = new Three.Scene()
const bufferQuad = new Three.Mesh(
new Three.PlaneGeometry(2, 2),
new Three.ShaderMaterial({
uniforms: {
u_resolution: { value: new Three.Vector2(window.innerWidth, window.innerHeight) }
},
blending: Three.NoBlending,
vertexShader: vertShader,
fragmentShader: bufferShader,
depthWrite: false,
depthTest: false,
})
);
bufferScene.add(bufferQuad);
//Screen Scene
const screenScene = new Three.Scene()
const screenQuad = new Three.Mesh(
new Three.PlaneGeometry(2, 2),
new Three.ShaderMaterial({
uniforms: {
buffer: { value: buffer.texture }
},
blending: Three.NoBlending,
vertexShader: vertShader,
fragmentShader: screenShader,
depthWrite: false,
depthTest: false,
})
);
screenScene.add(screenQuad);
window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
render(screenScene)
}
function loop() {
requestAnimationFrame(loop)
render(screenScene)
}
function render(scene) {
renderer.render(scene, camera)
}
function main() {
render(bufferScene);
loop();
}
main()
And the shaders
const vertShader = `
varying vec2 vUv;
void main(){
vUv=position.xy*.5+.5;
gl_Position=vec4(position.xy,1.,1.);
}`;
const bufferShader = `
precision highp float;
uniform vec2 u_resolution;
void main(){
vec2 uv=gl_FragCoord.xy/u_resolution.xy;
gl_FragColor=vec4(uv,0.,1.);
}`;
const screenShader = `
precision highp float;
uniform sampler2D buffer;
varying vec2 vUv;
void main(){
vec4 texel=texture2D(buffer,vUv);
gl_FragColor=texel;
}`;
It seems you set the render target in the renderer. Try to rewrite your main()
function like so:
function main() {
renderer.setRenderTarget(buffer);
render(bufferScene);
renderer.setRenderTarget(null);
loop();
}
Full code:
const vertShader = `
varying vec2 vUv;
void main(){
vUv=position.xy*.5+.5;
gl_Position=vec4(position.xy,1.,1.);
}`;
const bufferShader = `
precision highp float;
uniform vec2 u_resolution;
void main(){
vec2 uv=gl_FragCoord.xy/u_resolution.xy;
gl_FragColor=vec4(uv,0.,1.);
}`;
const screenShader = `
precision highp float;
uniform sampler2D buffer;
varying vec2 vUv;
void main(){
vec4 texel=texture2D(buffer,vUv);
gl_FragColor=texel;
}`;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
const buffer = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
stencilBuffer: false,
depthBuffer: false,
type: THREE.UnsignedByteType
});
buffer.texture.needsUpdate = false;
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
camera.position.set(0, 0, 1000);
//Buffer scene
const bufferScene = new THREE.Scene()
const bufferQuad = new THREE.Mesh(
new THREE.PlaneGeometry(2, 2),
new THREE.ShaderMaterial({
uniforms: {
u_resolution: {
value: new THREE.Vector2(window.innerWidth, window.innerHeight)
}
},
blending: THREE.NoBlending,
vertexShader: vertShader,
fragmentShader: bufferShader,
depthWrite: false,
depthTest: false,
})
);
bufferScene.add(bufferQuad);
//Screen Scene
const screenScene = new THREE.Scene()
const screenQuad = new THREE.Mesh(
new THREE.PlaneGeometry(2, 2),
new THREE.ShaderMaterial({
uniforms: {
buffer: {
value: buffer.texture
}
},
blending: THREE.NoBlending,
vertexShader: vertShader,
fragmentShader: screenShader,
depthWrite: false,
depthTest: false,
})
);
screenScene.add(screenQuad);
window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
render(screenScene)
}
function loop() {
requestAnimationFrame(loop)
render(screenScene)
}
function render(scene) {
renderer.render(scene, camera)
}
function main() {
renderer.setRenderTarget(buffer);
render(bufferScene);
renderer.setRenderTarget(null);
loop();
}
main()
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.145/build/three.min.js"></script>