Creating dynamic textures through the use of canvas and Three.js rotation

I am attempting to rotate a texture on a single face of a cube using Three.js.

Since I am generating the cube multiple times with different textures, I am utilizing a function that creates the material and mesh with a texture parameter.

However, I need the texture to be rotated by 90°. After some research, I discovered that creating a canvas, placing the texture inside, rotating it, and then using this canvas as the mesh texture would be the best approach. I tried implementing this solution using the code from Three.js Rotate Texture, but unfortunately, I kept getting a black texture.

Below is my function:

function createCube(pos, texture) {
     var img = new Image();
     img.src = texture;

     var imgWidth = imgHeight = img.width;
     var mapCanvas = document.createElement('canvas');
     mapCanvas.width = mapCanvas.height = img.width;

     // document.body.appendChild(mapCanvas);
     var ctx = mapCanvas.getContext('2d');
     ctx.translate(imgWidth / 2, imgHeight / 2);
     ctx.rotate(Math.PI / 2);
     ctx.translate(-imgWidth / 2, -imgHeight / 2);
     ctx.drawImage(img, 0, 0, imgWidth, imgHeight);

     var texture = new THREE.Texture(mapCanvas);
     texture.needsUpdate = true;
     var materials = [
                //Left side (posx)
                new THREE.MeshLambertMaterial({
                    color: 0x1a0e05
                }),
                //Right side (negx)
                new THREE.MeshLambertMaterial({
                    color: 0x1a0e05
                }),
                //Top side (posy)
                new THREE.MeshLambertMaterial({
                    color: 0x1a0e05
                }),
                //Bottom side (negy)
                new THREE.MeshLambertMaterial({
                    color: 0xffffff,
                    map: texture
                }),
                //Front side (posz)
                new THREE.MeshLambertMaterial({
                    color: 0x1a0e05
                }),
                //Back side (negz)
                new THREE.MeshLambertMaterial({
                    color: 0x1a0e05
                })
    ];

    cube = new THREE.Mesh(new THREE.CubeGeometry(100, 2, 100, 1, 1, 1), new THREE.MeshFaceMaterial(materials));

    ...

    return cube;

}

The issue could potentially be linked to the texture not being fully loaded when added to the canvas. I removed the img.onLoad part (from Three.js Rotate Texture) because I was unsure how to integrate this callback within a function called multiple times... Additionally, this function must return the mesh. Can I achieve this using an external .onLoad function?

Thank you!

Answer №1

Your explanation regarding "due to the texture not yet loaded when appended to the canvas" is absolutely correct.

