How can I incorporate an Instanced Billboard feature into my Three.JS project?

I am trying to achieve a specific effect where all instances of a mesh face the camera.

uniform vec2 size;
uniform vec3 center;

vec3 billboard(vec3 v, mat4 view) {
    vec3 up = vec3(view[0][1], view[1][1], view[2][1]);
    vec3 right = vec3(view[0][0], view[1][0], view[2][0]);
    vec3 pos = center + right * v.x * size.x + up * v.y * size.y;
    return pos;
}

void main() {
   vec3 worldPos = billboard(position, viewMatrix);
   gl_Position = projectionMatrix * modelViewMatrix * vec4(worldPos, 1.0);
}

The current code I have for rendering a billboard is not displaying anything as expected. Passing 'position' into the vec4 constructor on the last line renders the shape correctly, indicating an issue with the calculation within the function.

I have been attempting to follow this tutorial: detailing solution #2, but so far have struggled to resolve the problem.

There are other potential solutions such as those mentioned in these resources:
- THREE.JS GLSL sprite always front to camera
- THREE.js - Billboard Vertex Shader
Although they provide some insight, none of them seem to perfectly fit my requirements.

Based on my understanding, it seems crucial to send the center position after any translations to ensure accurate calculations in world space.

Considering that Three.js passes the camera position in the vertex shader, I wonder if applying a transformation based on the distance between the camera and billboard center would impact performance significantly.

Since this will be instanced, using a Sprite object or setting LookAt to the camera position every frame is not feasible in my case.

If anyone has insights or guidance, I would greatly appreciate it!

Answer №1

Success! I managed to crack it!

One major distinction is that I prefer not having all the billboards aligned parallel to the camera's forward vector. While it may look good in most scenarios, when a billboard isn't closely oriented with the camera forward vector, it appears odd as the billboard seems to be facing a different point instead of towards the camera.

Here's the snippet of the vertex shader:

uniform vec2 size;
uniform vec3 center;

vec3 viewDirection = normalize(cameraPosition - center);
vec3 cameraUp = vec3(view[0][1], view[1][1], view[2][1]);
vec3 rightVec = cross(cameraUp, viewDirection);
vec3 upVec = cross(viewDirection, rightVec);
vec3 position = center + rightVec * v.x * size.x + upVec * v.y * size.y;
return position;

JS script excerpt:

        const width = 0.75;
        const height = 0.25;

        containerShape.moveTo(0, 0);
        containerShape.lineTo(0, height);
        containerShape.lineTo(width, height);
        containerShape.lineTo(width, 0);
        containerShape.lineTo(0, 0);

        const containerGeometry = new ShapeBufferGeometry(containerShape);
        containerGeometry.translate(-width / 2, -height / 2, 0);

        const containerMaterial = new ShaderMaterial({
            uniforms: {
                size: {
                    value: new Vector2(width, height),
                },
                center: {
                    value: new Vector3(1, 0.5, 1),
                },
            },
        });

This covers the essentials. Even though there may be missing images and broken links, this resource: proved extremely helpful for me.

UPDATE 4/12/19 I stumbled upon a significant issue with the previously mentioned solution: http://prntscr.com/nayjic. If you're open to having the billboard constrained along one axis, the following code resolves the problem. Without fixing the billboard's up vector to a constant value, I couldn't resolve the glitch completely.

