【TA】Unity角色二次元风格渲染

NRMToonLitSample


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


文章目录

  • NRMToonLitSample
    • 1. 模型贴图基本信息
    • 2. 基础渲染效果
      • 2.1 基础shader Toon
      • 2.2 光照模型效果
        • 第一步:光照色阶
        • 第二步:增加ILM贴图
        • 第三步:顶点信息
      • 2.3 当前渲染效果展示
    • 3. 卡通高光
      • 3.1 增加高光效果
      • 3.2 高光颜色优化
    • 4. 描边
      • 4.1 增加描线效果
      • 4.2 使用DetailMap
      • 4.3 描线融合与增强
    • 5. 色彩校正
    • 6. 外描边
      • 6.1 轮廓描边实现
      • 6.2 边缘颜色融合
    • 7. 效果展示

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

1. 模型贴图基本信息

原始模型

亮部贴图RGBA

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

暗部颜色RGBA

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

LightMap R通道
控制高光强度

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

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

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

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

顶点色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));

6. 外描边

6.1 轮廓描边实现

外轮廓的描线做法,使用双通道,在Pass2中拿到角色在对应空间坐标上的顶点,根据顶点得到法线,在法线上对顶点进行外拓。

_OutlineWidth ("OutLine Width",Range(0,10)) = 5.0 // 外轮廓宽度

世界空间坐标下外拓实现

float3 pos_world = mul(unity_ObjectToWorld, v.vertex).xyz;
float3 normal_world = UnityObjectToWorldNormal(v.normal);
// 顶点外拓 拿到世界坐标
pos_world += normal_world * _OutlineWidth * 0.001;
// 拿到vp矩阵
o.pos = mul(UNITY_MATRIX_VP, float4(pos_world, 1.0));
return float4(0, 0, 0, 1.0); // 黑色描边

观察空间坐标下外拓实现

float3 pos_view = UnityObjectToViewPos(v.vertex);
// 观察空间下的normal方向
float3 normal_world = UnityObjectToWorldNormal(v.normal);
float3 outline_dir = mul((float3x3)UNITY_MATRIX_V, normal_world);
pos_view += outline_dir * _OutlineWidth * 0.001;
o.pos = mul(UNITY_MATRIX_P, float4(pos_view, 1.0));

轮廓描边效果

6.2 边缘颜色融合

根据自定义描边颜色降低对比度,降低饱和度,使得颜色偏暗

_OutlineColor ("Outline Color",Color) = (1,1,1,1) // 轮廓颜色
half4 frag(v2f i) : SV_Target
{float3 baseColor = tex2D(_BaseMap, i.uv.xy).xyz;half maxComponent = max(max(baseColor.r, baseColor.g), baseColor.b) - 0.004;half3 saturatedColor = step(maxComponent.rrr, baseColor) * baseColor;saturatedColor = lerp(baseColor.rgb, saturatedColor, 0.6);half3 outlineColor = 0.8 * saturatedColor * baseColor * _OutlineColor.xyz;return float4(outlineColor, 1.0);
}

7. 效果展示

全身效果
在这里插入图片描述

半身效果
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/72801.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Fiora一款二次元的Web多人在线网络聊天系统

源码介绍 Fiora是一款偏二次元的Web多人在线聊天应用,使用Node.js、Mongodb、Socket.io和React编写,使用起来还行,挺简洁的,这里水个搭建教程,有兴趣的可以玩玩。 源码功能 好友,群组,私聊&a…

Unity制作二次元卡通渲染角色材质——1、资源分析

Unity制作二次元材质角色 回到目录 大家好,我是阿赵。 开始制作二次元角色材质之前,我觉得应该是先分析一下,我手上拿到的这个角色模型资源,总共有哪些信息是我们能用的。 所以这篇文章我不会分享具体的Shader,但我感觉…

WPF 3D 贴图: 为你的二次元老婆们做个3D画廊

文章目录 WPF3D系列为你的二次元老婆们做个3D画廊 WPF3D系列 💎WPF 3D初步|源码 新建一个立方体并调整视角相机控制:位置和视角的调节 💎键盘控制|源码💎鼠标控制|源码 💎为你的二次元老婆们做个3D画廊|源码&#x1f…

关于人工智能写作的发展以及看法

人工智能技术的快速发展使其应用领域得以扩展。从金融服务到小说创作,人工智能技术都占有了一席之地。 人工智能可以取代编辑吗?近日某公司开发了一个神码AI人工智能写作软件,据说现在人工智能可以理解超过85%的内容。现在也可以…

换一种姿势阅读《人工智能简史》

2017 年 12 月,一本名为《人工智能简史》的图书发布。这个时间节点对于多数普通人的生活来说不算特别,但正是从前一年开始,人工智能在世界范围内开始进入了一段新的飞速发展期。2017 年和 2018 年也是中国 AI 企业的创业热潮期。 你说这个时代…

