地球人己阻止不了程序猿们学习cocos2d-x了 (第六篇)

转自http://cocos2d.cocoachina.com/bbs/forum.php?mod=viewthread&tid=3527&extra=page%3D1


内容重点: Hello World 3D, 简单的3D 渲染 + MD2 模型


English version:  http://jameshui.com/?p=10

cocos2d-x 是一个2D 遊戏引擎, 当然主要是拿来写2D遊戏, 但有时候我们会想加些简单的3D 物件做效果或一些特殊的用途, 那该怎麽理呢?

OpenGL ES 2.0 开始, 一切的渲染操作都是用 shader 了, 我首先尝试的是用一些网上找到的 shader, 放到一个 CCLayer 里, 然後在 CCLayer 的 draw() 里画一个3D 的盒子, 可惜试了几个不同的 shader 都没成功.

後来再研究了一下 CCSprite 的 draw(), 发现它用的坐标竟然就是3D的(x, y, z). 所以老话说什麽来著, 寻寻觅觅费劲跑到老远去找你爱的人没找著, 其实她就在你身边只是你没发现...

有了这个发现, 接下来就变得容易了, 基本上可以用 cocos2d-x 本来已有的 shader 就可以渲染简单的3D物件.

(注意: 当测试时, 不要用 cocos2d-x 自带的 HelloWorld, 这个例子的 VC 工程少了一些 lib 的设定, 一定要建立一个新的项目)

在这次的例子里, 我建立了一个叫 Layer3D 的 CCLayer 专门用作渲染3D 物件, 这个 layer 用的 shader 在 init()  里设定为"ShaderPositionTexture":
  1. CCGLProgram* program = CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTexture);
  2.                 setShaderProgram(program);
复制代码



我们想渲染一个有贴图的盒子, 所以同时也载入一张贴图:

  1. mTexture = CCTextureCache::sharedTextureCache()->addImage("HelloWorld.png");
复制代码


接下来我们就可以在 Layer3D 的 draw()  里利用 glDrawArrays 来画3D物件了:

  1.         CCDirector::sharedDirector()->setDepthTest(true);   // 1

  2.         ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );   // 2

  3.         getShaderProgram()->use();  // 3

  4. ccGLBindTexture2D( mTexture->getName() );    // 4
复制代码

1) 要开了 Depth Test, 不然会分不清盒面的前後次序
2) 告诉系统我们会用上顶点列表和贴图座标列表
3) 调用之前设定的 shader
4) 启用盒子的贴图

  1.         ccVertex3F vertices[4];
  2.         ccVertex2F uv[4];

  3.         glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, 0, vertices);
  4.     glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, uv);


  5.         float x = 0;
  6.         float y = 0;
  7.         float len = 8;

  8.         /// front
  9.         vertices[0] = vertex3(x-len,y-len,len);                
  10.         vertices[1] = vertex3(x-len,y+len,len);
  11.         vertices[2] = vertex3(x+len,y-len,len);
  12.         vertices[3] = vertex3(x+len,y+len,len);

  13.         uv[0] = vertex2(0, 1);
  14.         uv[1] = vertex2(0, 0);
  15.         uv[2] = vertex2(1, 1);
  16.         uv[3] = vertex2(1, 0);

  17.     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

  18.         // right
  19.         vertices[0] = vertex3(x+len,y-len,len);                        
  20.         vertices[1] = vertex3(x+len,y+len,len);
  21.         vertices[2] = vertex3(x+len,y-len,-len);
  22.         vertices[3] = vertex3(x+len,y+len,-len);

  23.         uv[0] = vertex2(0, 1);
  24.         uv[1] = vertex2(0, 0);
  25.         uv[2] = vertex2(1, 1);
  26.         uv[3] = vertex2(1, 0);

  27.         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

  28.         / back
  29.         vertices[0] = vertex3(x+len,y-len,-len);        
  30.         vertices[1] = vertex3(x+len,y+len,-len);
  31.         vertices[2] = vertex3(x-len,y-len,-len);
  32.         vertices[3] = vertex3(x-len,y+len,-len);

  33.         uv[0] = vertex2(0, 1);
  34.         uv[1] = vertex2(0, 0);
  35.         uv[2] = vertex2(1, 1);
  36.         uv[3] = vertex2(1, 0);

  37.     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

  38.         // left
  39.         vertices[0] = vertex3(x-len,y-len,len);                        
  40.         vertices[1] = vertex3(x-len,y+len,len);
  41.         vertices[2] = vertex3(x-len,y-len,-len);
  42.         vertices[3] = vertex3(x-len,y+len,-len);

  43.         uv[0] = vertex2(0, 1);
  44.         uv[1] = vertex2(0, 0);
  45.         uv[2] = vertex2(1, 1);
  46.         uv[3] = vertex2(1, 0);

  47.         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  48.         

  49.         / top
  50.         vertices[0] = vertex3(x+len,y+len,len);        
  51.         vertices[1] = vertex3(x-len,y+len,len);
  52.         vertices[2] = vertex3(x+len,y+len,-len);
  53.         vertices[3] = vertex3(x-len,y+len,-len);

  54.         uv[0] = vertex2(0, 0);
  55.         uv[1] = vertex2(1, 0);
  56.         uv[2] = vertex2(0, 1);
  57.         uv[3] = vertex2(1, 1);

  58.     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

  59.         / bottom
  60.         vertices[0] = vertex3(x+len,y-len,len);        
  61.         vertices[1] = vertex3(x-len,y-len,len);
  62.         vertices[2] = vertex3(x+len,y-len,-len);
  63.         vertices[3] = vertex3(x-len,y-len,-len);

  64.         uv[0] = vertex2(0, 0);
  65.         uv[1] = vertex2(1, 0);
  66.         uv[2] = vertex2(0, 1);
  67.         uv[3] = vertex2(1, 1);

  68.     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
