PhongMaterial designed specifically for rendering InstancedBufferGeometry

I am working on creating a scene with thousands of simple meshes, and I decided to implement InstancedBufferGeometry for better performance. Most of my code is based on the example provided here:

Although instancing works well, it seems to only function properly with the THREE.RawShaderMaterial as shown in the example:

instancedMaterial = new THREE.RawShaderMaterial( {
    uniforms: {
        map: { value: new THREE.TextureLoader().load( 'textures/grassAlpha.png' ) },
        time: { value: 0 }
    },
    vertexShader: document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );

This involves using certain shaders:

<script id="vertexShader" type="x-shader/x-vertex">
    precision highp float;
    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    uniform float time;
    attribute vec3 position;
    attribute vec3 offset;
    attribute vec2 uv;
    attribute vec4 orientation;
    varying vec2 vUv;
    void main() {
        vec3 vPosition = position;
        vec3 vcV = cross( orientation.xyz, vPosition );
        vPosition = vcV * ( 2.0 * orientation.w ) + ( cross( orientation.xyz, vcV ) * 2.0 + vPosition );
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );
    }
</script>

<script id="fragmentShader" type="x-shader/x-fragment">
    precision highp float;
    uniform sampler2D map;
    varying vec2 vUv;
    void main() {
        vec4 texelColor = texture2D( map, vUv );
        if ( texelColor.a < 0.4 ) discard;
        gl_FragColor = texelColor;
    }
</script>

My question now is how can I integrate THREE.MeshPhongMaterial instead of the current shader setup? When I try to use other materials like basic or phong, the mesh either disappears or becomes fully transparent without any console errors.

Answer №1

If you want to utilize Material.onBeforeCompile, the code snippet below demonstrates how to do so with a single instanced attribute called offset.

material.onBeforeCompile = function ( shader ) {
    shader.vertexShader = 'attribute vec3 offset;\n' + shader.vertexShader;
    shader.vertexShader = shader.vertexShader.replace( '#include <begin_vertex>',
       [
         'vec3 transformed = vec3( position + offset );',
       ].join( '\n' )
     );
     materialShader = shader;
};

Check out the demo here: https://codepen.io/anon/pen/erGbXj?editors=1010

Answer №2

If you're looking to simplify a complex problem, there's an npm package designed to do just that.

Check out this npm package for more information

It seems to be optimized for working with shadows as well.

Please note: While this npm package is versatile and compatible with different features of Three.js, it may have limitations when rendering with shadows specifically. The primary goal is to ensure proper rendering with depth effects along with materials and cameras.

onBeforeCompile could potentially cause issues depending on its usage. It appears to be more intentional than accidental, but caution is advised:

Introducing if else statements within onBeforeCompile might yield varying shader compilations based on the scene's mesh order.

Cloning using material.clone() may not replicate the entire object. This can be observed in the example provided in the accepted answer. (Refer to this github issue for more details).

Another challenge could stem from trying to streamline necessary logical operations. If implementing onBeforeCompile in an existing project:

decorate_material_written_by_another_dev( material ){
  ...
  material.onBeforeCompile = shader => {} //potential conflict if another instance exists
  ...
}

This behavior isn't explicitly outlined in the link provided by the accepted answer.

To revisit, the inquiry begins with:

I need to create a scene with thousands of simple meshes,

In optimizing numerous basic meshes, organization into a scene graph becomes crucial:

Scene
|-Mesh0000
|-Mesh0001
...
|-Mesh1000

Wouldn't it be preferable to have a similar interface like Mesh.position, Mesh.scale, Mesh.rotation/Mesh.quaternion, regardless of the optimization techniques employed?

In essence, limited manipulation of strings, shaders, and even materials should be required.

Picture being able to execute the following:

import { InstanceMesh, InstanceMaterial } from 'examples/instancing' //or npm module

const myInstanceMesh = new InstanceMesh(
  new CubeGeometry(), 
  new InstanceMaterial(new MeshStandardMaterial())
)

myInstanceMesh.material.onBeforeCompile = onBeforeCompile_unrelated_to_instancing

The above scenario falls short if the example already involves onBeforeCompile. Hence, these instances aren't prevalent in existing examples.

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

Vue.js Element UI form validation - showcasing errors returned by server

Utilizing Vue.js and Element UI libraries for my current project, I have implemented front-end validation with specific rules. However, I now also require the ability to display backend errors for the current field. When the form is submitted and an error ...

Utilizing Vue.js: Disabling button on image carousel when there is no "next" photo accessible

This is my initial experience with Vue. I am attempting to assemble a slideshow using an array of images. I have successfully managed to disable the "previous" button when the user reaches the beginning of the slideshow, but I am encountering difficulties ...

