实例形状内的透明度

问题描述 投票:0回答:2

我一直在和

THREE.InstancedBufferGeometry
一起玩。我终于得到了一个可以使用的示例,现在已经开始使用着色器了。我尝试的第一件事是设置透明度。我的示例代码如下。

初始状态,以及从许多其他摄像机角度(例如将鼠标向左拖动),透明度似乎没有任何效果。但在其他摄像机角度(例如重新加载并将鼠标拖动到右侧),形状明显重叠,这正是我所期望的。

对于实例形状,深度排序的处理方式是否不同,或者我做错了什么,或者遗漏了什么?我是否需要以某种方式更新形状,以便相机知道它们在场景中的正确深度?

var cubeGeo = new THREE.InstancedBufferGeometry().copy(new THREE.BoxBufferGeometry(10, 10, 10));
//cubeGeo.maxInstancedCount = 8;

cubeGeo.addAttribute("cubePos", new THREE.InstancedBufferAttribute(new Float32Array([
  25, 25, 25,
  25, 25, -25, -25, 25, 25, -25, 25, -25,
  25, -25, 25,
  25, -25, -25, -25, -25, 25, -25, -25, -25
]), 3, false, 1));

var vertexShader = [
  "precision highp float;",
  "",
  "uniform mat4 modelViewMatrix;",
  "uniform mat4 projectionMatrix;",
  "",
  "attribute vec3 position;",
  "attribute vec3 cubePos;",
  "",
  "void main() {",
  "",
  " gl_Position = projectionMatrix * modelViewMatrix * vec4( cubePos + position, 1.0 );",
  "",
  "}"
].join("\n");
var fragmentShader = [
  "precision highp float;",
  "",
  "void main() {",
  "",
  " gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);",
  "",
  "}"
].join("\n");

var mat = new THREE.RawShaderMaterial({
  uniforms: {},
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
  transparent: true
});

var mesh = new THREE.Mesh(cubeGeo, mat);

scene.add(mesh);
html * {
  padding: 0;
  margin: 0;
  width: 100%;
  overflow: hidden;
}

#host {
  width: 100%;
  height: 100%;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/TrackballControls.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/libs/stats.min.js"></script>
<div id="host"></div>

<script>
  var WIDTH = window.innerWidth,
    HEIGHT = window.innerHeight,
    FOV = 35,
    NEAR = 1,
    FAR = 1000;

  var renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setSize(WIDTH, HEIGHT);
  document.getElementById('host').appendChild(renderer.domElement);

  var stats = new Stats();
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.top = '0';
  document.body.appendChild(stats.domElement);


  var camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
  camera.position.z = 250;

  var trackballControl = new THREE.TrackballControls(camera, renderer.domElement);
  trackballControl.rotateSpeed = 2.0; // need to speed it up a little

  var scene = new THREE.Scene();

  var light = new THREE.PointLight(0xffffff, 1, Infinity);
  camera.add(light);

  scene.add(light);

  function render() {
    if (typeof updateVertices !== "undefined") {
      updateVertices();
    }
    renderer.render(scene, camera);
    stats.update();
  }

  function animate() {
    requestAnimationFrame(animate);
    trackballControl.update();
    render();
  }

  animate();
</script>

three.js
2个回答
4
投票

您正在使用

InstancedBufferGeometry
和半透明的网格。

实例按照它们在缓冲区中出现的顺序进行渲染。每个实例的面按照几何体指定的顺序渲染。

因此,如果您使用半透明实例,则可能会出现伪影,具体取决于视角。

根据您的用例,您可以尝试设置

material.depthWrite = false
,但这可能会导致其他问题。

如果您的网格纹理具有完全透明(而不是部分透明)的区域,您应该能够使用

material.alphaTest
丢弃不需要的片段,而不会产生伪影。

三.js r.84


1
投票

在评论中与 WestLangley 讨论后,我为我的实例添加了一个排序器。它根据实例与相机的距离对实例位置进行排序。

(旁注:如果我还有其他

THREE.InstancedBufferAttributes
,我需要同时重新订购它们。)

