Three.js如何将多种材质与onBeforeCompile

时间:2018-04-23 20:25:54

标签: javascript three.js

说我有类似的东西:

//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*/ }
  }
}

现在我可以使用材料的FOO版本。但是如果我想添加同时执行FOO和BAR的MeshStandardMaterial的另一个版本呢?

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. 我有点想通过一些黑客来管理这些回调
  2. 这不会起作用,因为在第一个#include <some_chunk>处理之后没有onBeforeCompile,我无法知道它被替换了什么。
  3. 我能想到解决这个问题的唯一方法是使用一些像GLSL代码这样的超级全局代码,每个可能的排列由#ifdef控制?但我不想全局修改THREE.ShaderChunk对象。

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

    ^这似乎有点乏味,但容易出错。

    还有类似的东西:

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

    不起作用,因为three.js具有忽略这些条件的缓存机制。假设我有10个材料使用同一个回调,它们都将编译为单个,从该列表中随机选择。

    任何建议,想法?

1 个答案:

答案 0 :(得分:0)

我很犹豫地说这是一个答案。另外,我的TypeScript非常简陋。但我的意思是这样......

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 = ()=>{
            // perform the replacement using this.shaderStuff
        }
    }
}

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

        // you assigned onBeforeCompile during the constructor
        // so it wasn't inherited
        this.onBeforeCompile = ()=>{
            // perform the replacement using this.shaderStuff
            // in this case, this.shaderStuff contains the FULL
            // COMBINED list from both foo AND bar
        }
    }
}

正在发生的事情是每个班级都将自己的替代追加到shaderStuff。我编写的方式,任何扩展类都将用自己的覆盖覆盖现有的覆盖。

如果这没有意义,或者我误解了这个问题,请告诉我。