vue+three.js的3D可視化機(jī)房

1、WebGL與threeJS

WebGL是一種3D繪圖協(xié)議期虾,其允許JavaScript和OpenGL ES2.0結(jié)合在一起原朝,為H5 Canvas提供硬件3D加速渲染,可以借助系統(tǒng)顯卡在瀏覽器里更流暢地顯示3D場(chǎng)景和模型镶苞。Threejs是一款webGL框架喳坠,由于其易用性被廣泛應(yīng)用。Threejs在WebGL的api接口基礎(chǔ)上茂蚓,又進(jìn)行了一層封裝壕鹉。

WebGL原生的api是一種非常低層的接口剃幌,需要一些數(shù)學(xué)和圖形學(xué)的相關(guān)技術(shù)。其解決是如何在畫布上畫圖的問(wèn)題晾浴,怎么畫點(diǎn)负乡、線、面脊凰,怎么上色抖棘,怎么貼圖,怎么處理光線狸涌,視角轉(zhuǎn)動(dòng)之后怎么換算繪制等等切省。對(duì)于沒(méi)有相關(guān)基礎(chǔ)的人來(lái)說(shuō),入門很難帕胆,Three.js將入門的門檻降低了一大截朝捆,其解決底層的渲染細(xì)節(jié)和復(fù)雜的數(shù)據(jù)結(jié)構(gòu),將復(fù)雜的底層細(xì)節(jié)抽象出來(lái)懒豹,簡(jiǎn)化我們創(chuàng)建三維動(dòng)畫場(chǎng)景的過(guò)程芙盘。

2、ThreeJs核心概念

為快速入手歼捐,在使用threejs之前何陆,需要了解場(chǎng)景、照相機(jī)豹储、對(duì)象贷盲、光、渲染器等核心概念剥扣。

2.1巩剖、場(chǎng)景-Scene

場(chǎng)景是所有物體的容器,對(duì)應(yīng)著現(xiàn)實(shí)生活中三維世界钠怯,所有的可視化對(duì)象及相關(guān)的動(dòng)作均發(fā)生在場(chǎng)景中佳魔。

2.2、照相機(jī)-Camera

Camera是三維世界中觀察者晦炊,類似與眼睛鞠鲜。為了觀察這個(gè)世界,需要描述空間中的位置断国,three.js采用右手坐標(biāo)系

image2021-1-4_11-40-25.png

Threejs中的Camera有兩種贤姆,分別是正交投影相機(jī)THREE.OrthographicCamera和透視投影相機(jī)THREE.PerspectiveCamera

image2021-1-4_11-40-31.png

正交投影與透視投影的區(qū)別如上圖所示,左圖是正交投影稳衬,物體發(fā)出的光平行地投射到屏幕上霞捡,遠(yuǎn)近的方塊都是一樣大的;右圖是透視投影薄疚,近大遠(yuǎn)小碧信,符合我們平時(shí)看東西的感覺(jué)

2.3赊琳、對(duì)象-Objects

這是著名的斯坦福兔子,隨著三角形數(shù)量的增加砰碴,它的表面越來(lái)越平滑準(zhǔn)確躏筏。

image2021-1-4_11-40-37.png

在Three中,Mesh的構(gòu)造函數(shù)是這樣的:Mesh( geometry, material )呈枉。geometry是它的形狀寸士,material是它的材質(zhì)。不止是Mesh碴卧,創(chuàng)建很多物體都要用到這兩個(gè)屬性。下面我們來(lái)看看這兩個(gè)重要的屬性乃正。

Geometry--形狀住册,它通過(guò)存儲(chǔ)模型用到的點(diǎn)集和點(diǎn)間關(guān)系(哪些點(diǎn)構(gòu)成一個(gè)三角形)來(lái)達(dá)到描述物體形狀的目的。Three提供了立方體(其實(shí)是長(zhǎng)方體)瓮具、平面(其實(shí)是長(zhǎng)方形)荧飞、球體、圓形名党、圓柱叹阔、圓臺(tái)等6種基本形狀;你也可以通過(guò)自己定義每個(gè)點(diǎn)的位置來(lái)構(gòu)造形狀传睹;對(duì)于比較復(fù)雜的形狀耳幢,我們還可以通過(guò)外部的模型文件導(dǎo)入。

