吱吱说VR,你怕了吗?
首先,看下demo效果,扫一下下面的二维码:
主要利用浏览器的deviceorientation事件监视设备朝向,记录下其受地心引力作用下而在方向上产生变化的数据,然后使用DeviceOrientationControls.js(一个three.js的插件)让摄像头根据设备的移动进行调整,相当于模拟人看向物体的某个方向,犹如人的视线一样。最后,结合three.js来构建一个3d世界。
1. 画一个会动的太阳
引用three.js, 建立3个要素:场景(scene)、相机(camera)和渲染器(renderer)。有了这三样东西,才能将物体渲染到网页中,然后再画一个太阳。
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. 构建一个太阳系
为了效果好看一点,顺便把其他行星也画上去,实现原理跟太阳的一样。接着就让各行星围绕着太阳转啊转。
//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);
再画点星星点缀一下。
//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插件,快速打造虚拟现实分屏效果。
看核心代码
//绑定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
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