Noob question about cameras and ratio

Hi guys,
I’ve got a noob question.

In my scene I have a square mesh and I set the sizes in this way:
this.object.scale.set(200, 200, 1)

When I resize my scene if I use the Perspective camera It keeps the ratio (it remains a square) instead if I use the Orthographic camera It doesn’t keep the ratio but it stretches the mesh.

I set up the cameras in this way:

Perspective

const PerspectiveCamera = (canvas) => {
  const fov = (180 * (2 * Math.atan(canvas.offsetHeight / 2 / 800))) / Math.PI
  const camera = new THREE.PerspectiveCamera(fov,  canvas.offsetWidth / canvas.offsetHeight, 1, 10000)
  camera.position.set(0, 0, 800)
  return camera
} 

Orthographic

const OrthographicCamera = (canvas) => {
  var camera = new THREE.OrthographicCamera( canvas.offsetWidth / - 2, canvas.offsetWidth / 2, canvas.offsetHeight / 2, canvas.offsetHeight / - 2, 1, 10 );
  camera.position.z = 1
  return camera
}

and my resize function is:

if (resizeRenderer(this.renderer, this.parent)) {
      const canvas = this.renderer.domElement
      this.camera.aspect = canvas.clientWidth / canvas.clientHeight
      this.camera.updateProjectionMatrix()
    }

where resizeRenderer is a simple resize

const resizeRenderer = (renderer, parent) => {
  const canvas = renderer.domElement
  const width = parent === window ? parent.innerWidth : parent.getBoundingClientRect().width 
  const height = parent === window ? parent.innerHeight : parent.getBoundingClientRect().height 
  const canvasPixelWidth = canvas.width / window.devicePixelRatio
  const canvasPixelHeight = canvas.height / window.devicePixelRatio
  const needResize = canvasPixelWidth !== width || canvasPixelHeight !== height
  if (needResize) {
    renderer.setSize(width, height, false)
  }
  return needResize
}

Have I missed something or this is a normal behaviour :expressionless: ?

Thanks in advance and kind regards,

Davide

The OrthographicCamera constructor’s first 4 arguments are: left, right, top, bottom. But these are expected to be in the 3D world units, not pixel units. When you use values such as canvas.offsetWidth / - 2, canvas.offsetHeight / - 2 then you’re assigning pixel-based units, and you’re going to get wildly different camera dimensions based on your user’s browser window size. Mobile users would get a tiny frustrum.

Instead, you should use a fixed world value, let’s say you want your ortho cam to be 1000 units from top to bottom plane:

// Half of 1000 is 500
var halfCamHeight = 1000 / 2;
var aspect = canvas.offsetWidth / canvas.offsetHeight;

var cam = new THREE.OrthographicCamera(
    -halfCamHeight * aspect, // left
    halfCamHeight * aspect,  // right
    halfCamHeight,  // top
    -halfCamHeight  // bottom
);

You can see this approach in action in this example, notice how the left/right edges get cropped when you change the browser’s width, but the top/bottom edges actually scale down the scene when you change the browser’s height.

Great! Thank you very much.
You’ve clarified my doubts. :slight_smile: