《 Unity Shader 入门精要》 第3章 Unity Shader 基础

news2024/11/26 4:22:31

第3章 Unity Shader 基础

3.1 Unity Shader 概述

材质与 Unity Shader

在 Unity 中我们通常需要将材质(Material) 和 Unity Shader 配合使用,常见流程如下:

  1. 创建一个材质
  2. 创建一个 Unity Shader, 并将它赋给材质
  3. 将材质赋给要渲染的对象
  4. 在材质面板调整 Unity Shader 的属性,以得到满意的效果。

在这里插入图片描述
Unity 中的材质需要结合 GameObject 的 Mesh 或者 Particle Systems 组件来工作,它决定了我们的游戏对象看起来是什么样子的。默认情况下,一个新建的材质将使用 Unity 内置的 Standard Shader, 这是一种基于物理渲染的着色器。
我们把 Unity 中的 Shader 文件统称为 Unity Shader,其与我们之前提到的渲染管线中的 Shader 有所不同。

3.2 Unity Shader 的基础: ShaderLab

什么是 ShaderLab?

Unity Shader 是 Unity 为开发者提供的高层级的渲染抽象层,Unity 希望通过这种方式来让开发者更加轻松地控制渲染。
在这里插入图片描述
所有的 Unity Shader 都是使用 ShaderLab 来编写的,ShaderLab 是 Unity 提供的编写 Unity Shader 的一种说明性语言。它使用一种嵌套在花括号内部的语义(syntax)来描述一个 Unity Shader 文件的结构。从设计上,ShaderLab 类似于 CgFX 和 Direct#d Effects 语言,它们都定义要显示一个材质的所有东西,而不仅仅是着色器代码
一个 Unity Shader 的基础结构如下所示:

Shader "ShaderName"{
	Properties{
		// 定义属性
	}
	SubShader {
		// 显卡 A 使用的子着色器
	}
	SubShader {
		// 显卡 B 使用的子着色器
	}
	Fallback "VertexLit"
}

Unity 会根据平台将 Unity Shader 编译成真正的代码和 shader 文件,而开发者只需要和 Unity Shader 打交道即可。

3.3 Unity Shader 的结构

名字

每个 Unity Shader 文件的第一行都需要通过 Shader 语义来制定该 Unity Shader 的名字:

Shader "Custom/MyShader" {}

Properties

Properties 语义块中包含了一系列的属性,这些**属性会出现在材质面板中。**Properties 语义块的定义通常如下:

Properties {
	Name ("display name", PropertyType) = DefaultValue
	Name ("display name", PropertyType) = DefaultValue
	...
}
  • 名字(Name)用于我们在 Shader 代码中访问使用
  • 显示的名字(display name)则是显示在材质面板上的名字
  • 另外我们需要为每个属性指定他的类型(PropertyType),我们还需要为每个属性设置一个默认值

在这里插入图片描述

Unity 允许我们重载默认的材质编辑面板,以提供更多自定义的数据类型,具体可参考Customer Shader GUI一文。

重量级成员 SubShader

每一个Unity Shader文件可以包含多个 SubShader 语义块,但最少要有一个。当Unity需要加载这个 Unity Shader 时,Unity 会扫描所有的 SubShader 语义块,然后选择第一个能够在目标平台上运行的 SubShader。如果都不支持的话,Unity 就会使用Fallback 语义指定的 Unity Shader。
SubShader语义块包含的定义通常如下:

SubShader {
	//可选的
	[Tags]
	
	//可选的
	[RenderSetup]
	
	Pass {}
	// Other Passes
}

标签(Tag)和渲染状态(RenderSetup)可以在 SubShader 中设置,也可以在 Pass 中设置,如果在 SubShader 中设置,则会对所有 Pass 生效,在 Pass 中设置则只对该 Pass 生效。
每个 Pass 定义了一次完整的渲染流程,如果 Pass 数目过多,往往会造成渲染性能下降,因此我们应尽量使用最小数目的 Pass。

RenderSetup

ShaderLab 提供了一系列渲染状态的设置指令,这些指令可以设置显卡的各种状态。
在这里插入图片描述

Tags

SubShader 的标签(Tags)是一个键值对,它的键和值都是字符串,它们是 SubShader 和渲染引擎之间的沟通桥梁,用于控制 Unity 怎样以及何时去渲染一个对象。
在这里插入图片描述

Pass 语义块

Pass 语义块包含的语义如下:

Pass {
	[Name]
	[Tags]
	[RenderSetup]
	// Other Code
}

首先我们可以在 Pass 中定义名称:

Name "MyPassName"

通过这个名称,我们可以在其他 Shader 中直接引用该 Pass:

UsePass "MyShader/MYPASSNAME"

需要注意的是,由于Unity内部会把所有 Pass 的名称转换成大写字母的表示,因此在使用 UsePass 命令时必须使用大写形式的名字。

3.4 Unity Shader 的形式

Unity Shader 支持三种方式:表面着色器(Surface Shader)顶点/片元着色器(Vertex/Fragment Shader)固定函数着色器(Fixed Function Shader)

表面着色器

表面着色器(Surface Shader)是 Unity 自己创建的一种着色器类型,其是 Unity 对顶点/片元着色器的更高一层的抽象,它存在的价值在于,Unity 为我们处理了很多光照细节,使得我们不再需要操心这些“烦人的事情”。Unity 最后会将表面着色器转换为对应的顶点/片元着色器。
一个简单的表面着色器代码示例如下:

Shader "MyShader/Surface"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf Lambert

        struct Input
        {
            float4 color : COLOR;
        };

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            o.Albedo = 1;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

表面着色器被定义在 SubShader 语义块(而非 Pass 语义块)中的 CGPROGRAM
ENDCG 之间。原因是,表面着色器不需要开发者关心使用多少个 Pass、每个 Pass 如何渲染等问题,Unity 会在背后为我们做好这些事情。

顶点/片元着色器

在Unity中我们可以使用 Cg/HLSL语言来编写顶点/片元着色器(Vertex/Fragment Shader)。它们更加复杂,但灵活性也更高。

Shader "MyShader/VertexFragment Shader"
{
    SubShader
    {
        Pass {
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag

            float4 vert(float4 v : POSITION) : SV_POSITION {
                return UnityObjectToClipPos(v);
            }

            fixed4 frag() : SV_Target {
                return fixed4(0.0, 0.0, 0.0, 1.0);
            }

            ENDCG
        }
    }
    FallBack "Diffuse"
}

和表面着色器类似,顶点/片元着色器的代码也需要定义在 CGPROGRAM 和 ENDCG
之间,但不同的是,顶点/片元着色器是写在 Pass 语义块内,而非 SubShader 内的。原因是我们需要自己定义每个 Pass 需要使用的 Shader 代码,虽然我们可能需要编写更多的代码,但带来的好处是灵活性很高。

固定函数着色器

对于一些不支持可编程渲染管线的较旧的设备,我们需要使用固定函数着色器(Fixed Function Shader)来完成渲染,这些着色器往往只完成一些简单的效果。

Shader "Tutorial/Basic" {
    Properties {
        _Color ("Main Color", Color) = (1,0.5,0.5,1)
    }
    SubShader {
        Pass {
            Material {
                Diffuse [_Color]
            }
            Lighting On
        }
    }
}

固定函数着色器的代码被定义在 Pass 语义块中,这些代码完全使用 ShaderLab 的语法来编写,而非使用 Cg/HLSL。
由于现在绝大多数 GPU 都支持可编程的渲染管线,这种固定管线的编程方式已经逐渐被抛弃。实际上,在 Unity 5.2 中,所有固定函数着色器都会在背后被 Unity 编译成对应的顶点/片元着色器,因此真正意义上的固定函数着色器已经不存在了。

选择何种 Unity Shader

  • 如果光源数量较多,可以选择表面着色器,但需要小心它在移动平台的性能表现
  • 如果光源数量较少,则使用顶点/片元着色器是更好的选择
  • 最重要的是,如果你有很多自定义的渲染效果,那么请选择顶点/片元着色器
  • 除非你有明确的要求必须使用固定函数着色器,否则不要使用它

答疑

我可以用 GLSL 来写吗

