Is there a way to reverse the upside-down text generated by OffscreenCanvas.getContext().fillText()?

When using

OffscreenCanvas.getContext().fillText()
to generate text and then
OffscreenCanvas.transferToImageBitmap()
to create a map, I noticed that the text appeared flipped upside down when applied as a texture in a threejs project. The image clearly shows the issue with the letter "R".

My attempt to resolve this involved using createImageBitmap() with the flipY option, but unfortunately, it did not result in any changes. The function did not display any errors, but the text orientation remained unchanged.

If you have any alternative solutions or tricks to address this problem, please advise me accordingly.

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

Answer №1

Utilizing an OffscreenCanvas while passing it to a THREE.CanvasTexture appears to be functioning correctly within a worker. You can also set texture.flipY = false which overrides the default setting of true.

In the demonstration below, texture.flipY = false is currently commented out. If you uncomment it, you will observe the textures flipping.

// Three.js - OffscreenCanvas
// from https://threejsfundamentals.org/threejs/threejs-offscreencanvas.html

'use strict';  // eslint-disable-line

function main() {  /* eslint consistent-return: 0 */
  const canvas = document.querySelector('#c');
  if (!canvas.transferControlToOffscreen) {
    canvas.style.display = 'none';
    document.querySelector('#noOffscreenCanvas').style.display = '';
    return;
  }
  const offscreen = canvas.transferControlToOffscreen();
  const worker = new Worker(getWorkerBlob());
  worker.postMessage({type: 'main', canvas: offscreen}, [offscreen]);

  function sendSize() {
    worker.postMessage({
      type: 'size',
      width: canvas.clientWidth,
      height: canvas.clientHeight,
    });
  }

  window.addEventListener('resize', sendSize);
  sendSize();
}
main();

// Helper function to create Worker Blobs for self-contained snippets
function getWorkerBlob() {
  const idsToUrls = [];
  const scriptElements = [...document.querySelectorAll('script[type=x-worker')];
  for (const scriptElement of scriptElements) {
    let text = scriptElement.text;
    for (const {id, url} of idsToUrls) {
      text = text.split(id).join(url);
    }
    const blob = new Blob([text], {type: 'application/javascript'});
    const url = URL.createObjectURL(blob);
    const id = scriptElement.id;
    idsToUrls.push({id, url});
  }
  return idsToUrls.pop().url;
}
body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
#noOffscreenCanvas {
  display: flex;
  width: 100vw;
  height: 100vh;
  align-items: center;
  justify-content: center;
  background: red;
  color: white;
}
<script id="worker-offscreencanvas-cubes.js" type="x-worker">
'use strict';  // eslint-disable-line

/* global importScripts, THREE */

importScripts('https://threejsfundamentals.org/threejs/resources/threejs/r112/build/three.min.js');

const state = {
  width: 300,   // canvas default
  height: 150,  // canvas default
};

