获取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语言中,传入的变量有两种,attributeuniform。其中,attribute变量只能定义在顶点着色器中,传输的是与顶点有关的数据,而uniform变量可以定义在顶点着色器和片元着色器中,传输的是与顶点无关或者说所有顶点共同使用的值。还有一类变量,varying变量,是用于顶点着色器和片元着色器之间传输数据的。定义varying变量时,需要在顶点着色器和片元着色器中各定义一个名称、类型都相同的变量,并指明为varying变量。

只传入一个数据(不使用缓冲区)

给attribute变量赋值

以示例的shader代码为例,如果我们只打算在指定的位置绘制一个点,那么我们需要做的事就是:找到变量所在的地址,然后给它赋值即可。所以,给一个变量赋值步骤如下:

  1. 找到变量所在的地址
  2. 给变量赋值

示例代码

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类型的值,表示是否转置,默认为falsevalue是一个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 operations
      • gl.UNIFORM_BUFFER:用于存储统一块的buffer
      • gl.PIXEL_PACK_BUFFER:用于像素传输操作的buffer
      • gl.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 operations
      • gl.UNIFORM_BUFFER:用于存储统一块的buffer
      • gl.PIXEL_PACK_BUFFER:用于像素传输操作的buffer
      • gl.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变量地址及赋值的更多相关文章

  1. 驱动中获取PsActiveProcessHead变量地址的五种方法也可以获取KdpDebuggerDataListHead

    PsActiveProcessHead的定义: 在windows系统中,所有的活动进程都是连在一起的,构成一个双链表,表头是全局变量PsActiveProcessHead,当一个进程被创建时,其Act ...

  2. java 27 - 4 反射之 通过反射获取成员变量并使用

    类Field: 提供有关类或接口的单个字段的信息,以及对它的动态访问权限. A:获得类的成员变量 数组: 1.getFields(公共类的) 2.getDeclaredFields(所有类型的) B: ...

  3. $_SERVER变量 以及 PHP 使用 $_SERVER['PHP_SELF'] 获取当前页面地址及其安全性问题

    PHP $_SERVER['PHP_SELF'] $_SERVER['PHP_SELF'] 表示当前 php 文件相对于网站根目录的位置地址,与 document root 相关. 假设我们有如下网址 ...

  4. Ansible系列(六):各种变量定义方式和变量引用

    本文目录:1.1 ansible facts1.2 变量引用json数据的方式 1.2.1 引用json字典数据的方式 1.2.2 引用json数组数据的方式 1.2.3 引用facts数据1.3 设 ...

  5. Ansible系列(五):各种变量定义方式和变量引用

    Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html 1.1 ansible facts facts组件是用来收集被管理节点信息的 ...

  6. php 获取客户端IP地址

    /** * 获取真实IP地址 */ /* 在PHP中getenv(参数)函数是一个用于获取环境变量的函数,根据提供不同的参数可以获取不同的环境变量, getenv("REMOTE_ADDR& ...

  7. JavaScript进阶系列03,通过硬编码、工厂模式、构造函数创建JavaScript对象

    本篇体验通过硬编码.工厂模式.构造函数来创建JavaScript对象. □ 通过硬编码创建JavaScript对象 当需要创建一个JavaScript对象时,我们可能这样写: var person = ...

  8. java版gRPC实战之六:客户端动态获取服务端地址

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. webgl 系列 —— 绘制一个点(版本2、版本3、版本4、版本5)

    绘制一个点 我们初步认识了 webgl,本篇主要围绕绘制一个点的示例,逐步实现下面功能: 点的位置从 js 传入着色器 点的大小由 js 传入着色器 通过鼠标点击绘点 通过鼠标点击绘点,并改变点的颜色 ...

  10. webgl 系列 —— 绘制猫

    其他章节请看: webgl 系列 绘制猫 上文我们了解了如何绘制渐变彩色三角形,明白了图形装配.光栅化,以及片元着色器计算片元的颜色. 现在如果让你绘制如下一只猫.难道绘制很多三角形,然后指定它们的颜 ...

随机推荐

  1. ROS2的安装与使用(超详细图文教程)

    ROS2的安装与使用(超详细图文教程) 如果前面的虚拟机以及Ubuntu22.04镜像都安装好了,根据目录直接跳到ROS2的安装. 资料参考于:古月居 VMware虚拟机的安装 安装地址: 对于不了解 ...

  2. 访问nginx报错502日志:failed (13: Permission denied) while connecting to upstream

    1.错误问题 nginx启动成功,但是访问nginx报错502.检查后台项目,使用IP+端口可以正常访问项目的,这说明项目启动成功了.那就是nginx的问题.检查了nginx.conf文件发现配置的反 ...

  3. js 获取窗口/容器内部滚动位置

    前端 (document.getElementsByClassName("container")[0]).scrollTop -- 容器内部滚动条位置 (document.getE ...

  4. [OpenCV-Python] 24 模板匹配

    文章目录 OpenCV-Python:IV OpenCV中的图像处理 24 模板匹配 24.1 OpenCV 中的模板匹配 24.2 多对象的模板匹配 OpenCV-Python:IV OpenCV中 ...

  5. rfc7234之http缓存

    声明:本人原创文章,详细内容已发布在我的微信个人技术公众号---网络技术修炼,公众号总结普及网络基础知识,包括基础原理.网络方案.开发经验和问题定位案例等,欢迎关注. 缓存概念 缓存处理请求步骤 缓存 ...

  6. 基于APM模式的异步实现及跨线程操作窗体或控件方法的实现示例

    最近在一家某电力外派公司开发相关于GIS的功能,在实现代码的过程中出现了一些常见的问题比如: 1.跨线程执行窗体或控件操作(直接使用委拖) 2.异步模式执行某长时间耗时方法 经过一系列摸索可算找到解决 ...

  7. 2023-02-14:魔物了占领若干据点,这些据点被若干条道路相连接, roads[i] = [x, y] 表示编号 x、y 的两个据点通过一条道路连接。 现在勇者要将按照以下原则将这些据点逐一夺回:

    2023-02-14:魔物了占领若干据点,这些据点被若干条道路相连接, roads[i] = [x, y] 表示编号 x.y 的两个据点通过一条道路连接. 现在勇者要将按照以下原则将这些据点逐一夺回: ...

  8. 【工作随手记】mysql优化之1

    原SQL: SELECT p.id, p.NAME, p.idcard, p.phone, p.plate, p.FAMILY_NO FROM t_person_info p WHERE p.id I ...

  9. Python从零到壹丨图像增强的顶帽运算和底帽运算

    摘要:这篇文章详细介绍了顶帽运算和底帽运算,它们将为后续的图像分割和图像识别提供有效支撑. 本文分享自华为云社区<[Python从零到壹] 四十九.图像增强及运算篇之顶帽运算和底帽运算>, ...

  10. Ubuntu22.04 安装单机版kubernetes

    前言 上期讲到要实现.net 6框架下的EF Core操作数据库基本增删改查,没有及时兑现.没有兑现的原因就是因为安装kubernetes.安装kubernetes的过程是灾难性的,也是十分顺利的.灾 ...