cocos简单的3d渲染

来源:互联网 发布:连接网络将服务器 编辑:程序博客网 时间:2024/04/28 08:13

文/Cocos2d-X社区版主dr_watson

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

English version 地址点这里 

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[4];

        ccVertex2F uv[4];

        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[0] = vertex3(x-len,y-len,len);                

        vertices[1] = vertex3(x-len,y+len,len);

        vertices[2] = vertex3(x+len,y-len,len);

        vertices[3] = vertex3(x+len,y+len,len);

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

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

        uv[2] = vertex2(1, 1);

        uv[3] = vertex2(1, 0);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        ////////// right

        vertices[0] = vertex3(x+len,y-len,len);                        

        vertices[1] = vertex3(x+len,y+len,len);

        vertices[2] = vertex3(x+len,y-len,-len);

        vertices[3] = vertex3(x+len,y+len,-len);

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

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

        uv[2] = vertex2(1, 1);

        uv[3] = vertex2(1, 0);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        ///////// back

        vertices[0] = vertex3(x+len,y-len,-len);        

        vertices[1] = vertex3(x+len,y+len,-len);

        vertices[2] = vertex3(x-len,y-len,-len);

        vertices[3] = vertex3(x-len,y+len,-len);

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

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

        uv[2] = vertex2(1, 1);

        uv[3] = vertex2(1, 0);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        ////////// left

        vertices[0] = vertex3(x-len,y-len,len);                        

        vertices[1] = vertex3(x-len,y+len,len);

        vertices[2] = vertex3(x-len,y-len,-len);

       vertices[3] = vertex3(x-len,y+len,-len);

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

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

        uv[2] = vertex2(1, 1);

        uv[3] = vertex2(1, 0);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

       ///////// top

        vertices[0] = vertex3(x+len,y+len,len);        

        vertices[1] = vertex3(x-len,y+len,len);

        vertices[2] = vertex3(x+len,y+len,-len);

        vertices[3] = vertex3(x-len,y+len,-len);

        uv[0] = vertex2(0, 0);

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

        uv[2] = vertex2(0, 1);

        uv[3] = vertex2(1, 1);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        ///////// bottom

        vertices[0] = vertex3(x+len,y-len,len);        

        vertices[1] = vertex3(x-len,y-len,len);

        vertices[2] = vertex3(x+len,y-len,-len);

        vertices[3] = vertex3(x-len,y-len,-len);

        uv[0] = vertex2(0, 0);

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

        uv[2] = vertex2(0, 1);

        uv[3] = 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 

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

 

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

原地址:http://www.cocoachina.com/gamedev/gameengine/2012/0816/4606.html

原创粉丝点击