Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js Resizing Canvas

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 pixelated

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

like image 565
Abu Romaïssae Avatar asked Nov 29 '13 16:11

Abu Romaïssae


3 Answers

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 );

}
like image 51
Shawn Whinnery Avatar answered Nov 04 '22 18:11

Shawn Whinnery


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 :)

like image 44
Abu Romaïssae Avatar answered Nov 04 '22 17:11

Abu Romaïssae


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.

like image 14
agm1984 Avatar answered Nov 04 '22 18:11

agm1984