首页IT科技webgl教程视频(webgl 系列 —— 绘制一个点(版本2、版本3、版本4、版本5))

webgl教程视频(webgl 系列 —— 绘制一个点(版本2、版本3、版本4、版本5))

时间2025-09-09 13:35:50分类IT科技浏览4858
导读:绘制一个点 我们初步认识了 webgl,本篇主要围绕绘制一个点的示例,逐步实现下面功能:...

绘制一个点

我们初步认识了 webgl               ,本篇主要围绕绘制一个点的示例                    ,逐步实现下面功能:

点的位置从 js 传入着色器 点的大小由 js 传入着色器 通过鼠标点击绘点 通过鼠标点击绘点        ,并改变点的颜色

绘制一个点(版本2)

需求

在上篇中我们在canvas中心绘制了一个点(效果如下)            ,但这点的位置是直接写在顶点着色器中 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);                。

需求:点的位置从 js 传入着色器

思路

将位置信息从 js 传入着色器有两种方式:attribute 变量              、uniform 变量

attribute - 传输的是那些与顶点相关的数据 uniform - 传输的是那些对于所有顶点都相同的数据

我们这里使用 attribute 变量                    ,因为每个点都有各自的坐标

Tip:GLSL 中有三种类型的“变量               ”或者说数据存储类型                    。每一种类型都有特定的目标和使用方法:: attributes                       、varyings(复杂            ,暂不介绍)和uniforms —— Data in WebGL

attribute

attribute 是一种着色器语言(GLSL ES)变量        ,用于向顶点着色器内传输数据                    ,只有顶点着色器能使用它        。

使用 attribute 有如下三步:

在顶点着色器中声明 attribute 变量 在顶点着色器中将声明的 attribute 变量赋值给 gl_Position 变量 向 attribute 变量传输数据 实现

完整代码如下:

// point02.js // 必须要 ; const VSHADER_SOURCE = ` // 声明 attribute 变量 attribute vec4 a_Position; void main() { // 将声明的 attribute 变量赋值给 gl_Position 变量 gl_Position = a_Position; gl_PointSize = 10.0; } ` const FSHADER_SOURCE = ` void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } ` function main() { const canvas = document.getElementById(webgl); const gl = canvas.getContext("webgl"); // 初始化着色器 if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log(初始化着色器失败); return; } // 获取 attribute 变量的存储位置            。如果找不到该属性则返回 -1                    。 const a_Position = gl.getAttribLocation(gl.program, a_Position) if (a_Position < 0) { console.log(找不到 a_Position 的存储位置); return; } // 为顶点 attibute 变量赋值 gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.POINTS, 0, 1); }

Tip:顶点着色器中必须要写 ;

核心代码:

// 声明 attribute 变量 attribute vec4 a_Position; void main() { // 将声明的 attribute 变量赋值给 gl_Position 变量 gl_Position = a_Position; } // 获取 attribute 变量的存储位置            。如果找不到该属性则返回 -1        。 // gl.program - 在 initShaders() 函数中创建了这个程序对象                    。现在只需知道它是一个参数 const a_Position = gl.getAttribLocation(gl.program, a_Position) // 为顶点 attibute 变量赋值 gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);

Tip:习惯:所有 attribute 的变量以 a_ 开头               ,所有 uniform 的变量以 u_ 开头               。

getAttribLocation

WebGLRenderingContext.getAttribLocation(program, name) 方法返回了给定 WebGLProgram对象 中某属性的下标指向位置    。

vertexAttrib3f

vertexAttrib3f 是一系列同族方法中的一个    ,为顶点 attibute 变量赋值                     。

一系列方法指:

void gl.vertexAttrib1f(index, v0); void gl.vertexAttrib2f(index, v0, v1); // 将数据(v0, v1, v2) 传给 index 指定的 attribute 变量 void gl.vertexAttrib3f(index, v0, v1, v2); void gl.vertexAttrib4f(index, v0, v1, v2, v3); // 矢量版本 v(vector) void gl.vertexAttrib1fv(index, value); void gl.vertexAttrib2fv(index, value); void gl.vertexAttrib3fv(index, value); void gl.vertexAttrib4fv(index, value); gl.vertexAttrib1f 传1个分量                  。第二第三分量设置为 0.0                     ,第四个分量设置为1.0 gl.vertexAttrib3f 传3个分量。第四个分量设置为 1.0                  ,以此类推                  。

矢量版本以 v 结尾,接受类型化数组                     。就像这样:

const floatArray = new Float32Array([10.0, 5.0, 2.0]); gl.vertexAttrib3fv(a_foobar, floatArray);

绘制一个点(版本3)

需求

需求:点的大小由 js 传入着色器 —— 在版本2的基础上实现

实现

和版本2的实现类似:

const VSHADER_SOURCE = ` attribute vec4 a_Position; +attribute float a_PointSize; void main() { // 将声明的 attribute 变量赋值给 gl_Position 变量 gl_Position = a_Position; - gl_PointSize = 10.0; + gl_PointSize = a_PointSize; } ` function main() { gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0); + const a_PointSize = gl.getAttribLocation(gl.program, a_PointSize) + if (a_PointSize < 0) { + console.log(找不到 a_PointSize 的存储位置); + return; + } + // 为顶点 attibute 变量赋值 + gl.vertexAttrib1f(a_PointSize, 10.0); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT);

绘制一个点(版本4)

需求

需求:通过鼠标点击绘点

效果如下:

实现

完整代码如下:

const VSHADER_SOURCE = ` // 声明 attribute 变量 attribute vec4 a_Position; attribute float a_PointSize; void main() { // 将声明的 attribute 变量赋值给 gl_Position 变量 gl_Position = a_Position; gl_PointSize = a_PointSize; } ` const FSHADER_SOURCE = ` void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } ` function main() { const canvas = document.getElementById(webgl); const gl = canvas.getContext("webgl"); // 初始化着色器 if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log(初始化着色器失败); return; } gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); const a_PointSize = gl.getAttribLocation(gl.program, a_PointSize) if (a_PointSize < 0) { console.log(找不到 a_PointSize 的存储位置); return; } // 为顶点 attibute 变量赋值 gl.vertexAttrib1f(a_PointSize, 10.0); // 获取 attribute 变量的存储位置    。如果找不到该属性则返回 -1               。 const a_Position = gl.getAttribLocation(gl.program, a_Position) if (a_Position < 0) { console.log(找不到 a_Position 的存储位置); return; } // 存储所有点 const points = []; // 注册点击事件 $(canvas).click(event => { // 将点击的坐标转为 webgl 坐标系统                    。 const rect = event.target.getBoundingClientRect(); const x = ((event.clientX - rect.left) - canvas.width / 2) / (canvas.width / 2); const y = (canvas.height / 2 - (event.clientY - rect.top)) / (canvas.height / 2); console.log(x, y) // 将点保存 points.push({ x, y }) // 注:使用预设值来清空缓冲        。如果注释这行                  ,颜色缓冲区会被 webgl 重置为默认的透明色(0.0, 0.0, 0.0, 0.0) —— 必须 gl.clear(gl.COLOR_BUFFER_BIT); // 绘点 points.forEach(item => { // 为顶点 attibute 变量赋值 // 注:即使 x, y 是整数程序也没问题 gl.vertexAttrib3f(a_Position, item.x, item.y, 0.0); gl.drawArrays(gl.POINTS, 0, 1); }) }) }

核心思路如下:

给 canvas 注册点击事件(这里引入jQuery) 点击时将 (x, y) 转为 webgl 坐标(怎么转换?百度搜索                     ,这不是重点)    ,并将该点存入一个变量 points 中 循环 points 不停绘制点

注:循环前得通过 gl.clear 清空绘图区               ,否则canvas背景会被重置为透明色            。

绘制一个点(版本5)

需求

需求:通过鼠标点击绘点                    ,并改变点的颜色 —— 在版本4的基础上实现

效果如下:

思路:颜色从硬编码改成从 js 传入                    。使用 uniform 变量            。

uniform

前面我们用 attribute 向顶点着色器传输顶点的位置        ,只有顶点着色器才能使用 attribute        。

对于片元着色器            ,需要使用 uniform 变量                    。

使用 uniform 有如下三步(和 attribute 类似):

在顶点着色器中声明 uniform 变量 在顶点着色器中将声明的 uniform 变量赋值给 gl_FragColor 变量 向 uniform 变量传输数据 实现

完整代码:

const VSHADER_SOURCE = ` attribute vec4 a_Position; attribute float a_PointSize; void main() { gl_Position = a_Position; gl_PointSize = a_PointSize; } ` const FSHADER_SOURCE = ` // 片元着色器必须加上精度描述               。否则浏览器报错:No precision specified for (float) precision mediump float; // 声明变量 uniform vec4 u_FragColor; void main() { gl_FragColor = u_FragColor; } ` function main() { const canvas = document.getElementById(webgl); const gl = canvas.getContext("webgl"); if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log(初始化着色器失败); return; } gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); const a_PointSize = gl.getAttribLocation(gl.program, a_PointSize) if (a_PointSize < 0) { console.log(找不到 a_PointSize 的存储位置); return; } gl.vertexAttrib1f(a_PointSize, 10.0); const a_Position = gl.getAttribLocation(gl.program, a_Position) if (a_Position < 0) { console.log(找不到 a_Position 的存储位置); return; } // 获取 uniform 变量的存储位置    。如果找不到该属性则返回 -1                     。 const u_FragColor = gl.getUniformLocation(gl.program, u_FragColor) if (u_FragColor < 0) { console.log(找不到 u_FragColor 的存储位置); return; } const points = []; // [0, 1) const getColor = () => Number.parseFloat(Math.random()) $(canvas).click(event => { const rect = event.target.getBoundingClientRect(); const x = ((event.clientX - rect.left) - canvas.width / 2) / (canvas.width / 2); const y = (canvas.height / 2 - (event.clientY - rect.top)) / (canvas.height / 2); // 将点的随机颜色 points.push({ x, y, rgb: [getColor(), getColor(), getColor()] }) gl.clear(gl.COLOR_BUFFER_BIT); points.forEach(item => { gl.vertexAttrib3f(a_Position, item.x, item.y, 0.0); // 给 unifrom 变量赋值 gl.uniform4f(u_FragColor, ...item.rgb, 1.0); gl.drawArrays(gl.POINTS, 0, 1); }) }) }

核心代码:

const FSHADER_SOURCE = ` // 片元着色器必须加上精度描述                  。否则浏览器报错:No precision specified for (float) precision mediump float; // 声明变量 uniform vec4 u_FragColor; void main() { gl_FragColor = u_FragColor; } ` function main() { // 获取 uniform 变量的存储位置。如果找不到该属性则返回 -1                  。 const u_FragColor = gl.getUniformLocation(gl.program, u_FragColor) if (u_FragColor < 0) { console.log(找不到 u_FragColor 的存储位置); return; } $(canvas).click(event => { ... points.forEach(item => { ... // 给 unifrom 变量赋值 gl.uniform4f(u_FragColor, ...item.rgb, 1.0); gl.drawArrays(gl.POINTS, 0, 1); }) }) }

注:片元着色器必须加上精度描述(例如:precision mediump float;)                     。否则浏览器报错:No precision specified for (float)

getUniformLocation

getUniformLocation 与 getAttribLocation 类似                    ,只是这里返回 uniform 变量的位置

uniform4f

有了 uniform 变量的存储地址            ,就可以使用 uniform4f(和 vertexAttrib3f 很类似) 向变量中写入数据    。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
halcon两张图片拼在一起(Halcon图像拼接) 面包屑导航在SEO中的优化策略(如何通过优化面包屑导航提升网站SEO排名)