【Unity Shader入门精要 第3章】Unity Shader基础

1. Unity提供的四种shader模板

  • Standard Surface Shader:unity自己创建的shader类型,提供了基本的光照处理逻辑,使用者不需要自己实现vertext/fragment着色器,只要指定光照模型,unity会自动编译生成对应的vertext/fragment
  • shader Unlit Shader:一个不含光照处理的基础的vertext/fragment shader
  • Image Effect Shader:用于屏幕后处理效果的基础模板
  • Compute Shader:一种特殊的shader文件,与渲染过程本身无关,主要是为了利用GPU强大的并行计算能力进行快速计算

2. Unity Shader是什么

unity shader就是对渲染流水线中可编程或可配置部分进行实际控制的文件,这里面包括了两个语言的概念

  • ShaderLab
    unity提供的,用于描述shader文件本身的一种语言,可以理解为这种语言是与Unity引擎交互的,用来通知Unity引擎这个shader是谁、都包含哪些内容
  • Cg/HLSL/GLSL
    三种用于编写着色器代码的语言,是相对于通过汇编直接与GPU交互而产生的更易于理解和编写的高级语言,可以理解为Unity用这部分语言的代码通知显卡如何真正进行渲染
    UnityShader中可以使用这三种语言中的任意一种,只需要在shader文件中指明使用的类型即可,为了描述方便,无论实际使用的是哪种语言,后面的文章中都会笼统称之为“CG代码段”

3. Unity Shader的基础结构

Shader "PathA/PathB/.../ShaderName_1"
{Properties {}SubShader{}SubShader{}...FallBack "PathC/PathD/.../ShaderName_2"
}

名字

字符串指定shader路径和名字
路径部分决定了在材质面板下拉框中shader所在的层级位置

属性

PropertyName("DisplayName", PropertyType) = DefaultValue
  • PropertyName:属性名
  • DisplayName:面板显示名
  • PropertyType:属性类型
  • DefaultValue:默认值

常用的属性类型可以分成三大类:

  • 基本数值类
    包括Int, Float, Range
    默认值为一个具体的数值
_IntPro("IntPro", Int) = 1
_FloatPro("FloatPro", Float) = 1.0
_RangePro("RangePro", Range(0.0, 1.0)) = 0.5
  • 矢量类
    包括Vector 和Color
    默认值为一个四维矢量
_VecPro("VecPro", Vector) = (0, 0, 0, 1)
_ColorPro("ColorPro", Color) = (1, 1, 1, 1)
  • 纹理类
    包括2D, 3D, Cube
    默认值为字符串 + 花括号
    字符串可以填内置的纹理名(如"White" “Black” "Gray"等)或空字符串
_Tex2D("Tex2D", 2D) = "White"{}
_Tex3D("Tex3D", 3D) = ""{}
_TexCube("TexCube", Cube) = ""{}

注意:Properties{}是ShaderLab的语义,其作用是通知unity引擎当前shader中有这些属性,需要unity在面板上显示出来可以编辑。但是如果在着色器中要使用的话,还需要在CG代码块中声明变量

4. SubShader

一个SubShader可以理解为一个渲染方案
每个UnityShader中可以有多个SubShader,但至少要有一个
Unity会从上往下依次查找当前平台支持的第一个SubShader使用
如果没有找到可以使用的SubShader,会使用FallBack指定的Shader

SubShader的基本结构

SubShader
{Tags{}[Render Setup]Pass{}Pass{}...
}

Tags

当前SubShader的渲染标签,可选项,如果设置了Tag,会应用于当前SubShader下的所有Pass

