最近驾考C1通过已拿到驾照,而且每天玩GTA5,好久没管博客了,今天有时间来一篇卡通渲染。

卡通头发渲染也是一个有意思的地方,头发上就像有一圈白条,如下:

这个白条还有个学名叫“天使环(angel ring)”,当然棋魂动漫里面是一个“带锯齿的天使环”。

我们可以稍微简单形象化一下,好比一个sphere(头顶)上有一圈白条,如下:

这种光照其实起源于之前聊过的各向异性光照,比如kajiyakay和marschner模型就很类似,当然我们需要修改得更加卡通化。

amd hair rendering pdf file

顺便提交到下载区,厚着脸皮混一点分

hair-rendering模型核心就是高光颜色使用BT(副切换)代替N(法线)去计算,这也好理解,如果使用N(法线)与H(半角向量),如下:

这里我具象的把线框图画出来辅助学习,如果我们使用dot(n,half),那么观察如下(黑色为viewdir,白色为lightdir,黄色为normaldir,粉色为halfdir):

 

(左)right viewport                                                                             (右)front viewport

如果有闲工夫可以仔细观察每个顶点:黄线(normaldir)和粉线(halfdir)夹角越小点积越大光强权重越大,则形成白斑(specular分量)。

当然用这种方法是无法形成“天使环”的,而上面提到的模型中使用T(切线)或BT(副切线)则效果如下:

黄色为Normal,蓝色为Tangent,天蓝色则为叉积(左手定则)计算出的BTangent,可以看得出我们先不管hair光照公式如何,光是BTangent副切线就“长”得跟头发一样。所以我感觉我们使用BT参与光照计算,有机会可以得到一个横向垂直BT的“光带”(称为“天使环”),我们先来分别验证三种计算方式:

1.BTangent dot LightDir

Shader "CartoonHair/BTangentDotLightDirShader"
{Properties{_MainTex ("Texture", 2D) = "white" {}_DiffuseFactor("Diffuse Factor",Color) = (1,1,1,1)_SpecularFactor("Specular Factor",Color) = (1,1,1,1)_SpecularGloss("Specular Gloss",Range(0,50)) = 1_LightFactor("Light Factor",Color) = (1,1,1,1)}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;float3 tangent : TANGENT;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;float3 worldNormal : TEXCOORD1;float3 worldTangent : TEXCOORD2;float3 worldBTangent : TEXCOORD3;float3 worldP2S : TEXCOORD4;float3 worldP2V : TEXCOORD5;};sampler2D _MainTex;float4 _MainTex_ST;float4 _DiffuseFactor;float4 _SpecularFactor;float _SpecularGloss;float4 _LightFactor;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldTangent = mul(UNITY_MATRIX_M,v.tangent);o.worldBTangent = cross(o.worldNormal,o.worldTangent);o.worldP2V = WorldSpaceViewDir(v.vertex);o.worldP2S = WorldSpaceLightDir(v.vertex);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.uv);float3 worldtangent = normalize(i.worldTangent);float3 worldbtangent = normalize(i.worldBTangent);float3 worldp2s = normalize(i.worldP2S);float3 worldp2v = normalize(i.worldP2V);float3 worldnorm = normalize(i.worldNormal);float worldhalf = normalize(worldp2v+worldp2s);float ndots = max(0,dot(worldnorm,worldp2s));float sdotbt = max(0,1-abs(dot(worldp2s,worldbtangent)));float3 light = _LightColor0.rgb*_LightFactor;float3 diffuse = _LightColor0.rgb*ndots*_DiffuseFactor;float3 specular = _LightColor0.rgb*pow(sdotbt,_SpecularGloss)*_SpecularFactor;col*=fixed4(light+diffuse+specular,1);return col;}ENDCG}}
}

效果如下:

脑海里思考一下就能想象到1-dot(btangent,lightdir)可以形成“光环带”,“光环带”的大小和位置随太阳光朝向而变化。

   2.BTangent dot ViewDir

float vdotbt = max(0,1-abs(dot(worldp2v,worldbtangent)));
float3 specular = _LightColor0.rgb*pow(vdotbt,_SpecularGloss)*_SpecularFactor;

如图:

因为我们用的viewdir,所以光环的大小和位置就只随maincamera的坐标y轴而变化了。

  3.BTangent dot HalfDir

float hdotbt = max(0,1-abs(dot(worldhalf,worldbtangent)));
float3 specular = _LightColor0.rgb*pow(hdotbt,_SpecularGloss)*_SpecularFactor;

如图:

三种感觉还是dot(btangent,lightdir)效果好一点。

PS:为了追求计算效率,我们要因地制宜,比如这里的btangent是normal和tangent通过cross计算得到的,如果我们一开始在建模工具(3dmax或blender)中将tangent翻转到btangent(也就是沿着发根到发梢方向),就免去了cross计算。当然如果我们通过贴图采样得到btangent,那就更好了,我们甚至可以通过btangent贴图制作各种定制化的”光环“效果。

下面实现一下官方推荐的kajiyakay光照:

Shader "CartoonHair/KajiyaKayHairShader"
{Properties{_MainTex ("Texture", 2D) = "white" {}_DiffuseFactor("Diffuse Factor",Color) = (1,1,1,1)_LightFactor("Light Factor",Color) = (1,1,1,1)_SpecularGloss("Specular Gloss",Range(0,100)) = 1_SpecularFactor("Specular Factor",Color) = (1,1,1,1)}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal : NORMAL;float3 tangent : TANGENT;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;float3 worldNormal : TEXCOORD1;float3 worldTangent : TEXCOORD2;float3 worldBTangent : TEXCOORD3;float3 worldP2S : TEXCOORD4;float3 worldP2V : TEXCOORD5;};sampler2D _MainTex;float4 _MainTex_ST;float4 _DiffuseFactor;float4 _LightFactor;float _SpecularGloss;float4 _SpecularFactor;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldTangent = mul(UNITY_MATRIX_M,v.tangent);o.worldBTangent = cross(o.worldNormal,o.worldTangent);o.worldP2S = WorldSpaceLightDir(v.vertex);o.worldP2V = WorldSpaceViewDir(v.vertex);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.uv);float3 worldnormal = normalize(i.worldNormal);float3 worldtangent = normalize(i.worldTangent);float3 worldbtangent = normalize(i.worldBTangent);float3 worldp2s = normalize(i.worldP2S);float3 worldp2v = normalize(i.worldP2V);float3 worldhalf = normalize(worldp2s+worldp2v);float ndotl = dot(worldnormal,worldp2s);float3 light = _LightColor0.rgb*_LightFactor;float3 diffuse = _LightColor0.rgb*ndotl*_DiffuseFactor;float3 specular = _LightColor0.rgb*pow(sqrt(1-pow(dot(worldbtangent,worldhalf),2)),_SpecularGloss)*_SpecularFactor;col*=fixed4(light+diffuse+specular,1);return col;}ENDCG}}
}

specular分量计算公式按照文档中推荐的来,效果如下:

我个人觉得官方推荐的计算公式看着比较舒服。接着我们改的稍微卡通化一点:

float specularpower = smoothstep(0.6,1,pow(sqrt(1-pow(dot(worldbtangent,worldhalf),2)),_SpecularGloss));
float3 specular = _LightColor0.rgb*specularpower*_SpecularFactor;

顺便用ps制作一张卡通的cartoon-hair-opaque贴图:

再看看效果:

是不是有点感觉了?当然更加先进的hair光照算法也是不少的,我们有兴趣google上到处逛逛资料和论文就能找到。

ok,我继续玩GTA5,估计通关了再写博客。

