【Unityシェーダー】よく使う手法・計算まとめ

3d model thumbnail

シェーダーを作る際に、いちいち検索してやり方を調べるのがめんどくさかったので、コピペで基本的なシェーダーを作れるようにしました。

基本Unlitシェーダー想定です。

適用したい効果をコピペしてシェーダーを組み立ててください。

クリックすると展開します

Shader “MyCustomShader/Default”
{
    Properties
    {
    }
    SubShader
    {
        Tags { “RenderType”=”Opaque” }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            #include “UnityCG.cginc”

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(1,1,1,1);
            }
            ENDCG
        }
    }
}

↑のデフォルトテンプレートに↓の中で追加したい要素を追加していく形になります。

<不透明>

SubShader内

Tags { “RenderType”=”Opaque” }

<透明>

SubShader内

Tags { “RenderType” = “Transparent” }
Blend SrcAlpha OneMinusSrcAlpha //透明色の重ね方は←を変更する

<カットアウト>

Properties

_Cutoff (“Alpha cutoff”, Range(0,1)) = 0.5

SubShader内

Tags {“Queue”=”AlphaTest” “RenderType”=”TransparentCutout”}
Blend SrcAlpha OneMinusSrcAlpha

Pass内

float _Cutoff;

frag内

fixed4 c = カットアウトしたいテクスチャや色;
clip(c.a – _Cutoff);

<テクスチャ>

Properties

_MainTex (“MainTexture”, 2D) = “white” {}

Pass内

sampler2D _MainTex;

vert内

v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);

frag内

fixed4 c = tex2D(_MainTex, i.uv);

<カラー>

Properties

_MainColor(“MainColor”,Color) = (1,1,1)

Pass内

float4 _MainColor;

frag内

fixed4 c = 適用したい色、テクスチャなど * _MainColor;

<フォッグ>

vert内

v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
UNITY_TRANSFER_FOG(o,o.vertex);

frag内

UNITY_APPLY_FOG(i.fogCoord, 最終的な計算が終わった色);

<ライト>

Pass内

Tags { “LightMode”=”ForwardBase”}
#include “Lighting.cginc”

appdata内

float3 normal : NORMAL;

v2f内

float3 normal : TEXCOORD1;
float4 diffuse : COLOR0;

vert内

v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.normal = UnityObjectToWorldNormal(v.normal);

float3 lightDir = _WorldSpaceLightPos0.xyz; //ライトの方向
float3 normal = normalize(i.normal); //ポリゴンの法線方向
float luminance =  saturate(dot(normal, lightDir)); //光具合

frag内

fixed4 c = fixed4(ライトを適用したい色やテクスチャ  * _LightColor0 * luminance , アルファ値);

<ライトの範囲拡大>

トゥーンシェーダーなどに使用する手法。明るい範囲を広くする。↑のライトを実装した後frag内のluminanceを↓のように書き換える

frag内

float  luminance =  saturate(dot(normal, lightDir)  * 0.5 + 0.5);  //光具合

スポンサーリンク

<影を落とす>

↓のパスをそのまま追加する。

追加する新たなパス

Pass
{
Tags {“LightMode”=”ShadowCaster”}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include “UnityCG.cginc”
struct v2f {
V2F_SHADOW_CASTER;
};
v2f vert(appdata_base v)
{
v2f o;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
return o;
}
float4 frag(v2f i) : SV_Target
{
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}

<影を受ける>

Pass内

Tags { “LightMode”=”ForwardBase”}

#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight

#include “AutoLight.cginc”

appdata内

float2 lightmapUV : TEXCOORD1;

v2f内

float4 pos : SV_POSITION;  //←vertexをposに書き換えなければいけない
float3 worldPos : TEXCOORD2;
#ifdef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS
    UNITY_LIGHTING_COORDS(TEXCOORDの使ってない番号,使ってない番号+1)
#else
    UNITY_SHADOW_COORDS(TEXCOORDの使ってない番号)
#endif

vert内

v2f o;
UNITY_INITIALIZE_OUTPUT(v2f, o);
o.pos = UnityObjectToClipPos(v.vertex);
UNITY_TRANSFER_LIGHTING(o,v.lightmapUV.xy);

frag内

//attenuationという名前出ないとダメ。この中に受ける影のデータが来ている
UNITY_LIGHT_ATTENUATION(attenuation, i, i.worldPos);
fixed4 c = 影を落としたい色やテクスチャ * attenuation;

<環境光を受ける>

スカイボックスからのAmbientColorとライトプローブなどのベイクしてある光を適用します。ちゃんとStaticにしないと受け付けないようです。

v2f内

float4 diffuse : COLOR0;

vert内

v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.diffuse.rgb = ShadeSH9(half4(UnityObjectToWorldNormal(v.normal), 1));

frag内

fixed4 c = fixed4(環境光を適用したい色やテクスチャ  *  i.diffuse.rgb , アルファ値);

<ライト+環境光+影を受ける>

↑のライトと環境光と影を受けるのに必要な物を追加した上で最終的な計算を↓にする

frag内

fixed4 c = fixed4 ( max ( i.diffuse.rgb, luminance * _LightColor0) * attenuation, 0 );

<ノーマルマップ>

Properties

_NormalMap (“Normal map”, 2D) = “bump” {}

appdata内

float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float2 uv : TEXCOORD0;

v2f内

float4 pos : SV_POSITION;
float4 diffuse : COLOR0;
float2 uv : TEXCOORD0;
float3 worldPos : TEXCOORD1;
half3 tspace0 : TEXCOORD2;
half3 tspace1 : TEXCOORD3;
half3 tspace2 : TEXCOORD4;

Pass内

#include “Lighting.cginc”

sampler2D _NormalMap;

vert内

v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _NormalMap);  //←メインテクスチャがあるならそっちに
half3 worldNormal = UnityObjectToWorldNormal(v.normal);

//ノーマルマップ用の情報書き込み
half3 wTangent = UnityObjectToWorldDir(v.tangent.xyz);
half tangentSign = v.tangent.w * unity_WorldTransformParams.w;
half3 wBitangent = cross(worldNormal, wTangent) * tangentSign;
o.tspace0 = half3(wTangent.x, wBitangent.x, worldNormal.x);
o.tspace1 = half3(wTangent.y, wBitangent.y, worldNormal.y);
o.tspace2 = half3(wTangent.z, wBitangent.z, worldNormal.z);

frag内

// ノーマルマップを適用した法線方向を計算 
half3 tnormal = UnpackNormal(tex2D(_NormalMap, i.uv));
half3 worldNormal;
worldNormal.x = dot(i.tspace0, tnormal);
worldNormal.y = dot(i.tspace1, tnormal);
worldNormal.z = dot(i.tspace2, tnormal);

//光の方向
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);

//光具合
float luminance = saturate(dot(worldNormal, lightDir));

fixed4 c = fixed4(ライトを適用したい色やテクスチャ  * _LightColor0 * luminance , アルファ値);

<ノーマルマップ+環境光>

↑のノーマルマップと環境光を追加した状態でfrag内の最後の計算を↓のように書き換える。

環境光が当たっている方向をカメラの向きで指定しているので少し不自然ではあるので各自のプロジェクトによって要調整

frag内

//環境光の光具合
float ambientLuminance = saturate(dot(worldNormal,UNITY_MATRIX_V[2].xyz));


fixed4 c = fixed4(ライトを適用したい色やテクスチャ  * _LightColor0 * luminance , アルファ値) + i.diffuse * ambientLuminance;

タイトルとURLをコピーしました