使用实例化,我无法更改单个子几何的透明度/不透明度

时间:2019-07-25 14:00:29

标签: javascript three.js aframe buffer-geometry geometry-instancing

我有一个简单的模型,其中包含1000个球体实例。我正在尝试使用实例化来减少绘图调用的次数。但是,我无法更改各个子几何的透明度/不透明度。

我已经尝试了以下操作:

我能够使用

更改每个球体的透明度
material.fragmentShader = "varying vec3 vColor;void main() {  gl_FragColor = vec4( vColor, 0.2 );}"; 

但是,这会将每个球体的不透明度更改为0.2。

html文件类似于:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>A-Frame Instancing component</title>
    <meta name="description" content="A-Frame Instancing component">
    <script>
    /*
    var WebVRConfig = {
        FORCE_ENABLE_VR: true,
        BUFFER_SCALE: 1.0
    };
    */
    </script>
    <script src="https://cdn.rawgit.com/aframevr/aframe/v0.4.0/dist/aframe-master.min.js"></script>
    <script src="https://cdn.rawgit.com/donmccurdy/aframe-extras/v3.2.0/dist/aframe-extras.min.js"></script>
    <script type="text/javascript" src="build/aframe-instancing.js"></script>
  </head>
  <body>
    <a-scene stats>
      <a-assets>
        <img id="sky" src="https://cdn.rawgit.com/aframevr/aframe/master/examples/primitives/models/peach-gradient.jpg">
      </a-assets>
      <a-entity instancing="count:100"></a-entity>
      <a-sky src="#sky"></a-sky>
      <a-entity light="type:directional;color:#FFFFFF" position="-1 1 1"></a-entity>
    </a-scene>
  </body>
</html>

实现实例化的功能:

AFRAME.registerComponent('instancing', {
      schema: {
        count: {type: 'int', default: 10000}
      },

        var geometry = new THREE.InstancedBufferGeometry();
        geometry.copy(new THREE.SphereBufferGeometry(5.0));


        var translateArray = new Float32Array(count*3);
        var vectorArray = new Float32Array(count*3);
        var colorArray = new Float32Array(count*3);

         geometry.addAttribute('translate', new THREE.InstancedBufferAttribute(translateArray, 3, 1));
        geometry.addAttribute('vector', new THREE.InstancedBufferAttribute(vectorArray, 3, 1));
        geometry.addAttribute('color', new THREE.InstancedBufferAttribute(colorArray, 3, 1));

         var material = new THREE.ShaderMaterial({
          uniforms: {
            time: {value: 0}
          },
          vertexShader: [
            'attribute vec3 translate;',
            'attribute vec3 vector;',
            'attribute vec3 color;',
            'uniform float time;',
            'varying vec3 vColor;',
            'const float g = 9.8 * 1.5;',
            'void main() {',
            '  vec3 offset;',
            '  offset.xz = vector.xz * time;',
            '  offset.y = vector.y * time - 0.5 * g * time * time;',
            '  gl_Position = projectionMatrix * modelViewMatrix * vec4( position + translate + offset, 1.0 );',
            '  vColor = color;',
        '}'
          ].join('\n'),
          fragmentShader: [
            'varying vec3 vColor;',
            'void main() {',
            '  gl_FragColor = vec4( vColor, 1 );',
            '}'
          ].join('\n')
        });

        var mesh = new THREE.Mesh(geometry, material);

        this.model = mesh;
        el.setObject3D('mesh', mesh);

        el.emit('model-loaded', {format:'mesh', model: mesh});
        //try to change opacity here
        material.fragmentShader = "varying vec3 vColor;void main() {  gl_FragColor = vec4( vColor, 0.2 );}";

        material.transparent = true;

        //use the new opacity
        var mesh1 = new THREE.Mesh(geometry1, material);
        this.mesh = mesh1;
        el.setObject3D('mesh', mesh1);
        el.emit('model-loaded', {format:'mesh', model: mesh1});
      }   
    });
 }
 ]);

任何人都可以告诉我,如何更改仅一个球体的不透明度吗?预先谢谢你!

1 个答案:

答案 0 :(得分:2)

您的颜色仅是RGB的值,而不是RGBA。更新您的color属性以支持4个值,并更改关联的vec3引用以使用vec4。向量中的最后一个值将是您的alpha(透明度)值。

您似乎已经知道如何将vertex shader中的值发送到fragment shader中,因此在此我不再赘述。但是在您的fragment shader中,您可以直接使用颜色,因为gl_FragColor希望设置为vec4

进一步的说明:

创建InstancedBufferAttribute时,将为每个实例创建一个属性 。因此,您的color属性当前每个实例仅包含RGB个值。

1处(即0.2)对wgl_FragColor = vec4( vColor, 1 );进行硬编码,可以将其普遍应用于所有实例。因此,您需要根据每个实例定义alpha值,而最简单的方法是通过已创建并实例化的color属性。

//geometry.addAttribute('color', new THREE.InstancedBufferAttribute(colorArray, 3, 1)
geometry.addAttribute('color', new THREE.InstancedBufferAttribute(colorArray, 4, 1)

上面的代码为alpha值腾出了空间,您应该为每个球体提供该值。您的colorArray将包含诸如[ R, G, B, A, R, G, B, A, ... ]之类的数据。

然后,在您的着色器中...

// vertex shader
// ...
attribute vec4 color;
varying vec4 vColor;
// ...
void main(){
  // ...
  vColor = color;
  // ...
}
// fragment shader
// ...
varying vec4 vColor;
// ...
void main(){
  // ...
  gl_FragColor = vColor;
}

现在,您为每个球体实例提供的alpha值将仅用于该实例。例如,如果您希望索引1处的球体是唯一的透明球体,则colorArray缓冲区应如下所示:

colorArray = [
  1.0, 1.0, 1.0, 1.0,
  1.0, 1.0, 1.0, 0.5,
  1.0, 1.0, 1.0, 1.0,
  // ...
];`

重要警告

此实现不会对实例进行深度排序,因此混合将取决于渲染顺序。您可以在以下问题中阅读有关此内容的更多信息:

Transparency within instanced shapes