C for Graphic:卡通头发相关推荐

  1. 图形学基础|各项异性与头发渲染

    图形学基础|各项异性与头发渲染 文章目录 图形学基础|各项异性与头发渲染 一.前言 二.各向异性光照 2.1 各向异性光照现象 2.2 ShadingModel扩展 三.头发光照模型 3.1 Kaji ...

  2. 从《BLAME!》说开去——新一代生产级卡通真实感混合的渲染方案Maneki

    <BLAME!>是Polygon Pictures Inc.(以下简称PPI)创业33周年以来制作的第一部CG剧场电影,故事来自于贰瓶勉的同名漫画作品(中文译名为<探索者>或者 ...

  3. 经典ps教程600例 打造ps高手

    经典ps教程600例 打造ps高手 Photoshop CS魔术,制作神秘魔眼 Photoshop教程:制作熊熊的火焰在燃烧 Photoshop教程活用通道 Photoshop换头术巧妙修改闭眼照片 ...

  4. [经典收藏]1200个Photoshop经典实例打造ps高手!

    通道抠图之终极手腕 漂亮女人与颜色的唯美设计 Photoshop精彩文字特效:长根的树形字 AI结合PS制作:晚风中的芦苇丛 Photoshop图层遮罩做简单平面设计效果 Photoshop制作环形文 ...

  5. 【自学教程分享】UI设计/平面/网页/移动端/交互设计全套视频资源

    新手小白设计入门.零基础转行.设计师在职提升自学必备资源:     第一模块:手绘   游戏美术---手绘原画系列目录 第1节  手绘的用途 第2节  手绘-入门基础 第3节  手绘的学习方法 第4节 ...

  6. C for Graphic:卡通眼睛

    连续四天科目三练车,总算是要考试了,暂时休息一下,就来写一篇卡通眼睛渲染.眼睛的着色效果也是一大特色,所谓"双眼有神",也是视觉上的一个褒义特点. 这里我们看看卡通眼睛渲染的效果, ...

  7. C for Graphic:卡通光照

    最近出了个游戏很火,叫原神,我特意下载玩了几天,可以说除了内容不好玩之外(这也是传统内购网游的通病,和一次性付费就能获取小说电影般体验的3A大作不一样,网游必须通过不断的重复性内容延长运营时间.还得通 ...

  8. 【卡通渲染】【URP】【头发渲染-各向异性高光】

    效果图 用来做头发上的光泽 这个又叫做天使环 备注 各向异性引入切线来计算光照 代码 Shader "DC/CelShading/CelShading" {Properties{_ ...

  9. Photoshop制作一只可爱的卡通小鸟

    这篇photoshop教程介绍卡通小鸟的制作方法.真个制作过程并不复杂.大致了解物体构造以后,然后分开来制作,如把头部,身体,翅膀等分开制作,每一部分注意好高光及暗调的渲染即可. 最终效果 1.新建一 ...

最新文章

  1. python3中map函数_解决Python3下map函数的显示问题
  2. 利用go语言创建web server的两种方式
  3. oracle---函数(trunc,nvl,nvl2)
  4. log4net在WinForm和ASP.net下的设置
  5. 为什么你写的拦截器中不能注入Java bean?
  6. leetcode —— 1079. 活字印刷
  7. JQuery弹出菜单时禁止页面(body)滚动
  8. Java层Binder使用(ServiceManager)
  9. Postman Request Payload发送请求
  10. 转:awakeFromNib/loadView/viewDidLoad总结
  11. 阶段3 1.Mybatis_12.Mybatis注解开发_6 mybatis注解开发一对一的查询配置
  12. 手机号码归属地查询数据库下载
  13. sl400通过ac无法连接psk加密无线网络
  14. VMware的linux虚拟机玩耍 [2] (环境配置与一些软件安装)
  15. CUDA中的线程层次
  16. 助力篇|常见金融风控数据分析内容汇总,助你面试道路畅通无阻
  17. 做需求分析师的几点困惑
  18. 2019年必看最新创意手机聊天界面设计
  19. apple tv 开发_如何在Apple TV上观看直播电视
  20. SSD固态硬盘的相关知识和选购

热门文章

  1. 一失脚为千古恨,再回头一百年人
  2. android camera textureview,textureview_learn
  3. LCD工控液晶触摸屏贴合如何进行贴合工程?
  4. mfcc计算 java_MFCC特征提取详细计算过程
  5. html中热点怎么写,HTML中给图片添加热点
  6. Android图片切片热点区域点击
  7. 人生感悟:信仰的真谛
  8. 我的世界java最新更新_我的世界21w07a
  9. 高德地图路径规划接口计算出发地与目的地的通行时间计算
  10. 蚂蚁感冒,蓝桥杯,简易AC代码讲解