three实例化模型颜色混合同步普通模型颜色混合效果

1.普通模型:贴图颜色*材质颜色

2.实例化模型:贴图颜色*材质颜色*单例颜色

如果想要在实例化模型中还原普通模型的颜色混合效果,则需要把材质颜色始终设置为(1,1,1)使其在着色器颜色混合时不生效,这样下来 贴图*单例颜色 就与 普通模型的颜色混合效果一致了

 

方案核心点:

1.首先需要清除实例材质的颜色,并且将材质颜色填充到instanceColor数组中,避免影响模型的初始样子

2.启用颜色混合时,把材质设置为(1,1,1)然后修改instanceColor为目标颜色,混合在着色器中进行

 

具体步骤:

记录材质初始颜色:

 for (const mesh of iconModel.meshes) {
      data.index = mesh.count;
      //记录材质颜色,在实例化模型中使用实例color代替材质color来进行颜色混合的关键步骤
      !mesh.userData.materiaColor && (mesh.userData.materiaColor = mesh.material?.color?.clone() || mesh.material[0]?.color?.clone());
      mesh.setColorAt(data.index, mesh.userData.materiaColor);
      mesh.instanceColor.needsUpdate = true;
      // 填充数组
      // this.instanceOpacity.setX(data.index, Math.max(0, Math.min(1, opacity)));
      mesh.count++;
    }

重写instancedMesh的setColorAt方法:(支持颜色与透明度)

  mesh.setColorAt = function (index, color, opacity = 1) {
                    //设置实例颜色
                    if (color !== null) {
                      if (!this.clearedMaterialColor) {
                        //如果设置实例颜色,则清除材质颜色
                        if (Array.isArray(this.material)) {
                          for (const eachMate of this.material) {
                            eachMate.color.set(0xffffff);
                            // eachMate.needsUpdate = true;
                          }
                        } else {
                          this.material.color.set(0xffffff);
                          // this.material.needsUpdate = true;
                        }
                        this.clearedMaterialColor = true;
                      }
                      color.toArray(this.instanceColor.array, index * 3);
                    }

                    if (opacity !== null) {
                      this.instanceOpacity.setX(index, Math.max(0, Math.min(1, opacity)));
                      this.instanceOpacity.needsUpdate = true;
                    }
                  }.bind(mesh);

着色器修改-实例材质替换:

             if (Array.isArray(child.material)) {
                  material = [];

                  for (const eachMate of child.material) {
                    const newMate = eachMate.clone();
                    newMate.onBeforeCompile = _onMaterialBeforeCompile;

                    material.push(newMate);
                  }
                } else {
                  material = child.material.clone();
                  material.onBeforeCompile = _onMaterialBeforeCompile;
                }

着色器代码:

const _onMaterialBeforeCompile = function (parameters, renderer) {
  let vertexShader = parameters.vertexShader;

  //#region vertex color

  vertexShader = vertexShader.replace(
    '#include <color_pars_vertex>',
    `
    #if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )

      attribute float instanceOpacity;
      varying vec4 vColor;

    #endif
    `
  );

  vertexShader = vertexShader.replace(
    '#include <color_vertex>',
    `
    #if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )

      vColor = vec4( 1.0 );

    #endif

    #ifdef USE_COLOR

      vColor.xyz *= color.xyz;

    #endif

    #ifdef USE_INSTANCING_COLOR

      vColor.xyz *= instanceColor.xyz;
      vColor.w *= instanceOpacity;

    #endif
    `
  );

  parameters.vertexShader = vertexShader;

  let fragmentShader = parameters.fragmentShader;

  //#region fragment color

  fragmentShader = fragmentShader.replace(
    '#include <color_pars_fragment>',
    `
    #ifdef USE_COLOR

      varying vec4 vColor;

    #endif
    `
  );

  const useInstanceColor = `
 diffuseColor *= vColor;
  `;
  fragmentShader = fragmentShader.replace('#include <color_fragment>', ` ${useInstanceColor}`);

  //#endregion

  parameters.fragmentShader = fragmentShader;
};

 

posted @ 2025-11-28 16:13  SimoonJia  阅读(0)  评论(0)    收藏  举报