使用实例化,我无法更改单个子几何体的 transparency/opacity

With Instancing, I am not able to change the transparency/opacity of the individual child geometries

我有一个由 1000 个球体实例组成的简单模型。我正在尝试使用实例化来减少绘制调用的次数。但是,我无法更改单个子几何图形的 transparency/opacity。

我已经尝试过以下方法:

我可以使用

改变每个球体的透明度
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});
      }   
    });
 }
 ]);

谁能告诉我,如何只改变一个球体的不透明度?提前致谢!

此外,假设我正在尝试复制多个盒子。 其中之一如下:

    <a-box position="19.0 1.5 23.0"
           width="32.0"
           height="1.0"
           depth="40.0"
           color="#969696"
           shader="flat"
           flat-shading="true">
    </a-box>

我将在 translateArray 和 vectorArray 中填写什么值? 非常感谢!

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

看来您已经知道如何将 vertex shader 中的值发送到 fragment shader,所以我不会在那里详细介绍。但是在你的fragment shader中,你可以直接使用颜色,因为gl_FragColor期望设置为vec4

进一步说明:

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

硬编码 10.2w 位置(即 gl_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,
  // ...
];`

重要警告

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