【计算机动画】实验 路径曲线与运动物体控制 设计

要求 - 路径曲线与运动物体控制

  1. 掌握Cardinal样条曲线的表示和算法,了解控制参数对曲线形状的影响。
  2. 对照Cardinal样条曲线的数学表示和程序代码的对应关系。
  3. 在路径曲线上放置一小汽车,使其在路径上运动起来,汽车运动速度可调。

1.Cardinal spline

P(u)=UTMB
UT=[u3u2u1],B=Pi1PiPi+1Pi+2

M=τ12102/τ13/τ+101/τ2/τ+13/τ+1101100

.三阶B样条插值

M=1331363033001000

介绍
http://www.cnblogs.com/caster99/p/4746652.html
http://www.cnblogs.com/icmzn/p/5101323.html

.Bezier曲线

M=161331360433311000 ‘’
τ=0.5

2.弧长计算方法

对应时间统计 QTimer
精度设置
1. Simpson
2. Newton-Raphson + 高斯求积
3. 向前差分的近似计算方法

小车

计算倾斜角 QtMath

int Line::calculate_theta_single(const int deltax,const int deltay)
{
    double angle;
    double length =sqrt(deltax*deltax+deltay*deltay);
    angle = asin(deltay/length);
    if(deltax<0)
        angle = 3.1415926-angle;

    return angle/3.1415926*180;
}

速度统计

  • 弧长参数化
  • 等时间间距点
    速度曲线

二维 -> 三维

实现

整条曲线、记录点的位置

class line
{
mat *points;
int point_num;//record the number in the line
public:
line(){}
~line(){}
addpoint(mat point){}//insert new point
init_all(){}//change the value of \tau will cause a change for all the subline
init_single(){}//change the position of a certain point

记录每条分段的线

class subline
{
int index;//record line index
mat factor;
public:
subline(int i)index(i):{}
~subline(){}
init(){//special attention should be payed to the starting & ending point}//acording to index and \tau
getS(){}//return the length according to radio with intergal
getu(){}//return the radio according to the length with numerical method
}

Qt相关类

呈现

QGraphicsView
QLabel - QMovie可以呈现动图

实现过程

类的确定

mainWindow(主界面) - mainscene(场景管理) - points(点)&line(插值)

界面

图标

http://www.cnblogs.com/davesla/archive/2011/01/17/1937343.html

QLabel显示gif - QMovie

http://www.cnblogs.com/hnrainll/archive/2011/05/22/2053701.html

Wegiet处理

http://blog.sina.com.cn/s/blog_791f544a0100r2ru.html
http://blog.csdn.net/anialy/article/details/8181038

插入点

这里要比较熟悉QGraphicView\Scene\Item的操作
http://www..com/kevinzhwl/archive/2012/09/06/2673439.html

QGraphicsView重写 - 接受鼠标点击事件
https://yq.aliyun.com/wenzhang/show_32192
http://blog.sina.com.cn/s/blog_4b9ee9e501011xx1.html
http://blog.sina.com.cn/s/blog_4ed318310101fhfa.html

QGraphicsView显示点
固定QGraphicsScene的坐标
并且对resizeEvent进行处理
(不这样的话 会自己移动调整到最适合显示……冷漠.jpg)
(然后用mapToScene什么估计很麻烦,就酱)

void MainWindow::resizeShape(qreal w,qreal h)
{
    myscene.Scene.setSceneRect(0, 0, w, h);
}

然后QGraphicItem有直接的setPen这种的函数继承下来(我一直想用QPainter类但是不会= =)

初步绘制直线 - 对起始点的特殊处理(第一个点不用添加直线)

后来我发现如果想的话可以把Point设置成可以拖动

路径插值

如果不做参数化的话,应该问题不大

参数化的话,这个好像没太做好,感觉想做的话还要新开数组去记录每一行的长度。
现在我做的是比较偷懒,就,先统计整条插值后的曲线的长度,然后算出我应该隔多少距离插一个点,然后对每条单独的曲线都按这个插值(所以端点处的计算肯定有问题)。
然后细节计算也不是用二分法而是 ,扫过去……

下面的大概就是,在两点之间取样的总次数是grain*16,然后一段一段累加sum,直到sum大于传入的某个step值之后记录这个点。

    for(int i = 0; i < grain*16 ; i++)
    {
        tx = get_length(px,step_record);
        ty = get_length(py,step_record);

            double temp = sqrt(tx*tx+ty*ty);
            sum += temp;
            step_record += step;

            if(sum>record/step)
            {
                tweenX[count] = get_pos(px,step_record);
                tweenY[count++] = get_pos(py,step_record);
                sum = sum-record/step;
            }
    }


double Line::get_length(double *p,double u) const
{
    return p[2]+u*(2.*p[1]+3.*u*p[0]);
}

角色移动

角色移动的时候,设置所有角色的精灵都是某个Item的子结点。
因为QGraphicItem里child的位置是相对于Parent的位置,所以直接修改Parent会方便很多(毕竟我这动画帧有8*2(往左往右)=16个)

这里没有在QT内找到对应的(水平翻转)函数,所以是靠PS的,然后QGraphItem也不会显示gif所以是靠自己控制图片显示不同加的。
因为希望角色的gif和移动是独立开来的,所以是由俩个不同的QTimer类控制的

对于垂直特殊处理(不修改状态),然后为了防止速度的一些突然变换设置的是,记录前一个点的状态然后连续两个点是同一个方向才改他的方向(虽然好像没啥道理)

       if(theta == 90 || theta == -90)
        {
        //对第一帧的特殊处理
           if(1==mov_flame)
           {
               group_character->setRotation(theta+180);
               if(theta==90)
               {
                    char_index= true;
               }
               else
               {
                    char_index= false;
               }
           }

        }

       else if( theta>90 || theta<-90 )
        {
            if( char_index_before== true)
            {
                if(true == char_index){}
                else
                {
                    char_index= true;
                    character[ch_flame][0]->setVisible(false);
                    group_character->setRotation(theta+180);
                    character[ch_flame][1]->setVisible(true);
                }
                group_character->setRotation(theta+180);
            }
            else
                char_index_before = true;
        }
        else
        {
           //......
        }

如果按课本的话,应该是u-t的关系是正弦。
然后我写的成了,v-t的关系。这就造成了加速sin曲线的第一个点死活走不动(因为速度是0……)

定时器

http://blog.163.com/bingcaihuang@126/blog/static/198942122010103104026183/

转载于:https://www.cnblogs.com/BirdCage/p/9974036.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值