Material--材質(zhì)欧啤,材質(zhì)其實(shí)是物體表面除了形狀以為所有可視屬性的集合睛藻,例如色彩、紋理邢隧、光滑度店印、透明度、反射率倒慧、折射率按摘、發(fā)光度。Threejs里需要知道材質(zhì)(Material)纫谅、貼圖(Map)和紋理(Texture)的關(guān)系炫贤。材質(zhì)包括了貼圖以及其它。貼圖其實(shí)是‘貼’和‘圖’系宜,它包括了圖片和圖片應(yīng)當(dāng)貼到什么位置照激。紋理其實(shí)就是‘圖’。對(duì)于復(fù)雜的材質(zhì)盹牧,可以通過(guò)Threejs提供的貼圖和紋理api實(shí)現(xiàn)俩垃。同時(shí)励幼,Threejs提供了多種材質(zhì)可供選擇,能夠自由地選擇漫反射/鏡面反射等材質(zhì)口柳。
Points是另一種對(duì)象苹粟,其實(shí)就是一堆點(diǎn)的集合,它在之前很長(zhǎng)時(shí)間都被稱為ParticleSystem(粒子系統(tǒng))跃闹,而Three中的Points簡(jiǎn)單得多嵌削。因此最終這個(gè)類被命名為Points。

2.4望艺、光-Light

同現(xiàn)實(shí)世界一樣苛秕,我們要看到物體需要光,光影效果是讓畫面豐富的重要因素找默。Three提供了包括環(huán)境光AmbientLight艇劫、點(diǎn)光源PointLight、 聚光燈SpotLight惩激、方向光DirectionalLight店煞、半球光HemisphereLight等多種光源。只要在場(chǎng)景中添加需要的光源风钻,即可實(shí)現(xiàn)相應(yīng)得光效果顷蟀。

2.5、渲染器-Renderer

在場(chǎng)景中建立了各種物體骡技,也有了光鸣个,還有觀察物體的相機(jī),Renderer則負(fù)責(zé)將物體渲染到場(chǎng)景中布朦。Renderer綁定一個(gè)canvas對(duì)象毛萌,并可以設(shè)置大小,默認(rèn)背景顏色等屬性喝滞。
調(diào)用Renderer的render函數(shù)阁将,傳入scene和camera,就可以把圖像渲染到canvas中了右遭。

3做盅、vue結(jié)合three.js(準(zhǔn)備工作)

  1. 安裝three.js

  2. 安裝three-orbit-controls安裝軌道控件插件

  3. 安裝threebsp

  4. 安裝tweenjs/tween.js

npm install three three-orbit-controls threebsp tweenjs/tween.js -S

在需要用到的vue文件中導(dǎo)入

import * as THREE from 'three'

import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'

import 'imports-loader?THREE=three!threebsp'

import TWEEN from '@tweenjs/tween.js'
  • ThreeJs制作3D可視化機(jī)房
    image2021-1-4_11-40-58.png

目標(biāo)圖

3.1、初始化場(chǎng)景和相機(jī)

布置場(chǎng)景容器窘哈,之后所有我們創(chuàng)建的對(duì)象都會(huì)在scene場(chǎng)景對(duì)象中吹榴,相機(jī)的作用就相當(dāng)與人的眼睛。通過(guò)add()方法將創(chuàng)建的對(duì)象插入至場(chǎng)景中滚婉。

*// 獲取場(chǎng)景容器*

this.container = this.$refs.home*// 創(chuàng)建場(chǎng)景*

this.scene = new THREE.Scene()

let width = this.container.clientWidth*//窗口寬度*

let height = this.container.clientHeight*//窗口高度*

