吱吱说VR,你怕了吗?
首先,看下demo效果,扫一下下面的二维码:
主要利用浏览器的deviceorientation事件监视设备朝向,记录下其受地心引力作用下而在方向上产生变化的数据,然后使用DeviceOrientationControls.js(一个three.js的插件)让摄像头根据设备的移动进行调整,相当于模拟人看向物体的某个方向,犹如人的视线一样。最后,结合three.js来构建一个3d世界。
1. 画一个会动的太阳
引用three.js, 建立3个要素:场景(scene)、相机(camera)和渲染器(renderer)。有了这三样东西,才能将物体渲染到网页中,然后再画一个太阳。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | var canvas = document.querySelector( '#main-canvas' ); var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1 ,2000); scene.add(camera); //画太阳 var initPlanet = function (name, revolutionSpeed, color, distance, volume, map) { var material; material = new THREE.MeshLambertMaterial({ emissive: 0xdd4422, //发光 map: THREE.ImageUtils.loadTexture(__uri( '../../img/sun.jpg' )) //太阳的皮肤 }); //SphereGeometry用来在三维空间内创建一个球体对象. var mesh = new THREE.Mesh( new THREE.SphereGeometry( volume, 50,50 ), material); mesh.position.x = -distance; mesh.receiveShadow = true ; mesh.castShadow = true ; scene.add(mesh); }; initPlanet(); //由于是会动的,所以调用requestAnimationFrame函数 ( function render(timestamp) { requestAnimationFrame(render); //太阳自转 stars.Sun.Mesh.rotation.y = (stars.Sun.Mesh.rotation.y == 2*Math.PI ? 0.0008*Math.PI : stars.Sun.Mesh.rotation.y+0.0008*Math.PI); renderer.render(scene, camera); }()); |
就这样简单画出了一个太阳。扫二维码看效果。
2. 构建一个太阳系
为了效果好看一点,顺便把其他行星也画上去,实现原理跟太阳的一样。接着就让各行星围绕着太阳转啊转。
1 2 3 4 5 6 7 8 | //RingGeometry用来在三维空间内创建一个二维圆环面对象. //轨道, 以太阳为中心的运动轨道 var track = new THREE.Mesh( new THREE.RingGeometry(distance - 0.2, distance + 0.2, 100, 1), new THREE.MeshBasicMaterial( { color: 0xffffff,transparent: true , opacity: 0.1, side: THREE.DoubleSide } ) ); track.rotation.x = - Math.PI / 2; scene.add(track); |
再画点星星点缀一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | //buffer做星星 var bufferGeometry = new THREE.BufferGeometry(); var gap = 1000; // 定义星星的最近出现位置 for ( var i = 0; i < positions.length; i += 3 ) { // positions //-2gap < x < 2gap var x = ( Math.random() * gap *2 )* (Math.random()<.5? -1 : 1); var y = ( Math.random() * gap *2 )* (Math.random()<.5? -1 : 1); var z = ( Math.random() * gap *2 )* (Math.random()<.5? -1 : 1); /*找出x,y,z中绝对值最大的一个数*/ var biggest = Math.abs(x) > Math.abs(y) ? (Math.abs(x) > Math.abs(z) ? 'x' : 'z' ) : (Math.abs(y) > Math.abs(z) ? 'y' : 'z' ); var pos = { x: x, y: y, z: z}; //如果最大值比n要小(因为要在一个距离之外才出现星星)则赋值为n(-n) if (Math.abs(pos[biggest]) < gap) pos[biggest] = pos[biggest] < 0 ? -gap : gap; x = pos[ 'x' ]; y = pos[ 'y' ]; z = pos[ 'z' ]; positions[ i ] = x; positions[ i + 1 ] = y; positions[ i + 2 ] = z; //70%星星有颜色 var hasColor = Math.random() > 0.3; var vx, vy, vz; if (hasColor){ vx = (Math.random()+1) / 2 ; vy = (Math.random()+1) / 2 ; vz = (Math.random()+1) / 2 ; } else { vx = 1 ; vy = 1 ; vz = 1 ; } color.setRGB( vx, vy, vz ); colors[ i ] = color.r; colors[ i + 1 ] = color.g; colors[ i + 2 ] = color.b; } bufferGeometry.addAttribute( 'position' , new THREE.BufferAttribute( positions, 3 ) ); bufferGeometry.addAttribute( 'color' , new THREE.BufferAttribute( colors, 3 ) ); bufferGeometry.computeBoundingSphere(); //星星的material var material = new THREE.PointsMaterial( { size: 6, vertexColors: THREE.VertexColors } ); var particleSystem = new THREE.Points( bufferGeometry, material ); scene.add( particleSystem ); |
这样就形成一个星空环境了。扫二维码看效果。
3. 创造虚拟现实的分屏效果
最后,也就是关键时刻。
- DeviceOrientationControls.js,一个three.js插件,它帮助我们完成之前提到过的deviceorientation事件,让摄像头根据设备的移动进行调整,形成上帝视角;
- OrbitControls.js,这是一个备用的控制器,当设备不支持deviceorientation事件改用鼠标调整摄像头;
- StereoEffect.js,也一个three.js插件,快速打造虚拟现实分屏效果。
看核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | //绑定deviceorientation事件 function setOrientationControls(e){ //事件监听器提供一组alpha,beta和gamma值。如果没有alpha值就不能通过deviceorientation事件进行控制,转而替代的是OrbitControls.js if (e.alpha) { controls = new THREE.DeviceOrientationControls(camera, true ); //controls.connect(); controls.update(); } window.removeEventListener( 'deviceorientation' , setOrientationControls, true ); } window.addEventListener( 'deviceorientation' , setOrientationControls, true ); //没有alpha值就用鼠标来 controls = new THREE.OrbitControls(camera, canvas); controls.target.set( camera.position.x, camera.position.y, camera.position.z - 0.15 ); controls.noPan = true ; controls.noZoom = true ; //分屏 var effect = new THREE.StereoEffect(renderer); ( function render(timestamp) { ... //renderer.render(scene, camera); effect.render(scene, camera); }()); |
遇到的问题
- three.js的版本要用78,THREE.StereoEffect才有效果,之前用77版的一直无效。
- THREE.ImageUtils.loadTexture 注意图片路径跨域问题
手机阅读请扫描下方二维码:
牛逼
1
1
1
1
1
1
1
1
1
1
1
1
12345678

12345678

12345678

bgsmanqfuqhdwjxgdbgw
12345678

12345678

1
12345678

12345678

12345678

12345678

12345678

12345678

12345678

1

1

555
1

1

1

1

1

1

1

1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1