Vue鸣哀、Three.js實現(xiàn)全景圖

一架忌、首先我們需要創(chuàng)建一個Vue工程

本文主要詳細(xì)記錄搭建全景圖的過程,故搭建Vue工程不在過多描述我衬。

二叹放、安裝Three.js

npm install three --save
npm install three-trackballcontrols --save
npm install three-orbit-controls --save
npm i three-obj-mtl-loader --save
npm i three-fbx-loader --save
npm i three-stats --save

three-trackballcontrols:軌跡球控件,最常用的控件挠羔,可以使用鼠標(biāo)輕松的移動井仰、平移,縮放場景破加。
three-orbit-controls :三維場景操作插件俱恶。其實在 npm install three 的時候已經(jīng)下載對應(yīng)的插件, 在 node_modules 文件夾下找到 three/examples/jsm/controls/OrbitControls 這個路徑里面也能找到對應(yīng)的插件范舀。
three-obj-mtl-loader:加載 .obj 模型文件 , .mtl 材質(zhì)信息文件的插件合是。
three-fbx-loader:fbx模型文件的插件。
three-stats:性能檢測插件锭环,可以監(jiān)控動畫運(yùn)行的幀數(shù)聪全。

三、渲染器-renderer辅辩, 場景-scene难礼,相機(jī)-camera

??Three.js中吱七,場景可理解為是一個容器,我們可以將需要的物體放入場景中鹤竭。相機(jī)的作用在場景中取一個合適的景踊餐,把它拍下來。渲染器的作用就是將相機(jī)拍攝下來的圖片臀稚,渲染至瀏覽器展示吝岭。

四、具體實現(xiàn)

  1. 引入依賴
import * as THREE from "three";
import * as ThreeStats from 'three-stats'
const OrbitControls = require('three-orbit-controls')(THREE);
  1. 定義變量
data() {
  return {
    renderer: '', //渲染器
    scene: '', //場景
    light: '', //光源
    camera: '', //相機(jī)
    controls: '', //控制器
    stats: '', //性能監(jiān)控器
    mygroup: '', //模型組
    action: '', //控制動畫的值
    clock: '', //時鐘
    mixer: '', //混合實例
    rotateAnimate: '', //旋轉(zhuǎn)動畫
    sRotate: 1, //是否開啟旋轉(zhuǎn)
  }
}
  1. 初始化渲染器
rendererInit() {
    var width = 1000;
    var height = 800;
    this.renderer = new THREE.WebGLRenderer();
    this.renderer.setClearColor(0xffffff); 
    this.renderer.setSize(width, height); 
    // 通過 this.$refs獲取頁面的dom并綁定渲染器
    this.$refs.threeDom.appendChild(this.renderer.domElement);
}
  1. 初始化場景
sceneInit() {
    this.scene = new THREE.Scene();
    var ambient = new THREE.AmbientLight(0x444444, 3); //添加光源  顏色和光照強(qiáng)度
    var axisHelper = new THREE.AxesHelper(600); //添加輔助坐標(biāo)系
    this.scene.add(ambient, axisHelper);
},

AmbientLight:環(huán)境光吧寺,會均勻的照亮場景中的所有物體窜管。不能用來投射陰影,因為它沒有方向稚机。

AmbientLight( color : Integer, intensity : Float )
color - (參數(shù)可選)顏色的rgb數(shù)值幕帆。缺省值為 0xffffff。
intensity - (參數(shù)可選)光照的強(qiáng)度赖条。缺省值為 1失乾。

AxesHelper:用于簡單模擬3個坐標(biāo)軸的對象。紅色代表 X 軸纬乍,綠色代表 Y 軸碱茁,藍(lán)色代表 Z 軸。

AxesHelper( size : Number )
size -- (可選的) 表示代表軸的線段長度. 默認(rèn)為 1仿贬。

  1. 創(chuàng)建模型