let k = width/height*//窗口寬高比*

let s = 200 

*//創(chuàng)建相機(jī)對(duì)象*

this.camera = new THREE.OrthographicCamera(-s*k ,s*k ,s ,-s ,1 , 1000)

this.camera.position.set(80,100,200)*//設(shè)置相機(jī)位置*

this.camera.lookAt(this.scene.position)*//設(shè)置相機(jī)方向(指向場(chǎng)景對(duì)象)*

this.scene.add(this.camera)

3.2图筹、初始化渲染器

渲染場(chǎng)景容器,使場(chǎng)景呈現(xiàn)在頁(yè)面中,并且設(shè)置容器的大小登屬性

/*

  • 創(chuàng)建渲染器對(duì)象*

*/

this.renderer = new THREE.WebGLRenderer()

this.renderer.setSize(width, height)*//設(shè)置渲染區(qū)域尺寸*

this.renderer.setClearColor(0x375e98,1)*//設(shè)置**渲染區(qū)域背景*

this.container.appendChild(this.renderer.domElement)*//home元素中插入canvas對(duì)象*

3.3远剩、構(gòu)建光系統(tǒng)

沒(méi)有光源的場(chǎng)景中是一片漆黑的扣溺,就算渲染器設(shè)置了渲染區(qū)域顏色,我們也看不見瓜晤,你可以理解為地球的夜晚中沒(méi)有光就會(huì)什么都看不見

點(diǎn)光源:THREE.PointLight()創(chuàng)建锥余,光線會(huì)從一個(gè)點(diǎn)向四周擴(kuò)散

環(huán)境光源:THREE.AmbientLight()環(huán)境光顏色與網(wǎng)格模型的顏色進(jìn)行RGB進(jìn)行乘法運(yùn)算,僅僅使用環(huán)境光的情況下痢掠,你會(huì)發(fā)現(xiàn)整個(gè)立方體沒(méi)有任何棱角感驱犹,這是因?yàn)榄h(huán)境光知識(shí)設(shè)置整個(gè)空間的明暗效果。如果需要立方體渲染要想有立體效果足画,需要使用具有方向性的點(diǎn)光源雄驹、平行光源等

*//點(diǎn)光源*

this.point1 = new THREE.PointLight(0xffffff)

this.point1.position.set(400,400,300)*//設(shè)置點(diǎn)光源位置*

this.scene.add(this.point1)

*//環(huán)境光源*
 
this.ambient = new THREE.AmbientLight(0x333333)

this.scene.add(this.ambient)

3.4、繪制機(jī)房地板

為了使機(jī)房的地板有自己的樣式淹辞,我找了一張地板紋理貼圖荠医,需要注意的是,紋理圖的尺寸都需要是寬和高都是2的冪桑涎,例如128x128、256*256等兼贡,這樣出來(lái)效果才會(huì)好攻冷。這也是3D軟件一般所要求的。另外紋理要能連續(xù)拼接不露破綻遍希,這樣才好

image2021-1-4_11-41-27.png

通過(guò)紋理貼圖加載器[TextureLoader]的load()方法加載一張圖片可以返回一個(gè)紋理對(duì)象Texture等曼,紋理對(duì)象Texture可以作為模型材質(zhì)顏色貼圖.map屬性的值。

//創(chuàng)建地板

let box = new THREE.BoxBufferGeometry(400,400,4)*//創(chuàng)建一個(gè)長(zhǎng)400凿蒜,寬400禁谦,厚度4的立方體*

let texture = new THREE.TextureLoader().load(require('../assets/textures/floor3.png'))*//加載紋理貼圖*

texture.wrapS = THREE.RepeatWrapping;*//水平方向紋理的包裹方式簡(jiǎn)單地重復(fù)到無(wú)窮大*

texture.wrapT = THREE.RepeatWrapping;*//垂直方向紋理的包裹方式簡(jiǎn)單地重復(fù)到無(wú)窮大*