function main(data) {
  const {canvas} = data;
  const renderer = new THREE.WebGLRenderer({canvas});

  state.width = canvas.width;
  state.height = canvas.height;

  const fov = 75;
  const aspect = 2; // the canvas default
  const near = 0.1;
  const far = 100;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 4;

  const scene = new THREE.Scene();

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);
  }

  const boxWidth = 1;
  const boxHeight = 1;
  const boxDepth = 1;
  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

  const offscreenCanvas = new OffscreenCanvas(256, 256);
  const ctx = offscreenCanvas.getContext('2d');
  ctx.fillStyle = '#FDB';
  ctx.fillRect(0, 0, 256, 256);
  ctx.font = '200px bold sans-serif';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.fillStyle = '#666';
  ctx.fillText('F', 128, 128);
  const texture = new THREE.CanvasTexture(offscreenCanvas);

  // texture.flipY = false;

  function makeInstance(geometry, color, x) {
    const material = new THREE.MeshPhongMaterial({
      map: texture,
    });

    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);

    cube.position.x = x;

    return cube;
  }

  const cubes = [
    makeInstance(geometry, 0x44aa88, 0),
    makeInstance(geometry, 0x8844aa, -2),
    makeInstance(geometry, 0xaa8844, 2),
  ];

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = state.width;
    const height = state.height;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render(time) {
    time *= 0.001;

    if (resizeRendererToDisplaySize(renderer)) {
      camera.aspect = state.width / state.height;
      camera.updateProjectionMatrix();
    }

    cubes.forEach((cube, ndx) => {
      const speed = 1 + ndx * .1;
      const rot = time * speed;
      cube.rotation.x = rot;
      cube.rotation.y = rot;
    });

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

function size(data) {
  state.width = data.width;
  state.height = data.height;
}

const handlers = {
  main,
  size,
};

self.onmessage = function(e) {
  const fn = handlers[e.data.type];
  if (!fn) {
    throw new Error('no handler for type: ' + e.data.type);
  }
  fn(e.data);
};

</script>
<canvas id="c"></canvas>
<div id="noOffscreenCanvas" style="display:none;">
  <div>no OffscreenCanvas support</div>
</div>

Answer №2

To stop the vertical flipping of your threejs texture, simply set the property .flipY to false. This flipping behavior is default in OpenGL textures due to historical reasons related to scanline rasterization.

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

What steps should be taken to ensure that my nodeJS server can maintain the identity of a specific user?

Currently, I am in the process of building a mobile application that utilizes Flutter for the front-end and NodeJS for the back-end. Progress has been steady, but I have hit a roadblock while trying to incorporate a lottery feature. The idea is for the se ...

What is the most effective way to import and load three-orbitcontrols?

Has anyone tried implementing the OrbitControls function in conjunction with ReactJS? I have included a snippet of the code below: import React, { Component } from 'react'; import 'tachyons'; import * as THREE from 'react'; im ...

Removing a row from a table seamlessly without the need to reload the page

I am having an issue with my page that displays a list of orders. When a user clicks on a button to delete a row from the table, it only removes the first row successfully. However, when attempting to delete the second or third row, it does not work. Can s ...

An improved method for generating a jQuery selection

I developed a custom plugin to extract a specific segment of a collection: jQuery.range = function(start, end, includingTheLast) { var result = $([]), i = 0; while (!this.eq(i).is(start) && i < this.length) i++; for (; i & ...

Simple steps to load various json files into separate json objects using node.js

I am new to working with Json and node.js My goal is to load a json file into a JsonObject using node.js, but I have been struggling to accomplish this task. I have created two files, one named server.js and the other jsonresponse.json. My objective is t ...

Nodejs functions properly on a local machine, however, it encounters issues when deployed on a VPS

My nodejs/javascript code seems to be running fine on my local pc, but when I try to run it on my vps, it's not working properly. Even though I have the same node_modules installed and the code is identical. Here's a snippet of my code for refere ...

The error message "Type Error: val.toString is not a function - mysql npm" indicates

I'm encountering an issue with the 'mysql' package in NPM on a nodeJS backend and I'm puzzled by this error message: TypeError: val.toString is not a function at Object.escape (/Applications/MAMP/htdocs/nodeJS_livredor/node_modules/sql ...

Passing data to an Angular directive

I am facing an issue while trying to pass information through a view in a directive. Despite binding the scope, I keep seeing the string value 'site._id' instead of the actual value. Below is the code for the directive: angular.module('app ...

Creating a canvas with multiple label introductions can be achieved by following these

I am looking to group labels and sublabels on the x-axis of a canvas component. Currently, I only have sublabels like: RTI_0, RTI_1... I would like to add labels to these sublabels like: RTI = {RTI_0,RTI_1,RTI_2] BB = {BB_0, BB_1,BB_2,BB_3] <div cla ...

Unpredictable Redirection when URL is Clicked using PHP or Javascript

Looking to send users to a random URL from a specific list? For instance: With 3 URLs available - Google.com, Facebook.com, and Yahoo.com <a href="<?php $sites[array_rand($sites)] ?>">Click here</a> Upon clicking the link, users will ...

Having trouble interpreting PHP-generated JSON data in JavaScript

I have a PHP script that outputs a JSON string. <?php $arr = array( 'id' => '1', 'myarray' => array( array('a' => 'a1', 'b' => 'b1', 'c' => 'c1', & ...

Unable to modify the value of an HTML dropdown list

My latest project is a website located at pg.wcyat.me (Source code), where I utilized github.com/thdoan/pretty-dropdowns for dropdown menus. Using JavaScript, I am able to dynamically change the values of select lists. For example: document.getElementById( ...

refreshing the webpage's content following the completion of an asynchronous request

I am working on an Ionic2 app that utilizes the SideMenu template. On the rootPage, I have the following code: export class HomePage { products: any = []; constructor(public navCtrl: NavController, public navParams: NavParams, private woo: WooCommer ...

Passing Data to a Different Route in Vue.js

Being new to Vue.js, I have a question on how to efficiently handle data retrieval from my backend application. Here is the code snippet that fetches all the data: var app2 = new Vue({ delimiters: ['%%', '%%'], el: '#app2& ...

Looking for a way to locate the point where objects intersect in three.js?

My goal is to load 20 objects with random positions in a way that they do not intersect. How can I detect and check for intersections between these objects? for (var i = 0; i < 20; i++) { // Create a material var textureLoader = new ...

Why is it necessary to use 'then' on the response JSON when using the Fetch API? It's like trying to decipher the hidden meaning

While delving into the realm of promises, I decided to test it out with a basic GET request on Twitch. Yet, one aspect is still puzzling me - why does json() return a promise? The response already contains the data, so what's the deal with it being wr ...

The error message "The useRef React Hook cannot be invoked within a callback function" is displayed

I'm currently working on developing a scroll-to feature in Reactjs. My goal is to dynamically generate referenced IDs for various sections based on the elements within an array called 'labels'. import { useRef } from 'react'; cons ...

Nested promise not being waited for

As someone new to all things asynchronous, I am currently facing a challenge. I want to ensure that a file exists before updating it, creating the file if necessary. However, I am struggling to figure out how to achieve this. I am aware of the option to u ...

A guide to troubleshooting the "Cannot resolve all parameters error" in Angular

Recently delved into the world of angular 2, and I've come across my first challenge. I'm trying to establish a service for retrieving data from a server but I keep encountering this particular error Error: Can't resolve all parameters fo ...

Label it as submit ID rather than value or label

Check out this awesome plugin called https://github.com/aehlke/tag-it. It's really cool! Here is the issue I'm facing: <input type="hidden" name="tags" id="mySingleField" value="Apple, Orange" disabled="true"> Tags:<br ...