Unity3d Shader篇(十四)— 卡通着色


前言

卡通着色是一种常见的图形渲染效果,它将物体的光照和颜色处理成简单的、扁平的色块,以模拟漫画或动画中的风格。本篇博客将介绍如何在Unity中使用Shader实现卡通着色效果。


一、什么是卡通着色?

1. 卡通着色原理

简化光照:卡通着色将光照计算简化为基于表面法线和光源方向的漫反射模型,通常忽略了光源的阴影和反射等复杂效果,使得渲染结果更加扁平。
颜色平滑处理:卡通着色通过将颜色分段处理或应用简单的插值,使得颜色之间的过渡更加平滑,呈现出类似于印刷品的色彩效果。
轮廓加粗
:为了突出物体的轮廓,卡通着色通常会在物体的边缘添加黑色或彩色的轮廓线,增强了整体的辨识度和艺术感。
卡通效果增强:通过调整卡通效果的参数,可以控制渲染结果的卡通程度,从而满足不同风格的需求。

2. 卡通着色优缺点

优点:

独特的艺术风格:卡通着色能够产生独特的艺术效果,使得场景或物体呈现出类似于漫画或动画的视觉风格,增加了趣味性和表现力。
渲染速度快:相比于传统的真实感渲染技术,卡通着色通常需要计算的光照和材质参数较少,因此渲染速度较快,适用于实时渲染和移动平台。
简单易用:实现卡通着色的技术和工具已经比较成熟,开发者可以通过使用现成的着色器或工具包,快速实现卡通效果,降低了开发成本。

缺点:

失去真实感:卡通着色通常会忽略真实世界中的光照、阴影和材质细节,因此渲染结果可能缺乏真实感,无法满足某些场景或项目的需求。
局限性较大:卡通着色的艺术风格和效果相对固定,适用范围较窄,无法满足所有类型的项目或用户需求。
易产生过度简化:为了追求卡通效果,有时候可能会过度简化场景或物体的细节,导致渲染结果显得过于平面化或单调。

二、使用步骤

1. Shader 属性定义

首先,我们定义Shader中所需的属性,包括主纹理贴图、渐变纹理贴图、漫反射颜色、轮廓大小、轮廓颜色、卡通效果步数、卡通效果强度、边缘光颜色和边缘光强度等。

// 定义属性
Shader "Unlit/ToonShader"
{
    Properties
    {
        _MainTex ("Main Texture", 2D) = "white" // 主纹理贴图
        _RampTex ("Ramp Texture", 2D) = "white" // 渐变纹理贴图
        _Diffuse("Diffuse Color",Color)=(1,1,1,1) // 漫反射颜色属性,默认白色
        _OutlineScale("Outline Scale",Range(0,1))=0.5 // 轮廓大小属性
        _OutlineColor("Outline Color",Color)=(0,0,0,1) // 轮廓颜色属性
        _Steps("Steps",Range(1,30))=1 // 卡通效果步数
        _ToonEffect("Toon Effect",Range(0,1))=0.5 // 卡通效果强度
        _RimColor("Rim Color",Color)=(1,1,1,1) // 边缘光颜色
        _RimPower("Rim Power",Range(0.001,3))=1 // 边缘光强度
    }

    // 其他SubShader和Pass部分省略
}

2. SubShader 设置

SubShader
{
    Tags
    {
        "Queue"="Geometry+1000"// 在其他不透明物体后面渲染
        "RenderType"="Opaque" // 渲染类型为Opaque
    }
    
    LOD 100 // 细节级别
}

3. 卡通轮廓 Pass

卡通着色常常伴随着黑色轮廓,我们首先实现轮廓效果。在Shader中,通过对顶点位置进行外扩,并在片元着色器中输出轮廓颜色来实现。

// 轮廓Pass
Pass
{
    Name "Outline" // Pass名称为Outline
    Cull Front // 剔除正面

    CGPROGRAM
    #pragma vertex vert // 顶点着色器函数声明
    #pragma fragment frag // 片元着色器函数声明
    #include "UnityCG.cginc" // 包含Unity宏

    float _OutlineScale; // 轮廓大小
    float4 _OutlineColor; // 轮廓颜色

    struct v2f
    {
        float4 vertex:SV_POSITION; // 顶点位置
    };

    // 顶点着色器
    v2f vert(appdata_base v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex); // 将顶点位置从对象空间转换到裁剪空间

        float3 normal = normalize(mul((float3x3)UNITY_MATRIX_IT_MV, v.normal)); // 计算变换后的法线
        float2 viewNormal = TransformViewToProjection(normal.xy); // 将法线转换到投影空间
        o.vertex.xy += viewNormal * _OutlineScale; // 根据轮廓大小调整顶点位置

        return o;
    }

    // 片元着色器
    fixed4 frag(v2f i):SV_Target
    {
        return _OutlineColor; // 输出轮廓颜色
    }
    ENDCG
}

