前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在独立游戏里的渲染开发踩坑笔记

在独立游戏里的渲染开发踩坑笔记

作者头像
HkingAuditore
发布2023-11-21 09:24:52
1950
发布2023-11-21 09:24:52
举报
文章被收录于专栏:HkingAuditoreHkingAuditore

背景

《玩具帝国》是一款Windows+安卓平台的双端游戏,使用Unity URP进行开发。画面属于写实风格。

纸片渲染

纸片渲染的核心要点是“透光性”,体现在游戏里,有以下几点:

  • 透光性好,受光面与背光面亮度接近。
  • 双面显示阴影。如果有一个面受到投影,那这个面的反面也会显示出阴影。
  • 投出的阴影上仍然有透光,不是完全的阴影

第一个问题很好解决,首先开启双面渲染,然后直接指定面的法线,让它满足与光线点乘为正。由于游戏场景的光源始终是固定的,纸片也的走向也是固定的,所以只要给每个场景的所有纸片指定一个特定的法线值即可。

代码语言:javascript
复制
Light mainLight = GetMainLight(inputData,inputData.shadowMask,aoFactor);
half nDotL=dot(mainLight.direction,_LightingNormal);

进一步,还需要考虑纸片对光线透射与吸收,所以正反两面的颜色还是略有区别的。所以我在这里直接以albedo的rgb加权求和得到一个光线吸收率,对ndotl进行缩放。

第二个问题不需要专门的处理,只要走的是双面渲染,正常采Shadow Map,就可以让两个面获得相同的阴影。不过这里做了模拟纸片发生散射阴影处被提亮的trick:

代码语言:javascript
复制
half shadow = mainLight.shadowAttenuation;
half3 sssShadow=saturate(1-mainLight.distanceAttenuation*shadow)*_SubsurfaceStrength*nDotL*surfaceData.albedo;

至于第三个问题,直接用半透明阴影的做法,在Shadow Caster中加了个Dither,用高度做控制:

代码语言:javascript
复制
half p=GenerateHashedRandomFloat(input.positionCS);
half height=input.positionOS.y;
half k=pow(smoothstep(_Min,_Max,height),_ShadowContrast);
half a=SampleAlbedoAlpha(input.uv,TEXTURE2D_ARGS(_BaseMap,sampler_BaseMap)).a;

a=(a+.2*(1-k))*k;
p=lerp(p,1-p,step(0.5,a));
clip(a-p);

区别还是很明显的:

之前 之后

实物投影和纸片投影的区别

由于游戏中的士兵很多,还必须进行合批:

士兵在受到攻击时会闪红,所以需要为它准备Per Instance信息:

代码语言:javascript
复制
UNITY_INSTANCING_BUFFER_START(Props)
  UNITY_DEFINE_INSTANCED_PROP(float,_HitTime)
UNITY_INSTANCING_BUFFER_END(Props)

原本想传递闪红瞬间时间值,由材质计算具体的闪红。但发现由于精度原因,在游戏进行时间变长后闪红的计算误差会越来越大,最后改成通过程序传值,不知道有没有规避的方法=。=。

还没有做图集,所以目前只对同种士兵合批

茸毛灌木丛

游戏里的灌木丛按设定上是茸毛球

核心思路是让球面Mesh上的每一个四边面都变成Billboard,但法线信息依然照旧,用来计算光影、散射,做出假的体积感

只需要将模型拓扑成四边面,让四个点分别在UV的四个角即可。

代码语言:javascript
复制
float3 FurVertex(float2 uv,float3 positionOS)
{
  half3 localOffset=half3(remap(uv,0,1,-1,1),0);
  half3x3 rotateMat=AngleAxis3x3(_WindStrength*(Wind(positionOS,_TimeScale)),normalize(GetCameraPositionWS()-TransformObjectToWorld(half3(0,0,0))));
  localOffset=.1*normalize(mul(UNITY_MATRIX_I_M,mul(rotateMat,mul(UNITY_MATRIX_I_V,localOffset))));
  localOffset=lerp(0,localOffset,_Shape);
  return localOffset;
}

//…Vertex Shader
half3 localOffset=FurVertex(output.uv,input.positionOS);
VertexPositionInputs vertexInput=GetVertexPositionInputs(input.positionOS.xyz+localOffset);

最后加上风动

代码语言:javascript
复制
 float Wind(float3 posOS,half timeScale)
{
  half3 posWS=TransformObjectToWorld(posOS);
  half random=sin(dot(posWS,half3(125,3651.52456,38512.352)));
  return 2.36*sin(2.35*random*timeScale*_Time+10.52)+3.255*cos(6.325*timeScale*random*_Time+491.463);
}

类似的操作在我的新书《Unity Shader入门与实战》中有详细的阐述,这是我面向对Shader一无所知的菜鸟人群撰写的Unity Shader入门读物(〃∀〃),都是以最简单最浅显的语言对Unity Shader开发中基本技术进行讲解,欢迎各位老爷支持。

当当 《Unity Shader入门与实战》《Unity Shader入门与实战》【摘要 书评 试读】- 京东图书

高亮与描边

鼠标移动到建筑上会产生高亮效果,同时建筑上带有外描边效果。这也是相当经典的案例了,在Unity URP刚发布的时候,官方案例就有类似的例子,在此也是用Render Feature处理的。逻辑里将需要描边或高亮的物体设置到对应的Rendering Layer中即可。

描边用了三个Pass,分别处理:

  1. Stencil Mask,用来指示建筑内部范围,用于剔除内描边
  2. Outline Pass 1,但关闭深度测试,显示被遮挡时的轮廓
  3. Outline Pass 2,但开启深度测试,显示未被遮挡时的轮廓
代码语言:javascript
复制
Pass
{
	Ztest Off
    
    // ...
    // 高亮效果
}
// 被遮挡时的描边
Pass 
{
    Cull Front
    Ztest LEqual
    ZWrite On
    Stencil
	{
		Ref 1
		Comp NotEqual
		Pass keep
	}					
    // ...
}
// 未被遮挡时的描边
Pass 
{
    Cull Front
    Ztest Greater
    ZWrite On
    Stencil
	{
		Ref 1
		Comp NotEqual
		Pass keep
	}
    // ...
}
/// 剔除内描边
Pass 
{
    Blend Zero One
    Ztest Off
    Zwrite Off
    
    Stencil
	{
		Ref 1
		Comp Always
		Pass Replace
	}
}

描边用的软法线存在顶点色里,用houdini可以简单实现,Blender的几何节点也能很容易拉出来

Houdini

Blender

这个经典例子的操作在我的新书《Unity Shader入门与实战》中也有详细的阐述(〃∀〃),再次拉出来。

当当 《Unity Shader入门与实战》《Unity Shader入门与实战》【摘要 书评 试读】- 京东图书

特效

VAT

城楼上抖动的旗帜是用Houdini中物理解算布料后,导出VAT实现的。根据需要可以在材质里调节风动的强度,这样在与风场结合时可以非常方便。

至于顶点数量比较多的模型,可以烘焙成骨骼动画导入

破碎特效

( ˇωˇ)众所周知Unity里没有Chaos,所以建筑破碎也是在Houdini里切的,效果还凑合。

爆炸/烟雾特效

Embergeni出Flipbook真的好用,向各位老爷们推荐,六点光照、Motion Vector都可以直出,不过游戏里的光照都是固定死的,所以我只需要一张最基础的图就够用了。

在Unity里用的是VFX Graph,( ˇωˇ)用起来没有Niagara那么爽,不过比原来的particle system还是强上不少的。游戏里的火焰效果与逻辑有一部分重合,这部分可以直接移动到VFX Graph里去算。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-11-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 纸片渲染
  • 茸毛灌木丛
  • 高亮与描边
  • 特效
    • VAT
      • 破碎特效
        • 爆炸/烟雾特效
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档