GLSL ES 1.0

GLSL ES 概述

写在前面

  • 程序是大小写敏感的
  • 每一个语句都应该以英文分号结束
  • 一个shader必须包含一个main函数,该函数不接受任何参数,并且返回void
    void main()
    {
    }
    

数据值类型

GLSL支持三种数据类型:

  • 整型
  • 浮点型:必须包含小数点,不然会被认为是浮点型,比如1表示整形,1.0才表示浮点型
  • 布尔类型

GLSL是强类型语言,这意味着:

  • 将浮点数赋值给一个整型变量是不对的,同理,将一个整数赋值给浮点数变量也不被允许
    // 会报错,错误信息如下:
    // Failed to compile shader: ERROR: 0:56: '=' :
    // cannot convert from 'const int' to 'mediump float'
    float a1 = 1;// 会报错,错误信息如下:
    // Failed to compile shader: ERROR: 0:56: '=' : 
    // cannot convert from 'const float' to 'mediump int'
    int a1 = 1.0;
    
  • 在一个计算表达式中,必须统一数据类型,比如一个包含浮点数的表达式中,不能使用整型数据,这个经常由于不小心的书写导致编译失败。
    // 会报错
    // Failed to compile shader: ERROR: 0:57: '*' : 
    // wrong operand types - no operation '*' exists that 
    // takes a left-hand operand of type 'mediump float' 
    // and a right operand of type 'const int'
    float a1 = 1.0;
    float a2 = a1 * 3;
    

数据转换

虽然GLSL是强类型语言,但是我们可以通过显示转换实现数据类型的转变,比如我们可以使用float()将数据类型转换为浮点数,GLSL支持float、int和bool的相互转换

// 将整数转换为浮点数
float(int)
// true被转换为1.0 false被转换为0.0
float(bool)
// 将浮点数的小数删去,整数部分转换为整型
int(float)
// 	true被转换为1 false被转换为0
int(bool)
// 0.0被转换为false,其他值转换为true
bool(float)
// 0被转换为false,其他值转换为true
bool(int)

矢量和矩阵

GLSL可以通过基本数值类型组合成矢量和矩阵,矢量的数据类型可以是浮点数,整数和bool值,但是矩阵WebGL1.0只支持浮点数

矢量

  • vec2, vec3, vec4:具有2、3、4浮点数元素的矢量
  • iec2, ivec3, ivec4:具有2、3、4整数元素的矢量
  • bec2, bec3, bec4:具有2、3、4bool值元素的矢量

矩阵

  • mat2:2x2浮点数矩阵
  • mat3:3x3浮点数矩阵
  • mat4:4x4浮点数矩阵

赋值构造

在给矢量或者矩阵赋值的时候,必须遵循:

  • 赋值两边的数据类型必须一致,不然会报错
  • 赋值两边的元素个数必须一致
  • 对于矩阵,默认的构造顺序是按照列主序的
  • 对于矩阵,如果只传递了一个数值,会构造一个对角线都是该值,其他值都是0的矩阵

访问

访问矢量和矩阵可以有两种方式,一种是通过.运算符,一种是通过[]
使用点运算符访问有三种访问方式:

  • x,y,z,w:分别对应矢量的第1、2、3、4个分量,注意:矩阵是不能用该方式访问的
  • r,g,b,a:分别对应矢量的第1、2、3、4个分量,注意:矩阵是不能用该方式访问的
  • s,t,p,q:分别对应矢量的第1、2、3、4个分量,注意:矩阵是不能用该方式访问的

对于每一种访问方式,都可以混合使用,比如:

// 下面这些访问方式都是正确的
vec4 a1 = vec4(1.0, 1.1, 1.2, 1.3);
float b1 = a1.x;
vec2 c1 = a1.xy;
vec2 d1 = a1.yx;
vec2 e1 = a1.xx;

但是不同访问方式之间不可以混合使用

矩阵的访问更简单,类似于C语言的数组访问,使用[],从0开始,0表示第一项,使用[]访问的时候需要注意:

  • 矩阵是列主序的
  • []必须是整型字面值或者const整型或者循环索引或者三者的组合表达式

运算

如果一个矢量和一个数值进行运算,结果是该数值和矢量的每个分量进行运算
如果一个矩阵和一个数值进行运算,结果是该数值和矩阵的每个分量进行运算

结构体

