Why THREE.WebGLRenderer.setPixelRatio() on computer is slower than mobile? - three.js

In the main js script I have below properties for the renderer
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(10) // 2 is good enough for pixel ratio but I just want to play around and set to 10.
My render became really smooth, on both google chrome desktop and mobile. However on my desktop which is using rtx2060 super, the fps is very low around 10fps, and on my mobile there is no drop on fps. I could not debug the issue.

renderer.setPixelRatio(10)
Please don't do that. This line will produce a final drawing buffer size which will be problematic for most devices. In almost all use cases, setPixelRatio() should be used like so in order to render at the native screen resolution:
renderer.setPixelRatio( window.devicePixelRatio );
It's not recommended to experiment with different values other than window.devicePixelRatio.

Related

How to fix gaps between seamless objects in Three.js?

I am trying to achieve seamless objects next to each other in Three.JS which currently works fine on most devices / browsers but in some cases i'm experiencing difficulties. For example while using MacOS with the latest version of Google Chrome (and also Safari) the objects render with pixelated gaps in between that should not be there.
Bug occurs with all 3D Objects, GLTF models (left) and BoxGeometry (right):
While using the same Mac device but using Firefox everything renders as expected:
Sizes are exactly (1, 1, 1) and should fit exactly next to each other. I've also tried to scale it up to (1.05, 1.05, 1.05) but this didn't fix the problem, in fact it only got worse as applying scaling results in Z-fighting when textures are enabled.
I'm currently using R137 of Three.JS and made sure my application correctly applies window.devicePixelRatio so that should not be the problem either - is there any other renderer setting that i'm forgetting which could help resolve this rendering issue?
The behaviour for Android and Windows devices also works correctly. The used Android device has a devicePixelRatio greater than 2 and everything looks smooth there. I doubt it's a problem with my Mac GPU as it renders correctly with Firefox; is this a bug of the browser maybe, and is there something we can do about it ourselves?
Hopefully this is not a duplicate, i couldn't find any solutions/answers to this.
EDIT:
I've found out that EffectComposer (for FXAA) are causing these problems for Google Chrome / Safari on Mac devices. Which is weird because it works completely fine on all other devices. I'm currently still looking for a way to fix this. If anyone had problems in the past with EffectComposer for Mac and managed to fix them please share your solution with us. When replacing FXAA shader with for example Sepia shader the same bugs occur, it doesn't seem to matter which shaders are being passed, anything pass from EffectComposer causes this.
I've made a fiddle: https://jsfiddle.net/ilanbentley/g3yxdvmh/3/
Note how the right side (EffectComposer) has buggy edges while the left side (Renderer) looks good (for Mac).
Somehow the code below is responsible for this buggy behaviour:
const renderPass = new RenderPass( scene, camera );
fxaaPass = new ShaderPass( FXAAShader );
composer2 = new EffectComposer( renderer );
composer2.addPass( renderPass );
composer2.addPass( fxaaPass );

THREE.JS Anti-Alias not working in multi-scene set-up