texture.repeat.set( 12, 12 );*//水平、垂直重復(fù)次數(shù)*

let material = new THREE.MeshLambertMaterial({

   map:texture *//材質(zhì)引用紋理貼圖*

})

this.mesh1 = new THREE.Mesh(box,material) *//創(chuàng)建網(wǎng)格對(duì)象*

this.mesh1.rotation.x = 0.5*Math.PI *//x軸旋轉(zhuǎn)*

this.scene.add(this.mesh1)

效果如下:

image2021-1-4_11-41-34.png

3.5废封、繪制機(jī)房過(guò)道邊墻

使為了減少重復(fù)代碼州泊,封裝了一個(gè)創(chuàng)建網(wǎng)格對(duì)象并插入場(chǎng)景方位的方法

*/**

*        *  ===========創(chuàng)建墻面*

*        *  width:寬度*

*        *  height:高度*

*        *  depth:深度*

*        *  angle:y軸旋轉(zhuǎn)角度*

*        *  material:材質(zhì)*

*        *  x:x坐標(biāo)位置*

*        *  y:y坐標(biāo)位置*

*        *  z:z坐標(biāo)位置*

*    */*

createWall(width, height, depth, x, y, z,material, rotationX, rotationY, rotationZ){

      let geometry = new THREE.BoxGeometry(width,height,depth)

      let wall = new THREE.Mesh(geometry, material)

      wall.position.set(x,y,z)

      if (rotationX) {

        wall.rotation.x += rotationX * Math.PI;*//-逆時(shí)針旋轉(zhuǎn),+順時(shí)針*

      }

      if (rotationY) {

        wall.rotation.y += rotationY * Math.PI;*//-逆時(shí)針旋轉(zhuǎn),+順時(shí)針*

      }

      if (rotationZ) {

        wall.rotation.z += rotationZ * Math.PI;*//-逆時(shí)針旋轉(zhuǎn),+順時(shí)針*

      }

    return wall

},

為創(chuàng)建玻璃效果,使用MeshStandardMaterial漂洋,PBR物理材質(zhì)遥皂,相比較高光Phong材質(zhì)可以更好的模擬金屬、玻璃等效果

并且為了讓玻璃拼接到墻內(nèi)去刽漂,threeBSP庫(kù)演训,可以將現(xiàn)有的模型組合出更多個(gè)性的模型來(lái)使用,它提供了3個(gè)方法來(lái)方便自由組合模型

  • intersect(交集):使用該函數(shù)可以基于兩個(gè)現(xiàn)有幾何體的重合的部分定義此幾何體的形狀贝咙。
  • union(并集):使用該函數(shù)可以將兩個(gè)幾何體聯(lián)合起來(lái)創(chuàng)建出一個(gè)新的幾何體样悟。
  • subtract(差集):使用該函數(shù)可以在第一個(gè)幾何體中移除兩個(gè)幾何體重疊的部分來(lái)創(chuàng)建新的幾何體。
*//窗戶材質(zhì)*
let windowMaterial = new THREE.MeshStandardMaterial({

    color:0x049ef4,*//注意:**transparent**必須設(shè)置為true,**opacity**的值才會(huì)生效*

    opacity:0.5,

    transparent:true,

})

*//創(chuàng)建邊墻*
let wall1 = this.createWall(400,60,6,-197,32,0,wallMaterial,0,0.5,0)

*//創(chuàng)建ThreeBSP對(duì)象*

let windowLeftBSP = new ThreeBSP(windowLeft)*//窗孔*

let wall1BSP = new ThreeBSP(wall1)

*//差集:新的模型會(huì)失去網(wǎng)格類型和網(wǎng)格材質(zhì),需要重新賦予----注意*

let resultwall1BSP = wall1BSP.subtract(windowLeftBSP)

*//更新網(wǎng)格對(duì)象*

let resultwall1 = resultwall1BSP.toMesh()

*//更新網(wǎng)格材質(zhì)*

resultwall1.material = wallMaterial

