three.js淺談@glsl與threejs

什么是glsl

眾所周知threejs是對webGL的封裝,而webGL又是openGL的web版本验靡,而GL則是使用GLSL(OpenGL Shading Language)這種語言來描述胜嗓。
這里有兩張圖描述這種關(guān)系

來自《WebGL編程指南》

來自《WebGL編程指南》

所以其實(shí)threejs也是對glsl的一種封裝,但是threejs也保留了對glsl的接口便于我們直接書寫glsl來更好的從底層的描述我們的圖像

著色器

在GL中繪圖我們就必須要使用2種著色器程序
頂點(diǎn)著色器

頂點(diǎn)著色器是用來描述頂點(diǎn)特性(如位置钩乍、顏色等)的程序辞州。頂點(diǎn)是指二維或三維空間中的一個(gè)點(diǎn),比如二維或三維圖形的端點(diǎn)和交點(diǎn)

頂點(diǎn)是一系列的坐標(biāo)點(diǎn)寥粹,因?yàn)橐粋€(gè)圖形是有大量的三角形構(gòu)成的变过,每一個(gè)三角形就有3個(gè)頂點(diǎn)
頂點(diǎn)著色器的輸入是一系列的頂點(diǎn)信息,比如坐標(biāo)顏色等涝涤,然后將這些信息進(jìn)行處理之后輸出給片源著色器

片元著色器

進(jìn)行逐片元處理過程如光照的程序媚狰。片元是一個(gè)WebGL術(shù)語,你可以將其理解為像素(圖像的單元)

在頂點(diǎn)著色器運(yùn)行完畢之后其實(shí)并不是立馬執(zhí)行片元著色器阔拳,這個(gè)時(shí)候回有一部光柵化的過程哈雏。什么是光柵化呢彭羹?在未光柵化之前,圖形是連續(xù)的拓轻,但是顯示器上面的像素是離散的枣氧,光柵化就是將連續(xù)的圖形轉(zhuǎn)化為離散的“像素”荒典,這個(gè)一個(gè)像素就是一個(gè)片元螃征,當(dāng)然和真正的像素還是有所區(qū)別,比如完全重疊的2個(gè)圖形按像素看就是一份像素,按片元看就要分為“上面的”片元和“下面的”片元

總的來說一個(gè)渲染流程入下圖所示


https://www.adobe.com/devnet/flashplayer/articles/how-stage3d-works.html

如何在theejs中使用glsl

我們這里假裝你已經(jīng)熟知了glsl的語法交排,欠缺的只是如何把threejs和glsl湊合到一起(如果不熟悉的可以移步這里)
先來展示一段代碼

import * as THREE from 'three'

const scene = new THREE.Scene();//創(chuàng)建一個(gè)場景
const camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.z=1//因?yàn)閯倓倓?chuàng)建的對象都會(huì)位于原點(diǎn)同窘,我們需要把相機(jī)拉遠(yuǎn)一點(diǎn)
//創(chuàng)建一個(gè)渲染器,并設(shè)置大小丧没,然后把這個(gè)渲染器加入到dom中
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const vertices = new Float32Array([
    0.0,  0.0, 0.0,//頂點(diǎn)
]);
//將頂點(diǎn)數(shù)組放入緩沖區(qū)域
const verticesPosition = new THREE.BufferAttribute( vertices, 3 );
//創(chuàng)建一個(gè)空白的模型
const geometry = new THREE.BufferGeometry();
//將頂點(diǎn)數(shù)據(jù)傳入到空白模型中
geometry.addAttribute('position',verticesPosition);
//使用著色器材質(zhì)
const material=new THREE.ShaderMaterial({
    vertexShader:  `void main( void ) {
                        gl_Position = vec4( position, 1.0 );
                        gl_PointSize = 100.0;
                    }`,
    fragmentShader:`void main() {
                        gl_FragColor = vec4(0,0,0.9,1.0);
                    }`,
});
const points=new THREE.Points(geometry,material);//模型對象
scene.add( points )//場景中加入多面體
renderer.render(scene, camera);

這段代碼的效果


效果

我們來解釋一下上面這段代碼和之前的不一樣的部分

const vertices = new Float32Array([
    0.0,  0.0, 0.0,//頂點(diǎn)
]);

這是一個(gè)頂點(diǎn)數(shù)數(shù)組套蒂,JavaScript中的普通數(shù)組是無類型的骨坑,但是有時(shí)候js可能也會(huì)與其他強(qiáng)類型的語言溝通礁遣,所以不得不需要有類型的數(shù)組沸呐,因此創(chuàng)建了這一系列的api用來代替類型數(shù)組根暑,一個(gè)頂點(diǎn)由4個(gè)數(shù)據(jù)組成x淳地、y、z蕴茴、w,這4個(gè)數(shù)據(jù)組成的坐標(biāo)稱為齊次坐標(biāo)撞叽,等價(jià)于三維坐標(biāo)x/w、y/w真椿、z/w,因?yàn)閣的值一般是1.0所以就可以省略一個(gè)位置,這個(gè)1.0在著色器中寫死锋八。x/y/z/w的取值范圍是[-1.0,1.0]

const verticesPosition = new THREE.BufferAttribute( vertices, 3 );
//創(chuàng)建一個(gè)空白的模型
const geometry = new THREE.BufferGeometry();
//將頂點(diǎn)數(shù)據(jù)傳入到空白模型中
geometry.addAttribute('position',verticesPosition);

