一、实验内容

通过上次实验,了解了Three.js创建场景的基本步骤。这一节,我们将通过Three.js实现全景漫游功能。如下图:

全景图是获取一个3D场景中的不同角度的图片,然后通过拼接、融合实现3D的虚拟场景。例如百度地图上全景漫游。

二、探讨

方法1:使用软件(例如:Pano2vr )

前提准备:下载Pano2vr软件;全景图。

全景图:对于现实世界,可以通过鱼眼摄像头拍摄得到全景图;对于虚拟世界,使用3D模型软件,例如3dMaxs,导入场景模型,生成全景图。

有点:可以导出flash、html5等格式的全景漫游。你只需要准备一张全景图就可以。

这里我们使用的是另外一种方法,使用Three.js实现全景漫游的功能,这样有利于我们以后的功能扩展。

三、全景漫游基本知识

全景图通过广角的表现手段以及绘画、相片、视频、三维模型等形式,尽可能多表现出周围的环境。360全景,即通过对专业相机捕捉整个场景的图像信息或者使用建模软件渲染过后的图片,使用软件进行图片拼合,并用专门的播放器进行播放,即将平面照片或者计算机建模图片变为360 度全观,用于虚拟现实浏览,把二维的平面图模拟成真实的三维空间,呈现给观赏者。[1]

实现360度全景漫游的有3种方法,1)球形图、2)圆柱图、3)正方体。

对基本原理比较感兴趣的朋友可以去看看这篇博客,写的很详细。

https://aotu.io/notes/2016/01/02/3D-panorama/?utm_source=tuicool&utm_medium=referral

注:圆柱图实现方法的确定比较明显,所以使用的比较少。上面提到的软件实现全景漫游,使用的是球形的方法。这里我们实现的方法是正方体。

四、实验步骤

1、创建场景:

/**
* 创建场景
* @type {THREE.Scene}
*/
scene = new THREE.Scene();

2、添加相机

这里我们使用的是透视相机。

/**
* 添加相机
* @type {THREE.PerspectiveCamera}
*/
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

3、添加渲染器

这里使用的是CSS3DRenderer渲染器,要在html文件中添加:

/**
* 添加一个渲染器
* @type {THREE.CSS3DRenderer}
*/
renderer = new THREE.CSS3DRenderer();
renderer.setClearColor(0x000000, 1.0);
renderer.setSize(window.innerWidth, window.innerHeight);

4、创建正方体

创建正方体,分别对正方体的六个面进行贴图

/**
*正方体的6个面的资源及相关(坐标、旋转等)设置
*/
var sides = [{url: './images/posx.jpg', position: [-512, 0, 0], rotation: [0, Math.PI / 2, 0]},
{url: './images/negx.jpg', position: [512, 0, 0], rotation: [0, -Math.PI / 2, 0]},
{url: './images/posy.jpg', position: [0, 512, 0], rotation: [Math.PI / 2, 0, Math.PI]},
{url: './images/negy.jpg', position: [0, -512, 0], rotation: [-Math.PI / 2, 0, Math.PI]},
{url: './images/posz.jpg', position: [0, 0, 512], rotation: [0, Math.PI, 0]},
{url: './images/negz.jpg',position: [0, 0, -512], rotation: [0, 0, 0]}]; for (var i = 0; i < sides.length; i++) {
var side = sides[i];
var element = document.createElement('section');
document.body.appendChild(element);
element.id = 'section_'+ i;
var imgElement = document.createElement('img');
imgElement.width = 1028; // 2 pixels extra to close the gap.
imgElement.height = 1028;
imgElement.src = side.url;
element.appendChild(imgElement);
var object = new THREE.CSS3DObject(element);
object.position.set(side.position[0], side.position[1], side.position[2]);
object.rotation.set(side.rotation[0], side.rotation[1], side.rotation[2]);
scene.add(object);
}

5、实时渲染函数

/**
* 实时渲染函数
*/
function render() {
requestAnimationFrame(render);
lon = Math.max(-180, Math.min(180, lon));//限制固定角度内旋转
lat = Math.max(-85, Math.min(85, lat));
phi = THREE.Math.degToRad(90 - lat);
theta = THREE.Math.degToRad(lon);
target.x = Math.sin(phi) * Math.cos(theta);
target.y = Math.cos(phi);
target.z = Math.sin(phi) * Math.sin(theta);
camera.lookAt(target);
renderer.render(scene, camera);
}

6、窗口改变时对camera焦点的处理

/**
* 窗体大小改变
*/
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}

7、相机焦点跟着鼠标的操作移动

function onDocumentMouseDown(event) {
event.preventDefault();
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('mouseup', onDocumentMouseUp, false);
} function onDocumentMouseMove(event) {
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
lon -= movementX * 0.1;
lat += movementY * 0.1;
} function onDocumentMouseUp(event) {
document.removeEventListener('mousemove', onDocumentMouseMove);
document.removeEventListener('mouseup', onDocumentMouseUp);
} /**
* 鼠标滚轮改变相机焦距
*/
function onDocumentMouseWheel(event) {
camera.fov -= event.wheelDeltaY * 0.05;
camera.updateProjectionMatrix();
} function onDocumentTouchStart(event) {
event.preventDefault();
var touch = event.touches[0];
touchX = touch.screenX;
touchY = touch.screenY;
} function onDocumentTouchMove(event) {
event.preventDefault();
var touch = event.touches[0];
lon -= (touch.screenX - touchX) * 0.1;
lat += (touch.screenY - touchY) * 0.1;
touchX = touch.screenX;
touchY = touch.screenY;
}

