当前位置:首页 >娱乐 >一起学 WebGL:动态绘制点 起学而不需要重新编译着色器

一起学 WebGL:动态绘制点 起学而不需要重新编译着色器

2024-06-29 06:55:25 [百科] 来源:避面尹邢网

一起学 WebGL:动态绘制点

作者:前端西瓜哥 开发 前端 这节课我们会通过 JavaScript 给着色器动态提供数据,起学而不需要重新编译着色器。态绘

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

一起学 WebGL:动态绘制点 起学而不需要重新编译着色器

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

一起学 WebGL:动态绘制点 起学而不需要重新编译着色器

​​《一起学 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

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

责任编辑:姜华 来源: 前端西瓜哥 JavaScriptWebGL

(责任编辑:时尚)

    推荐文章
    热点阅读