Combining multiple materials in Three.js using onBeforeCompile

Imagine having a scenario like this:

//some chunks i want to override for functionality FOO
const myNormalChunks = {
   beginnormal_vertex,
   defaultnormal_vertex, 
   normalmap_pars_fragment,
}

//a version of `MeshStandardMaterial` that does FOO instead of default 
class StandardMaterialWithFOO extends THREE.MeshStandardMaterial{
  constructor(params){
    super(params)

    this.onBeforeCompile = shader=> { /*replace chunks by name*/ }
  }
}

Now you can use the FOO version of the material. But what if you wish to incorporate another version of the MeshStandardMaterial that combines both FOO and BAR?

const BAR_onBeforeCompile = shader => { 
  /* 1. replace another chunk */
  /* 2. add something after beginnormal_vertex */
}


class ShaderMaterialWithFOOandBAR extends StandardMaterialWithFOO {
  constructor(params){
    super(params)
    this.onBeforeCompile = /* ??? */
  }
}
  1. There might be a possibility to cleverly link these callbacks together.
  2. This method is not foolproof because there is no #include <some_chunk> directive after the initial onBeforeCompile processes it, making it hard to track changes made.

The one solution I can think of to address this dilemma is through a comprehensive GLSL code containing all possible variations controlled by #ifdef. However, personally, I prefer not to alter the global THREE.ShaderChunk object.

someChunk = `
  #ifdef isFOO 
    /* logic */
  #endif

  #ifdef isBAR
    /* logic */
  #endif
`

^ although effective, this approach seems laborious and prone to mistakes.

Additionally, consider something like:

const mySuperUberOneSizeFitAllOnBeforeCompile = shader =>{
  if( isBAR ) {...}
  if( isFOO ) {...}
}

However, this strategy falls short as three.js employs a caching mechanism that disregards such conditional statements. If multiple materials utilize the same callback, they will amalgamate into a single entity randomly chosen from that list.

Do you have any suggestions or innovative ideas to solve this issue?

Answer №1

I'm a bit uncertain about calling this an answer. Additionally, my knowledge of TypeScript is quite basic. However, I envision something along these lines...

function copyHashes(input, output) {
    let key
    for (key in input) {
        output[key] = input[key]
    }
}

class foo {
    shaderStuff = {}
    constructor(params) {
        copyHashes({
            beginnormal_vertex: "",
            defaultnormal_vertex: "",
            normalmap_pars_fragment: ""
        },
            this.shaderStuff)

        this.onBeforeCompile = ()=>{
            // utilize the replacement with this.shaderStuff
        }
    }
}

class bar extends foo {
    constructor(params) {
        super(params)
        copyHashes({
            somethingelse_vertex: "",
            other_pars_fragment: ""
        },
            this.shaderStuff)

        // onBeforeCompile was assigned during the constructor
        // so it wasn't inherited
        this.onBeforeCompile = ()=>{
            // utilize the replacement using this.shaderStuff
            // here, this.shaderStuff includes the ENTIRE
            // COMBINED list from both foo AND bar
        }
    }
}

The concept involves each class adding their own overrides to shaderStuff. As currently structured, any subclass will replace an existing override with their own.

If this explanation is unclear or if I have misconstrued the query, please inform me.

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 eliminate duplicate data once it has been retrieved in a modal and used for editing purposes?

Encountering an issue where, upon clicking the modal, the second set of data is being duplicated from the first set retrieved, portrayed in these images: https://i.sstatic.net/VRRs0.png Upon clicking one of the data sets to edit, the duplication as sho ...

Unable to append HTML table row to designated table

I am trying to populate an HTML table with the JSON string data I receive. The object data seems correct, but for some reason, it is not getting appended to the table. Can you help me identify what's wrong with my jQuery append statement? functio ...

steps to adjust screen zoom back to default after automatic zoom in forms

I'm not very well-versed in javascript/jquery and have been on an extensive search for a solution to my specific problem. While I've come across some close answers, I am struggling to adapt them to fit my own scenario. On my website, I have a fo ...

Implementing seamless redirection to the login page with Passport in Node.js

