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),以下是最终效果:

原文地址:https://www.cnblogs.com/Red-ButterFly/p/7510660.html