Reusing EffectsComposer result - three.js

I have an effectsComposer creating a result that is heavy in white.
var composer = new THREE.EffectComposer(renderer);
var renderPass = new THREE.RenderPass(shaderHeavyScene, camera);
composer.render(delta)
In the same project I have a material and scene with with a second image loaded into it.
When I replace: composer.render(delta);
with: renderer.render( secondImageScene, camera );
I can see my secondary image loaded into the three.js canvas.
My plan was to multiply the white heavy image of effectsComposer over the secondImageScene. (Revealing secondImageScene through the white)
My question is this: How would I go about multiplying the end result of the effectsComposer overtop of secondImageScene?

Use another pass that has input of two textures that were rendered in the previous passes, that multiplies them.

Related

Three.js - Stencil only on certain objects

I'm looking into making kind of a portal effect using Three.js.
The main idea is to be able to see through multiple windows another Scene.
Exactly like in this example :
https://www.ronja-tutorials.com/post/022-stencil-buffers/ (See gif in article, too big to upload here)
I found an exact example of what i'm trying to do using three.js.
Here is the link :
https://sites.google.com/site/cgwith3js/home/masking-with-stencil
The fiddle was not working but I changed it to make it work :
http://jsfiddle.net/yzhreu6p/23/
scene = new THREE.Scene();
sceneStencil = new THREE.Scene();
...
scene.add(box); // red one
...
function animate() {
requestAnimationFrame(animate);
renderer.clear();
// animate the box
box.position.x = Math.cos(clock.getElapsedTime()) * 10;
var gl = renderer.getContext();
// enable stencil test
gl.enable(gl.STENCIL_TEST);
//renderer.state.setStencilTest( true );
// config the stencil buffer to collect data for testing
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE);
// render shape for stencil test
renderer.render(sceneStencil, camera);
// set stencil buffer for testing
gl.stencilFunc(gl.EQUAL, 1, 0xff);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
// render actual scene
renderer.render(scene, camera);
// disable stencil test
gl.disable(gl.STENCIL_TEST);
}
Then I reuse the code in my project where I have kind of a town with buildings, and the hidden scene has a nyan cat textured box.
The problem I'm having is that the planes are disappearing when a building is behind and more serious problem, when there are buildings back the nyan cat texture, we see the texture in the building.
To better explain here is an image
I'm looking for a solution where the images are not visible inside the building, I found people that are talking about stencilMask but it's new for me.
Do I need to create another scene to make it work independently ?
If someone can help me, thank you for reading.

Super sample antialiasing with threejs

I want to render my scene at twice the resolution of my canvas and then downscale it before displaying it. How would I do that using threejs?
for me the best way to have a perfect AA with not too much work (see the code below)
ps :if you increase more than 2 its start to be too sharpen
renderer = new THREE.WebGLRenderer({antialiasing:true});
renderer.setPixelRatio( window.devicePixelRatio * 1.5 );
This is my solution. The source comments should explain what's going on. Setup (init):
var renderer;
var composer;
var renderModel;
var effectCopy;
renderer = new THREE.WebGLRenderer({canvas: canvas});
// Disable autoclear, we do this manually in our animation loop.
renderer.autoClear = false;
// Double resolution (twice the size of the canvas)
var sampleRatio = 2;
// This render pass will render the big result.
renderModel = new THREE.RenderPass(scene, camera);
// Shader to copy result from renderModel to the canvas
effectCopy = new THREE.ShaderPass(THREE.CopyShader);
effectCopy.renderToScreen = true;
// The composer will compose a result for the actual drawing canvas.
composer = new THREE.EffectComposer(renderer);
composer.setSize(canvasWidth * sampleRatio, canvasHeight * sampleRatio);
// Add passes to the composer.
composer.addPass(renderModel);
composer.addPass(effectCopy);
Change your animation loop to:
// Manually clear you canvas.
renderer.clear();
// Tell the composer to produce an image for us. It will provide our renderer with the result.
composer.render();
Note: EffectComposer, RenderPass, ShaderPass and CopyShader are not part of the default three.js file. You have to include them in addition to three.js. At the time of writing they can be found in the threejs project under the examples folder:
/examples/js/postprocessing/EffectComposer.js
/examples/js/postprocessing/RenderPass.js
/examples/js/postprocessing/ShaderPass.js
/examples/js/shaders/CopyShader.js
Here's how you might be able to work it out: In your three.js initialization code, when you create your renderer, make it double the dimensions of your primary canvas, and set it to render to a secondary, hidden canvas element that is twice as large as your primary canvas. Perform the necessary image manipulation on the secondary canvas, and then display the result on the primary canvas.

Why does the lighting on my walls look funny? Three.js

