ムラサメ研究ブログ

主にゲームやプログラミングのログ

トゥーンシェーダ―作ってみる 

トゥーンシェーダ―作りたい

シェーダーの色々な知見が出来たので少しずつメモ

中野シスターズ

まず 中野シスターズをダウンロードしてくる
詳細は省略するが、ダウンロードして UNITYにインポートしシーンに配置する
f:id:murasame-labo:20170910113613p:plain

暗いので、今後色々と遊ぶので ポイントライトを4-5個つけてみる
調整はまたこんど
f:id:murasame-labo:20170910113702p:plain

ちなみに Forwardレンダリングだと
DrawCall 74 f:id:murasame-labo:20170910113732p:plain

Deferredレンダリングだと
DrawCall 41 f:id:murasame-labo:20170910113753p:plain

ライトが多いと圧倒的に Deferredのメリットが出てくる

シェーダーをコピー

中野シスターズは Standardシェーダ(Unityのビルトインシェーダ)を使っている
UNITYの公式ページより ビルトインシェーダをダウンロードすれば中身を見れる

UNITYエディタで Create->Shaderで シェーダを作り、Standardをコピーしよう
シェーダー名は 今回は Yuki/Standard にした

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

Shader "Yuki/Standard"
{
    Properties
    {
        _Color("Color", Color) = (1,1,1,1)
        _MainTex("Albedo", 2D) = "white" {}

    _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5

        _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5
        _GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0
        [Enum(Metallic Alpha,0,Albedo Alpha,1)] _SmoothnessTextureChannel("Smoothness texture channel", Float) = 0

        [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
        _MetallicGlossMap("Metallic", 2D) = "white" {}

    [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0
        [ToggleOff] _GlossyReflections("Glossy Reflections", Float) = 1.0

        _BumpScale("Scale", Float) = 1.0
        _BumpMap("Normal Map", 2D) = "bump" {}

    _Parallax("Height Scale", Range(0.005, 0.08)) = 0.02
        _ParallaxMap("Height Map", 2D) = "black" {}

    _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
        _OcclusionMap("Occlusion", 2D) = "white" {}

    _EmissionColor("Color", Color) = (0,0,0)
        _EmissionMap("Emission", 2D) = "white" {}

    _DetailMask("Detail Mask", 2D) = "white" {}

    _DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
    _DetailNormalMapScale("Scale", Float) = 1.0
        _DetailNormalMap("Normal Map", 2D) = "bump" {}

    [Enum(UV0,0,UV1,1)] _UVSec("UV Set for secondary textures", Float) = 0


        // Blending state
        [HideInInspector] _Mode("__mode", Float) = 0.0
        [HideInInspector] _SrcBlend("__src", Float) = 1.0
        [HideInInspector] _DstBlend("__dst", Float) = 0.0
        [HideInInspector] _ZWrite("__zw", Float) = 1.0
    }

        CGINCLUDE
#define UNITY_SETUP_BRDF_INPUT MetallicSetup
        ENDCG

        SubShader
    {
        Tags{ "RenderType" = "Opaque" "PerformanceChecks" = "False" }
        LOD 300


        // ------------------------------------------------------------------
        //  Base forward pass (directional light, emission, lightmaps, ...)
        Pass
    {
        Name "FORWARD"
        Tags{ "LightMode" = "ForwardBase" }

        Blend[_SrcBlend][_DstBlend]
        ZWrite[_ZWrite]

        CGPROGRAM
#pragma target 3.0

        // -------------------------------------

#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature _ _GLOSSYREFLECTIONS_OFF
#pragma shader_feature _PARALLAXMAP

#pragma multi_compile_fwdbase
#pragma multi_compile_fog
#pragma multi_compile_instancing
        // Uncomment the following line to enable dithering LOD crossfade. Note: there are more in the file to uncomment for other passes.
        //#pragma multi_compile _ LOD_FADE_CROSSFADE

#pragma vertex vertBase
#pragma fragment fragBase
#include "UnityStandardCoreForward.cginc"

        ENDCG
    }
        // ------------------------------------------------------------------
        //  Additive forward pass (one light per pass)
        Pass
    {
        Name "FORWARD_DELTA"
        Tags{ "LightMode" = "ForwardAdd" }
        Blend[_SrcBlend] One
        Fog{ Color(0,0,0,0) } // in additive pass fog should be black
        ZWrite Off
        ZTest LEqual

        CGPROGRAM
#pragma target 3.0

        // -------------------------------------


#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature _PARALLAXMAP

#pragma multi_compile_fwdadd_fullshadows
#pragma multi_compile_fog
        // Uncomment the following line to enable dithering LOD crossfade. Note: there are more in the file to uncomment for other passes.
        //#pragma multi_compile _ LOD_FADE_CROSSFADE

#pragma vertex vertAdd
#pragma fragment fragAdd
#include "UnityStandardCoreForward.cginc"

        ENDCG
    }
        // ------------------------------------------------------------------
        //  Shadow rendering pass
        Pass{
        Name "ShadowCaster"
        Tags{ "LightMode" = "ShadowCaster" }

        ZWrite On ZTest LEqual

        CGPROGRAM
#pragma target 3.0

        // -------------------------------------


#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _PARALLAXMAP
#pragma multi_compile_shadowcaster
#pragma multi_compile_instancing
        // Uncomment the following line to enable dithering LOD crossfade. Note: there are more in the file to uncomment for other passes.
        //#pragma multi_compile _ LOD_FADE_CROSSFADE

#pragma vertex vertShadowCaster
#pragma fragment fragShadowCaster

#include "UnityStandardShadow.cginc"

        ENDCG
    }
        // ------------------------------------------------------------------
        //  Deferred pass
        Pass
    {
        Name "DEFERRED"
        Tags{ "LightMode" = "Deferred" }

        CGPROGRAM
#pragma target 3.0
#pragma exclude_renderers nomrt


        // -------------------------------------

#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature _PARALLAXMAP

#pragma multi_compile_prepassfinal
#pragma multi_compile_instancing
        // Uncomment the following line to enable dithering LOD crossfade. Note: there are more in the file to uncomment for other passes.
        //#pragma multi_compile _ LOD_FADE_CROSSFADE

#pragma vertex vertDeferred
#pragma fragment fragDeferred

#include "UnityStandardCore.cginc"

        ENDCG
    }

        // ------------------------------------------------------------------
        // Extracts information for lightmapping, GI (emission, albedo, ...)
        // This pass it not used during regular rendering.
        Pass
    {
        Name "META"
        Tags{ "LightMode" = "Meta" }

        Cull Off

        CGPROGRAM
#pragma vertex vert_meta
#pragma fragment frag_meta

#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature EDITOR_VISUALIZATION

#include "UnityStandardMeta.cginc"
        ENDCG
    }
    }

        SubShader
    {
        Tags{ "RenderType" = "Opaque" "PerformanceChecks" = "False" }
        LOD 150

        // ------------------------------------------------------------------
        //  Base forward pass (directional light, emission, lightmaps, ...)
        Pass
    {
        Name "FORWARD"
        Tags{ "LightMode" = "ForwardBase" }

        Blend[_SrcBlend][_DstBlend]
        ZWrite[_ZWrite]

        CGPROGRAM
#pragma target 2.0

#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature _ _GLOSSYREFLECTIONS_OFF
        // SM2.0: NOT SUPPORTED shader_feature ___ _DETAIL_MULX2
        // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP

#pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED

#pragma multi_compile_fwdbase
#pragma multi_compile_fog

#pragma vertex vertBase
#pragma fragment fragBase
#include "UnityStandardCoreForward.cginc"

        ENDCG
    }
        // ------------------------------------------------------------------
        //  Additive forward pass (one light per pass)
        Pass
    {
        Name "FORWARD_DELTA"
        Tags{ "LightMode" = "ForwardAdd" }
        Blend[_SrcBlend] One
        Fog{ Color(0,0,0,0) } // in additive pass fog should be black
        ZWrite Off
        ZTest LEqual

        CGPROGRAM
#pragma target 2.0

#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature ___ _DETAIL_MULX2
        // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP
#pragma skip_variants SHADOWS_SOFT

#pragma multi_compile_fwdadd_fullshadows
#pragma multi_compile_fog

#pragma vertex vertAdd
#pragma fragment fragAdd
#include "UnityStandardCoreForward.cginc"

        ENDCG
    }
        // ------------------------------------------------------------------
        //  Shadow rendering pass
        Pass{
        Name "ShadowCaster"
        Tags{ "LightMode" = "ShadowCaster" }

        ZWrite On ZTest LEqual

        CGPROGRAM
#pragma target 2.0

#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _METALLICGLOSSMAP
#pragma skip_variants SHADOWS_SOFT
#pragma multi_compile_shadowcaster

#pragma vertex vertShadowCaster
#pragma fragment fragShadowCaster

#include "UnityStandardShadow.cginc"

        ENDCG
    }

        // ------------------------------------------------------------------
        // Extracts information for lightmapping, GI (emission, albedo, ...)
        // This pass it not used during regular rendering.
        Pass
    {
        Name "META"
        Tags{ "LightMode" = "Meta" }

        Cull Off

        CGPROGRAM
#pragma vertex vert_meta
#pragma fragment frag_meta

#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature EDITOR_VISUALIZATION

#include "UnityStandardMeta.cginc"
        ENDCG
    }
    }


        FallBack "VertexLit"
        CustomEditor "StandardShaderGUI"
}

各メッシュのシェーダを Standardから Yuki/Standardに変更
f:id:murasame-labo:20170910114557p:plain

Passというのが シェーダのパスで
Tags{ “LightMode” = “ForwardBase” } となっている部分が、レンダリングモード

Forwardレンダリング時は
メインライトのパスが ForwardBase
その他のライトがライト毎に ForwardAdd

Deferredレンダリング時は
Deferredパスが呼ばれる

また影の計算時に
ShadowCasterパスが呼ばれる

輪郭線を付ける

今回は単純な オブジェクトの裏側を法線方向に拡大して表示する

アウトラインのパスを作る
先ほどのシェーダーに輪郭線パスを増やす
StandardはLODにより2個あるので 出来れば2つのSubshaderに書くほうが良い

     Pass{
            Name "Outline"
        
        Tags{ "LightMode" = "ForwardBase" }

    Cull Front

        CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define _GLOSSYENV 1
#include "UnityCG.cginc"

#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_shadowcaster
#pragma multi_compile_fog
#pragma only_renderers d3d9 d3d11 glcore gles 
#pragma target 5.0


    struct VertexInput {
        float4 vertex : POSITION;
        float3 normal : NORMAL;
    };
    struct VertexOutput {
        float4 pos : SV_POSITION;
        UNITY_FOG_COORDS(1)
    };
    VertexOutput vert(VertexInput v) {
        VertexOutput o = (VertexOutput)0;

        float width = 1;

        o.pos = UnityObjectToClipPos(float4(v.vertex.xyz + v.normal*(width*0.01),1));
        UNITY_TRANSFER_FOG(o,o.pos);
        return o;
    }
    float4 frag(VertexOutput i, float facing : VFACE) : COLOR{
        float isFrontFace = (facing >= 0 ? 1 : 0);
        float faceSign = (facing >= 0 ? 1 : -1);
        float4 outlineColor = float4(0,0,0,1);
        return fixed4(outlineColor);
    }
        ENDCG
    }

上記はForwardパスなので Deferredパスにも同じものを追加すると Deferredでも輪郭線がつく
具体的には上記の
Tags{ “LightMode” = “ForwardBase” }

Tags{ “LightMode” = “Deferred” }
にしたものを書けばいい

Forward

f:id:murasame-labo:20170910121631p:plain

Deferred
DeferredではMSAAが使えないため、画質が悪い。
Deferredでは他の方法で アンチエイリアスを考える必要がある

f:id:murasame-labo:20170910121642p:plain