What is the best way to attach a tag or label onto multiple objects so that it remains facing the camera whenever the user interacts with the objects?

My goal is to create a tag or label that always faces the camera when a user clicks on an object, even if that object is rotated. How can I achieve this?

I've been advised to use an Orthogonal camera, but I'm not sure how to do that. Additionally, I was suggested to use CSS for the label. Refer to my previous post for more information: How can I make my text labels face the camera at all times? Perhaps using sprites?

Below you'll find the CSS and HTML code for a single cube label. I want to extend this functionality to multiple objects, so I'll need to create a list of tags for each cube in this case.

CSS:

label {
    vertical-align: middle;
    display: table-cell;
    background-color : #99FFCC;
    border: 1px solid #008000;
    width: 150px;
}

HTML:

<div id="Cube1">
    <label>Cube 1</label>
</div>

Previous Code:

<!DOCTYPE html>
<html lang="en">
<head>
        <title>three.js canvas - interactive - cubes</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
                body {
                        font-family: Monospace;
                        background-color: #f0f0f0;
                        margin: 0px;
                        overflow: hidden;
                }
        </style>
</head>
<body>

        <script src="js/three.min.js"></script>

        <script src="js/stats.min.js"></script>

        <script>

                // JavaScript code here...

        </script>

</body>

Feel free to ask for clarification if needed.

Answer №1

I don't have much experience with Three.js, but I can guide you through the typical steps:

  • First, select a point on the object's surface where you want to place the label.
  • Utilize projector.projectVector to convert the in-world point to an on-screen point.
  • (You might need to adjust the NDC (-1 to 1) result to canvas (0 to canvas.width) coordinates; this step may require scaling.)
  • Use the X and Y coordinates to apply CSS absolute positioning to position your label.