Tags{"Tag1Name" = "Tag1Value" "Tag2Name" = "Tag2Value" ...}
Tag说明示例
Queue指定渲染队列“Queue” = “Transparent”
RenderType指定着色器类型,其实并没有什么实际作用,可以用来筛选shader,可以自己任意指定“RenderType” = “Opaque”
DisableBatching是否关闭合批“DisableBatching” = “True”
ForceNoShadowCasting关闭阴影“ForceNoShadowCasting” = “True”
IgnoreProjector不受Projector影响,比如在做透明度检测时使用“IgnoreProjector” = “True”
CanUseSpriteAtlas用于sprite“CanUseSpriteAtlas” = “True”
PreviewType材质在面板中的预览类型“PreviewType” = “Plane”

Render Setup

状态设置,可选项,用于对渲染流水线中的各种可配置项进行配置,如果配置了状态,会应用于当前SubShader下的所有Pass,但会被单个Pass中的设置覆盖

配置项说明示例
Cull剔除模式Cull Back/Cull Front/Cull Off
ZTest深度测试类型ZTest Greater/ZTest Less/ZTest Equal/ZTest GEqual/ZTest LEqual/ZTest NotEqual/ZTest Always
ZWrite深度写入ZWrite Off/ ZWrite On
Blend透明度混合因子Blend SrcAlpha OneMinusSrcAlpha
BlendOp透明度混合操作模式BlendOp Add

5. Pass

一个Pass对应着一个完整的渲染流程,当一个SubShader中配置了N个Pass时,就代表在这种渲染方案中,需要进行N遍渲染才能得到最终的渲染效果

Pass的基本结构

Pass
{Name ""Tags{}[Render Setup][CGCode]
}

Name

可以为Pass指定名字,方便在其他shader中使用之前已经写好的pass
在跨shader使用Pass的时候,需要通过shader名 + “/” + pass名的方式指定要使用的Pass
Pass的名字会被Unity转化为大写,因此在使用的时候,指定的Pass名字也要用大写,如“PathA/PathB/ShaderA/PASS_1”

Tags

当前Pass的渲染标签,Pass可以使用的Tag与SubShader使用的Tag不同,不会覆盖SubShader的标签,只是补充

Tag说明示例
LightMode指定渲染路径以及在渲染路径中的角色“LightMode” = “ForwardBase”
RequireOptions指定满足条件时才使用Pass,值为空格或分开的字符串“RequireOptions” = “SoftVegetation”

Render Setup

状态设置,可选项,对当前Pass的渲染流水线配置做单独针对性设置,会覆盖SubShader中的同类设置。可设置的内容也与上文SubShader中一样。

CG代码段

XXPROGRAM
#pragma vertex vertFunc
#pragma fragment fragFunc
#pragma ...
...fixed4 _ColorPro;
...struct a2v 
{...
};
struct v2f 
{...
};
...v2f vertFunc(a2v _input) 
{v2f _output;...return _output;
}...fixed4 fragFunc(v2f _input)
{...return (1, 1, 1, 1)
}ENDXX
  • 通过 XXPROGRAM 开启CG代码段,其中XX代表使用的语言,如CGPROGRAM,HLSLPROGRAM
  • 通过ENDXX关闭CG代码段,其中XX代表使用的语言,如ENDCG
  • 通过#pragma … 指定编译指令,如 #pragma vertext vertFunc 指定顶点着色器为verFunc,#pragma fragment fragFunc指定片元着色器为fragFunc
  • 通过类型和变量名声明变量,如果要声明的变量是使用Properties中定义的属性的值,则声明的变量名需要与Properties中定义的属性名一样,变量类型也需要跟属性的类型对应, 如 fixed4 _ColorPro; 就是声明了 _ColorPro 变量,且使用了上文Properties中定义的_ColorPro属性值
  • 通过struct定义自定义结构 实现定义的顶点着色器和片元着色器,如果要加入可选着色器
  • 也可以在CG代码段中加入可选着色器,与顶点/片元着色器方式一样

后面章节中会对CG代码段内的内容做更详细的介绍

6. 表面着色器