五、总结

开始导师要实现全景图的功能,开始对这方面的知识不了解,无从下手。后来通过查找资料,看论文等掌握了全景漫游的基本知识点。通过这次式样,掌握了全景漫游功能的基本原理已经实现方法。

六、完整代码

main.js

var scene, renderer, camera;
var target = new THREE.Vector3(); //相机焦点
var lon = 90, lat = 0;
var phi = 0, theta = 0;
var touchX, touchY; function init() {
/**
* 创建场景
* @type {THREE.Scene}
*/
scene = new THREE.Scene(); /**
* 添加相机
* @type {THREE.PerspectiveCamera}
*/
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); /**
* 添加一个渲染器
* @type {THREE.CSS3DRenderer}
*/
renderer = new THREE.CSS3DRenderer();
renderer.setClearColor(0x000000, 1.0);
renderer.setSize(window.innerWidth, window.innerHeight); /**
*正方体的6个面的资源及相关(坐标、旋转等)设置
*/
var sides = [{url: './images/posx.jpg', position: [-512, 0, 0], rotation: [0, Math.PI / 2, 0]},
{url: './images/negx.jpg', position: [512, 0, 0], rotation: [0, -Math.PI / 2, 0]},
{url: './images/posy.jpg', position: [0, 512, 0], rotation: [Math.PI / 2, 0, Math.PI]},
{url: './images/negy.jpg', position: [0, -512, 0], rotation: [-Math.PI / 2, 0, Math.PI]},
{url: './images/posz.jpg', position: [0, 0, 512], rotation: [0, Math.PI, 0]},
{url: './images/negz.jpg',position: [0, 0, -512], rotation: [0, 0, 0]}]; for (var i = 0; i < sides.length; i++) {
var side = sides[i];
var element = document.createElement('section');
document.body.appendChild(element);
element.id = 'section_'+ i;
var imgElement = document.createElement('img');
imgElement.width = 1028; // 2 pixels extra to close the gap.
imgElement.height = 1028;
imgElement.src = side.url;
element.appendChild(imgElement);
var object = new THREE.CSS3DObject(element);
object.position.set(side.position[0], side.position[1], side.position[2]);
object.rotation.set(side.rotation[0], side.rotation[1], side.rotation[2]);
scene.add(object);
}
document.body.appendChild(renderer.domElement); /**
* 注册监听
*/
document.addEventListener('mousedown', onDocumentMouseDown, false);
document.addEventListener('mousewheel', onDocumentMouseWheel, false);
document.addEventListener('touchstart', onDocumentTouchStart, false);
document.addEventListener('touchmove', onDocumentTouchMove, false);
window.addEventListener('resize', onWindowResize, false); render();
} /**
* 实时渲染函数
*/
function render() {
requestAnimationFrame(render);
lon = Math.max(-180, Math.min(180, lon));//限制固定角度内旋转
lon += 0.1;//自动旋转
lat = Math.max(-85, Math.min(85, lat));
phi = THREE.Math.degToRad(90 - lat);
theta = THREE.Math.degToRad(lon);
target.x = Math.sin(phi) * Math.cos(theta);
target.y = Math.cos(phi);
target.z = Math.sin(phi) * Math.sin(theta);
camera.lookAt(target);
renderer.render(scene, camera);
} /**
* 窗体大小改变
*/
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
} function onDocumentMouseDown(event) {
event.preventDefault();
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('mouseup', onDocumentMouseUp, false);
} function onDocumentMouseMove(event) {
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
lon -= movementX * 0.1;
lat += movementY * 0.1;
} function onDocumentMouseUp(event) {
document.removeEventListener('mousemove', onDocumentMouseMove);
document.removeEventListener('mouseup', onDocumentMouseUp);
} /**
* 鼠标滚轮改变相机焦距
*/
function onDocumentMouseWheel(event) {
camera.fov -= event.wheelDeltaY * 0.05;
camera.updateProjectionMatrix();
} function onDocumentTouchStart(event) {
event.preventDefault();
var touch = event.touches[0];
touchX = touch.screenX;
touchY = touch.screenY;
} function onDocumentTouchMove(event) {
event.preventDefault();
var touch = event.touches[0];
lon -= (touch.screenX - touchX) * 0.1;
lat += (touch.screenY - touchY) * 0.1;
touchX = touch.screenX;
touchY = touch.screenY;
} /**
* 脚本入口
* @type {init}
*/
window.onload = init;

引用

1:百度百科 http://baike.baidu.com/view/2424250.htm

