Home > other >  Threejs sprites are getting displayed with the wrong aspect ratio
Threejs sprites are getting displayed with the wrong aspect ratio

Time:09-11

I am not sure what is causing this, but I am trying to render two objects in an Orthographic camera, and they are not rendering correctly, and I am not sure why.

The two images are supposed to look like this:

Objects Normal Images

But when rendered within threejs, they look like this:

Squished Images

As you can see the paddle is squished. The chunk of code is where I setup the canvas, renderer, etc to display on the page. This is how I setup the canvas:

import { animationFrames, tap } from 'rxjs';

export class Game {
  static renderer = new WebGLRenderer({
    alpha: true,
    antialias: true
  });

  // Starts the renderer
  static start() {
    this.updateRendererSize();
    window.addEventListener('resize', this.updateRendererSize.bind(this));
    document.querySelector('.container')?.appendChild(this.renderer.domElement);

    /* Snipped: Load all objects into the scene. */

    animationFrames().pipe(
      tap(() => this.renderGame())
    ).subscribe();
  }

  // Sets the renderer size
  private static updateRendererSize() {
    const aspect = this.game.aspect; // 1.777
    this.renderer.setSize(window.innerWidth, window.innerWidth / aspect);
  }

  // Renders the scene/camera
  private static renderGame() {
    this.renderer.render(this.activeScene.scene, this.activeCamera.camera);
  }
}

This is how I am creating the camera.

export class GameCamera {

  camera: Camera;

  private aspectRatio = 1.7777777777777777;
  private size = 5;

  private readonly width = options.size;
  private readonly height = this.size / this.aspectRatio;

  constructor() {
    const dim = this.cameraDimensions();
    this.camera = new OrthographicCamera(
      dim.left, dim.right,
      dim.top, dim.bottom, 
      0, 100);
  }

  private cameraDimensions() {
    const left = this.width / -2;
    const right = this.width / 2;
    const top = this.height / 2;
    const bottom = this.height / -2;
    return { left, right, top, bottom };
  }
}

This is how I am loading the textures:

  loadResource() {
    const map = new TextureLoader().load(this.resource);
    this.material = new SpriteMaterial({
      map,
      precision: 'highp',
    });
    this.object = new Sprite(material);

    /* Snipped: add sprite to scene. */
  }

CodePudding user response:

Hi so Sprite in 3d engine is usually a textured plane that is 1x1 unit in world space.

Since your texture aren’t square you have to set size for sprite explicitly, to do so in threejs you have to use:

sprite.scale.set( x, y, 1 );

where x and y would be aspect ratio of texture

to calculate aspect you have two general options:

  1. against height (default)
const height = 1;
const width =(1/texture.height)*texture.width;
  1. against width
const width = 1;
const height = (1/texture.width)*texture.height;

There are options also to use min max to fitIn or fitOut of the 1 by 1 square

and if you want to tweak size you can replace 1 by factor so you can scale sprite according to your scene and camera setup

  • Related