To solve this issue, you will need to reintroduce the callback function by reorganizing your code. Here is an example of how it could be implemented (although untested, the concept should be clear even if it doesn't work immediately):

function createCube(pos, texture) {
     var img = new Image();

     var imgWidth = imgHeight = img.width;
     var mapCanvas = document.createElement( 'canvas' );
     mapCanvas.width = mapCanvas.height = img.width;

     var texture = new THREE.Texture( mapCanvas );


     img.onload = function() {


         // document.body.appendChild( mapCanvas );
         var ctx = mapCanvas.getContext( '2d' );
         ctx.translate( imgWidth / 2, imgHeight / 2 );
         ctx.rotate( Math.PI / 2 );
         ctx.translate( -imgWidth / 2, -imgHeight / 2 );
         ctx.drawImage( img, 0, 0, imgWidth, imgHeight );

         texture.needsUpdate = true;


    }

    var materials = [
              //Left side (posx)
              new THREE.MeshLambertMaterial({
                  color: 0x1a0e05
              }),
              //Right side (negx)
              new THREE.MeshLambertMaterial({
                  color: 0x1a0e05
              }),
              //Top side (posy)
              new THREE.MeshLambertMaterial({
                  color: 0x1a0e05
              }),
              //Bottom side (negy)
              new THREE.MeshLambertMaterial({
                  color: 0xffffff,
                  map: texture
              }),
              //Front side (posz)
              new THREE.MeshLambertMaterial({
                  color: 0x1a0e05
              }),
              //Back side (negz)
              new THREE.MeshLambertMaterial({
                  color: 0x1a0e05
              })
    ];

    img.src = texture; 

    cube = new THREE.Mesh(new THREE.CubeGeometry(100, 2, 100, 1, 1, 1), new THREE.MeshFaceMaterial(materials));

    ...

    return cube;

}

You must have a render loop in place, or alternatively, update the scene rendering within the onload callback as well.

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

Struggling with jQuery UI Draggable 1.10.3 bug in Firefox: Cursor center not detected when scrolling window

Before version 1.10.3, possibly 1.9.x, I didn't encounter this issue. However, after updating to jQuery UI 1.10.3, Firefox seems to have trouble locating the center of the cursor on the draggable plugin when the window is scrolled down. This problem ...

Encountering a problem when trying to pass a PHP array variable to a JavaScript function

I need some help with passing an array and input value from a form to a JavaScript function. The array, $quotes, contains posts. <form method="post"> <p>Search:<input type="text" name="qSearch" id="qSea ...

One function is failing to execute properly due to multiple if conditions

Take a look at my JavaScript code below: function showLater1() { if ((vidos.currentTime >= 30) && (vidos.currentTime <= 34)) { lay.style.opacity = "1"; content.style.opacity = "0"; controls.style.opacity = "0"; ...

Preventing Body Overflow Without Affecting Iframe Overflow in Meteor.js

Currently, I am working on a project using Meteor for a Point of Sale (POS) system. For those unfamiliar with it, Meteor is a framework that allows for the use of JavaScript, jQuery, and various other web app scripting languages. The goal of this applicati ...

What is the method for organizing object bodies (parent/child) in Cannon.js?

After extensively searching and reviewing issues and documentation, it seems that apart from establishing a constraint between two Cannon bodies, there is no direct method to unite shapes of varying masses. Currently, I am using the lockConstraint approac ...

Combining arrays in Javascript that share the same key by utilizing a loop

Can you advise on the most effective method to restructure an array for desired output? My goal is to combine all key values, whether in arrays or not, into objects with the same name key. Here is my current array: brands: [ 0:ZARA: {product: "ZARA Blac ...

What is the best approach to determine the numerical equivalents of options in a dropdown menu using PHP and JS

Hey guys, I'm really stuck on this problem and I can't seem to find a helpful tutorial anywhere. I've got a form with two drop-down menus, each with a "value" attribute. What I want is for users to be able to select an item from both drop-do ...

Activate the stripe button after successful bootstrap validation

My goal was to implement BootstrapValidator for validation on a couple of fields and enable the Stripe button only when both fields are valid. Currently, the button is enabled once any of the fields pass validation. The challenge lies in ensuring that the ...

Can ajax requests be made without a web browser?

Currently, I am in the process of developing JavaScript tests using mocha and chutzpah, which means conducting all my tests without a browser. However, I have encountered an issue where all my AJAX calls are resulting in empty strings. Even when using the ...

Incorporating script within an ASPX webpage

I've been struggling with using this code on an ASPX page. I keep trying to implement it within a text box on the same page, but without success. Strangely though, I can successfully use the script within a text box in my master page. Any assistance w ...

Tips for triggering the .click() function upon returning to index.html after visiting a different page

I'm in the process of creating a portfolio website where the index.html page features a sliding navigation bar that displays a collection of projects. Each project is linked to a separate work.html page. I would like the sliding nav to automatically o ...

Steps for interacting with a button of the <input> tag in Selenium using Python

As I attempt to complete a form submission, I encounter an issue where clicking the submit button does not produce any action. It seems that the problem lies with the button being tagged as <input>: <input type="submit" name="submit ...

Innovative and interactive animated data display

I've taken inspiration from an example and expanded the code to achieve the following: Dynamic height adjustment Accessibility without JavaScript enabled Is this implementation correct? Can it be expected to function properly on most browsers? You ...

anticipating the completion of useEffect and subsequently retrieving object properties

I'm struggling with the following code: const [files, setFiles] = useState([]); const [greeting, setGreeting] = useState(0); const [menu, setMenu] = useState([]); const [options, setOptions] = useState([]); var customer_id = 1; useEffect(() => { ...

Using Vue.js to mark a checkbox as selected

I've searched extensively and tried various combinations, but I'm unable to initialize my checkboxes as checked. For example: <ul class="object administrator-checkbox-list"> <li v-for="module in modules"> <label v-bin ...

Transforming JSON data from JavaScript to Python JSON format

I am working with JavaScript JSON data: var data = '{a: 10, b: 20}' Now I need to convert this into Python JSON. Any suggestions on how to achieve this? Current Scenario: I have a script that extracts text from a website. The data on the webs ...

Symbol positioned beside the text in a react-select multiple label

Currently utilizing the react-select library, I am attempting to display icons next to the text of each label that can be added or removed using multiSelect. const data = [ { label: <svg /> && 'keyword one', value: 'keyword o ...

Is there a way to stop Bootstrap from automatically bolding the font?

When testing this simple example without the bootstrap link, everything seems to be working correctly: Hovering over any word changes its color to red, and when hovering away it returns to black. But as soon as the bootstrap link is included, the text bec ...

What are the benefits of using a combination of design patterns in JavaScript?

Currently, I am working on a personal project for learning purposes, which is a simple To-Do List. I am implementing the modular pattern (specifically, the revealing module pattern). The image below showcases my general idea of how I intend to build it. V ...

Avoid filling the container with an excessive amount of grids while maintaining the correct aspect ratio

I encountered a situation where I needed to dynamically create a grid with square grids of dimensions MxN. Below is the code snippet for achieving this: rerender = (event) => { const height = document.getElementById("y-input").value; const width ...