If the camera is positioned above the billboard (http://prntscr.com/naz4iy), then the mismatch between the billboard's "gaze" and the camera becomes more prominent. Any potential solution suggestions would be greatly appreciated!

            vec3 billboard(vec3 v, mat4 view) {
                vec3 look = cameraPosition - instanceOffset;
                look.y = 0.0;
                look = normalize(look);
                // vec3 cameraUp = vec3(view[0][1], view[1][1], view[2][1]);
                vec3 billboardUp = vec3(0, 1, 0);
                vec3 billboardRight = cross(billboardUp, look);
                vec3 pos = instanceOffset + billboardRight * v.x * size.x + billboardUp * v.y * size.y;
                return pos;
            }

Answer №2

Utilizing the <Billboard /> component from the specialized drei package in react-three-fiber, you can achieve this functionality:

import { Billboard, Text, OrbitControls } from '@react-three/drei'

...

<Billboard position={[0.5, 2.05, 0.5]}>
  <Text fontSize={1} outlineWidth={'5%'} outlineColor="#000000" outlineOpacity={1}>
    box
  </Text>
</Billboard>

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

AngularJS view is not refreshing

I am facing an issue with updating a view via a controller that fetches data from a service. Despite changing the data in the service, the view does not reflect these updates. I have created a simplified example from my application, which can be found here ...

What is the best way to achieve a complete vertical rotation around an object using OrbitControls?

I want the rotation to continuously go around the object, but I'm having trouble setting the minPolarAngle and maxPolarAngle values (Setting them to (+-)Infinity causes the rotation to stop). Is it possible for the min and max PolarAngles in OrbitCon ...

Difficulty maintaining list formatting in AngularJS and Bootstrap due to ng-repeat functionality

I'm currently working on a project where I need to display content from an array using ng-repeat in Angular. The content is originally in JSON format, but it has been stringified before being added to the array. The problem I am facing is that this c ...

How can we showcase the data within this loop on the user interface in React JS?

I'm currently working with React JS and I have a question regarding how to display data from a loop in the UI. The code snippet below shows the data being logged to the console, but I want to show it on the actual user interface. Could you please guid ...

Vue.js: API request taking too long during mounted lifecycle

I am facing an issue with API data in my Vue js project. The page loads quickly but the data from the API takes more than 5 seconds to load. Strangely, the API response appears very fast in the console. I have implemented the API in a separate file called ...

Connect Angular ngx-datatable accountid to a specific details page

My datatable is displaying static data with account numbers and other details, including a column for actions such as viewing a row. When I click on the button, an alert shows me the specific details. userdetails.component.ts rows: any = [ { id: 0 ...

Utilizing TypeScript Variables within a Jquery Each Iteration

I have a variable named tableIndexNumber that I need to use in different methods. When trying to access this variable, I use "this.tableIndexNumber" and it works fine. However, I face an issue when using it inside a jQuery each loop because the HTML elemen ...

A Guide on Integrating a Javascript Reference into HTML while Displaying a PHP Object

Our website relies heavily on PHP modules to generate objects that are essential for constructing our web pages. Some of the key modules we have include: Anchor (ahref) Button CheckBox ComboBox DateTime Email Label Note Password Phone RadioButton RichTe ...

Switch tabs with JavaScript

I'm encountering an issue with changing tabs using JavaScript and Ajax. The script I have works when not using Ajax but fails to work properly with it. Here is the script: $(document).ready(function(){ $("#mtabs li").click(function() { ...

How about making a TicTacToe game with JavaScript?

While developing a TicTacToe game, I encountered a syntax error towards the end of my code. Despite not completing the game yet, it is perplexing that the error is appearing after the last line, which seemingly doesn't contain any issues. Any insights ...

Learn the process of adding values to HTML forms within ExpressJS

I am facing a challenge in injecting Javascript variable values into HTML forms on an Expression JS server. I am unsure about how to solve this issue. All I want to do is insert the values of x, y, and res into the forms with the IDs 'firstvalue&apos ...

What are some ways to enhance the speed of my canvas animations?

My code generates imagedata and places it in a canvas. However, when I expand the window size, the rendering slows down significantly. Is there a way to optimize this for smooth operation in fullscreen mode, even though it might seem naive? What would be ...

Avoid using CSS styles when accessing the website from China

There seems to be an issue with one of our websites. Visitors from China are viewing the site without the CSS files, only the HTML. What could be causing this? Why is it only happening in China? Could there be restrictions in place, possibly for JavaScri ...

react dealing with clicking and blurring at the same time

Is there a way to ensure an input's onBlur event fires only after a button's onClick event is completed? The challenge is that the function relying on the state change caused by the onClick needs to be executed by the onBlur event. Using setTimeo ...

What is the best way to apply custom styles in reactJs to toggle the visibility of Google Maps?

There are three radio buttons that correspond to school, restaurant, and store. Clicking on each button should display nearby locations of the selected type. Displaying Google Map and nearby places individually works fine without any issues. class Propert ...

All pixels have a value of 1 for gl_FragCoord.x, y, and z, while the depth value is represented by

I'm currently utilizing THREE.js in combination with a shader. My goal is to access the zbuffer information. For the vertex shader: // enabling high precision floats #ifdef GL_ES precision highp float; #endif void main() { gl_Position = project ...

Unable to make a jQuery Ajax HTTP Request within a Chrome extension

I'm facing an issue with sending a jQuery Ajax HTTP Request within google chrome extensions. I have already imported the jQuery library and used the following code: $.ajax({ method: "PUT", url: "https://spreadsheets.google ...

Tips for transferring JSON data to a CodeIgniter view

I have a query regarding how to replace a specific section of my webpage with data returned from the controller. Currently, I have a page that displays movie details directly fetched from the database. My goal is to only display movies of a particular genr ...

React - Issues with setTimeout() method not triggering following Promise.all execution

I am facing an issue with my arrow function that is called from the `componentDidMount` lifecycle method to fetch updated status of schedules every 20 seconds using a `setTimeout()`. The problem is that the `setTimeout()` method does not trigger another re ...

Can you tell me what this code on Facebook is for?

Upon inspection of Facebook's activity in my browser, I stumbled upon the following code snippet: for (;;);{"t":"refresh"} Attempting to decipher its purpose reveals an infinite loop. Can you identify its function? ...