【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 系列 绘制猫 上文我们了解了如何绘制渐变彩色三角形,明白了图形装配.光栅化,以及片元着色器计算片元的颜色. 现在如果让你绘制如下一只猫.难道绘制很多三角形,然后指定它们的颜 ...
随机推荐
- 音视频通讯QoS技术及其演进
利用多种算法和策略进行网络传输控制,最大限度满足弱网场景下的音视频用户体验. 良逸|技术作者 01 什么是QoS?音视频通讯QoS是哪一类? QoS(Quality of Service)是服务质量的 ...
- [C++提高编程] 3.1 string容器
文章目录 3.1 string容器 3.1.1 string基本概念 3.1.2 string构造函数 3.1.3 string赋值操作 3.1.4 string字符串拼接 3.1.5 string查 ...
- 分享一个提高运维效率的 Python 脚本
哈喽大家好我是咸鱼,今天给大家分享一个能够提升运维效率的 python 脚本 咸鱼平常在工作当中通常会接触到下面类似的场景: 容灾切换的时候批量对机器上的配置文件内容进行修改替换 对机器批量替换某个文 ...
- 2020-10-25:go中channel的close流程是什么?
福哥答案2020-10-25:
- 2021-03-31:给定一个数组arr,给定一个值v。求子数组平均值小于等于v的最长子数组长度。
2021-03-31:给定一个数组arr,给定一个值v.求子数组平均值小于等于v的最长子数组长度. 福大大 答案2021-03-31: 这道题是昨天每日一题的变种.数组每个元素减v,然后求<=0 ...
- 分库分表的 21 条法则,hold 住!
大家好,我是小富- (一)好好的系统,为什么要分库分表? 本文是<分库分表ShardingSphere5.x原理与实战>系列的第二篇文章,距离上一篇文章已经过去好久了,惭愧惭愧- 还是不着 ...
- < Python全景系列-2 > Python数据类型大盘点
<Python全景系列-2> Python数据类型大盘点 欢迎来到我们的系列博客<Python全景系列>!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高 ...
- 【汇编】masm文件夹整理
整理masm文件夹 前言 不好意思,我又来了,今天上汇编课,发现汇编masm文件夹实在是太乱了,像这样: 着实太乱了!程序一多就会很乱很让人心烦!(虽然我现在没有认真上汇编课吧,就这几个文件) 开始折 ...
- Github疯传!200本计算机经典书籍!
好书在精不在多,每一本经典书籍都值得反复翻阅,温故而知新! 下面分享几本计算机经典书籍,都是我自己看过的. 重构 改善既有代码的设计 就像豆瓣评论所说的,看后有种醍醐灌顶.欲罢不能的感觉.无论你是初学 ...
- django中有关登陆验证的LoginRequiredMixin类
通常情况判断一个用户是否登陆可以使用 request.user.is_is_authenticate(),就可以完成,返回结果TRUE或者FALSE class UserCenterInfoView( ...