GLSL使用如下方式定义一个结构体:

struct light
{vec4 color;vec3 position;
};
light l1;
light l2;

使用点运算符访问结构体的成员。

数组

GLSL中可以使用数组,但是只可以使用一维数组
以下是数组的声明方式:

float floatArray[4];
vec4 vec4Array[3];

数组的长度必须是大于0的整型常量表达式:

  • 整型字面值
  • 用const限定符修饰的全局变量或者局部变量
  • 由前面两条组成的表达式

注意:在使用数组的时候,数组的索引只可以是整型常量表达式或者uniform变量。
注意:数组不可以在声明的时候直接初始化,必须显示的对每个元素进行初始化。

采样器

GLSL支持一种内置类型-采样器,我们只能通过采样器来获取纹理的数据。
GLSL ES1.0支持两种采样器类型:

  • sampler2D:二维纹理贴图
  • samplerCube:三维纹理贴图

采样器只能是uniform变量

我们通过GLSL提供的内置函数来从采样器中访问纹理数据,内置函数有两类,可以参考文章WebGL 1.0 内置函数

唯一能赋值给采样器变量的就是纹理单元编号,而且你必须使用WebGL方法

gl.uniform1i(u_Sampler, 纹理单元编号);

for循环

GLSL中可以使用for循环,和C语言很像,但是有些限制:

  • 循环变量只能有一个
  • 循环变量只能是int或者float
  • 循环变量只能和整型常量做比较
    有些时候,循环变量的比较对象我们可能期望是一个uniform传递过来的动态值。这个时候直接进行比较是不可以的,一种处理的办法是给一个足够大的比较值,然后在循环体内部判断循环变量和uniform变量的大小
  • 在循环体内,循环变量不可以被赋值

discard

discard只能在片元着色器使用,表示放弃当前片元的处理。

函数

GLSL的函数和C语言类似,如果我们在函数定义前就调用了函数,需要先对函数进行声明。

对于函数的参数,我们可以为参数指定限定词,以控制参数的行为。
函数参数的限定词有下面几种:

  • in:这是默认的限定词。值传递,函数内部修改参数的值不会影响传入的值
  • const in:也是值传递,但是函数内部不可以修改该值
  • out:引用传递,类似于C语言的指针或者C++的引用,内部修改会影响传入参数的值。
  • inout:和out一样也是引用传递,但是和out不同之处为out不应该对传入的值抱有期待,out主要为了传递出函数内部的值。而inout表明该参数既要被函数使用,也要被函数修改。

存储限定符

GLSL中的存储限定符有四种:

  • attribute
  • uniform
  • varying
  • const

const

表明当前变量不可以被修改,是一个常量
const变量定义时就需要赋值。

attribute

  • attribute变量只能出现在顶点着色器
  • attribute只能声明为全局变量
  • 在GLSL ES1.0中,attribute只能是float、vec2、vec3、vec4、mat2、mat3、mat4
  • 可以通过访问内置的全局变量gl_MaxVertexAttribs来获取attribute变量支持的数目,对于WebGL环境,最小为8

attribute表示逐顶点数据,应该传递顶点独有的属性数据,对于所有顶点共有的属性,应该使用uniform

uniform

  • uniform变量在顶点着色器和片元着色器中都可以使用
  • uniform只能声明为全局变量
  • uniform变量是只读的
  • 对于GLSL ES1.0,uniform不能声明为数组或者结构
  • 如果在顶点着色器和片元着色器声明了同名的uniform变量,该变量会被两个着色器共享。
  • 可以通过访问内置的全局变量gl_MaxVertexUniformVectors获取顶点着色器支持的uniform变量数量,通过访问内置的全局变量gl_MaxFragmentUniformVectors获片元着色器支持的uniform变量数量,对于WebGL环境,gl_MaxVertexUniformVectors最小为128,gl_MaxFragmentUniformVectors最小为16

varying

  • varying的目的是从顶点着色器传递数据到片元着色器。
  • varying成对出现,并且在顶点着色器和片元着色器中的名称和类型一致。
  • varying只能是全局变量
  • varying的类型和attribute一致

varying的中文翻译是变化的意思,既然为了传递数据,为什么用这么个名字呢?
原因就是我们在片元着色器中看到的varying变量虽然和顶点着色器中的名称和类型一致,但数据已经不一样了,看下面的代码:

