Three.js模型標(biāo)簽
在很多的實(shí)際的項(xiàng)目中,你可能需要給一個(gè)Three.js的模型添加標(biāo)簽缕题,標(biāo)簽可以通過(guò)一個(gè)包含文字圖形信息的HTML元素或者一個(gè)three.js的精靈模型來(lái)表示侯勉。
常見(jiàn)問(wèn)題
- three.js三維模型如何添加注釋文字秘症?
- Three.js模型對(duì)象如何設(shè)置標(biāo)簽?
- three.js如何用HTML元素設(shè)置顯示熱點(diǎn)
- 如何把模型的世界坐標(biāo)轉(zhuǎn)化為屏幕坐標(biāo)?
每個(gè)人的基礎(chǔ)不同偏螺,雖然知識(shí)點(diǎn)區(qū)別不大,可能描述的時(shí)候會(huì)有很大區(qū)別矾瑰。
視頻講解和源碼
下面對(duì)知識(shí)點(diǎn)簡(jiǎn)單介紹,關(guān)于視頻講解可以關(guān)注我博客發(fā)布可的相關(guān)課程隘擎,個(gè)人WebGL/Three.js技術(shù)博客殴穴。
層級(jí)模型
復(fù)雜的項(xiàng)目,一個(gè)three.js場(chǎng)景往往包含包含多個(gè)模型對(duì)象货葬,模型對(duì)象也會(huì)有一些父對(duì)象采幌,這樣就會(huì)形成一個(gè)層級(jí)模型,從數(shù)據(jù)結(jié)構(gòu)的角度來(lái)看就是樹(shù)結(jié)構(gòu)震桶。
一個(gè)模型相對(duì)世界坐標(biāo)系原點(diǎn)的位置是世界坐標(biāo)休傍,相對(duì)父對(duì)象的位置是局部坐標(biāo)。
獲取模型位置
你如果想給一個(gè)模型設(shè)置標(biāo)簽蹲姐,首先需要獲得模型在世界坐標(biāo)系中所在的位置磨取,如果你希望標(biāo)注一個(gè)模型的某個(gè)局部位置,那就要獲得該局部區(qū)域的一個(gè)頂點(diǎn)坐標(biāo)柴墩。
-
.position
屬性是一個(gè)模型的局部位置忙厌,相對(duì)父對(duì)象的位置,如果一個(gè)網(wǎng)格模型Mesh直接屬于場(chǎng)景Scene江咳,沒(méi)有除了Scene意外的父對(duì)象 -
.vertices
如果幾何體是Geometry類型逢净,可以通過(guò).vertices
屬性訪問(wèn)頂點(diǎn),通過(guò)下標(biāo)可以訪問(wèn)具體的頂點(diǎn)位置坐標(biāo)歼指。 -
.attributes.position
如果幾何體是BufferGeometry類型爹土,可以通過(guò).attributes.position
屬性訪問(wèn)頂點(diǎn)位置數(shù)據(jù)。 -
.getWorldPosition()
實(shí)際項(xiàng)目中一個(gè)模型對(duì)象可以有多個(gè)父對(duì)象踩身,這個(gè)時(shí)候想獲得該模型對(duì)象的世界坐標(biāo)胀茵,就不能通過(guò).position
屬性,應(yīng)該通過(guò).getWorldPosition()
方法實(shí)現(xiàn)挟阻,該方法的使用參考基類Object3D
宰掉。
實(shí)際項(xiàng)目中獲得一個(gè)模型,可能是通過(guò)點(diǎn)擊獲得赁濒,或者遍歷對(duì)象根據(jù)屬性值找到某個(gè)或某些模型轨奄,等等這里不展開(kāi)說(shuō),這不是本節(jié)課的重點(diǎn)拒炎,關(guān)于遞歸遍歷模型或者鼠標(biāo)點(diǎn)擊選中某個(gè)模型可以關(guān)注課程的其它部分挪拟。
精靈模型Sprite
作為標(biāo)簽
在使用精靈模型表示標(biāo)簽之前,你應(yīng)該先了解精靈模型Sprite有什么特點(diǎn)击你。使用精靈模型表示一個(gè)模型對(duì)象的標(biāo)簽玉组,那么精靈模型就要位于模型對(duì)象的附近谎柄。可以獲得要標(biāo)注模型的世界坐標(biāo)惯雳,然后來(lái)設(shè)置精靈標(biāo)簽的位置朝巫,適當(dāng)偏移一點(diǎn)就可以,當(dāng)然也可以把精靈對(duì)象插入到模型對(duì)象的父對(duì)象中石景,和模型對(duì)象一樣作為父對(duì)象的子對(duì)象劈猿,這樣的話如果模型父對(duì)象的位置變化,精靈模型可以跟著一起變化潮孽。
標(biāo)簽的樣式可以讓美術(shù)設(shè)計(jì)好直接作為精靈的貼圖就可以揪荣,如果標(biāo)簽不是特定的,比如用戶輸入文字往史,平臺(tái)自動(dòng)生成模型標(biāo)簽仗颈,可以通過(guò)程序自動(dòng)化合成一個(gè)紋理作為精靈模型的貼圖,關(guān)于如何自動(dòng)合成紋理貼圖這里不詳細(xì)闡述椎例。
/**
* 創(chuàng)建點(diǎn)精靈模型
*/
// 創(chuàng)建精靈材質(zhì)對(duì)象SpriteMaterial
var spriteMaterial = new THREE.SpriteMaterial({
map: new THREE.TextureLoader().load("立方體.png"), //設(shè)置精靈紋理貼圖
transparent: true,//開(kāi)啟透明(紋理圖片png有透明信息)
});
// 創(chuàng)建精靈模型對(duì)象挨决,不需要幾何體geometry參數(shù)
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(30, 30, 1); //精靈大小
// 把精靈模型插入到模型對(duì)象的父對(duì)象下面
group.add( sprite);
// 父對(duì)象group位置變化,網(wǎng)格模型及其對(duì)象的標(biāo)簽同樣發(fā)生變化
group.position.set(10, 0, -80);
// 表示標(biāo)簽信息的精靈模型對(duì)象相對(duì)父對(duì)象設(shè)置一定的偏移
sprite.translateY(30);
div
等html元素作為標(biāo)簽(世界坐標(biāo)轉(zhuǎn)屏幕坐標(biāo))
通過(guò)html元素表示標(biāo)簽相比較使用精靈來(lái)說(shuō)比較麻煩,需要進(jìn)行坐標(biāo)變換订歪,一個(gè)模型顯示在Canvas畫(huà)布上凰棉,經(jīng)過(guò)了相機(jī)的視圖、投影變換陌粹,如果想把一個(gè)div元素標(biāo)注在一個(gè)模型附近撒犀,就需要計(jì)算模型渲染到畫(huà)布上的具體位置,也就是所謂的屏幕坐標(biāo)掏秩。使用html元素的好處是可以直接輸入漢字或舞,利用css來(lái)設(shè)置一下標(biāo)簽的樣式,當(dāng)然也可以直接加載美術(shù)設(shè)計(jì)的標(biāo)簽蒙幻。
世界坐標(biāo)轉(zhuǎn)WebGL標(biāo)準(zhǔn)設(shè)備坐標(biāo)
- 世界坐標(biāo):世界坐標(biāo)簡(jiǎn)單說(shuō)就是模型在three.js三維空間中的位置映凳,但是注意不是局部位置屬性
.position
,你可以通過(guò).getWorldPosition()
方法獲得世界坐標(biāo)邮破,每個(gè)子對(duì)象都有一個(gè)相對(duì)父對(duì)象的位置诈豌,把一個(gè)對(duì)象的所有父對(duì)象相對(duì)Scene坐標(biāo)原點(diǎn)的位置加起來(lái)就是一個(gè)模型的世界坐標(biāo) - 屏幕坐標(biāo):你可以理解為Canvas畫(huà)布上的位置,單位是像素px抒和,這和HTML說(shuō)的像素是一樣的矫渔。
//創(chuàng)建一個(gè)三維向量作為世界坐標(biāo)
var worldVector = new THREE.Vector3();
//獲取網(wǎng)格模型boxMesh的世界坐標(biāo),賦值給worldVector
boxMesh.getWorldPosition(worldVector);
//世界坐標(biāo)轉(zhuǎn)標(biāo)準(zhǔn)設(shè)備坐標(biāo)摧莽,standardVector是WebGL設(shè)備坐標(biāo)
var standardVector = worldVector.project(camera);
.project()
是向量Vector3的方法庙洼,一個(gè)表示位置的向量Vector3把相機(jī)作為參數(shù)執(zhí)行該方法可以得到經(jīng)過(guò)相機(jī)變換后的坐標(biāo)。一般threejs渲染器渲染的時(shí)候,會(huì)自動(dòng)從相機(jī)對(duì)象讀取視圖和投影矩陣對(duì)模型的頂點(diǎn)進(jìn)行變換油够。
WebGL標(biāo)準(zhǔn)設(shè)備坐標(biāo)轉(zhuǎn)屏幕坐標(biāo)
Canvas全屏顯示的時(shí)候復(fù)合下面的計(jì)算規(guī)則蚁袭,如果不是全屏要注意修改計(jì)算規(guī)則。如果不是全屏石咬,計(jì)算a和b的值揩悄,不能使用window.innerWidth,而應(yīng)該使用canvas的具體寬高鬼悠。如果canvas是局部顯示相對(duì)body區(qū)域的左上角有偏移删性,那么div元素也要設(shè)置一定的偏移。
// 根據(jù)WebGL標(biāo)準(zhǔn)設(shè)備坐標(biāo)standardVector計(jì)算div標(biāo)簽在瀏覽器頁(yè)面的坐標(biāo)
var a = window.innerWidth / 2;
var b = window.innerHeight / 2;
var x = Math.round(standardVector.x * a + a); //標(biāo)準(zhǔn)設(shè)備坐標(biāo)轉(zhuǎn)屏幕坐標(biāo)
var y = Math.round(-standardVector.y * b + b); //標(biāo)準(zhǔn)設(shè)備坐標(biāo)轉(zhuǎn)屏幕坐標(biāo)
/**
* 設(shè)置標(biāo)簽元素的位置
*/
div.style.left = x + 'px';
//這里的130px主要是為了標(biāo)簽和模型有一定偏移厦章,當(dāng)然也可以不設(shè)置镇匀,兩者疊加在一起
div.style.top = y - 130 + 'px';