剔除正面: 轮廓 Pass 会设置剔除正面(Cull Front),这意味着只有物体的背面会被渲染,而正面将被剔除。
顶点着色器处理: 顶点着色器会对物体的顶点进行处理,通常会通过一定的方式扩大或缩小顶点的位置,以产生轮廓效果。这可以通过将顶点从对象空间转换到裁剪空间后,根据一定的算法调整顶点的位置来实现。
片元着色器处理: 片元着色器负责输出轮廓的颜色。通常轮廓的颜色是黑色或者是与物体主色彩对比较大的颜色,以便与主 Pass 渲染的物体区分开来。

4. 卡通主 Pass

接下来,我们实现卡通着色的主要效果。在片元着色器中,根据光照和漫反射计算出最终颜色,并加入卡通效果和边缘光效果。

// 主Pass
Pass
{
    CGPROGRAM
    #pragma vertex vert // 顶点着色器函数声明
    #pragma fragment frag // 片元着色器函数声明
    #include "UnityCG.cginc" // 包含Unity宏
    #include "Lighting.cginc" // 包含光照宏

    struct v2f
    {
        float4 vertex : SV_POSITION; // 顶点位置
        float2 uv : TEXCOORD0; // 纹理坐标
        fixed3 worldNormal : TEXCOORD1; // 世界空间法线
        float3 worldPos : TEXTCOORD2; // 世界空间位置
    };

    sampler2D _MainTex; // 主纹理贴图
    sampler2D _RampTex; // 渐变纹理贴图
    float4 _MainTex_ST; // 主纹理贴图的缩放和偏移参数
    float4 _Diffuse; // 漫反射颜色
    float _Steps; // 卡通效果步数
    float _ToonEffect; // 卡通效果强度
    float4 _RimColor; // 边缘光颜色
    float _RimPower; // 边缘光强度

    // 顶点着色器
    v2f vert(appdata_base v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex); // 将顶点位置从对象空间转换到裁剪空间
        o.worldNormal = UnityObjectToWorldNormal(v.normal); // 将法线从对象空间转换到世界空间
        o.worldPos = mul(unity_ObjectToWorld, v.vertex); // 将顶点位置从对象空间转换到世界空间
        o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); // 转换纹理坐标
        return o;
    }

    // 片元着色器
    fixed4 frag(v2f i) : SV_Target
    {
        fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; // 环境光
        fixed4 albedo = tex2D(_MainTex, i.uv); // 纹理采样
        fixed3 worldLightDir = UnityWorldSpaceLightDir(i.worldPos); // 光源方向
        fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); // 视角方向

        // 求半兰伯特模型
        float difLight = dot(worldLightDir, i.worldNormal) * 0.5 + 0.5; // 计算漫反射光强度

        // 卡通颜色处理
        difLight = smoothstep(0, 1, difLight); // 平滑过渡
        float toon = floor(difLight * _Steps) / _Steps; // 卡通效果
        difLight = lerp(difLight, toon, _ToonEffect); // 混合卡通效果

        // 边缘光计算
        float rim = 1 - dot(i.worldNormal, viewDir); // 边缘光强度
        fixed3 rimColor = _RimColor * pow(rim, 1 / _RimPower); // 边缘光颜色

        // 漫反射计算
        fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * difLight; // 漫反射光颜色

        fixed3 color = diffuse + ambient + rimColor; // 最终颜色
        return fixed4(color, 1); // 输出最终颜色
    }
    ENDCG
}

顶点着色器处理: 主 Pass 的顶点着色器会对物体的顶点进行一些必要的计算和变换,如将顶点从对象空间转换到裁剪空间、将法线从对象空间转换到世界空间等。
片元着色器处理: 主 Pass 的片元着色器负责处理每个像素的渲染。这包括对物体表面的光照计算、纹理采样、漫反射计算、卡通效果处理、边缘光计算等。最终输出的颜色会结合光照、材质、纹理等信息,生成最终的渲染结果。
光照计算: 主 Pass 会根据场景中的光源信息以及物体的法线等属性,计算每个像素的光照效果。这可以是简化的漫反射光照模型,也可以包括其他光照效果,如环境光、辐射光等。
卡通效果处理: 主 Pass 也可能包含卡通效果的处理。这通常是通过调整颜色、平滑度等参数,使渲染结果呈现出卡通风格的效果。
边缘光计算: 一些主 Pass 也会包含边缘光效果的计算。这是为了增强物体的轮廓,使得物体在渲染结果中更加清晰可辨。