复制代码


座标 (0,0,0) 是萤幕的左下角,  如果我们想把盒子移到其他位置, 就要利用 shader 的 matrix 了, 自己设定 matrix 的内容可是一件头痛的事, 还好 cocos2d-x 里自带了 kazmath 库, 我们可以好好的利用一下:

  1.     kmMat4 matrixP;
  2.     kmMat4 matrixMV;
  3.     kmMat4 matrixMVP;

  4.     kmGLGetMatrix(KM_GL_PROJECTION, &matrixP );
  5.     kmGLGetMatrix(KM_GL_MODELVIEW, &matrixMV );

  6.         kmQuaternion quat;
  7.         kmQuaternionRotationYawPitchRoll(&quat, mYaw, mPitch, mRoll); // 1

  8.         kmMat3 rotation;
  9.         kmMat3RotationQuaternion(&rotation, &quat);  // 2

  10.         kmVec3 translation;
  11.         kmVec3Fill(&translation, 240, 150, 220);  // 3

  12.         kmMat4 rotationAndMove;
  13.         kmMat4RotationTranslation(&rotationAndMove, &rotation, &translation);  // 4

  14.     kmMat4Multiply(&matrixMVP, &matrixP, &matrixMV);
  15.         kmMat4Multiply(&matrixMVP, &matrixMVP, &rotationAndMove);        // 5

  16.         GLuint matrixId = glGetUniformLocation(getShaderProgram()->getProgram(), "u_MVPMatrix");
  17.     getShaderProgram()->setUniformLocationwithMatrix4fv(matrixId, matrixMVP.mat, 1);  // 6
复制代码

1) 设定一个带有 X, Y, Z 叁个轴的旋转资料的 quaternion
2) 把 quaternion 换成 3x3 的 matrix
3) 设定移动的数据
4) 设定一个带有旋转和位移的 4x4 matrix
5) 把上边的 matrix 加入到用作更新 shader 的 matrix 里
6) 更新 shader 的 matrix 
box.png 

当然, 如果可以画盒子, 我们自然也可以画3D 模型, 这里就怀旧一下, 我把以前弄的一个 MD2 (Quake2) 模型类移植了过来:

capture02.png capture01.png 
Screen Shot 2012-08-13 at 11.33.54 AM.png 
Screen Shot 2012-08-13 at 11.33.45 AM.png 

这里我只是随便的弄了一下, 大家可以继续研究研究怎样处理 camera 或是加入 lighting 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值