[译]Unity3D Shader教程(二)HLSL

2023-12-20 17:08
文章标签 教程 shader unity3d hlsl

本文主要是介绍[译]Unity3D Shader教程(二)HLSL,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1 HLSL?
  • 2 Builtin Types
  • 3 Vector Values
  • 4 Matrix Values
  • 5 Textures
  • 6 Math
  • 7 Custom Types
  • 8 Variables
  • 9 Functions
  • 10 Control Flow
    • 10.1 if statements
    • 10.2 Loops


原文地址
Shader Tutorials by Ronja。


1 HLSL?

HLSL(High Level Shading Language,高级着色器语言)是Unity用来编写着色器的语言,其用来自定义逻辑并最终决定在屏幕上绘制什么内容。 HLSL是微软设计开发的,供Direct3D API使用的GPU语言。 严格来说,大多数 Unity Shader都是用 CG 编写。Cg是C for Graphics的缩写,Cg与 HLSL 共享大部分语法和功能,并在 2012 年被弃用,因此错误地将Unity Shader中的语言称为HLSL能帮助您在搜索引擎中找到更想要的结果。 理论上Unity 也支持编写GLSL(OpenGL Shading Language)着色器,这是为 OpenGL 设计的语言。因为HLSL有更多示例,并且Unity最终会将Shader将转换为导出平台的对应语言,所以Unity中,我们坚持使用HLSL来编写Shader。
其实上面这段没怎么说清楚为什么咱们用的是HLSL语言来编写Unity Shader。这里来解释一下,编写Shader的语言无非就三种,一是微软平台的HLSL语言,二是OpenGL平台的GLSL语言,三是NVIDA的Cg语言。Cg语言是真正意义上的跨平台着色器语言,即用Cg编写的语言既可以在微软的Direct3D上跑也可以在Open Gl上跑。但是由于Cg和DX9风格的HLSL从写法上说几乎是同一种语言,所以在Unity中HLSL和Cg是等价的。我们一般在CGPROGRAM和ENDCG代码片段中编写。
为了在 Unity 中学习着色器,我们建议您不要从这里开始您的编程之旅。着色器调试起来很麻烦,它们可以做的事情非常有限,而且在许多情况下,您必须朝着与大多数编程上下文略有不同的方向进行处理。 所以我们假设你知道类型、变量、类、方法、循环、if 语句等等的基本编程知识。

2 Builtin Types

内置类型。
fixed、half、float表示浮点数,int表示有符号的整型,uint表示无符号的整型。
在移动端的GPU 上,fixed的范围为-2~2之间的数字,精度为 1/256,half是 16 位浮点数,float是 32 位浮点数。 在PC端GPU 上,所有这些值都是 32 位浮点数,所以为了方便我们会到处使用float,但根据数据的大小选择对应的类型也是一种优化。
整型是只能包含整数值的数字,int 可以包含正值和负值,uint 只能包含正值,使用uint可以带来轻微的性能优势。
此外,还有一个简单的数据类型 bool(布尔值),它保存的值为真或假,因此我们可以将检查结果存储在其中。 如果您将布尔值与其他数字一起使用(例如将它们相加或相乘),它们的行为就像数字 0(如果它为假)或 1(如果它为真)。

3 Vector Values

向量。
我们可以在第2节中的内置类型后面添加一个数字(最大为4)来组成一个多维向量,如fixed4, float2 或 half3。我们向量来表示纹理坐标、颜色和位置。
当我们想访问向量中的某一个值时,如果此向量表示位置,我们依次使用 vector.x、vector.y、vector.z 和 vector.w;当向量表示颜色时 ,我们使用vector.r、vector.g、vector.b 和 vector .a。或者我们也可以这样:vector[2]([]中的2是索引值,是从0开始的,因此4维向量的 4 个值将是 0、1、2 和 3)。
如果我们想从一个向量中获取多个值并将它们放入另一个向量中,我们不必自己构造那个新向量,我们可以使用 Swizzling。 Swizzling 意味着在点之后写入多个向量子值。 如:
vector.xy - 仅获取向量的前 2 个值并将它们放入二维向量中。
vector.zyx - 获取向量的前 3 个值并颠倒它们的顺序。
vector.xxxx - 取向量的第一个值并构建一个全部是该值的 4维向量。

(Swizzling能够提高性能)

4 Matrix Values

矩阵。
像向量在一个方向上扩展基本类型一样,矩阵在两个方向上扩展它们。 它们的语法是将 number x number 附加到标量类型上。 如 float4x4、half3x2 甚至 bool2x4。可以通过像 matrix[3][2] 这样的方括号来访问矩阵的成员,第一个数字表示行,第二个数字表示列。 或者通过像 _m32 这样的访问器。 这钟访问器也可以用于 swizzling,如 matrix._m03_m13_m23 以获取最后一列的前 3 个值并将它们写入 3维 向量。 如果我们使用方括号版本并且只使用一对括号,我们将得到定义该行的向量,如matrix[3]表示第三行。
幸运的是,我们几乎从不需要访问矩阵中的值,所以没必要完全掌握它,如果某天你需要使用到矩阵钟的某个元素,再回过头来看看即可。

