Три. js определяют, когда объект частично и полностью перекрыт - PullRequest
1 голос
/ 30 января 2020

Я пытаюсь определить, когда объект в тройке. js частично и полностью перекрыт (скрыт) другим объектом.

Мое текущее простое решение направляет один луч в центр объект:

function getScreenPos(object) {
  var pos = object.position.clone();
  camera.updateMatrixWorld();
  pos.project(camera);
  return new THREE.Vector2(pos.x, pos.y);
}

function isOccluded(object) {
  raycaster.setFromCamera(getScreenPos(object), camera);
  var intersects = raycaster.intersectObjects(scene.children);
  if (intersects[0] && intersects[0].object === object) {
    return false;
  } else {
    return true;
  }
}

Однако он не учитывает размеры объекта (ширина, высота, глубина).

Не перекрывается (поскольку центр объекта не находится позади) Object not occluded

закрыто (потому что центр объекта находится позади) Object occluded

Просмотреть рабочую демонстрацию:

https://jsfiddle.net/kmturley/nb9f5gho/57/

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

var box = new THREE.Box3().setFromObject(object);
var size = box.getSize();

Я хотел бы найти более надежный подход, который мог бы дать логические значения partially occluded и fully occluded или, может быть, даже percentage occluded?

Ответы [ 2 ]

1 голос
/ 31 января 2020

Мне удалось получить рабочую версию для WebGL1, основанную на ответе TheJim01!

Сначала создайте вторую более простую сцену, чтобы использовать ее для расчетов:

pickingScene = new THREE.Scene();
pickingTextureOcclusion = new THREE.WebGLRenderTarget(window.innerWidth / 2, window.innerHeight / 2);
pickingMaterial = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors });
pickingScene.add(new THREE.Mesh(BufferGeometryUtils.mergeBufferGeometries([
  createBuffer(geometry, mesh),
  createBuffer(geometry2, mesh2)
]), pickingMaterial));

Воссоздайте ваши объекты как геометрию буфера ( быстрее для производительности):

function createBuffer(geometry, mesh) {
  var buffer = new THREE.SphereBufferGeometry(geometry.parameters.radius, geometry.parameters.widthSegments, geometry.parameters.heightSegments);
  quaternion.setFromEuler(mesh.rotation);
  matrix.compose(mesh.position, quaternion, mesh.scale);
  buffer.applyMatrix4(matrix);
  applyVertexColors(buffer, color.setHex(mesh.name));
  return buffer;
}

Добавить цвет, основанный на me sh .name, например, id 1, 2, 3, et c

function applyVertexColors(geometry, color) {
  var position = geometry.attributes.position;
  var colors = [];
  for (var i = 0; i < position.count; i ++) {
    colors.push(color.r, color.g, color.b);
  }
  geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
}

Затем во время рендер l oop проверяет вторую сцену на эту текстуру и сопоставляет данные пикселей с именем me sh:

function isOccludedBuffer(object) {
  renderer.setRenderTarget(pickingTextureOcclusion);
  renderer.render(pickingScene, camera);
  var pixelBuffer = new Uint8Array(window.innerWidth * window.innerHeight);
  renderer.readRenderTargetPixels(pickingTextureOcclusion, 0, 0, window.innerWidth / 2, window.innerHeight / 2, pixelBuffer);
  renderer.setRenderTarget(null);
  return !pixelBuffer.includes(object.name);
}

Рабочую демонстрацию WebGL1 можно посмотреть здесь:

https://jsfiddle.net/kmturley/nb9f5gho/62/

Одно замечание, которое следует отметить при таком подходе, заключается в том, что ваша сцена выбора должна оставаться в курсе изменений в основной сцене . Так что, если ваши объекты перемещаются по положению / повороту и т. Д. c, их также необходимо обновить в сцене выбора. В моем примере камера движется, а не объекты, поэтому она не нуждается в обновлении.

Для WebGL2 у нас будет лучшее решение:

https://tsherif.github.io/webgl2examples/occlusion.html

Но это поддерживается не во всех браузерах:

https://www.caniuse.com/#search = webgl

1 голос
/ 30 января 2020

Переполнение стека поиска и три. js примера для «выбора GPU». Концепцию можно разбить на три основных шага c:

  1. Измените материал каждой фигуры на уникальный плоский (MeshBasicMaterial) цвет.
  2. Визуализируйте сцену с помощью уникальные материалы.
  3. Считайте пиксели визуализированной рамки, чтобы собрать информацию о цвете.

Ваш сценарий позволяет вам сделать несколько предостережений.

  1. Дайте только форма, которую вы тестируете, имеет уникальный цвет - все остальное может быть черным.
  2. Вам не нужно визуализировать всю сцену, чтобы протестировать одну форму. Вы можете настроить область просмотра так, чтобы отображалась только область, окружающая фигуру, о которой идет речь.
  3. Поскольку вы задали цвет только для тестовой части, остальные данные должны быть равны нулю, что позволяет найти пиксели, соответствующие вашему уникальному цвету. намного проще.

Теперь, когда у вас есть данные о пикселях, вы можете определить следующее:

  • Если ни один пиксель не соответствует уникальному цвету, то форма полностью закрыта.
  • Если НЕКОТОРЫЕ пиксели соответствуют уникальному цвету, то форма по крайней мере частично видима.

Вторая пуля говорит, что форма "по крайней мере частично" видимый. Это потому, что вы не можете проверить полную видимость с информацией, которая у вас есть на данный момент.

То, что I сделает (а у кого-то еще может быть лучшее решение), отрендерте тот же видовой экран во второй раз, но видна только тестовая форма, которая эквивалентна полностью видимой части. Имея эту информацию в руках, сравните пиксели с первым рендером. Если у обоих одинаковое количество (возможно, в пределах допуска) пикселей уникального цвета, можно сказать, что часть полностью видима / не закрыта.

...