What's the trick for getting anti-aliasing to work properly on smaller scenes - which are overlaid on top of big scenes?
Check out this fiddle here:
https://jsfiddle.net/gilomer88/j974zmq0/6/
When you tap on any of the cubes you see there a new smaller "detailsScene" opens up on top of the main scene - and the cube in that "detailsScene" is not looking good. (It may not look all that bad here, but trust me, in my real project I'm loading a ".glb" model and it looks really terrible there. And it's not the model that's off. I know that because when I load it into my main scene it looks 100% perfect. Unless I have to re-load it for some reason into this smaller scene...?)
Otherwise I'm pretty sure I set the renderer for this smaller scene the right way, using:
detailsRenderer.setPixelRatio( window.devicePixelRatio );
(You'll find that bit on line 192 in the JS of the fiddle code.)
Any thoughts?
Anti-aliasing is working fine. The scene is just a bit blurred, because the canvas is scaled up while the renderer renders on a smaller size. You should always set the size of the renderer, such that it matches the canvas size. Just passing the canvas element to the renderer is obviously not enough in order to let the renderer know on which size it should render the scene.
detailsRenderer.setSize(detailsCanvas.offsetWidth, detailsCanvas.offsetHeight);
https://jsfiddle.net/sg3fn0tk/

Threejs webvr with two separate renderers

I have two separate renderers with separate scenes. In one scene, I have a very expensive dynamic shader which I am rendering at a low resolution to boost fps (using .setPixelRatio(0.3). The other renderer takes care of everything else. I can render both at the same time, one on top of the other, without issue.
The problem is I cannot figure out how to render both at the same time with WebVR enabled.
Here is the relevant code
self.shaderRenderer.vr.enabled = true;
self.renderer.vr.enabled = true;
WEBVR.getVRDisplay( function ( display ) {
self.renderer.vr.setDevice( display );
self.shaderRenderer.vr.setDevice( display );
document.body.appendChild( WEBVR.getButton( display, self.renderer.domElement ) );
});
self.shaderRenderer.animate(self.renderShader);
self.renderer.animate(self.render);
I can switch between the two in VR mode by swapping the renderer.domElement in the 6th line. How do I render both, one on top of the other with WebVR enabled?

WebGL rendering on Firefox - Light effects show darker than in Chrome

I have a scene where one light is present, and diamonds.
Light properties:
Point light, position: 0 0 30, intensity: 1, distance 60, color: White.
The diamonds material is Phong, color:Red, no emissive, specular: White, shininess 10.
On Chrome, the diamons shine as suppose to, but on Firefox the diamonds not shine at all, and looks very dark (like have something black on it).
I have tried to use both Firefox on desktop Windows and Android mobile phone.
I would like to ask what I am missing?
Below are the settings in my code:
// Renderer:
ren=new THREE.WebGLRenderer({ antialias:true,alpha:true });
ren.shadowMap.enabled=true;
elm.appendChild(ren.domElement); // the renderer is added to a DOM element "elm"
// Light
var o=new THREE.PointLight(0xffffff,1,60);
o.position.set(0,0,30);
o.name="sun"; // light will be later added to the scene, and use "update materials" flag to update the materials of the entire scene.
// The diamond's material: (I gave a new parameter "name", for later use. I guess it should not makes trouble to the engine....)
var mt=new THREE.MeshPhongMaterial({ name:"RedDiamond", transparent:true, opacity:0.85, fog:false, color:0xff0020, specular:0xffffff, shininess:10 });
Live example can see here: https://www.crazygao.com/VideoGames/Lamps, since the first level (loading may takes a bit time only for the first time, the opening scene though is yet not complete). The lighting difference issue can be seen even in the progress scene (with the flash one)
My question: What should I do to make the diamonds shine in Firefox, but not make the entire scene too bright in Chrome? (I tried adding Ambient light to the scene, then in Chrome it becomes too bright....)
Is the problem comes from my settings, or it is the nature of Firefox? What are the best steps I can take to solve this issue?
Thanks a lot
My guess is that you're missing that the webgl canvas is composited with the HTML behind it. By default the browser expects the values of the pixels in the canvas to represent premultiplied alpha values. That means there are many possible invalid colors
Example RGBA = 1,1,1,0
That's an invalid color because since alpha = 0 and multiplying by 0 = 0 then R, G, and B also have to be zero
When the values are invalid the results are undefined and so you'll get different results on different browsers
This answers covers some of the solutions.

Are all renderers good for textures?

So, the scene include an earth spinning on its axis, a moon rotating around the earth, and a light source to the right that will help to simulate the effect of an eclipse. I thought it would be easy because we've done shadows and transformations before but I ran into a problem.
In our template we have the following at the top:
// For the assignment where a texture is required you should
// deactivate the Detector and use ONLY the CanvasRenderer. There are some
// issues in using waht are called Cross Domain images for textures. You
// can get more details by looking up WebGL and CORS using Google search.
// if ( Detector.webgl )
// var renderer = new THREE.WebGLRenderer();
// else
var renderer = new THREE.CanvasRenderer();
My problem is, when I leave it like that, the spotlight doesn't appear on the scene. However, as was warned, if I activate the Detector, the textures won't work.
But I need both textures and the spotlight. How do I work around this?
You are confusing yourself. Detector.webgl only checks for support of WebGL on the browser. The code below uses the WebGL renderer if the current browser supports WebGL and CanvasRenderer if there is no WebGL support.
if ( Detector.webgl )
var renderer = new THREE.WebGLRenderer();
else
var renderer = new THREE.CanvasRenderer();
With WebGL - loading textures will run into a cross domain issue. Best to then execute the code either on a web server or a local server like http://www.wampserver.com/en/ for Windows or https://www.mamp.info/en/ for Mac. Or npm-package like https://github.com/tapio/live-server.
As far as I know shadows are not supported on the CSSCanvasRender. I would ask your assignment head to clarify.

Resources