5 Textures

纹理。
Hlsl 也有描述纹理的类型。我们后面再讲。

6 Math

算数运算。
除了简单数学中的+ - * / 运算符和 逻辑运算符> < == != ! >= <= && 、|| ,hlsl 还内置了许多数学函数,如 abs、dot、lerp、pow、min、atan2 (支持的函数可以见这里)。
还有一些简写,如 += *= -= 和 /= ,它们修改一个变量,然后再次赋值给它自己,还有var++ 和 var- -,其从给定的变量中加或减 1。
标量类型和向量类型的乘法返回一个向量类型,它们的维数都与数字相乘。 所以 float2(2, 7) * 3 等于 float2(6, 21)。
另外,我们我们使用mul函数来实现矩阵与向量相乘以变换向量。矩阵和向量是具体是怎么计算的,这里不细说。

7 Custom Types

自定义类型。
除了内置类型,我们还可以添加我们自己的类型。 添加你自定义类型的语法是这样的(最后的分号很重要!):

struct typeName{float variable;float2 otherVariable;
};

理论上我们也可以使用 class 关键字,使用继承、成员函数甚至接口,但我从未在任何着色器中遇到过它们,所以我不会在这里解释,等它们出现时再说。 如果您确实想使用这些功能,则语法类似于 C++/C#。
与向量类型一样,我们使用来访问自定义类型的成员变量,例如 instance.variable 或 instance.otherVariable.x。

8 Variables

变量。
hlsl 中的所有数据类型都是值类型。 这意味着一旦我们拥有一个值,我们就可以更改它,而无需通过 new 或类似的方式创建它。
如果我们想创建向量类型,我们可以通过调用函数之类的类型来实现。 在这些情况下,参数类型中的子值数量之和必须与目标类型中的值数量相等。比如我们可以通过传入 4 个float或2 个float 2或一个float、一个float2 和另一个float或者仅一个float4来构建一个新的float4。 如我们可以这样构建我们自定义类型的变量:

typeName instance;
instance.variable = 3.14;
instance.otherVariable = float2(3, 1.4);

我们声明的变量可以在函数内部,在这种情况下,它们只能被该函数内部的其他部分访问,这些部分需晚于变量声明(就像在大多数编程语言中一样);也可以在函数之外,在这种情况下,它们可以被 从着色器中的所有函数访问,无论变量声明在哪儿(但通常在顶部声明它们,在函数上方以轻松找到它们)。

9 Functions

