• cocos2dx实现翻书效果。


    因为项目需求,需要使用cocos实现3d翻书的效果,刚开始确实没有什么思路,cocos2d做3d的效果这不是开玩笑吗。但是,再难也得做啊,没办法。

    开始查资料,在百度,google上搜索了好几天,基本把所有的文章都翻遍了,根本没有人实现过惊恐,好吧,我承认有点虚了,这可咋办。

    后来想到cocos2dx的例子里有个类似的效果,不过那个是个action,后来看了看感觉还可以,只是效果和我的需求有点差异,但终归是找到了实现的思路,于是开始看cocos2dx的源码,主要用到的是cocos的网格动画,涉及到以下几个文件:

    CCGrid.h /cpp :网格数据及渲染,包括基本网格数据和3D网格数据,这是数据的基础。

    CCActionGrid.h /cpp :网格基本动画,这是动画的基础。

    CCActionGrid3D.h/cpp: 3D网格基本动画,这是3D网格动画的基础。

    CCActionTiledGrid.h / cpp :网格衍生动画,这是最终的特效实现。

    咱们这里主要用到CCGrid.h进行渲染,其他三个是action的实现。

    这里插一句,在此之前,我曾经还想用遮罩去实现类似的翻书效果,因为android上类似效果的实现就是实用遮罩的,可是在cocos中这种方法行不通,最终放弃了。

    看CCActionPageTurn3d这个类,cocos的翻页效果的实现就是在这个类中实现的,在这个类中有个update()函数:

      1 /*
      2 
      3  * Update each tick
      4 
      5  * Time is the percentage of the way through the duration
      6 
      7  */
      8 
      9 voidCCPageTurn3D::update(float time)
     10 
     11 {
     12 
     13     float tt =MAX(0, time -0.25f);
     14 
     15     float deltaAy = (tt * tt *500);
     16 
     17     float ay = -100 - deltaAy;
     18 
     19     
     20 
     21     float deltaTheta = - (float)M_PI_2 *sqrtf( time) ;
     22 
     23     float theta =/*0.01f */ + (float)M_PI_2 +deltaTheta;
     24 
     25     
     26 
     27     float sinTheta =sinf(theta);
     28 
     29     float cosTheta =cosf(theta);
     30 
     31     
     32 
     33     for (int i =0; i <=m_sGridSize.width; ++i)
     34 
     35     {
     36 
     37         for (int j =0; j <=m_sGridSize.height; ++j)
     38 
     39         {
     40 
     41            // Get original vertex
     42 
     43             ccVertex3F p = originalVertex(ccp(i ,j));
     44 
     45             
     46 
     47             float R = sqrtf((p.x * p.x) + ((p.y - ay) * (p.y - ay)));
     48 
     49             float r = R * sinTheta;
     50 
     51             float alpha = asinf( p.x / R );
     52 
     53             float beta = alpha / sinTheta;
     54 
     55             float cosBeta = cosf( beta );
     56 
     57             
     58 
     59            // If beta > PI then we've wrapped around the cone
     60 
     61            // Reduce the radius to stop these points interfering with others
     62 
     63             if (beta <= M_PI)
     64 
     65             {
     66 
     67                 p.x = ( r *sinf(beta));
     68 
     69             }
     70 
     71             else
     72 
     73             {
     74 
     75                // Force X = 0 to stop wrapped
     76 
     77                 // points
     78 
     79                 p.x =0;
     80 
     81             }
     82 
     83  
     84 
     85             p.y = ( R + ay - ( r * (1 - cosBeta) * sinTheta));
     86 
     87  
     88 
     89            // We scale z here to avoid the animation being
     90 
     91            // too much bigger than the screen due to perspective transform
     92 
     93             p.z = (r * (1 - cosBeta ) * cosTheta) /7;// "100" didn't work for
     94 
     95  
     96 
     97            //    Stop z coord from dropping beneath underlying page in a transition
     98 
     99            // issue #751
    100 
    101             if( p.z < 0.5f )
    102 
    103             {
    104 
    105                 p.z =0.5f;
    106 
    107             }
    108 
    109             
    110 
    111            // Set new coords
    112 
    113             setVertex(ccp(i, j), p);
    114 
    115             
    116 
    117         }
    118 
    119     }
    120 
    121 }

    刚开始看这个,完全不知所云,一堆三角函数,抓狂,简直了,后来找了好久,找到一篇论文

    正好把源码解释得一清二楚,论文的链接为:http://www.parc.com/content/attachments/turning-pages-3D.pdf

    看完之后才明白,原来是建立了一个数学模型,通过数学模型去计算每个顶点在变换过程中的位置,明白了。到现在才理解大学时老师说的那句话,数学对编程来说很重要。

    回到主题,我们要实现的是类似翻书的效果,通过上面的算法,得到的效果和我的需求有点差异,既然他是想象成一个锥体的运到,我们可以想象成一个圆柱体的运到,通过改变圆柱体轴心的位置,来实现翻动的效果,不多说了,直接上源码:

      1 voidPageTurn::calculateHorizontalVertexPoints(float offsetX)
      2 
      3 {
      4 
      5     float theta = (GLfloat)(M_PI /6.0f);
      6 
      7     float R =50;
      8 
      9     float b = (m_pBgSprite->getContentSize().width - offsetX *1.4f) *sinf(theta);
     10 
     11     
     12 
     13     
     14 
     15     
     16 
     17     for (int i =0; i <=m_sGridSize.width; ++i)
     18 
     19     {
     20 
     21         for (int j =0; j <=m_sGridSize.height; ++j)
     22 
     23         {
     24 
     25            // Get original vertex
     26 
     27            ccVertex3F p =originalVertex(ccp(i ,j),m_pForeSprite);
     28 
     29             
     30 
     31             float x = (p.y + b) / tanf(theta);
     32 
     33             
     34 
     35             float pivotX = x + (p.x - x) * cosf(theta) * cosf(theta);
     36 
     37             float pivotY = pivotX * tanf(theta) - b;
     38 
     39             
     40 
     41             float l = (p.x - pivotX) / sinf(theta);
     42 
     43             float alpha = l / R;
     44 
     45             if (l >= 0) {
     46 
     47                 if (alpha > M_PI) {
     48 
     49                     p.x = (GLfloat)(mHOffsetX + pivotX - R * (alpha -M_PI) *sinf(theta));
     50 
     51                     p.y = (GLfloat)(mHOffsetY + pivotY + R * (alpha -M_PI) *cosf(theta));
     52 
     53                     p.z = (GLfloat)(2 * R /9);
     54 
     55                 }
     56 
     57                 else if (alpha <= M_PI)
     58 
     59                 {
     60 
     61                     p.x = (GLfloat)(mHOffsetX + pivotX + R *sinf(alpha) *sinf(theta));
     62 
     63                     p.y = (GLfloat)(mHOffsetY + pivotY - R *sinf(alpha) *cosf(theta));
     64 
     65                     p.z = (GLfloat)((R - R *cosf(alpha))/9);
     66 
     67                 }
     68 
     69             }
     70 
     71             else
     72 
     73             {
     74 
     75                 p.x +=mHOffsetX;
     76 
     77                 p.y +=mHOffsetY;
     78 
     79             }
     80 
     81             
     82 
     83            // Set new coords
     84 
     85             setVertex(ccp(i, j), p,m_pForeSprite);
     86 
     87             
     88 
     89             
     90 
     91         }
     92 
     93     }
     94 
     95     
     96 
     97     for (int i =0; i <=m_sGridSize.width; ++i)
     98 
     99     {
    100 
    101         for (int j =0; j <=m_sGridSize.height; ++j)
    102 
    103         {
    104 
    105            // Get original vertex
    106 
    107            ccVertex3F p =originalVertex(ccp(i ,j),m_pBgSprite);
    108 
    109             float x = (p.y + b) / tanf(theta);
    110 
    111             
    112 
    113             float pivotX = x + (p.x - x) * cosf(theta) * cosf(theta);
    114 
    115             float pivotY = pivotX * tanf(theta) - b;
    116 
    117             
    118 
    119             float l = (p.x - pivotX) / sinf(theta);
    120 
    121             float alpha = l / R;
    122 
    123             if (l >= 0) {
    124 
    125                 if (alpha > M_PI) {
    126 
    127                     p.x = (GLfloat)(mHOffsetX + pivotX - R * (alpha -M_PI) *sinf(theta));
    128 
    129                     p.y = (GLfloat)(mHOffsetY + pivotY + R * (alpha -M_PI) *cosf(theta));
    130 
    131                     p.z = (GLfloat)(2 * R /9);
    132 
    133                 }
    134 
    135                 else if (alpha <= M_PI)
    136 
    137                 {
    138 
    139                     p.x = (GLfloat)(mHOffsetX + pivotX + R *sinf(alpha) *sinf(theta));
    140 
    141                     p.y = (GLfloat)(mHOffsetY + pivotY - R *sinf(alpha) *cosf(theta));
    142 
    143                     p.z = (GLfloat)((R - R *cosf(alpha))/9);
    144 
    145                 }
    146 
    147             }
    148 
    149             else
    150 
    151             {
    152 
    153                 p.x +=mHOffsetX;
    154 
    155                 p.y +=mHOffsetY;
    156 
    157             }
    158 
    159             
    160 
    161             setVertex(ccp(i, j), p,m_pBgSprite);
    162 
    163             
    164 
    165             
    166 
    167             
    168 
    169         }
    170 
    171     }
    172 
    173     
    174 
    175     //    float R2 = 50;
    176 
    177     //    float offsetX2 = mTouchBegin.x - pTouch->getLocation().x;
    178 
    179     //    float pivotX2 = m_pForeSpriteVertical->getContentSize().height - offsetX2;
    180 
    181     //
    182 
    183     //
    184 
    185     //    for (int i = 0; i <= m_sGridSize.width; ++i)
    186 
    187     //    {
    188 
    189     //        for (int j = 0; j <= m_sGridSize.height; ++j)
    190 
    191     //        {
    192 
    193     //            // Get original vertex
    194 
    195     //            ccVertex3F p = originalVertex(ccp(i ,j),m_pForeSpriteVertical);
    196 
    197     //            float l = p.x - pivotX2;
    198 
    199     //            float alpha = l / R2;
    200 
    201     //            if (l >= 0) {
    202 
    203     //                if (alpha > M_PI) {
    204 
    205     //                    p.x = mVOffsetX + pivotX2 - R2 * (alpha - M_PI);
    206 
    207     //                    p.z = 2 * R2 / 9;
    208 
    209     //                    p.y = p.y + mVOffsetY;
    210 
    211     //                }
    212 
    213     //                else if (alpha <= M_PI)
    214 
    215     //                {
    216 
    217     //                    p.x = mVOffsetX + pivotX2 + R2 * sinf(alpha);
    218 
    219     //                    p.z = (R2 - R2 * cosf(alpha))/9;
    220 
    221     //                    p.y = p.y + mVOffsetY;
    222 
    223     //                }
    224 
    225     //            }
    226 
    227     //            else
    228 
    229     //            {
    230 
    231     //                p.x = p.x + mVOffsetX;
    232 
    233     //                p.y = p.y + mVOffsetY;
    234 
    235     //            }
    236 
    237     //
    238 
    239     //
    240 
    241     //            // Set new coords
    242 
    243     //            setVertex(ccp(i, j), p,m_pForeSpriteVertical);
    244 
    245     //
    246 
    247     //
    248 
    249     //        }
    250 
    251     //    }
    252 
    253     //
    254 
    255     //    for (int i = 0; i <= m_sGridSize.width; ++i)
    256 
    257     //    {
    258 
    259     //        for (int j = 0; j <= m_sGridSize.height; ++j)
    260 
    261     //        {
    262 
    263     //            // Get original vertex
    264 
    265     //            ccVertex3F p = originalVertex(ccp(i ,j),m_pBgSpriteVertical);
    266 
    267     //            float l = p.x - pivotX2;
    268 
    269     //            float alpha = l / R2;
    270 
    271     //            if (l >= 0) {
    272 
    273     //                if (alpha > M_PI) {
    274 
    275     //                    p.x = mVOffsetX + pivotX2 - R2 * (alpha - M_PI);
    276 
    277     //                    p.z = 2 * R2 / 9;
    278 
    279     //                    p.y = p.y + mVOffsetY;
    280 
    281     //                }
    282 
    283     //                else if (alpha <= M_PI)
    284 
    285     //                {
    286 
    287     //                    p.x = mVOffsetX + pivotX2 + R2 * sinf(alpha);
    288 
    289     //                    p.z = (R2 - R2 * cosf(alpha))/9;
    290 
    291     //                    p.y = p.y + mVOffsetY;
    292 
    293     //                }
    294 
    295     //            }
    296 
    297     //            else
    298 
    299     //            {
    300 
    301     //                p.x = p.x + mVOffsetX;
    302 
    303     //                p.y = p.y + mVOffsetY;
    304 
    305     //            }
    306 
    307     //
    308 
    309     //            // Set new coords
    310 
    311     //            setVertex(ccp(i, j), p,m_pBgSpriteVertical);
    312 
    313     //            
    314 
    315     //            
    316 
    317     //            
    318 
    319     //        }
    320 
    321     //    }
    322 
    323 }

    3d节点的渲染我用的是CCGridBase的子类CCGrid3D,只需要把CCGrid3DAction中渲染的部分摘出来即可,代码在cocos中都有(补充下,我用的是cocos2dx2.2.6),以下是最终效果:

  • 相关阅读:
    C#学习之委托和事件
    ArcGIS许可启动问题
    空间插值——克里金插值
    maven 问题解决 tools以及jconsole两个jar包 无效
    JDBC代码示例
    mysql 同一IP 产生太多终端的数据库连接导致阻塞
    apache 反向代理配置
    oracle、mysql、sql server等;流行数据库的链接驱动配置
    POI XSSF与HSSF的 使用区别
    使用IDEA开发Activiti工作流
  • 原文地址:https://www.cnblogs.com/Red-ButterFly/p/7510660.html
Copyright © 2020-2023  润新知