可以利用Threejs中的立方体或者球体实现全景图功能,把立方体或球体当成天空盒子,将无缝衔接的图片贴上,看起来就像在一个场景中,相机一般放置在中央,只要离边缘足够远就看不出是立方体或球体,但如果超出边界就能看到他们。Threejs也有官方的全景图实例:
https://threejs.org/examples/?q=pano#webgl_panorama_cube
https://threejs.org/examples/?q=pano#css3d_panorama
下面的实现代码在以上实例webgl_panorama_cube的基础上修改,去掉了OrbitControls对视角的控制,改用鼠标拖动事件控制天空盒的旋转,鼠标滚轮控制相机的FOV。
1、立方体实现
立方体6个面要贴上6个方向的图片,这6个图片如下所示
图片加载的顺序是正X(px.jpg),负X(nx.jpg),正Y(py.jpg),负Y(ny.jpg),正Z(pz.jpg)和负Z(nz.jpg),将他们分别赋给6个材质的贴图,然后作为立方体skyBox的材质,因为相机在skyBox的内部,而内部的面不会显示,所以要将X轴或者Z轴的放大倍数变为负数,这样才能看到内部,scale.z=-1时相当于将Z轴正向的面移到Z轴负方向上。
var materials = [];
var texturepx = new THREE.TextureLoader().load( 'cubetexture/px.jpg' );
materials.push( new THREE.MeshBasicMaterial( { map: texturepx} ) );
var texturenx = new THREE.TextureLoader().load( 'cubetexture/nx.jpg' );
materials.push( new THREE.MeshBasicMaterial( { map: texturenx} ) );
var texturepy = new THREE.TextureLoader().load( 'cubetexture/py.jpg' );
materials.push( new THREE.MeshBasicMaterial( { map: texturepy} ) );
var textureny = new THREE.TextureLoader().load( 'cubetexture/ny.jpg' );
materials.push( new THREE.MeshBasicMaterial( { map: textureny} ) );
var texturepz = new THREE.TextureLoader().load( 'cubetexture/pz.jpg' );
materials.push( new THREE.MeshBasicMaterial( { map: texturepz} ) );
var texturenz = new THREE.TextureLoader().load( 'cubetexture/nz.jpg' );
materials.push( new THREE.MeshBasicMaterial( { map: texturenz} ) );
var skyBox = new THREE.Mesh( new THREE.BoxBufferGeometry( 100, 100, 100 ), materials );
skyBox.geometry.scale( 1, 1, - 1 );
在鼠标按下的mousemove事件中旋转skyBox(也可以旋转相机视角),旋转速度可以自己调节
var bMouseDown = false;
var x = -1;
var y =-1;
container.onmousedown=function(event){
x=event.clientX;
y=event.clientY;
bMouseDown = true;
}
container.onmouseup=function(event){
bMouseDown = false;
}
container.onmousemove=function(event){
if(bMouseDown){
skyBox.rotation.y += -0.005*(event.clientX-x);
skyBox.rotation.x += -0.005*(event.clientY-y);
if(skyBox.rotation.x>Math.PI/2)
{
skyBox.rotation.x = Math.PI/2
}
if(skyBox.rotation.x<-Math.PI/2)
{
skyBox.rotation.x = -Math.PI/2
}
x=event.clientX;
y=event.clientY;
}
}
在mousewheel事件中改变camera的FOV值
container.onmousewheel=function(event){
if(event.wheelDelta!=0){
camera.fov+=event.wheelDelta>0?1:-1;
if(camera.fov>150)
{
camera.fov=150;
}
else if(camera.fov < 30)
{
camera.fov = 30;
}
camera.updateProjectionMatrix();
}
}
如果要禁掉右键菜单可以在body标签加上οncοntextmenu="return false"
完整代码如下
three.js cube panorama
运行结果
2、球体实现
下面这张图片将6个面合成到一张图片中,这样的图片也可以由球体来实现
当然也要球体的UV设置正确才能正常展示,Threejs中的SphereBufferGeometry/SphereGeometry可以直接使用,球体是用多面体来近似,面数越多越接近真实球体,性能也会随着面数增多而下降,SphereBufferGeometry的第二和第三个参数分别表示水平方向和垂直方向的段数,第一个参数是球体的半径,只要不超过相机的远截面值即可。
var material = new THREE.MeshBasicMaterial();
var texture = new THREE.TextureLoader().load( 'pano.jpg' );
material.map = texture;
var skyBox= new THREE.Mesh(new THREE.SphereBufferGeometry(100, 100, 100),material);
skyBox.geometry.scale( 1, 1, -1 );
其他的与立方体的实现差不多,完整代码如下
three.js sphere panorama