【转载】人工智能发展简史

网络查阅资料时候,看到的对人工智能发展简史,较为完整的讲述,故转载,仅供学习使用,原文链接:https://www.aminer.cn/ai-history。侵删。 人工智能到底是什么?通常来说,人工智能&…

人工智能再次超越人类,这次是阅读理解

在斯坦福大学举办的阅读理解比赛中,由微软和阿里巴巴分别独立开发的人工智能的得分都超过了人类。 在斯坦福大学举办的阅读理解比赛中,由微软和阿里巴巴分别独立开发的人工智能(AI)模型的得分均超过了人类。 这一人工智能里程碑是…

与AI合作穿越剧 编剧徐婷:AI脑洞大,但无法替代人类的情感表达

热门喜剧秀《周六夜现场》本季提前结束,美剧《亿万》最新第七季的更新搁浅,漫威新电影《新刀锋战士》暂停拍摄……美国影视娱乐行业的编剧们以抵制AI为由的大罢工,开始影响诸多作品的产出,据说造成了100亿美元的损失。 这场罢工已…

人工智能简史+电子版原文

自从学习了人工智能,对其的发展史产生了浓厚的兴趣,于是选择了《人工智能简史》这本书细细品味。下面将分享我看书时的一些体会。 人工智能的发展过程 我们想要理解人工智能,首先要知道这个名词从何而来。1956年达特茅斯会议被公认为人工智能…

AI:周志华老师文章《关于强人工智能》的阅读笔记以及感悟

AI:周志华老师文章《关于强人工智能》的阅读笔记以及感悟 导读 关于人工智能,长期存在两种不同的目标或者理念。一种是希望借鉴人类的智能行为,研制出更好的工具以减轻人类智力劳动,一般称为“弱人工智能”,类似…

《人工智能》之《绪论》习题解析

教材:《人工智能及其应用》,蔡自兴等,2016m清华大学出版社(第5版) 参考书: 对应同系列博客:《人工智能》之《绪论》 《人工智能》之《绪论》习题解析 1 什么是人工智能?试从学科…

解读人工智能续写名著的经典论

这段时间,人工智能“续写”名著的现象受到舆论聚焦。在人工智能的“作品”中,“林黛玉大战孙悟空”之类“脑洞大开”的情节纷纷亮相,大大超出了一般人的预料。面对《聊斋志异》里的经典故事,人工智能竟然创作出了 “蒲松龄笔下的狼…

论人工智能——写在当今人工智能突飞猛进的时代

人工智能是现代科技领域最为热门的研究方向之一,它是一种基于计算机技术和算法的智能体系,可以模拟人类的思维和判断能力,实现诸如语音识别、图像识别、自然语言处理等多项智能化任务。在日常生活中,人工智能的应用已经变得日益广…

股票交易接口软件服务涵盖范围有哪些?

通常所说的股票交易接口软件是指量化交易程序员们可以自行查询各大交易网站或交易所的股票历史数据及行情数据的工具,如:实时报价;走势图;价差图;基金、债券、期货、外汇、保险等各类金融数据查询等,进行数…

android官方转圈圈,android 弹出之后,一直转圈圈??

flutter version: version: 1.0.01 environment: sdk: ">2.1.0 <3.0.0" photo: 0.4.5 1 code: GestureDetector( child: Text(从相册选择), onTap: () async { var assetPathList await PhotoManager.getImageAsset(); _pickAsset(PickType.onlyImage, pathL…

爬取股票的历史数据(个股)

股票的历史数据爬取 爬取网易财经的个股历史数据 爬取链接&#xff1a;http://quotes.money.163.com/trade/lsjysj_000001.html? 先爬取股票的对应的代码 爬取股票代码的网站 https://www.banban.cn/gupiao/list_sh.html 代码 import requests,pymysql,re,datetime impo…

计算机技能高考600分,高三一模成绩530高考能上600分吗

有可能。很多地方在高三为了督促同学复习不松懈&#xff0c;一模二模的考试往往试题难度会比高考更高&#xff01;同时模拟考也往往不像高考评分那么工整、有详尽的步骤分&#xff0c;这就导致了学生考分的偏低。三模的试卷由于接近高考了&#xff0c;学生的状态好了&#xff0…

参加物理竞赛就是偏科严重?今天说说参加物理竞赛的好处和坏处!

前段时间&#xff0c;质心姐姐跟一些朋友聊起了竞赛这个话题。发现好多人都不知道竞赛能保送清北这个东东&#xff0c;或者就是略知一二~这让质心姐姐想来写一篇关于参加物理竞赛好处和坏处的文章。 先说说好处&#xff1a; 可以通过参加物理竞赛保送清北一般参加物理竞赛的流…