相对于相机,Three.js立方体面旋转向量

7
我有一个旋转的球体,上面附着一个div,示例可以在此处查看:https://jsfiddle.net/ao5wdm04/。我计算x和y值,并使用translate3d变换将div放置在正确的位置,这个方法运行地相当不错。
我的问题是如何获得rotateXrotateYrotateZrotate3d的值,以使div“切线”于球体表面。我知道立方体网格面朝向球体中心,因此我假设外向法向量相对于相机的旋转矢量包含我需要的值。但我不太确定如何获得这些值。 更新 通过使用欧拉角,我几乎实现了所需效果,效果如下: https://jsfiddle.net/ao5wdm04/1/ 但旋转不够大。

这个fiddle展示了如何混合使用WebGLRendererCSS3DRenderer。在我的Chrome浏览器中可以正常运行,但可能会出现一些问题。你能否在你的应用程序中使用THREE.PlaneGeometry代替div并避免使用CSS3D呢? - WestLangley
这是一个不错的想法,但在Safari中无法工作,CSS变换不可行吗? - Andreas Jarbol
抱歉,我不确定发生了什么。考虑只使用“WebGLRenderer”。 - WestLangley
2个回答

2

免责声明:我对three.js一无所知。我只了解了一点OpenGL。

你的欧拉角来自于一个模型-视图-投影的原点(第74至80行)。我看不出这背后的逻辑。

如果你的

在球面表面上,那么它应该由球面在
位置处的法向量定向。幸运的是,你已经有了这些角度。它们被命名为rotation

如果你使用用于定位

的旋转角度替换第82-84行的欧拉角,那么在我的浏览器中,当
在圆的边缘时,它会呈边缘姿态,在中心时则会呈正面姿态。它看起来像是沿着一条边贴着屏幕移动的圆形。这是你想要的效果吗?

我对链接代码进行了修改:

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)';

我不知道纬度应该如何在initrender函数之间传递。正如我所说,我不熟悉这种语言。


好吧,那只有在圆放置在赤道时才有效。如果我将第27行更改为0以外的其他内容(例如45),圆形将无法正确旋转。 - Andreas Jarbol
谢谢,这正是我想要的效果! - Andreas Jarbol

0

关于openGL或其他图形中的变换和旋转的详细信息,请查看此处


基础 -

在3D世界中,基本上有两种变换方式-

  1. 平移
  2. 旋转

enter image description here

这里有一个关于这些东西的小例子在这里


如果您仔细阅读所有内容,我认为您对3D变换系统有了清晰的概念。

如果您能理解这些,那么您可以轻松模拟它 :) 因为每次移动都需要同时完成这两个步骤。

尝试这段代码-

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>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接