The texture is not refreshing in three.js

I am currently utilizing the threejs editor as a foundation for my threejs projects. One issue I am facing involves displaying tooltips when the user hovers over specific elements. To accomplish this, I have set up a canvas that is rendered as a texture on a sprite.

// Creating a canvas element
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 20px Arial";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillText('Hello, world!', 0, 20);

// The canvas content will be used for a texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;

// Using the texture as a material
var spriteMaterial = new THREE.SpriteMaterial({
    map: texture1,
    useScreenCoordinates: false
});

// Creating the sprite and adding it to the scene
var sprite1 = new THREE.Sprite(spriteMaterial);
sprite1.scale.set(1000, 500, 1.0);
sprite1.position.set(50, 50, 0);
scene.add(sprite1);

var i = 0;
// Changing the content of the canvas
setInterval(function () {
    context1.clearRect(0, 0, canvas1.width, canvas1.height);
    var message = 'test' + i++;
    context1.fillText(message, 4, 20);
    texture1.needsUpdate = true;
}, 1000)

The text "test0" appears, but the sprite does not update. How can I go about updating the text on the sprite? Is there something missing in terms of cache invalidation?

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

Answer №1

Have you considered a different approach to placing the text box on your 3D canvas? In my opinion, it would be more beneficial to position your 2D html object by projecting the 3D object position in the context of your page.

The main advantage of this method is that there will be no decrease in rendering performance and you can easily apply normal CSS/HTML styling for your info box.

You can see an excellent example of how to do this here.

There is also another example mentioned in this stackoverflow answer. Implementation is as simple as shown below:

var proj = toScreenPosition(divObj, camera);

divElem.style.left = proj.x + 'px';
divElem.style.top = proj.y + 'px';

If you search online, you'll find many more examples to explore...

Here is a fiddle where you can experiment with this concept.

Answer №2

The reason it's not functioning could be due to the missing specifications for the height and width of the canvas element.

canvas1.width = 256;
canvas1.height = 256;

An issue was identified in this line as well:

context1.fillStyle = "rgba(0.0,0,0,0.95)";

I replaced it with : context1.fillStyle = '#ff0000'; to make it functional

For a visual representation of your code with the necessary adjustments made, you can visit this JSFiddle link.

If Wilt's approach aligns better with your requirements, it may be a preferable alternative to consider.

Answer №3

UPDATE: My mistake, I just realized this question is actually from 2 years ago.

It appears to be functioning correctly on my end... Have you double-checked for any errors in the console? Did you set a breakpoint in your setInterval function to ensure it's being triggered?

I had to modify the update method to renderloop since setInterval was not defined for SO snippets. Here's the adjusted code:

var renderer = new THREE.WebGLRenderer();
var w = 300;
var h = 200;
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
  45, // Field of view
  w / h, // Aspect ratio
  0.1, // Near
  10000 // Far
);
camera.position.set(15, 10, 15);
camera.lookAt(scene.position);
controls = new THREE.OrbitControls(camera, renderer.domElement);

var light = new THREE.PointLight(0xFFFF00);
light.position.set(20, 20, 20);
scene.add(light);
var light1 = new THREE.AmbientLight(0x808080);
light1.position.set(20, 20, 20);
scene.add(light1);

var sphereGeom = new THREE.SphereGeometry(5, 16, 16);
for (var i = 0; i < sphereGeom.vertices.length; i++) {
  var v = sphereGeom.vertices[i];
  if (v.y < 0) v.y = 0;
}
sphereGeom.verticesNeedUpdate = true;
sphereGeom.computeFaceNormals();
sphereGeom.computeVertexNormals();

var material = new THREE.MeshLambertMaterial({
  color: 0x808080
});
var mesh = new THREE.Mesh(sphereGeom, material);
scene.add(mesh);
renderer.setClearColor(0xdddddd, 1);

// create a canvas element
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 20px Arial";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillText('Hello, world!', 0, 20);

// use canvas contents as texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;

// apply texture as material
var spriteMaterial = new THREE.SpriteMaterial({
  map: texture1,
  useScreenCoordinates: false
});

// create and add sprite to scene
var sprite1 = new THREE.Sprite(spriteMaterial);
sprite1.scale.set(40, 20, 1.0);
sprite1.position.set(-5, 0, -5);
scene.add(sprite1);

var i = 0;

(function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
  
  context1.clearRect(0, 0, canvas1.width, canvas1.height);
  var message = 'test' + i++;
  context1.fillText(message, 4, 20);
  texture1.needsUpdate = true;
})();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>

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

Building multiple files in React allows developers to divide their code

Can a React/Redux application be split into modules during webpack build? For example, having a set of components for users and another set for invoices. I want webpack to generate users.js and invoices.js that can be imported into index.html. If I make ch ...

When creating a FlipCard, you may encounter the error message "The object may be null" while using the document.querySelector() method

