How to resize canvas without resizing renderer or scaling contents?

Hi all,

I tried searching for an answer to this but didn’t find anything, hope I didn’t miss anything obvious. I also posted the question on SO before realising this forum existed :slight_smile:

I’d like to find an efficient way to resize the canvas to match the size of the browser window, without resizing or scaling the contents of the canvas – ie. if I’m displaying an object that takes up all of the viewport in fullscreen, when reducing the window it shouldn’t be entirely visible anymore.

Right, now, I’m doing this:
renderer.setSize(window.screen.width, window.screen.height)

Then, on init and resize:

camera.fov = window.innerHeight / window.screen.height;
camera.aspect = window.innerWidth / window.innerHeight;
renderer.setViewport(0, 0, window.innerWidth, window.innerHeight);

Which works, but I’m just not sure it’s the proper way to do it. Mainly I’m concerned that it’s wasteful if the user is only ever using a tiny window – are all the contents of a full-size canvas still ‘computed’, or does setViewport avoid that?

Cheers.

First, you normally don’t change the field of view when resizing. Besides, calculating it like that seems strange. It’s normally a value like 40, 60, 70, something like that.

Even more important: If you don’t call camera.updateProjectionMatrix(), all your changes to camera properties have no effect.

I’m still not sure what you try to achieve. Can you show your code with a live example?

I’ll make a codepen in a moment. I am calling camera.updateProjectionMatrix(), I just didn’t mention it for tthe sake of clarity, my bad :smile:

The effect I want is basically the same as if you had a canvas with a fixed size that you didn’t resize at all, but I don’t want to render that even for users who use small windows.

Here is a codepen: https://codepen.io/Acccent/pen/MVgeeo?editors=0010

When you resize the window, the cube keeps the same size and stays centred. This is the wanted behaviour. I’m just wondering if I’m doing it the right way.

Can’t you use the following approach? https://codepen.io/anon/pen/QmLvQL

This is the default camera/rendering setup of the official three.js examples. Even if you resize, the cube keeps its size and stays centered. The thing is: It’s unusual to call WebGLRenderer.setViewport() since it’s automatically called by WebGLRenderer.setSize() with proper parameters. And you don’t have to worry about performance. Smaller windows means in general a lower resolution and therefore a performance benefit for fragment/pixel bound applications.

1 Like

In your codepen, if you resize the window the cube does get resized too. It keeps it size relative to the size of the window; I would like the content to keep the same size relative to the size of the physical screen.

I do not at all fundamentally want or need to use .setSize(), it’s just that I found a solution that uses it, but I’m more than open about other solutions that do not.

I made a small graphic to explain what I’m trying to achieve and the reasoning behind my current implementation:

three%20scaling-01

Okay, i see. Since i’ve never worked with such a setup, i can’t tell you if there are better ways to achieve the same result. Maybe somebody else of the community knows more.

1 Like

No worries, thanks anyway! Hope someone else ran into the same thing and can provide some advice :slight_smile:

Just a quick post to say that a better approach, instead of setting the camera fov to window.innerHeight / window.screen.height, is to use this in order to keep a consistent size for objects at z=0 (hopefully this will make sense to at least some people):

camera.fov = Math.atan(window.innerHeight / 2 / camera.position.z) * 2 * THREE.Math.RAD2DEG;

We actually have a fiddle for this on our FAQ site :blush:. Maybe this helps:

http://jsfiddle.net/Q4Jpu/

2 Likes

Ah, cheers!
I’ll leave my project as it is for now since this approach seems fairly close to what I’m doing, so I don’t think I’m losing a lot (if at all) in terms of performance, and I’ll revisit this thread towards the end of development to see if I can change it up without breaking anything :stuck_out_tongue:

Hi! I am trying to do something similar, but when adding this to camera.fov, the cube on your CodePen becomes really small.

I also notice that the viewport is squared and the cube looks very distorted. Do you manage to solve this problem?

Could you provide an example or excerpt of how you implemented it please?

Here’s how I ended up doing it:

renderer.setSize(window.innerWidth, window.innerHeight);
camera.fov = Math.atan(window.innerHeight / 2 / camera.position.z) * 2 * THREE.Math.RAD2DEG;
camera.aspect = window.innerWidth / window.innerHeight;

(Preferably, save the window dimensions and use those saved values instead!)

I updated your initial code pen, with these lines of code, and this is the result:

As you will see, the cube looks like a pixel (very small size). I tried by changing the camera.position.z to a lower value, like 1 or 10, but it still looks small. Do you an idea of what is happening?

ah, I see!

So, in my first codepen, the fov was essentially 1, so you could see the cube cover the screen because its own dimensions were 1.

In that new code tidbit, the fov basically adapts to the window size, so if the window is 1000px high you’ll see 1000px in the renderer (at z==0). Since the cube is so small, it’s normal that you barely see it now (it’s just 1px tall). Does that make sense?

This second approach works better if the camera is way far. So you’d set camera.position.z to something like 5000 or more, increase the draw distance accordingly, and then if you make the cube 200px wide it’ll take exactly that space on the screen as long as you set its z to 0.

Here’s a new codepen:

Oh, got it, Thanks for the explanation!

So what it is happening here is that the perspective camera is behaving like an Orthographic camera, and thus the perspective distorsion isn’t noticeable. This make me think that we could instead use an Orthographic camera from start (although the math to prevent resize/scaling may change).

1 Like

It doesn’t really behave like an orthographic camera. If you change camera.position.z to be lower (something like 300), you’ll definitely notice the distorsion. The cube will still only take up 200px on the screen though.

I only used a high value for z as a matter of preference and to get a result that’s similar to what was shown in the other codepen – since the camera is so far, the perspective is barely noticeable but it’s still there.

It’s up to you whether to use such high values, really. And you could also use an orthographic camera if you’d like! :slight_smile:

Indeed. Distorsion happens on close distance. Thanks again for making things clear!

1 Like