Вектор вращения грани куба Three.js относительно камеры

У меня есть вращающаяся сфера, к которой прикреплен div, пример можно посмотреть здесь: https://jsfiddle.net/ao5wdm04/ Я вычисляю значения x и y и размещаю div, используя преобразование translate3d, и это работает достаточно хорошо.

Мой вопрос заключается в том, как получить значения для преобразований rotateX, rotateY и rotateZ или rotate3d, чтобы div «касался» поверхности сферы. Я знаю, что сетка куба обращена к центру сферы, поэтому я предполагаю, что вектор вращения обращенного наружу вектора нормали по отношению к камере будет содержать нужные мне значения. Но я не совсем уверен, как их получить.

Обновить

Используя углы Эйлера, я почти достиг желаемого эффекта, показанного здесь: https://jsfiddle.net/ao5wdm04/1/, но вращение недостаточно велико.


person Andreas Jarbol    schedule 29.02.2016    source источник
comment
Эта скрипта показывает, как смешивать WebGLRenderer и CSS3DRenderer. У меня работает в Chrome, но могут быть некоторые проблемы. Можете ли вы использовать THREE.PlaneGeometry вместо div для своего приложения и избежать использования CSS3D?   -  person WestLangley    schedule 04.03.2016
comment
Это хорошая мысль, однако она не работает в Safari, разве CSS-преобразования нежизнеспособны?   -  person Andreas Jarbol    schedule 06.03.2016
comment
Извините, я не знаю, что происходит. Рассмотрите возможность использования только WebGLRenderer.   -  person WestLangley    schedule 06.03.2016


Ответы (2)


Отказ от ответственности: я ничего не знаю о three.js. Я только что сделал немного OpenGL.

Ваши углы Эйлера исходят из проецируемого вида модели (строки 74-80). Я не вижу в этом логики.

Если ваш div находится на поверхности сферы, то он должен быть ориентирован по нормали сферы в том месте, где находится div. К счастью, у вас уже есть эти углы. Их зовут rotation.

Если вы замените углы Эйлера в строках 82-84 углами поворота, используемыми для позиционирования элемента div, то в моем браузере элемент div отображается ребром, когда он находится на краю круга, и лицевой стороной, когда он находится в центре. Кажется, что он движется по кругу, краем к экрану. Это тот эффект, который вы хотите?

Моя модификация связанного кода:

82 var rotX = (rotation.x * (180/ Math.PI));
83 var rotY = (rotation.y * (180/ Math.PI));
84 var rotZ = 0;

ИЗМЕНИТЬ

Ах хорошо. Переменная rotation — это просто переменная камеры. Он управляет касательной на экваторе. Вам также необходимо изменить ориентацию, чтобы учесть широту.

Сделайте rotY равным минусу вашей широты. Затем убедитесь, что это вращение происходит до экваториального вращения. Повороты не коммутативны.

Таким образом, изменения кода на странице https://jsfiddle.net/ao5wdm04/1/ таковы: следует:

27 var lat = 45 * Math.PI / 180;
...
82 var rotX = (rotation.x * (180/ Math.PI));
83 var rotY = - 45;
...
88 document.getElementById('face').style.webkitTransform = 'translate3d(' + x + 'px,' + y + 'px,0px) rotateY('+rotX+'deg) rotateX('+rotY+'deg)';

Я не знаю, как широта должна распространяться между функциями init и render. Как я уже сказал, я не знаю языка.

person Bill    schedule 10.03.2016
comment
Хорошо, это сработает, только если круг расположен на экваторе. Если я изменю строку 27 на значение, отличное от 0 (т.е. 45), круг повернется неправильно. - person Andreas Jarbol; 15.03.2016
comment
Спасибо, именно такого эффекта я и добивался! - person Andreas Jarbol; 18.03.2016

Для получения подробной информации о преобразовании и вращении в openGL или любой другой графике перейдите здесь< /а>.


Базовый

В основном существует 2 вида преобразований в 3D-мире:

  1. Перевод
  2. Вращение

введите здесь описание изображения

Небольшой пример по этому поводу приведен здесь.


Если вы пройдете их все, я думаю, у вас будет четкое представление о системе 3D-преобразования.

Если вы можете их понять, вы можете легко смоделировать это :), потому что вам нужно делать 2 вещи для каждого движения одновременно.

Попробуйте этот код-

var camera, scene, renderer, raycaster, geometry, material, mesh, box;
var rotation = {
  x: 0,
  y: 0
};
var distance = 500;

init();
animate();

function init() {
  raycaster = new THREE.Raycaster(); ;
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.z = distance;
  camera.position.y = 100;
  scene.add(camera);

  geometry = new THREE.SphereGeometry(100, 50, 50, 50);
  material = new THREE.MeshNormalMaterial();

  mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  var transform = new THREE.Matrix4().getInverse(scene.matrix);

  var lat = 0 * Math.PI / 180;
  var lon = 90 * Math.PI / 180;
  var r = 100;
  var p = new THREE.Vector3(-r * Math.cos(lat) * Math.cos(lon),
    r * Math.sin(lat),
    r * Math.cos(lat) * Math.sin(lon)
  );
  p.applyMatrix4(transform);

  var geometry = new THREE.CubeGeometry(10, 10, 10);
  box = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
    color: 0xff0000,
    
  }));
  box.position.set(p.x, p.y, p.z);
  box.lookAt(mesh.position);
  //scene.add(box);
  box.updateMatrix();

  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);

  document.body.appendChild(renderer.domElement);

}

function animate() {

  requestAnimationFrame(animate);
  render();
}

function render() {

  rotation.x += 0.01;
  camera.position.x = distance * Math.sin(rotation.x) * Math.cos(rotation.y);
  camera.position.y = distance * Math.sin(rotation.y);
  camera.position.z = distance * Math.cos(rotation.x) * Math.cos(rotation.y);

  camera.lookAt(mesh.position);

  var w = window.innerWidth;
  var h = window.innerHeight;

  var mat = new THREE.Matrix4();
  var v = new THREE.Vector3();

  mat.copy(scene.matrix);
  mat.multiply(box.matrix);
  v.set(0, 0, 0);
  v.applyMatrix4(mat);
  v.project(camera);
  
  var euler = new THREE.Euler().setFromVector3(v);
  
  var rotX = (rotation.x * (180/ Math.PI));
  var rotY = (rotation.y * (180/ Math.PI));
  var rotZ = 0;
  
  var x = (w * (v.x + 1) / 2) - 12.5; //compensate the box size
  var y = (h - h * (v.y + 1) / 2) - 12.5;
  document.getElementById('face').style.webkitTransform = 'translate3d(' + x + 'px,' + y + 'px,0px) rotateX('+rotY+'deg) rotateY('+rotX+'deg) rotateZ('+rotZ+'deg)';

  renderer.render(scene, camera);

}
#face {
  position: absolute;
  width: 25px;
  height: 25px;
  border-radius: 50%;
  background-color: red;
}
<script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>

<div id="face"></div>

person Abrar Jahin    schedule 11.03.2016