【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 系列 绘制猫 上文我们了解了如何绘制渐变彩色三角形,明白了图形装配.光栅化,以及片元着色器计算片元的颜色. 现在如果让你绘制如下一只猫.难道绘制很多三角形,然后指定它们的颜 ...
随机推荐
- 25-tree shaking(树摇)
const { resolve } = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin') ...
- 17-js代码压缩
const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); modul ...
- 安装MongoDB、及基本使用
1.MongoDB简介 MongoDB是一个介于关系数据库和非关系数据库之间的产品,基于分布式文件存储的数据库.是非关系数据库当中功能最丰富,最像关系数据库的.它支持的数据结构非常松散,是类似json ...
- 卧槽Winform也可以这么好看?
Winform也可以这么好看? 对于Winform很多人的刻板印象就是拖拉拽,简单生产界面,但是这样对于界面的效果,它并不会很好,虽然简单,快,但是效果也是极差,所以有很多人就去使用WPF,去写xml ...
- 2022-10-15:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。 你可以按 任意顺序 返回答案。 要求时间复杂度O(N)。 输入: nums = [1,1,1
2022-10-15:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素. 你可以按 任意顺序 返回答案. 要求时间复杂度O(N). 输入: nums = [1,1,1 ...
- 2022-03-13:golang项目代码push到gogs上,如何自动编译、打镜像、k8s上运行?
2022-03-13:golang项目代码push到gogs上,如何自动编译.打镜像.k8s上运行? 答案2022-03-13: 2022-02-23:如何搭建k8s单机环境(用k3s),并且搭建da ...
- Windows server 2012 安装ad域
Windows server 2012 安装ad域 安装ad域(active directory)服务的作用:存储目录数据并管理域之间的通信,包括用户登录处理,身份验证和目录搜索等. 1.使用ad ...
- Ubuntu 18.04 (Bionic) 简单快速的安装mongodb
按步骤走,不带脑子式安装(注意4.0版本mongodb官方已经不再支持,以下代码中可以修改mongodb版本号安装,目前最新版为6.0,如果懒得改直接用也可以,文章后边第三章第一条代码会直接升级为最新 ...
- linux 的 vi 命令详解
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的任何版本,vi编辑器是完全相 ...
- Spring boot+vue打包、上传宝塔面板并配置https
终于把网站搞完了,也终于能够通过域名访问了,这次就简单回顾一下这么多时间的经历,总结一下. 项目地址穆音博客,本文发布原地址在Spring boot+vue打包.上传宝塔面板并配置https 我的开发 ...