OpenGL ES 学习教程(4):给立方体贴墙纸

发表于2017-11-22
评论0 2k浏览

上一篇制作了一个彩色的旋转的 Cube ,不是很好看,所以想换一个颜色,加入想去实现上图中的效果,那就要把图片贴到人物模型上,这个做设计的就可以搞定 。接下来就用上篇做好的 Cube,给立方体贴上一张墙纸。


首先来了解下 纹理坐标 和 顶点坐标


学术上,把一张图片贴到一个平面上,叫做纹理映射。

怎么映射呢?

看上图中,左边是顶点坐标(-1,1) 右边是纹理坐标 (0,1)

我们只要把纹理坐标的 (0,1) 对应到 顶点的 (-1,1) 就好了。


Tips:纹理坐标又称为 UV 坐标。

好,我搞来一张图片,把这个图片贴到 Cube上。


1、先来添加 Cube 对应 的 UV坐标。

glm::vec3 pos[] =  
{  
    //Front  
    glm::vec3(-1.0f, -1.0f, 1.0f),  
    glm::vec3(1.0f, -1.0f, 1.0f),  
    glm::vec3(1.0f, 1.0f, 1.0f),  
    glm::vec3(-1.0f, -1.0f, 1.0f),  
    glm::vec3(1.0f, 1.0f, 1.0f),  
    glm::vec3(-1.0f, 1.0f, 1.0f),  
    //back  
    glm::vec3(-1.0f, -1.0f, -1.0f),  
    glm::vec3(1.0f, -1.0f, -1.0f),  
    glm::vec3(1.0f, 1.0f, -1.0f),  
    glm::vec3(-1.0f, -1.0f, -1.0f),  
    glm::vec3(1.0f, 1.0f, -1.0f),  
    glm::vec3(-1.0f, 1.0f, -1.0f),  
    //left  
    glm::vec3(-1.0f, -1.0f, -1.0f),  
    glm::vec3(-1.0f, -1.0f, 1.0f),  
    glm::vec3(-1.0f, 1.0f, 1.0f),  
    glm::vec3(-1.0f, -1.0f, -1.0f),  
    glm::vec3(-1.0f, 1.0f, 1.0f),  
    glm::vec3(-1.0f, 1.0f, -1.0f),  
    //right  
    glm::vec3(1.0f, -1.0f, -1.0f),  
    glm::vec3(1.0f, -1.0f, 1.0f),  
    glm::vec3(1.0f, 1.0f, 1.0f),  
    glm::vec3(1.0f, -1.0f, -1.0f),  
    glm::vec3(1.0f, 1.0f, 1.0f),  
    glm::vec3(1.0f, 1.0f, -1.0f),  
    //up  
    glm::vec3(-1.0f, 1.0f, 1.0f),  
    glm::vec3(1.0f, 1.0f, 1.0f),  
    glm::vec3(1.0f, 1.0f, -1.0f),  
    glm::vec3(-1.0f, 1.0f, 1.0f),  
    glm::vec3(1.0f, 1.0f, -1.0f),  
    glm::vec3(-1.0f, 1.0f, -1.0f),  
    //down  
    glm::vec3(-1.0f, -1.0f, 1.0f),  
    glm::vec3(1.0f, -1.0f, 1.0f),  
    glm::vec3(1.0f, -1.0f, -1.0f),  
    glm::vec3(-1.0f, -1.0f, 1.0f),  
    glm::vec3(1.0f, -1.0f, -1.0f),  
    glm::vec3(-1.0f, -1.0f, -1.0f),  
};  
glm::vec2 uv[] =  
{  
    //front  
    glm::vec2(0, 0),  
    glm::vec2(1, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 1),  
    //back  
    glm::vec2(0, 0),  
    glm::vec2(1, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 1),  
    //left  
    glm::vec2(0, 0),  
    glm::vec2(1, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 1),  
    //right  
    glm::vec2(0, 0),  
    glm::vec2(1, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 1),  
    //top  
    glm::vec2(0, 0),  
    glm::vec2(1, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 1),  
    //down  
    glm::vec2(0, 0),  
    glm::vec2(1, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 0),  
    glm::vec2(1, 1),  
    glm::vec2(0, 1)  
};  