BufferAttribute方法用于將頂點(diǎn)數(shù)據(jù)轉(zhuǎn)化為Threejs需要的對象,第二個(gè)參數(shù)表示3個(gè)一組
BufferGeometry空白的緩存幾何對象挟纱,里面不含任何頂點(diǎn)數(shù)據(jù)
addAttribute向該幾何對象添加屬性第一個(gè)參數(shù)是名稱参萄,第二個(gè)參數(shù)是值痒谴。
值得一提的是槐雾,這里使用了position作為名稱傳遞給幾何對象逐抑,這個(gè)鍵值對最終會(huì)傳遞到頂點(diǎn)著色器里面鸠儿,而頂點(diǎn)著色器必須使用attribute vec3 position;這種方式去接受,但是我們這里卻并沒有在著色器定義這個(gè)變量,原因是因?yàn)閠hreejs預(yù)先幫我們定義好了一系列變量进每,其中就包括position汹粤,因此如果傳無關(guān)變量,就需要自己定義了品追。順帶一提使用著色器材質(zhì)也可以傳遞參數(shù)而且沒這么麻煩

//使用著色器材質(zhì)
const material=new THREE.ShaderMaterial({
    vertexShader:  `void main( void ) {
                        gl_Position = vec4( position, 1.0 );
                        gl_PointSize = 100.0;
                    }`,
    fragmentShader:`void main() {
                        gl_FragColor = vec4(0,0,0.9,1.0);
                    }`,
});

這部分就是我們這次的主角
ShaderMaterial著色器材質(zhì)有2個(gè)配置項(xiàng)一個(gè)是vertexShader(頂點(diǎn)著色器)玄括,一個(gè)是fragmentShader(片元著色器)。
在頂點(diǎn)著色器中我們接到了之前傳過來的position并添上"1.0"成為齊次坐標(biāo)傳遞給gl_Position ,然后設(shè)定點(diǎn)的大小是100.0
在片元著色器中我們將顏色(這里的顏色是rgba肉瓦,參數(shù)是[0.0,1.0])設(shè)定為藍(lán)色冰傳遞給gl_FragColor

const points=new THREE.Points(geometry,material);//模型對象

最后我們有了模型有了材質(zhì)遭京,2者一結(jié)合就形成了我們看到了一個(gè)100像素藍(lán)色點(diǎn)的效果

附錄

Threejs在頂點(diǎn)著色器中預(yù)定義的變量

precision highp float;
precision highp int;
#define HIGH_PRECISION
#define SHADER_NAME ShaderMaterial
#define VERTEX_TEXTURES
#define GAMMA_FACTOR 2
#define MAX_BONES 0
#define BONE_TEXTURE
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat3 normalMatrix;
uniform vec3 cameraPosition;
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
#ifdef USE_TANGENT
    attribute vec4 tangent;
#endif
#ifdef USE_COLOR
    attribute vec3 color;
#endif
#ifdef USE_MORPHTARGETS
    attribute vec3 morphTarget0;
    attribute vec3 morphTarget1;
    attribute vec3 morphTarget2;
    attribute vec3 morphTarget3;
    #ifdef USE_MORPHNORMALS
        attribute vec3 morphNormal0;
        attribute vec3 morphNormal1;
        attribute vec3 morphNormal2;
        attribute vec3 morphNormal3;
    #else
        attribute vec3 morphTarget4;
        attribute vec3 morphTarget5;
        attribute vec3 morphTarget6;
        attribute vec3 morphTarget7;
    #endif
#endif
#ifdef USE_SKINNING
    attribute vec4 skinIndex;
    attribute vec4 skinWeight;
#endif

參考

  1. STAGE3D如何工作:https://www.adobe.com/devnet/flashplayer/articles/how-stage3d-works.html
  2. LearnOpenGL-CN:https://learnopengl-cn.readthedocs.io/zh/latest/
  3. 2: OpenGL ES 2.0 知識串講:http://geekfaner.com/shineengine/blog1_career.html
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市泞莉,隨后出現(xiàn)的幾起案子哪雕,更是在濱河造成了極大的恐慌,老刑警劉巖鲫趁,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斯嚎,死亡現(xiàn)場離奇詭異,居然都是意外死亡挨厚,警方通過查閱死者的電腦和手機(jī)堡僻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疫剃,“玉大人钉疫,你說我怎么就攤上這事〕布郏” “怎么了牲阁?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長壤躲。 經(jīng)常有香客問我城菊,道長,這世上最難降的妖魔是什么碉克? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任凌唬,我火速辦了婚禮,結(jié)果婚禮上漏麦,老公的妹妹穿的比我還像新娘客税。我一直安慰自己,他們只是感情好唁奢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布霎挟。 她就那樣靜靜地躺著,像睡著了一般麻掸。 火紅的嫁衣襯著肌膚如雪酥夭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機(jī)與錄音熬北,去河邊找鬼疙描。 笑死,一個(gè)胖子當(dāng)著我的面吹牛讶隐,可吹牛的內(nèi)容都是我干的起胰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼巫延,長吁一口氣:“原來是場噩夢啊……” “哼效五!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起炉峰,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤畏妖,失蹤者是張志新(化名)和其女友劉穎疼阔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體婆廊,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年淘邻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片列荔。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡敬尺,死狀恐怖枚尼,靈堂內(nèi)的尸體忽然破棺而出贴浙,到底是詐尸還是另有隱情,我是刑警寧澤署恍,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布崎溃,位于F島的核電站,受9級特大地震影響盯质,放射性物質(zhì)發(fā)生泄漏袁串。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一呼巷、第九天 我趴在偏房一處隱蔽的房頂上張望囱修。 院中可真熱鬧,春花似錦王悍、人聲如沸破镰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鲜漩。三九已至源譬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間孕似,已是汗流浹背踩娘。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喉祭,地道東北人养渴。 一個(gè)月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像泛烙,于是被迫代替她去往敵國和親厚脉。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

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