如果你坚持使用 GLSL 来写而不是 Cg/HLSL,那么你发布的平台就只有 Mac OS X、OpenGL ES 2.0 或者Linux,而对于 PC、Xbox 360 这样的仅支持 DirectX 的平台来说,你就放弃它们了。

扩展阅读

  • Unity Shader 官方文档:https://docs.unity3d.com/Manual/SL-Reference.html
  • NVIDIA Cg 文档:https://developer.download.nvidia.com/cg/index_stdlib.html
  • NVIDIA Cg 教程:https://developer.download.nvidia.com/CgTutorial/cg_tutorial_chapter01.html

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

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

相关文章

Android View类

布局定义了应用中的界面结构(例如 Activity 的界面结构)。布局中的所有元素均使用 View 和 ViewGroup 对象的层次结构进行构建。View 通常用于绘制用户可看到并与之交互的内容。ViewGroup 则是不可见的容器,用于定义 View 和其他 ViewGroup 对…

AppScan自定义扫描策略,扫描针对性漏洞

系列文章 AppScan介绍和安装 AppScan 扫描web应用程序 AppScan被动手动探索扫描 AppScan绕过登录验证码深入扫描 第五节-AppScan自定义扫描策略,扫描针对性漏洞 AppScan安全扫描往往速度是很慢的,有些场景下他的扫描项目又不是我们需要的,…

如何实现六轴机械臂的逆解计算?

