あなたはシェーダラボを理解していない場合は、シェーダラボ関連コンテンツを見ることをお勧めします:ジャンプ・インタフェースを。
そして、各シェーダを用意行う光は非常に異なるオプション、異なるレンダリングパスをシェーディング、ライティングのさまざまな種類があり、複雑であり、着色剤は何とかすべての複雑さに対処する必要があります。
コード生成方法の表面シェーダUnityは、それがより書き込みにはるかに容易になります色の頂点/フラグメントシェーダ、サーフェスシェーダはすべてが、手動で、まだ書き込みHLSLシェーダに必要な書き込みコードへの繰り返しの必要性を生成します。
表面シェーダーの動作原理:
「表面関数」(機能表面処理)の定義は、彼が私達の入力データ構造、出力構造「SurfaceOutput」構造を充填する、メソッドを配置する必要があります。表面シェーダは、次いで、所望の入力、出力等が充填されている計算しますそして、実際の頂点/フラグメントシェーダを生成しますそして、作成プロセスフォワード胸が張り裂ける及び繰延shaderingレンダリングパスは、パス(合格)をレンダリングします。
例えば:
//...
#pragma surface surf Lambert
struct Input
{
//...
}
void surf(Input i,inout SurfaceOutput o)
{
o.Albedo =1;
//...
}
//...
上面就用#pragma surface 定义了一个surf表面函数,并且使用Lambert光照模型,定义了Input结构体,并在surf 方法中对输出结构体SurfaceOutput进行了填充
サーフェスシェーダコンパイラディレクティブ:
ブロックに書き込みにシェーダCGPROGRAMの必要性を表面とENDCGそして、次のように注意を払う必要があります。
1.必须放在SubShder块内(注意不是Pass内,表面着色器本身将编译为多个通道)
2.使用#pragma surface ...指令来指示当前shader为Surface Shader。
#pragma表面命令形式:
#pragma surface surfaceFunction lightModel [optionalparams]
命令の種類 | Instruction | 説明 |
---|---|---|
パラメータ必須 | surfaceFunction | CGは関数であり、表面のシェーダコード、フォーマット含む自動任意の関数所望の表面テクスチャ座標および追加の変数を含まなければならない構造定義から空隙サーフ(入力IN、INOUT SurfaceOutput O)、入力 |
- | lightModel | 使用するモデル照明、そこを内蔵しており、物理ベースの標準StandardSpecular、および単純な物理的ランバート、BlinnPhongおよびカスタムライティングモデルに基づいていません |
- | ||
- | StandardSpecular:ユニティ標準で使用SurfaceOutputStandardSpecular出力構造、および整合(鏡面セットアップ)シェーダ | |
- | Lamber BlinnPhongと物理ベースのモデルが点灯していないが、着色でそれらを使用すると、すぐにローエンドのハードウェア上でレンダリングすることができます | |
オプションのパラメータ | 透明性や不透明度テスト | 物理的に、アルファブレンディング(フェードのオブジェクト)より合理的な「あらかじめ乗算ハイブリッド」と(あらかじめ乗算ブレンド、半透明の表面の鏡面反射を保持して正常に実行):不透明度、透明度は、一般に、2つを有していてもよいです。 |
- | アルファまたはアルファ:オート | 選択の方法は、単にフェード(アルファを持つ:フェード同じ)透明を照射します照明の物理的方法を選択し、透明度(:同じpremulアルファ)に基づいて乗算されます。 |
- | アルファ:ブレンド | アルファブレンディングを有効にします。 |
- | アルファ:フェード | 伝統的にフェードを達成 |
- | アルファ:premul | プリマルチアルファ透明度を有効にします |
- | alphatest | 透過性試験、剪断アルファ透明度を可能にします。浮動小数点変数を使用してオフ変数名は、正しい命令addshadow影を生成するために使用することができます。 |
- | キープアルファ | デフォルトでは、不透明な着色表面を問わずアルファ値出力構造である、または何照明機能が戻るかどうかの、1.0アルファチャンネルを記述します。このオプションがあっても、不透明なサーフェスシェーダウエルため、照明機能のアルファ値を維持することができます。 |
- | デカール:アドオン | デカールシェーダ(例えば地形addpass)を追加します。表面の上に位置する他のオブジェクトに適用し、添加して混合使用。 |
- | デカール:ブレンド | 半透明のアップリケ他の上部表面上に位置するオブジェクトのためのシェーダ、およびアルファブレンディングを使用。 |
- | カスタム関数修飾子 | 着信または計算された頂点データを変更し、または算出された最終フラグメントの色を変更するために使用され |
- | 頂点:VertexFunction | カスタム頂点変形関数は、この関数は、生成された頂点シェーダの開始時に呼び出され、各頂点データに対する変更または計算することができます |
- | finalcolor:ColorFunction | 最終編集カスタムカラー |
- | finalgbuffer:ColorFunction | Gbufferは、カスタムパス遅延の内容を変更するために使用しました |
- | finalprepass:ColorFunction | カスタムチャネル前のベースパス |
- | 影とテッセレーション | 他の命令は、テッセレーションの方法とプロセスを制御するために設けられていてもよいです |
- | addshadow | 通常、カスタム頂点を変更するために使用するシャドウを投影するレンダリングパス(パス)を生成するので、任意の影のキャスティングが頂点アニメーションプログラムを得ることができます。彼らはフォールバック指定影に使用することができますので、通常は特別なシェーダシェーディング処理ません |
- | フル前方に影 | フォワードレンダリングは、光と影のパスのすべての種類をサポートしています。(内部シェーダ変数がカウント保存)デフォルトでは、シェーダフォワードレンダリングは影平行光のみをサポートしています。所望の点の光スポットまたは影フォワードレンダリングは、このコマンドを使用することができる場合 |
- | テッセレーション:TessFunction | 使用DX11 GPUセグメント。関数は、テッセレーション係数を計算します。 |
- | コード生成オプション | デフォルトでは、生成されたサーフェスシェーダコードは、すべての可能な光/影/ライトマップを処理しようとしますが、いくつかのケースでは、必要とされていないし、それらをスキップし、生成されたコードを調整することができる、と順に、その一部小さいシェーダリフトローディング速度を生成します。 |
- | exclude_path:延期、exclude_path:前方、exclude_path:prepass | 所与のレンダリングパスレンダリングパス(PASS)(遅延シェーディング、および転送遅延従来の照明をレンダリング)のために生成されません |
- | noshadow | サポートを受けるには、このシェーダのすべてのシャドウを無効にします。 |
- | noambient | 任意の周囲照明や光プローブを使用しないでください。 |
- | novertexlights | または、各ソース頂点をレンダリングする順方向検出器内の任意の光を使用しないでください。 |
- | nolightmap | すべて無効にライトマップは、このシェーダをサポートしています。 |
- | nodynlightmap | このダイナミックなグローバルイルミネーションシェーダサポート操作で無効になっています。 |
- | nodirlightmap | この方向シェーダライトマップのサポートを無効にします。 |
- | nofog | 禁用所有内置的雾支持。 |
— | nometa | 不生成"meta“通道(由光照贴图和动态全局照明用于提取表面信息)。 |
— | moforwardadd | 禁用Forward add 渲染通道,这使得着色支持一个全方向光,所有其他的光源按照顶点/SH的方式计算,可以使着色器更小 |
— | 其他 | |
— | softvegetation | 仅在启用”Soft Vegetation“时才渲染表面着色器 |
— | interpolateview | 在顶点着色器中计算视图方向并进行插值,而不是在像素着色器中计算。这样可以使像素着色器更快,但需要消耗一个纹理插值器 |
— | halfasview | 将半向方向矢量传递到光照函数而不是试图方向,每个顶点将计算并归一化半方向。这样会更快,但不完全正确 |
— | dualforward | 在forward rendering中使用双光照贴图 |
InputStruct(输入结构):
输入结构通常具有着色器所需要的任何纹理坐标。纹理坐标必须命名为"uv",后跟纹理名称(或”uv2“开头,使用第二个纹理坐标)(例如:uv_MainTex 或 uv2_MainTex);
其他可以放入输入结构的值有:
指令 | 描述 |
---|---|
float3 viewDir | 包含视角方向,可用于计算边缘光照等效果 |
float4 变量名:Color | 包含差值后逐顶点颜色 |
float4 screenPos | 包含了屏幕空间的坐标,可用于反射或屏幕特效。注意,这不适合GrabPass;需要使用ComputeGrabScreenPos函数自己计算定义UV。 |
float3 worldPos | 包含世界空间位置。 |
float3 worldRefl | 如果没有修改o.Normal,则包含世界空间下的反射向量。 |
float3 worldNormal | 如果修改o.Normal,则包含世界空间下的法线向量。 |
float3 worldRefl;INTERNAL_DATA | 如果修改了o.Normal,需要使用该变量告诉Unity要基于修改后的法线计算世界空间下的反射向量。可以使用WorldReflectionVector(IN,o.Normal)来得到世界空间下的反射方向。 |
float3 worldNormal;INTERNAL_DATA | 如果修改了o.normal,需要使用该变量告诉Unity要基于修改后的法线计算世界空间下的法线方向。可以使用WorldNormalVector(IN,o.Normal)来得到世界空间下的法线方向 |
SurfaceOutput结构:
SurfaceOutput基本上描述了平面的属性(如albedo、normal、emission、specularity等)
标准输出结构如下:
struct SurfaceOutput
{
fixed3 Albedo; //漫反射
fixed3 Normal; //正切空间法线
fixed3 Emission; //自发光
half Specular; //高光率 0-1
fixed Gloss; // 高光强度
fixed Alpha; // 透明度
};
在Unity中还可以使用基于物理的照明模型,内置Standard和StandardSpecular模型分别使用下面这些输出结构:
struct SurfaceOutputStandard
{
fixed3 Albedo; //漫反射颜色
fixed3 Normal; // 切线空间法线
half3 Emission; //自发光颜色
half Metallic; // 金属 0 - 1
half Smoothness; // 平滑度0-1
half Occlusion; // occlusion (default 1)
fixed Alpha; // 透明度
};
struct SurfaceOutputStandardSpecular
{
fixed3 Albedo; // 漫反射颜色
fixed3 Specular; // 高光颜色
fixed3 Normal; // 切线空间法线
half3 Emission; //自发光颜色
half Smoothness; //平滑度0-1
half Occlusion; // occlusion (default 1)
fixed Alpha; // 透明度
};
实例:
1.简单的着色器:
Shader "Example/DiffuseSimple"
{
SubShader
{
Tags{"RenderType" = "Opaque"}
CGPROGRAM
#pragma surface surf Lambert
struct Input
{
fixed4 color : COLOR;
};
void surf(Input IN, inout SurfaceOutput o)
{
o.Albedo = 1;
}
ENDCG
}
FallBack "Diffuse"
}
//在上述着色器中,声明找色器为表面找色器(#pragma surface) ,定义了表面函数(surf)以及指定基本光照为Lambert。
//声明输入结构(Input) 包含顶点颜色。
//在表面方法(surf)中,设置输出函数的漫反射颜色为1(o.Albedo = 1;)
//如果此着色器在硬件上没法使用的话会使用Diffuse着色器进行替换
2.Texture(纹理):
Shader "Example/Texture"
{
Properties
{
_MainTex("MainTex",2D) = ""{}
}
SubShader
{
Tags{"RenderType" = "Opaque"}
CGPROGRAM
#pragma surface surf Lambert
struct Input //获取_MainTex的第一套纹理坐标
{
float2 uv_MainTex;
};
//注意 在Properties中声明的属性,需要在CGPROGRAM块内声明一个同样名称且类型匹配的变量来进行关联
sampler2D _MainTex;
void surf(Input IN, inout SurfaceOutput o)
{
//根据Input中纹理坐标匹配_MainTex的纹理设置漫反射颜色
o.Albedo = tex2D(_MainTex, IN.uv_MainTex);
}
ENDCG
}
FallBack "Diffuse"
}
3.Normal(法线):
Shader "Example/DiffuseBump"
{
Properties
{
_MainTex("MainTex",2D) = ""{}
// 定义法线贴图
_BumpTex("BumpTex",2D) = ""{}
}
SubShader
{
Tags{"RenderType"="Opaque"}
CGPROGRAM
#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
//法线贴图纹理坐标
float2 uv_BumpTex;
};
sampler2D _MainTex;
sampler2D _BumpTex;
void surf(Input IN, inout SurfaceOutput o)
{
o.Albedo = tex2D(_MainTex, IN.uv_MainTex);
//设置法线
o.Normal = UnpackNormal(tex2D(_BumpTex, IN.uv_BumpTex));
}
ENDCG
}
FallBack "Diffuse"
}
4.Rim Light(边缘照明):
Shader "Example/RimLight"
{
Properties
{
_MainTex("MainTex",2D) = ""{}
_BumpTex("BumpTex",2D) = ""{}
_RimColor("Rim Color",Color) = (1,1,1,1)
_RimPower("Rim Power",Range(0,8)) = 0
}
SubShader
{
Tags{"RenderType" = "Opaque"}
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
sampler2D _BumpTex;
float4 _RimColor;
float _RimPower;
struct Input
{
float2 uv_MainTex;
float2 uv_BumpTex;
float3 viewDir;//视角方向
};
void surf(Input IN, inout SurfaceOutput o)
{
o.Albedo = tex2D(_MainTex, IN.uv_MainTex);
o.Normal = UnpackNormal(tex2D(_BumpTex, IN.uv_BumpTex));
half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
o.Emission = _RimColor.rgb*pow(rim, _RimPower);
}
ENDCG
}
}