modelling(){
      this.mygroup = new THREE.Group();

      var textureLoader = new THREE.TextureLoader(); //創(chuàng)建紋理貼圖
      var img = textureLoader.load(require('../../public/img/home3.jpeg'));

      var geometry = new THREE.SphereGeometry(130, 256, 256); // 球體網(wǎng)格模型
      var material = new THREE.MeshLambertMaterial({
        map: img, //設(shè)置顏色貼圖屬性值
        side: THREE.DoubleSide, //雙面渲染
      });
      var meshSphere = new THREE.Mesh(geometry, material); //網(wǎng)格模型對象Mesh
      meshSphere.name = '球體容器';
      this.mygroup.add(meshSphere);

      var canvasText = this.getcanvers('進(jìn)門'); //生成一個canvers 文字圖案對象
      var texture = new THREE.CanvasTexture(canvasText);
      var geometryText = new THREE.PlaneGeometry(16, 10, 60, 60);
      var materialText = new THREE.MeshPhongMaterial({
        map: texture, // 設(shè)置紋理貼圖
        side: THREE.DoubleSide, //雙面渲染
      });
      var meshText = new THREE.Mesh(geometryText, materialText);
      meshText.name = '進(jìn)門';
      meshText.position.set(40, 20, -90)
      this.mygroup.add(meshText);

      this.scene.add(this.mygroup);
      this.addAnimation(); //添加并開啟動畫
      this.refresh();
    }
    // 生成一個canvers圖案
    getcanvers(text) {
      var canvasText = document.createElement("canvas");
      var c = canvasText.getContext('2d');
      // 矩形區(qū)域填充背景
      c.fillStyle = "#FFFFFF"; //canver背景
      c.fillRect(0, 0, 300, 200); //生成一個矩形
      c.translate(160, 80);
      c.fillStyle = "#000000"; //文本填充顏色
      c.font = "bold 100px 宋體"; //字體樣式設(shè)置
      c.textBaseline = "middle"; //文本與
      c.textAlign = "center"; //文本居中
      c.fillText(text, 0, 0);
      return canvasText;
    }

SphereGeometry:一個用于生成球體的類纽竣。

SphereGeometry(radius : Float, widthSegments : Integer, heightSegments : Integer, phiStart : Float, phiLength : Float, thetaStart : Float, thetaLength : Float)
radius — 球體半徑,默認(rèn)為1茧泪。
widthSegments — 水平分段數(shù)(沿著經(jīng)線分段)蜓氨,最小值為3,默認(rèn)值為8队伟。
heightSegments — 垂直分段數(shù)(沿著緯線分段)穴吹,最小值為2,默認(rèn)值為6缰泡。
phiStart — 指定水平(經(jīng)線)起始角度刀荒,默認(rèn)值為0代嗤。棘钞。
phiLength — 指定水平(經(jīng)線)掃描角度的大小,默認(rèn)值為 Math.PI * 2干毅。
thetaStart — 指定垂直(緯線)起始角度宜猜,默認(rèn)值為0。
thetaLength — 指定垂直(緯線)掃描角度大小硝逢,默認(rèn)值為 Math.PI姨拥。

MeshLambertMaterial:一種非光澤表面的材質(zhì)绅喉,沒有鏡面高光。

MeshLambertMaterial( parameters : Object )
.map : Texture叫乌。顏色貼圖柴罐。默認(rèn)為null。
.side : Integer憨奸。定義將要渲染哪一面 - 正面革屠,背面或兩者。 默認(rèn)為THREE.FrontSide排宰。其他選項有THREE.BackSide和THREE.DoubleSide似芝。

CanvasTexture:從Canvas元素中創(chuàng)建紋理貼圖。

PlaneGeometry: 一個用于生成平面幾何體的類板甘。

MeshPhongMaterial:一種用于具有鏡面高光的光澤表面的材質(zhì)党瓮。

  1. 初始化相機(jī)
cameraInit() {
    var width = 800; //窗口寬度
    var height = 800; //窗口高度
    this.camera = new THREE.PerspectiveCamera(90, width / height, 1, 1000); //使用透視相機(jī)
    this.camera.position.set(0, 0, 10); //設(shè)置相機(jī)位置
    this.camera.lookAt(new THREE.Vector3(0, 0, 0)); // 相機(jī)看向
}

PerspectiveCamera:透視相機(jī)。

PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )
fov — 攝像機(jī)視錐體垂直視野角度
aspect — 攝像機(jī)視錐體長寬比
near — 攝像機(jī)視錐體近端面
far — 攝像機(jī)視錐體遠(yuǎn)端面

  1. 初始化控制器(三維場景操作插件)
controlInit() {
    this.controls = new OrbitControls(this.camera, this.$refs.threeDom); // 初始化控制器
    this.controls.target.set(0, 0, 0); // 設(shè)置控制器的焦點(diǎn)盐类,使控制器圍繞這個焦點(diǎn)進(jìn)行旋轉(zhuǎn)
    this.controls.minDistance = 10; // 設(shè)置移動的最短距離(默認(rèn)為零)
    this.controls.maxPolarAngle = Math.PI; //繞垂直軌道的距離(范圍是0-Math.PI,默認(rèn)為Math.PI)
    this.controls.maxDistance = 30; // 設(shè)置移動的最長距離(默認(rèn)為無窮)
    this.controls.enablePan = false; //禁用右鍵功能
    this.controls.addEventListener('change', this.refresh); //監(jiān)聽鼠標(biāo)寞奸、鍵盤事件 讓整個控件可以拖動
  },
  1. 旋轉(zhuǎn)動畫
