首页 > 其他分享 >【WebGL系列-03】获取shader变量地址及赋值

【WebGL系列-03】获取shader变量地址及赋值

时间:2023-07-24 13:45:47浏览次数:35  
标签:03 变量 buffer WebGL shader 缓冲区 顶点 gl 赋值

获取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,指定要关闭的顶点属性

标签:03,变量,buffer,WebGL,shader,缓冲区,顶点,gl,赋值
From: https://www.cnblogs.com/masakulayou/p/17576998.html

相关文章

  • 【WebGL系列-04】清除缓冲区并绘制图形
    清除缓冲区并绘制图形前文中已经准备好了webgl程序和绘制所用的数据,但是在绘制图像之前,还要对画布进行处理。清除缓冲区由于图像的绘制是一帧一帧绘制,每一帧针对当前的状态,计算屏幕上每个像素的颜色,得到最终的绘制结果。这些状态被保存在一个叫帧缓冲区的地方。帧缓冲区不仅能......
  • sqlserver:拒绝了对对象 'QualityChxxx' (数据库 'xxx',架构 'dbo')的 SELECT 权限
    选择数据库(xxxx)—>安全性—->架构—->dbo(属性)—>权限—>添加—>浏览–>QualityChxxx  ......
  • Cannot read properties of undefined (reading 'state') 或者 Cannot read propertie
     第一步,先检查是否在main.js中引入store.js 如果检查完都引入了,且还是存在报错,第二步:在package.json将vuex的版本更换为其它版本,并从新yarn安装,建议vuex版本为3.0然后从新启动项目即可解决......
  • Codeforces Round 887 (Div 2) C. Ntarsis' Set
    Ntarsis'Set题意是给你n个数,每次按照顺序删除位于a[i]位置的这n个数,问k次后最小的是多少参考这位大佬的题解CodeforcesRound887(Div2)A~C-知乎(zhihu.com)结合一个官方题解,进行一次操作后,由于前面删掉i个数,a[i]到a[i+1]间所有数的排名都要-=i,那么在a[i]到a[i+1]之间的......
  • 打造原生 WebGL 2D 引擎:一场创意与技术的融合
    打造原生WebGL2D引擎:一场创意与技术的融合1.引言在当今数字化时代,网页的功能越来越丰富,已经远远超越了传统的文本和图片呈现。我们生活在一个充满交互性和视觉魅力的网络世界。每天都会遇到许多令人惊叹的网页效果和动画。作为一个Web3D图形的开发,希望可以通过网页来实现更多......
  • Failed to convert property value of type 'java.lang.String' to required typ
    标题:深入了解Spring框架中的类型转换异常概述:在开发过程中,我们经常会遇到类型转换的问题。尤其是在使用Spring框架进行开发时,经常会遇到“Failedtoconvertpropertyvalueoftype'java.lang.String'torequiredtype”的异常。本文将详细介绍这个异常的原因和解决方法,并提供......
  • Building for iOS, but the linked and embedded framework 'libpag.framework' w
    BuildingforiOS,butthelinkedandembeddedframework'libpag.framework'issueWhendevelopingiOSapps,itisnotuncommontocomeacrossvariouserrorsandissuesduringthebuildprocess.Onesuchissueisthe"BuildingforiOS,butth......
  • STM32F103C8T6串口通信
     首先来看一下需要操作的函数,以及配置的步骤:图1                         图2  Code:usart.c#include"usart.h"voidustart_Init(void){GPIO_InitTypeDefGPIO_Init_Ustar;//定义......
  • Python报错 | AttributeError: 'NoneType' object has no attribute 'group'
    报错信息使用Python正则匹配的时候,报如下错误:AttributeError:'NoneType'objecthasnoattribute'group'错误原因报错翻译过来是:属性错误:“NoneType”对象没有属性“group”没有匹配到符合正则表达式的内容,但又调用了group方法。importrestr='hellopython!!!hel......
  • week-0703
    电信和卫健委举办的攻防演练,资产主要是全市的医院,有保密协议,只能挑两个简单说说 医院a小程序口腔种植科可以直接修改价格 经典老洞了一分钱以上随便改 医院b可以未授权访问看到接口信息,其中一个口是发验证码的,构造content和mobile参数,可以实现指定内容的短信轰炸,中文除外......