Having trouble creating a flipcard on Next.js with tsx. The querySelector('.cardflipper') doesn't seem to locate the object and I keep getting this error: "Possibly the object is null". Does anyone know a solution to help my method recognize ...

Setting or passing a variable via URL in Angular 2 applications

I am working on an Angular2 application that includes a chart component. Users can adjust the chart by setting certain variables. I want to give users the option to have the chart preset with specific variables by using a URL link. For instance: localhost ...

Leveraging ES6 with jQuery in Symfony 4

Currently working on a simple app using Symfony 4 and trying to add custom triggers in JavaScript. Having trouble getting my additional code to work as expected, even though it's compiled by Webpack via encore. It seems like my event is not triggering ...

Issue with displaying Youtube search API results on EJS template file

I'm currently trying to integrate the YouTube Search API into my website. However, when I make the API call from my route, the results are returned but the page is rendered before the results finish processing - likely due to the asynchronous behavior ...

Utilize various addMethods on a field in the event a radio button is chosen through the jQuery validator plugin

When a specific radio button value is selected, I need to apply different methods to a single field. If "true" is selected, method X should be applied. If "false" is selected, method Y should be used on the same field. I attempted to achieve this with a ...

What is the best method to trigger a form submission using Jquery?

Happy New Year! Wishing you a joyful 2015! I have a basic PHP contact form that I'm validating with Parsley.js. The validation is working well, but I'm receiving a high volume of spam emails. I think that if I make the form submission dependent ...

jQuery Validation for Radio Buttons and Optional Fields

I've been pondering over this issue for a couple of hours now. Currently, my focus is on validating a form using a jQuery plugin. Here's the link to the documentation: http://docs.jquery.com/Plugins/Validation Here's the code I have so fa ...

Retrieval of jQuery remove() method

Essentially, I am utilizing an OnClick function to delete a DIV. Once the OnClick is triggered, it invokes the remove() jQuery function to eliminate the div. Below is my code that implements the removal using remove(): <div id="add"> <button typ ...

Finding Corresponding Values in an Array with JavaScript

I am working with an array of objects that have a specific format: [ { "card_details": { "cardType": "gift" }, "merchant_details": { "merchantName": "Walter Heisenberg1", "timeZone": "+05:30", } }, { "card_detai ...

Getting the Value of an Object in an Array in My Angular Project

Within my Angular Application, I am receiving an array of objects from an API: "register":[ { "club": 8, "players": 100, "officials": 10 }, { "male": 7, "female": 2, "other": 1 }, { "Brazil": 5, "France": 1, "Italy": 2, "England": 2 } ] I want to specifi ...

Attempting to enable a checkbox using a controller located in a separate controller

I am attempting to trigger a checkbox from a separate controller. Suppose I have a card called information technology under one controller, and when clicked, it should redirect to another page that contains a checkbox for information technology managed by ...

If the handler of an event listener in jQuery requires a callback function, be sure to detach the event

Currently, I am facing a dilemma with a listener I have: $(document).on("keypress", function(e){ebClose(e,mpClose)}); I am exploring ways to dynamically delete this listener. The issue lies in the fact that I specifically want ebClose to receive mpClose ...

Is it possible to drag the parent element but only select the text within the child

How can I make the parent div draggable, yet keep the text in the child span selectable? <aside draggable="true" id="dragme"> This is an aside, drag me. <span id="copyme" draggable="false">But copy me!</span> </aside> A simila ...

The fullcalendar is experiencing difficulties in showing the event

I am facing an issue with Fullcalendar where the events fetched by ajax are not showing up on the calendar. Even though the events are successfully passed and can be displayed in a pop-up, they do not render on the calendar. When manually setting the event ...

The div in JavaScript is expanding properly, but it is not contracting back as expected

I'm experiencing an issue with a div element that I created. My goal is to have it expand when a link is clicked and collapse when the same link is clicked again. At the moment, the div expands correctly but does not collapse as expected. Any assistan ...

Verify if input is selected using jQuery

Is it possible to achieve the following using jQuery? if($(this).parent().find('input:checked') == true) {$(this).find('.switch').attr('state','on');} else{$(this).find('.switch').attr('state',& ...

Searching for 10 random data records within a collection of 100 in MongoDB

Can MongoDB retrieve a specific number of random documents in one query? For example, I currently load all the documents in the collection on the JavaScript side, which is inefficient. I'm wondering if there's a better way to achieve this with a ...

Implementing Promises in AngularJS Controller: A Comprehensive Guide

I'm currently working on implementing a basic function using promises in one of my controllers to make sure it works correctly before adding more complex functionality. I keep running into a "TypeError: undefined is not a function" error when trying t ...

Having difficulty locating any content within the return element in JSX

I'm relatively new to React and JSX and currently working on creating a button that, when clicked, should trigger a dialog box to appear. Within this dialog box, there should be a table with three columns: name, status, and exception error, all repres ...