与普通的顶点/片元着色器不同,表面着色器直接在SubShader中定义(而非Pass中),也就是直接在SubShader中添加CG代码段
表面着色器除了指定着色器类型和名字外,还需要指定使用的光照模型,如 #pragma surface surfaceFunc Lambert 就是制定了表面着色器名字为surfaceFunc,且使用的光照模型为Lambert

表面着色器会被unity自动编译成普通的顶点/片元着色器,因此不需要返回值

SubSader
{Tags{"Queue" = "Transparent"}CGPROGRAM#pragma surface surfaceFunc Lambert;struct Input{float4 color : COLOR;}void surfaceFunc(Input _input, inout SurfaceOutput o){o.Albedo = 1;}ENDCG
}

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

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

相关文章

C语言 基本数据类型及大小

一、基本数据类型 1.整型int 整型的关键字是int,定义一个整型变量时,只需要用int来修饰即可。也分为短整型和长整型。 2.浮点型 浮点型又分单精度浮点型float和双精度浮点型double。 3.字符型char 前面的整型和浮点型都是用于存放数字。字符型&…

docker部署nginx并实现https

文章目录 docker部署nginx并实现https1、服务器环境2、安装docker3、准备证书4、准备nginx配置文件和dockerfile文件5、创建nginx镜像与容器6、验证访问 docker部署nginx并实现https 1、服务器环境 [rootliuyanfen12 ~]#systemctl stop firewalld [rootliuyanfen12 ~]#setenf…

【c++】继承学习(二):探索 C++ 中派生类的默认机制与静态成员共享

🔥个人主页:Quitecoder 🔥专栏:c笔记仓 目录 1.派生类的默认成员函数2.继承与友元3.继承与静态成员 朋友们大家好,本篇文章我们来学习继承的第二部分 1.派生类的默认成员函数 来看下面的类: class Person…

Django框架之模板层

一、模版语法 1、模版初识 (1)语法 {{ }}: 变量相关 {% %}: 逻辑相关 (2)变量 ① 传值 在Django的模板语言中按此语法使用: {{ 变量名 }}。 当模版引擎遇到一个变量,它将计算这个变量,然…

Delta lake with Java--分区表

今天尝试一下将昨天的数据操作建立的表换成分区表,参考Delta Lake Up and Running做法用分区表的方式来更新数据。还要比较一下分区表的查询与非分区表的查询,结果显示分区表的查询速度要比非分区表要快。直接上代码: import io.delta.table…

发表博客之:transformer 架构 推理时候运算流程详细讲解,以及变长推理支持,小白都可以看得懂,AI推理工程师必备技能!