*//玻璃窗*

let windowleftTrue = this.createWall(400,45,2,-197,32,0,windowMaterial,0,0.5,0)

this.scene.add(resultwall1)

this.scene.add(windowleftTrue)

效果如下:

image2021-1-4_11-41-45.png

3.6窟她、繪制機(jī)房墻和綁定點(diǎn)擊事件

方法跟創(chuàng)建過(guò)道邊墻一樣陈症,利用threeBSP合成想要的墻體效果,但是為了使機(jī)房交互性更更強(qiáng)礁苗,添加了一個(gè)開門關(guān)門動(dòng)作爬凑。

由于在threeJS中,網(wǎng)格對(duì)象自身的旋轉(zhuǎn)试伙、平移都是針對(duì)于本身的中心為原點(diǎn)進(jìn)行的嘁信,所有使用Object3D()模型對(duì)象,它可以添加多個(gè)模型對(duì)象疏叨,要想門圍繞著自己的邊旋轉(zhuǎn)潘靖,就需要把門網(wǎng)格對(duì)象平移到Object3D()模型對(duì)象的中心,這樣開門的時(shí)候控制Object3D()模型對(duì)象繞y軸旋轉(zhuǎn)就可以實(shí)現(xiàn)開門關(guān)門了蚤蔓。

this.door3D = new THREE.Object3D()

let doorGeometry = new THREE.BoxGeometry(28,40,2)

let doorTexture = new THREE.TextureLoader().load(require('../assets/textures/door.png'));

let doorMaterial = new THREE.MeshLambertMaterial({map:doorTexture,side:THREE.DoubleSide,transparent:true});

let doorTrue = new THREE.Mesh( doorGeometry, doorMaterial )

doorTrue.position.x = 14

[doorTrue.name](http://doortrue.name/) = '房門'

實(shí)現(xiàn)方法是清楚了卦溢,可是如何給場(chǎng)景里的模型對(duì)象綁定點(diǎn)擊事件呢?這和普通的2D平面不一樣秀又,場(chǎng)景如何知道光標(biāo)位置以及作用的模型是哪個(gè)单寂?

光線投射(Raycaster):光線投射用于進(jìn)行鼠標(biāo)拾取(在三維空間中計(jì)算出鼠標(biāo)移過(guò)了什么物體)吐辙。

用戶點(diǎn)擊屏幕的時(shí)候宣决,threejs會(huì)根據(jù)視角從觸碰點(diǎn)會(huì)發(fā)射一條“激光”,激光掃到的所有記錄在數(shù)組里的對(duì)象昏苏,都被會(huì)捕捉到尊沸。

.setFromCamera(coords:Vector2,camera:Camera)

coords —— 在標(biāo)準(zhǔn)化設(shè)備坐標(biāo)中鼠標(biāo)的二維坐標(biāo) —— X分量與Y分量應(yīng)當(dāng)在-1到1之間。
camera —— 射線所來(lái)源的攝像機(jī)贤惯。

.intersectObjects(objects:Array,recursive:Boolean,optionalTarget:Array)

objects —— 檢測(cè)和射線相交的一組物體洼专。
recursive —— 若為true,則同時(shí)也會(huì)檢測(cè)所有物體的后代孵构。否則將只會(huì)檢測(cè)對(duì)象本身的相交部分屁商。默認(rèn)值為false。
optionalTarget —— (可選)(可選)設(shè)置結(jié)果的目標(biāo)數(shù)組颈墅。如果不設(shè)置這個(gè)值棒假,則一個(gè)新的Array會(huì)被實(shí)例化;如果設(shè)置了這個(gè)值精盅,則在每次調(diào)用之前必須清空這個(gè)數(shù)組(例如:array.length = 0;)帽哑。

檢測(cè)所有在射線與這些物體之間,包括或不包括后代的相交部分叹俏。返回結(jié)果時(shí)妻枕,相交部分將按距離進(jìn)行排序,最近的位于第一個(gè)),相交部分和.intersectObject所返回的格式是相同的屡谐。

