[Unity 学习] - 进阶篇 - 基础渲染系列(二)游戏开发的画笔——着色器
本文并非原创,只是本人的学习记录,原文是由放牛的星星老师翻译Catlike系列教程
链接: https://zhuanlan.zhihu.com/p/138230081
文章目录
- [Unity 学习] - 进阶篇 - 基础渲染系列(二)游戏开发的画笔——着色器
- 1 构建场景
- 1.1 剥离
- 2 从物体到图像
1 构建场景
创建一个默认场景,自带一个相机和一个定向光,创建一个Sphere,放置远点,摄像机放置前方。
这个简单的场景已经发生了许多复杂的渲染,我们需要将其一步步剥离出来
1.1 剥离
剥离前我们需要知道这个场景中有哪些东西
在Hierarchy栏中我们可以看到场景中有一个主摄像机(Main Camera), 一个环境光(Derectional Light),还有我们刚刚创建的球体(Sphere)。
事实上还有没有在Hierarchy中显示出的东西,比如说天空盒(Skybox)
打开场景的照明设置我们可以看到场景中有一个默认的Skybox
当我们使用天空盒时,会将天空盒作用于场景背景,环境照明和反射。我们将它删掉。因为它对灯光的影响很大。
没有的天空盒时,我们会在Scene中看到背景变为灰色,Sphere颜色会变得更暗,这是因为没有环境光反射了。但神奇的是我们在Game窗口中会看到背景变为蓝色,原因是摄像机自定义了背景色,默认情况下回渲染天空盒,但是当我们把天空盒删除后就会渲染原色。
PS: 这里拍的alpha的值是5,但是事实上作为背景色没有任何影响,在不同的版本也不同,我所用Unity 2019.3.0版本的默认背景色alpha == 0,
现在我们关掉灯光,看一下在全黑的情况的,物体是什么样子的。
2 从物体到图像
创建一个Shader
这里偷个懒,将整个Shader所有内容都写到一个脚本里面了
Shader "Unlit/UnlitS"
{
// Shader 语法结构
// Propertise 定义我们传入的数据
Properties
{
// [变量名]("监视面板名",类型)=值
// 四个值
_Color ("Color",Color) = (1,1,1,1) // r,g,b,a
_Vector ("Vector",Vector) = (0,0,0,0) // x,y,z,w
// 贴图类型
_MainTex ("Texture", 2D) = "white" {}
_BumpTex ("Bump", 2D) = "bump" {} // bump为法线贴图为空的特殊默认值
_CubeTex ("Cube", Cube) = "white" {} // Cub类型,常用来做环境球,采样值是三维向量
// 浮点类型
_Value ("value",float ) = 0.5
_RangeValue("RangeValue",Range(0,1)) = 0.5
}
// SubShader 是给GPU运行的程序
// 一个Shader中可以有多个SubShader,但是只执行第一个Shader
SubShader
{
// 定义该次渲染类型和队列位置
Tags { "RenderType"="Opaque" }
LOD 100 // 你的贴图在这个距离外开始启用LOD
// 可以编写多个Pass,但每个都会被依次执行
// 比如灯光编写一个Pass,阴影编写一个Pass
Pass
{
CGPROGRAM // CGPROGRAM ENDCG 在这个范围内编写CG语言
// 定义两个函数:顶点函数,片元函数
// 可以理解为有两个入口函数
// 顶点函数,Mesh需要渲染的每个像素执行一次
#pragma vertex vert
#pragma fragment frag
// make fog work
// Unity内置宏,方便我们生成雾色
#pragma multi_compile_fog
// 引用外部文件
#include "UnityCG.cginc"
// 将Properties中定义的变量进行绑定,这样GPU才会找到对应的数据
sampler2D _MainTex;
float4 _MainTex_ST;
// appdata为传递给顶点函数的结构体(a2v)
// appdata中定义的属性来源为Mesh网格信息
// appdata中的所有属性都是针对当前渲染的顶点
struct appdata
{
// 定义方式: [类型名][变量名]:[标识符]
float4 vertex : POSITION; //vertex对应的位置信息
float3 normal : NORMAL; // normal对应法线信息
fixed4 color : Color; // color对应顶点颜色
float2 uv : TEXCOORD0; // uv对应uv信息
};
// v2f为顶点函数的返回类型
// 顶点函数执行完以后会将返回值传入到片元函数
// 这里的值需要定义,在订点函数中间进行赋值
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
// 顶点函数
v2f vert (appdata v)
{
v2f o;
// 对顶点进行空间变换,转移到摄像机的投影空间中
o.vertex = UnityObjectToClipPos(v.vertex);
// 对uv进行运算和赋值
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//之前定义的雾的宏方法
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
// 片元函数 传入v2f,即顶点函数返回的值,像素函数
// 返回值是一个fixed4,说明我们返回的是一个颜色值,也就是一个像素
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
// 定义一个像素,通过tex2D对贴图对应位置进行采样
fixed4 col = tex2D(_MainTex, i.uv);
// apply fog
// 雾定义的宏方法对颜色进行加工并返回
UNITY_APPLY_FOG(i.fogCoord, col);
return col; // 将这个像素返回到屏幕
}
ENDCG
}
}
}
需要注意的是在Properties设置的属性可以在着色器检查器中查看属性