WebGL04
我们上一个小节已经了解了通过attribute变量动态传递值实现动态点的绘制。
uniform变量
我们要动态修改颜色值的话,就需要动态给片元着色器中gl_FragColor动态赋值。
uniform类型变量可以在顶点着色器和片元着色器中被访问
uniform vec4 u_FragColor
我们需要给我们的内置变量gl_FragColor动态赋值一个vec4类型变量
const fragmentCode=`
precision mediump float;
uniform vec4 u_FragColor;
void main () {
gl_FragColor = u_FragColor;
}
`
我们可以注意到上面的片段代码,我们使用precision mediump float声明,使用精度限定词来指定变量的范围和精度。不加的话片元着色器代码会报错。 接下来就是和attribute变量赋值一样,我们需要先找到变量的存储位置,在设置值即可。
- gl.getUniformLocation 参数(program,name)
- gl.uniform[1234]f[v] 参数(index,v0-v3)
// 获取 unfirom 变量存储位置
const u_FragColor = gl.getUniformLocation(program, 'u_FragColor')
// 通过 随机数 对 rgb 进行赋值,透明度固定为 0.8
gl.uniform4f(u_FragColor, Math.random(), Math.random(), Math.random(), .8)
示例
var canvas = document.getElementById("canvas");
canvas.width = canvas.height = 600;
const gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
const vertexCode = `
attribute vec4 a_Position;
void main () {
// 顶点坐标
gl_Position = a_Position;
// 顶点渲染像素大小
gl_PointSize = 10.0;
}
`;
const fragmentCode = `
precision mediump float;
uniform vec4 u_FragColor;
void main () {
// 顶点颜色——蓝色 (R, G, Bule, A)
gl_FragColor = u_FragColor;
}
`;
//着色器代码的初始化
// 绘制实现
document.getElementById("redFn").addEventListener("click", () => {
gl.clear(gl.COLOR_BUFFER_BIT);
});
function createShader({ glslCode, type }) {
// 创建对应类型着色器
const shader = gl.createShader(type);
// 传入对应着色器代码
gl.shaderSource(shader, glslCode);
// 编译着色器
gl.compileShader(shader);
return shader;
}
// 创建顶点着色器
const vertexShader = createShader({
glslCode: vertexCode,
type: gl.VERTEX_SHADER
});
// 创建片元着色器
const fragmentShader = createShader({
glslCode: fragmentCode,
type: gl.FRAGMENT_SHADER
});
// 创建着色器程序
const program = gl.createProgram();
// 分别添加两个着色器 gl.attachShader
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// 链接两个着色器
gl.linkProgram(program);
gl.useProgram(program);
// 动态修改顶点位置
const a_Position = gl.getAttribLocation(program, "a_Position");
gl.vertexAttrib2f(a_Position, -0.9, 0.9);
const u_FragColor = gl.getUniformLocation(program, "u_FragColor");
gl.uniform4f(u_FragColor, Math.random(), Math.random(), Math.random(), 0.9);
gl.clearColor(0.0, 0.0, 0.0, 0.5);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 1);
canvas.addEventListener("click", (e) => {
const halfWidth = canvas.width / 2;
const halfHeight = canvas.height / 2;
const x = (e.offsetX - halfWidth) / halfWidth;
const y = (halfHeight - e.offsetY) / halfHeight;
// gl.clear(gl.COLOR_BUFFER_BIT);
gl.vertexAttrib2f(a_Position, x, y);
gl.uniform4f(u_FragColor, Math.random(), Math.random(), Math.random(), 0.9);
//动态设置颜色值
gl.drawArrays(gl.POINTS, 0, 1);
});
varying变量
我们通过varying变量也可以实现绘制动态变化的颜色点,该变量会通过顶点着色器向片元着色器传输数据。换句话说,如果顶点着色器和片元着色器有类型和变量名完全相同的varying变量,那我们就可以将变化的数据从顶点着色器向片元着色器传递。
const vertexCode=`
attribute vec4 a_Position;
// 定义 a_Color 动态接受值
attribute vec4 a_Color;
// 定义 v_Color 接收、传递颜色值(跟片元着色器一致)
varying vec4 v_Color;
void main () {
gl_Position = a_Position;
gl_PointSize = 24.0;
v_Color = a_Color;
}
`
const fragmentCode=`
precision mediump float;
// 定义 v_Color,注意类型、变量名跟顶点着色器的一致,用于接收变量
varying vec4 v_Color;
void main () {
gl_FragColor = v_Color;
}
`
示例
var canvas = document.getElementById("canvas");
canvas.width = canvas.height = 600;
const gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
const vertexCode = `
attribute vec4 a_Position;
// 定义 a_Color 动态接受值
attribute vec4 a_Color;
// 定义 v_Color 接收、传递颜色值(跟片元着色器一致)
varying vec4 v_Color;
void main () {
gl_Position = a_Position;
gl_PointSize = 10.0;
v_Color = a_Color;
}
`;
const fragmentCode = `
precision mediump float;
// 定义 v_Color,注意类型、变量名跟顶点着色器的一致,用于接收变量
varying vec4 v_Color;
void main () {
gl_FragColor = v_Color;
}
`;
//着色器代码的初始化
// 绘制实现
document.getElementById("redFn").addEventListener("click", () => {
gl.clear(gl.COLOR_BUFFER_BIT);
});
function createShader({ glslCode, type }) {
// 创建对应类型着色器
const shader = gl.createShader(type);
// 传入对应着色器代码
gl.shaderSource(shader, glslCode);
// 编译着色器
gl.compileShader(shader);
return shader;
}
// 创建顶点着色器
const vertexShader = createShader({
glslCode: vertexCode,
type: gl.VERTEX_SHADER
});
// 创建片元着色器
const fragmentShader = createShader({
glslCode: fragmentCode,
type: gl.FRAGMENT_SHADER
});
// 创建着色器程序
const program = gl.createProgram();
// 分别添加两个着色器 gl.attachShader
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// 链接两个着色器
gl.linkProgram(program);
gl.useProgram(program);
// 动态修改顶点位置
const a_Position = gl.getAttribLocation(program, "a_Position");
const a_Color = gl.getAttribLocation(program, 'a_Color')
gl.vertexAttrib2f(a_Position, -0.9, 0.9);
gl.vertexAttrib4f(a_Color, Math.random(), Math.random(), Math.random(), 0.9);
gl.clearColor(0.0, 0.0, 0.0, 0.5);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 1);
canvas.addEventListener("click", (e) => {
const halfWidth = canvas.width / 2;
const halfHeight = canvas.height / 2;
const x = (e.offsetX - halfWidth) / halfWidth;
const y = (halfHeight - e.offsetY) / halfHeight;
// gl.clear(gl.COLOR_BUFFER_BIT);
gl.vertexAttrib2f(a_Position, x, y);
gl.vertexAttrib4f(a_Color, Math.random(), Math.random(), Math.random(), 0.9);
//动态设置颜色值
gl.drawArrays(gl.POINTS, 0, 1);
});
uniform、varying之间的区别
- uniform是全局变量 varying变量用于从顶点着色器向片元着色器传递值,之后有个内插过程会涉及。
- gl.drawArrays调用一次绘制一个点,我们使用缓冲区对象的时候可以实现调用drawArrays一次绘制多个点。
- varying变量是可变我们通过缓冲区不断给a_Color赋值的,对应的片元着色器会接收到当前从顶点着色器传递下来的a_Color值,因此可以在一次绘制中,绘制多个不同颜色。
写在最后
未完待续…
希望大家好好生活,健康快乐。