移动端枪击受伤效果(二)

原本的版本主要有两个很费或是影响低配机效果的地方,一是使用了两次vtf,一次是为了获取终点mesh的顶点法线,对顶点法线也做morgh,一次是为了获取射击点。二是shader会不停的遍历所有的射击点计算距离,对于旧的射击点,很多计算是重复的。

干掉VTF

如果不对法线做morgh的区别大概是这样
(左边没有使用终点mesh法线,右边使用了)


以这个丧尸模型为例的话,主要的区别在胸腔,没用使用终点mesh法线的胸腔正面看还是鼓鼓的,侧面看的话还是有凹陷的感觉。带来的问题就是,玩家在正面射击胸腔时,看起来只是皮被打掉了。如果制作模型时,胸腔位置的变化主要不是靠凹陷,而是躯干部分整个变小了,也就是尽量用顶点的变化来凸显射击的变化,这样即便没有变化法线,射击效果也是明显的。

大概改了一下模型,改成最右边截图中的效果,射击造成的变化有变明显一些

而针对采样得到射击点位置,可以限制射击点数量,使用constant buffer传递射击点数组。constant buffer的大小是16kb-64kb,一般情况下射击数量不会超过100,这样占据buffer不会超过1.6kb,感觉还可以。
放弃使用终点mesh法线,而且使用constant buffer传递射击点位置后的真机测试结果如下:
同样是场景中只有一个模型,测试机为iPhone 6s

下图分别是0次、5次、10次、20次射击




对比之前在vs中采样得到法线贴图和射击点位置时的测试结果,提升还是比较明显的

干掉重复计算

1
2
3
4
5
6
7
8
9
10
11
12
13
float p = 0;

for (int ii = 0;ii < _pointsLength; ii++) {
//计算采样uv位置
float4 uvInBuffer = float4(
(ii % _ShootPointsSize + 0.5) / _ShootPointsSize*1.0,
(ii / _ShootPointsSize + 0.5) / _ShootPointsSize*1.0, 0, 0);

//采样得到第i个射击点
float3 points_i = tex2Dlod(_points, uvInBuffer).rgb;
//大致的p的计算方法
p = saturate(p += saturate((distance(worldPos, points_i) - HoleSize) * HoleIndensity));
}

这里计算p值时,不停的在计算旧的射击点的距离,所以希望可以保存上一次计算结果,下一次就直接在上一次结果的基础上进行计算就可以了。
目前想到的方法还是需要VTF,可以作为中配机高配机的优化方案。

方案1:在脚本中做这个计算的话,可以很容易的获取到上次的结果,将结果存入一张贴图,每次有新的射击点就更新这张贴图,shader中直接采样就行。这个方案除了增加采样和写入次数外,会在每次有新的射击点时,遍历整个模型几千甚至上万的顶点,而旧方案每个顶点并行遍历几十个射击点,但这个遍历可能是每帧的。尝试了一下,这个方法在编辑器中都有一些卡,模型有一万多个顶点……

方案2:另外使用一个摄像机,通过replacementshader来给场景中的对应模型换上特殊的shader,这个shader按顶点uv采样一张贴图的值(得到上一次的p的计算结果),shader用新的射击点计算新的值,将结果按uv位置输出到屏幕空间,摄像机RT就获取到了下次输入shader的贴图。这个方案使得模型顶点间依然是并行的,具体的效率提升还需要测试,在射击次数较多时应该是有优化效果的,不过射击次数一般不会到三位数,不会有很明显的效率提升。

简化版本

有些时候,对效率要求比较高,策划可以接受受伤效果都是固定的,就是受攻击到一定程度有固定的地方出现固定的受伤效果。

针对这个需求的方案:

美术资源制作中增加一个步骤:
在两套uv制作完成后,在sp中按照肢体变化的先后顺序绘制灰度贴图,先变化的肢体部分灰度值越高。
如下图的绘制,消失的顺序是手、小腿、头和身子、大腿

这张贴图会在 将终点mesh信息烘到起点mesh顶点色的工具中使用,工具中同时导入这张贴图,贴图上的灰度值会存入顶点色的a通道。shader会将射击次数加在这个灰度值上,作为mesh morphing的参数。

1
2
3
4
//  射击脚本中
flag = hitCount / 5;
// shader中的morphing参数p
p = smoothstep(1.0, 1.2, v.color.a + _flag / 5.0);

这样做的话iPhone 6s真机测试结果一直相当于之前的0次射击