前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >3D绘图小帮手WebGL入门与进阶(中)——着色器的基本编程

3D绘图小帮手WebGL入门与进阶(中)——着色器的基本编程

作者头像
京东技术
发布于 2018-06-20 09:32:57
发布于 2018-06-20 09:32:57
1.3K00
代码可运行
举报
文章被收录于专栏:京东技术京东技术
运行总次数:0
代码可运行

程序创建完之后,我们需要需要对着色器进行动态控制才能达到我们所需要的功能。(如不知道怎么创建WebGL,可参考上篇文章)。

首先让我来介绍2个变量,我们需要借助这2个变量搭建的桥梁才能使JavaScript与GLSL ES之间进行沟通。

  • attribute: 用于顶点点着色器(Vertex Shader)传值时使用。
  • uniform:可用于顶点着色器(Vertex Shader)与片元着色器(Fragment Shader)使用。

将顶点动态化

先在顶点着色器代码中,将对应的vec4的固定值变成变量。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var VSHADER_SOURCE = 
  'attribute vec4 a_Position;\n' +
  'void main() {\n' +
    '  gl_Position = a_Position;\n' +
    '  gl_PointSize = 10.0;\n' + 
  '}\n';

位置参数使用了attribute变量来承载。这样WebGL对象就可以获取到对应的存储位置,就可以去动态改变GLSL变量了。

使用WebGL来获取对应参数的存储地址。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//返回对应的地址信息
var aPosition = gl.getAttribLocation(gl.program, 'a_Position');
//判断地址是否获取成功
if(aPosition < 0) {
    console.log('没有获取到对应position');
}

然后给变量赋值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gl.vertexAttrib3f(aPosition, 1.0, 1.0, 0.0);
//或者使用Float32Array来传参
var p = new Float32Array([1.0, 1.0, 1.0]);
gl.vertexAttrib3fv(aPosition, p);

注意:vertexAttrib3fv这个函数是典型的GLSL语法命名规范,vertexAttrib函数功能:

3:对应需要传3个参数,或者是几维向量。

f:表示参数是float类型。

v:表示传如的为一个vector变量。

也就是说对应设置顶点着色器的函数有一下几种功能:

  • void gl.vertexAttrib1f(index, v0);
  • void gl.vertexAttrib2f(index, v0, v1);
  • void gl.vertexAttrib3f(index, v0, v1, v2);
  • void gl.vertexAttrib4f(index, v0, v1, v2, v3);
  • void gl.vertexAttrib1fv(index, value);
  • void gl.vertexAttrib2fv(index, value);
  • void gl.vertexAttrib3fv(index, value);
  • void gl.vertexAttrib4fv(index, value);

同样操作可以如下修改PointSize:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//着色器中添加变量
var VSHADER_SOURCE = 
  'attribute vec4 a_Position;\n' +
  'attribute float a_PointSize;\n' +
  'void main() {\n' +
    '  gl_Position = a_Position;\n' +
    '  gl_PointSize = a_PointSize;\n' + 
  '}\n';
var aPointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
gl.vertexAttrib1f(aPointSize, 10.0);

片元着色器编程

对片元着色器变成需要使用uniform变量来承载。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var FSHADER_SOURCE =
'precision mediump float;\n'+
'uniform vec4 vColor;\n'+
'void main() {\n' +
'  gl_FragColor = vColor;\n' + // Set the point color
'}\n';

获取片元着色器变量地址。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var vColor = gl.getUniformLocation(gl.program, 'vColor');

给变量赋值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gl.uniform4f(vColor, 1.0, 0.0, 0.0, 1.0);
//或使用Float32Array来传参
var color = new Float32Array([1.0, 0.0, 0.0, 1.0]);
gl.uniform4fv(vColor,color)

注意:uniform3fv这个函数是典型的GLSL语法命名规范,uniform3fv函数功能:

3:对应需要传3个参数,或者是几维向量。

f:表示参数是float类型。

u:表示参数是Uint32Array类型。

i:表示参数是integer类型。

ui:表示参数是unsigned integer类型。

v:表示传如的为一个vector变量。

uniform对应函数同attribute的函数构成相似,这里就不详细列举,具体请参考 [1]。

着色器中的代码precision mediump float;表示的意思是着色器中配置的float对象会占用中等尺寸内存。 具体包含的尺寸:

  • highp for vertex positions,
  • mediump for texture coordinates,
  • lowp for colors.

如果不设置此参数会报错:

我们可以绘制自定义的点了,接下来我们就可以尝试绘制大批量点来达到波浪的基础效果,但是之前的操作都是针对一个点的,如何可以同时绘制多个订点呢,如果你的回答是循环数据,BINGGO,没错这样你的确是可以达到这个目的,但是不是我们接下来要讲的,因为在3D绘制的时候是会经常出现大批量点、线、面的绘制的,所以WebGL提供了一种承载机制来达到传递多点的能力,说了这么多,也让我们来看看它到底是什么吧。

缓存区对象

之前的方式可以通过循环来绘制多个点,一次需要绘制多个点,需要同时传递进去多个点的数据。刚好,在WebGL中提供了一种机制:缓存区对象(buffer data),缓存区对象可以同时向着色器传递多个顶点坐标。缓存区是WebGL中的一块内存区域,我们可以向里面存放大量顶点坐标数据,可随时供着色器使用。

使用缓存区步骤

  • 创建缓存区对象(gl.createBuffer())
  • 绑定缓存区对象(gl.bindBuffer())
  • 将数据写入缓存区对象(gl.bufferData())
  • 将缓存区对象分配给一个attribute变量(gl.vertexAttribPointer())
  • 开启attribute变量(gl.enableVertexAttribArray())

我们需要进行缓冲区的操作: 首先,需要创建一个缓冲区来承载大量顶点的坐标。(代码继续上文)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 创建缓存区 
var vertexBuffer = gl.createBuffer();
if(!vertexBuffer) {
    log('创建缓存区失败。');
    return -1;
}
// 将创建的缓存区对象绑定到target表示的目标上 
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 开辟存储空间,向绑定在target上的缓存区对象中写入数据 
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// 获取着色器中的变量值 
var a_position = gl.getAttribLocation(gl.program, 'a_p');
// 将缓存区对象绑定到着色器变量中 
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 0, 0);
// 启用缓存区 
gl.enableVertexAttribArray(a_position);
// 绘制缓存区中画的多个顶点 
gl.drawArrays(gl.POINTS, 0 , array);

看完了绘制过程,让我们来拆解一下具体内容:

首先,我们要在茫茫内存中申请一个区域来放置缓存区对象的内容,但是我们无法直接放置缓存对象进入内存中,否则会无法识别对应的数据类型,从而无法达到存取自如的境界,那我们就需要将数据的类型告知内存,bingBuffer就是为解决此问题诞生的,函数会在内存中申请一部分区域,并且通过target来制定数据类型,也就是说,缓存区是需要放置在target表示的类型部分去存储。

gl.bindBuffer(target, buffer):

target: 指定存储缓存区的目标类型,

  • gl.ARRAY_BUFFER : 指缓存区中包含了顶点的数据。
  • gl.ELEMENTARRAYBUFFER : 指缓存区中包含了顶点数据的索引值。

buffer: 自己创建的缓存区对象,

接下来,我们需要做的是填充刚刚申请的缓存区,我们需要使用一个符合GLSL语法的数据格式,Javascript中可用Float32Array类型来创建支持GLSL的数据。使用bufferData函数将数据放入缓存区内。

gl.bufferData(target, size, usage):

target: 同上,

size: 为多个顶点坐标的集合数组,

usage: 表示程序将如何使用缓存区中的数据,

  • gl.STATIC_DRAW : 只会向缓存区对象中写入一次数据,但需要绘制很多次。
  • gl.STREAM_DRAW : 只会向缓存区对象中写入一次数据,然后绘制若干次。
  • gl.DYNAMIC_DRAW : 会想缓存区对象中多次写入数据,并绘制很多次。

缓存区中已经存储了多个顶点坐标,接下来我们需要将此数据运用到对应的着色器上,才能真正的绘制出来可视化图像,如何传递呢?首先我们需要在着色器中建立一个attribute类型的变量以方便我们操作,着色器中的对象,着色器中存在对象之后,我们可以使用Javascript中getAttribLocation函数获取着色器中的attribute类型变量,并且通过vertexAttribPointer将其赋值改变,从而达到改变图像呈现。

gl.getAttribLocation(program,name):

param: webgl之前创建的进程,

name: 变量名称,

gl.vertexAttribPointer(name, size, type, normalized, stride, offset):

name: 指定要赋值的attribute变量位置,

size: 指定每个顶点数据的分量个数(1或4),

type: 指定传入的数据格式,

  • gl.BYTE: 字节型, 取值范围[-128, 127]。
  • gl.SHORT: 短整型,取值范围[-32768, 32767]。
  • gl.UNSIGNED_BYTE: 无符号字节型,取值范围[0, 255]。
  • gl.UNSIGNED_SHORT: 无符号短整型, 取值范围[0, 65535]。
  • gl.FLOAT: 浮点型。

normalized: 表明是否将非浮点数的数据归入到[0, 1]或[-1, 1]区间,

stride: 指定相邻2个顶点间的字节数,默认为0,

offset: 指定缓存区对象中的偏移量,设置为0即可,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
如为2,则
new Float32Array([
    1.0, 1.0,
    1.0,1.0
])
代表2个顶点
如为4,则
new Float32Array([
    1.0, 1.0, 1.0,1.0
])
代表1个顶点

现在缓存区已经存在多个顶点数据,接下来我们来启用携带缓存区数据的attribute变量,使用enableVertexAttribArray来启用对应变量。

gl.enableVertexAttribArray(name):

name: 待启动的变量指针,也就是名称,

所有的缓存区操作步骤我们都已经完成,那么接下来我们可以绘制出缓存区中的多个顶点。

gl.drawArrays(mode, first, count)

mode: 需要绘制的图像形状,

  • gl.POINTS: 绘制一个点。
  • gl.LINE_STRIP: 绘制一条直线到下一个顶点。
  • gl.LINE_LOOP: 绘制一条首尾相连的线。
  • gl.LINES: 绘制一条线。
  • gl.TRIANGLES: 绘制一个三角形。

first: 绘制的开始点,

count: 需要绘制的图形个数,

让我们先来创建多个点,上一课已经讲过,WebGL的坐标与真实坐标会有一些出入,所以我们需要转换一下,并且数据我们需要使用Float32Array对象来创建,我们创建一个三维的点数据,总数为200个。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function createPoints() {
    //波动最大幅度 10px;
    var arr = [];
    var n = 20;
    var m = 10;
    for(var i = 0; i < n; i++) {
        for(var j = 0; j < m; j++) {
            var x = webglX(-(width/2) + i*20);
            var y = webglY((height/2) - j*20);
            var z = -1;
            var item = [x, y, z];
            arr = arr.concat(item);
        }
    }
    return new Float32Array(arr)
}

接下来我们使用数据缓存区来讲此200个点一次渲染出来。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, createPoints(), gl.STATIC_DRAW);
我们先获取到对应的顶点着色器中的变量
var a_position = gl.getAttribLocation(gl.program, 'a_Position');
//我们需要设置数据中的点的维度。否则会解析出错。
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_position);
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
//我们需要确定绘制的具体点的数量
gl.drawArrays(gl.POINTS, 0 , 200);

看看屏幕吧,是不是出来了好多点?没错你已经成功的掌握了着色器基本编程以及数据缓存区的知识。

我们掌握了这些知识之后,下一篇让我们先来使用这些内容创建一个点的波浪吧。

扩展阅读

[1] https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/uniform

下面的内容同样精彩

点击图片即可阅读

移动测试避坑指南(第一篇)

京东博士后工作站正在联合众多大咖搞事情

京东技术 ∣关注技术的公众号

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-05-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京东技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
使用了这个数据库神器,让我工作效率提升了数倍
很多时候,我们需要在本地电脑上,直接连接开发或测试环境的数据库,方便对数据进行增删改查。当然很多数据库都提供了自带的客户端,比如mysql的客户端是这样的:
苏三说技术
2022/08/25
9580
使用了这个数据库神器,让我工作效率提升了数倍
★Navicat For Mysql 数据库备份与还原
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/135512.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/05
5K0
★Navicat For Mysql 数据库备份与还原
Navicat操作MySQL简易教程
日常使用 MySQL 的过程中,我们可能会经常使用可视化工具来连接 MySQL ,其中比较常用的就是 Navicat 了。平时也会遇到某些同学问, Navicat 怎么安装,如何使用等问题。本篇文章笔者将结合个人经验,分享下 Navicat 操作 MySQL 简易教程。
MySQL技术
2021/03/23
2.2K0
Navicat操作MySQL简易教程
数据库管理工具:如何使用 Navicat for MySQL 导出导入数据表 Excel 文件?
Navicat 导出数据表的格式很多,增加了对 Excel 2007 以上版本的支持,当设计完一个表后,如果有上百条或更多的数据需要导入 MySQL 数据库时,我们可以先把设计好的数据导出到一个 Excel 表中,然后按照格式去填充,最后把这些填充完的数据再导入到 MySQL 数据库中。
白鹿第一帅
2022/11/30
5.3K0
数据库管理工具:如何使用 Navicat for MySQL 导出导入数据表 Excel 文件?
Navicat Premium基本使用
Navicat Premium基本使用 Navicat是一套数据库管理工具,专为简化数据库的管理及降低系统管理成本而设。Navicat 是以直觉化的图形用户界面而建的,可以安全和简单地创建、组织、访问并共用信息。 Navicat Premium 是 Navicat 的产品成员之一,能简单并快速地在各种数据库系统间传输数据,或传输一份指定 SQL 格式及编码的纯文本文件。其他功能包括导入向导、导出向导、查询创建工具、报表创建工具、资料同步、备份、工作计划及更多。 本文介绍在Navicat Premium中进行简单的数据库管理。 在下载安装完 Navicat Premium 之后,进行以下操作。
zls365
2020/08/19
1.1K0
Navicat Premium基本使用
yyds,Navicat使用指南(上)
因为工作原因,需要经常连接不同的数据库,这里我安装的是Navicat Premium版本,在公众号后台回复 Navicat 即可获取。
SQL数据库开发
2024/04/25
1590
yyds,Navicat使用指南(上)
再见收费的Navicat,操作所有数据库就靠它了!
作为一名开发者,免不了要和数据库打交道,于是我们就需要一款顺手的数据库管理工具。很长一段时间里,Navicat 都是我的首选,但最近更换了一台新电脑,之前的绿色安装包找不到了。
沉默王二
2022/03/07
1.8K0
再见收费的Navicat,操作所有数据库就靠它了!
数据库导入sql文件_mysql导入sql文件命令
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/11
20.1K0
数据库导入sql文件_mysql导入sql文件命令
MySQL 数据库图形化管理界面应用种草之 Navicat Premium 如何使用
Navicat premium 是一款数据库管理工具。将此工具连接数据库,你可以从中看到各种数据库的详细信息。包括报错,等等。当然,你也可以通过他,登陆数据库,进行各种操作。Navicat Premium 是一个可多重连线资料库的管理工具,它可以让你以单一程式同时连线到 MySQL、SQLite、Oracle 及 PostgreSQL 资料库,让管理不同类型的资料库更加的方便。
白鹿第一帅
2021/03/02
2.3K0
MySQL 数据库图形化管理界面应用种草之 Navicat Premium 如何使用
测试使用navicat工具将MySQL格式SQL文件导入到MogDB数据库
当我们想把mysql格式的SQL文件导入到MogDB数据库时,我们可以借助navicat工具,先将SQL文件导入到mysql数据库中,再使用数据传输功能把SQL中的对象和数据直接导入到MogDB。或者使用数据传输功能将这些对象的定义和数据导出成PG格式的SQL语句,再导入到MogDB数据库中。
数据和云
2021/09/22
3.6K0
测试使用navicat工具将MySQL格式SQL文件导入到MogDB数据库
navicat导入sql文件报错_navicat怎么导入sql数据库文件
一、打开navicat,打开连接,右击连接名(如果新建连接,需要使用对应数据库的ip地址和密码,本机的是地址localhost,密码是自己mysql数据库的密码),选择新建数据库,数据库名要和想要导入的文件名一样(这种情况针对的是sql文件是直接由整个数据库导出的一个sql文件,如果表导出的sql文件,应该是随便命名数据库的名字,表名应该是和需要导入的文件名字相同(第二种情况没有亲自试过))。
全栈程序员站长
2022/11/09
4.7K0
navicat导入sql文件报错_navicat怎么导入sql数据库文件
Navicat使用指南(下)
这个是比较常见的功能,相比其他管理工具,Navicat将建表过程中所涉及的各种常用功能都包含进去了,包含新字段,索引,主键,外键,唯一键等等与表有关的内容,具体如下图:
SQL数据库开发
2024/04/25
2840
Navicat使用指南(下)
navicat连接mysql教程_navicat如何连接mysql?navicat 连接mysql Navicat使用教程
用Phpmyadmin导入导出数据受一定限制或服务商不配合提供mysql数据库的源文件,mysql数据库管理工具navicat for mysql,对于不怎么喜欢图形界面或者不太方便使用SQL的时候。我们可以通过用这个图形界面数据库管理工具来管理mysql,可以考虑使用第三方软件备份推荐使用Navicat for MySQL。
全栈程序员站长
2022/09/18
18.2K0
navicat连接mysql教程_navicat如何连接mysql?navicat 连接mysql Navicat使用教程
navicat premium使用教程详解_navicat premium怎么用
##Navicat Premium基本使用 Navicat是一套数据库管理工具,专为简化数据库的管理及降低系统管理成本而设。Navicat 是以直觉化的图形用户界面而建的,可以安全和简单地创建、组织、访问并共用信息。 Navicat Premium 是 Navicat 的产品成员之一,能简单并快速地在各种数据库系统间传输数据,或传输一份指定 SQL 格式及编码的纯文本文件。其他功能包括导入向导、导出向导、查询创建工具、报表创建工具、资料同步、备份、工作计划及更多。
全栈程序员站长
2022/09/23
2.1K0
navicat premium使用教程详解_navicat premium怎么用
Navicat数据库软件免费了!推出Navicat Premium Lite:支持MySQL、Redis等
数据库管理工具领域的知名品牌Navicat,推出其免费版本——Navicat Premium Lite,用户可从Navicat官网下载体验这款软件。
零云
2024/06/27
2.2K0
Navicat数据库软件免费了!推出Navicat Premium Lite:支持MySQL、Redis等
Navicat的详细教程{收藏}
Navicat 是一套快速、可靠并价格相宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设。它的设计符合数据库管理员、开发人员及中小企业的需要。Navicat 是以直觉化的图形用户界面而建的,让你可以以安全并且简单的方式创建、组织、访问并共用信息。
框架师
2019/09/19
5.7K0
Navicat的详细教程{收藏}
使用MYSQL命令直接导入导出SQL文件
很多时候,我们的数据开发都会用到很多开发利器,比如powerdesigner, navicat等这些软件,虽然好用,但是要收费,在公司里面是禁止使用盗版软件的,怕罚款各方面的,所以我们也不敢直接在公司的机子上装破解版,这个时候,如果我们要导入或者导出sql语句怎么办,虽然也有免费的软件如mysql-workbench的存在,但是不好用啊,操作复杂麻烦,要说好处吧,个人觉得就是记住密码和ip地址用户名这些方便咯,当然实际上它还是很强大的。
拓荒者
2019/03/15
9.5K0
使用MYSQL命令直接导入导出SQL文件
【每晚玩转一套ssm项目】厨艺交流平台网站
本文章教程手把手带你玩转ssm项目,曾经博主也是小白经过数个日夜终于将ssm玩透彻了。现在博主免费推出了【每晚玩转一套ssm项目】这一系列专栏,带你手把手上手ssm。请大家关注并监督我每晚更新哦~这个过程我也会从新人的角度总结出易错点并写道文章的最后。博主也是一枚在校大学生,现在带学弟学妹们入门ssm项目。在此之前你需要一定的计算机操作基础,现在我将带你,不需要写一行代码,从0到1搭建一个项目。
菜菜有点菜
2025/01/14
1280
【每晚玩转一套ssm项目】厨艺交流平台网站
Navicat Premium 15永久使用,安装教程,快捷键.md
在当今信息化的时代,数据库已经成为了生活和工作中不可或缺的一部分。而Navicat作为一款功能强大的数据库管理工具,深受广大开发者和数据库管理员的喜爱。最新版的Navicat Premium 15 已经发布了,但是是收费的,可以免费试用14天,为了享受永远试用,特作研究,本文只做研究探讨,支持购买正版。同时为大家介绍一些Navicat Premium 15中常用的快捷键,帮助你提升数据库管理的效率。
木头左
2024/06/12
5310
MySQL数据库界面化工具 - Navicat
本文使用的工具版本为:Navicat Premium 15,文中提到的功能在旧版中同样支持,如果需要最新版的软件(Mac/Windows)可私信博主。
一头小山猪
2020/05/19
6.4K0
MySQL数据库界面化工具 - Navicat
推荐阅读
相关推荐
使用了这个数据库神器,让我工作效率提升了数倍
更多 >
LV.1
腾讯云TDP产品KOL
目录
  • 将顶点动态化
  • 片元着色器编程
  • 缓存区对象
    • 使用缓存区步骤
      • gl.bindBuffer(target, buffer):
      • gl.bufferData(target, size, usage):
      • gl.getAttribLocation(program,name):
      • gl.vertexAttribPointer(name, size, type, normalized, stride, offset):
    • gl.enableVertexAttribArray(name):
    • gl.drawArrays(mode, first, count)
  • 扩展阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档