博客
关于我
【Shader入门精要】第十四章——卡通风格的渲染
阅读量:500 次
发布时间:2019-03-07

本文共 9331 字,大约阅读时间需要 31 分钟。

卡通风格渲染与素描风格渲染技术实现

一、卡通风格渲染

卡通风格的渲染通常采用渐变纹理漫反射和分块的高光反射处理,能够在视觉上创造出生动的卡通效果。这种方法通过模拟光线反射和漫反射,赋予物体颜色和质感,使其更加生动且富有层次感。

渲染过程

  • 轮廓线处理

    • 使用法线扩展技术,向外扩展并渲染背面,生成轮廓线。
    • 渲染结果为边缘颜色,用于后续细节处理。
  • 漫反射渐变纹理

    • 采用渐变纹理漫反射,通过纹理映射来模拟光线在表面产生的漫反射效果。
    • 使用光照方向和法线方向的点积来计算纹理坐标,采样纹理数据生成漫反射颜色。
  • 高光反射处理

    • 高光反射采用分块处理,通过设置阈值来控制反光区域。
    • 阈值的选择决定了反光块的大小和数量,避免锯齿现象,实现平滑的高光效果。
  • 光照衰减与抗锯齿

    • 通过计算光照衰减值,结合法线方向和视角方向,调整高光反射的强度。
    • 使用动态阈值和平滑步进函数(smoothstep),实现高光反射的平滑过渡。
  • 代码实现

    Shader "MilkShader/14/ToonShading" {
    Properties {
    _Color("Color Tint", Color) = (1,1,1,1)
    _MainTex("Main Tex", 2D) = "white"
    _Ramp("Ramp Texture", 2D) = "white"
    _Outline("Outline", Range(0,1)) = 0.1
    _OutlineColor("Outline Color", Color) = (1,1,1,1)
    _Specular("Specular", Color) = (1,1,1,1)
    _SpecularScale("Specular Scale", Range(0, 0.1)) = 0.01
    }
    SubShader {
    Tags {"RenderType"="Opaque" "Queue"="Geometry"}
    LOD 100
    Pass {
    NAME "OUTLINE"
    Cull Front
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    include "UnityCG.cginc"
    float _Outline;
    fixed4 _OutlineColor;
    struct a2v {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    };
    struct v2f {
    float4 pos : SV_POSITION;
    };
    v2f vert(a2v v) {
    v2f o;
    pos = mul(UNITY_MATRIX_MV, v.vertex);
    normal = mul(UNITY_MATRIX_IT_MV, v.normal);
    normal.z = -0.5;
    pos = pos + normalize(normal) * _Outline;
    o.pos = mul(UNITY_MATRIX_P, pos);
    return o;
    }
    float4 frag(v2f i) : SV_Target {
    return _OutlineColor.rgb;
    }
    ENDCG
    }
    Pass {
    Tags {"LightMode"="ForwardBase"}
    Cull Back
    CGPROGRAM
    include "UnityCG.cginc"
    include "Lighting.cginc"
    include "AutoLight.cginc"
    include "UnityShaderVariables.cginc"
    #pragma vertex vert
    #pragma fragment frag
    #pragma multi_compile_fwdbase
    sampler2D _MainTex;
    float4 _MainTex_ST;
    fixed4 _Color;
    sampler2D _Ramp;
    fixed4 _Specular;
    fixed _SpecularScale;
    struct a2v {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    };
    struct v2f {
    float4 pos : POSITION;
    float2 uv : TEXCOORD0;
    float3 worldNormal : TEXCOORD1;
    float3 worldPos : TEXCOORD2;
    SHADOW_COORDS(3)
    };
    v2f vert(a2v v) {
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    o.worldNormal = UnityObjectToWorldNormal(v.normal);
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    TRANSFER_SHADOW(o);
    return o;
    }
    float4 frag(v2f i) : SV_Target {
    fixed3 worldNormal = normalize(i.worldNormal);
    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
    fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
    fixed3 worldHalfDir = normalize(worldLightDir + worldViewDir);
    fixed4 c = tex2D(_MainTex, i.uv);
    fixed3 albedo = c.rgb * _Color.rgb;
    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
    UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
    fixed diff = dot(worldNormal, worldLightDir);
    diff = (diff * 0.5 + 0.5) * atten;
    fixed3 diffuse = _LightColor0.rgb * albedo * tex2D(_Ramp, float2(diff, diff)).rgb;
    fixed spec = dot(worldNormal, worldHalfDir);
    fixed w = fwidth(spec) * 2.0;
    fixed3 specular = _Specular.rgb * lerp(0,1, smoothstep(-w,w,spec + _SpecularScale - 1)) * step(0.0001, _SpecularScale);
    return fixed4(ambient + diffuse + specular, 1.0);
    }
    ENDCG
    }
    }
    Fallback "Diffuse"
    }

    二、素描风格渲染

    素描风格的渲染通过多层纹理和线条处理,模拟手绘效果,赋予物体细腻的艺术感。这种方法通过层叠纹理和权重计算,生成丰富的纹理效果。

    渲染过程

  • 素描纹理层叠

    • 使用多个素描纹理层(如Hatch0到Hatch5),每层负责特定的纹理线条生成。
    • 通过顶点着色器计算每个纹理层的权重,决定其对最终颜色的影响程度。
  • 纹理权重计算

    • 根据法线方向和光照方向,计算纹理权重,确定哪些纹理层对当前片元有影响。
    • 权重计算分为不同的区间,每个区间对应不同的纹理层和权重分配。
  • 颜色混合

    • 在片元着色器中,根据权重对不同纹理层的颜色进行加权混合。
    • 非素描部分使用白色作为基色,素描部分根据权重计算颜色。
  • 光照处理

    • 结合光照衰减值,调整纹理颜色,确保光照和阴影效果自然融合。
  • 代码实现

    Shader "MilkShader/14/Hatching" {
    Properties {
    _Color("Color Tint", Color) = (1,1,1,1)
    _TileFactor("Tile Factor", Float) = 1
    _Outline("Outline", Range(0,1)) = 0.1
    _OutlineColor("Outline Color", Color) = (1,1,1,1)
    _Hatch0("Hatch 0", 2D) = "white"
    _Hatch1("Hatch 1", 2D) = "white"
    _Hatch2("Hatch 2", 2D) = "white"
    _Hatch3("Hatch 3", 2D) = "white"
    _Hatch4("Hatch 4", 2D) = "white"
    _Hatch5("Hatch 5", 2D) = "white"
    }
    SubShader {
    Tags {"RenderType"="Opaque" "Queue"="Geometry"}
    UsePass "MilkShader/14/ToonShading/OUTLINE"
    Pass {
    Tags {"LightMode"="ForwardBase"}
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    #pragma multi_compile_fwdbase
    include "UnityCG.cginc"
    include "Lighting.cginc"
    include "AutoLight.cginc"
    include "UnityShaderVariables.cginc"
    fixed4 _Color;
    fixed _TileFactor;
    fixed _Outline;
    fixed4 _OutlineColor;
    sampler2D _Hatch0;
    sampler2D _Hatch1;
    sampler2D _Hatch2;
    sampler2D _Hatch3;
    sampler2D _Hatch4;
    sampler2D _Hatch5;
    struct appdata {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float2 texcoord : TEXCOORD0;
    float3 normal : NORMAL;
    };
    struct v2f {
    float4 pos : POSITION;
    float2 uv : TEXCOORD0;
    fixed3 hatchWeight0 : TEXCOORD1;
    fixed3 hatchWeight1 : TEXCOORD2;
    float3 worldPos : TEXCOORD3;
    SHADOW_COORDS(4)
    };
    v2f vert(appdata v) {
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.uv = v.texcoord.xy * _TileFactor;
    fixed3 worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
    fixed3 worldLightDir = normalize(WorldSpaceLightDir(v.vertex));
    fixed diff = max(0, dot(worldNormal, worldLightDir));
    hatchFactor = diff * 7.0;
    o.hatchWeight0 = fixed3(0,0,0);
    o.hatchWeight1 = fixed3(0,0,0);
    if (hatchFactor > 6.0) {
    } else if (hatchFactor > 5.0) {
    o.hatchWeight0.x = hatchFactor - 5.0;
    } else if (hatchFactor > 4.0) {
    o.hatchWeight0.x = hatchFactor - 4.0;
    o.hatchWeight0.y = 1 - o.hatchWeight0.x;
    } else if (hatchFactor > 3.0) {
    o.hatchWeight0.y = hatchFactor - 3.0;
    o.hatchWeight0.z = 1 - o.hatchWeight0.y;
    } else if (hatchFactor > 2.0) {
    o.hatchWeight0.z = hatchFactor - 2.0;
    o.hatchWeight1.x = 1 - o.hatchWeight0.z;
    } else if (hatchFactor > 1.0) {
    o.hatchWeight1.x = hatchFactor - 1.0;
    o.hatchWeight1.y = 1 - o.hatchWeight1.x;
    } else {
    o.hatchWeight1.y = hatchFactor;
    o.hatchWeight1.z = 1 - o.hatchWeight1.y;
    }
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    TRANSFER_SHADOW(o);
    return o;
    }
    fixed4 frag(v2f i) : SV_Target {
    fixed4 hatchTex0 = tex2D(_Hatch0, i.uv) * i.hatchWeight0.x;
    fixed4 hatchTex1 = tex2D(_Hatch1, i.uv) * i.hatchWeight0.y;
    fixed4 hatchTex2 = tex2D(_Hatch2, i.uv) * i.hatchWeight0.z;
    fixed4 hatchTex3 = tex2D(_Hatch3, i.uv) * i.hatchWeight1.x;
    fixed4 hatchTex4 = tex2D(_Hatch4, i.uv) * i.hatchWeight1.y;
    fixed4 hatchTex5 = tex2D(_Hatch5, i.uv) * i.hatchWeight1.z;
    fixed4 whiteColor = fixed4(1,1,1,1) * (1 - i.hatchWeight0.x - i.hatchWeight0.y - i.hatchWeight0.z - i.hatchWeight1.x - i.hatchWeight1.y - i.hatchWeight1.z);
    fixed4 hatchColor = hatchTex0 + hatchTex1 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5 + whiteColor;
    UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
    return fixed4(hatchColor.rgb * _Color.rgb * atten, 1.0);
    }
    ENDCG
    }
    }
    Fallback "Diffuse"
    }

    平铺系数说明

    平铺系数(_TileFactor)决定了纹理的密度。值越大,纹理线条越密集;值越小,纹理线条越稀疏。通过调整平铺系数,可以根据需求控制纹理的细腻程度。

    总结

    卡通风格和素描风格渲染通过不同的纹理处理和光照模拟方法,分别实现了生动的卡通效果和细腻的素描效果。两种方法都结合了光照和纹理的精细控制,确保了视觉效果的自然和一致性。

    转载地址:http://xhucz.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现蓄水池算法(附完整源码)
    查看>>
    Objective-C实现装饰模式(附完整源码)
    查看>>
    Objective-C实现观察者模式(附完整源码)
    查看>>
    Objective-C实现观访问者模式(附完整源码)
    查看>>
    Objective-C实现视频流转换为图片(附完整源码)
    查看>>
    Objective-C实现视频除雾算法(附完整源码)
    查看>>
    Objective-C实现角谷猜想(附完整源码)
    查看>>
    Objective-C实现解密 Atbash 密码算法(附完整源码)
    查看>>
    Objective-C实现解密藏头诗(附完整源码)
    查看>>
    Objective-C实现解析数学表达式解析(附完整源码)
    查看>>
    Objective-C实现解释器模式(附完整源码)
    查看>>
    Objective-C实现计时(附完整源码)
    查看>>
    Objective-C实现计算 32 位整数中设置的位数算法(附完整源码)
    查看>>
    Objective-C实现计算 sin 函数算法(附完整源码)
    查看>>
    Objective-C实现计算x的n次方(附完整源码)
    查看>>
    Objective-C实现计算π值算法(附完整源码)
    查看>>
    Objective-C实现计算两个日期之间的天数算法(附完整源码)
    查看>>
    Objective-C实现计算二维平面上两点之间的距离算法(附完整源码)
    查看>>
    Objective-C实现计算信息熵(附完整源码)
    查看>>
    Objective-C实现计算各种形状的体积算法 (附完整源码)
    查看>>