此篇文章参考 Hair Rendering and Shading
地址: https://web.engr.oregonstate.edu/~mjb/cs519/Projects/Papers/HairRendering.pdf
另一篇:http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/Scheuermann_HairSketchSlides.pdf
感兴趣的小伙伴可以直接查看原版。

效果:

概述:
使用多段面片实现ui头发的渲染
着色器使用Kajiya-Kay和Marschner的物理光照混合实现
简单的近似深度排序方案

头发在视觉上很重要,大部分人头上拥有10w-15w的发丝,许多不同的发型,最终幻想 - 灵魂深处》总渲染时间的约 25% 花费在主角的头发上

为什么我们选择多边形头发模型而不是绘制线?
几何复杂度低于线的渲染
深度排序更快
契合我们使用到的渲染管线

头发模型的创作
使用贴片模拟头发的体积,这样可以节约大量的面数
使用近似自阴影的环境光遮蔽

需要的纹理贴图:
基础纹理贴图,头发的基础色,纵向拉伸的noise贴图

半透明贴图 其实一般都会设置到基础颜色贴图的a通道,用于裁剪剔除
高光偏移贴图和高光扰动noise贴图

渲染实现:
基于Kajiya-Kay光照模型

使用了各向异性光照
计算反射的角度不再使用法向N而是改为沿着头发朝向的Bitangent(不是图片中的tangent,tangent在unity中生成,是基于模型uv的u方向,而一般头发图片的制作是垂直排布,也就是v方向)
直接光镜面反射实现使用到了blin-phong 半角向量 (光朝向和眼睛朝向相加,和物体朝向点乘,计算夹角作为高光强度,算头发不用法向用副切线)

要考虑到头发的散射特性
使用了Marschner里面的双高光,主高光接近发梢,次高光接近发根(并且是彩色的)
使用一些特征来模拟观察到的效果。

Shader 实现:
顶点着色器向片元传入 法线 切线 视角方向 主光源方向 环境光遮蔽

片元着色器:
Kajiya-Kay的漫反射实现 sin(T,L)太亮了,我看了一下下面代码,是这么做的

