本文介绍了如何使用OpenGL ES 2.0 API实现纹理图片的叠加显示效果。
vs2013 / C++
libEGL.lib : windows上的OpenGL ES环境
libGLESv2.lib : OpenGL ES 2.0 API
d3dcompiler_47.dll : 使用DX来模拟OpenGL
FreeImage.lib/dll : 加载纹理数据
代码架构: 仿cocos2d-x结构,启动点在ELAppdelegate.cpp.
MultiTexture.h
#pragma once
#include "gl_include.h"
#include "ELShaderProgram.h"
#include
NS_BEGIN(elloop);
class MultiTexture : public ShaderProgram
{
public:
static MultiTexture* create();
void begin() override;
void end() override;
void render() override;
uniform mvp_;
uniform textureBg_;
uniform textureCloud_;
uniform deltaUv_;
attribute position_;
attribute uv_;
unsigned int textureBgId_;
unsigned int textureCloudId_;
protected:
struct Vertex
{
CELL::float2 pos;
CELL::float2 uv;
};
bool init();
MultiTexture()
: mvp_(-1)
, textureBg_(-1)
, textureCloud_(-1)
, textureBgId_(-1)
, textureCloudId_(-1)
, position_(-1)
, uv_(-1)
, deltaUv_(-1)
{
vsFileName_ = "shaders/multi_texture_vs.glsl";
fsFileName_ = "shaders/multi_texture_fs.glsl";
}
~MultiTexture()
{}
unsigned int loadTexture(const std::string &fileName);
};
NS_END(elloop);
MultiTexture.h
#include "scenes/MultiTexture.h"
#include "app_control/ELDirector.h"
#include "math/ELGeometry.h"
#include "include/freeImage/FreeImage.h"
NS_BEGIN(elloop);
void MultiTexture::begin()
{
glUseProgram(programId_);
glEnableVertexAttribArray(position_);
glEnableVertexAttribArray(uv_);
}
void MultiTexture::end()
{
glDisableVertexAttribArray(uv_);
glDisableVertexAttribArray(position_);
glUseProgram(0);
}
bool MultiTexture::init()
{
valid_ = ShaderProgram::initWithFile(vsFileName_, fsFileName_);
if ( valid_ )
{
position_ = glGetAttribLocation(programId_, "position_");
uv_ = glGetAttribLocation(programId_, "uv_");
deltaUv_ = glGetUniformLocation(programId_, "deltaUv_");
textureBg_ = glGetUniformLocation(programId_, "textureBg_");
textureCloud_ = glGetUniformLocation(programId_, "textureCloud_");
mvp_ = glGetUniformLocation(programId_, "mvp_");
}
textureBgId_ = loadTexture("images/dog.png");
textureCloudId_ = loadTexture("images/fog.bmp");
return valid_;
}
MultiTexture* MultiTexture::create()
{
auto * self = new MultiTexture();
if ( self && self->init() )
{
self->autorelease();
return self;
}
return nullptr;
}
unsigned int MultiTexture::loadTexture(const std::string &fileName)
{
unsigned int textureId = 0;
FREE_IMAGE_FORMAT format = FreeImage_GetFileType(fileName.c_str(), 0);
FIBITMAP *bitmap = FreeImage_Load(format, fileName.c_str(), 0);
bitmap = FreeImage_ConvertTo24Bits(bitmap);
BYTE *pixels = FreeImage_GetBits(bitmap);
int width = FreeImage_GetWidth(bitmap);
int height = FreeImage_GetHeight(bitmap);
for (size_t i=0; i3; i+=3)
{
BYTE temp = pixels[i];
pixels[i] = pixels[i+2];
pixels[i+2] = temp;
}
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_RGB,GL_UNSIGNED_BYTE,pixels);
FreeImage_Unload(bitmap);
return textureId;
}
void MultiTexture::render()
{
using namespace CELL;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auto director = Director::getInstance();
Size s = director->getFrameSize();
float width = s.width_;
float height = s.height_;
glViewport(0, 0, width, height);
begin();
matrix4 screenProj = ortho<float>(0, width, height, 0, -100.0f, 100);
GLfloat x = 100;
GLfloat y = 100;
GLfloat w = 300;
GLfloat h = 300;
Vertex ary[] =
{
float2{ x, y }, float2(0, 1),
float2{ x + w, y }, float2(1, 1),
float2{ x, y + h }, float2(0, 0),
float2{ x + w, y + h }, float2(1, 0),
};
static float incUv = 0;
incUv += 0.01;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureBgId_);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureCloudId_);
glUniformMatrix4fv(mvp_, 1, false, screenProj.data());
glUniform1i(textureBg_, 0);
glUniform1i(textureCloud_, 1);
glUniform1f(deltaUv_, incUv);
glVertexAttribPointer(position_, 2, GL_FLOAT, false, sizeof(Vertex), ary);
glVertexAttribPointer(uv_, 2, GL_FLOAT, false, sizeof(Vertex), &(ary[0].uv));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
end();
}
NS_END(elloop);
顶点着色器:multi_texture_vs.glsl
precision lowp float;
attribute vec2 position_;
uniform mat4 mvp_;
attribute vec2 uv_;
varying vec2 outUv_;
void main() {
vec4 pos = vec4(position_, 0, 1);
gl_Position = mvp_ * pos;
outUv_ = uv_;
}
片段着色器:multi_texture_fs.glsl
precision lowp float;
varying vec2 outUv_;
uniform sampler2D textureBg_;
uniform sampler2D textureCloud_;
uniform float deltaUv_;
void main()
{
vec4 bgColor = texture2D(textureBg_, outUv_);
vec2 moveUv = vec2(outUv_.x + deltaUv_, outUv_.y);
vec4 cloudColor = texture2D(textureCloud_, moveUv);
gl_FragColor = bgColor + cloudColor;
/* gl_FragColor = mix(bgColor, cloudColor, 0.5); */
}
有空的时候再来补充注释及说明,想了解更多内容请参考源码部分。
在绑定纹理的时候,误把glBindTexture(GL_TEXTURE_2D, &textureId)
误写为glBindTexture(GL_SAMPLER_2D, &textureId)
, 导致只能加载最后一次调用loadTexture()的纹理。今后不会混淆GL_TEXTURE_2D
和GL_SAMPLER_2D
了。
源码中包含
如果源码对您有帮助,请帮忙在github上给我点个Star, 感谢 :)
作者水平有限,对相关知识的理解和总结难免有错误,还望给予指正,非常感谢!
在这里也能看到这篇文章:github博客, CSDN博客, 欢迎访问