版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ww1351646544/article/details/88633790
两个结构体
表面着色器支持最多自定义4种关键函数:
表面着色器:各种表面性制如反射率、法线等
光照函数:定义使用的光照模型
顶点修改函数:修改或传弟顶点属性
颜色修改函数:对最终的颜色进行修改
一个表面着色器需要两个结构体:
表面函数输入结构体Input 和 存储表面属性的结构休SurfaceOutput(或SurfaceOutputStandard和SurfaceOutputStandardSpecular)
Input结构体数据来源:
变量 | 描述 |
---|---|
float3 ViewDir | 视角方向,用于计算边缘光等 |
COLOR语义定义的float4 | 包含 了插值后的逐点颜色 |
float4 screenPos | 屏幕空间坐标,可用于反射或屏幕特效 |
float3 worldPos | 世界下的位置 |
float3 worldRefl | 世界空间下的反射方向,前提是没有修改表面法线o.Normal |
float3 worldRefl;INTERNAL_DATA | 如果改了表面法线o.Normal,要使用变量告诉Unity基于修改后的法线计算世界空间下的反射方向 |
float3 worldNormal | 世界空间的法线方向。前提是没有修改表面法线 o.Normall |
float3 worldNormal;INTERNAL_DATA | 如果改了表面法线o.Normal,要使用变量告诉Unity基于修改后的法线计算世界空间下的法线方向 |
我们并不需要自己计算这些变量,只要在Input中严格声明这些变量即可。
表面属性:SurfaceOutput:
有SurfaceOutput、SurfaceOutputStandard、SurfaceOutputStandardSpecular
这个提前声明好的,你挑你喜欢的就可以了。
struct SurfaceOutput{
fixed3 Albedo;
fixed3 Normal;
fixed3 Emission;
half Specular;
fixed Gloss;
fixed Alpha;
}
struct SurfaceOutputStandard{
fixed3 Albedo;
fixed3 Normal;
fixed3 Emission;
half Metallic;
half Smoothness;
half Occlusion;
fixed Alpha;
}
struct SurfaceOutputStandardSpecular{
fixed3 Albedo;
fixed3 Specular;
fixed3 Normal;
fixed3 Emission;
half Smoothness;
half Occlusion;
fixed Alpha;
}
简单的、非物理的光照模型包括Lambert和BlinnPhong这种通常使用SubfaceOutput如果 是基于物理的光照则使用后面两个。
着重讲一下SubfaceOutput:
- fixed3 Albedo:对光源的反射率。
- fixed3 Normal:表面法线方向。
- fixed3 Emission:自发光。
- half Specular:高光反射中的指数部分系数。
- fixed Gloss:高光反射中强度系数。
- fixed Alpha:透明通道。
表面着色器极大的减少了我们的工作,但它的问题是我们不知道它为什么会得到这样的结果。
例子:
这效果其实非常简单,即是顶点向法线方向扩张。
解释都在代码里:
Shader "Unity Shaders Book/Chapter 17/Normal Extrusion" {
Properties {
_ColorTint ("Color Tint", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_BumpMap ("Normalmap", 2D) = "bump" {}
_Amount ("Extrusion Amount", Range(-0.5, 0.5)) = 0.1
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 300
CGPROGRAM
// surface surf 指定为表面着色器.
// CustomLambert 使用简单兰伯特光照模型.
// vertex:myvert 使用自定义顶点功能.
// finalcolor:mycolor - 使用定制最终颜色功能.
// addshadow - 使用阴影.
// exclude_path:deferred/exclude_path:不生成延迟渲染相关的路径.
// nometa - 取消对提取元数据的Pass生成.
#pragma surface surf CustomLambert vertex:myvert finalcolor:mycolor addshadow exclude_path:deferred exclude_path:prepass nometa
#pragma target 3.0
fixed4 _ColorTint;
sampler2D _MainTex;
sampler2D _BumpMap;
half _Amount;
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
};
void myvert (inout appdata_full v) {
//顶点位置+法线方向位置
v.vertex.xyz += v.normal * _Amount;
}
void surf (Input IN, inout SurfaceOutput o) {
//纹理取样
fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
//反射即是取样结果
o.Albedo = tex.rgb;
o.Alpha = tex.a;
//法线取样
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
half4 LightingCustomLambert (SurfaceOutput s, half3 lightDir, half atten) {
//点乘法线和光源位置
half NdotL = dot(s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
c.a = s.Alpha;
return c;
}
void mycolor (Input IN, SurfaceOutput o, inout fixed4 color) {
color *= _ColorTint;
}
ENDCG
}
FallBack "Legacy Shaders/Diffuse"
}
点开这里可以看到具体做了什么
有兴趣的同学自己研究研究或是直接看一下《Unity Shader 入门精要》冯乐乐吧。