Below is the code snippet from my Cubes project that achieves a similar outcome (although it doesn't use Three.js, the underlying concepts remain applicable). This code is slightly more intricate as it places the element adjacent to an object defined by a series of points (which are provided to the callback function attached to pointGenerator). It also includes logic to handle situations where the object is outside the camera's view.

Feel free to use and modify this code as needed.

// Function to position an HTML overlay element next to a given set of points.
function positionByWorld(element, keepInBounds, pointGenerator) {
  var canvasStyle = window.getComputedStyle(theCanvas,null);
  var canvasWidth = parseInt(canvasStyle.width, 10);
  var canvasHeight = parseInt(canvasStyle.height, 10);

  var elemStyle = window.getComputedStyle(element, null);
  var elemWidth = parseInt(elemStyle.width, 10);
  var elemHeight = parseInt(elemStyle.height, 10);

  var slx = Infinity;
  var sly = Infinity;
  var shx = -Infinity;
  var shy = -Infinity;
  var toScreenPoint = vec4.create();

  pointGenerator(function (x, y, z, w) {
    toScreenPoint[0] = x;
    toScreenPoint[1] = y;
    toScreenPoint[2] = z;
    toScreenPoint[3] = w;
    renderer.transformPoint(toScreenPoint);
    toScreenPoint[0] /= toScreenPoint[3];
    toScreenPoint[1] /= toScreenPoint[3];
    toScreenPoint[2] /= toScreenPoint[3];
    if (toScreenPoint[3] > 0) {
      slx = Math.min(slx, toScreenPoint[0]);
      shx = Math.max(shx, toScreenPoint[0]);
      sly = Math.min(sly, toScreenPoint[1]);
      shy = Math.max(shy, toScreenPoint[1]);
    }
  });

  if (shx > -1 && shy > -1 && slx < 1 && sly < 1 /* visible */) {
    // convert to screen
    slx = (slx + 1) / 2 * canvasWidth;
    //shx = (shx + 1) / 2 * canvasWidth;
    //sly = (sly + 1) / 2 * canvasHeight;
    shy = (shy + 1) / 2 * canvasHeight;
    if (keepInBounds) {
      slx = Math.max(0, Math.min(canvasWidth - elemWidth, slx));
      shy = Math.max(0, Math.min(canvasHeight - elemHeight, shy));
    }
    element.style.left   = slx + "px";
    element.style.bottom = shy + "px";
  } else {
    element.style.left   = canvasWidth + "px";
  }
}

Link to GitHub Permalink

Answer №2

Make sure to check out the ThreeJS documentation for Sprites.

A sprite is essentially a flat plane that constantly aligns itself to face the camera, typically with a semi-transparent texture on it.

Additionally, there are components known as CSS2DLables, which also automatically adjust to face the camera.

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

Is it possible to access Firebase data in Vue.js, with or without Vuefire, using a router parameter before the DOM is rendered?

When I navigate to a view from another view, I pass the itemId as a param value to vue router. My goal is to call firebase with that itemId in order to filter the data and use the filtered result/data in the UI. Specifically, I am utilizing vuefire. The ...

How to show a placeholder in a select input using ReactJS

I'm currently trying to incorporate placeholder text into a select input field using ReactJS, but it doesn't seem to be working as intended. Here is the code snippet I am working with: <Input type="select" placeholder="placeholder"> ...

Creating a jQuery countdown script

Is it possible to easily convert the function below into jQuery and still maintain the ability to call multiple instances of the countdown? This particular function receives a server time echoed by the server and then initiates a countdown to the specifie ...

Twitter Bootstrap Dropdown PHP link fails to function

Recently, I designed a dropdown menu to be used on a PHP page. The main button, which contains the dropdown links, needs to still function as a link to another page. Despite following all the instructions provided on the Bootstrap website, the main button ...

Ensure that the entire webpage is optimized to display within the viewport

My goal is to make the entire website fit perfectly into the viewport without requiring any scrolling. The main pages I am focusing on are index, music, and contact, as the other two pages lead to external sources (you can find the link at the bottom of th ...

What is the best way to retrieve app.state in a Remix project when running a Cypress test?

One way Cypress can expose an app's state to the test runner is by using the following approach in React: class MyComponent extends React.Component { constructor (props) { super(props) // only expose the app during E2E tests if (window.C ...

Utilizing JavaScript to retrieve data from a JSON-parsed SOAP envelope

Welcome to the exciting world of development! This is my first post, so please bear with me if I ask a seemingly silly question. Currently, I am utilizing Xml2js for sending a SOAP request and then converting the response into JSON format. However, I&apos ...

What is the best way to make three divs that can be adjusted in size?

Desired Layout: | A | | B | | C | ^ ^ Adjustment Behavior: | A | | B | | C | Current Issue: | A | C | I attempted to enhance the functionality by modifying the provided JavaScript cod ...

Javascript - Could anyone provide a detailed explanation of the functionality of this code snippet?

Ever since joining a new company 9 months ago, I've been encountering this line of code in JavaScript. It seems to work fine and I've been incorporating it into my coding style to align with the previous developers. However, I'm not entirely ...

What is the best way to merge the value of an input field (contained in an array) with another input field before submitting the form

Currently, I am in the process of editing the data in a form's input field. I know that submitting form data this way is not ideal, but I encountered a challenge with getting the value from a datetimepicker into the ng-model. Specifically, I was able ...

"Using only JavaScript to target and manipulate child elements within the

I'm currently transitioning from using jQuery to pure JavaScript, and I've just started but am encountering difficulties. Specifically, I am unsure how to select child elements in the DOM. <div class="row-button"> <input type="submi ...

What are the best scenarios for implementing jQuery-ui plugin as opposed to Backbone View?

I am feeling uncertain about the concept of "componentization" in web UI development. When I need a component, should I develop my own jQuery-UI plugin or opt for creating a MarionetteComponent if I am using Backbone.Marionette? Both options provide reusa ...

AngularJS and TypeScript encountered an error when trying to create a module because of a service issue

I offer a service: module app { export interface IOtherService { doAnotherThing(): string; } export class OtherService implements IOtherService { doAnotherThing() { return "hello."; }; } angular.mo ...

JavaScript encountered an issue while parsing XML: the format is not well-formed

I keep seeing an error message saying "Error parsing XML: not well-formed" when I encounter this line in my javascript code: for (var i=1; i<=totalImgs; i++) If I remove the < character from the line, the parsing error goes away. However, the javas ...

Maintain the active menu open when navigating to a different page on the website

My website has a dropdown menu, but whenever I click on a submenu link, the new page opens and the menu closes. However, I want the active menu to remain open on the new page of the website! To demonstrate what I have tried in a simple way, I created an e ...

Is there a way to remove the initial word from a sentence?

Tue 26-Jul-2011 Looking to remove the initial word "Mon" using javascript with jQuery. Any suggestions on accomplishing this task? ...

The FontLoader feature seems to be causing issues when integrated with Vuejs

While working on a Vue project with threejs, I encountered an error similar to the one described here. The issue arose when attempting to generate a text geometry despite confirming that the path to the typeface font is accurate and in json format. ...

Guide on creating a function that accepts an Array of strings as a parameter and displays the initial letter of each element individually on separate lines

I am currently tackling my initial JavaScript assignment which involves the task of creating a function that accepts an array of strings as its parameter and outputs the first letter of each element individually on separate lines. The unique requirement ...

Javascript alert: forgetting to add ; before statement causes SyntaxError

Seeking to incorporate a post-it application into my django website using Javascript/JQuery. Came across a tutorial and attempted to add it to my script, but encountered a SyntaxError: SyntaxError: missing ; before statement post-it.js:2:19 Not be ...

What is the best way to define the active <li> tab using JQuery?

Initially, my HTML code includes a set of <li> elements that I want to dynamically add to the existing <ul>. <ul class="tabs" id="modal_addquestion_ul"> <li class="tab-link current" data-tab="multipleChoice">Multiple Choice< ...