Threejs применяет отсечение к определенной области объекта

1

Я использую 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!

Вот что я получаю: Изображение 174551

Теги:
three.js

2 ответа

3
Лучший ответ

Да, удаление пересечения плоскостей отсечения поддерживается в три раза. Вы можете использовать шаблон, подобный этому:

// 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.

three.js r.85

  • 0
    Спасибо за ваш ответ. Да, это работает, но только для двух самолетов. Я должен разрезать кость, чтобы соответствовать протезу, поэтому мне нужно несколько плоскостей. когда я добавляю все плоскости в массив localPlanes с включенным clipIntersection, ничто не обрезается вообще!
  • 0
    Спасибо, что подняли это. Я нашел это только после того, как опубликовал свой ответ, и он мне нравится намного лучше, чем я предлагал, у меня просто не было времени, чтобы дать новый ответ.
Показать ещё 6 комментариев
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 верхнюю половину myMesh когда вы вызываете рендер. Поэтому вы хотите работать с остальными.

Сначала сделайте другую плоскость, плоскость plane2, обратной plane1. plane2 затем myMesh BOTTOM myMesh. Но если вы сделаете один проход с использованием plane1, а другой с помощью plane2, то вы вернетесь с полной сеткой. Таким образом, вам понадобится третий клип-самолет, plane3, который plane3 только желаемую половину myMesh. Помещение plane2 и plane3 в один проход рендеринга приведет только к 1/4 рендеринга myMesh.

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();
      })
    })
  })
})();
  • 0
    Спасибо за Ваш ответ. но теперь я получаю эту ошибку: Uncaught TypeError: Cannot read property 'normal' of null at wa.copy (three.min.js:458) at b (three.min.js:130) at ig.setState (three.min.js:131) at n (three.min.js:139) at Xd.renderBufferDirect (three.min.js:171) at f (three.min.js:38) at f (three.min.js:38) at Je.render (three.min.js:42)
  • 0
    Можете ли вы переключиться на использование three.js (а не three.min.js ), чтобы мы могли видеть реальный стек вызовов?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню