如何通过three.js隐藏两个3d对象的交集?

时间:2019-06-29 05:54:12

标签: javascript three.js

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

有两个领域是“ S-红色”和“ S-蓝色”

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

enter image description here

但我希望可以这样显示

enter image description here

1 个答案:

答案 0 :(得分:0)

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

enter image description here

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>