Scale CSS3DRenderer respect to WebGLRenderer

Hi guys, when mixing CSS3DRenderer and WebGLRenderer in the same scene I’ve noticed that the CSS3D elements are really huge in size respect to 3d models rendered with the WebGLRenderer. Is it possible to scale down everything rendered with the CSS3DRenderer to match the size of the other elements?

Thanks for any info!

Can you please demonstrate the issue with a live example. I have never heard of such a scaling issue so a demo might help to understand your problem.

I’ve had that problem before. Reason is that CSS3D elements are sized in pixels, but Object3D elements are sized in abstract “units”. So if you have a CSS3D element with CSS rule width: 100px; next to a Mesh with a width of 10, your CSS element will be rendered 10 times bigger.

To fix this, you can perform .scale.set(0.1, 0.1, 0.1) on each of your CSS3D objects. But then you’ll run into this bug on Microsoft Edge. For a solution I found that works across all browsers, simply multiply the camera’s position by whatever factor will equalize the scale of both worlds. In my example above, the factor is 10:

update() {
    camera.position.set(/*whatever position you need*/);
    this.rendererWGL.render(scene, camera);
    camera.position.multiplyScalar(10);
    this.rendererCSS.render(sceneCSS, camera);
}

You don’t need to worry about the camera’s near or far frustum because CSS renderer doesn’t perform culling. However, if the camera is “looking at” anywhere besides (0, 0, 0), you’ll need to multiply that location as well.

5 Likes

Hi, here is a small example https://plnkr.co/edit/9QCYXjdX0ZBLGuxD8y9N?p=preview

Thank you very much, this is very helpful!

In my current application I am using controls like OrbitControls and PointerlockControls. In this scenario how should I write the update logic for the camera?

Ah, I just thought of a much easier approach. Simply scale down the entire CSS3DScene once:

cssScene = new THREE.Scene();
cssScene.scale.set(0.1, 0.1, 0.1);

And then you won’t have to mess with the camera on each frame.

Keep in mind that Firefox and Chrome render 3d transforms differently. These are both 12px font, but Chrome performs the 3D transform while maintaining vector fidelity, while Firefox converts to bitmap first, THEN performs the 3D Transform:

55%20PM
Chrome (left), Firefox (right)

This could be alleviated by using 120px font instead of 12px, and scaling down the scene even further.

5 Likes

Scene scaling seems a very good idea! I’ve tried on chrome and firefox and it works fine. Unfortunately on microsoft edge the scaling makes the text very blurry and unreadable, but I guess there is no much I can do about it.

I’ve tried also the multiplyScalar solution with PointerLockControls, with no luck. I am sure there is something wrong in the update logic:

function animate() {
// [other code]
// yawObject is an Object3D containing the camera

yawObject.translateX(velocity.x * delta);
yawObject.translateZ(velocity.z * delta);
renderer.render(scene, camera);
yawObject.position.multiplyScalar(10);
cssRenderer.render(cssScene, camera);
yawObject.position.divideScalar(10);    

requestAnimationFrame(animate);

}

I´ve tryed that solution and for me is not working, things seem to be moving in different scales anyway. Why is this happening?

:man_shrugging:

Can’t help you if you don’t show us anything.

2 Likes

Sorry.

So im making 3D world where you can move inside.
I have coded the controls based on PointerLockControls

Its a very big proyect, but this are the relevant parts of the CSS3RENDERER and webGLRenderer.

I have configure my render :

renderer = new THREE.WebGLRenderer({ antialias: true ,alpha:true});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( Ancho,Alto );
renderer.shadowMap.enabled = true; 
renderer.setClearColor( 0x000000 ,0.0);
document.getElementById('renderWEBGL').appendChild(renderer.domElement);

scene = new THREE.Scene();

My camera :

 camera = new THREE.PerspectiveCamera( 80, 
									window.innerWidth / window.innerHeight, 
									1, 
									2000 );

This is the configuration of my CSS3DRENDERER :

