3. js, Расчет матрицы преобразования между двумя состояниями позиции BufferGeometry - PullRequest
1 голос
/ 18 июня 2020

Я работаю над проектом AR, где AI обнаружения объектов возвращает вершины обнаруженного объекта.

На сцене у меня есть обнаруженный объект как родительский я sh с BufferGeometry и position attributes обновлено из вывода AI, мне нужно вычислить его матрицу преобразования, когда вершины меняются, и применить это преобразование к его дочерним элементам. ) от одного «обнаружения (положение вершин)» к другому.

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

https://jsfiddle.net/uv76tj89/1/

Спасибо.

1 Ответ

1 голос
/ 18 июня 2020

Если вы знаете, что дочерняя геометрия будет вдвое меньше родительской, просто примените child.scale.set(0.5, 0.5, 0.5);, а затем назначьте те же позиции вершин, что и родительская геометрия при обновлении:

parentGeometry.getAttribute('position').array = parentPositions[posIndex];
parentGeometry.getAttribute('position').needsUpdate = true;
childGeometry.getAttribute('position').array = parentPositions[posIndex];
childGeometry.getAttribute('position').needsUpdate = true;

Движок 3. js применит масштаб 1/2 и +5 к оси z к дочерним вершинам, поэтому вам не нужно беспокоиться о ручном внесении этих корректировок. См. Демонстрацию ниже.

(Обратите внимание, что я создал Float32Array s в parentPositions[] в качестве оптимизации, поэтому вам не нужно создавать новый массив и новый BufferAttribute каждый раз, когда вы их обновляете. Это не заметно прироста производительности всего с 4 вершинами, но помогает, когда у вас есть тысячи вершин).

var scene = new THREE.Scene();
var camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 1000 );
var renderer = new THREE.WebGLRenderer({antialias : true});
renderer.setClearColor(0x444444);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
camera.position.z = 100;
new THREE.OrbitControls( camera, renderer.domElement );

/* Helpers */
// Grid helper
var width = 100;
var height = 100;
var gridHelper = new THREE.GridHelper(width * 2, 10, 0x999999, 0x000000);
gridHelper.position.y = -height / 2;
scene.add(gridHelper)
// Axes helper
scene.add(new THREE.AxesHelper(50));

/* parent Mesh */
var parentGeometry = new THREE.PlaneBufferGeometry(width, height);
var parentMaterial = new THREE.MeshBasicMaterial( { color:  0x209ad6} );
var parent = new THREE.Mesh( parentGeometry, parentMaterial );
scene.add(parent);


/* Child mesh */
var childGeometry = new THREE.PlaneBufferGeometry(width, height);
var childMaterial = new THREE.MeshBasicMaterial( {color:  0xFF0000} );
var child = new THREE.Mesh( childGeometry, childMaterial );
parent.add(child);

// Apply desired transformations to the child Mesh
child.position.z = 5;
child.scale.set(0.5, 0.5, 0.5);

/* Parent positions */
// Make all position arrays Float32Array
// so we don't have to create a new one each frame.
var parentPositions = [
	//Reference point
  new Float32Array([
    -50, 50, 0,
    50, 50, 0,
    -50, -50, 0,
    50, -50, 0
  ]),
  //Variations
	new Float32Array([
     -50, 50, 50,
      50, 50, 50,
      -50, -50, -50,
      50, -50, -50
	]),
  new Float32Array([
     -75, 75, -25,
      75, 75, -25,
      -75, -75, 25,
      75, -75, 25
	]),
  new Float32Array([
     0, 75, -25,
      75, 0, -25,
      -75, 0, 25,
      0, -75, 25,  
	]),
  //... random positions
];

var lastTime = 0;
var posIndex = 0;

function render(currentTime) {
  requestAnimationFrame( render );
  
  // Update position attributes
  // Instead of making a new attribute on each update
   if (currentTime >= lastTime + 1000)  {
     parentGeometry.getAttribute('position').array = parentPositions[posIndex];
     parentGeometry.getAttribute('position').needsUpdate = true;
     childGeometry.getAttribute('position').array = parentPositions[posIndex];
     childGeometry.getAttribute('position').needsUpdate = true;

     lastTime = currentTime;
     posIndex = posIndex === 3 ? 0 : posIndex + 1;
  }

  
  

  renderer.render( scene, camera );
}
render()
html, body {margin: 0; padding: 0;overflow: hidden;}
<script src="https://cdn.jsdelivr.net/npm/three@0.117.1/build/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r110/examples/js/controls/OrbitControls.js"></script>

Я не уверен, почему вы изначально сделали ребенка PlaneGeometry, но мне пришлось изменить его, чтобы он соответствовал родительскому PlaneBufferGeometry .

Изменить:

Думаю, я только сейчас начинаю понимать, в чем ваша проблема, и вам нужно рассчитать вектор, перпендикулярный вашей плоскости лица. Для этого вы можете выбрать любые три из четырех вершин: enter image description here

Вы можете использовать этот ответ , чтобы выяснить, в какую точку указывает треугольник. , а затем вы можете указать child в этом направлении с помощью child.lookAt(x, y, z);

Вы можете прочитать эту статью , чтобы получить более подробное объяснение как получить этот перпендикуляр.

...