最大的缺点是,随着场景变大,无论是实例形状还是非实例形状,它都会变得越来越昂贵。

// Instances Sorter, called each frame
function sortObjectInstances(obj) {
  if (obj.geometry) {
    if (obj.geometry instanceof THREE.InstancedBufferGeometry) {
      var array = obj.geometry.attributes.cubePos.array,
        vecArray = [];
      for (var i = 0, l = array.length / 3; i < l; ++i) {
        vecArray.push(new THREE.Vector3(array[(i * 3)], array[(i * 3) + 1], array[(i * 3) + 2]));
      }
      vecArray.sort(function(a, b) {
        if (a.distanceTo(camera.position) > b.distanceTo(camera.position)) {
          return -1;
        }
        if (a.distanceTo(camera.position) < b.distanceTo(camera.position)) {
          return 1;
        }
        return 0;
      });
      for (var i = 0, l = vecArray.length; i < l; ++i) {
        array[(i * 3)] = vecArray[i].x;
        array[(i * 3) + 1] = vecArray[i].y;
        array[(i * 3) + 2] = vecArray[i].z;
      }
      obj.geometry.attributes.cubePos.needsUpdate = true;
    }
  } else {
    for (var i = 0, l = obj.children.length; i < l; ++i) {
      sortObjectInstances(obj.children[i]);
    }
  }
}

var cubeGeo = new THREE.InstancedBufferGeometry().copy(new THREE.BoxBufferGeometry(10, 10, 10));
//cubeGeo.maxInstancedCount = 8;

cubeGeo.addAttribute("cubePos", new THREE.InstancedBufferAttribute(new Float32Array([
  25, 25, 25,
  25, 25, -25, -25, 25, 25, -25, 25, -25,
  25, -25, 25,
  25, -25, -25, -25, -25, 25, -25, -25, -25
]), 3, true, 1));

var vertexShader = [
  "precision highp float;",
  "",
  "uniform mat4 modelViewMatrix;",
  "uniform mat4 projectionMatrix;",
  "",
  "attribute vec3 position;",
  "attribute vec3 cubePos;",
  "",
  "void main() {",
  "",
  " gl_Position = projectionMatrix * modelViewMatrix * vec4( cubePos + position, 1.0 );",
  "",
  "}"
].join("\n");
var fragmentShader = [
  "precision highp float;",
  "",
  "void main() {",
  "",
  " gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);",
  "",
  "}"
].join("\n");

var mat = new THREE.RawShaderMaterial({
  uniforms: {},
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
  transparent: true
});

var mesh = new THREE.Mesh(cubeGeo, mat);

scene.add(mesh);
html * {
  padding: 0;
  margin: 0;
  width: 100%;
  overflow: hidden;
}

#host {
  width: 100%;
  height: 100%;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/TrackballControls.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/libs/stats.min.js"></script>
<div id="host"></div>

<script>
  var WIDTH = window.innerWidth,
    HEIGHT = window.innerHeight,
    FOV = 35,
    NEAR = 1,
    FAR = 1000;

  var renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setSize(WIDTH, HEIGHT);
  document.getElementById('host').appendChild(renderer.domElement);

  var stats = new Stats();
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.top = '0';
  document.body.appendChild(stats.domElement);


  var camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
  camera.position.z = 250;

  var trackballControl = new THREE.TrackballControls(camera, renderer.domElement);
  trackballControl.rotateSpeed = 2.0; // need to speed it up a little

  var scene = new THREE.Scene();

  var light = new THREE.PointLight(0xffffff, 1, Infinity);
  camera.add(light);

  scene.add(light);

  function render() {
    if (typeof sortObjectInstances !== "undefined") {
      sortObjectInstances(scene); // Sort the instances
    }
    renderer.render(scene, camera);
    stats.update();
  }

  function animate() {
    requestAnimationFrame(animate);
    trackballControl.update();
    render();
  }

  animate();
</script>

© www.soinside.com 2019 - 2024. All rights reserved.