游戏开发论坛

 找回密码
 立即注册
搜索
楼主: ACGFan

再论纯关键帧动画

[复制链接]

20

主题

465

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
QQ
发表于 2006-11-19 16:03:00 | 显示全部楼层

Re:再论纯关键帧动画

你没搞明白我的意思吗?你都说了“我的目标不是什么,而是什么什么”,这不就完了吗?你认为关键帧动画满足你的需求,所以你就使用关键帧动画,我也是认为关键帧动画满足我的需求,所以我也用关键帧动画。这不就完了吗?
有人认为骨骼动画够好,关键帧不能满足需求(不是说哪个能做什么,哪个不能做什么,而是说由哪个来做更好,这在每个游戏中都是不同的),骨骼动画用起来很好,他用骨骼动画有什么不好?
你一副为关键帧正名的口气,在我听来莫明其妙。

6

主题

95

帖子

103

积分

注册会员

Rank: 2

积分
103
 楼主| 发表于 2006-11-21 15:52:00 | 显示全部楼层

Re:再论纯关键帧动画

误会。现阶段各有所长,以后可能会有消长变化,我猜测一下而已。毕竟手段能变的简单总是让人振奋的。能说一下您的3D战棋游戏中,每个批次(调用Draw*)画出什么东西?画的时候每个批次给出什么数据,每顶点给什么数据吗?

6

主题

307

帖子

309

积分

中级会员

Rank: 3Rank: 3

积分
309
发表于 2006-11-21 16:07:00 | 显示全部楼层

Re:再论纯关键帧动画

其实你这个就是顶点动画,每个顶点带一系列的关键帧矩阵,这个其实是个很费的方案

1、每个顶点每帧都要计算自己的插值,一般一个人物4-5K个点,就要计算4-5K个矩阵插值,用骨骼只要计算几十个骨骼点就行。随后的顶点变换都一样要做
2、骨骼动画多套皮肤可以共用一套骨骼,但顶点动画就得每套皮肤就有一套关键帧矩阵,内存耗费不是大一点的问题。

20

主题

465

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
QQ
发表于 2006-11-21 16:09:00 | 显示全部楼层

Re:再论纯关键帧动画

我的构架是这样的,有一个物体对象,然后物体对象里面有ID3DXMesh的网格。
这个网格是每次根据当前物体的帧数而决定的。每次都要重新生成这个网格。这在NextFrame中执行。然后在Rander里面依次画每个物体。这是建立网格的函数。画网格就只是一句char_mesh->DrawSubset(0)就行了。


