我有一个旋转的球体,我附上了一个div,这个例子可以在这里查看:https://jsfiddle.net/ao5wdm04/
我计算了x和y值并使用translate3d
变换放置了div,这非常有用。
我的问题是如何获取rotateX
,rotateY
和rotateZ
或rotate3d
变换的值,以便div“切线”球体表面。我知道立方体网格面向球体中心,所以我假设相对于相机的向外法线向量的旋转向量将包含我需要的值。但我不太清楚如何获得这些。
更新
通过使用欧拉角,我几乎达到了预期的效果,如下所示:https://jsfiddle.net/ao5wdm04/1/但旋转不够大。
答案 0 :(得分:2)
免责声明:我对three.js
一无所知。我刚刚完成了一些OpenGL。
您的欧拉角来自模型视图投影的原点(第74-80行)。我无法看到这背后的逻辑。
如果你的div在球体表面上,那么它应该被div的位置处的球体法线定向。幸运的是,你已经拥有了这些角度。它们被命名为rotation
。
如果用第82-84行中的euler角度替换用于定位div的旋转角度,那么在我的浏览器中,当div位于圆的边缘时div显示为边缘,而当它位于圆的边缘时则显示为on中心。它看起来像是在一个圆圈中移动,边缘在屏幕上。这是你想要的效果吗?
我对链接代码的修改:
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
函数之间传播。正如我所说,我不熟悉这种语言。
答案 1 :(得分:0)
有关openGL或任何其他图形中的变换和旋转的详细信息,请浏览here。
基本 -
3D世界中基本上有两种转换 -
关于这件事的一个小例子是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>
&#13;