lerp (0.25, 1.0, dot(normal, lightVec)

高光呢,添加了一个偏移切线位置的方法

镜面反射
我们使用半角向量和切线方向点乘计算得出方向遮挡
然后使用三角函数求出强度

当我在项目里面一步步测试的时候,突然发现,unity竟然内置了相关代码

所以,我们直接用内置的就行了,下面我贴一下片元着色器代码:

half4 Fragment(Varyings input, float face : VFACE) : SV_TARGET
{UNITY_SETUP_INSTANCE_ID(input);HairSurfaceData sfd = InitializeSurfaceData(input.uv);half3 V = SafeNormalize(input.viewDirWS);half3 N = input.normalWS.xyz;half3 T = input.tangentWS.xyz;float sgn = input.tangentWS.w;      // should be either +1 or -1half3 B = sgn * cross(input.normalWS.xyz, input.tangentWS.xyz);N = TransformTangentToWorld(sfd.normalTS, half3x3(T, B, N));N = NormalizeNormalPerPixel(N);// N = face > 0 ? N : - N;Light mainLight = GetMainLight();half3 L = mainLight.direction;half3 LightColor = mainLight.color;half atten = mainLight.shadowAttenuation;//----------------------------------Direct Diffuse 直接光漫反射----------------------------------half diffTerm = max(0.0, dot(N, L));half halfLambert = (diffTerm + 1.0) * 0.5; //让主光源也影响一些间接光的效果half diffuse = saturate(lerp(0.25, 1.0, diffTerm * atten));half3 directDiffuse = diffuse * LightColor * sfd.albedo;//----------------------------------Direct Specular 直接光镜面反射----------------------------------half2 anisoUV = input.uv * _AnsioMap_ST.xy + _AnsioMap_ST.zw;half anisoNoise = SAMPLE_TEXTURE2D(_AnsioMap, sampler_AnsioMap, anisoUV).r - 0.5;half3 H = normalize(L + V); //半角向量//spec1float3 specColor1 = _SpecColor1.rgb * sfd.albedo * _SpecColor1.a * atten * LightColor;float3 t1 = ShiftTangent(B, N, _SpecOffset1 + anisoNoise * _SpecNoise1);float3 specular1 = specColor1 * max(D_KajiyaKay(t1, H, _SpecShininess1), 0.0);//spec2float3 specColor2 = _SpecColor2.rgb * sfd.albedo * _SpecColor2.a * atten * LightColor;float3 t2 = ShiftTangent(B, N, _SpecOffset2 + anisoNoise * _SpecNoise2);float3 specular2 = specColor2 * max(D_KajiyaKay(t2, H, _SpecShininess2), 0.0);half3 directSpecular = specular1 + specular2;//环境光 漫反射half3 env = SampleSH(N) * sfd.albedo;//环境光 镜面反射half3 reflectVector = reflect(-V, N);half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, _Roughness, 1.0) * sfd.albedo;half3 color = directDiffuse + directSpecular + env + indirectSpecular + sfd.emission;// color.rgb = diffTerm;return half4(color, sfd.alpha);
}

排序问题
对于半透明的物体,需要从后向前渲染保证渲染的正确性
对于有头发的头,这和头发从内向外渲染很相似。这个可以在制作模型的时候,内部的顶点坐标往前放,外部的顶点坐标向后放,主要是索引的顺序要正确。

接下来看一下他们的解决方案:
按照下面的顺序去渲染,分4个pass (深度写入,不透明,半透明背面,半透明正面)

  1. 第一个pass,使用alphaTest剔除半透明像素,禁用背面剔除,写入深度,深度检测为less,不需要渲染颜色,只需要写入深度。
  2. 第二个pass,进行完整的头发像素渲染,禁用背面剔除,禁用深度写入,深度检测为 Equal,用来绘制不透明部分的表面。
  3. 第三个pass,用于绘制半透明背面,剔除正面渲染,不写入深度,深度检测为less。
  4. 第四个pass,半透明正面渲染,剔除背面,深度写入,深度检测为less,启用深度写入可以防止不正确的深度顺序。

解决方案的优缺点:
优点:
几何复杂度低 深度排序更快 兼容低端设备

缺点:
有动画会出现深度问题
马尾之类的需要单独处理
不适合所有类型的头发

unity urp 实现头发渲染相关推荐

  1. unity urp 实现丝绸渲染

    首先看一下实际上真实的效果 再来一张 这是专门去找的. 可以看到丝绸渲染使用了各向异性的GGX去实现,有点仿头发的感觉,接下来看一下怎么实现的. 首先,准备实现双向反射率分布函数(BRDF)的DVF项 ...

  2. unity urp 棉麻织物渲染

    我在前一篇写了对于衣服和硬表面材质的区别.这一篇来实现一下正常的棉麻类的渲染实现. 首先,说一下棉麻类的衣服的特点. 棉麻类的布料是由线组成的,也就是一根根的线织出来的,所以它是相对来说比较平整的结构 ...

  3. [Unity/URP学习]风格化水体渲染(一)

    风格化水体的实现内容 文章目录 风格化水体的实现内容 风格化水体实现过程 1.水体颜色 1.1风格化水体颜色渐变 1.2水体深浅区域 1.2.1开启深度纹理 1.2.2深度纹理采样 1.3水体透明度 ...

  4. Unity URP中的多Pass Shader和Planer shadow

    一 .Unity移动端软阴影技术总结: https://blog.csdn.net/jxw167/article/details/82422891 二. 平面阴影的原理 https://zhuanla ...

  5. system volume information是什么文件_如何扩展Unity URP的后处理Volume组件

    Unity在更新到Unity2019.4之后,大家或许已经发现,在使用URP(通用渲染管线)的情况下,Unity原来的Post Processing插件好像不起效了.原来Unity在Unity2019 ...

  6. Unity URP入门实战

    导读 本文讲述 如何从应用层面使用URP 如何在代码层面为URP增加更多的渲染特性 如果拓展URP的后处理效果 URP管线特性 光源数量: 直线光外加4个其他光源 内置管线的多Pass Forward ...

  7. Unity URP DOTS Pathfinding+Animation 10000个单位

    Unity URP DOTS Pathfinding+Animation 10000个单位 头发不知道掉了多少,猪脑过载

  8. unity URP内置shader lit解析

    unity内置的pbr渲染shader Properties为shader相关属性 两个SubShader里面为相应的渲染内容,第二个为降级处理渲染,如果第一个SubShader不兼容,才会渲染第二个 ...

  9. Unity - URP RenderFeature - 实现类似多 Pass 的 XRay: Rim、Pattern

    文章目录 环境 XRay : Rim, Pattern, Pattern+Rim 在 Built-RP 中 在 URP 中 Shader 脚本 效果 Pattern URP RendererFeatu ...

最新文章

  1. html页面怎样禁止复制粘贴,javascript中如何禁止复制粘贴?
  2. 机器学习需要理解的五个基本概念
  3. reviewboard搭建
  4. linux c显示日期,Linux C判断日期格式是否合法
  5. 生活随笔:大学需要确立自己的方向
  6. 索尼服务器维护时间,索尼云服务器
  7. Python爬虫——爬取Python岗位的那些事
  8. 首次亮相!法拉第未来公布FF 91内饰图:贾跃亭心血没白费
  9. post 和 get 网站
  10. ITIL4 讲解:监控管理
  11. 软件工程领域2021年上半年的CCF-A和B类会议列表
  12. Controller中使用swagger注解的正确姿势
  13. zyf的童年(异或运算的运用)
  14. 转换接头PL8000V-B 0-70MPa
  15. ms office excel2013教程 - 从网站加载数据
  16. java检索电脑的所有图片_查找电脑里重复的照片
  17. 【2016浙江省赛:区间取模】E : Modulo Query | ZOJ - 3940
  18. p16panda合并concat
  19. Java字符串使用Split以竖线作为分隔符
  20. 固定宽度柱状图添加固定宽度的背景和选中阴影~echarts奇奇怪怪系列

热门文章

  1. 傲慢与偏见——程序员想让HR知道的七件事
  2. 学习 React 17 系统精讲 结合TS打造旅游电商平台
  3. 表达式、逻辑结构、方法
  4. Vivado编译报错:[Place 30-574] Poor placement for routing between an IO pin and BUFG.
  5. 明日之后1月14日服务器维护,《明日之后》1月14日更新内容汇总 1月14日新增内容介绍...
  6. 试图5天学会python——Mooc 实例
  7. 【企业】人性与管理:经典语录摘要
  8. 空调维修加氟维修移机制冷安装服务
  9. 靶机渗透练习51-KB-VULN3
  10. OpenCV函数汇总