void AlphaObject::BuildAnimMesh(LPDEVICE device)
{
        // 清除旧的网格
        SAFE_RELEASE(char_mesh);
        SAFE_RELEASE(weapon_mesh);

        // 获取动画信息
        AlphaAnimFrame & anim = origin->anims[action];
        AlphaAnimFrame & anim_next = origin->anims[next_action];

        // 确定开始帧和结束帧
        // 进行顶点插值计算
        float factor = frame - (int)frame;

        // 获取两个帧的位置
        int curr_frame = frame;
        int next_frame = curr_frame + 1;
        // 判断下一个顶点是不是超出边界了(用于处理循环动画)
        if (next_frame >= anim.start + anim.count)
        {
                next_frame = anim_next.start;
        }

        // 获取两个帧的顶点
        const PtrVector3D char_curr = origin->vlist + origin->num_verts * curr_frame;
        const PtrVector3D char_next = origin->vlist + origin->num_verts * next_frame;
        const PtrTextCoord char_text = origin->tlist;
        const PtrVector3D weapon_curr = weapon->vlist + weapon->num_verts * curr_frame;
        const PtrVector3D weapon_next = weapon->vlist + weapon->num_verts * next_frame;
        const PtrTextCoord weapon_text = weapon->tlist;

        // 顶点缓冲
        PtrVertex char_vlist = new Vertex[origin->num_index];
        PtrVertex weapon_vlist = new Vertex[weapon->num_index];

        // 确定不需要插值计算的情况
        if (factor < 0.01f)
        {
                for (int p = 0, v = 0; p < origin->num_polys; ++p, v += 3)
                {
                        char_vlist[v + 0].x = char_curr[origin->plist[p].vindex[0]].x;
                        char_vlist[v + 0].y = char_curr[origin->plist[p].vindex[0]].y;
                        char_vlist[v + 0].z = char_curr[origin->plist[p].vindex[0]].z;
                        char_vlist[v + 0].u = char_text[origin->plist[p].tindex[0]].u;
                        char_vlist[v + 0].v = char_text[origin->plist[p].tindex[0]].v;

                        char_vlist[v + 1].x = char_curr[origin->plist[p].vindex[1]].x;
                        char_vlist[v + 1].y = char_curr[origin->plist[p].vindex[1]].y;
                        char_vlist[v + 1].z = char_curr[origin->plist[p].vindex[1]].z;
                        char_vlist[v + 1].u = char_text[origin->plist[p].tindex[1]].u;
                        char_vlist[v + 1].v = char_text[origin->plist[p].tindex[1]].v;
                       
                        char_vlist[v + 2].x = char_curr[origin->plist[p].vindex[2]].x;
                        char_vlist[v + 2].y = char_curr[origin->plist[p].vindex[2]].y;
                        char_vlist[v + 2].z = char_curr[origin->plist[p].vindex[2]].z;
                        char_vlist[v + 2].u = char_text[origin->plist[p].tindex[2]].u;
                        char_vlist[v + 2].v = char_text[origin->plist[p].tindex[2]].v;
                }

                for (int p = 0, v = 0; p < weapon->num_polys; ++p, v += 3)
                {
                        weapon_vlist[v + 0].x = weapon_curr[weapon->plist[p].vindex[0]].x;
                        weapon_vlist[v + 0].y = weapon_curr[weapon->plist[p].vindex[0]].y;
                        weapon_vlist[v + 0].z = weapon_curr[weapon->plist[p].vindex[0]].z;
                        weapon_vlist[v + 0].u = weapon_text[weapon->plist[p].tindex[0]].u;
                        weapon_vlist[v + 0].v = weapon_text[weapon->plist[p].tindex[0]].v;

                        weapon_vlist[v + 1].x = weapon_curr[weapon->plist[p].vindex[1]].x;
                        weapon_vlist[v + 1].y = weapon_curr[weapon->plist[p].vindex[1]].y;
                        weapon_vlist[v + 1].z = weapon_curr[weapon->plist[p].vindex[1]].z;
                        weapon_vlist[v + 1].u = weapon_text[weapon->plist[p].tindex[1]].u;
                        weapon_vlist[v + 1].v = weapon_text[weapon->plist[p].tindex[1]].v;
                       
                        weapon_vlist[v + 2].x = weapon_curr[weapon->plist[p].vindex[2]].x;
                        weapon_vlist[v + 2].y = weapon_curr[weapon->plist[p].vindex[2]].y;
                        weapon_vlist[v + 2].z = weapon_curr[weapon->plist[p].vindex[2]].z;
                        weapon_vlist[v + 2].u = weapon_text[weapon->plist[p].tindex[2]].u;
                        weapon_vlist[v + 2].v = weapon_text[weapon->plist[p].tindex[2]].v;
                }

                // 根据顶点列表来创建网格
                CreateMesh(device, char_mesh, char_vlist, origin->num_index, origin->ilist, origin->num_index);
                CreateMesh(device, weapon_mesh, weapon_vlist, weapon->num_index, weapon->ilist, weapon->num_index);
        }
        else // 需要进行差值计算
        {
                for (int p = 0, v = 0; p < origin->num_polys; ++p, v += 3)
                {
                        const Vector3D & va0 = char_curr[origin->plist[p].vindex[0]];
                        const Vector3D & va1 = char_curr[origin->plist[p].vindex[1]];
                        const Vector3D & va2 = char_curr[origin->plist[p].vindex[2]];
                        const Vector3D & vb0 = char_next[origin->plist[p].vindex[0]];
                        const Vector3D & vb1 = char_next[origin->plist[p].vindex[1]];
                        const Vector3D & vb2 = char_next[origin->plist[p].vindex[2]];

                        char_vlist[v + 0].x = (va0.x + (vb0.x - va0.x) * factor);
                        char_vlist[v + 0].y = (va0.y + (vb0.y - va0.y) * factor);
                        char_vlist[v + 0].z = (va0.z + (vb0.z - va0.z) * factor);
                        char_vlist[v + 0].u = char_text[origin->plist[p].tindex[0]].u;
                        char_vlist[v + 0].v = char_text[origin->plist[p].tindex[0]].v;

                        char_vlist[v + 1].x = (va1.x + (vb1.x - va1.x) * factor);
                        char_vlist[v + 1].y = (va1.y + (vb1.y - va1.y) * factor);
                        char_vlist[v + 1].z = (va1.z + (vb1.z - va1.z) * factor);
                        char_vlist[v + 1].u = char_text[origin->plist[p].tindex[1]].u;
                        char_vlist[v + 1].v = char_text[origin->plist[p].tindex[1]].v;
                       
                        char_vlist[v + 2].x = (va2.x + (vb2.x - va2.x) * factor);
                        char_vlist[v + 2].y = (va2.y + (vb2.y - va2.y) * factor);
                        char_vlist[v + 2].z = (va2.z + (vb2.z - va2.z) * factor);
                        char_vlist[v + 2].u = char_text[origin->plist[p].tindex[2]].u;
                        char_vlist[v + 2].v = char_text[origin->plist[p].tindex[2]].v;
                }

                for (int p = 0, v = 0; p < weapon->num_polys; ++p, v += 3)
                {
                        Vector3D & va0 = weapon_curr[weapon->plist[p].vindex[0]];
                        Vector3D & va1 = weapon_curr[weapon->plist[p].vindex[1]];
                        Vector3D & va2 = weapon_curr[weapon->plist[p].vindex[2]];
                        Vector3D & vb0 = weapon_next[weapon->plist[p].vindex[0]];
                        Vector3D & vb1 = weapon_next[weapon->plist[p].vindex[1]];
                        Vector3D & vb2 = weapon_next[weapon->plist[p].vindex[2]];

                        weapon_vlist[v + 0].x = va0.x + (vb0.x - va0.x) * factor;
                        weapon_vlist[v + 0].y = va0.y + (vb0.y - va0.y) * factor;
                        weapon_vlist[v + 0].z = va0.z + (vb0.z - va0.z) * factor;
                        weapon_vlist[v + 0].u = weapon_text[weapon->plist[p].tindex[0]].u;
                        weapon_vlist[v + 0].v = weapon_text[weapon->plist[p].tindex[0]].v;

                        weapon_vlist[v + 1].x = va1.x + (vb1.x - va1.x) * factor;
                        weapon_vlist[v + 1].y = va1.y + (vb1.y - va1.y) * factor;
                        weapon_vlist[v + 1].z = va1.z + (vb1.z - va1.z) * factor;
                        weapon_vlist[v + 1].u = weapon_text[weapon->plist[p].tindex[1]].u;
                        weapon_vlist[v + 1].v = weapon_text[weapon->plist[p].tindex[1]].v;
                       
                        weapon_vlist[v + 2].x = va2.x + (vb2.x - va2.x) * factor;
                        weapon_vlist[v + 2].y = va2.y + (vb2.y - va2.y) * factor;
                        weapon_vlist[v + 2].z = va2.z + (vb2.z - va2.z) * factor;
                        weapon_vlist[v + 2].u = weapon_text[weapon->plist[p].tindex[2]].u;
                        weapon_vlist[v + 2].v = weapon_text[weapon->plist[p].tindex[2]].v;
                }

                // 根据插值后的顶点列表来创建网格
                CreateMesh(device, char_mesh, char_vlist, origin->num_index, origin->ilist, origin->num_index);
                CreateMesh(device, weapon_mesh, weapon_vlist, weapon->num_index, weapon->ilist, weapon->num_index);               
        }

        // 善后工作
        delete [] char_vlist;
        delete [] weapon_vlist;
        // 大功告成
        return ;
}

