Три JS группы поворота с той же ориентацией, что и камера для View Cube / Orientation Cube - PullRequest
2 голосов
/ 16 февраля 2020

Я пытаюсь создать вид ориентации blender-esk, который выглядит следующим образом, используя Three JS:

enter image description here

Мой план состоит в том, чтобы возьмите поворот камеры и поверните 3 векторных точки (представляющих X, Y и Z пузыри на рисунке). Затем, получив эти точки, я могу использовать координаты X и Y, чтобы нарисовать круги на холсте и нарисовать линии, чтобы соединить их с центром. Затем я могу использовать направление Z, чтобы определить, что должно быть нарисовано поверх чего.

В настоящее время я использую сцену 2-й три. js, чтобы визуализировать положение этих точек X, Y и Z как Я пытаюсь разными способами повернуть группу вершин, чтобы она соответствовала ориентации камеры. Я борюсь с этой частью, и я попробовал кучу вещей, которые не сработали.

Вот JS Fiddle для того, где я сейчас нахожусь:

https://jsfiddle.net/j9mcL0x4/4/ (не загружается в Brave, но работает в Chrome)

Когда вы перемещаете камеру, она перемещает 3 куба во 2-й сцене но я не могу заставить его вращаться правильно.

Точки X, Y и Z представлены группой Vector3 как:

this.ref = [
  [new THREE.Vector3(1,0,0), 0xFF0000],
  [new THREE.Vector3(0,1,0), 0x00FF00],
  [new THREE.Vector3(0,0,1), 0x0000FF],
]

Затем я создаю каждый куб и добавляю его в группа:

this.group = new THREE.Group();
for(var pos of this.ref) {
  var geometry = new THREE.BoxGeometry(.25,.25,.25);
  var material = new THREE.MeshBasicMaterial({
    color: pos[1]
  });
  var cube = new THREE.Mesh(geometry, material);
  cube.position.copy(pos[0]);
  this.group.add(cube);
}

this.scene.add(this.group);

Затем в своей функции анимации я пытаюсь вычислить вращение для группы, чтобы она была в той же ориентации, что и основной вид:

var quaternion = new THREE.Quaternion();
camera.getWorldQuaternion( quaternion );

let rotation = new THREE.Euler();
rotation.setFromQuaternion(quaternion);

var dir = new THREE.Vector3();
dir.subVectors( camera.position, controls.target ).normalize();

orientationHelper.group.rotation.set(dir.x, dir.y, dir.z);
orientationHelper.animate();

То, что у меня есть, совершенно неправильно, но вот некоторые вещи, которые я пробовал:

  • Рассчитайте точку перед камерой, затем используйте ее, чтобы заставить группу смотреть в этом направлении, используя lookAt function
  • Я использую элементы управления орбитой, цель которой сфокусирована на камере. Я попытался вычесть вектор положения камеры и целевой вектор, чтобы получить направление взгляда, но это не сработало (что сейчас находится в jsfiddle)
  • Я попытался использовать только локальное вращение камеры (и попытался отменить это)

Примечание Я мог бы повернуть камеру во 2-й сцене, чтобы соответствовать камере на главном виде, но я действительно хочу вращать сами векторы. Поэтому я могу взять эти точки и спроецировать их на основание c, чтобы нарисовать 6 кругов и 3 линии. Я чувствую, что это будет намного проще, чем пытаться использовать спрайты в 3d, и Три JS не могут легко рисовать толстые линии, не создавая прямоугольные angular сетки для этого.

Вот несколько примеров того, как должен выглядеть вывод:

enter image description here

enter image description here

Обновление

Эта проблема была решена Rabbid76, и если кто-то заинтересован в использовании ориентационного куба Blender Style для своего проекта, вы можете найти полный исходный код здесь:

https://github.com/jrj2211/three-orientation-gizmo/

1 Ответ

1 голос
/ 16 февраля 2020

Прежде всего в области просмотра, ось X направлена ​​вправо, ось Y направлена ​​вверх, а ось Z направлена ​​за пределы холста.
Таким образом, вы должны выбрать начальную позицию для OrientationHelper камера на положительной оси Z:

