Skip to content

Setting onBeforeCompile on derived material may cause infinite recursion #347

@brianchirls

Description

@brianchirls

If you set onBeforeCompile to itself or to that of another derived material, the setter for that property will assign it to this[privateBeforeCompileProp], and the function will call itself infinitely.

For example:

const customMaterial = createDerivedMaterial(
  baseMaterial,
  {
    // ...
  }
)
const clonedMaterial = customMaterial.clone()
clonedMaterial.onBeforeCompile = customMaterial.onBeforeCompile;

The reason this came up for me is that I needed to clone some materials, including the callbacks. Three.js Material .clone() does not copy callbacks, so I had to write my own code to do it. I tried checking with Object.hasOwn to avoid copying the callback function if it's on the prototype, but it doesn't work here. So I can't find a good workaround.

You could easily check against setting the function to itself by making a change like this:

    onBeforeCompile: {
      get() {
        return onBeforeCompile
      },
      set(fn) {
        if (fn !== onBeforeCompile) {
          this[privateBeforeCompileProp] = fn;
        }
      }
    },

...but that won't work if you copy it over from another material. Another option might be to put every internal onBeforeCompile function in a shared WeakSet and check that. Or tag it somehow by adding a property.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions