【WebGL系列-03】获取shader变量地址及赋值
获取shader变量地址及赋值
上一节创建了WebGL程序对象,创建好program对象后,对象中包含顶点着色器和片元着色器,着色器中含有变量,我们需要对其进行赋值后才能够进行绘制。
着色器代码如下:
const VSHADER_SOURCE = /* glsl */`
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
gl_PointSize = 10.0;
}
`;
const FSHADER_SOURCE = /* glsl */`
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
其中,顶点着色代码VSHADER_SOURCE中定义了一个attribute变量,a_Position,在main函数中将其赋值给GLSL ES的内置变量gl_Position,表示这个顶点所在的位置。
GLSL ES语言中,传入的变量有两种,attribute和uniform。其中,attribute变量只能定义在顶点着色器中,传输的是与顶点有关的数据,而uniform变量可以定义在顶点着色器和片元着色器中,传输的是与顶点无关或者说所有顶点共同使用的值。还有一类变量,varying变量,是用于顶点着色器和片元着色器之间传输数据的。定义varying变量时,需要在顶点着色器和片元着色器中各定义一个名称、类型都相同的变量,并指明为varying变量。
只传入一个数据(不使用缓冲区)
给attribute变量赋值
以示例的shader代码为例,如果我们只打算在指定的位置绘制一个点,那么我们需要做的事就是:找到变量所在的地址,然后给它赋值即可。所以,给一个变量赋值步骤如下:
- 找到变量所在的地址
- 给变量赋值
示例代码
const a_Position = gl.getAttribLocation(shaderProgram, "a_Position");
if (a_Position < 0) {
console.log("变量a_Position地址查找失败!");
return;
}
gl.vertexAttrib3f(a_position, 0.0, 0.0, 0.0);
接口
GLint WebGLRenderingContext.getAttribLocation(program, name)
获取attribute变量的地址
program: WebGLProgram,webgl程序name: string,变量名,与shader中的变量名一致
void WebGLRenderingContext.vertexAttrib3f(index, v0, v1, v2)
给顶点着色器中一个attribute变量赋值
index: 变量的地址
v0,v1,v2: 要赋值的值
vertexAttrib3f还有很多同族函数,针对不同类型的变量
vertexAttrib1f(index, v0)
vertexAttrib2f(index, v0, v1)
vertexAttrib3f(index, v0, v1, v2)
vertexAttrib4f(index, v0, v1, v2, v3)
vertexAttrib1fv(index, value)
vertexAttrib2fv(index, value)
vertexAttrib3fv(index, value)
vertexAttrib4fv(index, value)
其中,以f结尾的函数表示以浮点数的形式对变量进行赋值,1234表示分量的个数
以fv结尾的函数表示使用一个向量进行赋值,其值为一个Float32Array类型的值,1234表示这个结构化数组中的元素个数。
对变量进行赋值的时候,我们既可以通过浮点数分别对每个分量进行赋值,也可以使用结构化数组对整体赋值。
const a_foobar = gl.getAttribLocation(shaderProgram, "foobar");
// 对每个分量进行赋值
gl.vertexAttrib3f(a_foobar, 10.0, 5.0, 2.0);
// 使用结构化数组进行赋值
const floatArray = new Float32Array([10.0. 5.0, 2.0]);
gl.vertexAttrib3fv(a_foobar, floatArray);
对于矩阵,实际上是由多个列向量构成的,在计算其位置的时候,可以先获取到矩阵的起始位置,该位置+0,为第一列向量的位置,位置+1,为第二列向量的位置,以此类推,分别对每个列向量进行赋值,完成对整个矩阵的赋值。
/**
* 想赋值的3x3的矩阵为:
* 0 1 2
* 3 4 5
* 6 7 8
*/
const matrix3x3Location = gl.getAttribLocation(shaderProgram, "matrix3x3");
gl.vertexAttrib3f(matrix3x3Location, 0, 3, 6);
gl.vertexAttrib3f(matrix3x3Location + 1, 1, 4, 7);
gl.vertexAttrib3f(matrix3x3Location + 2, 2, 5, 8);
对uniform变量的赋值
uniform变量又称为一致变量,一般定义为与顶点无关的变量,即所有顶点保持一致的变量。
首先需要获取uniform变量的位置:
GLIint WebGLRenderingContext.getUniformLocation(program, name)
获取uniform变量的地址
program: WebGLProgram, webgl程序对象name: string,变量名
之后,就可以对这些变量进行赋值
uniform1f(location, v0)uniform2f(location, v0, v1)uniform3f(location, v0, v1, v2)uniform4f(location, v0, v1, v2, v3)uniform1fv(location, value)uniform2fv(location, value)uniform3fv(location, value)uniform4fv(location, value)uniform1i(location, v0)uniform1i(location, v0, v1)uniform1i(location, v0, v1, v2)uniform1i(location, v0, v1, v2, v3)uniform1iv(location, value)uniform2iv(location, value)uniform3iv(location, value)uniform4iv(location, value)
参数的含义与vertexAttrib[1234][fv]相同,不同的是,uniform变量可以设置整数类型的变量,即将其中的f换成i便代表整数类型,传入的数值类型也为整数。
对于uniform矩阵,有以下三个接口可以使用
uniformMatrix2fv(location, transpose, value)uniformMatrix3fv(location, transpose, value)uniformMatrix4fv(location, transpose, value)
其中,location表示uniform变量的地址,transpose为一个GLboolean类型的值,表示是否转置,默认为false,value是一个Float32Array类型的结构化数组,以列主序的方式指定矩阵的值
还有一个函数,用于获取指定位置的uniform变量的值
WebGLRenderingContext.getUniform(program, location)
获取uniform变量的值
program: WebGLProgram,webgl程序对象location: GLint,变量位置,可以由getUniformLocation获取
该函数的返回值跟据变量类型的不同而改变,对应类型如下表:
| Uniform类型 | 返回类型 |
|---|---|
| Uniform type | Returned type |
| WebGL 1 only | |
| boolean | GLBoolean |
| int | GLint |
| float | GLfloat |
| vec2 | Float32Array (with 2 elements) |
| ivec2 | Int32Array (with 2 elements) |
| bvec2 | Array of GLBoolean (with 2 elements) |
| vec3 | Float32Array (with 3 elements) |
| ivec3 | Int32Array (with 3 elements) |
| bvec3 | Array of GLBoolean (with 3 elements) |
| vec4 | Float32Array (with 4 elements) |
| ivec4 | Int32Array (with 4 elements) |
| bvec4 | Array of GLBoolean (with 4 elements) |
| mat2 | Float32Array (with 4 elements) |
| mat3 | Float32Array (with 9 elements) |
| mat4 | Float32Array (with 16 elements) |
| sampler2D | GLint |
| samplerCube | GLint |
| Additionally available in WebGL 2 | |
| uint | GLuint |
| uvec2 | Uint32Array (with 2 elements) |
| uvec3 | Uint32Array (with 3 elements) |
| uvec4 | Uint32Array (with 4 elements) |
| mat2x3 | Float32Array (with 6 elements) |
| mat2x4 | Float32Array (with 8 elements) |
| mat3x2 | Float32Array (with 6 elements) |
| mat3x4 | Float32Array (with 12 elements) |
| mat4x2 | Float32Array (with 8 elements) |
| mat4x3 | Float32Array (with 12 elements) |
| any sampler type | GLint |
赋值多个数据(使用缓冲区)
一般情况下,一个图形程序中有很多要绘制的对象,每个对象的位置、颜色等信息都不相同,但是用的是同一份shader源码,此时,如果使用上面的方法给shader中的变量赋值,那么最终渲染的结果会发现所有的东西都是一模一样的。此时,就需要使用缓冲区对每个渲染对象赋值不同的值。
缓冲区可以这么理解,就是开辟一个内存空间,把所有对象的位置信息、颜色信息等各种数据存储起来,当执行到这个对象对应的shader时,从内存中找到这个对象对应的数据,然后对变量进行赋值。这样,每次渲染的时候,每个对象都可以绘制成不同的样子。
使用缓冲区给变量赋值的过程分为如下几步:
- 创建缓冲区对象
- 将缓冲区对象绑定到目标
- 向缓冲区中写入数据
- 找到变量的位置
- 将缓冲区对象分配给变量
- 链接变量与缓冲区对象
示例代码
// 定义顶点数据
let vertices = new Float32Array([
0.0, 0.5, -0.5, -0.5, 0.5, -0.5
]);
// 创建顶点缓冲区
let vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
alert("缓冲区对象创建失败!");
}
// 绑定顶点缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 绑定顶点数据,并定义绘制方式
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 获取attribute变量地址
let aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition");
if (aVertexPosition < 0) {
alert('查找变量aVertexPosition失败!');
}
// 将缓冲区对象分配给变量
gl.vertexAttribPointer(aVertexPosition, 2, gl.FLOAT, false, 0, 0);
// 链接变量与缓冲区对象
gl.enableVertexAttribArray(aVertexPosition);
接口
WebGLBuffer WebGLRenderingContext.createBuffer()
创建一个buffer对象
void WebGLRenderingContext.bindBuffer(target, buffer)
将一个Buffer对象绑定到目标
target:GLenum,可以是以下几种:gl.ARRAY_BUFFER,包含顶点属性的buffer,如顶点坐标、纹理坐标数据或顶点颜色数据gl.ELEMENT_ARRAY_BUFFER:用于元素索引的buffer- 在webgl2,还可以使用以下值:
gl.COPY_READ_BUFFER:从一个buffer对象复制到另一个buffer对象gl.COPY_WRITE_BUFFER:从一个buffer对象复制到另一个buffer对象gl.TRANSFORM_FEEDBACK_BUFFER:buffer for transform feedback operationsgl.UNIFORM_BUFFER:用于存储统一块的buffergl.PIXEL_PACK_BUFFER:用于像素传输操作的buffergl.PIXEL_UNPACK_BUFFER:用于像素传输操作的buffer
buffer:要绑定的buffer
webgl1中
void WebGLRenderingContext.bufferData(target, size, usage)
void WebGLRenderingContext.bufferData(target, ArrayBuffer? srcData, usage)
void WebGLRenderingContext.bufferData(target, ArrayBufferView srcData, usage)
webgl2中
void WebGLRenderingContext.bufferData(target, ArrayBufferView srcData, usage, srcOffset, length)
创建并初始化buffer对象的数据存储区
target: GLenum,指定绑定目标,可以时以下值:gl.ARRAY_BUFFER,包含顶点属性的buffer,如顶点坐标、纹理坐标数据或顶点颜色数据gl.ELEMENT_ARRAY_BUFFER:用于元素索引的buffer- 在webgl2,还可以使用以下值:
gl.COPY_READ_BUFFER:从一个buffer对象复制到另一个buffer对象gl.COPY_WRITE_BUFFER:从一个buffer对象复制到另一个buffer对象gl.TRANSFORM_FEEDBACK_BUFFER:buffer for transform feedback operationsgl.UNIFORM_BUFFER:用于存储统一块的buffergl.PIXEL_PACK_BUFFER:用于像素传输操作的buffergl.PIXEL_UNPACK_BUFFER:用于像素传输操作的buffer
size:GLsizeiptr:设定buffer对象的数据存储区大小srcData(optional):一个ArrayBuffer、SharedArrayBuffer或者ArrayBufferView类型的数组对象,将被复制到buffer的数据存储区,如果为null,数据存储区会被创建,但是不会进行初始化和定义usage:GLenum,指定数据存储区的使用方法,可以是以下值:gl.STATIC_DRAW:缓冲区的内容可能经常使用,而不会经常修改,内容被写入缓冲区,但不被读取gl.DYNAMIC_DRAW:缓冲区的内容可能经常被使用,并且经常更改,内容被写入缓冲区,但不被读取gl.STREAM_DRAW:缓冲区的内容可能不会经常使用,内容被写入缓冲区,但不被读取- 使用webgl2时,还可以使用以下值:
gl.STATIC_READ:缓冲区的内容可能经常使用,而不会经常修改,内容从缓冲区读取,但不写入gl.DYNAMIC_READ:缓冲区的内容可能经常被使用,并且经常更改,内容从缓冲区读取,但不写入gl.STREAM_READ:缓冲区的内容可能不会经常使用,内容从缓冲区读取,但不写入gl.STATIC_COPY:缓冲区的内容可能经常使用,而不会经常修改,内容既不从缓冲区读取,也不写入gl.DYNAMIC_COPY:缓冲区的内容可能经常被使用,并且经常更改,内容既不从缓冲区读取,也不写入gl.STREAM_COPY:缓冲区的内容可能不会经常使用,内容既不从缓冲区读取,也不写入
srcOffset:GLuint,指定读取缓冲时的初始元素索引偏移量length(optional):GLuint,默认为0
void WebGLRenderingContext.vertexAttribPointer(index, size, type, normalized, stride, offset)
告诉显卡从当前绑定的缓冲区中读取顶点数据。
index:GLuint,指定要修改的顶点的索引size:GLint,指定每个顶点属性的组成数量,必须是1,2,3,4之一type:GLenum,指定数组中每个元素的数据类型,可以是以下值:gl.BYTE:有符号8位整数,范围[-128, 127]gl.SHORT:有符号16位整数,范围[-32768, 32767]gl.UNSIGNED_BYTE:无符号8位整数,范围[0, 255]gl.UNSIGNED_SHORT:无符号16位整数,范围[0, 65535]gl.FLOAT:32位IEEE标准的浮点数gl.HALF_FLOAT(webgl2):16位IEEE标准的浮点数
normalized:GLboolean,当转换为浮点数时是否应该将整数数值归一化到特定的范围- 对于BYTE和SHORT,将归一化到[-1, 1]
- 对于UNSIGNED_BYTE和UNSIGNED_SHORT,将归一化到[0, 1]
- 对于FLOAT和HALF_FLOAT,此参数无效
stride:GLsizei,以字节为单位指定连续顶点属性开始之间的偏移量offset:GLintptr,指定顶点属性数组中第一部分的字节偏移量,必须是类型的字节长度的倍数
void WebGLRenderingContext.enableVertexAttribArray(index)
打开属性数组列表中指定索引处的通用点点属性数组
index:GLuint,指向要激活的顶点属性
如果要关闭顶点属性数组,可以使用以下接口
void WebGLRenderingContext.disableVertexAttribArray(index)
关闭属性数组列表中指定索引处的通用点属性数组
index:GLuint,指定要关闭的顶点属性
【WebGL系列-03】获取shader变量地址及赋值的更多相关文章
- 驱动中获取PsActiveProcessHead变量地址的五种方法也可以获取KdpDebuggerDataListHead
PsActiveProcessHead的定义: 在windows系统中,所有的活动进程都是连在一起的,构成一个双链表,表头是全局变量PsActiveProcessHead,当一个进程被创建时,其Act ...
- java 27 - 4 反射之 通过反射获取成员变量并使用
类Field: 提供有关类或接口的单个字段的信息,以及对它的动态访问权限. A:获得类的成员变量 数组: 1.getFields(公共类的) 2.getDeclaredFields(所有类型的) B: ...
- $_SERVER变量 以及 PHP 使用 $_SERVER['PHP_SELF'] 获取当前页面地址及其安全性问题
PHP $_SERVER['PHP_SELF'] $_SERVER['PHP_SELF'] 表示当前 php 文件相对于网站根目录的位置地址,与 document root 相关. 假设我们有如下网址 ...
- Ansible系列(六):各种变量定义方式和变量引用
本文目录:1.1 ansible facts1.2 变量引用json数据的方式 1.2.1 引用json字典数据的方式 1.2.2 引用json数组数据的方式 1.2.3 引用facts数据1.3 设 ...
- Ansible系列(五):各种变量定义方式和变量引用
Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html 1.1 ansible facts facts组件是用来收集被管理节点信息的 ...
- php 获取客户端IP地址
/** * 获取真实IP地址 */ /* 在PHP中getenv(参数)函数是一个用于获取环境变量的函数,根据提供不同的参数可以获取不同的环境变量, getenv("REMOTE_ADDR& ...
- JavaScript进阶系列03,通过硬编码、工厂模式、构造函数创建JavaScript对象
本篇体验通过硬编码.工厂模式.构造函数来创建JavaScript对象. □ 通过硬编码创建JavaScript对象 当需要创建一个JavaScript对象时,我们可能这样写: var person = ...
- java版gRPC实战之六:客户端动态获取服务端地址
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- webgl 系列 —— 绘制一个点(版本2、版本3、版本4、版本5)
绘制一个点 我们初步认识了 webgl,本篇主要围绕绘制一个点的示例,逐步实现下面功能: 点的位置从 js 传入着色器 点的大小由 js 传入着色器 通过鼠标点击绘点 通过鼠标点击绘点,并改变点的颜色 ...
- webgl 系列 —— 绘制猫
其他章节请看: webgl 系列 绘制猫 上文我们了解了如何绘制渐变彩色三角形,明白了图形装配.光栅化,以及片元着色器计算片元的颜色. 现在如果让你绘制如下一只猫.难道绘制很多三角形,然后指定它们的颜 ...
随机推荐
- 笔记七:进程间的通信(IPC通信之信号灯)
信号量 定义信号变量: sem_t sem1 sem2 初始化信号量 P操作 V操作 功能 信号量(POSOX) 信号量灯(IPC) 定义信号变量 sem_t sem1 ...
- Godot 4.0 设置应用程序图标、项目图标
godot版本:4.0.2,理论上4.0.0版也适用. 本文章是针对window应用程序而写的,其他平台不一定适用,仅供参考. 效果 输出的可执行文件图标为指定的图标,适配多种尺寸 执行时窗口图标为指 ...
- [ [Ynoi2013] 无力回天 NOI2017 ] 解题报告
[Ynoi2013] 无力回天 NOI2017 首先看到异或,想到能维护异或的东西就那几样(线性基/01trie/数位 dp/FWT),再看到求选任意个数后的异或最大值,线性基无疑了. 这时再看还要维 ...
- 记一次nginx配置不当引发的499与failover 机制失效
背景 nginx 499在服务端推送流量高峰期长期以来都是存在的,间或还能达到告警阈值触发一小波告警,但主观上一直认为499是客户端主动断开,可能和推送高峰期的用户打开推送后很快杀死app有关,没有进 ...
- Maven工程开发
Maven工程开发 编写pom.xml配置文件 <properties></properties>定义项目的基本信息 groupId 反向域名,定义项目组名 artifactI ...
- 如何理解 Spring Boot 中的 Starter ?
假如 没有 Spring Boot Starter,我们有两种方式来创建 Spring Bean. spring xml 模式 (远古模式,并不推荐) spring API 来创建 Spring Be ...
- Rocky 9 Linux 软件安装 neovim 和 git
目录 编辑器 Neovim 版本控制工具 Git RHEL 系列软件安装介绍 软件安装包简介 源码包安装 rpm包安装 yum & dnf 在线安装 脚本安装包 rockyLinux 介绍软件 ...
- 2021-02-05:给定一个数N,想象只由0和1两种字符,组成的所有长度为N的字符串。如果某个字符串,任何0字符的左边都有1紧挨着,认为这个字符串达标。请问有多少达标的字符串?
2021-02-05:给定一个数N,想象只由0和1两种字符,组成的所有长度为N的字符串.如果某个字符串,任何0字符的左边都有1紧挨着,认为这个字符串达标.请问有多少达标的字符串? 福哥答案2021-0 ...
- 2021-10-31:移动零。给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。示例:输入: [0,1,0,3,12]。输出: [1,3,12,0,0]。说
2021-10-31:移动零.给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序.示例:输入: [0,1,0,3,12].输出: [1,3,12,0,0].说 ...
- SQL Server:User, group, or role 'iemis' already exists in the current database.
--最新的解决方法 --先创建用户帐户,不进行授权,然后通过下面的SQL语句将该用户帐户关联至对应的数据库用户.优点是避免了重新授权的操作. USE tempdbEXEC sp_change_user ...