函数。(C#中称为方法)
hlsl 中的大多数函数都在全局范围内。 这意味着它们不属于任何数据类型,我们可以从任何地方调用它们。 它们可以接受多个(或没有)参数并返回一个值。 如果您的函数没有返回值,则必须将返回类型声明为 void。 典型的函数语法如下所示:

returnType functionName(argType arg1, otherArgType arg2){//do some stuff and calculate returnValuereturn returnValue;
}

要调用一个函数,我们只需写下函数名,后跟方括号和后缀中的参数。 如果有多个具有相同名称但参数类型不同的函数,hlsl 将自动找到适合我们调用它的参数的函数。如functionName(arg1, arg2)。

10 Control Flow

流程控制。
对于许多着色器来说,一个接一个执行一个命令就足够了,而不会遗漏或重复任何一个命令。 对于他们中的很多人来说,在两种代码路径之间进行选择也很重要。 众所周知,在着色器中使用控制流是有害的,尤其是在移动 GPU 上会影响您的性能,您应该使用诸如 step 之类的函数。 但是这种方法是完全错误的,因为step这些函数在它们内部其实也是使用了分支,使用它们反而会使你的代码更复杂和阅读。如果使用if能使你的代码更整洁,那么就可以使用它。
(“step不能提高效率”这观点我持保留意见,等考证后再说)

10.1 if statements

if语句。
如下面的例子,如果condition为真,则执行 do thing 块,否则执行 do other thing 块,两个代码块永远不会同时执行。

if(condition){//do thing
} else {//do other thing
}

其中, else是可选的。 条件周围的括号是强制性的。 如果你不使用花括号,该语句只会影响下一行(直到下一个分号,而不是下一个换行符),而不是之后的行。 条件可以是布尔值、数字(在这种情况下 0 为假,任何其他值包括负数为真)或返回两者之一的操作。 如果你有一个与你想要的相反的值(当你想执行一些代码时为假,否则为真),只需在它前面加上一个感叹号,就会翻转:真值变为假,假值变为真。如!flag。

10.2 Loops

循环。
控制哪些代码被执行,哪些不执行的另一种方式是循环。 While 循环是一种更简单的循环。 只要定义它们的条件不再为真,它们就会永久执行。 如果一开始就不是真的,它们根本不会被执行。 它们看起来像这样:

while(condition){//do things
}

重要的是,在 do things 中的某个地方您要讲条件改为true,否则循环while将永远运行,这很糟糕,甚至可能使您的整个编辑器崩溃。
另一种循环是 for 循环,它添加了一些语法糖来迭代和计数,它们是这样定义的。

for(beforeLoopLogic; condition; inLoopLogic){//do things
}

我们偶尔会遍历某个数组,变量索引从 0 到 maxValue-1 ,不那么令人困惑的版本如下:

for(uint index=0;index<maxValue;index++){//do things
}

此代码等效于使用 while 循环的代码:

uint index = 0;
while(index < maxValue){//do thingsindex++;
}

两个循环也支持关键字 break 和 continue。
在您的代码中使用 break 语句会使代码跳转到下一个循环的末尾。 这也将跳出无限的 while 循环。
使用 continue 语句会使循环跳转到循环的下一次迭代的开始。

博主本文链接

这篇关于[译]Unity3D Shader教程(二)HLSL的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

MySQL 安装配置超完整教程

《MySQL安装配置超完整教程》MySQL是一款广泛使用的开源关系型数据库管理系统(RDBMS),由瑞典MySQLAB公司开发,目前属于Oracle公司旗下产品,:本文主要介绍MySQL安装配置... 目录一、mysql 简介二、下载 MySQL三、安装 MySQL四、配置环境变量五、配置 MySQL5.1

MQTT SpringBoot整合实战教程

《MQTTSpringBoot整合实战教程》:本文主要介绍MQTTSpringBoot整合实战教程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录MQTT-SpringBoot创建简单 SpringBoot 项目导入必须依赖增加MQTT相关配置编写

在Java中基于Geotools对PostGIS数据库的空间查询实践教程

《在Java中基于Geotools对PostGIS数据库的空间查询实践教程》本文将深入探讨这一实践,从连接配置到复杂空间查询操作,包括点查询、区域范围查询以及空间关系判断等,全方位展示如何在Java环... 目录前言一、相关技术背景介绍1、评价对象AOI2、数据处理流程二、对AOI空间范围查询实践1、空间查

Logback在SpringBoot中的详细配置教程

《Logback在SpringBoot中的详细配置教程》SpringBoot默认会加载classpath下的logback-spring.xml(推荐)或logback.xml作为Logback的配置... 目录1. Logback 配置文件2. 基础配置示例3. 关键配置项说明Appender(日志输出器

Kali Linux安装实现教程(亲测有效)

《KaliLinux安装实现教程(亲测有效)》:本文主要介绍KaliLinux安装实现教程(亲测有效),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、下载二、安装总结一、下载1、点http://www.chinasem.cn击链接 Get Kali | Kal

Web技术与Nginx网站环境部署教程

《Web技术与Nginx网站环境部署教程》:本文主要介绍Web技术与Nginx网站环境部署教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Web基础1.域名系统DNS2.Hosts文件3.DNS4.域名注册二.网页与html1.网页概述2.HTML概述3.

spring security 超详细使用教程及如何接入springboot、前后端分离

《springsecurity超详细使用教程及如何接入springboot、前后端分离》SpringSecurity是一个强大且可扩展的框架,用于保护Java应用程序,尤其是基于Spring的应用... 目录1、准备工作1.1 引入依赖1.2 用户认证的配置1.3 基本的配置1.4 常用配置2、加密1. 密

WinForms中主要控件的详细使用教程

《WinForms中主要控件的详细使用教程》WinForms(WindowsForms)是Microsoft提供的用于构建Windows桌面应用程序的框架,它提供了丰富的控件集合,可以满足各种UI设计... 目录一、基础控件1. Button (按钮)2. Label (标签)3. TextBox (文本框

C#实现访问远程硬盘的图文教程

《C#实现访问远程硬盘的图文教程》在现实场景中,我们经常用到远程桌面功能,而在某些场景下,我们需要使用类似的远程硬盘功能,这样能非常方便地操作对方电脑磁盘的目录、以及传送文件,这次我们将给出一个完整的... 目录引言一. 远程硬盘功能展示二. 远程硬盘代码实现1. 底层业务通信实现2. UI 实现三. De

ubuntu20.0.4系统中安装Anaconda的超详细图文教程

《ubuntu20.0.4系统中安装Anaconda的超详细图文教程》:本文主要介绍了在Ubuntu系统中如何下载和安装Anaconda,提供了两种方法,详细内容请阅读本文,希望能对你有所帮助... 本文介绍了在Ubuntu系统中如何下载和安装Anaconda。提供了两种方法,包括通过网页手动下载和使用wg