文章目录 [发表博客之:transformer 架构 推理时候运算流程详细讲解,以及变长推理支持,小白都可以看得懂,AI推理工程师必备技能!](https://cyj666.blog.csdn.net/article/details/138439826)总结一下高性能变长推理 发表…

JAVA面试题--数据库基础

连接查询 1.左连接 (左外连接)以左表为基准进行查询,左表数据会全部显示出来,右表 如果和左表匹配 的数 据则显示相应字段的数据,如果不匹配,则显示为 NULL; 2.右连接 (右外连接)以右表为基准进行查询,右表数据会全部显示出来,右…

初识Vue-脚本架(如何创建vue项目并使用)

一、介绍vue脚本架 Vue 脚手架”通常指的是 Vue CLI,是一个官方提供的命令行工具,用于快速搭建 Vue 项目。Vue CLI 提供了一套标准化的项目模板和一系列的开发工具,使得创建、管理和部署 Vue 项目变得更加简单和高效。以下是 Vue CLI 的一些…

定点乘除法

目录 一、定点乘法 1.串行乘法器 2.并行乘法器 二、定点除法 1.笔算除法 2.机器除法 一、定点乘法 1.串行乘法器 1.符号位单独处理,两数的符号位按异或运算得到,而乘积的数值部分则是两个正数相乘之积。 2.过程 (1) 由乘…

持续总结中!2024年面试必问 100 道 Java基础面试题(二十八)

上一篇地址:持续总结中!2024年面试必问 100 道 Java基础面试题(二十七)-CSDN博客 五十五、Object类有哪些常用的方法? Java中的Object类是所有Java类的根类,它位于类继承层次结构的顶端。Object类提供了一…

「2024年」前端开发常用工具函数总结 TypeScript

前言 在前端开发中,工具函数是提高代码复用率、保持代码整洁和增加开发效率的关键。使用 TypeScript 编写工具函数不仅可以帮助开发者捕捉到更多的类型错误,还可以提供更清晰的代码注释和更智能的代码补全。下面是一些在 TypeScript 中常用的前端开发工…

在Django中实现多用户角色和权限管理的方法

在Django中实现多用户角色和权限管理可以通过以下步骤实现: 定义用户角色模型:首先,定义一个用户角色模型,该模型表示不同的用户角色,例如管理员、普通用户、编辑等。 from django.db import modelsclass Role(model…

移动构造函数是否标记noexcept对性能有重要影响

1. 移动构造标记noexcept时才会被正确调用 #include <iostream> #include <string> #include <vector>class Vehicle{ public:Vehicle(){std::cout << "Vehicle default-ctor called.\n";}Vehicle(const std::string& brand) : brand_(…

Java如何获取当前日期和时间?

Java如何获取当前日期和时间&#xff1f; 本文将为您介绍 Java 中关于日期和时间获取的方法&#xff0c;以及介绍 Java 8 中获取日期和时间的全新API。 1、 System.currentTimeMillis() 获取标准时间可以使用 System.currentTimeMillis() 方法来获取&#xff0c;此方法优势是…

Hadoop生态系统的核心组件探索

理解大数据和Hadoop的基本概念 当我们谈论“大数据”时&#xff0c;我们指的是那些因其体积、速度或多样性而难以使用传统数据处理软件有效管理的数据集。大数据可以来自多种来源&#xff0c;如社交媒体、传感器、视频监控、交易记录等&#xff0c;通常包含了TB&#xff08;太…

【算法】双指针思想

一、Leetcode27.移除元素 1.题目描述 给你一个数组 nums和一个值 val&#xff0c;你需要 [原地] 移除所有数值等于 val的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 [原地 ]修改输入数组。 元素的顺序可以…

【C语言】详解预处理

、 最好的时光&#xff0c;在路上;最好的生活&#xff0c;在别处。独自上路去看看这个世界&#xff0c;你终将与最好的自己相遇。&#x1f493;&#x1f493;&#x1f493; 目录 •✨说在前面 &#x1f34b;预定义符号 &#x1f34b; #define • &#x1f330;1.#define定义常…

ControlNet官方资源链接【ControlNet论文原文】【持续更新中~】

ControlNet官方资源链接 ControlNet论文原文&#xff1a;https://arxiv.org/abs/2302.05543ControlNet官方GitHub&#xff1a;https://github.com/lllyasviel/ControlNetControlNet 1.1官方GitHub&#xff1a;https://github.com/lllyasviel/ControlNet-v1-1-nightlyControlNe…

phpMyAdmin增加自定义IP登录教程

phpMyAdmin增加自定义IP登录教程 1、打开phpMyAdmin目录&#xff0c; 在此目录下是否有config.sample.inc.php文件&#xff0c;如果存在&#xff0c;那么将其改名为config.inc.php&#xff08;为避免修改失误所造成的损失&#xff0c;强烈建议先备份config.sample.inc.php文件…

4_C语言复杂表达式与指针高级应用

指针数组与数组指针 字面意思来理解指针数组与数组指针 指针数组的实质是一个数组&#xff0c; 这个数组中存储的内容全部是指针变量。 数组指针的实质是一个指针&#xff0c; 这个指针指向的是一个数组。 分析指针数组与数组指针的表达式 int * p[5]; 指针数组 int (*p)[5]…