I am trying to add a glowing effect to my scene. As far as I know the best way to do is with the a bloom filter using the EffectComposer. Unfortunately using the EffectComposer negates the beautiful anti-aliasing that comes with the renderer. I added a SSAARenderPass but it causes banding even with unbiased set to true, and sampleLevel to 32. See attached pictures below.
I ran across this discussion dealing with a similiar issue: https://discourse.threejs.org/t/effect-composer-gamma-output-difference/12039/23 and I believe I integrated the discussed solution, by explicitly creating a RenderTarget for the EffectComposer that has type set to THREE.FloatType. This definitely helped, but I still have some pretty noticeable banding.
How can I have a glowing effect and preserve a clean render without aliasing or banding?
const pixelRatio = renderer.getPixelRatio();
const renderScene = new RenderPass( scene, camera );
const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
bloomPass.threshold = 0.9;
bloomPass.strength = 1.5;
bloomPass.radius = 0.15;
var ssaaRenderPass = new SSAARenderPass( scene, camera );
ssaaRenderPass.sampleLevel = 32;
ssaaRenderPass.unbiased = true;
var adaptToneMappingPass = new AdaptiveToneMappingPass(true, 256);
var gammaCorrectionPass = new ShaderPass( GammaCorrectionShader );
var renderTarget = new THREE.WebGLRenderTarget( window.innerWidth * pixelRatio, window.innerHeight * pixelRatio,
{
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
stencilBuffer: false,
type: THREE.FloatType
});
renderTarget.texture.name = 'EffectComposer.rt1';
composer = new EffectComposer(renderer, renderTarget);
composer.addPass(renderScene);
composer.addPass(ssaaRenderPass); //Seems to be better than fxaa but has terrible banding
composer.addPass(adaptToneMappingPass);
composer.addPass(bloomPass);
composer.addPass(gammaCorrectionPass);
This is with no SSAA or Bloom. No banding but terrible aliasing
This is with Bloom but no SSAA. No banding in the background, though there is in the bloom effect
This is with both Bloom and SSAA. The aliasing is better but the banding in the background and bloom is bad
I believe you're running into the exact issue that this demo solves. When unbiased = false you see color banding:
but when unbiased = true, the banding is fixed:
Should be a simple fix by setting ssaaRenderPass.unbiased = true;
Related
so I have a school project where I have to remake a GameBoy. For this I wanted to create a GameBoy model with ThreeJS (i'm a beginner) and use a public repo of a GameBoy emulator in JavaScript. So I somewhat finished the GameBoy model (still need some some stuff to be added but i'll make it better later) and I decided to use this repo for the GameBoy emulator https://github.com/alexaladren/jsgameboy. This repo worked perfectly fine when it was given a canvas with an ID "display". But when I tried to change the canvas to the canvas I made in ThreeJS it doesn't display anything, here is the code of when I make the Canvas:
geometry = new THREE.PlaneGeometry( 0.55, 0.45, 0.1 );
for (let index = 0; index < 6; index++) {
let x2 = document.createElement("canvas");
let xc2 = x2.getContext("2d");
x2.width = 320;
x2.height = 288;
xc2.fillStyle = "rgba(0, 0, 200, 0.5)";
x2.style.id = 'display';
screenCanvas = x2;
xc2.fillRect(0, 0, x2.width, x2.height);
let tex2 = new THREE.CanvasTexture(x2);
screen.push(new THREE.MeshBasicMaterial({
map: tex2,
transparent:true,
opacity:0.3
}))
number++;
}
material = new THREE.MeshBasicMaterial({color: 0xA1A935});
mesh = new THREE.Mesh( geometry, screen );
mesh.position.y = 0.25;
mesh.position.z = 0.3;
group.add(mesh);
Here is the code I edited in the emulator where the default "display" canvas was mentioned:
if(window.gb != undefined){
clearInterval(gb.interval);
screenCanvas.getContext("2d").setTransform(1,0,0,1,0,0);
}
gb = new GameBoy(arraybuffer);
gb.displaycanvas = screenCanvas.getContext("2d");
screenCanvas.getContext("2d").scale(2,2);
The PlaneGeometry is correctly displayed (I also tried BoxGeometry but same results) but the game won't display on the Canvas I created.
My thoughts on why it doesn't work:
- Because the Canvas is created in ThreeJS it doesn't seem to be added to the DOM elements and probably to the already existing ThreeJS canvas?
- Maybe the canvas I created isn't updating? But I set it to a CanvasTexture so it should update?
Thank you for your help.
Update: Still looking into it but haven’t found a solution, been trying to find help in 3 different Discord servers that provide threejs Discord but no luck. I might have to make the gameboy static while the game is playing and put the game display ontop of the screen if I don’t find another solution.
I am trying to create chainlink surface. I have 2 textures; a standard map which has the metallic look of the metal links with a white background (diffuse):
I also have an alpha map:
I am trying to apply both of these to a MeshBasicMaterial without luck:
var chainlinkMask = THREE.ImageUtils.loadTexture('textures/chainlink_Large-Panels_mask.png');
chainlinkMask.wrapS = THREE.RepeatWrapping;
chainlinkMask.wrapT = THREE.RepeatWrapping;
chainlinkMask.repeat.set( 2, 2 );
var chainlinkDiffuse = THREE.ImageUtils.loadTexture('textures/chainlink_Large-Panels_Diffuse.png');
chainlinkDiffuse.wrapS = THREE.RepeatWrapping;
chainlinkDiffuse.wrapT = THREE.RepeatWrapping;
chainlinkDiffuse.repeat.set( 2, 2 );
material.map = chainlinkMask;
material.alphaMap = chainlinkDiffuse;
material.transparency = true;
material.side = THREE.DoubleSide;
This gives me the following:
As you can see, the alpha map isn't being applied.
Why not?
Any help appreciated.
Try setting the transparent parameter to true instead of transparency
material.transparent = true;
If you are using an alpha map, use one of these two patterns when defining your material:
alphaMap: texture,
transparent: true,
or
alphaMap: texture,
alphaTest: 0.5, // if transparent is false
transparent: false,
Use the latter if possible, and avoid artifacts that can occur when transparent is true.
three.js r.85
directly use material.transparent will cause rendering problem, for example. you have 2 corssing plane with each one applied material.transparent = true, and material.side = DoubleSide. rotate it you will see rendering problem.
just use the solution #WestLangley mentioned above.
is it possible to create a very soft / very subtle shadow in three.js?
like on this pic?
everything I managed to do so far is this:
My Lights:
hemisphereLight = new THREE.HemisphereLight(0xaaaaaa,0x000000, 0.9);
ambientLight = new THREE.AmbientLight(0xdc8874, 0.5);
shadowLight = new THREE.DirectionalLight(0xffffff, 1);
shadowLight.position.set(5, 20, -5);
shadowLight.castShadow = true;
shadowLight.shadowCameraVisible = true;
shadowLight.shadowDarkness = 0.5;
shadowLight.shadow.camera.left = -500;
shadowLight.shadow.camera.right = 500;
shadowLight.shadow.camera.top = 500;
shadowLight.shadow.camera.bottom = -500;
shadowLight.shadow.camera.near = 1;
shadowLight.shadow.camera.far = 1000;
shadowLight.shadowCameraVisible = true;
shadowLight.shadow.mapSize.width = 4096; // default is 512
shadowLight.shadow.mapSize.height = 4096; // default is 512
and render:
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
thanks you
You can soften shadows by setting radius like this:
var light = new THREE.PointLight(0xffffff, 0.2);
light.castShadow = true;
light.shadow.radius = 8;
I was curious about this too, so i played around with all possible vars i found. The first real change made this one at init:
shadowLight.shadow.mapSize.width = 2048; // You have there 4K no need to go over 2K
shadowLight.shadow.mapSize.height = 2048; // - || -
Then i tested something other and when i've set:
shadowLight = new THREE.DirectionalLight(0xffffff(COLOR), 1.75(NEAR should in this case under 2), 1000 (FAR should just be the range between light/floor)); the Shadows smothing more out when i set also my directional lights position the 250 with:
shadowLight.position.set( 100(X just for some side effects), 250(Y over the scene), 0(Z) );
!!!!!!!!!!!!!!!!!Delete the (VAR) parts before using!!!!!!!!!!
Then i change this value to the value of my floor width.
d = 1000;
shadowLight.shadow.camera.left = -d;
shadowLight.shadow.camera.right = d;
shadowLight.shadow.camera.top = d;
shadowLight.shadow.camera.bottom = -d;
because if you use this:
var helper = new THREE.CameraHelper( shadowLight.shadow.camera );
and put it also in render:
scenes.add( shadowLight, helper );
...you see the box of your light and it should be maxed to your scene width itself i think. Hope it helps someone out.
What you're looking at is called Ambient Occlusion. There are a few things already available to look at, and you can probably find more now that you know what to search for. For example: Ambient occlusion in threejs
Actually that is not Ambient Occlusion. AO is only the contact shadow between 2 meshes which are very close one to each other.
What you are looking for, those soft shadows, you can get them in 2 ways:
First one, the easier: creating lightmaps in the 3D software that you use to create your models. That is: baking the shadows (and ambient occlusion too, if you want, and even textures and materials) into 1 texture that you can use later in ThreeJS. BUT: you will not be able to move those objects later... or better said, you will be able to move them, but their shadows will remain in the objects where they were being projected when you baked the lightmap.
The other way is doing something as it is done in this example, but unfortunately I haven't been able to go through it yet and I don't know much about it:
http://helloracer.com/webgl/
Good luck with it! Regards.
EDIT: Sorry... the 2nd option, the one with the F1 car, is still a lightmap :( But that shadow is made to follow the car, so the effect is quite nice at the end. Here you have the shadow being used, it is all baked, not real-time calculated:
http://helloracer.com/webgl/obj/textures/Shadow.jpg
I think drei is a good solution of soft shadow
https://github.com/pmndrs/drei#softshadows
I am having a strange problem when using pngs as a texture in three.js. The pngs get strange borders at the area between visible and transparent. I allready tried to play around with alphatest value but then sometimes the image disapears completly in areas where are really thin 1px lines. Is there a solution how to solve this?
var explosionTexture = new THREE.ImageUtils.loadTexture( 'explosion.png' );
boomer = new TextureAnimator( explosionTexture, 4, 4, 16, 55 ); // texture, #horiz, #vert, #total, duration.
var explosionMaterial = new THREE.MeshBasicMaterial( { map: explosionTexture } );
explosionMaterial.transparent = true;
var cube2Geometry = new THREE.PlaneGeometry( 64, 64, 1, 1 );
cube2 = new THREE.Mesh( cube2Geometry, explosionMaterial );
cube2.position.set(100,26,0);
scene.add(cube2);
// renderer
//renderer = new THREE.WebGLRenderer( { antialias: false, premultipliedAlpha: true } );
renderer = new THREE.WebGLRenderer( { antialias: false } );
Just try this:
explosionTexture.anisotropy = 0;
explosionTexture.magFilter = THREE.NearestFilter;
explosionTexture.minFilter = THREE.NearestFilter;
Also you should not use antialaising when constructing the renderer:
renderer = new THREE.WebGLRenderer({antialias: false});
Did this to preview minecraft texture packs, works great :-)
Use material blending, the following configuration worked for me:
material.blending = THREE.CustomBlending
material.blendSrc = THREE.OneFactor
material.blendDst = THREE.OneMinusSrcAlphaFactor
See this example:
http://threejs.org/examples/#webgl_materials_blending_custom
Congratulations, you've run directly into the Texel-to-Pixel-mapping-trap. :)
This should help you out of there, although it's not WebGL the basics still apply.
Ok, so I tried all the solutions on this page. They all failed.
What worked for me was to use the correct Texture.wrapS (horizontal wrapping) and Texture.wrapT (vertical wrapping) for the sprite texture.
I personally was finding this ugly edge on the top of my sprite. I just had to make sure my Texture.wrapT setting was THREE.ClampToEdgeWrapping instead of THREE.RepeatWrapping.
Solved the issue perfectly without messing with alpha test values, texture filters, vertices or antialiasing.
i solved it like this:
var c2GVertices = cube2Geometry.vertices;
for (var i = 0; i < c2GVertices.length; i++) {
c2GVertices[i].x = c2GVertices[i].x - 0.5;
c2GVertices[i].y = c2GVertices[i].y - 0.5;
}
is there an easier way to move all vertices a half pixel?
I've made a circle as follows:
material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
arcShape = new THREE.Shape();
arcShape.absarc( 0, 0, 20, 0, -Math.PI*2, true );
geometry = arcShape.makeGeometry();
circle = new THREE.Mesh(geometry, material);
scene.add(circle);
Like that, it is visible. But rotate it, and it disappears.
shadow.rotation.x = Math.PI / 2;
I've seen several other posts where this problem has not been solved. (So unless someone has a solution, I'll resort to making a flat cylinder instead. It's just a niggling problem).
I've set mesh.doubleSided = true and mesh.flipSided = false. I've also tried all 4 combinations of toggling the renderer's depthTest and the material's depthWrite properties.
Is there anything else I could try? If not, I'm guessing the code is sensitive to the order of some of my calls, in which case, I've had a long day so I'll stick with the cylinder!!
material.side = THREE.DoubleSide;