【流程向】模型复原与Unity渲染

项目简述

简单记录下学校里的一个项目,涉及到对/何家村遗宝/的模型复原,记录一下模型制作的全流程,同时涉及到Unity中一些优化画面的技术点。项目中渲染效果优先,没有怎么考虑性能。

流程:Blender高低模与展UV -> Substance Painter贴图制作 -> PS贴图编辑 -> Unity渲染


Blender高低模与展UV

此次项目之前DCC使用的一直是C4D,借着这次机会学习了一波Blender,这部分涉及的内容均是一些备忘技巧。(参考视频在后面)

  • 一些好用的Add-ons,从名字应该能大概了解到用途:
  1. Object: Bool Tool; 
  2. Mesh: LoopTools; 
  3. Mesh: AutoMirror;
  4. Import-Export: Import Image as Planes;
  • Object关于平面镜像(无修改器):
  1. Shift+C,游标归位原点
  2. 选中被镜像的物体,Shift+D复制
  3. Pivot Point设为3D_Cursor
  4. 选中复制出来的物体,Control+M,拖动鼠标中键镜像
  • 内置雕刻笔刷的适用情景(个人习惯)
  1. Blob -> 可用于浮雕等凸起平面,反向凹陷
  2. Pinch -> 捏边,增加细节,及时Control+R平均布线
  3. Grab -> 大体修形
  4. Inflate -> 对凸起内容进行膨胀,鼓起,增加体积,反向同理
  5. 注意:使用Layer、Clay等笔刷时小心模型背面,如果太薄可能编辑前面时同时受到影响。

  • Blender工作流

        首先低面体建模之前设置一下视图的渲染,有效提升幸福感(确信

        好像比较规范的高低模工作流是使用Multi-Resolution Modifier,因为没有来得及细研究,并且项目只涉及到引擎用的低模和烘焙用的高模,所以对于上面的牛来说,直接由高模添加Remesh修改器,使用其中的Sharp项更好的保留细节;对于左边的马来说,主体部分直接使用低面体加表面细分修改器作为低模,雕刻信息交由贴图烘焙。

        UV展开的比较草率,尽量保证了接缝处在看不到的地方,并没有苛求通过缩放来最大程度填满uv,painter里直接出高分辨率贴图来填补,也没有管uv拉伸的程度。此外,由于UV组还没有搞明白,像是牛鼻子这些部件实际上是另外的一个模型,本质上在Unity中一个模型Prefeb里是由好几个分开的mesh组成的。

        雕刻部分应该只是刚能雕出东西的水平。。上面的马高模细节并没有很多,却搞了700万个顶点出来,进入雕刻模式要卡一下,要是手滑Tab进了编辑模式要20G的内存占用,M1Pro的16G内存可以说是完全不够用,疯狂Swap,一个星期没关机看硬盘读写有1.4T。。

Substance Painter 贴图制作

        绘画流程对于一个不会美术的人来说可以说是很痛苦了,好在大多可以通过一些讨巧的手段获得还不错的效果。以下面这个马的主体为例。

        这个壶的主体是一个没有什么细节的简单模型,直接使用雕刻好的高模主体烘焙贴图,会得到与马有关的Normal,AO,Curvature,Thickness等信息。不过注意,此时AO是不会像上图中一样有链条等遮挡信息。保存当前的AO,单独导出一个包含所有部件的模型并烘焙AO,得到链条等AO信息,再将两张图在PS中变暗处理即合成最终AO。

        过程中还遇到另外一个问题,以下面这个低模高模均没有雕刻细节的壶盖举例。这个模型上表面的花瓣形状的凸起是新建带有Height信息的图层,并加以遮罩实现的,所以由高模烘焙的法线和曲率贴图并不存在这个信息,智能材质也就不能据此来创建磨损等细节。

        解决方法是直接导出法线贴图,也就是将高度信息烘焙到法线上去,然后再将得到的法线贴图放入烘焙贴图的槽内,最后去除为烘焙指定的高模,只勾选World Normal,Curvature,AO即可以当前模型的法线进行烘焙了。同样的原理也用在了下面这些小狮子的制作,十几只形态各异,而书中给了轮廓描边,于是将它们转换成贴图倒入SP,再进行了上面的操作。

        此外其他的几个注意点:

        低模在导出的过程中注意在Blender里设置为Shade_Flat,不然导进Painter里也不是平滑的。

        由于金属部分在Unity中直接使用了Standard Shader,所以自己进行了输出贴图配置。

Unity模型渲染 

        最终效果展示比较简单,主要是向着这个视频中的交互,仅仅涉及到天空球的切换和旋转观看文物,所以这部分主要围绕天空盒的更换以及天空盒对物体的受光展开。

玉石Shader

        制作的这几个模型中,大部分都是金属材质,可以直接使用Unity的Standard Shader,可以根据启用不同的Reflection Probes呈现出不同的受光效果。不过为了做这个玉的效果,很自然就会想到SSS,Unity资源商店发现了付费的Shader,不过对于玉石这种并没有很透的物体,又查到了DICE模型的实现,在将示例的Surface Shader整合到和庄懂老师学习的Shader中,得到了这个玉石Shader。

        这部分的Shader分成两个Pass,第一个Pass处理环境光照和直射光,使用Phong光照模型完成基础光照,使用球谐光照作为环境光源,采样unity_SpecCube0作为环境反射。

        可以看到下面代码中环境光反射部分尝试了指定Cubemap贴图、指定Hdr贴图的方法,最后找到了unity的api,果断用Reflection Probe最香。

float4 fragOne(VertexOutput i) : COLOR
{
    float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);
    float3 nDirTS = UnpackNormal(tex2D(_NormTex, i.uv0)).rgb;// 切线空间法线
    float3 nDirWS = normalize(mul(nDirTS, TBN));                        // 世界空间法线 
    float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);  // 世界空间视线
    float3 vrDirWS = reflect(-vDirWS, nDirWS);                          // 视线反射方向          
    float3 lDirWS = _WorldSpaceLightPos0.xyz;                           // 光线方向
    float3 lrDirWS = reflect(-lDirWS, nDirWS);                          // 光线反射方向
    float ndotl = dot(nDirWS, lDirWS);                                      
    float vdotr = dot(vDirWS, lrDirWS);
    float vdotn = dot(vDirWS, nDirWS);
    float3 var_MainTex = tex2D(_MainTex, i.uv0).rgb;
    float var_AOTex = tex2D(_AOTex, i.uv0);
    // 环境光反射部分
    //Cubemap反射
    // float3 var_Cubemap = texCUBElod(_Cubemap, float4(vrDirWS, lerp(_CubemapMip, 0.0, var_SpecTex.a))).rgb;
    //手动全景贴图反射
    // float3 dir = mul(RotationY(_Rotation), vrDirWS);
    // float2 uv = float4((atan2(dir.x, dir.z) / UNITY_PI + 1.0)*0.5, 1.0-acos(dir.y) / UNITY_PI;
    // float3 var_SkyTex = tex2Dlod(_SkyTex, uv, 0.0 ,lerp(_CubemapMip, 0.0, var_SpecTex.a)))
    //采样Reflection Probe反射
    float4 var_specTex = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, vrDirWS, 0.0);
    // 光照模型(直接光照部分)
    float3 baseCol = var_MainTex.rgb;                   // 模型基色
    float lambert = max(0.0, ndotl);                    // 兰伯特模型
    float phong = pow(max(0.0, vdotr), _SpecPow);       // Phong高光
    float shadow = LIGHT_ATTENUATION(i);                // 接受的Shadow
    float3 dirLighting = (baseCol * lambert + phong) * _LightColor0 * shadow;
    // 光照模型(环境光照部分)
    half3 envCol = ShadeSH9(float4(normalize(nDirWS.xyz), 1.0));// 球协环境光
    float fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow);          // 菲涅尔
    float occlusion = var_AOTex;                                      // 采样环境光遮蔽
    float3 envLighting = (baseCol * envCol * _EnvDiffInt + var_specTex * fresnel * _EnvSpecInt) * occlusion;
    // 返回结果
    float3 finalRGB = dirLighting + envLighting;
    return float4(finalRGB, 1.0);
}

        第二个Pass模拟SSS效果,根据Thickness贴图提高模型局部亮度,代码透明部分参考GDC2011发表

