【TA】Unity角色二次元风格渲染
创始人
2024-03-31 10:19:03

NRMToonLitSample


Author: 文若
Demo地址:我的GitHub(欢迎Start) NRMToonLitSample
学习视频教程Kerry大佬的 技术美术实战培训课程—卡通人物渲染方案


文章目录

  • NRMToonLitSample
    • 1. 模型贴图基本信息
      • 1.1 亮度
      • 1.2 阴影
      • 1.3 LightMap
      • 1.4 DetailMap
      • 1.5 顶点色
    • 2. 基础渲染效果
      • 2.1 基础shader Toon
      • 2.2 光照模型效果
        • 第一步:光照色阶
        • 第二步:增加ILM贴图
        • 第三步:顶点信息
      • 2.3 当前渲染效果展示
    • 3. 卡通高光
      • 3.1 增加高光效果
      • 3.2 高光颜色优化
    • 4. 描边
      • 4.1 增加描线效果
      • 4.2 使用DetailMap
      • 4.3 描线融合与增强
    • 5. 色彩校正

NRM由四张图构成角色渲染,亮部贴图,阴影贴图图,ilm贴图和细节贴图。

1. 模型贴图基本信息

原始模型

1.1 亮度

亮部贴图RGBA

亮部贴图Alpha
用于区分人物的皮肤区域以及非皮肤区域。

1.2 阴影

暗部颜色RGBA

暗部贴图Alpha
用于做某些mask使用。

1.3 LightMap

R通道
控制高光强度

G通道
偏移光照,越黑部分越接近阴影,越白部分越接近亮部。128中度灰不会对原来光线进行偏移。

B通道
控制高光范围大小(光滑度)越黑部分高光越小,纯黑区域五高光。

Alpha通道
一张描线图,记录描线,内描线。

1.4 DetailMap

Detail的RGBA
使用第二套UV采样,也是描线图。但UV分部并不严格。按照第二套UV做点缀使用。

1.5 顶点色

顶点色R通道
遮挡部分颜色较黑,代表环境光的遮挡。剩余通道控制描边的粗细,深度偏移等信息。

2. 基础渲染效果

2.1 基础shader Toon

