varying 傳遞著色資訊
文章推薦指數: 80 %
至今為止的範例,片段著色器的gl_FragColor 都是寫死的,然而attribute 只能用在頂點著色器中,若想自行指定顏色資訊,應當如何傳遞給片段著色器? 著色器的設計, ...
回WebGL
至今為止的範例,片段著色器的gl_FragColor都是寫死的,然而attribute只能用在頂點著色器中,若想自行指定顏色資訊,應當如何傳遞給片段著色器?
著色器的設計,基本上應該只針對各個頂點與像素,不能直接指定資訊給片段著色器,是可以理解的,想要傳遞給片段著色器的資訊,可以透過varying變數,它是頂點著色器的輸出,片段著色器的輸入。
最單純的做法是,將顏色資訊指定給頂點著色器,然後透過varying傳遞至片段著色器,例如:
頂點著色器會有預設的精度highp,然而片段著色器沒有預設精度,因此在片段著色器必須指定精度,precisionmediumpfloat的指定方式會適用整個片段著色器,也可以使用varyingmediumpvec4fColor的方式個別指定,可以指定的精度有highp、mediump與lowp,越高的精度負擔越大,在某些效能不好的行動裝置上可能會有問題,然而低精度可能有損繪製的效果呈現,通常mediump是個風險較低的權衡做法。
片段著色器的varying變數與頂點著色器的varying名稱相同,這表示頂點著色器中被指定的值,會傳遞到片段著色器中的同名變數。
來寫個隨機畫彩色線的例子作為示範,先建立頂點以及顏色資訊:
//頂點數
constn=20;
constverteices=[];
for(leti=0;i<3*n;i+=3){
verteices[i]=Math.random()-0.5;//x
verteices[i+1]=Math.random()-0.5;//y
verteices[i+2]=Math.random()-0.5;//z
}
//頂點Buffer
constvertexBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(verteices),gl.STATIC_DRAW);
constcolors=[];
for(leti=0;i<4*n;i+=4){
colors[i]=Math.random();//R
colors[i+1]=Math.random();//G
colors[i+2]=Math.random();//B
colors[i+3]=Math.random();//Alpha
}
//顏色Buffer
constcolorBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(colors),gl.STATIC_DRAW);
顏色的資訊是隨機產生的,接下來,指定頂點與顏色等資訊給各個attribute變數並繪製:
//指定給各attribute
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
constattr_position=gl.getAttribLocation(prog,'position');
gl.vertexAttribPointer(attr_position,3,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(attr_position);
gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);
constattr_color=gl.getAttribLocation(prog,'color');
gl.vertexAttribPointer(attr_color,4,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(attr_color);
gl.uniform1f(
gl.getUniformLocation(prog,'aspect'),
gl.canvas.clientWidth/gl.canvas.clientHeight
);
//繪製
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.LINES,0,20);
可以按一下範例網頁來看看效果,這邊也擷個圖來展示一下:
varying之所為varying,是因為在片段著色器中,varying變數的值是會變化的,也就是片段著色器會自動根據兩個頂點座標處指定的varying變數值,為每個像素計算出插值來執行演算內容,最後指定給gl_FragColor,這也就是為何你會看到有漸層色的線段。
另一種常見的著色方式,是根據頂點資訊來做些顏色資訊的演算,例如,來個正四面體旋轉:
正四面體的四個面都是正三角,只不過,該怎麼計算頂點呢?拿出三角函數是一個方式,不過,其實正四面體可以連接正立方體的四個頂點來畫出來:
那麼要用drawArray還是drawElement呢?也就是,該用無索引頂點還是搭配頂點索引陣列呢?對正四面體來說都可以!這邊先示範使用無索引頂點,也就是使用drawArray的方式,正四面體可以有共用邊,將之展開的話就可以清楚看出:
這邊打算讓正四面體的四個面呈現漸層色,漸層的資訊是根據頂點而來:
在JavaScript的部份,就只要指定頂點等資訊:
//正四面體
constn=0.25;
constverteices=[
n,-n,-n,
-n,-n,n,
n,n,n,
-n,n,-n,
n,-n,-n,
-n,-n,n
];
rotateXY(verteices,Math.PI/3,0);
//頂點Buffer
constvertexBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(verteices),gl.DYNAMIC_DRAW);
constattr_position=gl.getAttribLocation(prog,'position');
gl.vertexAttribPointer(attr_position,3,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(attr_position);
gl.uniform1f(
gl.getUniformLocation(prog,'aspect'),
gl.canvas.clientWidth/gl.canvas.clientHeight
);
接下來就是繪製的部份,結合了滑鼠事件以及requestAnimationFrame,因為繪製時會有共用邊,因此drawArrays時搭配的是gl.TRIANGLE_STRIP:
letanimation=false;
functiondrawTetrahedron(){
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP,0,6);
rotateXY(verteices,0,0.025);
gl.bufferSubData(gl.ARRAY_BUFFER,0,newFloat32Array(verteices));
if(animation){
requestAnimationFrame(drawTetrahedron);
}
}
gl.canvas.addEventListener('mousedown',()=>{
animation=!animation;
if(animation){
drawTetrahedron();
}
});
drawTetrahedron();
你可以按一下範例網頁看看效果,看起來好像不錯,不過其實並不是正確的繪製結果,仔細看的話,會發現應該是看不見的背面也被繪製了,這有兩種方式可以解決,一是啟用深度測試讓較深的點不會繪製,二是啟用面剔除(Faceculling),不繪製背面,這就留待下一篇來說明。
延伸文章資訊
- 1Using gl_FragColor vs. out vec4 color? - Stack Overflow
Writing to gl_FragColor specifies the fragment color that will be used by the subsequent fixed fu...
- 2找gl_FragColor相關社群貼文資訊| 服飾貼文懶人包-2022年1月
關於「gl_FragColor」標籤,搜尋引擎有相關的訊息討論:. 使用shaders 在WebGL 上色- Web APIs | MDN。 ARRAY_BUFFER, new Float32A...
- 3[Day9] webGL 修羅道- 特效實戰及總結 - iT 邦幫忙
我們把處理過後的紋理座標和sampler 結合在一起,並且傳值給 gl_FragColor 。 完整的fragment shader 會長這樣: precision mediump float;...
- 4varying 傳遞著色資訊
至今為止的範例,片段著色器的gl_FragColor 都是寫死的,然而attribute 只能用在頂點著色器中,若想自行指定顏色資訊,應當如何傳遞給片段著色器? 著色器的設計, ...
- 5WebGL着色器内置变量gl_PointSize - gl_FragCoord - CSDN博客
gl_FragColor, 片元颜色值, vec4. gl_FragCoord, 片元坐标,单位像素, vec2. gl_PointCoord, 点渲染模式对应点像素坐标, vec2 ...