float4 fragTwo(VertexOutput i) : COLOR
{
    float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);
    float3 nDirTS = UnpackNormal(tex2D(_NormTex, i.uv0)).rgb; 
    float3 nDirWS = normalize(mul(nDirTS, TBN));                           
    float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz); 
    float3 var_MainTex = tex2D(_MainTex, i.uv0).rgb;
    
    float3 lightDir = _WorldSpaceLightPos0 - i.posWS;
    UNITY_LIGHT_ATTENUATION(atten, i, i.posWS.xyz);
    half3 transLightDir = lightDir + nDirWS * _Distortion;
    float transDot = pow(max(0, dot(vDirWS, -transLightDir)), _Power) * _Scale;
    fixed3 transLight = (atten * 2) * (transDot + tex2D(_AOTex, i.uv0)) * tex2D(_Thickness, i.uv0).r * _SubColor.rgb;
    fixed3 transAlbedo = var_MainTex * _LightColor0.rgb * transLight;
    return float4(transAlbedo, 1.0);
}
ENDCG

天空盒同步Reflection Probes

        为了实现了为了实现视频中天空盒切换的效果,可以分为切换Skybox Material,以及切换场景中当前启用的Reflection Probe两部分。

        第一部分开始想的是只针对一个Material,把它设置为Skybox Material,更改它的_MainTex贴图,但貌似要开hdr贴图的read/write enable,还是选择了每个Hdr贴图配置一个Material,还可以分开调曝光。而在代码里直接给 RenderSettings.skybox赋值Material对象就行了。(Hdr来自HDRIs • Poly Haven

        第二部分对每一个Skybox要进行一下Reflection Probe的烘焙,这里有个坑,注意一下Reflection Probe的类型,并不是多建几个Probes分别在不同天空盒下Bake一下就好了,经常会在启动后或者再烘焙别的什么Probe的时候,当前Probe的光照就变了。正确的做法是设置为Custom然后为其指定为已经烘焙好的Cubemap了,然后再启用不同的Probe就可以控制物体的反射。

后处理 Post Processing

        最后再简单的使用PostProcessing stack v2处理一下大概的效果如下,在运行中更改天空盒。

参考

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值