Threejs将剪裁应用于对象的特定区域

时间:2017-06-02 09:43:45

标签: javascript three.js

我正在使用THREE.Plane剪辑我的STL模型。

localPlane = new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), 4);
.
.
.
material = new THREE.MeshPhongMaterial( {
    color: 0xffffff,
    side: THREE.DoubleSide,
    clippingPlanes: [
        localPlane,
    ],
    clipShadows: true
} );

它正在运作;但问题是整个物体的顶部被这个无限大小的平面修剪掉了。我希望它只剪辑它的一小部分(似乎没有办法扩展THREE.Plane)

我也尝试过使用ThreeCSG.js,但对STL对象来说似乎不方便!

这是我得到的: The whole model is cut through top

2 个答案:

答案 0 :(得分:3)

是的,在three.js中支持删除剪切平面的交叉点。你可以使用这样的模式:

// clipping planes
var localPlanes = [
    new THREE.Plane( new THREE.Vector3( - 1, 0, 0 ), 1 ),
    new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 1 )
];

// material
var material = new THREE.MeshPhongMaterial( {
    color: 0xffffff,
    side: THREE.DoubleSide,
    clippingPlanes: localPlanes,
    clipIntersection: true
} );

另请参阅three.js example

three.js r.85

答案 1 :(得分:1)

编辑: 按照WestLangley的建议。我会把她留给她作为替代但不那么有效的执行裁剪的方法。

剪切平面是无限的。没有解决这个问题。所以,你可以做什么?多个渲染过程中的多个剪裁平面!

为此,您需要关闭自动清除功能,并自行清除手动缓冲区。

renderer = new THREE.WebGLRenderer();    
renderer.autoClear = false;

现在让我们说plane1是你现在拥有的剪裁平面。

material = new THREE.MeshPhongMaterial( {
    ...
    clippingPlanes: [
        plane1,
    ],
    clipShadows: true
} );

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

当您调用渲染时,它会剪切myMesh的上半部分。所以你想和剩下的人一起工作。

首先,使另一个平面plane2成为plane1的倒数。然后plane2会剪切myMesh的底部。但是,如果使用plane1渲染一个传递,使用plane2渲染另一个传递,那么您将使用完整网格渲染。因此,您需要第三个剪裁平面plane3,它仅剪切myMesh的所需部分。将plane2plane3放在同一个渲染过程中只会导致myMesh渲染的1/4。

var pass1ClipPlanes = [
        plane1
    ],
    pass2ClipLanes = [
        plane2, // this plane is the inverse of plane 1, so it clips the opposite of plane1
        plane3 // this clips the left/right half of the model
    ];

然后当你去渲染时,首先清除绘制缓冲区,然后调用两个渲染过程,更新它们之间的剪裁平面。

// clear the draw buffers
renderer.clear();

// clip the top
myMesh.material.clipPlanes = pass1ClipPlanes;
renderer.render(scene, camera);

// clip the bottom and one side
myMesh.material.clipPlanes = pass2ClipPlanes;
renderer.render(scene, camera);

第一遍渲染模型的底部,第二遍渲染顶部的一半。

ETA:示例

var renderer, scene, camera, controls, stats;

var cube,
  pass1ClipPlanes,
  pass2ClipPlanes;

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

function init() {
  document.body.style.backgroundColor = "slateGray";

  renderer = new THREE.WebGLRenderer({
    antialias: true,
    alpha: true
  });
  renderer.localClippingEnabled = true;
  renderer.autoClear = false;

  document.body.appendChild(renderer.domElement);
  document.body.style.overflow = "hidden";
  document.body.style.margin = "0";
  document.body.style.padding = "0";

  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
  camera.position.z = 50;
  scene.add(camera);

  controls = new THREE.TrackballControls(camera, renderer.domElement);
  controls.dynamicDampingFactor = 0.5;
  controls.rotateSpeed = 3;

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

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

  resize();
  window.onresize = resize;

  // POPULATE EXAMPLE
  var plane1 = new THREE.Plane(new THREE.Vector3(0, -1, 0), 0),
    plane2 = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
    plane3 = new THREE.Plane(new THREE.Vector3(-1, 0, 0), 0);
  pass1ClipPlanes = [plane1];
  pass2ClipPlanes = [plane2, plane3];

  var cubeGeo = new THREE.BoxBufferGeometry(10, 10, 10),
    cubeMat = new THREE.MeshPhongMaterial({
      color: "red",
      side: THREE.DoubleSide
    });
  cube = new THREE.Mesh(cubeGeo, cubeMat);
  scene.add(cube);

  animate();
}

function resize() {
  WIDTH = window.innerWidth;
  HEIGHT = window.innerHeight;
  if (renderer && camera && controls) {
    renderer.setSize(WIDTH, HEIGHT);
    camera.aspect = WIDTH / HEIGHT;
    camera.updateProjectionMatrix();
    controls.handleResize();
  }
}

function render() {
  renderer.clear();
  cube.material.clippingPlanes = pass1ClipPlanes;
  renderer.render(scene, camera);
  cube.material.clippingPlanes = pass2ClipPlanes;
  renderer.render(scene, camera);
}

function animate() {
  requestAnimationFrame(animate);
  render();
  controls.update();
  stats.update();
}

function threeReady() {
  init();
}

(function() {
  function addScript(url, callback) {
    callback = callback || function() {};
    var script = document.createElement("script");
    script.addEventListener("load", callback);
    script.setAttribute("src", url);
    document.head.appendChild(script);
  }

  addScript("https://threejs.org/build/three.js", function() {
    addScript("https://threejs.org/examples/js/controls/TrackballControls.js", function() {
      addScript("https://threejs.org/examples/js/libs/stats.min.js", function() {
        threeReady();
      })
    })
  })
})();