高性能GPU渲染帧动画方案

        公司项目中美术效果要求有超多观众动画参与增加环境氛围,观众有多个朝向,有多套动画,动画都为循环动画。

GPU渲染帧动画方案

在推论出序列帧动画是最优解决思路之后,我们着重需要考虑如何简化序列帧动画带来的CPU消耗,使用GPU直接渲染应该就是最优解。

定帧解决思路

1.解决

传统序列帧动画可以理解为第x帧播放第y张贴图。定帧其实理解为连续几帧都播放同一张贴图。所以这里我们需要设置一个动画的序列,明确动画的排列顺序。也可能是动画不再播放,或者播快播慢,那就需要一个速度来控制动画的播放也就是FPS。

2.详解

在工具中,每一条动画都是通过拖入的图片形成的。比如在man这个动画中,nan-01这张图就会占两帧。同理,需要长时间停留但是又不影响动画循环的画面就需要在这里做队列上的延长。如果出现了所有角色动画的停止,或播放速度变化,就需要改变材质球的FPS属性。

图集合并思路

1.解决

在生成图集的时候需要将图片的序号记录下来。这里打图集只会将在面板中编辑的图片打成图集。这其中要筛出重复编辑的图片。打成图集时,需要匹配长宽,避免出现图集长宽差特别大。

注意:所有图片需要长宽一致。

2.问题记录

制作过程中发现,当图集的最后一行不为整数时,并没有对剩下的像素做处理时,所有采样到与这些像素相连的图片时,在边缘会出现断断续续的白边。这里的原因是采样图片的插值算法会采样周围几个纹理元素(texel)。将剩下的像素填入(0,0,0,0)后问题解决。

动画信息纹理

         1.问题

传统序列帧播放,会由C#代码传值进shader中控制序列帧播放。但当有很多游戏物体时,这种方法会造成大量的update在每帧执行,CPU消耗较多。这里为了节省CPU消耗,需要将这步移到GPU。

2.解决

这里采用通道图的方法。将序列帧的排列信息做成通道图。采样通道图的信息获得颜色的RGB值,然后换算出在序列帧图集中的图片序号。从而去缩放采样的uv,就可得到需要采样的贴图。

3.详解

1通过面板编辑的图片,取到的顺序编号后。在C#中生成序列图。在本工具中遵循以下的数字转换颜色规则。可表示0~65025。这里只用了颜色的r和g通道。

    Color EncodeShort2Color(short i)

    {

        return new Color32( (byte)((i >> 8) & 0xFF), (byte)(i & 0xFF), 0, 1);

}

每个动画的队列将会作为一横排。从下往上堆砌。

同时我们需要记录每条动画的长度,这个值将会作为每横排的第一张图。如下图:在PS中查看最后生成的排列图。及其一排1列的颜色值。

2得到排列图后,在shader中的采样需要设置UV。首先采样第x排的第一张图,x由顶点色传进来,表示第x个动画。拿到当前动画的长度和整张排列图的长、宽后就可以做UV的偏移控制。再去采样就可以得到图片的序号。

注意:这里的采样可以去采样每个UV的中心点。

Mesh合并思路

         1.问题

         这里需要在动画模型的Mesh中加入顶点色。如果由美术制作会维护困难,且难以控制顶点色的信息。所以这里考虑程序去合并Mesh和生成顶点色。

         2.解决

         首先,生成一张Mesh,需要顶点坐标List(List<Vector3> vertices),uv坐标List,三角形面片顺序List。这里需要顶点色,所以还要设置顶点色List。

         我们这里是通过将所有需要处理的游戏物体挂载在同一个父节点下,来拿到游戏物体的Mesh,就可以得到它的信息。将他们的信息整合起来就可以用来生成大Mesh。

需要处理顶点坐标List,将每个Mesh的顶点坐标做一个从本地坐标到世界坐标的转换。如下:gameObj是他们的父物体。

Vector3 wp = o.TransformPoint(vertex[i]);

            wp = gameObj.transform.InverseTransformPoint(wp);

uv没有变化,所以不用处理,直接将他们合成一个大List就可以了。

因为顶点List顺序变化,所以三角形顺序也将变化。因为每一个顶点原来的序号都是0~x。三角形顺序也都由0~x组成,而这里顶点序号发生了变化,三角形顺序就需要在原来的基础上加上已经处理过的顶点数vertices.count

还要为每个顶点加入顶点色,一个Mesh的顶点色都相同。得到动画信息后,这里color.r表示动画编号,color.g表示动画偏移。

Color col = Color.black;       

        col.r = ani/255f;

        col.g = frame/255f;

        for(int i = 0; i < 4; i++)

 

        {

            ans.Add(col);

        }

然后再使用这些数据生成Mesh,该Mesh就合并了所有子物体的Mesh。如下图,大量游戏物体和最后生成的合并Mesh。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值