The aspect ratio of Threejs sprites is appearing distorted

I'm facing an issue with rendering two objects in an Orthographic camera using Three.js. The objects are not rendering correctly and I'm unsure of the reason behind it.

The expected look of the two images is as follows:

https://i.sstatic.net/hQVZC.png

However, when rendered within Three.js, they appear like this:

https://i.sstatic.net/94N9D.png

The paddle seems squished in the rendered output. The code snippet below shows how I set up the canvas, renderer, and more for displaying on the page:

import { animationFrames, tap } from 'rxjs';

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

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

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

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

Below is the code snippet for 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 };
  }
}

And here 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. */
  }

Answer №1

When working with Sprite in a 3D engine, it is essentially a textured plane that occupies a 1x1 unit in world space.

If your texture is not square, you will need to explicitly set the size for the sprite. In Three.js, you can achieve this by using the following code:

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

Here, x and y represent the aspect ratio of the texture.

There are two general options to calculate the aspect ratio:

  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;

Additionally, there are options to use min and max to fit the texture inside or outside of the 1x1 square.

If you need to adjust the size further, you can replace the 1 with a factor to scale the sprite according to your scene and camera setup.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

TABULAOTR, The complete table calculation is failing to be retrieved

Apologies for any language mistakes, as I am Russian :)I am using Tabulator but facing an issue where the table footer is not being printed. I am also unable to retrieve data from the footer. The footer simply doesn't show up and I'm unsure of wh ...

Personalizing the dimensions of audio.js

I recently integrated the audio.js plugin into my website. I've added the necessary code to the header.php file located in the includes folder. <script src="audio/audiojs/audio.min.js"></script> While the player appears correctly on othe ...

ngFor is failing to show the array data, which is being fetched from Firebase

Hi there, I understand that this question has been asked frequently, but the regular solutions are not working for me. ts handleChangeFormType(formType) { this.serverData.getData('questionnaire/' + formType) .subscribe( (response: Respons ...

I attempted to use the Stripe API, but it seems to be non

I seem to be encountering an issue with the stripe.customers.create. My goal is to create a new Stripe customer using the email address of the current user, and then update my user with the generated customer.id. Despite the fact that stripe.customers.cre ...

Utilizing JavaScript to Extract JSON Information from Knockout.js

Incorporating knockout into my project has been a great help as I retrieve JSON objects using Ajax. One question that arises is how to effectively utilize this data in my custom JavaScript code: After receiving the mapped item from the ajax call, here is ...

Unable to generate two tables

I have a dynamic table creation issue. The tables are meant to be created based on the user's input for the "super" value. For example, if the user inputs "2" for super, then it should create 2 tables. However, this is not happening as expected becaus ...

Concurrent HTTP Requests - AngularJS

My directive, known as machineForm, includes a dataService: dataService.getMachineTaxesById($scope.machineId).then(function (response) { $scope.machine.machineTaxes = response.data; }); I am using this directive twice simultaneously. <div class= ...

What steps should I take in order to ensure that NPM commands run smoothly within Eclipse?

I have a functional workflow that I'm looking to enhance. Currently, I am developing a JavaScript library and conducting smoke tests on the code by using webpack to bundle the library and save it to a file that can be included in an HTML file for test ...

The Angular model does not automatically refresh when the Space or Enter key is pressed

Having an issue with my editable div and the ng-trim attribute. Even though I have set ng-trim to false, pressing SPACE or ENTER does not increment the string length by one in the div below. Using Angular 1.3.x and wondering if anyone has any ideas on how ...

Can I exclusively utilize named exports in a NextJS project?

Heads up: This is not a repeat of the issue raised on The default export is not a React Component in page: "/" NextJS I'm specifically seeking help with named exports! I am aware that I could switch to using default exports. In my NextJS ap ...

Struggling to determine the expense upon button activation - data remains stagnant

My coding project involves a basic ordering system where users can input an integer, click on an update button, and see the total cost displayed below. Despite my efforts, I've encountered issues with two different methods: Using plain JavaScript for ...

Switch up the box-shadow color with ColorThief!

Is there a way to adjust this script to change the box-shadow color of #player1? <script type="text/javascript> $(window).ready(function(){ var sourceImage = document.getElementById("art"); var colorThief = new ColorThief(); var color = ...

Preventing the automatic selection of the initial item in a PrimeNG dropdown menu

While utilizing the p-menu component from PrimeNG in popup mode ([popup]="true"), I encountered an unexpected issue where the first item in the menu is automatically selected and turns gray. Here is the code snippet that I am using: <p-menu #menu [popu ...

Ensure that the div remains fixed at the bottom even when multiple items are added

Following up on the previous question posted here: Sorting divs alphabetically in its own parent (due to many lists) I have successfully sorted the lists alphabetically, but now I need to ensure that a specific div with a green background (class: last) al ...

Tips for changing the text in a .txt file that has been accessed through a $.get request

Is there a way to read and open a file, but update a specific value within it? For example, if my data.txt looks like: [ {"slot": "1", "name": "Bob"}, {"slot": "2", "name": "John"} ] and I want to update it with a query like: "UPDATE data.txt SET na ...

Display a modal dialogue with an image on the initial page load for each user

Working on a project with Angular 11, Angular material, and Bootstrap, I encountered an issue. I want to display a popup ad the first time a user visits the home page. The modal dialog is created using Angular material, and I have it in the ads component, ...

Where is the optimal location for placing a JavaScript listening function within an Angular component?

Summary: Incorporating a BioDigital HumanAPI anatomical model into my Angular 5 application using an iFrame. The initialization of the API object is as follows: this.human = new HumanAPI(iFrameSrc); An important API function human.on(...) registers clic ...

Vibrant progress bar design with CSS

Could someone assist me in coding a multicolor progress bar? I would like it to display red when the progress is less than 50, green when the progress is between 50 and 90, and blue when the progress is between 90 and 100. How can I achieve this? ...

Instructions on enabling Angular 2 to detect dynamically added routerLink directive

As illustrated in this Plunker, I am dynamically injecting HTML into one of my elements, which can be simplified as follows: @Component({ selector: 'my-comp', template: `<span [innerHTML]="link"></span>`, }) export class MyCo ...

Assistance needed with selecting elements using jQuery

After some practice with jQuery, I managed to select this specific portion from a lengthy HTML file. My goal is to extract the values of subject, body, and date_or_offset (these are name attributes). How can I achieve this? Let's assume this snippet i ...