将 Perlin 噪声着色器仅应用于网格内的某些对象

Applying Perlin noise shader just to some objects within a mesh

我想使用柏林噪声修改网格中的一个对象。我现在是怎么做到的...

  1. 我正在创建对象并将它们添加到 3d 对象...

     spheres = new THREE.Object3D();
     for ( var i = 0; i < 40; i ++ ) {
         var ball = new THREE.Mesh(new THREE.SphereGeometry(20,20,20), material);
         ball.position.x = Math.random() * 600 - 300;
         ball.position.y = Math.random() * 600 - 300;
         ball.position.z = Math.random() * 600 - 300;
         spheres.add(ball);
    }
    scene.add(spheres);
    
  2. 我正在使用着色器material...

    material = new THREE.ShaderMaterial({
      uniforms: { 
    time: { 
        type: "f", 
        value: 0.0 
    },
    noisemax: { 
        type: "f", 
        value: 100.0 
    },
    transparent: true
    
    },
    vertexShader: document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent
    });
    

着色器 material 适用于所有 40 个球,没问题。我想做的是改变 spheres.children[0] 的着色器。是否可以更改一个对象的 perlin 噪声值 (noiseMax),或者它是否会自然地影响使用 material 的所有对象的 material?

你有几个选择。

简单的方法是为每个不同的项目创建和使用一个单独的 ShaderMaterial,并且您可以轻松地设置其统一。例如

var firstMaterial = new THREE.ShaderMaterial({
    uniforms: { noisemax: { type: 'f', value: 3}}
});

var secondMaterial = new THREE.ShaderMaterial({
    uniforms: { noisemax: { type: 'f', value: 10}}
});

var firstBall = new THREE.Mesh(new THREE.SphereGeometry(20,20,20), firstMaterial);
var secondBall = new THREE.Mesh(new THREE.SphereGeometry(20,20,20), secondMaterial);

// or in your case
spheres.children[0].material = secondMaterial;

或者,可能更适合您的情况(至少从性能的角度来看)是您应该将 noisemax 更改为 attribute,这样您就可以为每个对象设置一个单独的值.

您必须记住属性是每个顶点的,因此您需要复制属于每个对象的所有顶点的值。这会使事情变得有点复杂。

编辑:要减少内存使用,您可以使用THREE.InstancedBufferGeometry with THREE.InstancedBufferAttribute