var container = document.getElementById( 'renderCSS3D' );

			//camera2 = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5000 );
			//camera2.position.set( 500, 350, 750 );
			
	var SCENE_SCALE =0.1;
	scene2 = new THREE.Scene();

	scene2.scale.set(SCENE_SCALE,SCENE_SCALE,SCENE_SCALE);
	
	renderer2 = new THREE.CSS3DRenderer({ antialias: true ,alpha:true});
	renderer2.setSize( window.innerWidth, window.innerHeight );
	container.appendChild( renderer2.domElement );
	
	var offsetX = window.innerWidth/2;
	var offsetY = window.innerHeight/3;
	offsetY =0;
	offsetX = 500;
	var sep = 50;
	var offsetZ = -100;
	//offsetX = 0;
	//offsety = 0;
	cssGroup = new THREE.Group();
	
	cssGroup.add( new Element( 'SJOz3qjfQXU', 0+offsetX, 0+offsetY, sep+offsetZ, 0 ) );
	cssGroup.add( new Element( 'Y2-xZ-1HE-Q', sep+offsetX, 0+offsetY, 0+offsetZ, Math.PI / 2 ) );
	cssGroup.add( new Element( 'IrydklNpcFI', 0+offsetX, 0+offsetY, - sep+offsetZ, Math.PI ) );
	cssGroup.add( new Element( '9ubytEsCaS0', - sep+offsetX, 0+offsetY, 0+offsetZ, - Math.PI / 2 ) );
	scene2.add( cssGroup );

this is a function that calculates the translation of the previus position to next position each time you pressed the mouse :

function animarmovimiento(){
	//ANIMACION : 
	if(ismoving){
		helperG.visible = false;
		//helper.visible = false;
		lerpway+=0.01;
		var aux = new THREE.Vector3();
		aux.lerpVectors(startvec,endvec,lerpway*0.1);
		controls.getObject().position.copy(aux);
		
		if(lerpway>0.8){
			lerpway = 0;
			ismoving = false;
		}
	} else{
		helperG.visible = true;
		//helper.visible = true;
	}
}

This is the animate function :

if(showfps){stats.begin();}
	
	animarmovimiento(); //Animates de translation of the camara : 
	keyPressed(); //What happens when you press a key 
	requestAnimationFrame( animate );
	//Composer en vez del renderer para hacer el outline
	
	//I try multiply and divide camera without luck 
	//camera.position.multiplyScalar(10);
	renderer2.render( scene2, camera );
	//camera.position.divideScalar(10); 
	renderer.render( scene, camera );
	
	controls.updateMove(); //Update the dragging of pointer Lock Camara
	helper_update(); //This makes the thing in the mouse moves
	
	if(showfps){stats.end();}

Here is the running example in my webPage : http://mmtt.com.ar/sgp_ultimate3_test/render.html

I´ve tryed :
-Multiply /divide scalar of camera (not working).
-Scaling the scene by : 0.01, 0.25, 0.1, and all sort of numbers. Somes seem to be more accurate, but no matter value I test i always get some displacement when i´ve translate.
-Tryed scaling each css3DObject.

I’m looking at your source code here, and you left out a very important part in the animate() function:

camera.position.multiplyScalar(10);
renderer2.render( scene2, camera );
camera.position.divideScalar(10); 
renderer.render( scene, camera );

You should do one of two things: 1. Either scale down the scene that contains CSS3D elements, or scale the camera, but not both.

2 Likes

As you can see in the code i´ve posted, multiply and divide scalar are comented . So only
scane2.scale.set
is running.

I have already tryed implementing only :

camera.position.multiplyScalar(10);
renderer2.render( scene2, camera );
camera.position.divideScalar(10);
renderer.render( scene, camera );

And then ONLY scane2.scale.set .

but none of them are working

Any updates in the past couple years to alleviate the need to scale the css3D scene down?

It’s working for me when I scale the css3D scene down by 0.01 but then I have to multiply the position of all my css3D objects by 100 so it matches with the webGL Plane object it will be displayed “on”. Doable but not ideal so just curious if any solutions have been made

Also, is there any way to mitigate the delayed rendering of the css3D objects compared to the webGL objects? When I move around the scene the css3D object looks like it’s rendering a bit too slowly causing it to become unstuck to it’s webGL plane, then it catches up when movement stops. Any solutions?

For the first item, there can’t be any improvements done by the Three.js team because this is the browser’s rendering issue. Some browsers rasterize the elements before scaling, and there’s nothing that can be done to tell the browser to change this order, so scaling the scene is the only solution.

For the second item, I suggest you start a new thread with your code. It could be the order in which you do things, or it could be a performance issue.

1 Like