获取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. 25-tree shaking(树摇)

    const { resolve } = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin') ...

  2. 17-js代码压缩

    const { resolve } = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); modul ...

  3. 安装MongoDB、及基本使用

    1.MongoDB简介 MongoDB是一个介于关系数据库和非关系数据库之间的产品,基于分布式文件存储的数据库.是非关系数据库当中功能最丰富,最像关系数据库的.它支持的数据结构非常松散,是类似json ...

  4. 卧槽Winform也可以这么好看?

    Winform也可以这么好看? 对于Winform很多人的刻板印象就是拖拉拽,简单生产界面,但是这样对于界面的效果,它并不会很好,虽然简单,快,但是效果也是极差,所以有很多人就去使用WPF,去写xml ...

  5. 2022-10-15:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。 你可以按 任意顺序 返回答案。 要求时间复杂度O(N)。 输入: nums = [1,1,1

    2022-10-15:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素. 你可以按 任意顺序 返回答案. 要求时间复杂度O(N). 输入: nums = [1,1,1 ...

  6. 2022-03-13:golang项目代码push到gogs上,如何自动编译、打镜像、k8s上运行?

    2022-03-13:golang项目代码push到gogs上,如何自动编译.打镜像.k8s上运行? 答案2022-03-13: 2022-02-23:如何搭建k8s单机环境(用k3s),并且搭建da ...

  7. Windows server 2012 安装ad域

    Windows server 2012 安装ad域   安装ad域(active directory)服务的作用:存储目录数据并管理域之间的通信,包括用户登录处理,身份验证和目录搜索等. 1.使用ad ...

  8. Ubuntu 18.04 (Bionic) 简单快速的安装mongodb

    按步骤走,不带脑子式安装(注意4.0版本mongodb官方已经不再支持,以下代码中可以修改mongodb版本号安装,目前最新版为6.0,如果懒得改直接用也可以,文章后边第三章第一条代码会直接升级为最新 ...

  9. linux 的 vi 命令详解

    vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的任何版本,vi编辑器是完全相 ...

  10. Spring boot+vue打包、上传宝塔面板并配置https

    终于把网站搞完了,也终于能够通过域名访问了,这次就简单回顾一下这么多时间的经历,总结一下. 项目地址穆音博客,本文发布原地址在Spring boot+vue打包.上传宝塔面板并配置https 我的开发 ...