1. 机械臂运动学介绍 机械臂运动学 机器人运动学就是根据末端执行器与所选参考坐标系之间的几何关系,确定末端执行器的空间位置和姿态与各关节变量之间的数学关系。包括正运动学(Forward Kinematics)和逆运动学(Inverse Kinemati…

渔业养殖远程监控系统解决方案

传统的水产养殖依靠养殖者的经验进行观察,信息不准确,调控不及时,养殖规模扩大难,人工成本高。除此之外传统水产养殖以个户居多,生产管理方式粗放,个体生产能力不足,养殖产品的品质难以保障。 …

AppScan扫描报告

系列文章 AppScan介绍和安装 AppScan 扫描web应用程序 AppScan被动手动探索扫描 AppScan绕过登录验证码深入扫描 AppScan自定义扫描策略,扫描针对性漏洞 第六节-AppScan扫描报告 1.加载扫描结果 1.点击【打开】 2.选择之前保存过的扫描结果 3.等待加载完成 …

RK35XX(3568) Android WSL ubuntu22.04 编译环境配置

前言:装Ubuntu真机操作是很流畅但是没什么软件,装Vmware虚拟机操作卡顿配置也麻烦。那不如试一试wsl吧,命令行操作,流程又快捷wsl简介:适用于 Linux 的 Windows 子系统可让开发人员按原样运行 GNU/Linux 环境 - 包括大…

JAVA面试(如何进行有效面试)

1、什么是面试它是一种面试人与求职者之间相互交流信息的有目的的会谈。它使招聘方和受聘方都能得到充分的信息,以在招聘中作出正确的决定。面试是一个双方彼此考量和认知的过程。2、面试的目标从求职者那里获取与个人行为、工作有关的信息,以确定求职者…

c语言数组复习

1、一维数组 ----------&#xff08;1&#xff09;、键盘输入 10 个数&#xff0c;求最大值和最小值&#xff08;最简单的方法&#xff09; ----------&#xff08;2&#xff09;、数组的逆置 #include<stdio.h> void test01() {int arr[10] { 0 };int n sizeof(arr)…

【IoT】硬件选型:如何正确区分电子线的端子型号?

问题提出 笔者最近负责的一款重力传感器由于没有端子&#xff0c;需要在生产时自己压端子&#xff0c;这个时候就会涉及端子的选择。 端子介绍 一般来说&#xff0c;端子有多种不同的型号&#xff0c;在使用的时候&#xff0c;你必须要注意到每种型号之间的差别。 端子一般有XH…

权限管理---尚硅谷

1.项目基础 2.定义统一返回结果对象 3.Nodejs 4.前端内容编写 5.菜单详情 6.SpringSecurity权限管理 7.添加登录日志 8.操作日志 9.后端打包 10.前端打包 11.动态sql日期的判断 项目基础 定义统一返回结果对象定义全局统一返回结果类 import lombok.Data;/*** 全局统一返回结果…

小程序容器技术助力突破智能汽车瓶颈

作为一种综合系统&#xff0c;智能车辆集环境感知、规划决策、多等级辅助驾驶等功能于一体。近年来&#xff0c;智能车辆已经成为世界车辆工程领域研究的热点和汽车工业增长的新动力&#xff0c;很多发达国家都将其纳入到各自重点发展的智能交通系统当中。在共享经济兴起和汽车…

如何写好JS

本节课从实践维度解读在实际编码过程中何种类型的 JavaScript 代码称之为“好代码”&#xff0c;并从 JS 出发&#xff0c;总结其他语言编码可遵循的共性原则&#xff0c;由浅入深&#xff0c;其三大原则是&#xff1a; 各司其职——html&#xff0c;css&#xff0c;js分离组件…

通达信接口QQ是什么端口?

可以将通达信接口QQ视为使用通达信市场软件作为数据库&#xff0c;然后将信息整合为策略的前提&#xff0c;所有行为都是自动化的。通达信接口的优势在于交易策略是事先制定的。是否基于市场波动&#xff0c;不受个人情绪的影响&#xff0c;可以大大降低个人原因造成的错误。 …

[ACTF2020 新生赛]BackupFile

目录 信息收集 思路 构造payload 知识补充 信息收集 从题目来看应该是让扫描备份文件(backupfile) 进入页面就一句话 Try to find out source file! 先用dirbuster模糊扫描一下目录 常见的如下 index.phps index.php.swp index.php.swo index.php.php~ index.php.bak ind…

有哪些数据恢复软件?13个好用的数据恢复工具分享

个人编辑开发了此资源&#xff0c;以帮助购买者寻找最好的免费数据恢复软件来满足其组织的需求。选择合适的供应商和工具可能是一个复杂的过程&#xff0c;需要深入研究&#xff0c;而且往往不仅仅取决于工具及其技术能力。为了让您的搜索更轻松一些&#xff0c;我们在一个地方…

【C++】stack和queue的使用

文章目录Stackstack容器的定义方式:接口函数queuequeue容器的定义方式接口函数栈OJ题目最小栈栈的压入,弹出序列逆波兰表达式求值(后缀表达式)中缀表达式->后缀表达式用两个栈实现队列队列OJ题用队列实现栈使用两个队列实现栈使用一个队列实现栈二叉树的层序遍历I二叉树的层…

k8s之挂载本地磁盘到POD中

写在前面 本文一起看下如何挂载本地的磁盘到POD中。 1&#xff1a;都需要哪些API对象 现实世界中的存储设备有非常非常多的种类&#xff0c;如本文要分析的计算机磁盘&#xff0c;还包括NFS(一种网络磁盘存储协议)&#xff0c;Ceph&#xff08;一种分布式的文件存储系统&…

Web测试的各个测试点

1.什么是Web测试&#xff1f; Web测试测试Web或Web应用程序的潜在错误。它是在上线前对基于网络的应用程序进行完整的测试。 UI测试 功能测试 数据库测试 性能测试 兼容性测试 安全测试 自动化测试 2.WEB测试主要测试场景 1.UI测试 界面是否美观&#xff0c;风格、字体、…

【青训营】Go的并发编程

本文章整理自——字节跳动青年训练营&#xff08;第五届&#xff09;后端组 1.线程和协程 操作系统中有三个重要的概念&#xff0c;分别是进程、线程和协程。其中进程和线程的区别请移步操作系统专栏&#xff0c;现在主要叙述线程和协程的区别。 简单来说&#xff0c;协程又称…

看我们网络故障分析系统如何发现系统500报错

背景 汽车配件电子图册系统是某汽车集团的重要业务系统。业务部门反映&#xff0c;汽车配件电子图册调用图纸时&#xff0c;出现访问慢现象。 汽车集团总部已部署NetInside流量分析系统&#xff0c;使用流量分析系统提供实时和历史原始流量。本次分析重点针对汽车配件电子图册…