class OrientationHelper {
    constructor(canvas) {
        // [...]

        this.camera = new THREE.PerspectiveCamera(75, size / size, 0.1, 1000);
        this.camera.position.set(0, 0, 2);

        // [...]

Далее я рекомендую установить ориентацию группы в сцене OrientationHelper с помощью матрицы:

class OrientationHelper {
    // [...]

    setCameraRotation(rotation) {
        this.group.setRotationFromMatrix(rotation);
    }

    // [...]

Матрица просмотра - это обратная матрица этой матрицы, которая определяет положение и ориентацию камеры. Вы хотите визуализировать ориентацию камеры. Вы хотите визуализировать ориентацию матрицы вида.
Создать матрицу вращения из camera.rotation. Вычислите Обратную матрицу и установите ориентацию OrientationHelper по вычисленной матрице:

let rotMat = new THREE.Matrix4().makeRotationFromEuler(camera.rotation);
let invRotMat = new THREE.Matrix4().getInverse(rotMat); 

orientationHelper.setCameraRotation(invRotMat);
orientationHelper.update();

См. Пример:

class OrientationHelper {
  constructor(canvas) {
    this.canvas = canvas;
    
    this.ref = [
      [new THREE.Vector3(1,0,0), 0xFF0000],
      [new THREE.Vector3(0,1,0), 0x00FF00],
      [new THREE.Vector3(0,0,1), 0x0000FF],
    ]

    var size = 200;
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(75, size / size, 0.1, 1000);
    this.camera.position.set(0, 0, 2);

    this.renderer = new THREE.WebGLRenderer({alpha: true});
    this.renderer.setSize(size, size);
    canvas.appendChild(this.renderer.domElement);
    
    var controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
    
    var geometry = new THREE.SphereGeometry( .1, 32, 32 );
    var material = new THREE.MeshBasicMaterial( {color: 0xffffff} );
    var sphere = new THREE.Mesh( geometry, material );
    this.scene.add( sphere );

    this.group = new THREE.Group();
    for(var pos of this.ref) {
      var geometry = new THREE.BoxGeometry(.25,.25,.25);
      var material = new THREE.MeshBasicMaterial({
        color: pos[1]
      });
      var cube = new THREE.Mesh(geometry, material);
      cube.position.copy(pos[0]);
      this.group.add(cube);
    }

    this.scene.add(this.group);
  }

  setCameraRotation(rotation) {
    this.group.setRotationFromMatrix(rotation);
  }
  
  update() {
  	this.renderer.render(this.scene, this.camera);
  }
}

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);
camera.position.set(0, 3, 3);
controls.update();

//controls.autoRotate = true;

var size = 10;
var divisions = 10;

var gridHelper = new THREE.GridHelper(size, divisions);
scene.add(gridHelper);

var axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

 // material
  var material = new THREE.MeshBasicMaterial({
    color: 0xffffff,
    vertexColors: THREE.FaceColors
  });

var geometry = new THREE.BoxGeometry();

 // colors
  red = new THREE.Color(1, 0, 0);
  green = new THREE.Color(0, 1, 0);
  blue = new THREE.Color(0, 0, 1);
  var colors = [red, green, blue];
  
  for (var i = 0; i < 3; i++) {
    geometry.faces[4 * i].color = colors[i];
    geometry.faces[4 * i + 1].color = colors[i];
    geometry.faces[4 * i + 2].color = colors[i];
    geometry.faces[4 * i + 3].color = colors[i];
  }
  
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// Orientation
var orientationHelper = new OrientationHelper(document.getElementById("orientation-helper"));

function animate() {
  requestAnimationFrame(animate);
  controls.update();

  let rotMat = new THREE.Matrix4().makeRotationFromEuler(camera.rotation);
  let invRotMat = new THREE.Matrix4().getInverse(rotMat); 
  orientationHelper.setCameraRotation(invRotMat);
	orientationHelper.update();
  
  renderer.render(scene, camera);
}

animate();
body { margin: 0; }
canvas { display: block; }
#orientation-helper { position: absolute; top: 10px; left: 10px; background: #505050; }
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/examples/js/controls/OrbitControls.js"></script>
<div id='orientation-helper'></div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...