// 顶点着色器
attribute vec2 a_Position;
attribute vec3 a_Color;
varying vec3 v_Color;
void main() {v_Color = a_Color;gl_Position = vec4(a_Position.x,a_Position.y,0.0,1.0);
}`;// 片元着色器
varying vec3 v_Color;
void main()
{gl_FragColor = vec4(v_Color,1.0);
}	

我们过一下其中的过程:

  1. 顶点着色器将每个顶点的颜色赋值给v_Color,如果有100个顶点,就有100个v_Color值
  2. 从顶点着色器到片元着色器的过程中,发生了光栅话,就是说在这个过程中,根据绘制的图形,会对v_Color进行插值
  3. 片元着色器中的v_Color是每个片元插值后的值。所以,采用了varying这个名称来标记光栅话的过程

从上面的解释可以看出,一般而言,varying都是针对于attribute变量的传递,所以,varying变量的数据类型和attribute变量是一致的。

可以通过访问内置的全局变量gl_MaxVaryingVectors获取着色器支持的varying变量数量,对于WebGL环境,gl_MaxVaryingVectors最小为8

最后,给出一张不同限定符数据在GPU中的传递图
在这里插入图片描述

精度限定符

定义

GLSL ES 新引入了精度限定符,目的是帮助着色器程序提高运行效率,削减内存开支。 顾名思义,精度限定符用来表示每种数据具有的精度 (比特数)。简而言之,高精度的程序需要更大的开销 (包括更大的内存和更久的计算时间),而低精度的程序需要的开销则小得多。使用精度限定符,你就能精细地控制程序在效果和性能间的平衡。

作用

精度限定符有两个作用:

  • 对于浮点数和采样器,精度限定符限制了精度和取值范围
  • 对于整型数据,精度限定符限制了取值范围

三种精度类型

因为我们使用采样器的时候,传递的也是浮点纹理坐标,所以我们总结一下不同的精度限定符对float和int的影响:

  • highp:高精度,顶点着色器的最低精度
    • 对于float,取值范围为 ( − 2 62 , 2 62 ) (-2^{62},2^{62}) (262,262),精度范围 2 − 16 2^{-16} 216
    • 对于int,取值范围为 ( − 2 16 , 2 16 ) (-2^{16},2^{16}) (216,216)
  • mediump:中精度,片元着色器的最低精度
    • 对于float,取值范围为 ( − 2 14 , 2 14 ) (-2^{14},2^{14}) (214,214),精度范围 2 − 10 2^{-10} 210
    • 对于int,取值范围为 ( − 2 10 , 2 10 ) (-2^{10},2^{10}) (210,210)
  • lowp:低精度
    • 对于float,取值范围为 ( − 2 , 2 ) (-2,2) (2,2),精度范围 2 − 8 2^{-8} 28
    • 对于int,取值范围为 ( − 2 8 , 2 8 ) (-2^{8},2^{8}) (28,28)

实际上,对于现在的机器,大部分的值和上面的默认值不一样,
我们可以使用下面的js方法获取不同精度的描述信息:

getShaderPrecisionFormat(shaderType, precisionType)
  • shaderType:表示着色器类型,可以是gl.FRAGMENT_SHADER或者gl.VERTEX_SHADER
  • precisionType:要查询的精度限定符类型,可以是:
    • gl.LOW_FLOAT
    • gl.MEDIUM_FLOAT
    • gl.HIGH_FLOAT
    • gl.LOW_INT
    • gl.MEDIUM_INT
    • gl.HIGH_INT
  • 返回值:如果成功,返回WebGLShaderPrecisionFormat对象的实例,如果失败,返回null,下面是一个具体的例子:
// 返回对象有三个值,表示精度和取值范围,一看就能明白
// 精度precision: 23
// rangeMax: 127
// rangeMin: 127
var precisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER,gl.MEDIUM_FLOAT);

对变量使用精度限定符有两种方式:

  • 直接在变量定义的前面添加精度限定符highp、mediump或者lowp
  • 给指定类型统一设置精度限定符
// 给float类型统一设置mediump
precision mediump float;// 给变量单独设置精度限定
mediump float a;
highp vec4 position;
lowp vec3 color;

默认值

  • 对于采样器,默认精度值都是lowp
  • 对于顶点着色器,int和float默认精度值都是highp
  • 对于片元着色器,int的默认精度值是mediump
  • 对于片元着色器,float没有默认精度值,所以我们需要在片元着色器的最前边设置float的默认精度,不然会导致编译错误。
    precision mediump float;
    

预处理

GLSL ES支持预处理,所谓的预处理就是在代码编译之前的处理过程

常用预处理指令

#if 条件表达式如果条件表达式为真,执行这里
#endif#ifdef 某宏如果定义了某宏,执行这里
#endif#ifndef 某宏如果没有定义某宏,执行这里
#endif// 定义宏
#define 宏名 宏内容// 取消定义宏
#undef 宏名// 使用#else
#define NUM 100
#if NUM==100如果NUM等于100,执行这里
#else否则执行这里
#endif

内置宏定义

  • GL_ES:在OpenGL ES 2.0中定义为1
  • GL_FRAGMENT_PRECISION_HIGH:片元着色器是否支持highp

可以使用下面的方式对片元着色器的float进行精度设置

#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#endif

设置版本

可以在着色器的顶部设置WEBGL的版本号

// 100表示设置WEBGL 1.00
#version 100

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/252453.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大模型上下文长度扩展】FlashAttention:高效注意力计算的新纪元

FlashAttention:高效注意力计算的新纪元 核心思想核心操作融合,减少高内存读写成本分块计算(Tiling),避免存储一次性整个矩阵块稀疏注意力,处理长序列时的效率问题利用快速 SRAM,处理内存与计算…

二分查找------蓝桥杯

题目描述&#xff1a; 请实现无重复数字的升序数组的二分查找 给定一个元素升序的、无重复数字的整型数组 nums 和一个目标值 target&#xff0c;写一个函数搜索 nums 中的target&#xff0c;如果目标值存在返回下标 (下标从0 开始)&#xff0c;否则返回-1 数据范围: 0 < l…

【Java 数据结构】反射

反射 1 定义2 用途(了解)3 反射基本信息4 反射相关的类&#xff08;重要&#xff09;4.1 Class类(反射机制的起源 )4.1.1 Class类中的相关方法(方法的使用方法在后边的示例当中) 4.2 反射示例4.2.1 获得Class对象的三种方式4.2.2 反射的使用 5、反射优点和缺点 1 定义 Java的反…

网络编程套接字

目录 本节重点一、预备知识1.1 理解源IP地址和目的IP地址1.2 认识端口号1.3 理解 "端口号" 和 "进程ID"1.4 理解源端口号和目的端口号1.5 认识TCP协议1.6 认识UDP协议1.7 网络字节序 二、socket编程接口2.1 socket常见的API2.2 sockaddr结构2.3 in_addr结构…

SpringBoot集成axis发布WebService服务

文章目录 1、使用maven-web项目生成server-config.wsdd文件1.1、新建maven-web项目1.1.1、新建项目1.1.2、添加依赖 1.2、编写服务接口和实现类1.2.1、OrderService接口1.2.2、OrderServiceImpl实现类 1.3、配置deploy.wsdd文件deploy.wsdd文件 1.4、配置tomcat1.4.1、配置tomc…

MySQL数据库练习【一】

MySQL数据库练习【一】 一、建库建表-数据准备二、习题2.1. 查询部门编号为30的部门的员工详细信息2.2.查询从事clerk工作的员工的编号、姓名以及其部门号2.3.查询奖金多于基本工资的员工的信息、查询奖金小于基本工资的员工的信息2.4.查询奖金多于基本工资60%的员工的信息2.5.…

宠物空气净化器适合养猫家庭吗?除猫毛好的猫用空气净化器推荐

宠物掉毛是一个普遍存在的问题&#xff0c;尤其在脱毛季节&#xff0c;毛发似乎无处不在。这给家中的小孩和老人带来了很多麻烦&#xff0c;他们容易流鼻涕、过敏等不适。此外&#xff0c;宠物有时还会不规矩地拉扯和撒尿&#xff0c;这股气味实在是难以忍受。家人们对宠物的存…

【DC渗透系列】DC-4靶场

主机发现 arp-scan -l┌──(root㉿kali)-[~] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:6b:ed:27, IPv4: 192.168.100.251 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.100.1 00:50:56:c0:00:08 …

掌握Go的加密技术:crypto/rsa库的高效使用指南

掌握Go的加密技术&#xff1a;crypto/rsa库的高效使用指南 引言crypto/rsa 库概览RSA 加密算法基本原理crypto/rsa 库的功能和应用 安装和基本设置在 Go 项目中引入 crypto/rsa 库基本环境设置和配置 密钥生成与管理生成 RSA 密钥对密钥存储和管理 加密和解密操作使用 RSA 加密…

Kafka零拷贝技术与传统数据复制次数比较

读Kafka技术书遇到困惑: "对比传统的数据复制和“零拷贝技术”这两种方案。假设有10个消费者&#xff0c;传统复制方式的数据复制次数是41040次&#xff0c;而“零拷贝技术”只需110 11次&#xff08;一次表示从磁盘复制到页面缓存&#xff0c;另外10次表示10个消费者各自…

加固平板电脑丨三防智能平板丨工业加固平板丨智能城市管理

随着智能城市的不断发展&#xff0c;人们对于城市管理的要求也在不断提高&#xff0c;这就需要高效、智能的城市管理平台来实现。而三防平板就是一款可以满足这一需求的智能设备。 三防平板是一种集防水、防尘、防摔于一体的智能平板电脑&#xff0c;它可以在复杂的环境下稳定运…

【EI会议征稿通知】第三届智能控制与应用技术国际学术会议(AICAT 2024)

第三届智能控制与应用技术国际学术会议&#xff08;AICAT 2024&#xff09; 2024 3rd International Symposium on Artificial Intelligence Control and Application Technology 2024年第三届智能控制与应用技术国际学术会议&#xff08;AICAT 2024&#xff09;定于2024年5月…

Leetcode24:两两交换链表中的节点

一、题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff…

[Linux 进程控制(二)] 写时拷贝 - 进程终止

文章目录 1、写时拷贝2、进程终止2.1 进程退出场景2.1.1 退出码2.1.2 错误码错误码 vs 退出码2.1.3 代码异常终止引入 2.2 进程常见退出方法2.2.1 exit函数2.2.2 _exit函数 本片我们主要来讲进程控制&#xff0c;讲之前我们先把写时拷贝理清&#xff0c;然后再开始讲进程控制。…

JAVA面试汇总总结更新中ing

本人面试积累面试题 多线程微服务JVMKAFKAMYSQLRedisSpringBoot/Spring 1.面向对象的三个特征 封装&#xff0c;继承&#xff0c;多态&#xff0c;有时候也会加上抽象。 2.多态的好处 允许不同类对象对同一消息做出响应&#xff0c;即同一消息可以根据发送对象的不同而采用多种…

软考21-上午题-数组、矩阵

数组&#xff1a;一组地址连续的空间。 数组是定长线性表在维数上的扩展&#xff0c;即&#xff0c;线性表中的元素又是一个线性表。 一、数组 数组的特点&#xff1a; 数组数目固定&#xff0c;一旦定义了数组结构&#xff0c;不再有元素个数的增减变化。因此&#xff0c;数…

C# Onnx GroundingDINO 开放世界目标检测

目录 介绍 效果 模型信息 项目 代码 下载 介绍 地址&#xff1a;https://github.com/IDEA-Research/GroundingDINO Official implementation of the paper "Grounding DINO: Marrying DINO with Grounded Pre-Training for Open-Set Object Detection" 效果 …

MATLAB矩阵的操作(第二部分)

师从清风 矩阵的创建方法 在MATLAB中&#xff0c;矩阵的创建方法主要有三种&#xff0c;分别是&#xff1a;直接输入法、函数创建法和导入本地文件中的数据。 直接输入法 输入矩阵时要以中括号“[ ]”作为标识符号&#xff0c;矩阵的所有元素必须都在中括号内。 矩阵的同行元…

openssl3.2 - use openssl cmd create ca and p12

文章目录 openssl3.2 - use openssl cmd create ca and p12概述笔记实验的openssl环境建立CA生成私钥和证书请求生成CA证书用CA签发应用证书用CA对应用证书进行签名将已经签名好的PEM证书封装为P12证书验证P12证书是否可用END openssl3.2 - use openssl cmd create ca and p12 …

Redis(三)(实战篇)

查漏补缺 1.spring 事务失效 有时候我们需要在某个 Service 类的某个方法中&#xff0c;调用另外一个事务方法&#xff0c;比如&#xff1a; Service public class UserService {Autowiredprivate UserMapper userMapper;public void add(UserModel userModel) {userMapper.…