一起学 WebGL:动态绘制点

这节课我们会通过 JavaScript 给着色器动态提供数据,而不需要重新编译着色器。

这节课我们会通过 JavaScript 给着色器动态提供数据,而不需要重新编译着色器。

一起学 WebGL:动态绘制点

大家好,我是前端西瓜哥。上一篇文章讲解了如何绘制一个点。但这个点的信息是写死在渲染器源码中的,也就是硬编码。

这是系列文章,如果你是初学者,你需要看上一篇文章才好理解这节课的内容。

​《一起学 WebGL:绘制一个点》​

如果我们要频繁地改变点的位置去绘制,根据我们之前学到的知识点,那只能通过替换整个着色器代码字符串,不断地编译的方式去修改了,非常不便。

这节课我们会通过 JavaScript 给着色器动态提供数据,而不需要重新编译着色器。

静态绘制点

先贴上上篇文章的静态写法。

demo 地址:

https://codesandbox.io/s/webgl-hui-zhi-yi-ge-dian-2-bpwz8p。

/**
* wegbl 绘制一个点
*/

/** @type {HTMLCanvasElement} */
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");

const vertexShaderSrc = `
attrs
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 20.0;
}
`;

const fragmentShaderSrc = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

/**** 渲染器生成处理 ****/
// 创建顶点渲染器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);
// 创建片元渲染器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);
// 程序对象
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.program = program;

/** 画布绘制 **/
// 清空画布,并指定颜色
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// 绘制点
gl.drawArrays(gl.POINTS, 0, 1);

渲染结果:

图片

外部传递点的位置信息

下面我们希望顶点着色器的点的坐标可以通过 JavaScript 动态地修改。

加入 attribute 变量

修改顶点着色器的代码:

const vertexShaderSrc = `
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
gl_PointSize = 20.0;
}
`;

这里西瓜哥我将原本的 vec4 类型的写死的颜色值,换成了一个变量 a_Position。attribute是存储限定符,表示变量是 attribute 类型,它用于描述顶点数据,值可以通过外部传递被修改。后面我们从外部拿到这个变量,传入我们想要的值。

vec4则是变量类型,表示一个有四个分量的矢量。

变量通常会用a_作为前缀,表示该变量是 attribute 类型。

外部修改 attribute

然后是在 JavaScript 代码中获取这个 a_Position 变量,并传一个值给它。

const a_Position = gl.getAttribLocation(gl.program, "a_Position");
gl.vertexAttrib3f(a_Position, 0, 0.5, 0);

第一行 gl.getAttribLocation 方法的作用,是从 gl.program 程序对象中,取出一个名为 "a_Position" 的 attribute 变量的地址。如果找到,会返回一个大于等于 0 的值,找不到会返回 -1。

第二行,gl.vertexAttrib3f 就是根据地址给 a_Position 变量赋予值。a_Position 是 4 个浮点数组成的矢量类型,我们这里并没有传 4 个值,只传了 3 个。最后一个值对坐标系来说并无意义,但在矩阵变换时会用到,不提供会被自动填充为默认的 1.0。

你也可以用gl.vertexAttrib4f提供完成的 4 个浮点数,或者用gl.vertexAttrib1f或gl.vertexAttrib2f提供第一个或前两个浮点数。缺少的 y、z 默认会用 0.0,z 则使用 1.0。

这里我们给 y 设置了 0.5,渲染结果为:

图片

关于坐标系的文章

《​​一起学 WebGL:坐标系​​》

补充一下 WebGL 的坐标系图示:

图片

完整代码:

/**
* wegbl 绘制一个点
*/

/** @type {HTMLCanvasElement} */
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");

const vertexShaderSrc = `
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
gl_PointSize = 20.0;
}
`;

const fragmentShaderSrc = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

/**** 渲染器生成处理 ****/
// 创建顶点渲染器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);
// 创建片元渲染器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);
// 程序对象
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.program = program;

/** 修改着色器的 attribute */
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
gl.vertexAttrib3f(a_Position, 0, 0.5, 0);

/** 画布绘制 **/
// 清空画布,并指定颜色
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// 绘制点
gl.drawArrays(gl.POINTS, 0, 1);

demo 地址:

https://codesandbox.io/s/webgl-dong-tai-hui-zhi-dian-5cdped?file=/index.js。

不断修改位置信息

下面我们用一个定时器,不断地修改点的位置。

代码实现:

/**
* webgl 动态绘制点 + 定时器
*/

/** @type {HTMLCanvasElement} */
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");

const vertexShaderSrc = `
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
gl_PointSize = 20.0;
}
`;

const fragmentShaderSrc = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

/**** 渲染器生成处理 ****/
// 创建顶点渲染器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);
// 创建片元渲染器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);
// 程序对象
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.program = program;

/** 修改着色器的 attribute */
const a_Position = gl.getAttribLocation(gl.program, "a_Position");

let x = -1;
let y = -1;

setInterval(() => {
gl.vertexAttrib3f(a_Position, x, y, 0);
x += 0.25;
if (x > 1) x = -1;
y += 0.25;
if (y > 1) y = -1;

/** 画布绘制 **/
// 清空画布,并指定颜色
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// 绘制点
gl.drawArrays(gl.POINTS, 0, 1);
}, 180);

在定时器中,我们不断地修用 gl.vertexAttrib3f 修改点的位置,并重绘画布。

demo 地址:

https://codesandbox.io/s/webgl-dong-tai-hui-zhi-dian-ding-shi-qi-gnjx3t。

渲染效果:

图片

结尾

我是前端西瓜哥,欢迎关注我,学习更多前端知识。

这里布置一个小练习:动态修改点的大小,这次要用 float 类型,并对应使用 g1.vertexAttriblf 传递值。

答案在:https://codesandbox.io/s/g4ft9m

下一节我们将学习如何动态修改片元着色器中点的颜色。

©本文为清一色官方代发,观点仅代表作者本人,与清一色无关。清一色对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。本文不作为投资理财建议,请读者仅作参考,并请自行承担全部责任。文中部分文字/图片/视频/音频等来源于网络,如侵犯到著作权人的权利,请与我们联系(微信/QQ:1074760229)。转载请注明出处:清一色财经

(0)
打赏 微信扫码打赏 微信扫码打赏 支付宝扫码打赏 支付宝扫码打赏
清一色的头像清一色管理团队
上一篇 2023年5月7日 01:10
下一篇 2023年5月7日 01:10

相关推荐

发表评论

登录后才能评论

联系我们

在线咨询:1643011589-QQbutton

手机:13798586780

QQ/微信:1074760229

QQ群:551893940

工作时间:工作日9:00-18:00,节假日休息

关注微信