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.

4 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.

1 Like