庄懂老师TA学习笔记 - 卡通渲染

我们可以看到,这个卡通渲染有三个颜色,并且调子与半兰伯特类似,所以我们只需要创建一张有三种颜色的纹理,使用半兰伯特返回的结果作为UV的U值进行RampTex的取值,并把得到的颜色赋值到模型上,最后再加上一个描边即可。

RampTex制作方法

Shader Forge版

代码版

Shader "Unlit/CartoonCode" {
    Properties {
        _RampTex ("_RampTex", 2D) = "white" {}
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        // 外边框Pass
        Pass {
            Name "Outline"
            Cull Front
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.pos = UnityObjectToClipPos( float4(v.vertex.xyz + v.normal*0.05,1) );
                return o;
            }
            float4 frag(VertexOutput i) : SV_Target {
                return fixed4(0,0,0,1);
            }
            ENDCG
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            uniform sampler2D _RampTex; 
            uniform float4 _RampTex_ST;
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float4 posWorld : TEXCOORD0;
                float3 normalDir : TEXCOORD1;
                LIGHTING_COORDS(2,3)
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.normalDir = UnityObjectToWorldNormal(v.normal);
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                o.pos = UnityObjectToClipPos( v.vertex );
                TRANSFER_VERTEX_TO_FRAGMENT(o)
                return o;
            }
            float4 frag(VertexOutput i) : SV_Target {
                i.normalDir = normalize(i.normalDir);
                float3 nDir = i.normalDir;
                float3 lDir = normalize(_WorldSpaceLightPos0.xyz);
                float nDotl = (dot(nDir, lDir) * 0.5)+0.5;
                // 根据tiling和offset计算出uv取对应位置纹理的颜色
                float4 color = tex2D(_RampTex,TRANSFORM_TEX(float2(nDotl, 0.2), _RampTex));
                return fixed4(color.rgb,1);
            }
            ENDCG
        }
    }
    // 显示阴影
    FallBack "Diffuse"
}

这段代码里有这么几个新的知识点

1)由于需要渲染外边框Outline,所以我们为外边框多写一个Pass,在这个Pass里,物体的所有顶点都朝着发现方向做一个偏移,填充为黑色,并且将裁剪设置为Cull Front将模型前侧的外边框裁减掉,就可以得到一个完美的外边框了

2)第二个Pass中我们渲染物体的光照,第一个知识点是"LightMode"="ForwardBase"这句话,和这句话差不多的有一句话是"LightMode"="ForwardAdd",这些都是指定渲染模式为前向渲染,Base渲染最重要的逐像素灯光,Add渲染其他的逐像素灯光,具体的区别如下

  • ForwardBase:用于正向渲染中,该Pass会计算环境光、最重要的平行光、逐顶点/SH光源和Lightmaps光照贴图
  • ForwardAdd:用于前向渲染。该Pass会计算额外的逐像素光源,每一个Pass对应一个光源

3) 第二个Pass导入了AutoLight库,也就是#include "AutoLight.cginc",我们引入这个库之后,就可以使用下面代码里的LIGHTING_COORDS(2,3)和TRANSFER_VERTEX_TO_FRAGMENT(o),第一个函数声明了用于阴影纹理采样坐标 _ShadowCoord 和用于衰减纹理采样坐标 _LightCoord,第二个函数会根据该pass处理的光源类型(spot?point?or directional?)来计算光源坐标的具体值,以及进行和shadow相关的计算等(PS:其实我也没太明白,看ShaderForge这么写的,有大佬知道的话可以回复一下Up,未来我弄明白也会回来补充的!)

4)在取纹理颜色的时候,使用了TRANSFORM_TEX函数,之前我们使用的都是i.uv,这个函数可以根据纹理的Tiling和Offset返回一个最终uv供我们取色使用,这个函数的使用需要在Pass中声明纹理变量和ST变量也就是_RampTex和_RampTex_ST

5)最后我们需要显示物体投射出来的阴影,只需要Fallback “Diffuse”就可以了(PS:这个我也不太理解,可能Diffuse中使用了阴影相关的操作)

ShaderForge代码中还有下面这一个Pass,也就是上面说的ForwardAdd,大家可以看一下,对比一下自己的Shader代码进行学习

Pass {
            Name "FORWARD_DELTA"
            Tags {
                "LightMode"="ForwardAdd"
            }
            Blend One One
            
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #pragma multi_compile_fwdadd_fullshadows
            #pragma target 3.0
            uniform sampler2D __RampTex; uniform float4 __RampTex_ST;
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float4 posWorld : TEXCOORD0;
                float3 normalDir : TEXCOORD1;
                LIGHTING_COORDS(2,3)
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.normalDir = UnityObjectToWorldNormal(v.normal);
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                o.pos = UnityObjectToClipPos( v.vertex );
                TRANSFER_VERTEX_TO_FRAGMENT(o)
                return o;
            }
            float4 frag(VertexOutput i) : COLOR {
                i.normalDir = normalize(i.normalDir);
                float3 normalDirection = i.normalDir;
                float3 lightDirection = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - i.posWorld.xyz,_WorldSpaceLightPos0.w));
// Lighting:
                float3 finalColor = 0;
                return fixed4(finalColor * 1,0);
            }
            ENDCG
        }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值