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

  • 本帖最后由 dr_watson 于 2012-8-16 22:30 编辑 *

内容重点: 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":

CCGLProgram* program = CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTexture);
                setShaderProgram(program);

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


mTexture = CCTextureCache::sharedTextureCache()->addImage("HelloWorld.png");

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



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

        ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );   // 2

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

ccGLBindTexture2D( mTexture->getName() );    // 4


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

        ccVertex3F vertices;
        ccVertex2F uv;

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


        float x = 0;
        float y = 0;
        float len = 8;

        /////////// front
        vertices = vertex3(x-len,y-len,len);                
        vertices = vertex3(x-len,y+len,len);
        vertices = vertex3(x+len,y-len,len);
        vertices = vertex3(x+len,y+len,len);

        uv = vertex2(0, 1);
        uv = vertex2(0, 0);
        uv = vertex2(1, 1);
        uv = vertex2(1, 0);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        ////////// right
        vertices = vertex3(x+len,y-len,len);                        
        vertices = vertex3(x+len,y+len,len);
        vertices = vertex3(x+len,y-len,-len);
        vertices = vertex3(x+len,y+len,-len);

        uv = vertex2(0, 1);
        uv = vertex2(0, 0);
        uv = vertex2(1, 1);
        uv = vertex2(1, 0);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        ///////// back
        vertices = vertex3(x+len,y-len,-len);        
        vertices = vertex3(x+len,y+len,-len);
        vertices = vertex3(x-len,y-len,-len);
        vertices = vertex3(x-len,y+len,-len);

        uv = vertex2(0, 1);
        uv = vertex2(0, 0);
        uv = vertex2(1, 1);
        uv = vertex2(1, 0);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        ////////// left
        vertices = vertex3(x-len,y-len,len);                        
        vertices = vertex3(x-len,y+len,len);
        vertices = vertex3(x-len,y-len,-len);
        vertices = vertex3(x-len,y+len,-len);

        uv = vertex2(0, 1);
        uv = vertex2(0, 0);
        uv = vertex2(1, 1);
        uv = vertex2(1, 0);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        

        ///////// top
        vertices = vertex3(x+len,y+len,len);        
        vertices = vertex3(x-len,y+len,len);
        vertices = vertex3(x+len,y+len,-len);
        vertices = vertex3(x-len,y+len,-len);

        uv = vertex2(0, 0);
        uv = vertex2(1, 0);
        uv = vertex2(0, 1);
        uv = vertex2(1, 1);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        ///////// bottom
        vertices = vertex3(x+len,y-len,len);        
        vertices = vertex3(x-len,y-len,len);
        vertices = vertex3(x+len,y-len,-len);
        vertices = vertex3(x-len,y-len,-len);

        uv = vertex2(0, 0);
        uv = vertex2(1, 0);
        uv = vertex2(0, 1);
        uv = vertex2(1, 1);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);


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


    kmMat4 matrixP;
    kmMat4 matrixMV;
    kmMat4 matrixMVP;

    kmGLGetMatrix(KM_GL_PROJECTION, &matrixP );
    kmGLGetMatrix(KM_GL_MODELVIEW, &matrixMV );

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

        kmMat3 rotation;
        kmMat3RotationQuaternion(&rotation, &quat);  // 2

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

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

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

        GLuint matrixId = glGetUniformLocation(getShaderProgram()->getProgram(), "u_MVPMatrix");
    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
    440

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

442441
444
443

这里我只是随便的弄了一下, 大家可以继续研究研究怎样处理 camera 或是加入 lighting :slight_smile:

445446

449
450

448

:P好好学习…

牛X,啥时候弄个cocos3dx

地球人已经无法阻止了…

— Begin quote from ____

dr_watson 发表于 2012-8-27 11:40 url

在一?.

???工程主要分?是?入3D 模型的方法, 前者用了 fopen, 在 Android 系??出??, 正?的做 …

— End quote

嗯 好的 谢谢了 我试试

— Begin quote from ____

zmzsoftware 发表于 2012-8-27 09:16 url

Demo3D.part1.rar 用的是这个,后面那个地址在哪里我下来试试 我发现在android好多东西都在资源没加载就 …

— End quote

在一?.

???工程主要分?是?入3D 模型的方法, 前者用了 fopen, 在 Android 系??出??, 正?的做法是用CCFileUtils:


const char *path = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(filename);
unsigned char* buffer = CCFileUtils::sharedFileUtils()->getFileData(path, "rb", &fileLen);

— Begin quote from ____

dr_watson 发表于 2012-8-22 15:58 url

??是?LOAD 好模型.

你是用 Demo3D.part1.rar, Demo3D.part2.rar

— End quote

Demo3D.part1.rar 用的是这个,后面那个地址在哪里我下来试试 我发现在android好多东西都在资源没加载就运行都出错,有什么好的解决理法么,之前音乐就是这样的问题

帅气,地球人无法阻止了

强悍啊,留名

— Begin quote from ____

hxl35 发表于 2012-8-14 16:34 url

卧槽啊~人类已经无法阻止楼主了哇!继续学习楼主的教程
话说这个是用2.01版写的么? …

— End quote

?, 是用 cocos2d-x 2.0.1 版本.

:lol 太帅啦~~

加了android 工程:lol

追上了,谢谢分享。:smiley:

地球人已经无法阻止花生大了……

果断mark学习一下!!!

论坛很冷清,大神们加油了!

;P卧槽啊~人类已经无法阻止楼主了哇!继续学习楼主的教程
话说这个是用2.01版写的么?

太好啦,我们可以利用cocos2d-x 学习opengl啦。

  • 本帖最后由 dr_watson 于 2012-8-16 22:32 编辑 *

洋文版:
http://jameshui.com/?p=10

为什么我将
kmVec3Fill(&translation, 240, 150, 220);
改成:
kmVec3Fill(&translation, 240, 150, 0);
时不是从立方体内部看到的,我要怎样才能将视点移到立方体中心呢,怎么实现天空盒的效果呢,
求教育啊