cocos2dx 3D战斗类游戏制作:【五】——私家天空盒

来来来,说到做到,解密我的天空盒:882:

对于GL高手来说,这个东西根本不叫东西,呵呵。不过几个月前这个东西是cocos根本没有的东西,写出来再完成调试可是耗了个把星期的时间的。Cocos应该是也快出天空盒了,到时比较比较哈:14:

skybox.cpp:

#include "SkyBox.h"

SkyBox* SkyBox::loadme(float pSize, std::string pSkyID){
    auto o = new SkyBox();
    o->init(pSize, pSkyID);
    return o;
}
bool SkyBox::init(float pSize, std::string pSkyID){
    BoxID = pSkyID;//天空盒编号,可用于适配多套天空盒
    BoxSize = pSize;//天空盒尺寸
    log("hahahaha  skybox init......................................................");
    if ( !Node::init() ){return false;}
    mShaderProgram = new GLProgram;
    mShaderProgram->initWithFilenames("skybox/myshader.vert", "skybox/myshader.frag");//vert和frag文件放于resources/skybox目录下
    //mShaderProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
    //mShaderProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
    mShaderProgram->link();
    mShaderProgram->updateUniforms();
    _textureB = Director::getInstance()->getTextureCache()->addImage("skybox/" + BoxID + "/back.jpg")->getName();//back面纹理图片
    _textureF = Director::getInstance()->getTextureCache()->addImage("skybox/" + BoxID + "/front.jpg")->getName();//front面纹理图片
    _textureD = Director::getInstance()->getTextureCache()->addImage("skybox/" + BoxID + "/down.jpg")->getName();//down面纹理图片
    _textureU = Director::getInstance()->getTextureCache()->addImage("skybox/" + BoxID + "/up.jpg")->getName();//up面纹理图片
    _textureL = Director::getInstance()->getTextureCache()->addImage("skybox/" + BoxID + "/left.jpg")->getName();//left面纹理图片
    _textureR = Director::getInstance()->getTextureCache()->addImage("skybox/" + BoxID + "/right.jpg")->getName();//right面纹理图片

    glGenBuffers(1, &skyboxVertexBuffer);//顶点数据缓存
    glBindBuffer(GL_ARRAY_BUFFER, skyboxVertexBuffer);
    glGenBuffers(1, &skyboxIndexBuffer);//索引数据缓存
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, skyboxIndexBuffer);    
    return true;
}
void SkyBox::draw(cocos2d::Renderer *renderer, const Mat4 &transform, uint32_t transformUpdated){
    Node::draw(renderer, transform, transformUpdated);
    onDraw();
}
void SkyBox::onDraw(){
    typedef struct {
        float Position;
        float TexCoord;
    } Vertex;
    Vertex Vertices] = {//正方形顶点数组
        { { 1, 1, 1 },  { 1, 0 } }, { { 1, -1, 1 },  { 1, 1 } }, { { -1, -1, 1 },  { 0, 1 } }, { { -1, 1, 1 },  { 0, 0 } },// Front
        { { -1, -1, -1 },  { 1, 1 } }, { { 1, 1, -1 },  { 0, 0 } }, { { -1, 1, -1 },  { 1, 0 } }, { { 1, -1, -1 },  { 0, 1 } },// Back
        { { -1, 1, 1 },  { 1, 0 } }, { { -1, -1, 1 },  { 1, 1 } }, { { -1, -1, -1 },  { 0, 1 } }, { { -1, 1, -1 },  { 0, 0 } },// Left
        { { 1, 1, -1 },  { 1, 0 } }, { { 1, -1, -1 },  { 1, 1 } }, { { 1, -1, 1 },  { 0, 1 } }, { { 1, 1, 1 },  { 0, 0 } },// Right
        { { 1, 1, -1 },  { 1, 0 } }, { { -1, 1, -1 },  { 0, 0 } }, { { -1, 1, 1 },  { 0, 1 } }, { { 1, 1, 1 },  { 1, 1 } },// Top
        { { 1, -1, 1 },  { 1, 0 } }, { { -1, -1, 1 },  { 0, 0 } }, { { -1, -1, -1 },  { 0, 1 } }, { { 1, -1, -1 },  { 1, 1 } }// Bottom
    };
    int vertexCount = sizeof(Vertices) / sizeof(Vertices);
    GLubyte Indices] = {//指定三角形的索引
        0, 1, 2, 2, 3, 0// Front
        ,4, 5, 6, 4, 5, 7// Back
        ,8, 9, 10, 10, 11, 8// Left
        ,12, 13, 14, 14, 15, 12// Right
        ,16, 17, 18, 18, 19, 16// Top
        ,20, 21, 22, 22, 23, 20// Bottom
    };
    //创建索引缓冲区并绑定索引数据到缓冲区
    glBindBuffer(GL_ARRAY_BUFFER, skyboxVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, skyboxIndexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
    _positionLocation = glGetAttribLocation(mShaderProgram->getProgram(), "Position");//从着色器源程序中获取Position存储位置
    _modelViewUniform = glGetUniformLocation(mShaderProgram->getProgram(), "Modelview");//从着色器源程序中获取Modelview存储位置
    _textureLocation = glGetAttribLocation(mShaderProgram->getProgram(), "TextureCoord");//从着色器源程序中获取TextureCoord存储位置
    _textureUniform = glGetUniformLocation(mShaderProgram->getProgram(), "CC_Texture0");//从着色器源程序中获取CC_Texture0存储位置
    Mat4 modelView = this->getNodeToWorldTransform();//获取视口矩阵
    modelView.scale(BoxSize);//矩阵按BoxSize缩放
    mShaderProgram->use();// Use the program object
    mShaderProgram->setUniformsForBuiltins();//更新CC_MVPMatrix
    mShaderProgram->setUniformLocationWithMatrix4fv(_modelViewUniform, modelView.m, 1);//设置modelView到_modelViewUniform,传值给.vert
    glEnableVertexAttribArray(_positionLocation);//开启顶点属性数组
    glEnableVertexAttribArray(_textureLocation);//开启顶点属性数组
    glVertexAttribPointer(_positionLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Position));//位置信息赋值(1..顶点着色器位置属性;2..每一个顶点信息由几个值组成;3..顶点信息的数据类型;4..不要将数据类型标准化;5..数组中每个元素的长度;6..数组的首地址)
    glVertexAttribPointer(_textureLocation, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, TexCoord));//颜色信息赋值(1..顶点着色器位置属性;2..每一个顶点信息由几个值组成;3..顶点信息的数据类型;4..不要将数据类型标准化;5..数组中每个元素的长度;6..数组的首地址)
    //CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, vertexCount);//统计显示的顶点数
    GL::bindTexture2D(_textureB);//绑定back面纹理
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (GLvoid*)0);//基本图元的类型/顶点数/索引数据类型/索引数据在缓冲区的偏移(0)
    GL::bindTexture2D(_textureF);//绑定front面纹理
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (GLvoid*)6);//基本图元的类型/顶点数/索引数据类型/索引数据在缓冲区的偏移(6)
    GL::bindTexture2D(_textureL);//绑定left面纹理
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (GLvoid*)12);//基本图元的类型/顶点数/索引数据类型/索引数据在缓冲区的偏移(12)
    GL::bindTexture2D(_textureR);//绑定right面纹理
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (GLvoid*)18);//基本图元的类型/顶点数/索引数据类型/索引数据在缓冲区的偏移(18)
    GL::bindTexture2D(_textureU);//绑定up面纹理
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (GLvoid*)24);//基本图元的类型/顶点数/索引数据类型/索引数据在缓冲区的偏移(24)
    GL::bindTexture2D(_textureD);//绑定down面纹理
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (GLvoid*)30);//基本图元的类型/顶点数/索引数据类型/索引数据在缓冲区的偏移(30)
    mShaderProgram->setUniformLocationWith1i(_textureUniform, 0);//向着色器设置一致变量_textureUniform的值
    CHECK_GL_ERROR_DEBUG();
}


