老板看了一下,然后脑补一下整个页面的效果说还是不要这样子,很多模型都这样运动的话画面太乱了,最后决定的是简单点直接把所有模型摆放成一个球体形状,然后模型不单独运动,而是整体绕中心转,这个实现起来比较简单思路是直接设置外层模型y轴旋转就可以了。
四、所有模型在空间里的位置
整体的运动效果描绘出来了,接着就是开始实施了。接着遇到了一个算是比较坑的问题。那就是模型在空间位置的确认了,由于对3D场景的不熟悉,将所有模型摆出一个球体就有点困难了。只能求助设计大神了,然后他在C4D中将所有模型摆成一个球体之后,然后像操作模型一样导了一份obj给我。然后我利用Blender打开(如下图六所示),然后我看了下,每个模型在软件中都存在一个x,y,z值,我抱着侥幸的心里把所有模型的x,y,z记录下来然后填到页面中。最后发现球体的形状出来了,只是距离有点差异,接着想了个投机取巧的办法把所有的x,y,z进行等比的放大缩小,改完效果还不错。最后就是拉着设计师疯狂调整细节方面的问题。效果如下图七所示。
图六 (球体模型)
图七 (页面中渲染效果)
页面的基本样子出来了,剩下的就是页面的交互了,整个难点基本都在这里了。
项目需求:在页面中选中模型,然后选择模型现在在屏幕中间,然后用手指进行360度滑动,点击关闭按钮回到原型原有的位置。
思路:选中模型-->移动某个东西-->绑定旋转事件-->回位。
可以说项目大部分的时间都花在实现这个操作过程中。下面就简单说一下我是怎么去填这些坑的。
五、在页面中选中模型
之后的所有操作都要基于这个模型去做,所有第一步就需要选中这个模型。这个跟以前做的完全不同,然后在官网demo和stackoverflow游荡,因为涉及到屏幕坐标和世界坐标这个概念有种完全懵逼的感觉。还好官网上有demo的支持,参考了demo之后发现,首先获取屏幕坐标的x,y然后想办法转换成向量,接着标准化向量,通过raycaster.intersectObjects的检测来获取选中的模型。功能代码如下:
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1; //鼠标的x到屏幕y轴的距离与屏幕宽的一半的比值 绝对值不超过1 mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1; vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 ).unproject( camera ); raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() ); intersects = raycaster.intersectObjects( objects ); if ( intersects.length > 0 ) { //把选中的对象放到全局变量SELECTED中 SELECTED = intersects[ 0 ].object; }
参考:
模型选中之后然后开始下一步。
六、相机的移动
因为要让选中的模型显示在屏幕中间,于是想了两种方案:
(1)改变选中物体的x,y,z值
经过反复的测试发现改变x,y,z值,模型会在空间中乱窜,把握不好位置。于是就思考其它的方案。
(2)移动相机
移动相机这一块被坑了无数次,因为刚开始对这个相机的原理不是很清楚,就随意试了几个值(可以利用threejs提供的相机辅助线来操作具体参考:),来证明自己的方向是正确的,发现模型确实出现在不同的位置了,然后就继续往下深挖。首先在google中寻找有关threejs中相机的原理,具体参考:,对原理有一定了解之后,然后就想怎么让相机出现在自己想要的位置上。
首先获取到选中模型的世界坐标,然后再根据当前的坐标值改变相机的x,y,z让相机直接照在当前模型上。测试了一下发现选中模型出现在屏幕中间,不过根据模型的不同位置上有偏差,这个后来设置了默认值来修正偏差。效果下图所示:
图八 (相机移动)
功能实现了,然后发现选择之后出现的太突然了,没有体现相机移动的效果,然后就想到使用TweenMax这个动画库来实现平滑过渡的动画。代码如下:
TweenMax.to(camera.position, 1, { x: x, y: y, z: z, ease:Expo.easeInOut, onComplete: function (){} })
加上之后效果如下图所示:
图九 (相机平滑移动)