Three.js Resizing Canvas

Javascriptthree.js

Javascript Problem Overview


I have been working on a 3D project where we show 3D object in the web browser using Three.js Library.

The problem is:

  • 1st the model is displayed in a small dom element or when the browser window itself is small.
  • Then when the window (or the dom element is resized) the model become pixellated

Following are some screenshots:

Before resize:

enter image description here

After resize:

enter image description here

How it should be after resize:

enter image description here

Here is the part of code that is setting the the model dimensions (height and width), and this function gets called when the resize event if fired:

console.log("domChanged fired")

instance.domBoundingBox = instance.dom.getBoundingClientRect();
instance.domCenterPos.x = instance.domBoundingBox.width / 2 + instance.domBoundingBox.left;
instance.domCenterPos.y = instance.domBoundingBox.height / 2 + instance.domBoundingBox.top;

var width = instance.dom.clientWidth, height = instance.dom.clientHeight;
instance.domWidthHalf = width / 2, instance.domHeightHalf = height / 2;

// TODO: fire event to expose it to site developers

// here we should update several values regarding width,height,position
if(instance.cameraReal) {
    instance.cameraReal.aspect = instance.dom.clientWidth / instance.dom.clientHeight;
    instance.cameraReal.updateProjectionMatrix();
}

if(instance.renderer3D)
    instance.renderer3D.setSize(instance.dom.clientWidth, instance.dom.clientHeight);

Can anybody give me a hint? I've been working on that a couple of days already but no clue so far

Javascript Solutions


Solution 1 - Javascript

So the canvas element can be resized like every other element. What you want to do is tell the render and camera to resize the contents of your canvas as well.

window.addEventListener( 'resize', onWindowResize, false );

function onWindowResize(){

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize( window.innerWidth, window.innerHeight );

}

Solution 2 - Javascript

Finally the problem were solved the actually problem was coming from because the application is using the THREE.EffectComposer object, in the class constructor a composer object were created like following:

this.composer = new THREE.EffectComposer(this.renderer3D);

So as for the renderer, the composer needed to have the size updated after the event handler function like following:

if(instance.renderer3D)
    instance.renderer3D.setSize(instance.dom.clientWidth, instance.dom.clientHeight);
if(instance.composer)
    instance.composer.setSize(instance.dom.clientWidth, instance.dom.clientHeight);

And this fixed the issue perfectly :)

Solution 3 - Javascript

I applied Shawn Whinnery's answer to my needs with React JS:

Start listener onMount:

componentDidMount() {
  window.addEventListener('resize', this.handleResize, false)
}

Remove listener onUnmount (because we like garbage collection):

componentWillUnmount() {
  window.removeEventListener('resize', this.handleResize, false)
}

Install handler function:

handleResize = () => {
  this.camera.aspect = window.innerWidth / window.innerHeight
  this.camera.updateProjectionMatrix()
  this.renderer.setSize(window.innerWidth, window.innerHeight)
}

Fat arrow syntax is used to avoid binding this. The code will not work if you have this: handleResize() { ... }, but of course, it would work if you added this to your constructor:

this.handleResize = this.handleResize.bind(this)

Final note: confirm that your camera is this.camera and your renderer is this.renderer. Besides that, you should be able to paste it all in.

Solution 4 - Javascript

For those googling, if you want to start off quick with a helper util that does the resizing for you, check out this github: https://github.com/jeromeetienne/threex.windowresize

The only thing you have to do is install it via bower and initialise it:

new THREEx.WindowResize(renderer, camera)

Solution 5 - Javascript

It is very simple. this three.js code will not change even if resized the browser window.

Code:

//Simple Cube Example
var scene = new THREE.Scene();
			var camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 1000 );
			var renderer = new THREE.WebGLRenderer();
			renderer.setSize( window.innerWidth, window.innerHeight );
			document.body.appendChild( renderer.domElement );

			var geometry = new THREE.BoxGeometry( 1, 1, 1 );
			var material = new THREE.MeshBasicMaterial( { color: "rgb(255, 0, 0)" } );
			var cube = new THREE.Mesh( geometry, material );
			scene.add( cube );
			camera.position.z = 5;
			var edges = new THREE.EdgesHelper( cube, "rgb(0, 0, 0)" );
			edges.material.linewidth = 5;
			scene.add( edges );

			function animate(){
				requestAnimationFrame( animate );
				cube.rotation.x += 0.01;
				cube.rotation.y += 0.01;
				renderer.render( scene, camera );
			}
			animate();
			function rot(){
				requestAnimationFrame( rot );
				edges.rotation.x += 0.01;
				edges.rotation.y += 0.01;
			}
			rot();
      //this will not change it's size when browser is resized, but use css and correct it.

//this is the code. it does not work use a div and use the javascript
.code{
  float: left;
  width: 100vw; /*fullscreen*/
  height: 100vh;
}

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="robots" content="index, follow" />
<link rel="canonical" href="http://" />
<meta name="author" content="">
<meta name="google-site-verification" content="">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Hammersmith+One|Lato" rel="stylesheet">
<title></title>
<link rel="stylesheet" href="style.css">
</head>

<body>
		<script src="https://threejs.org/build/three.js"></script>
</body>
</html>

Solution 6 - Javascript

try antialias property to resolve pixelation problem by 50 - 70%

e.g :var renderer = new THREE.WebGLRenderer({antialias:true});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAbu Roma&#239;ssaeView Question on Stackoverflow
Solution 1 - JavascriptShawn WhinneryView Answer on Stackoverflow
Solution 2 - JavascriptAbu RomaïssaeView Answer on Stackoverflow
Solution 3 - Javascriptagm1984View Answer on Stackoverflow
Solution 4 - JavascriptpolyclickView Answer on Stackoverflow
Solution 5 - JavascriptDereck Smith ElijahView Answer on Stackoverflow
Solution 6 - JavascriptAslam khanView Answer on Stackoverflow