【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 系列 绘制猫 上文我们了解了如何绘制渐变彩色三角形,明白了图形装配.光栅化,以及片元着色器计算片元的颜色. 现在如果让你绘制如下一只猫.难道绘制很多三角形,然后指定它们的颜 ...
随机推荐
- Java的初始化块
三种初始化数据域的方法: 在构造器中设置值 在声明中赋值 初始化块(initialization block) 初始化块 在一个类的声明中,可以包含多个代码块.只要构造类的对象,这些块就会被执行. c ...
- 通过Handsontable实现像Excel一样编辑数据
一.Handsontable是指什么? 官网: http://handsontable.com Handsontable是一个JavaScript库,可以帮助您轻松实现类似Excel电子表格一样的编 ...
- Prism Sample 29-InvokeCommandAction
一下子跳到29,不是我的错,应该是新版本中去掉了一些过重的功能,案例就也去掉了,所以不是我的错. 本例是演示行为转命令的,事实上前面已经用到了. xmlns:i="http://schema ...
- docker常用命令之帮助启动类命令和镜像命令
docker安装之后,启动时会报如下错误: Job for docker.service failed because start of the service was attempted too o ...
- SQLLabs靶场 less11-20
SQLLabs靶场 less11-20 Less-11-16 请求方式 注入类型 拼接方式 POST 联合.报错.布尔盲注.延时盲注 username='x'11 请求方式 注入类型 拼接方式 POS ...
- 2022-09-26:以下go语言代码输出什么?A:{“Time“: “2020-12-20T00:00:00Z“, “N“: 5 };B:“2020-12-20T00:00:00Z“;C:{“N“:
2022-09-26:以下go语言代码输出什么?A:{"Time": "2020-12-20T00:00:00Z", "N": 5 }:B: ...
- 2022-09-20:以下go语言代码输出什么?A:8 8;B:8 16;C:16 16;D:16 8。 package main import ( “unsafe“ “fmt“ )
2022-09-20:以下go语言代码输出什么?A:8 8:B:8 16:C:16 16:D:16 8. package main import ( "unsafe" " ...
- 2022-05-18:假设数组a和数组b为两组信号: 1) length(b) <= length(a); 2) 对于任意0<=i<length(b), 有b[i+1] - b[i] == a[i+1
2022-05-18:假设数组a和数组b为两组信号: length(b) <= length(a): 对于任意0<=i<length(b), 有b[i+1] - b[i] == a[ ...
- 2021-05-27:定义何为step sum?比如680,680+68+6=754,680的step sum叫754。
2021-05-27:定义何为step sum?比如680,680+68+6=754,680的step sum叫754.给定一个整数num,判断它是不是某个数的step sum? 福大大 答案2021 ...
- 局部添加加载中效果loading (vue+elementUI)
产品需求:有时候我们不想为整个页面添加loading效果.只想给局部区域添加loading效果.(这效果就不揍产品了) 在一个表格数据加载时,因为需要连接其它东西,所以后台接口返回数据需要较长时间,因 ...