返回
掌握GLSL:绘制多个2D形状并发挥创作混搭
前端
2023-10-05 16:28:26
在WebGL的广阔天地中,2D图形始终扮演着不可或缺的角色,今天我们继续探索GLSL在绘制2D图形中的神奇力量,重点关注如何绘制多个2D形状,以及如何让这些形状在画布上和谐共舞。让我们从一个简单的圆形开始,逐步深入到更复杂的图形世界。
绘就多彩圆形,点缀视觉画布
// 定义圆形着色器代码
const vertexShaderSource = `
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// 将顶点位置归一化到[-1, 1]范围内
vec2 normalizedPosition = a_position / u_resolution;
// 计算圆形的半径
float radius = 0.5;
// 检查顶点是否在圆内
if (distance(normalizedPosition, vec2(0.0, 0.0)) < radius) {
// 如果顶点在圆内,则将片段颜色设置为红色
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
} else {
// 如果顶点不在圆内,则将片段颜色设置为黑色
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}
`;
// 定义片段着色器代码
const fragmentShaderSource = `
precision mediump float;
void main() {
// 输出片段颜色
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
// 创建着色器程序
const shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource);
// 从着色器程序中获取顶点位置属性和分辨率变量的位置
const positionAttributeLocation = gl.getAttribLocation(shaderProgram, "a_position");
const resolutionUniformLocation = gl.getUniformLocation(shaderProgram, "u_resolution");
// 创建一个缓冲区来存储圆形的顶点数据
const positionBuffer = gl.createBuffer();
// 将顶点数据绑定到缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// 设置缓冲区数据
const positions = [
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
1.0, 1.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// 启用顶点位置属性并指定其数据格式
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
// 设置分辨率变量
gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
// 清除画布
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// 使用着色器程序
gl.useProgram(shaderProgram);
// 绘制圆形
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
上述代码以一个红色的圆形作为开场,这只是我们旅程的开始。接下来,我们将把圆形转化为一个可以随意移动的小精灵,并添加更多的形状,让它们在画布上翩翩起舞。
画笔挥洒,描绘缤纷世界
// 定义精灵着色器代码
const vertexShaderSource = `
attribute vec2 a_position;
uniform vec2 u_resolution;
uniform vec2 u_translation;
void main() {
// 将顶点位置归一化到[-1, 1]范围内
vec2 normalizedPosition = a_position / u_resolution;
// 将顶点位置加上平移量
vec2 translatedPosition = normalizedPosition + u_translation;
// 计算圆形的半径
float radius = 0.5;
// 检查顶点是否在圆内
if (distance(translatedPosition, vec2(0.0, 0.0)) < radius) {
// 如果顶点在圆内,则将片段颜色设置为红色
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
} else {
// 如果顶点不在圆内,则将片段颜色设置为黑色
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}
`;
// 定义片段着色器代码
const fragmentShaderSource = `
precision mediump float;
void main() {
// 输出片段颜色
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
// 创建着色器程序
const shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource);
// 从着色器程序中获取顶点位置属性和分辨率变量的位置
const positionAttributeLocation = gl.getAttribLocation(shaderProgram, "a_position");
const resolutionUniformLocation = gl.getUniformLocation(shaderProgram, "u_resolution");
const translationUniformLocation = gl.getUniformLocation(shaderProgram, "u_translation");
// 创建一个缓冲区来存储精灵的顶点数据
const positionBuffer = gl.createBuffer();
// 将顶点数据绑定到缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// 设置缓冲区数据
const positions = [
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
1.0, 1.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// 启用顶点位置属性并指定其数据格式
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
// 设置分辨率变量
gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
// 设置平移变量
gl.uniform2f(translationUniformLocation, 0.0, 0.0);
// 清除画布
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// 使用着色器程序
gl.useProgram(shaderProgram);
// 绘制精灵
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
在这个代码中,精灵可以随心所欲地移动,为我们的画布增添了一份灵动和活力。为了丰富画布的内容,我们还可以添加更多形状,例如一个蓝色的正方形,并让它们一起在画布上共舞。
色彩交融,碰撞出创意火花
// 定义精灵着色器代码
const vertexShaderSource = `
attribute vec2 a_position;
uniform vec2 u_resolution;
uniform vec2 u_translation;
void main() {
// 将顶点位置归一化到[-1, 1]范围内
vec2 normalizedPosition = a_position / u_resolution;
// 将顶点位置加上平移量
vec2 translatedPosition = normalizedPosition + u_translation;
// 计算圆形的半径
float radius = 0.5;
// 检查顶点是否在圆内
if (distance(translatedPosition, vec2(0.0, 0.0)) < radius) {
// 如果顶点在圆内,则将片段颜色设置为红色
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
} else {
// 如果顶点不在圆内,则将片段颜色设置为黑色
gl_FragColor = vec4(0.0, 0.0, 0.