2、使用FreeImage读取图片的RGBA数据。

我写了一个 Texture2D 类,来读取图片数据。

void Texture2D::LoadTexture(const char* filename)  
{  
    m_imageFilePath = std::string(filename);  
    //1、获取图片格式;  
    FREE_IMAGE_FORMAT imageformat = FreeImage_GetFileType(filename, 0);  
    //2、根据获取到的格式来加载图片;  
    FIBITMAP *bitmap = FreeImage_Load(imageformat, filename, 0);  
    //3、转化为rag 24色;  
    bitmap = FreeImage_ConvertTo32Bits(bitmap);  
    //4、获取数据指针;  
    BYTE *pixels = (BYTE*)FreeImage_GetBits(bitmap);  
    //5、使用;  
    int width = FreeImage_GetWidth(bitmap);  
    int height = FreeImage_GetHeight(bitmap);  
    //6、交换数据,获得正确的颜色 交换1和3 RGB 原来存储的是 BGR?;  
    for (int i = 0; i < width * height * 4; i += 4)  
    {  
        BYTE r = pixels[i];  
        pixels[i] = pixels[i + 2];  
        pixels[i + 2] = r;  
    }  
    //1、产生一个纹理ID;  
    glGenTextures(1, &m_textureId);  
    //2、关联绑定这个纹理ID;  
    glBindTexture(GL_TEXTURE_2D, m_textureId);  
    //3、指定放大,缩小滤波方式,线性滤波,即放大缩小的插值方式;  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
    //将图片rgb数据上传到OpenGL,在这一步才把数据从内存Copy到显存;  
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);  
    //释放内存;  
    FreeImage_Unload(bitmap);  
}  

3、在Shader 中添加 图片纹理变量。我们要在C++代码中把 读取出来的图片RGBA数据设置到Shader中。在GLProgram_Texture.h 文件中。
virtual bool Initialize()  
{  
    const char* vertexShader=  
    {  
        "precision lowp float;"  
        "uniform mat4 m_mvp;"  
        "attribute vec3 m_position;"  
        "attribute vec4 m_color;"  
        "attribute vec2 m_uv;"  
        "varying vec4 m_outColor;"  
        "varying vec2 m_outUV;"  
        "void main()"  
        "{"  
        "   vec4 pos=vec4(m_position,1);"  
        "   gl_Position=m_mvp*pos;"  
        "   m_outColor=m_color;"  
        "   m_outUV=m_uv;"  
        "}"  
    };  
    const char* fragmentShader =  
    {  
        "precision lowp float;"  
        "uniform sampler2D m_texture;"  
        "varying vec4 m_outColor;"  
        "varying vec2 m_outUV;"  
        "void main()"  
        "{"  
        "   gl_FragColor=m_outColor*texture2D(m_texture,m_outUV);"  
        "}"  
    };  
    bool ret = createProgram(vertexShader, fragmentShader);  
    if (ret)  
    {  
        m_position = glGetAttribLocation(m_programId, "m_position");  
        m_color = glGetAttribLocation(m_programId, "m_color");  
        m_mvp = glGetUniformLocation(m_programId, "m_mvp");  
        m_uv = glGetAttribLocation(m_programId, "m_uv");  
        m_texture = glGetUniformLocation(m_programId, "m_texture");  
    }  
    return ret;  
}  

大概就是这样,然后如果要实现透明效果,不要忘记开启 Blend 。
glEnable(GL_BLEND);  
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  


示例工程下载:http://pan.baidu.com/s/1gdsIcpH   

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引