Tips for concealing subsequent pages and displaying pagination in jQuery ajax response

Is there a way to display pagination based on a limiter in an ajax response? For example, if the limiter is set to 5, only show 10 page links and hide the rest. 1 2 3 4 5 6 7 8 9 10 .. next 11 12 13 14 15.. next I attempted to count the li elements in ...

Developing a personalized error message pop-up system in Electron

I am currently in the process of developing an application for file backup, which involves a lot of reading and writing to the filesystem. While most parts of the app are functioning well, I am facing some challenges with error handling. In the image belo ...

What can be done to ensure that the a href tag is functioning as clickable?

Having an issue with my HTML and CSS code for a notification dropdown box. I am unable to click the tag, even after attempting to use JavaScript. Can't seem to figure out what's causing this problem. Any advice on how to make the tag clickable? ...

Issue with Vuex store not being updated when called from promise resolution

I am facing an issue with my Vue.js application where I have an array called items bound to a Vuex data store and exposed as a computed property using the mapGetters helper. In the created() hook of the component, I make a REST API call to update this arra ...

Array Filtering with Redux

I have come across similar queries, but I am still unable to find a solution. While typing in the search box, the items on the screen get filtered accordingly. However, when I delete a character from the search box, it does not show the previous items. For ...

Solutions for concealing the current div when clicking on a new div that reveals a fresh one

Is there a way to hide the current div once you click on a new div that reveals another one? The code below toggles the display of the div, but what I am attempting to achieve is that when you click on a new item after clicking on the first one, the first ...

Exploring Elasticsearch with Ajax Query Syntax

Attempting to send a post request via AJAX to my Elasticsearch index but encountering some issues. Here's the cURL result: [~]$ curl -XGET 'http://localhost:9200/firebase/_search?q=song:i%20am%20in' {"took":172,"timed_out":false,"_shards": ...

Move your cursor over the image to activate the effect, then hover over it again to make the effect disappear

Looking to enhance my images with hover effects. Currently, all the images are in grayscale and I'd like to change that so that when you hover over an image, it reverts to full color and remains that way until hovered over again. I've noticed so ...

What makes 'Parsing JSON with jQuery' unnecessary?

Just performed an ajax request with a query and noticed that my response is already in the form of a JavaScript object. When I try to parse the JSON using: var obj = jQuery.parseJSON(response); 'obj' turns out to be null, yet I can directly ac ...

How to Prevent Scrolling When Modal is in Use on Full Page JS

I am trying to achieve the functionality where when the modal is open, I want to prevent full-page scrolling in JavaScript. The issue arises when I open the modal and try to scroll, it ends up moving the content that's behind the modal, which is actua ...

HTML forms default values preset

I need help with pre-setting the values of a dropdown menu and text box in an HTML form for my iPhone app. When the user taps a button, it opens a webview and I want to preset the dropdown menu and text field. Can someone guide me on how to achieve this? ...

Utilizing Data Binding in D3.js

Why is the text "Hello" not appearing five times on the page as expected? index.html <html> <head> <title>Data Binding</title> </head> <body> <h1>D3.js</h1> <script src="https://d3js.o ...

Decoding a string within a JSON file using three.js

Recently embarking on my Three.js journey, I am faced with the challenge of extracting the value "DbgName": "mtl" from a JSON file utilizing Three.js's JSONLoader. Below is an excerpt from a sample three.js JSON file: {"metadata" : {"formatVersion" : ...

Juggling PHP scripts within javascript

Can you help me with a question I have? I am working on multiple JS scripts, such as this one: <script> $('#mapveto1').click(function() { $('#mapveto1').addClass('banned'); $('#map1').text('cobble ...

React is choosing to re-render only one of the setState functions, neglecting the other

I'm currently in the process of developing a basic Tic Tac Toe game using React. The Objective: Each button in the game has its own state. When a button is clicked, it should change from ' ' to an 'X' and update the player's ...

The jQuery event for clicking is not functioning as expected when trying to display particular data from a JSON array

Three dummy users were created with a JSON array structured like this: var userArray = {"users":[ {"Name":"User1","Email":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5a2f293f286b1a2935373f2e3233343d74393537">[email& ...

Unlocking the Secrets of JSON Data Retrieval

Could someone assist me in extracting data from the json provided below? I have received a json data in the following format, where each record contains "{0}". My query is how can I retrieve data from this format or if there is a way to remove "{0}" from ...

Is bower install failing to detect a local npm package?

After running bower install, I encountered the following error message: $ bower install module.js:340 throw err; ^ Error: Cannot find module 'minimist' at Function.Module._resolveFilename (module.js:338:15) at Function.Module._l ...