Shader 基础使用(二) --- surface Shader

时间:2022-06-28 10:18:02

基本数据类型

float 单个浮点数 (32位浮点数)
float2 两个浮点数 相当于 Vector2 (32位浮点数)
float3 三个浮点数 相当于 Vector3 (32位浮点数)
float4 四个浮点数 相当于 Vector4 (32位浮点数)
half half2 half3 half4 和float一样 只不过它是16位浮点数
int 整型 (32位整型)
fixed fixed2 fixed3 fixed4 和float一样 只不过它是12位浮点数
bool bool类型
sampler2D 纹理对象
string 字符串类型

表面着色器主要是渲染像素的 涉及到输入和输出

1. input saturate 
float2
--> uv_MainTex
--> uv纹理贴图
--> 命名方式必须为uv + 贴图变量名
float3
--> viewDir(视图方向)
-->worldPos(世界坐标位置)
float4
--> screenPos(屏幕空间位置)
-->color:COLOR(语义绑定 每个顶点的内插值颜色)
2.SurfaceOutput
half3
--> Albedo(反射值,即颜色纹理rgb)
-->Normal(法线,法向量)
-->Emission(自发光颜色)
half
-->Specular(镜面反射度)
-->Gloss(光泽度)
-->Alpha(透明度)

CG语言的编写规则

CGPROGRAM ——- CG语言开头
#pragma surface surf Lambert —– #pragma -> 预编译指令|surface -> 告诉编译器我的着色器类型(三种surface|vertex|fragment)|surf-> 着色器对应的函数名称|Lambert -> 光照模型(Lambert兰伯特光照模型)
//两个参数输入,输出 就是这个格式 不用改变
void surf(Input IN,inout SurfaceOutput o)
{
//在这里写我们的着色器代码
}
ENDCG ——- CG语言结尾

CG常用函数

1.UnpackNormal
传入的参数是fixed4 返回的是fixed3 也就是传入值对应的 法线
2.saturate
限制值的函数 限制值的范围为 0 - 1
3.dot
点乘的函数
4.tex2D
通过uv查找纹理的每个顶点的颜色值(也就是设置纹理贴图,传入参数是uv纹理)

应用案例
Shader 基础使用(二) --- surface Shader
直接上代码来看一下具体的实现

  • 最简单的实现单一主颜色/添加纹理贴图
Shader "SurfaceShader/SurfaceShader_001" {
Properties
{
_MainColor("主颜色",Color) = (1,0,0,1)
_MainTex("贴图",2D) = ""{}
}

SubShader
{
//表面着色器不需要Pass通道
//使用的是CG语言进行编写
CGPROGRAM
#pragma surface surf Lambert alpha
struct Input
{
float4 color:COLOR;
float2 uv_MainTex;
};

fixed4 _MainColor;
sampler2D _MainTex;

void surf(Input IN , inout SurfaceOutput o)
{
o.Albedo = _MainColor.rgb;
o.Alpha = _MainColor.a;
o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb;
}
ENDCG
}
}
  • 为了让其具有立体效果,我们需要用到法线题图,接下来写一下法线贴图
Shader "SurfaceShader/SurfaceShader_002" {
Properties
{
_MainTex("纹理贴图",2D) = ""{} //主纹理
_BumpMap("法线贴图",2D) = ""{} //与之对应的法线贴图
_MainColor("颜色",Color) = (1,1,1,1)
}

SubShader
{
//表面着色器不需要Pass通道
//使用的是CG语言进行编写
CGPROGRAM
#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
float2 uv_BumpMap;
};
sampler2D _MainTex;
sampler2D _BumpMap;
fixed4 _MainColor;
void surf(Input IN , inout SurfaceOutput o)
{
o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb; //首先设置纹理
o.Normal = UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap)); //设置法线
O.Albedo += _MainColor.rgb; //颜色与纹理融合 (加法融合会亮)
}
ENDCG
}
}
  • 边缘发光—小算法
Shader "SurfaceShader/SurfaceShader_003" {
Properties
{
_MainTex("纹理贴图",2D) = ""{} //主纹理
_BumpMap("法线贴图",2D) = ""{} //与之对应的法线贴图
_RimColor("边缘发光颜色",Color) = (1,1,1,1)
_RimPower("边缘发光强度",Range(0,0.5)) = 0.5
}

SubShader
{
//表面着色器不需要Pass通道
//使用的是CG语言进行编写
CGPROGRAM
#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
float2 uv_BumpMap;
float3 viewDir;//视图方向
};
//声明四个变量
sampler2D _MainTex;
sampler2D _BumpMap;
fixed4 _RimColor;
fixed _RimPower;
void surf(Input IN , inout SurfaceOutput o)
{
o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb; //首先设置纹理
o.Normal = UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap)); //设置法向量
//将视图方向和法线做一个点乘
//然后限制取值范围为0-1
//然后用一减一下将值变为大到小
fixed rim = 1 - saturate(dot(normalize(IN.viewDir),o.Normal)) ;
//pow 指数函数 下面是自发光的强度 也是边缘发光小算法
o.Emission = _RimColor.rgb * pow(rim,1 - _RimPower);
}
ENDCG
}
}
  • 在上面的基础上添加细节纹理
Shader "SurfaceShader/SurfaceShader_004" {
Properties
{
_MainTex("纹理贴图",2D) = ""{}
_BumpMap("法线贴图",2D) = ""{}
_DetailTex("细节纹理"2D) = ""{} //细节纹理
_RimColor("边缘发光颜色",Color) = (1,1,1,1)
_RimPower("边缘发光强度",Range(0,0.5)) = 0.5
}

SubShader
{
CGPROGRAM
#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
float2 uv_BumpMap;
float2 uv_DetailTex; //设置细节纹理uv
float3 viewDir;
};
sampler2D _MainTex;
sampler2D _BumpMap;
sampler2D _DetailTex; //声明细节纹理变量
fixed4 _RimColor;
fixed _RimPower;
void surf(Input IN , inout SurfaceOutput o)
{
o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb;
o.Albedo *= tex2D(_DetailTex,IN.uv_DetailTex).rgb;//添加细节纹理
o.Normal = UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap));
fixed rim = 1 - saturate(dot(normalize(IN.viewDir),o.Normal)) ;
o.Emission = _RimColor.rgb * pow(rim,1 - _RimPower);
}
ENDCG
}
}

表面着色器就简单介绍这么多,在这里介绍的都是最基本的使用,适合初学者,如果大家想要深入研究,遇到问题的可以评论留言,我会第一时间回复大家的问题,帮助大家解决,希望可以帮助到大家,谢谢