這一節的目標是,在上一節用鼠標點擊畫點的基礎上增加改變顏色的功能,點的顏色取決於其位置。
結果:
可以用 uniform 變量將顏色值傳給着色器,其步驟與用 attribute 變量傳遞的類似。不同的僅僅是,這次數據傳輸的目標是片元着色器,而非頂點着色器:
- 在片元着色器中準備 uniform 變量。
- 用這個 uniform 變量向 gl_FragColor 賦值。
- 將顏色數據從JS傳給該 uniform 變量。
示例程序 ColoredPoints.js
//頂點着色器程序
var VSHADER_SOURCE =
'attribute vec4 a_Position;'+
'void main(){'+
'gl_Position=a_Position;'+
'gl_PointSize=10.0;'+
'}';
//片元着色器程序
var FSHADER_SOURCE=
'precision mediump float;'+
'uniform vec4 u_FragColor;'+
'void main(){'+
'gl_FragColor = u_FragColor;'+
'}';
function main() {
//獲取canvas元素
var canvas = document.getElementById("webgl");
if(!canvas){
console.log("Failed to retrieve the <canvas> element");
return;
}
//獲取WebGL繪圖上下文
var gl = getWebGLContext(canvas);
if(!gl){
console.log("Failed to get the rendering context for WebGL");
return;
}
//初始化着色器
if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
console.log("Failed to initialize shaders.");
return;
}
//獲取a_Position變量存儲位置
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if(a_Position < 0){
console.log("Failed to get the storage location of a_Position");
return;
}
//獲取u_FragColor 變量存儲位置
var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
if(!u_FragColor){
console.log('Failed to get the storage location of u_FragColor');
return;
}
canvas.onmousedown = function(ev){
click(ev,gl,canvas,a_Position,u_FragColor);
};
//指定清空<canvas>顏色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//清空<canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
}
var g_points = [];
var g_colors = [];
function click(ev, gl, canvas, a_Position,u_FragColor){
var x= ev.clientX;
var y = ev.clientY;
var rect = ev.target.getBoundingClientRect();
x = ((x - rect.left) - canvas.width / 2) / (canvas.width / 2);
y = (canvas.height / 2 - (y - rect.top)) / (canvas.height / 2);
//將座標存儲到g_points數組中
g_points.push([x, y]);
if(x >= 0.0 && y >= 0.0){ //第一象限
g_colors.push([1.0, 0.0, 0.0, 1.0]); //紅色
}else if(x < 0.0 && y < 0.0){ //第三象限
g_colors.push([0.0, 1.0, 0.0, 1.0]); //綠色
}else{
g_colors.push([1.0, 1.0, 1.0, 1.0]); //白色
}
//清除<canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
var len = g_points.length;
for(var i = 0; i < len; i++){
var xy=g_points[i];
var rgba = g_colors[i];
//將點的位置傳遞到a_Position變量中
gl.vertexAttrib3f(a_Position, xy[0], xy[1], 0.0);
//將點的顏色傳遞到u_FragColor變量中
gl.uniform4f(u_FragColor, rgba[0], rgba[1], rgba[2], rgba[3]);
//繪製點
gl.drawArrays(gl.POINTS, 0, 1);
}
}
uniform 變量
只有頂點着色器才能使用 attribute 變量,使用片元着色器時,你就需要使用 uniform 變量。
在使用 uniform 變量之前,首先需要按照與聲明 attribute 變量相同的格式<存儲限定符><類型><變量名>來聲明 uniform 變量。
在例子中, uniform 變量 u_FragColor 被賦值給 gl_FragColor 變量。向 uniform 變量傳數據的方式向 attribute 變量傳數據相似:首先獲取變量的存儲地址,然後再JS程序中按照地址將數據傳遞過去。
//片元着色器程序
var FSHADER_SOURCE=
'precision mediump float;'+
'uniform vec4 u_FragColor;'+
'void main(){'+
'gl_FragColor = u_FragColor;'+
'}';
這一行使用精度限定詞來制定變量的範圍和精度,本例中爲中度精度,後面第5章會詳細講。
'precision mediump float;'+
獲取 uniform 變量的存儲地址
//獲取u_FragColor 變量存儲位置
var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
if(!u_FragColor){
console.log('Failed to get the storage location of u_FragColor');
return;
}
可以使用以下方法來獲取 uniform 變量的存儲地址
向 uniform 變量賦值
有了 uniform 變量的存儲地址,就可以使用 gl.uniform4f()向變量中寫入數據。該函數的功能和參數與 gl.vertexAttrib[1234]f()相似。
gl.uniform4f()的同族函數
gl.uniform4f()也有一系列同族函數。
結果: