首页 > 解决方案 > 如何通过three.js隐藏两个3d对象的交集?

问题描述

如何通过three.js隐藏/隐藏两个object3D的交集?例如:

有两个球体是“S-Red”和“S-Blue”

因为 S-Red 是透明的,所以看起来像:

在此处输入图像描述

但我希望可以这样显示

在此处输入图像描述

标签: javascriptthree.js

解决方案


您可以在片段着色器中设置球体像素的不透明度:

在此处输入图像描述

body, canvas { 
  margin: 0;  
  width: 100%;
  height: 100%;
  overflow: hidden;
  background-color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/104/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/controls/TransformControls.js"></script>
<script>
  var scene = new THREE.Scene();
  var camera = new THREE.PerspectiveCamera(75, innerWidth/innerHeight, 0.01, 1000);
  camera.position.set(5,5,0);
  var renderer = new THREE.WebGLRenderer();
  renderer.setSize(innerWidth,innerHeight);
  document.body.appendChild(renderer.domElement);
  let orbit = new THREE.OrbitControls(camera, renderer.domElement);
  scene.add(new THREE.GridHelper(500, 100, 0x666666, 0x444444));
  let s1 = sphere(3,  2, 0)
  let s2 = sphere(3, -2, 1)
  let u1 = s1.material.uniforms, u2 = s2.material.uniforms;
  requestAnimationFrame( render );
  
  function sphere(radius, position, color){
      color = color.toFixed(1)
      var geometry = new THREE.SphereGeometry(radius, 50, 50);
      var material = new THREE.ShaderMaterial({
          transparent: true,
          depthWrite: false,
          side: THREE.DoubleSide,
          uniforms: {c: {type: "3f"}, o: {type: "3f"}},
          vertexShader:   `
            varying vec3 p;
            void main() {
              // transfer vertex position to fragment shader, 
              // this value is interpolated by gpu hardware between pixels of triangle, 
              // containing this vertex
              p = position; 
              gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }`,
          fragmentShader: `
            varying vec3 p;  // position of current pixel relative to sphere center
            uniform vec3 c;  // center of current sphere
            uniform vec3 o;  // center of opposite sphere
            void main() {
               vec3 a = abs(p)*50.0;  
               float opacity = a.x<1. || a.y<1. || a.z<1. ? 0.8 : 0.3;               
               // here is test of shpere overlapping   
               opacity = distance(o, p + c) < 3.0 ? 0.0 : opacity; 
               gl_FragColor = vec4(vec3(${color}, 0.0, 1.0 - ${color}), opacity);
            }`
      });
      let mesh = new THREE.Mesh(geometry, material);
      mesh.translateX(position)
      scene.add(mesh);
      let control = new THREE.TransformControls(camera, renderer.domElement);
      control.addEventListener('dragging-changed', e => orbit.enabled = !e.value);
      scene.add(control);
      control.attach(mesh)
      return mesh;
  }

  function render() {
      requestAnimationFrame( render );
      let p1 = s1.position, p2 = s2.position;
      u2.o.value = u1.c.value = [p1.x, p1.y, p1.z];
      u1.o.value = u2.c.value = [p2.x, p2.y, p2.z];
      u1.c.needUpdate = u1.o.needUpdate = 
      u2.c.needUpdate = u2.o.needUpdate = true;   
      renderer.render( scene, camera );
  }
</script>


推荐阅读