In my game that uses Three.js (r52) I'm having some trouble getting the lighting right.
This dungeon level uses simple cuboids as the walls and the roof. For some reason the lighting is bright at the beginning of each mesh, but then fades to dark towards the other side.
Notice that the floor doesn't have artifacts, this is because it is one huge quad.
The light used is a PointLight. The materials for my meshes are simply created like this:
var texture = new THREE.Texture( image,
new THREE.UVMapping(),
THREE.RepeatWrapping,
THREE.RepeatWrapping,
THREE.NearestFilter,
THREE.NearestMipMapLinearFilter );
return new THREE.MeshLambertMaterial({
map : texture
});
The cuboids are exported OBJ models from 3ds max, converted using gw::OBJ-exporter. These are my export settings:
Any ideas?
Apparently you hit the same issue as in this thread: https://github.com/mrdoob/three.js/issues/1258
You need to use something like material.shading = THREE.FlatShading;

Drawing UI elements directly to the WebGL area with Three.js

In Three.js, is it possible to draw directly to the WebGL area (for a heads-up display or UI elements, for example) the way you could with a regular HTML5 canvas element?
If so, how can you get the context and what drawing commands are available?
If not, is there another way to accomplish this, through other Three.js or WebGL-specific drawing commands that would cooperate with Three.js?
My backup plan is to use HTML divs as overlays, but I think there should be a better solution.
Thanks!
You can't draw directly to the WebGL canvas in the same way you do with with regular canvas. However, there are other methods, e.g.
Draw to a hidden 2D canvas as usual and transfer that to WebGL by using it as a texture to a quad
Draw images using texture mapped quads (e.g. frames of your health box)
Draw paths (and shapes) by putting their vertices to a VBO and draw that with the appropriate polygon type
Draw text by using a bitmap font (basically textured quads) or real geometry (three.js has examples and helpers for this)
Using these usually means setting up a an orthographic camera.
However, all this is quite a bit of work and e.g. drawing text with real geometry can be expensive. If you can make do with HTML divs with CSS styling, you should use them as it's very quick to set up. Also, drawing over the WebGL canvas, perhaps using transparency, should be a strong hint to the browser to GPU accelerate its div drawing if it doesn't already accelerate everything.
Also remember that you can achieve quite much with CSS3, e.g. rounded corners, alpha transparency, even 3d perspective transformations as demonstrated by Anton's link in the question's comment.
I had exactly the same issue. I was trying to create a HUD (Head-up display) without DOM and I ended up creating this solution:
I created a separate scene with orthographic camera.
I created a canvas element and used 2D drawing primitives to render my graphics.
Then I created an plane fitting the whole screen and used 2D canvas element as a texture.
I rendered that secondary scene on top of the original scene
That's how the HUD code looks like:
// We will use 2D canvas element to render our HUD.
var hudCanvas = document.createElement('canvas');
// Again, set dimensions to fit the screen.
hudCanvas.width = width;
hudCanvas.height = height;
// Get 2D context and draw something supercool.
var hudBitmap = hudCanvas.getContext('2d');
hudBitmap.font = "Normal 40px Arial";
hudBitmap.textAlign = 'center';
hudBitmap.fillStyle = "rgba(245,245,245,0.75)";
hudBitmap.fillText('Initializing...', width / 2, height / 2);
// Create the camera and set the viewport to match the screen dimensions.
var cameraHUD = new THREE.OrthographicCamera(-width/2, width/2, height/2, -height/2, 0, 30 );
// Create also a custom scene for HUD.
sceneHUD = new THREE.Scene();
// Create texture from rendered graphics.
var hudTexture = new THREE.Texture(hudCanvas)
hudTexture.needsUpdate = true;
// Create HUD material.
var material = new THREE.MeshBasicMaterial( {map: hudTexture} );
material.transparent = true;
// Create plane to render the HUD. This plane fill the whole screen.
var planeGeometry = new THREE.PlaneGeometry( width, height );
var plane = new THREE.Mesh( planeGeometry, material );
sceneHUD.add( plane );
And that's what I added to my render loop:
// Render HUD on top of the scene.
renderer.render(sceneHUD, cameraHUD);
You can play with the full source code here:
http://codepen.io/jaamo/pen/MaOGZV
And read more about the implementation on my blog:
http://www.evermade.fi/pure-three-js-hud/

How to change the zOrder of object with Threejs?

I made a scene using the webgl renderer where I put multiple 3D objects that I can select and move. However when an object is selected, I'd like to draw its axes. No problem with drawing the lines to the center of the object but I'd like them to appear in front of anything else on the scene so that they are visible even if other objects are in front - Like in Blender.
I tried to play with the renderDepth param but I don't think I understood how to use it and I didn't get any result.
Thank you for your help.
If you want some objects to render "on top", or "in front", one trick is to create two scenes -- the first scene is your regular scene, and the second scene contains the objects that you want to have on top.
First, set
renderer.autoClear = false;
Then create two scenes
var scene = new THREE.Scene();
var scene2 = new THREE.Scene();
Add your objects to the first scene as usual, and add the objects you want to have "on top" to the second scene.
Then, in your render() function, do this:
renderer.clear();
renderer.render( scene, camera );
renderer.clearDepth();
renderer.render( scene2, camera );
This will render the first scene, clear the depth buffer, and then render the second scene on top.
three.js r.142

Resources