unity urp 实现衣服绒毛效果

实现衣服的绒毛效果,主要就是要模拟出一根根毛发的效果。这种效果对动物身上的短毛也同样有效果。实现方式主要是多层渲染,然后再通过一张noise渐变图,根据显隐进行剔除,来模拟出来绒毛向外生长的效果。
在这里插入图片描述
以上图片截取自:https://xbdev.net/directx3dx/specialX/Fur/index.php 用来展示了多pass渲染模拟出的绒毛效果。
其它方式还有一种是填充几何的方式,通过在表面添加额外的几何体,来实现模拟绒毛的效果。如果大家感兴趣,可以去https://github.com/hecomi/UnityFurURP 这个链接里面拉一下代码,看一下大佬的实现效果。

接下来我列一下实现这种短毛的方式:

  1. 直接修改模型,将默认模型复制多遍,然后通过设置层级实现多pass层级的效果,进行渲染。(推荐这种方式,因为这种方式可以记录每个pass的深度信息,提高最终渲染的效果)
  2. 使用多pass渲染,根据法向进行法向外扩,这种是在默认的渲染管线中实现方式。由于urp不支持多pass,那么这个多pass需要使用renderFeature去实现。
  3. 使用几何着色器或者曲面细分着色器去实现,可以去上面的链接看一下。

这里我使用的模型的方式,直接使用模型,可以在做ssao和屏幕阴影的时候,会有更好的效果。其实,像多pass也是这个道理,只是拿着模型多层渲染,但是,多pass无法将深度写入,也就最后渲染出来的效果上看上去没有那么好。

首先,将模型导入3dmax,由于模型导入到3dmax以后,层级会发生变换,我们需要额外创建一个层级,然后将它的轴向修改为y轴朝上。注意,添加了爷爷层级以后,需要在模型里面蒙皮里面,将父节点加入。
在这里插入图片描述
在模型编辑器里面的制作是为了实现模型的多次复制,然后将其顶点颜色修改进行分层,比如,最低层的使用颜色为0,最外层的颜色为1,中间就线性过渡就好。
我这里使用了一个工具,可以快速实现模型的复制。
在这里插入图片描述
首先点击可编辑多边形,然后在场景选中需要编辑的模型,然后在工具上点击check,用于检测当前模型是否可以实现多pass,如果提示可以,那么,直接process即可。
然后放到场景可以发现,它的顶点色的r通道被修改掉了。
然后将模型导入到unity中
在这里插入图片描述
这件衣服的三角面数也从之前的3W+膨胀到了60W面,证明我们成功了。
注意,我处理完成以后发现了好像没有自动平滑,需要手动去点一下自动平滑。

接下来就是shader的实现,首先我们要通过法线外扩,将多层的模型分开。

float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
positionWS += normalInput.normalWS * input.color.r * _FurLength * 0.01;
output.positionWS = positionWS;
VertexPositionInputs vertexInput = GetVertexPositionInputs(TransformWorldToObject(positionWS));
output.shadowCoord = GetShadowCoord(vertexInput);
output.positionCS = vertexInput.positionCS;

我这里先获取到世界空间坐标,然后在世界空间坐标系下进行发现外扩。FurLength就是外扩的最大距离,因为设置了颜色,所以可以根据颜色值强度,自动生成外扩范围。

外扩完成后,我们要实现上面提到的那种毛发效果,最简单的方式就是使用一张贴图去实现。
在这里插入图片描述
比如这种,刚好符合。设置可以修改它的tillingoffset,来修改密度。

saturate(SAMPLE_TEXTURE2D(_FurPatternMap, sampler_FurPatternMap, UV * _FurPatternMap_ST.xy + _FurPatternMap_ST.zw).r - input.furLayer);

我们用获取的颜色值去减去在顶点上设置的颜色强度,这样会形成,越在内层的面片的不透明度越高,越向外,透明度越高。最终会显示的效果如下:
在这里插入图片描述
这样可以粗略的模拟出绒毛的效果。
接下来处理最下面的那层基础的衣服不显示的问题,我们使用step以0.01进行区分,最下面一层是0,比0.01的值小的alpha直接使用1,比0.01大的我们还是使用之前的结果。

furAlpha = lerp(furAlpha, 1.0, step(input.furLayer, 0.01));

这样,最下面一层的渲染就不会被剔除掉了
在这里插入图片描述
然后再加一个值去单独控制一下绒毛的强度的,颜色强度也开方一下,让过渡不要那么线性。

half furAlpha = saturate(SAMPLE_TEXTURE2D(_FurPatternMap, sampler_FurPatternMap, UV * _FurPatternMap_ST.xy + _FurPatternMap_ST.zw).r * 2
- input.furLayer * input.furLayer * _EdgeFade);

在这里插入图片描述
效果看上去更好了
在这里插入图片描述
换一张的效果,更加明显,毛发效果。

接下来,就是朝向的问题,我们这样实现出来,毛发都是竖直的,没有一点弯曲,可以设置一个朝向,让毛发朝向一个方向弯曲。

half2 furUV = UV * _FurPatternMap_ST.xy + _FurPatternMap_ST.zw + _FurDiection * input.furLayer * input.furLayer;

我们使用一个二维的向量的值,去影响uv的采样位置,来修改它的方向。
在这里插入图片描述
我们也可以用一张flowmap贴图,去控制毛发朝向,让毛发的朝向显得更随机性一些。

half2 fruFlowUV = UV * _FurFlowMap_ST.xy + _FurFlowMap_ST.zw + _TimeParameters.x * _FurWind * 0.01;
half2 furFlow = SAMPLE_TEXTURE2D(_FurFlowMap, sampler_FurFlowMap, fruFlowUV).rg;
furFlow = (furFlow * 2 - 1) * _FurWindIntensity * input.furLayer * input.furLayer;
half2 furUV = UV * _FurPatternMap_ST.xy + _FurPatternMap_ST.zw + _FurDiection * input.furLayer * input.furLayer + furFlow;
half furAlpha = saturate(SAMPLE_TEXTURE2D(_FurPatternMap, sampler_FurPatternMap, furUV).r * 2 - input.furLayer * input.furLayer * _EdgeFade);
furAlpha = lerp(furAlpha, 1.0, step(input.furLayer, 0.01));
baseAlpha *= furAlpha;

为了让这张图动起来,可以用time去扰动flowmap的uv,实现那种波浪的效果。
在这里插入图片描述
做到这里,毛绒绒的感觉已经很棒了。接下来,我们还能继续优化,就是把毛的层级感觉体现出来,让越底层的毛发暗一些。

half Occlusion = lerp(_OcclusionStrength, 1.0, input.furLayer);

这里,我把occlusion修改成了限制底层最小值的ao,这样可以实现对ao的层级修改,防止一个位置的垂直方向大家的颜色都一样。
在这里插入图片描述
明暗效果明显

接下来,到了重点了,就是为什么要用dcc生成的模型,那是我们是为了要用模型生成深度信息,如果你是在renderFeature里面去做,是没有多pass的深度和法向的,效果肯定不如这个。
在这里插入图片描述
通过帧调试器,我们发现,绒毛的深度没有,那是因为深度法向渲染还是使用之前的,我们需要将深度法向pass的代码也修改掉。将法向外扩顶点和剔除加入进去。
在这里插入图片描述
在这里插入图片描述
好深度和法向都有了,大家记得将阴影pass也修改掉。
好了,分享就到这了。

猜你喜欢

转载自blog.csdn.net/qq_30100043/article/details/127631778
今日推荐