GLSL ES 1.0

news2024/9/23 21:29:10

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.coloradmin.cn/o/1436448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

posix_memalign 与 malloc 对比

1. 原因原理 编程中的类型对齐问题主要是处于性能考虑,如果不做对齐,那么单个数据元素的访问很容易跨在多个时钟周期上,从而导致性能下降。 内建数据类型的对齐,是由编译器和C语言库的API实现中自动完成的,这对于用户是…

LeetCode-第876题-链表的中间结点

1.题目描述 给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。 2.样例描述 3.思路描述 创建两个快慢指针 slow , fast ,起始共同指向头节点,slow 每次走一步,fas…

LabVIEW双光子荧光显微成像系统开发

双光子显微成像是一种高级荧光显微技术,广泛用于生物学和医学研究,尤其是用于活体组织的深层成像。在双光子成像过程中,振镜(Galvo镜)扮演了非常关键的角色,它负责精确控制激光束在样本上的扫描路径。以下是…

leetcode9. 回文数|详细深入讲解算法

前往题目有 反转一半数字 思路 映入脑海的第一个想法是将数字转换为字符串,并检查字符串是否为回文。但是,这需要额外的非常量空间来创建问题描述中所不允许的字符串。 第二个想法是将数字本身反转,然后将反转后的数字与原始数字进行比较&…

总结:图像生成网络

1、最新的几款图像生成网络 eCNN 文献:Bahrami A, Karimian A, Fatemizadeh E, et al. A new deep convolutional neural network design with efficient learning capability: Application to CT image synthesis from MRI[J]. Medical physics, 2020, 47(10): 515…

EasyX图形库学习(一、窗口创建函数initgraph、背景颜色设置setbkcolor、图形绘制函数)

目录 一、easyX图形库基本介绍 1、easyX的原理 2、easyX的安装 3、easyX的颜色(RGB颜色模型) 颜色模型相关函数: 4、easyX的坐标 二、相关函数介绍: 绘图设备相关函数: 图形颜色及样式设置相关函数: 图形绘制相关函数: 文字输出相关…

ManageEngine推出云原生身份平台以解决劳动力IAM挑战

ManageEngine推出云原生身份平台以解决企业员工身份与访问管理(IAM)面临的挑战。该公司还为其本地身份治理和管理(IGA)解决方案添加了先进的安全功能。 IAM 内置通用目录可在企业应用程序之间集中管理用户身份,使用身…

如何使用Docker部署Nginx容器实现无公网ip远程访问本地服务

文章目录 1. 安装Docker2. 使用Docker拉取Nginx镜像3. 创建并启动Nginx容器4. 本地连接测试5. 公网远程访问本地Nginx5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 在开发人员的工作中,公网远程访问内网是其必备的技术需求之一。对于…

CSS:三列布局

三列布局是指左右两列定宽&#xff0c;中间自适应。最终效果如下&#xff1a; HTML&#xff1a; <div class"container"><div class"left"></div><div class"center"></div><div class"right">…

jquery生成多个滑块,并对每个滑块做处理

基础滑块可以参考上一篇 eval(newThree).map((item, index) > { <div id"${uniqueId}" data-value"${item.text}" class"slider2"></div>$(document).ready(function () {for (let i 0; i < sliders.length; i)…

HTTP1.1、HTTP2、HTTP3

HTTP1.1 HTTP/1.1 相比 HTTP/1.0 性能上的改进&#xff1a; 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。支持管道&#xff08;pipeline&#xff09;网络传输&#xff0c;只要第一个请求发出去了&#xff0c;不必等其回来&#xff0c;就可以发第二个请求出去&…

Linux 服务器安装maven

1、压缩文件下载Maven – Download Apache Maven 2、解压 tar -xvf apache-maven-3.8.4-bin.tar.gz 3、配置环境变量 在/etc/profile中保存Maven的环境变量&#xff1a; export M2_HOME/opt/server/apache-maven-3.5.4 export PATH$PATH:$M2_HOME/bin 4、通过source生效文件 so…

如何将图片转化为png格式?图片转格式的方法步骤

png图片格式是一种无损图片格式&#xff0c;大多的设计工作者接触的比较多&#xff0c;平时我们在截图或者抠图的时候也都是png图片&#xff0c;那么如何将其他图片格式转换成png呢&#xff1f;不如试试小编分享的这款图片在线处理工具&#xff0c;不用下载安装&#xff0c;打开…

Scrum敏捷开发管理全流程-敏捷管理工具

Leangoo领歌是款永久免费的专业的敏捷开发管理工具&#xff0c;提供端到端敏捷研发管理解决方案&#xff0c;涵盖敏捷需求管理、任务协同、进展跟踪、统计度量等。 Leangoo领歌上手快、实施成本低&#xff0c;可帮助企业快速落地敏捷&#xff0c;提质增效、缩短周期、加速创新。…

春节假期旅游景点开放吗?春节提前做好出游待办计划更省心

春节的脚步越来越近了&#xff0c;那颗期待已久的心早已飞向了远方的风景。八天的小长假&#xff0c;对于很多人来说&#xff0c;是一次难得的出游机会。春节旅游&#xff0c;不仅可以欣赏到各地的美景&#xff0c;还能感受到浓浓的年味和不同的文化风情。 想象一下&#xff0…

​​​​​​​CleanMyMac X有什么优势?到底好不好用?

当你的Mac开始变得缓慢或者存储空间告急时&#xff0c;这通常是一个清理磁盘空间的信号。无论是工作文件、个人照片、还是各种应用程序&#xff0c;随着时间的推移&#xff0c;它们都可能在你的硬盘上积累了大量数据。有效地管理这些文件不仅可以提高你的工作效率&#xff0c;还…

Spring 多平台配置文件

前言 实际⼯作中,开发环境,测试环境以及⽣产环境的配置都是不⼀样的&#xff0c;⽐如 mysql 的⽤户名和密码&#xff0c; 我们可以针对不同的环境,设置不同的配置 详情 针对不同平台创建不同的配置⽂件,要求名字为 application-XXX.yml 或者 application-XXX.properties 以下以…

探索设计模式的魅力:设计之美-揭秘设计模式、原则与UML的魔法

设计模式专栏&#xff1a;http://t.csdnimg.cn/U54zu 目录 一、引言 二、设计模式与设计原则 设计模式 设计原则 三、面向对象设计原则 四、UML&#xff08;统一建模语言&#xff09; 4.1 UML是什么 UML是一种语言 UML是一种建模语言 UML是一种图形化语言 4.2 UML有什么 4.…

【SpringMVC】Nice! 终于有人把SpringMVC讲明白了!

1. 前言 在学习到Spring MVC的框架时&#xff0c;我看到了一篇非常好的文章&#xff0c;SpringMVC【入门篇】 - 知乎 (zhihu.com)因为我觉得这篇文章在有些地方讲的比较通俗易懂&#xff0c;而且不失专业&#xff0c;为了让初学者能够很好的理解Spring MVC&#xff0c;做到真正…

蓝桥杯嵌入式第8届真题(完成) STM32G431

蓝桥杯嵌入式第8届真题(完成) STM32G431 题目 分析和代码 对比第六届和第七届&#xff0c;这届的题目在逻辑思维上确实要麻烦不少&#xff0c;可以从题目看出&#xff0c;这届题目对时间顺序的要求很严格&#xff0c;所以就可以使用状态机的思想来编程&#xff0c;拿到类似题…