I am working on recreating an experiment similar to boiler, and I have come across a weird problem I cannot figure out. I can get the godrays to cast out, but somewhere in my occlusion pass it seems that each object is just a little bit off because there is issues with where the red objects are compared to the occlusion objects. My pictures show the example.
This is the result I get with my instanced objects:
I implemented volumetric god rays this way:
This is my rendering setup:
requestAnimationFrame(this.animate.bind(this));
if (this.params.animate) {
this.simulation.shader.uniforms.time.value = performance.now();
this.simulation.render();
(this.mesh as any).material.uniforms.curPos.value = this.simulation.front.texture;
(this.mesh as any).material.uniforms.prevPos.value = this.simulation.back.texture;
(this.occlusionMesh as any).material.uniforms.curPos.value = this.simulation.front.texture;
(this.occlusionMesh as any).material.uniforms.prevPos.value = this.simulation.back.texture;
this.simulation.shader.uniforms.init.value = 0;
}
if (this.params.postprocessing) {
// show the objects in the occlusion scene
this.camera.layers.set(this.OCCLUSION_LAYER);
// set a black background for the render
this.renderer.setClearColor(0x000000);
// render the occlusion scene and apply the volumetric light shader
this.occlusionComposer.render();
// show the objects in the lit scene
this.camera.layers.set(this.DEFAULT_LAYER);
// set a new background color
//this.renderer.setClearColor(0x000000);
// render the lit scene and blend the volumetric light effect
this.composer.render();
} else {
this.renderer.autoClear = true;
this.renderer.render(this.scene, this.camera);
}
My occlusion mesh is just a copy of my regular mesh, but it is black for the occlusion pass. The simulation just ping-pongs back and fourth between my texture and changes the x,y,z and w for the objects position and life.
Occlusion mesh:
this.occlusionMesh = new THREE.Mesh(this.geometry, new THREE.RawShaderMaterial({ uniforms: { curPos: { type: 't', value: this.posTexture }, prevPos: { type: 't', value: this.posTexture }, resolution: { type: 'v2', value: this.resolution }, color: { type: 'v3', value: new THREE.Color(0x000000) } }, vertexShader: this.materialVertexShader, fragmentShader: this.materialFragmentShader, side: THREE.DoubleSide })); this.occlusionMesh.layers.set(this.OCCLUSION_LAYER); this.scene.add(this.occlusionMesh);
Regular Mesh:
this.material = new THREE.RawShaderMaterial({ uniforms: { curPos: { type: 't', value: this.posTexture }, prevPos: { type: 't', value: this.posTexture }, resolution: { type: 'v2', value: this.resolution }, color: { type: 'v3', value: new THREE.Color(0xFF3344)} }, vertexShader: this.materialVertexShader, fragmentShader: this.materialFragmentShader, side: THREE.DoubleSide }); this.mesh = new THREE.Mesh(this.geometry, this.material); this.scene.add(this.mesh);
Geometry:
this.bufferGeometry = new THREE.BoxBufferGeometry(3., 1., 2.); this.geometry.index = this.bufferGeometry.index; (this.geometry as any).attributes.position = (this.bufferGeometry as any).attributes.position; (this.geometry as any).attributes.uv = (this.bufferGeometry as any).attributes.uv; (this.geometry as any).attributes.normal = (this.bufferGeometry as any).attributes.normal; let lookup: number[] = []; for (let i = 0; i < this.size; i++) { for (let j = 0; j < this.size; j++) { lookup.push(j / this.size); lookup.push(i / this.size); } } this.geometry.addAttribute('lookup', new THREE.InstancedBufferAttribute(new Float32Array(lookup), 2));
Texture for x,y,z and w:
// Each object has an x, y, z, and w let positions = new Float32Array(this.size * this.size * 4); for (let i = 0, l = this.size * this.size; i < l; i++) { let phi = Math.random() * 2 * Math.PI; let costheta = Math.random() * 2 - 1; let theta = Math.acos(costheta); let r = 100 - (Math.random() * 10); positions[i * 4] = r * Math.sin(theta) * Math.cos(phi); positions[i * 4 + 1] = r * Math.sin(theta) * Math.sin(phi); positions[i * 4 + 2] = r * Math.cos(theta); positions[i * 4 + 3] = Math.random() * 100; // frames life } this.posTexture = new THREE.DataTexture(positions, this.size, this.size, THREE.RGBAFormat, THREE.FloatType); this.posTexture.needsUpdate = true; this.simulationShader = new THREE.RawShaderMaterial({ uniforms: { source: { type: 't', value: this.posTexture }, seed: { type: 't', value: this.posTexture }, resolution: { type: 'v2', value: new THREE.Vector2(this.size, this.size) }, time: { type: 'f', value: 0 }, persistence: { type: 'f', value: 1. }, speed: { type: 'f', value: .05 }, spread: { type: 'f', value: .2 }, decay: { type: 'f', value: .5 }, init: { type: 'f', value: .1 } }, vertexShader: this.simVertexShader, fragmentShader: this.simFragmentShader });
Let me know if you have any ideas or if I need to include more information.