<Three.js>(第三节)全景漫游的更多相关文章

  1. three.js全景漫游实践

    Hello 小伙伴们,如果觉得本文还不错,记得给个 star , 小伙伴们的 star 是我持续更新的动力!GitHub 地址 简介 全景图分两种 由六张正方形图片组成的SkyBox 一整张的宽高比为 ...

  2. 打造H5里的“3D全景漫游”秘籍

    近来风生水起的VR虚拟现实技术,抽空想起年初完成的“星球计划”项目,总结篇文章与各位分享一下制作基于Html5的3D全景漫游秘籍. QQ物联与深圳市天文台合作,在手Q“发现新设备”-“公共设备”里,连 ...

  3. 打造自己的3D全景漫游

    three.js 示例: ​ 打造H5里的"3D全景漫游"秘籍 - 腾讯ISUX ​ QQ物联星球计划 通过pano2vr直接将鱼眼全景图生成立体空间的六个面:也可通过Photos ...

  4. 轩辕展览-VR虚拟展厅设计如何实现全景漫游功能

    什么是在线3d漫游?如何在VR虚拟展厅设计之中实现3d漫游功能?让我们来分享3dVR虚拟展厅的在线漫游. 实际上,在线3d漫游就是通过3d仿真场景,使用鼠标和键盘在虚拟空间之中自由漫游,它可以从高空俯 ...

  5. 3D全景漫游

    全景图共分为三种: ①球面全景图 利用一张全景图围成一个球,自身位置位于球体内.由于图片是矩形,所以最上和最下的缝合处很明显就能够看得出来. 球面全景图是最接近人眼的构建模式,若利用多个立面构建,拼接 ...

  6. Three.js 实现3D全景侦探小游戏🕵️

    背景 你是嘿嘿嘿侦探社实习侦探️,接到上级指派任务,到甄开心小镇调查市民甄不戳宝石失窃案,根据线人流浪汉老石‍提供的线索,小偷就躲在小镇,快把他找出来,帮甄不戳寻回失窃的宝石吧! 本文使用 Three ...

  7. Unity VR全景漫游

    一.前言: 最近VR如火如茶,再不学习就落伍啦.有空闲时间,跟Rodolfo一起研究下相关知识. 本文介绍了两种方法来制作VR场景: 方法一:通过6张小图搭建的VR场景 方法二:通过一张全景图来搭建V ...

  8. 摸索js的3d全景

    先我在网上找到了一个例子,http://silali.vicp.net/three/emaple.html 完美实现3d全景,在详细查看这个例子后,发现他在手机上运行并不流畅,而且显不全并会卡顿. 我 ...

  9. 全景视频外包团队:技术分享Unity3D全景漫游

    作者:未知 1.建模中使用的图片.文件.文件夹等以及模型中物体.材质等的名称都不能使用中文或者特殊符号,可以使用英文字母.数字.下划线等 2.调整Max的单位为米 3.烘培光影的设置 4.模型的中的植 ...

随机推荐

  1. redis的key对应mysql数据表设计

    根据用户名来查询用户信息 在关系型数据中,除主键外,还有可能其他列也步骤查询, 如上表中, username 也是极频繁查询的,往往这种列也是加了索引的. 转换到k-v数据中,则也要相应的生成一条按照 ...

  2. CSS实现栅格布局

    CSS实现栅格布局 设置容器container: .grid-container { width: 100%; max-width: 1200px; } 清除浮动: .row:before, .row ...

  3. Android ImageView 替换图片

    网上找了半天,找到的都是错的,都不是我想要的效果.我想要的是点击一个图片后,图片被替换. 通过一下方法可以实现:“v”是ImageView对象,“image_name”是替换后的图片资源 ((Imag ...

  4. 多年js学习累计总结

    http://www.codesec.net/list/6/ 大神http://www.cnblogs.com/tylerdonet/p/5543813.html

  5. 路飞学城Python-Day46

    16-如何正确的使用类选择器及总结 一般情况下尽量不要去使用id选择器,因为id选择器有很大的限制性,id一般都是JS配合使用的,类选择器都是和CSS配合使用的,特殊性情况可以用id选择器. 类的使用 ...

  6. [BOI2007]摩基亚

    题目:洛谷P4390.BZOJ1176. 题目大意: 给你一个\(W\times W\)的矩阵,初始每个数都为\(S\).现在有若干操作: 1. 给某个格子加上一个值:2. 询问某个子矩阵的值的和:3 ...

  7. 模板 NTT 快速数论变换

    NTT裸模板,没什么好解释的 这种高深算法其实也没那么必要知道原理 #include <cstdio> #include <cstring> #include <algo ...

  8. JS[获取两个日期中所有的月份]

    //------[获取两个日期中所有的月份中] function getMonthBetween(start,end){ var result = []; var s = start.split(&q ...

  9. qt 摄像头程序

    http://www.oschina.net/code/snippet_124925_3789?p=3#comments http://www.codesoso.net/Search?q=qt+%C9 ...

  10. C# .net IDE Rider入门

    话说史上最强IDE Visual Studio 所向披靡数十载尚无敌手,现在Intellij带着统一IDE界的目标来挑战VS的霸主地位.了解Rider后发现,哎哟亮点多多,还不错哦! Rider是一款 ...