三、效果

在这里插入图片描述

四、总结

卡通着色是一种特殊的渲染技术,通过简化光照和色彩处理,模拟出类似于漫画或动画的视觉风格。

动画和游戏设计: 在动画片、电子游戏以及其他媒体制作中,卡通着色常常用于呈现特定的艺术风格,如日本动漫、欧美卡通等。这种风格能够增加作品的趣味性和独特性,使得角色和场景更加生动活泼。

虚拟现实和增强现实: 在虚拟现实(VR)和增强现实(AR)应用中,卡通着色可以帮助创建出具有沉浸感和趣味性的虚拟环境。通过简化的色彩和光照处理,可以减少硬件的渲染负担,提高应用的性能和稳定性。

教育和培训: 在教育领域,卡通着色常被用于制作教学动画、交互式课件等教育资料。这种风格通常更容易吸引学生的注意力,使得知识传递更加生动有趣。

广告和营销: 在广告和营销领域,卡通着色可以用于创建具有吸引力和记忆点的广告宣传片或品牌形象。这种风格的广告更容易引起观众的共鸣,增强品牌形象和产品识别度。

艺术创作和表现: 艺术家们也常常利用卡通着色技术来创作艺术作品,表达个人风格和情感。通过简化的色彩和线条处理,可以创造出独特的艺术风格,表达作者的创意和情感。

总的来说,卡通着色具有广泛的应用范围,可以在各种媒体制作、虚拟环境、教育培训、广告营销以及艺术创作等领域发挥重要作用。其独特的艺术风格和易于吸引观众的特点,使得它成为许多项目和应用中的首选渲染技术之一。

  • 31
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个简单的Unity3D着色器,可以制作冰冻效果。它使用了一个简单的反射纹理和一个噪声纹理来创建冰的外观。 ``` Shader "Custom/IceShader" { Properties { _MainTex ("Texture", 2D) = "white" {} _ReflectTex ("Reflect Texture", 2D) = "white" {} _NoiseTex ("Noise Texture", 2D) = "white" {} _BumpScale ("Bump Scale", Range(0.01, 0.1)) = 0.05 _Reflectivity ("Reflectivity", Range(0.0, 1.0)) = 0.5 _NoiseScale ("Noise Scale", Range(0.1, 10.0)) = 1.0 _IceColor ("Ice Color", Color) = (1,1,1,1) } SubShader { Tags { "Queue"="Transparent" "RenderType"="Opaque" } LOD 100 CGPROGRAM #pragma surface surf Standard sampler2D _MainTex; sampler2D _ReflectTex; sampler2D _NoiseTex; float _BumpScale; float _Reflectivity; float _NoiseScale; fixed4 _IceColor; struct Input { float2 uv_MainTex; float2 uv_ReflectTex; float2 uv_NoiseTex; float3 worldPos; float3 worldNormal; }; void surf (Input IN, inout SurfaceOutputStandard o) { // Get the base color from the main texture fixed4 baseColor = tex2D(_MainTex, IN.uv_MainTex); // Get the reflection from the reflect texture fixed4 reflectColor = tex2D(_ReflectTex, IN.uv_ReflectTex); // Combine the base color and reflection fixed4 finalColor = lerp(baseColor, reflectColor, _Reflectivity); // Apply the ice color finalColor *= _IceColor; // Get the bump from the noise texture float4 noise = tex2D(_NoiseTex, IN.uv_NoiseTex); // Convert the noise to a normal vector float3 normal = UnpackNormal(noise.rgb); // Apply the bump to the surface normal IN.worldNormal += normal * _BumpScale; // Set output parameters o.Albedo = finalColor.rgb; o.Metallic = 0.0; o.Smoothness = 1.0; o.Normal = normalize(IN.worldNormal); o.Emission = finalColor.rgb; o.Occlusion = 1.0; o.Alpha = finalColor.a; } ENDCG } FallBack "Diffuse" } ``` 要使用这个着色器,您需要将三个纹理分别指定给_MainTex,_ReflectTex和_NoiseTex属性。您还可以调整_BumpScale,_Reflectivity和_NoiseScale参数来改变效果。最后,您可以使用_IceColor来指定冰的颜色。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jolley77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值