```


skybox.h:
#ifndef __SKYBOX_H__
#define __SKYBOX_H__
#include "cocos2d.h"
USING_NS_CC;

class SkyBox : public cocos2d::Node{
public:
    static SkyBox* loadme(float pSize, std::string pSkyID);
    virtual bool init(float pSize, std::string pSkyID);
private:
    virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t transformUpdated) override;
    void onDraw();
    Camera*_Camera;
    float BoxSize;
    std::string BoxID;
    Mat4 _modelViewMV;
    CustomCommand _customCommand;
    
    GLProgram *mShaderProgram;
    GLint _positionLocation;
    GLint _textureLocation;
    GLuint _modelViewUniform;
    GLuint _textureUniform;
    GLuint _textureU;
    GLuint _textureD;
    GLuint _textureF;
    GLuint _textureB;
    GLuint _textureL;
    GLuint _textureR;
    GLuint skyboxVertexBuffer;
    GLuint skyboxIndexBuffer;
};
#endif


```



myshader.vert

attribute vec4 Position;
attribute vec2 TextureCoord;
uniform mat4 Modelview;
varying vec2 v_texCoord;
void main(void) {
    v_texCoord = TextureCoord;
    gl_Position = CC_PMatrix * Modelview * Position;
}


```



myshader.frag

//varying vec4 DestinationColor;
//uniform sampler2D CC_Texture0;
varying vec2 v_texCoord;
void main(void) {
    //gl_FragColor = DestinationColor * texture2D(CC_Texture0, v_texCoord);
    gl_FragColor = texture2D(CC_Texture0, v_texCoord);
}

```


在场景中添加天空盒的代码:

            auto skybox = SkyBox::loadme(100000, "12");//创建SKYBOX,图片目录为resources/skybox/12
            addChild(skybox, -10000);

```




简单吧,嘿嘿,注释成那样,要是还要写什么说明,那也就醉了吧,嘿嘿

附上像素非常低的图片一套,拿去玩吧,什么什么?要高清图片?我也要。。。。。能给我几套不?

这方法,原理是对了,实现方式不够高效,高大上的有种两种方法,
但是都控制在一个glDrawElements完成。

3.6beta已经有了skybox了

暂时还没准备切换到3.6的天空盒,看代码的话那个没有做矩阵投射变换,所以貌似没有支持相机漫游,不知道是不是没看透。

正好需要用到,多谢楼主分享!

正在开发的项目中,设置了3个camera,加入Skybox后,设置和不设置 CameraFlag 都尝试了,看不到效果。

又新建项目测试了一下,编译、draw,onDraw 都有执行,但是跟没加天空盒,效果上也没有差别。

楼主知道是什么问题吗,或者有测试代码吗?多谢!

CameraFlag是一定要设置的。

不知道楼主说的我这个,还是cocos自带那个。

新手踩点:2: