什么是glsl
眾所周知threejs是對webGL的封裝,而webGL又是openGL的web版本验靡,而GL則是使用GLSL(OpenGL Shading Language)這種語言來描述胜嗓。
這里有兩張圖描述這種關(guān)系
所以其實(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è)渲染流程入下圖所示
如何在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