*//給容器綁定點(diǎn)擊事件述么,以獲取光標(biāo)與容器的相對(duì)位置*
this.container.addEventListener( 'click', e => this.doorHandle(e), false );

this.raycaster = new THREE.Raycaster()

*//門點(diǎn)擊事件*

doorHandle(event){

   event.preventDefault();

   this.mouse.x = (event.offsetX/this.renderer.domElement.clientWidth) * 2 - 1

   this.mouse.y = -(event.offsetY/this.renderer.domElement.clientHeight) *2 + 1

      *// 通過(guò)鼠標(biāo)點(diǎn)的位置和當(dāng)前相機(jī)的矩陣計(jì)算出raycaster*

   this.raycaster.setFromCamera( this.mouse, this.camera );

      *// 獲取raycaster直線和所有模型相交的數(shù)組集合*

   let intersects = this.raycaster.intersectObjects( this.scene.children,true );

   if (intersects.length > 0 && intersects[0].[object.name](http://object.name/) == '房門') {

      if (this.closeDoorFlag) {

        this.tweenTransform(this.door3D,500,0.4*Math.PI)

        this.closeDoorFlag = false

       } else {

           this.tweenTransform(this.door3D,500,0*Math.PI)

           this.closeDoorFlag = true

       }

  return

}

this.cabinetList3D.forEach(item => {

        if (item.children[1].children[0].name == intersects[0].[object.name](http://object.name/)) {

          if (item.children[1].closeFlag) {

            this.tweenTransform(item.children[1],500,0*Math.PI)

            item.children[1].closeFlag = false

          } else {

            this.tweenTransform(item.children[1],500,0.6*Math.PI)

            item.children[1].closeFlag = true

          }

        }

      })

    },

這樣一來(lái)點(diǎn)擊事件已經(jīng)綁定成功了,但突如其來(lái)的關(guān)門動(dòng)作顯得很生硬愕掏,這里還用到了tween.js度秘,借助tween.js快速創(chuàng)建補(bǔ)間動(dòng)畫,可以非常方便的控制機(jī)械饵撑、游戲角色運(yùn)動(dòng)

效果如圖:

image2021-1-4_11-41-56.png

3.7剑梳、繪制機(jī)房盆栽

createPlant(x,y,z){

      let plant = new THREE.Object3D();

      let geometryplant = new THREE.CylinderBufferGeometry( 5, 3, 10, 22 );

      let materialplant = new THREE.MeshLambertMaterial( {color: 0x845527} );

      let cylinder = new THREE.Mesh( geometryplant, materialplant );

      cylinder.position.x = 0;

      cylinder.position.y = 4;

      cylinder.position.z = 0;

      plant.add( cylinder );

      let leafTexture = new THREE.TextureLoader().load(require('../assets/textures/plant1.png'));

      let leafMaterial = new THREE.MeshBasicMaterial({map:leafTexture,side:THREE.DoubleSide,transparent:true});

      let geom = new THREE.PlaneGeometry(12, 24);

      for(var i=0;i<4;i++){

        let leaf = new THREE.Mesh( geom, leafMaterial );

        leaf.position.y = 18;

        leaf.rotation.y = -Math.PI/(i+1);

        plant.add(leaf);

      }
      plant.position.x = x;

      plant.position.y = y;

      plant.position.z = z;

      return plant

    },

效果如下:

image2021-1-4_11-42-5.png

3.8、繪制機(jī)柜

createCabinet(x,z,id){

      let cabinet3D = new THREE.Object3D()

      let cabinetTexture = new THREE.TextureLoader().load(require('../assets/textures/jigui4.png'));

      cabinetTexture.wrapS = THREE.RepeatWrapping;

      cabinetTexture.wrapT = THREE.RepeatWrapping;

      cabinetTexture.repeat.set( 1, 1 );

      let cabinetMaterial = new THREE.MeshLambertMaterial(

        {

          map:cabinetTexture,

          side:THREE.DoubleSide,transparent:true,

        }

      );

      let outsideBox = new THREE.BoxGeometry(30,60,36)

      let outside = new THREE.Mesh(outsideBox,cabinetMaterial)

      let insideBox = new THREE.BoxGeometry(26,56,32)

      let inside = new THREE.Mesh(insideBox,cabinetMaterial)

      inside.position.x = 2

      let outsideBSP = new ThreeBSP(outside)

      let insideBSP = new ThreeBSP(inside)

      let cabinetBSP = outsideBSP.subtract(insideBSP)

      let cabinet = cabinetBSP.toMesh()

      cabinet.material = cabinetMaterial

      cabinet3D.add(cabinet)

      let cabDoor3D = new THREE.Object3D()

      let cabDoorTexture = new THREE.TextureLoader().load(require('../assets/textures/cabDoor3.jpg'));

      let cabDoorMaterial = new THREE.MeshLambertMaterial(

        {

          map:cabDoorTexture,

          side:THREE.DoubleSide,transparent:true,

        }

      );

      let cabDoorBox = new THREE.BoxGeometry(1,56,32)

      let cabDoor = new THREE.Mesh(cabDoorBox,cabDoorMaterial)

      [cabDoor.name](http://cabdoor.name/) = id

      cabDoor.position.z = 16

      cabDoor3D.add(cabDoor)

      cabDoor3D.closeFlag = false

      cabDoor3D.position.set(14,0,-16)

      cabinet3D.add(cabDoor3D)

      cabinet3D.position.set(x,32,z)

      return cabinet3D

    },

效果如下:

image2021-1-4_11-42-14.png

4滑潘、總結(jié)

前端開發(fā)要學(xué)習(xí)的地方還是太多了垢乙,多種技術(shù)交替穿插使用。webgl算是最難的一門技術(shù)之一语卤,難點(diǎn)不在于技術(shù)的難追逮,而在于靈活性大、涉及知識(shí)面廣粹舵。而three.js是我去年就知道的一個(gè)基于webgl的框架钮孵,3d機(jī)房是一個(gè)很好的學(xué)習(xí)過(guò)程,也很高興自己能在工作閑暇的時(shí)候接觸到three.js眼滤,也會(huì)繼續(xù)實(shí)現(xiàn)功能更多更復(fù)雜的3d機(jī)房巴席。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市柠偶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌睬关,老刑警劉巖诱担,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異电爹,居然都是意外死亡蔫仙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門丐箩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)摇邦,“玉大人,你說(shuō)我怎么就攤上這事骡显√萦埃” “怎么了丑慎?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)鸥昏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任九秀,我火速辦了婚禮痹换,結(jié)果婚禮上畅厢,老公的妹妹穿的比我還像新娘浦楣。我一直安慰自己油狂,他們只是感情好夹供,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布鸟辅。 她就那樣靜靜地躺著,像睡著了一般贸铜。 火紅的嫁衣襯著肌膚如雪蛋济。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天川尖,我揣著相機(jī)與錄音缰贝,去河邊找鬼侵状。 笑死艇潭,一個(gè)胖子當(dāng)著我的面吹牛鳍寂,可吹牛的內(nèi)容都是我干的迄汛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼刃唤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼隔心!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起尚胞,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤硬霍,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后笼裳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唯卖,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年躬柬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拜轨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡允青,死狀恐怖橄碾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颠锉,我是刑警寧澤法牲,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站琼掠,受9級(jí)特大地震影響拒垃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瓷蛙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一悼瓮、第九天 我趴在偏房一處隱蔽的房頂上張望戈毒。 院中可真熱鬧,春花似錦横堡、人聲如沸埋市。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)恐疲。三九已至,卻和暖如春套么,著一層夾襖步出監(jiān)牢的瞬間培己,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工胚泌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留省咨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓玷室,卻偏偏與公主長(zhǎng)得像零蓉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子穷缤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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