##?
>?背景:?創(chuàng)建出threejs?3D場景后如何使用鼠標操作場景內(nèi)模型元素助泽?啰扛,如拖動,放大縮小嗡贺,平移隐解,點擊觸發(fā)交互等。诫睬。煞茫。
####?安裝threejs控制器組件
```js
npm?install?three-orbitcontrols?-D
```
####?第一步
>?創(chuàng)建盛放場景盒子div
```js
<template>
??<div?class="three-box-one">
????<div?id="threeone"?/>
??</div>
</template>
```
####?第二步
>?引入vue,?threejs?,?three-orbitcontrols
```js
import?Vue?from?'vue';
import?*?as?THREE?from?'three';
import?*?as?OrbitControls?from?'three-orbitcontrols'
```
####?第三步
>?創(chuàng)建基礎(chǔ)的data數(shù)據(jù)
```js
data?():?DataType?{
??return?{
????id:?null,
????domW:?0,
????domH:?0,
????scene:?null,
????camera:?null,
????renderer:?null,
????mesh:?null,
????controls:?null
??}
},
```
####?第四步
>?初始運行創(chuàng)建場景,獲取場景寬度高度
```js
mounted?()?{
??//?獲取盛放場景div標簽
??this.id?=?document.getElementById('threeone')
??//?獲取盛放標簽寬高
??this.domW?=?this.id.offsetWidth
??this.domH?=?this.id.offsetHeight
??//?運行創(chuàng)建場景函數(shù)
??this.init()
},
```
####?第五步
>?創(chuàng)建場景函數(shù)講解
??--?1.?知識點講解?---
??a.?`new?THREE.PerspectiveCamera(45,?this.domW?/?this.domH,?0.01,?20000)`
????//?設(shè)置相機?45?攝像機視錐體垂直視野角度摄凡,?
????//?this.domW?/?this.domH?攝像機視錐體長寬比
????//?0.01?攝像機視錐體近端面(攝像機拍攝最近距離)
????//?20000?攝像機拍攝最遠距離续徽,超出距離模型場景不顯示
??b.?`new?THREE.WebGLRenderer({?antialias:?true,?alpha:?true?})`
????```js
????WebGLRenderer(?parameters?:?Object?)
????//?canvas?-?一個供渲染器繪制其輸出的canvas?它和下面的domElement屬性對應(yīng)。?如果沒有傳這個參數(shù)亲澡,會創(chuàng)建一個新canvas
????//?context?-?可用于將渲染器附加到已有的渲染環(huán)境(RenderingContext)中钦扭。默認值是null
????//?precision?-?著色器精度.?可以是?"highp",?"mediump"?或者?"lowp".?如果設(shè)備支持,默認為"highp"?
????//?alpha?-?canvas是否包含alpha?(透明度)床绪。默認為?false
????//?antialias?-?是否執(zhí)行抗鋸齒土全。默認為false.?避免模型渲染出現(xiàn)鋸齒現(xiàn)象
????//?stencil?-?繪圖緩存是否有一個至少8位的模板緩存(stencil?buffer)捎琐。默認為true
????//?preserveDrawingBuffer?-是否保留緩緩存直到手動清除或被覆蓋。?默認false.
????//?depth?-?繪圖緩存是否有一個至少6位的深度緩存(depth?buffer?)裹匙。?默認是true.
????//?logarithmicDepthBuffer?-?是否使用對數(shù)深度緩存。如果要在單個場景中處理巨大的比例差異末秃,就有必要使用概页。
????```
>?init?函數(shù)講解
??```js
????init?()?{
??????//?實例化場景函數(shù)
??????this.scene?=?new?THREE.Scene()
??????//?設(shè)置相機
??????this.camera?=?new?THREE.PerspectiveCamera(45,?this.domW?/?this.domH,?0.01,?20000)
??????//?攝像機z軸位置
??????this.camera.position.z?=?800
??????//?this.camera.position.y?=?100
??????//?實例化渲染器
??????this.renderer?=?new?THREE.WebGLRenderer({
????????antialias:?true,
????????alpha:?true
??????})
??????//?設(shè)置渲染器寬高
??????this.renderer.setSize(this.domW,?this.domH)
??????//將渲染器append到div容器中
??????this.id.appendChild(this.renderer.domElement)
??????//?添加燈光
??????this.addLight()
??????//?添加輔助線
??????this.axisHelper()
??????//?創(chuàng)建正方體
??????this.initBox()
??????//?刷幀渲染動畫
??????this.animate()
??????//?響應(yīng)屏幕改變大小函數(shù)
??????this.onWindowResize()
??????//?場景控制器函數(shù)
??????this.controlsFn()
????},
??```
??####?第五步
??>?添加燈光
??```js
??addLight?()?{
??????//?設(shè)置環(huán)境光
??????const?ambientLight?=?new?THREE.AmbientLight('#ffffff')
??????this.scene.add(ambientLight)
??????//?設(shè)置平行光
??????const?light?=?new?THREE.DirectionalLight('#ffffff')
??????this.scene.add(light)
??????//?設(shè)置點光源
??????const?pointLight?=?new?THREE.PointLight('#ffffff',?0.1,?1000)
??????pointLight.position.set(300,?300,?300)
??????this.scene.add(pointLight)
????},
??```
??####?第六步
??>?添加空間輔助線
??```js
??axisHelper?()?{
??????//?空間輔助線函數(shù)
??????const?axes:THREE.AxesHelper?=?new?THREE.AxesHelper(800)
??????this.scene.add(axes)
??},
??```
??####?第七步
??>?創(chuàng)建正方體和網(wǎng)格圓球
????--?1.?創(chuàng)建球體知識點?--
????a.?`new?THREE.SphereGeometry()`
????```js
??????new?THREE.SphereGeometry(radius?:?Float,?widthSegments?:?Integer,?heightSegments?:?Integer,?phiStart?:?Float,?phiLength?:?Float,?thetaStart?:?Float,?thetaLength?:?Float)
??????//?radius?—?球體半徑,默認為1练慕。
??????//?widthSegments?—?水平分段數(shù)(沿著經(jīng)線分段)惰匙,最小值為3,默認值為8铃将。
??????//?heightSegments?—?垂直分段數(shù)(沿著緯線分段)项鬼,最小值為2,默認值為6劲阎。
??????//?phiStart?—?指定水平(經(jīng)線)起始角度绘盟,默認值為0。
??????//?phiLength?—?指定水平(經(jīng)線)掃描角度的大小悯仙,默認值為?Math.PI?*?2龄毡。
??????//?thetaStart?—?指定垂直(緯線)起始角度,默認值為0锡垄。
??????//?thetaLength?—?指定垂直(緯線)掃描角度大小沦零,默認值為?Math.PI。
??????//?該幾何體是通過掃描并計算圍繞著Y軸(水平掃描)和X軸(垂直掃描)的頂點來創(chuàng)建的货岭。?因此路操,不完整的球體(類似球形切片)可以通過為phiStart,phiLength千贯,thetaStart和thetaLength設(shè)置不同的值來創(chuàng)建屯仗,?以定義我們開始(或結(jié)束)計算這些頂點的起點(或終點)。
????```
>?initBox?函數(shù)講解
```js
initBox?()?{
??//?添加正方體
??const?geometry?=?new?THREE.BoxGeometry(200,?200,?200)
??//?添加正方體材質(zhì)
??const?material?=?new?THREE.MeshBasicMaterial({?color:?'#ffffff',?map:?new?THREE.TextureLoader().load('https://www.douchuanwei.com/api/files/img/1.jpeg')?})
??//?合成正方體mesh網(wǎng)格
??this.mesh?=?new?THREE.Mesh(geometry,?material)
??this.scene.add(this.mesh)
??//?創(chuàng)建球體
??const?geometry2?=?new?THREE.SphereGeometry(60,?20,?60)
??//?創(chuàng)建球體材質(zhì)
??const?material2?=?new?THREE.MeshLambertMaterial({
????color:?'red',
????wireframe:?true
????//?emissive:0xad1919,
????//?vertexColors:?THREE.NoColors
????//?specular:0x4488ee,
????//?shininess:?12
??})
??//?將球體和材質(zhì)添加到mesh網(wǎng)格
??const?mesh2?=?new?THREE.Mesh(geometry2,?material2)
??//?球體從中心點向x軸平移250
??mesh2.translateX(250)
??this.scene.add(mesh2)
??//?創(chuàng)建第二個球體
??const?geometry3?=?new?THREE.SphereGeometry(60,?20,?60)
??const?material3?=?new?THREE.MeshLambertMaterial({
????color:?'red',?//?紅色球體
????wireframe:?true?//?將球體變成網(wǎng)格
????//?emissive:0xad1919,
????//?vertexColors:?THREE.NoColors
????//?specular:0x4488ee,
????//?shininess:?12
??})
??const?mesh3?=?new?THREE.Mesh(geometry3,?material3)
??mesh3.translateX(-250)
??this.scene.add(mesh3)
},
```
####?第八步
>?幀渲染動畫丈牢,讓場景動起來
```js
animate?()?{
??window.requestAnimationFrame(this.animate)
??//?正方體旋轉(zhuǎn)
??this.mesh.rotation.y?+=?0.02
??this.mesh.rotation.x?+=?0.01
??//?場景旋轉(zhuǎn)
??this.scene.rotation.y?+=?0.01
??this.renderer.render(this.scene,?this.camera)
}
```
####?第九步
>?啟用場景控制器
```js
controlsFn?()?{
??//?tslint:disable-next-line
??this.controls?=?new?OrbitControls(this.camera,?this.renderer.domElement)
},
```
####??controls?知識點
```js
controls.enablePan?=?false;?//禁止右鍵拖拽
controls.enableZoom?=?false;//禁止縮放
controls.enableRotate?=?false;?//禁止旋轉(zhuǎn)
controls.minZoom?=?0.5;?//?最小縮放比例
controls.maxZoom?=?2;?//?放大最大比例
//?上下旋轉(zhuǎn)范圍
controls.minPolarAngle?=?0;
controls.maxPolarAngle?=?Math.PI;
//?左右旋轉(zhuǎn)范圍
controls.minAzimuthAngle?=?-Math.PI?*?(100?/?180);
controls.maxAzimuthAngle?=?Math.PI?*?(100?/?180);
//將其設(shè)為true祭钉,以自動圍繞目標旋轉(zhuǎn)。請注意己沛,如果它被啟用慌核,你必須在你的動畫循環(huán)里調(diào)用.update()。
controls.autoRotate?=?true
//?當.autoRotate為true時申尼,圍繞目標旋轉(zhuǎn)的速度將有多快垮卓,默認值為2.0,相當于在60fps時每旋轉(zhuǎn)一周需要30秒师幕。
controls.autoRotateSpeed?=?2
//?當使用鍵盤按鍵的時候呀页,相機平移的速度有多快。默認值為每次按下按鍵時平移7像素拷姿。
controls.keyPanSpeed?=?7
//?這一對象包含了用于控制相機平移的按鍵代碼的引用寸癌。默認值為4個箭頭(方向)鍵。
controls.keys?=?{
??LEFT:?'ArrowLeft',?//left?arrow
??UP:?'ArrowUp',?//?up?arrow
??RIGHT:?'ArrowRight',?//?right?arrow
??BOTTOM:?'ArrowDown'?//?down?arrow
}
//?移除所有的事件監(jiān)聽
controls.dispose?()?
//?為指定的DOM元素添加按鍵監(jiān)聽稽寒。推薦將window作為指定的DOM元素。
controls.listenToKeyEvents(?domElement?:?HTMLDOMElement?)?
//?更新控制器。必須在攝像機的變換發(fā)生任何手動改變后調(diào)用空镜,或如果.autoRotate或.enableDamping被設(shè)置時,在update循環(huán)里調(diào)用捌朴。
controls.update?()
```
####?完整代碼示例
```js
<template>
??<div?class="three-box-one">
????<div?id="threeone"?/>
??</div>
</template>
<script?lang="ts">
import?Vue?from?'vue';
import?*?as?THREE?from?'three';
import?*?as?OrbitControls?from?'three-orbitcontrols'
interface?DataType?{
????id:?HTMLElement?|?null?|?Object?|?any;
????domW:?Number?|?any;
????domH:?Number?|?any;
????scene:?THREE.Scene?|?null?|?any;
????camera:?THREE.Camera?|?null?|?any;
????renderer:?THREE.Renderer?|?null?|?any;
????mesh:?THREE.Mesh?|?any;
????controls:?null?|?any;
}
export?default?Vue.extend({
??name:?'ThreeTwo',
??layout:?'threelayout',
??data?():?DataType?{
????return?{
??????id:?null,
??????domW:?0,
??????domH:?0,
??????scene:?null,
??????camera:?null,
??????renderer:?null,
??????mesh:?null,
??????controls:?null
????}
??},
??mounted?()?{
????this.id?=?document.getElementById('threeone')
????this.domW?=?this.id.offsetWidth
????this.domH?=?this.id.offsetHeight
????this.init()
??},
??methods:?{
????init?()?{
??????this.scene?=?new?THREE.Scene()
??????this.camera?=?new?THREE.PerspectiveCamera(45,?this.domW?/?this.domH,?0.01,?20000)
??????this.camera.position.z?=?800
??????//?this.camera.position.y?=?100
??????this.renderer?=?new?THREE.WebGLRenderer({
????????antialias:?true,
????????alpha:?true
??????})
??????this.renderer.setSize(this.domW,?this.domH)
??????this.id.appendChild(this.renderer.domElement)
??????this.addLight()
??????this.axisHelper()
??????this.initBox()
??????this.animate()
??????this.onWindowResize()
??????this.controlsFn()
????},
????controlsFn?()?{
??????//?tslint:disable-next-line
??????this.controls?=?new?OrbitControls(this.camera,?this.renderer.domElement)
????},
????initBox?()?{
??????const?geometry?=?new?THREE.BoxGeometry(200,?200,?200)
??????const?material?=?new?THREE.MeshBasicMaterial({?color:?'#ffffff',?map:?new?THREE.TextureLoader().load('https://www.douchuanwei.com/api/files/img/1.jpeg')?})
??????this.mesh?=?new?THREE.Mesh(geometry,?material)
??????this.scene.add(this.mesh)
??????const?geometry2?=?new?THREE.SphereGeometry(60,?20,?60)
??????const?material2?=?new?THREE.MeshLambertMaterial({
????????color:?'red',
????????wireframe:?true
????????//?emissive:0xad1919,
????????//?vertexColors:?THREE.NoColors
????????//?specular:0x4488ee,
????????//?shininess:?12
??????})
??????const?mesh2?=?new?THREE.Mesh(geometry2,?material2)
??????mesh2.translateX(250)
??????this.scene.add(mesh2)
??????const?geometry3?=?new?THREE.SphereGeometry(60,?20,?60)
??????const?material3?=?new?THREE.MeshLambertMaterial({
????????color:?'red',
????????wireframe:?true
????????//?emissive:0xad1919,
????????//?vertexColors:?THREE.NoColors
????????//?specular:0x4488ee,
????????//?shininess:?12
??????})
??????const?mesh3?=?new?THREE.Mesh(geometry3,?material3)
??????mesh3.translateX(-250)
??????this.scene.add(mesh3)
????},
????addLight?()?{
??????const?ambientLight?=?new?THREE.AmbientLight('#ffffff')
??????this.scene.add(ambientLight)
??????const?light?=?new?THREE.DirectionalLight('#ffffff')
??????this.scene.add(light)
??????const?pointLight?=?new?THREE.PointLight('#ffffff',?0.1,?1000)
??????pointLight.position.set(300,?300,?300)
??????this.scene.add(pointLight)
????},
????axisHelper?()?{
??????const?axes:THREE.AxesHelper?=?new?THREE.AxesHelper(800)
??????this.scene.add(axes)
????},
????onWindowResize?()?{
??????window.onresize?=?()?=>?{
????????this.domH?=?this.id.offsetHeight
????????this.domW?=?this.id.offsetWidth
????????this.camera.aspect?=?this.domW?/?this.domH
????????this.camera.updateProjectionMatrix()
????????this.renderer.setSize(this.domW,?this.domH)
??????}
????},
????animate?()?{
??????window.requestAnimationFrame(this.animate)
??????this.mesh.rotation.y?+=?0.02
??????this.mesh.rotation.x?+=?0.01
??????this.scene.rotation.y?+=?0.01
??????this.renderer.render(this.scene,?this.camera)
????}
??}
});
</script>
```
```
[更多內(nèi)容請到小豆包》](https://www.douchuanwei.com/)
>?掃碼訪問小豆包
>?

###?掃碼關(guān)注小豆包公眾號