addAnimation() {
    this.clock = new THREE.Clock(); 
    var times = [0, 3600]; //   創(chuàng)建幀動畫序列
    var position_x = [0, 360];
    var keyframe = new THREE.KeyframeTrack('meshSphere.rotation[y]', times, position_x);
    var duration = 100; //持續(xù)時間
    var cilp = new THREE.AnimationClip('sphereRotate', duration, [keyframe]); //剪輯 keyframe對象
    this.mixer = new THREE.AnimationMixer(this.mygroup); //動畫混合實例
    this.action = this.mixer.clipAction(cilp);
    this.action.timeScale = 1; //播放速度
    this.action.setLoop(THREE.LoopPingPong).play(); //開始播放 像乒乓球一樣在起始點(diǎn)與結(jié)束點(diǎn)之間來回循環(huán)
    this.animate(); //開啟動畫
},
// 循環(huán)渲染
animate() {
    this.rotateAnimate = requestAnimationFrame(this.animate);
    this.renderer.render(this.scene, this.camera);
    this.update();
},

Clock:用于跟蹤時間。

KeyframeTrack:關(guān)鍵幀軌道(KeyframeTrack)是關(guān)鍵幀(keyframes)的定時序列, 它由時間和相關(guān)值的列表組成, 用來讓一個對象的某個特定屬性動起來在跳。

KeyframeTrack( name : String, times : Array, values : Array, interpolation : Constant )
name - 關(guān)鍵幀軌道(KeyframeTrack)的標(biāo)識符蝇闭。
times - 關(guān)鍵幀的時間數(shù)組, 被內(nèi)部轉(zhuǎn)化為 Float32Array。
values - 與時間數(shù)組中的時間點(diǎn)相關(guān)的值組成的數(shù)組, 被內(nèi)部轉(zhuǎn)化為 Float32Array硬毕。
interpolation - 使用的插值類型呻引。

AnimationClip:動畫剪輯(AnimationClip)是一個可重用的關(guān)鍵幀軌道集,它代表動畫吐咳。

AnimationClip( name : String, duration : Number, tracks : Array )
name - 此剪輯的名稱逻悠。
duration - 持續(xù)時間 (單位秒)。如果傳入負(fù)數(shù), 持續(xù)時間將會從傳入的數(shù)組中計算得到韭脊。
tracks - 一個由關(guān)鍵幀軌道(KeyframeTracks)組成的數(shù)組童谒。

AnimationMixer:動畫混合器是用于場景中特定對象的動畫的播放器。當(dāng)場景中的多個對象獨(dú)立動畫時沪羔,每個對象都可以使用同一個動畫混合器饥伊。

  1. 最后初始化加載
init() {
  this.$refs.threeDom.addEventListener('dblclick', this.onMouseDblclick); //監(jiān)聽雙擊事件
  this.rendererInit(); //創(chuàng)建渲染器
  this.sceneInit(); //創(chuàng)建場景    包含光源和輔助坐標(biāo)系
  this.cameraInit(); //創(chuàng)建相機(jī)
  this.controlInit(); //初始化控制器
  this.propertyInit(); //性能監(jiān)控
  this.modelling(); //建立模型
}

參考文章:
https://juejin.cn/post/6927193628724953096
https://blog.csdn.net/ithanmang/article/details/84062933

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蔫饰,隨后出現(xiàn)的幾起案子琅豆,更是在濱河造成了極大的恐慌,老刑警劉巖篓吁,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茫因,死亡現(xiàn)場離奇詭異,居然都是意外死亡杖剪,警方通過查閱死者的電腦和手機(jī)冻押,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門驰贷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洛巢,你說我怎么就攤上這事括袒。” “怎么了稿茉?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵箱熬,是天一觀的道長。 經(jīng)常有香客問我狈邑,道長城须,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任米苹,我火速辦了婚禮糕伐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蘸嘶。我一直安慰自己良瞧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布训唱。 她就那樣靜靜地躺著褥蚯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪况增。 梳的紋絲不亂的頭發(fā)上赞庶,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音澳骤,去河邊找鬼歧强。 笑死,一個胖子當(dāng)著我的面吹牛为肮,可吹牛的內(nèi)容都是我干的摊册。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼颊艳,長吁一口氣:“原來是場噩夢啊……” “哼茅特!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棋枕,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤白修,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后戒悠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體熬荆,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舟山,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年绸狐,在試婚紗的時候發(fā)現(xiàn)自己被綠了卤恳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡寒矿,死狀恐怖突琳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情符相,我是刑警寧澤拆融,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站啊终,受9級特大地震影響镜豹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蓝牲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一趟脂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧例衍,春花似錦昔期、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至梦抢,卻和暖如春般贼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奥吩。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工具伍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人圈驼。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓人芽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親绩脆。 傳聞我的和親對象是個殘疾皇子萤厅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容