unity3d Human skin real time rendering 真实模拟人皮实时渲染
先放出结果图片。。。由于网上下的模型是拼的,所以眼皮,脸颊,嘴唇看起来像存在裂痕,解决方式是加入曲面细分和置换贴图 进行一定隆起,但是博主试了一下fragment shader的曲面细分,虽然细分成功了但是着色效果变的很奇怪,这里就不用曲面细分了,大家如果有在fragment shader上用曲面细分的好办法,可以的话请告诉我
参数设置1
参数设置2
细致到毛孔的高光
次表面散射的耳朵
人皮渲染是十多年的课题了,人们想尽一切办法想让其变得真实可信,大型3A级次时代游戏近来做的又来越真实了如《罗马之子》,他们的皮肤自称已经超过了NVIDIA的例子
这是在2005年SIGGRAPH的多层皮肤渲染,他们的参数都是经过精密的医学上的测量的,而且渲染花费了5分钟的时间。。。
研究这个找了许多资料,在结合之前的知识弄出了一个看起来还算入眼的人皮
本例做到了以下几点
1. 次表面散射
2. 基于物理的渲染
包括specular和brdf等等,brdf我用了一张贴图调整曲率来代替,specular在之前这篇文章有详细讲解链接在此
3. 法线模糊
等等之类。。。
为什么皮肤渲染这么难?
1. 大多数的漫反射光来自次表面散射
2. 皮肤颜色主要来自上表皮
3. 粉或红色主要为真皮中的血液
此图为人皮的组成模拟,人有好多层表皮,这就说明在真实情况下要进行数次折射与反射,这就更难达到真实
光的折射与反射
上图直观的表明了光线“被怎么样了”
光线接触到皮肤时,有大约96%被皮肤各层散射了,只有大约4%被反射
再说specular,人的皮肤会出油,所以就会有反射,但是人的皮肤不能像镜子那样反射,因为人的皮肤是粗糙的,在这种情况下用基于物理的(physically based)方法就最好不过了,没了解过physically based的看官们可以先了解下这篇文章和上面的一样
使用了之前试出效果最好的的方法,也就是使命召唤2中用到的的方法,同时试了下beckmann的方法,但是效果并不好,phong等方法也没有试
这里,我们的实现方法是这样的:
<span style="font-size:14px;"> /*
*this part is compute Physically-Based Rendering
*the method is in the ppt about "ops2"
*/ float _SP = pow(8192, _GL);
float d = (_SP + 2) / (8 * PIE) * pow(dot(n2, H), _SP);
float f = _SC + (1 - _SC)*pow(2, -10 * dot(H, lightDir));
float k = min(1, _GL + 0.545);
float v = 1 / (k* dot(viewDir, H)*dot(viewDir, H) + (1 - k)); float all = d*f*v;
float3 refDir = reflect(-viewDir, n2);
float3 ref = texCUBElod(_Cubemap, float4(refDir, _nMips - _GL*_nMips)).rgb;</span>
然后发现尽管gloss调到最大也没有达到我们预期的那种效果,
又进行了 “智能补光”
也就是常规的求高光的方式,我们在此加入了高光贴图,不让不该高光的地方(如眉毛)产生高光
float specBase = max(0, dot(n2, H));
float spec = pow(specBase, 10) *(_GL + 0.2);
spec = lerp(0, 1.2, spec);
float3 spec3 = spec * (tex2D(_SpecularTex, i.uv_MainTex) - 0.1);
spec3 *= Luminance(diff);
spec3 = saturate(spec3);
spec3 *= _SpecularPower;
光经过哪,就带一部分那里的颜色,可以发现光从入射到出射,位置和方向都变了
光走的路径数量是无穷大,光反射回来的都为漫反射,油脂表面的透明度也都是不一样的,
这就产生了次表面散射
NVIDIA在GDC2007年的演讲中提到把图像blur个六遍达到柔和的次表面散射效果
每次blur都是在不同的颜色通道以不同的范围和程度进行blur
由于我们的贴图是这样的“高配”
用在本例上会丢失少许本来贴图上的细节,但是确实有一定的次表面散射效果,各位看官自行取舍,而且千万不要只做高斯模糊,这样的话细节会丢失更多,而且没有什么次表面散射的感觉
为了节省花销,省去了ppt中的rendering时blur,直接在ps上做了6张高斯模糊的贴图放入material,并线性混合
float3 c = tex2D(_MainTex, i.uv_MainTex) * 128;
c += tex2D(_BlurTex1, i.uv_MainTex) * 64;
c += tex2D(_BlurTex2, i.uv_MainTex) * 32;
c += tex2D(_BlurTex3, i.uv_MainTex) * 16;
c += tex2D(_BlurTex4, i.uv_MainTex) * 8;
c += tex2D(_BlurTex5, i.uv_MainTex) * 4;
c += tex2D(_BlurTex6, i.uv_MainTex) * 2;
c /= 256;
我们同时也起到重要作用的是边缘光rim和brdf,
使用了BRDF最明显的好处是,Brdf贴图间接控制了明暗交界线的颜色,可通过曲率控制,模拟了光与阴影交界处光对皮肤的反射与折射,如果全黑的话说明光只是普通的漫反射。
而且使人皮有了次表面散射的质感
/*
*this part is to add the sss
*used front rim,back rim and BRDF
*/ float3 rim = (1 - dot(viewDir, n2))*_RimPower * _RimColor *tex2D(_RimTex, i.uv_MainTex);
float3 frontrim = (dot(viewDir, n2))*_FrontRimPower * _FrontRimColor *tex2D(_FrontRimTex, i.uv_MainTex); float3 sss = (1 - dot(viewDir, n2)) / 50 * _SSSPower;
sss = lerp(tex2D(_SSSFrontTex, i.uv_MainTex), tex2D(_SSSBackTex, i.uv_MainTex), sss * 20)*sss; fixed atten = LIGHT_ATTENUATION(i);
float curvature = length(fwidth(mul(_Object2World, float4(normalize(i.normal), 0)))) /
length(fwidth(i.worldpos)) * _CurveScale; float3 brdf = tex2D(_BRDFTex, float2((dot(normalize(i.normal), lightDir) * 0.5 + 0.5)* atten, curvature)).rgb;
对于rim的话添加了前向rim和后向rim其实本质上还是rim,后向rim使用了白色的图片产生一种玉质的感觉(好吧其实更像羊羹),前向rim使用了红色的图片,相当于添加了光线在血液层的散射,让人的脸蛋有了真实的血色
这是次表面散射的结果:
光源在嘴里
像不像把手指或者耳朵放在手电筒前面的那种效果?那就是次表面散射
需要一张Intense strips贴图来混合原有颜色,方法就是在点光源情况下,求出当前点与点光源的距离,距离越近就越亮
关于法线,
用了一种新的混合方式,这样能保有更多法线细节,
这里简单讲解一下法线混合,
float3 n1 = tex2D(texBase, uv).xyz*2 - 1;
float3 n2 = tex2D(texDetail, uv).xyz*2 - 1;
float3 r = normalize(n1 + n2);
return r*0.5 + 0.5;
大家可能用过这种方式来混合两个法线贴图,这种线性的方式折中了两个贴图,得到的细节权重是平均的,效果并不好,得到的是这样的结果
改进了一下,变成了覆盖混合
float3 n1 = tex2D(texBase, uv).xyz;
float3 n2 = tex2D(texDetail, uv).xyz;
float3 r = n1 < 0.5 ? 2*n1*n2 : 1 - 2*(1 - n1)*(1 - n2);
r = normalize(r*2 - 1);
return r*0.5 + 0.5;
就是法线1的法线比较深的地方,就多一些权重,比较浅的地方就被法线2适当覆盖,但是这样效果还是不够真实
在GDC2012的Mastering DX11 with unity中讲到了一种官方的办法如下:
float3x3 nBasis = float3x3(
float3(n1.z, n1.y, -n1.x), //绕着y轴+90度旋转
float3(n1.x, n1.z, -n1.y),// 绕着x轴-90度旋转
float3 (n1.x, n1.y, n1.z )); n = normalize (n2.x*nBasis[0] + n2.y*nBasis[1] + n2.z*nBasis[2]);
得到的结果是这样的,是不是好了许多?
双方的细节程度都有很多提升,
他们用了一个basis来变换第二法线。具体可以看 这篇文章—链接
用
AutoLight.cginc里定义的一个函数LIGHT_ATTENUATION求出光的衰减atten,atten在directional
light中固定是1,在点光源中才有衰减效果,因为directional light在unity中是没有位置区别的,在哪里都一样。
fixed atten = LIGHT_ATTENUATION(i);
对于细节方面,如毛孔,在本例的贴图和法线贴图都很细致,已经包括毛孔和皮肤的纹路,如果贴图精度低还想要高细节的话,可以再贴上细节
全部可设置变量:
全部代码已共享至GitHub链接
---- by wolf96
unity3d Human skin real time rendering 真实模拟人皮实时渲染的更多相关文章
- unity3d Human skin real time rendering 真实模拟人皮实时渲染(转)
先放出结果图片...由于网上下的模型是拼的,所以眼皮,脸颊,嘴唇看起来像 存在裂痕,解决方式是加入曲面细分和置换贴图 进行一定隆起,但是博主试了一下fragment shader的曲面细分,虽然细分成 ...
- unity3d Human skin real time rendering with blood and water drop effect真实模拟人皮实时渲染之血液和水珠掉落效果
在之前的一篇(链接在此)文章中写了下关于真实模拟皮肤渲染,在此基础之上又想加上血液效果,在洗澡的时候(= =:)又想在skin上加上水珠的效果,所以研究了下,做出来效果感觉还不错,放下效果图: 水珠 ...
- unity3d Human skin real time rendering plus 真实模拟人皮实时渲染 plus篇
最近逃课做游戏,逃的有几门都要停考了,呵呵呵,百忙之中不忘超炒冷饭,感觉之前的人皮效果还是不够好,又改进了一些东西 首先上图 放大看细节 显而易见的比上次的效果要好很多,此次我把模型用3dmax进行了 ...
- Unity3d 屏幕空间人体皮肤知觉渲染&次表面散射Screen-Space Perceptual Rendering & Subsurface Scattering of Human Skin
之前的人皮渲染相关 前篇1:unity3d Human skin real time rendering 真实模拟人皮实时渲染 前篇2:unity3d Human skin real time ren ...
- 结合 CSS3 & Canvas 模拟人行走的效果
HTML5 和 CSS3 技术给 Web 带来了新的利器,点燃了 Web 开发人员的激情.所谓只有想不到,没有做不到,的确如此.下面给大家分享一个结合 CSS3 & Canvas 模拟人行走的 ...
- DirectUI中模态对话框和菜单的原理(自己控制整个Windows消息循环。或者,用菜单模拟窗体打开时用SetCapture取得控制权,一旦窗体收到WM_CAPTURECHANGED消息就把窗体退出)
经常有人问关于模态对话框和系统菜单内部实现原理方面的问题, 因为系统通过API隐藏了太多细节,这2个问题确实令初学者甚至是有经验的开发者困扰, 下面是我个人的一些经验总结. 先说模态对话框,外部看模态 ...
- python利用requests库模拟post请求时json的使用
我们都见识过requests库在静态网页的爬取上展现的威力,我们日常见得最多的为get和post请求,他们最大的区别在于安全性上: 1.GET是通过URL方式请求,可以直接看到,明文传输. 2.POS ...
- unity3d Hair real time rendering 真实头发实时渲染
先放上效果 惊现塞拉酱 算法是Weta Digital根据siggraph2003的论文加以改进,改进之前使用的是Kajiya and Kay’s 模型,它能量不守恒,也就是说不是基于物理的,不准确 ...
- unity3d Hair real time rendering 真实头发实时渲染(转)
惊现塞拉酱 算法是Weta Digital根据siggraph2003的论文加以改进,改进之前使用的是Kajiya and Kay’s 模型,它能量不守恒,也就是说不是基于物理的,不准确 电镜下真实头 ...
随机推荐
- .NET设计模式(6):原型模式(Prototype Pattern)
):原型模式(Prototype Pattern) ); //使用颜色 string colorName = "red"; C ...
- SQL查询一些浅薄的结论
一些简单的测试结论 在本机经过一些简单的测试,记录数6W条,得出以下结论,不同的硬件环境和数据记录数,可能会有不一样的结论 1.in, or, exists, like, not in , not e ...
- Python:文件操作
#!/usr/bin/python3 str1 = input("请输入:") print("你输入的是:",str1) f=open("abc.tx ...
- ZOJ 1076 Gene Assembly(LIS+路径打印 贪心)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=76 题目大意:在一个DNA上,给定许多基因的起始位置和结束位置,求出这 ...
- c语言字符数组与字符串的使用详解
转自:http://www.jb51.net/article/37456.htm 1.字符数组的定义与初始化字符数组的初始化,最容易理解的方式就是逐个字符赋给数组中各元素.char str[10]={ ...
- demo_02 less
html 中的代码<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> &l ...
- [转] 属性选择器.mark
CSS 2 引入了属性选择器. 属性选择器可以根据元素的属性及属性值来选择元素. 简单属性选择 如果希望选择有某个属性的元素,而不论属性值是什么,可以使用简单属性选择器. 例子 1 如果您希望把包含标 ...
- 移动端消除click事件的延迟效果
https://github.com/Plaputta/jquery.event.special.fastclick 用fastclick事件,类似zepto的tap事件,若想去除连点效果,可在外层显 ...
- python 包导入规则
python 包导入规则,恶心了一天,终于搞清楚了 1.目录 speed data __init__.py __init__.py static templates view __init__.py ...
- 【转】TypeScript中文入门教程
目录 虽然我是转载的,但看在Copy这么多文章也是很幸苦的好吧,我罗列一个目录. 转载:<TypeScript 中文入门教程> 17.注解 (2015-12-03 11:36) 转载:&l ...