You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为ThreeJS实例化网格的每个着色器材质实例设置不同颜色

解决方案:为InstancedMesh的自定义ShaderMaterial实现实例独立颜色

要让每个InstancedMesh实例拥有独立的面和边缘颜色,你需要在自定义ShaderMaterial中手动处理实例颜色属性——mesh.setColorAt()本质是给几何体的instanceColor属性赋值,但你的自定义着色器没有读取这个属性,所以无法生效。以下是完整修改步骤:

1. 为几何体添加实例颜色属性

创建BoxGeometry后,添加instanceColor属性,用于存储每个实例的颜色数据:

const geometry = new THREE.BoxGeometry(1, 1, 1);
// 添加实例颜色属性,每个实例对应一组RGB值
geometry.instanceColor = new THREE.InstancedBufferAttribute(new Float32Array(cell.length * 23 * 3), 3);

2. 修改顶点着色器

在顶点着色器中读取instanceColor属性,通过varying变量传递给片元着色器:

varying vec2 vUv;
varying vec3 vInstanceColor; // 新增:传递实例颜色

void main() {
    vUv = uv;
    vInstanceColor = instanceColor; // 读取实例颜色属性
    gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position, 1.0);
}

3. 修改片元着色器

使用传递过来的实例颜色替换原来的全局color uniform,实现每个实例独立的面+边缘颜色:

varying vec2 vUv;
uniform float thickness;
varying vec3 vInstanceColor; // 接收顶点着色器传递的实例颜色

float edgeFactor(vec2 p){
    vec2 grid = abs(fract(p - 0.5) - 0.5) / fwidth(p) / thickness;
    return min(grid.x, grid.y);
}

void main() {
    float a = clamp(edgeFactor(vUv), 0., 1.);
    // 用实例颜色替换全局color,边缘保留黑色(可改为独立的实例边缘色属性)
    vec3 c = mix(vec3(0), vInstanceColor, a);
    gl_FragColor = vec4(c, 1.0);
}

4. 更新ShaderMaterial设置

去掉不再需要的color uniform,确保材质配置正确:

var material = new THREE.ShaderMaterial({
    uniforms: {
        thickness: { value: 1.5 }
    },
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    extensions: { derivatives: true }
});

5. 在实例化时设置每个实例的颜色

在循环中为每个实例分配颜色,同时保留原有的矩阵设置逻辑:

const dummy = new THREE.Object3D();
let counter = 0;
for (let i = 0; i < cell.length; i++){
    for(let j = 0; j < cell[i].elevations.length - 1 ; j++){
        let depth = cell[i].elevations[j] - cell[i].elevations[j + 1];
        let zCenterElevation = (depth / 2) + cell[i].elevations[j + 1];
        
        dummy.position.set(cell[i].x, zCenterElevation, -cell[i].y);
        dummy.scale.set(cell[i].width, depth, cell[i].height);
        dummy.updateMatrix();
        mesh.setMatrixAt(counter, dummy.matrix);
        
        // 为当前实例设置颜色(示例用随机色,可替换为你的业务数据颜色)
        const color = new THREE.Color();
        color.setHSL(Math.random(), 0.7, 0.5);
        geometry.instanceColor.setXYZ(counter, color.r, color.g, color.b);
        
        counter++;
    }
}
// 标记属性更新,让GPU生效
geometry.instanceColor.needsUpdate = true;

扩展:实现独立边缘颜色

如果需要每个实例的边缘颜色也独立,可重复上述逻辑,新增instanceEdgeColor的InstancedBufferAttribute,在片元着色器中改为:

vec3 c = mix(vInstanceEdgeColor, vInstanceColor, a);

内容的提问来源于stack exchange,提问作者martinjp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 11:35:38