20

主题

465

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
QQ
发表于 2006-11-21 16:13:00 | 显示全部楼层

Re:再论纯关键帧动画

模型的原始数据是存放在这样一个结构中的。纹理、顶点、多边形都是分开存放,这样比较节约空间。还有皮肤的纹理。

        // 物体资源
typedef struct AlphaObjectResource
{
        TCHAR name[256]; // 物体名称
        int   attr; // 物体的属性

    int              num_frames; // 帧数
        int              num_anims; // 动画数量
        AlphaAnimFrame * anims; // 保存动画的状态信息

        int   num_verts; // 顶点数
        int   num_index; // 索引数
        int   num_textcoords; // 纹理数
        int   num_polys; // 多边形数

        Vector3D  * vlist; // 指向顶点坐标数组的指针
        TextCoord * tlist; // 纹理列表
        Poly      * plist; // 多边形列表
        int       * ilist; // 索引列表

        int            num_skins; // 纹理数量
        AlphaTexture * skins; // 纹理

        // AlphaObjectResource 方法 ///////////////////////////////////////////////

        void Scale(const Vertex & v); // 缩放
        void InvertVertex(int flag); // 反转坐标
        void InvertWindingOrder(void); // 反转环绕顺序
        void Release(void); // 清除对象
}*PtrAlphaObjectResource;

39

主题

170

帖子

170

积分

注册会员

Rank: 2

积分
170
发表于 2006-11-21 18:31:00 | 显示全部楼层

Re: 再论纯关键帧动画

[em5]
sf_20061121183031.jpg

39

主题

170

帖子

170

积分

注册会员

Rank: 2

积分
170
发表于 2006-11-21 18:50:00 | 显示全部楼层

Re: 再论纯关键帧动画

LOD [em1]
sf_20061121185023.jpg

39

主题

170

帖子

170

积分

注册会员

Rank: 2

积分
170
发表于 2006-11-21 18:58:00 | 显示全部楼层

Re: 再论纯关键帧动画

[em3]
sf_2006112118588.jpg

39

主题

170

帖子

170

积分

注册会员

Rank: 2

积分
170
发表于 2006-11-21 19:02:00 | 显示全部楼层

Re: 再论纯关键帧动画

[em10]
sf_2006112119220.jpg

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-11-22 12:16:00 | 显示全部楼层

Re:再论纯关键帧动画

呵呵,不得不支持楼主了...
在bones和morphing的速度上 和复杂度上 请进一步把问题抽象化,好找到共同点与不同点,我们做的都是关于空间变换问题..
输入多少信息=>输出多少信息      时间换空间空间换时间,精确度取舍 批量处理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-26 01:59

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表