Shader "Toon"
{Properties{_BaseMap ("Base Map", 2D) = "white" {}_SSSMap ("SSS Map", 2D) = "black" {}}SubShader{Tags{"RenderType"="Opaque"}LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "UnityCG.cginc"#include "AutoLight.cginc"struct appdata{float4 vertex : POSITION;float2 texcoord0 : TEXCOORD0;float2 texcoord1 : TEXCOORD1;float3 normal : NORMAL;float4 color : COLOR;};struct v2f{float4 pos : SV_POSITION;float4 uv : TEXCOORD0;float3 pos_world : TEXCOORD1;float3 normal_world : TEXCOORD2;};sampler2D _BaseMap;sampler2D _SSSMap;v2f vert(appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;o.normal_world = UnityObjectToWorldNormal(v.normal);o.uv = float4(v.texcoord0, v.texcoord1);return o;}half4 frag(v2f i) : SV_Target{half2 uv1 = i.uv.xy;half2 uv2 = i.uv.zw;half4 base_map = tex2D(_BaseMap, uv1);half4 sss_map = tex2D(_SSSMap, uv1);return base_map;}ENDCG}}
}

2.2 光照模型效果

// 单位向量
float3 normalDir = normalize(i.normal_world);
// 光照方向
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
// light
half NdotL = dot(normalDir,lightDir);
return NdotL.xxxx;

第一步:光照色阶

模型色阶

half toon_diffuse = step(0.0, NdotL); // 色阶化

在这里插入图片描述
图形色阶化
加入阈值范围和硬度

_ToonThreshold ("ToonThreshold", Range(0,1)) = 0.6 // 阈值范围
_ToonHardness ("ToonHardness",Float) = 50.0 // 过渡的生硬情况
half4 base_map = tex2D(_BaseMap, uv1);
half3 base_color = base_map.rgb;
half NdotL = dot(normalDir, lightDir); // 结果在(-1~1)
half half_lambert = (NdotL + 1.0) * 0.5; // 缩放到0-1之间
// 偏移光照位置
half toon_diffuse = saturate((half_lambert - _ToonThreshold) * _ToonHardness);
// 颜色*base图片的灰度值
half3 final_diffuse = toon_diffuse * base_color;
return float4(final_diffuse, 1.0);


提高阴影面的亮度
1.第一种方法,原有亮度的0.5倍

toon_diffuse = saturate(toon_diffuse + 0.5); // 提亮光照


2.采用阴影面贴图,拿到阴影面rgb和toondiffuse做插值计算

half4 sss_map = tex2D(_SSSMap, uv1);
half3 sss_color = sss_map.rgb;
half NdotL = dot(normalDir, lightDir); 
half half_lambert = (NdotL + 1.0) * 0.5; 
half toon_diffuse = saturate((half_lambert - _ToonThreshold) * _ToonHardness);
half3 final_diffuse = lerp(sss_color, base_color, toon_diffuse);

第二步:增加ILM贴图

// ILM贴图
half4 ilm_map = tex2D(_ILMMap,uv1);
float spec_intensity = ilm_map.r; // 控制高光的强度
float diffuse_control = ilm_map.g * 2.0 - 1.0; // 控制光照偏移,从0-1转换成-1~1
float spec_size = ilm_map.b; // 控制高光的大小
float inner_line = ilm_map.a; // 用来控制内描线

当前头发没有任何阴影,需要为头发末端添加光照阴影。

光照贴图的g通道,提前预设阴影区域,给角色头发做光照偏移的效果。这是一张灰度图,以0.5为分界线,灰度值高于128(0.5)的部分提前变亮,等于128的部分不会对光照进行偏移,低于128的部分变暗。

使用光照贴图优化

half lambert_term = half_lambert + diffuse_control; // 做一个偏移控制
half toon_diffuse = saturate((lambert_term - _ToonThreshold) * _ToonHardness);

第三步:顶点信息

当前效果中裙子内部应该是暗面,利用ao信息来渲染。

float4 vertex_color : TEXCOORD3;
o.vertex_color = v.color;
float ao = i.vertex_color.r;
half lambert_term = half_lambert * ao + diffuse_control;

2.3 当前渲染效果展示

在这里插入图片描述

3. 卡通高光

3.1 增加高光效果

一个完整的效果应该有漫反射和高光反射,上一节完成了漫反射效果。圈中的金属质感部分需要进行高光处理

ILM图的B通道控制高光形状的大小,高光部分越黑越光滑,形状也越小。

使用NotV进行计算,并且为这个值加上偏移结果

// 视觉方向
float3 viewDir = normalize(_WorldSpaceCameraPos - i.pos_world.xyz); 
// 高光处理
float NdotV = (dot(normalDir, viewDir) + 1.0) * 0.5; //拿到NdotV并进行数值范围缩放
float spec_trem = NdotV * ao + diffuse_control; // 光线偏移


增加高光系数

_SpecSize ("Spec Size",Range(0,1)) = 0.1 // 高光系数
// 高光处理 拿到NdotV并进行数值范围缩放
float NdotV = (dot(normalDir, viewDir) + 1.0) * 0.5;
float spec_trem = NdotV * ao + diffuse_control; // 光线偏移
// 当前高光是基于视角的高光 真正高光收到光照方向的影响
spec_trem = half_lambert * 0.9 + spec_trem * 0.1; // 高光权重分配
// 限制边缘
half toon_spec = saturate((spec_trem - (1.0 - spec_size * _SpecSize)) * 500); // 内部数值越大越光滑

在这里插入图片描述
对高光和Base颜色进行叠加,金属部分光线对比之前漫反射渲染效果有了明显变化。

half3 final_spec = toon_spec * base_color * spec_intensity;
half3 final_color = final_diffuse + final_spec;
return float4(final_color, 1.0);

在这里插入图片描述

3.2 高光颜色优化

对高光颜色优化,增加可自定义的高光颜色。

// 自定义的高光颜色与原来的颜色进行混合
half spec_color = (_SpecColor.xyz + base_color) * 0.5;
half3 final_spec = toon_spec * spec_color * spec_intensity;

4. 描边

4.1 增加描线效果

光照贴图的alpha通道用来控制内描线

float inner_line = ilm_map.a;

将描线效果叠加到当前颜色上

half3 final_line = inner_line.xxx; // 描线效果
half3 final_color = (final_diffuse + final_spec) * final_line;
return float4(final_color, 1.0);

4.2 使用DetailMap

detail map 的uv更加随意,可以勾勒出一些圆滑的斜线等。但是该贴图非常的大,只有高清二点情况下才能避免模糊。

half3 detail_color = tex2D(_DetailMap, uv2); // 采样detail map 使用第二套uv
half3 final_line = inner_line.xxx * detail_color;
half3 final_color = (final_diffuse + final_spec) * final_line;
return float4(final_color, 1.0);

4.3 描线融合与增强

使用插值将内描线线条增强并与皮肤颜色融合

half3 detail_color = tex2D(_DetailMap, uv2); // 采样detail map 使用第二套uv
detail_color = lerp(base_color * 0.2, float3(1.0, 1.0, 1.0), detail_color);
half3 inner_line_color = lerp(base_color * 0.2, float3(1.0, 1.0, 1.0), inner_line);
half3 final_line = inner_line_color * inner_line_color * detail_color;
half3 final_color = (final_diffuse + final_spec) * final_line;
return float4(final_color, 1.0);

5. 色彩校正

类Tone Mapping做法,将色彩进行微细的调整,稍微对比度压暗了一丢丢

final_color = sqrt(max(exp2(log2(max(final_color, 0.0)) * 2.2), 0.0));

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...