I have encountered a persistent issue while using node.js, express, and passport. After successfully validating the user with passport, my application keeps redirecting back to the login page instead of rendering the index page. Is there a problem with the ...

Leveraging external JavaScript libraries in Angular 2

Having some trouble setting up this slider in my angular2 project, especially when it comes to using it with typescript. https://jsfiddle.net/opsz/shq73nyu/ <!DOCTYPE html> <html class=''> <head> <script src='ht ...

Storing props in JSX components using variables in React.jsLearn how to set props in JSX components and

If I have already created a component: class Co extends React.Component { render = () => { const name = this.props.name; return ( <p>Hello, my name is {name}</p> ) } } and stored it in a variable ...

Problem with modals not triggering within the iDangero.us swiper

I am encountering an issue with the iDangerous.us Swiper where I cannot activate any events within the swiper-wrapper. I am attempting to trigger a modal on each slide but nothing is happening. Any Modal placed inside the swiper-wrapper does not work. I a ...

If there is only one remaining option after applying the angular filter, automatically choose that option

Currently, I have a scenario where there are two select boxes. The selection in one box acts as a filter for the other box. In some cases, this filter results in only one option left in the list. I am exploring options to automatically select that lone opt ...

Encountering a problem with Vite and PostCSS: "Assignment to invalid left-hand side"

Yesterday everything was running smoothly, but today I encountered an error message saying Invalid left-hand side in assignment. When I checked the Chrome console, it displayed the same error related to a file named ${mod.url} pointing to this source code: ...

How to identify the file type of a document using Node.js

A question posed six years ago about getting file types in Node.js through the File System still attracts attention. The answer from 2012 was once correct but has since been surpassed by a better solution. This raises the need for an updated approach to f ...

reinitializing the prototype object's constructor property

Let's analyze the code snippet provided: function shape(){ this.name = "2d shape" } function triangle(){ this.name = "triangle"; this.ttest = function(){ alert("in triangle constructor"); } } function equitriangle(){ thi ...

The function of hasClass within an if statement appears to be malfunctioning

I'm struggling to figure out why my .hasClass function is not functioning correctly. I've implemented the Quick Search jQuery plugin, and below is the code I am using: <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.mi ...

What could be the reason behind ng-bind-html only displaying text and not the link?

Utilizing ng-repeat to exhibit a list on my webpage. One of the fields in my data contains a URL that I want to display as an actual link within my HTML page. Please refer to the screenshots below: My HTML: https://i.sstatic.net/2Gj1U.png My rendered pa ...

How can I navigate between pages without losing the data entered in the form fields

Is there a way in Ajax or jQuery to save form data and navigate between multiple form pages without using PHP Sessions? I want the form data to be saved until the user submits it, and when they do submit, all information from different pages should be in ...

Replacing invalid characters using jQuery

My input field (type=password) is restricted to only accept certain characters. Below is the code snippet: $(document).ready(function() { $('#nguestpass, #nguestps, #nuserpass, #nuserps, #nadminpass, #nadminps').bind('keyup').bind(& ...

choose the checkbox in the first column using jQuery

I need assistance with selecting only the checkboxes in the first column of a simple table. Currently, my code is selecting all checkboxes in the table instead. How can I modify it to achieve my desired outcome? Html <script src="https://ajax.googleap ...

Pattern to identify digits from 0 to 9 along with specific symbols

I am currently in the process of creating a regular expression that can match 0 to 9 (up to 10 digits) and /-. (0 to 2 max), without having to be all . or all //. It can be /.\- or .-. or any combination of the three, with a maximum of two of those ch ...

Unable to change the main data of slot object in VueJS

When running this demo and selecting "modify in child", the text will be updated. However, if you choose "modify top level through slot", the text remains unchanged, and attempting to click the other button afterwards will not work. Is there a way to upda ...

Utilizing the map function to display elements from a sub array

I'm struggling to print out the comments using the map function in this code: class Postcomment2 extends React.Component { uploadcomment = () => { return this.props.post.comments.map((comment) => { return <div>{comment["comment"]}< ...

JavaScript code for submitting form input values

Recently, I encountered an issue on my PHP page where I handle password change requests. I am struggling to implement a Javascript function that checks if the new password contains at least one special character before proceeding to update the database fie ...