以下代码用于我的Android OpenGL-ES游戏,在屏幕上绘制纹理矩形。唯一的问题是,不是加载的PNG,而是在矩形上绘制黑色纹理。
AssetManager.cpp(将文件从文件系统加载到内存中)
void AssetManager::Retrieve() {
auto file = File("spritesheet_full.png");
if (!file.Open()) {
PrintVerbose("Woops");
}
unsigned char dataA[file.Length()];
size_t position = 0;
file.Read(dataA, file.Length(), position);
auto data = std::vector<unsigned char>(dataA, dataA + file.Length());
auto png = PNG(data);
Texture::Header textureHeader;
textureHeader.width = png.getWidth();
textureHeader.height = png.getHeight();
textureHeader.bytesPerPixel = 4;
textureHeader.dataSize = textureHeader.width * textureHeader.height
* textureHeader.bytesPerPixel;
texture.SetData(textureHeader, png.getData());
texture.Init();
}
PNG.cpp(读取数据并将其解码为原始图像数据。我假设此部分有效,因为读取宽度和高度正确。image
定义为unsigned char* image
)
PNG::PNG(std::vector<unsigned char> data)
{
std::vector<unsigned char> rawImage;
lodepng::decode(rawImage, width, height, data);
image = new unsigned char[width * height* 4];
for(int i = 0; i < width * height * 4; i++)
{
image[i] = rawImage[i];
}
}
Texture.cpp(包含图像数据,并将其与OpenGL链接)
Texture::Texture() :
id(GL_INVALID_VALUE) {
}
Texture::~Texture() {
}
void Texture::SetData(Texture::Header& header, void* pImageData) {
headerData = header;
imageData = pImageData;
}
void Texture::Init() {
GLint packBits = 4;
GLint internalFormat = GL_RGBA;
GLenum format = GL_RGBA;
switch (headerData.bytesPerPixel) {
case 1: {
packBits = 1;
internalFormat = GL_ALPHA;
format = GL_ALPHA;
}
break;
};
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, packBits);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, headerData.width,
headerData.height, 0, format, GL_UNSIGNED_BYTE, imageData);
}
TextureShader.cpp(纹理链接到着色器,通过一个简单的getter。然后由渲染器调用TextureShader::Setup
)
TextureShader::TextureShader() :
texture(NULL) {
vertexShaderCode = "attribute vec2 position; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 v_texCoord; \n"
"uniform mat4 projView; \n"
"uniform mat4 transformMatrix; \n"
"uniform mat4 cameraTransform; \n"
"void main(){ \n"
" gl_Position = projView * (cameraTransform * (transformMatrix * vec4(position, 0.0, 1.0))); \n"
" v_texCoord = a_texCoord; \n"
"} \n";
fragmentShaderCode = "precision highp float; \n"
"varying vec2 v_texCoord; \n"
"uniform sampler2D s_texture; \n"
"void main(){ \n"
" gl_FragColor = texture2D(s_texture, v_texCoord); \n"
"} \n";
}
TextureShader::~TextureShader() {
}
void TextureShader::Link() {
Shader::Link();
this->positionAttributeHandle = glGetAttribLocation(programId, "position");
this->texCoordAttributeHandle = glGetAttribLocation(programId, "a_texCoord");
this->samplerHandle = glGetUniformLocation(programId, "s_texture");
this->projectionViewUniformHandle = glGetUniformLocation(programId, "projView");
this->transformationUniformHandle = glGetUniformLocation(programId, "transformMatrix");
this->cameraTransformUniformHandle = glGetUniformLocation(programId, "cameraTransform");
}
void TextureShader::Setup(Renderable* renderable, GLfloat* cameraTransform,
GLfloat* projectionView) {
Geometry* pGeometry = renderable->GetGeometry();
if (pGeometry && texture) {
Shader::Setup(renderable, cameraTransform, projectionView);
glActiveTexture (GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture->GetId());
glUniform1i(samplerHandle, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUniformMatrix4fv(projectionViewUniformHandle, 1, GL_FALSE, projectionView);
glUniformMatrix4fv(transformationUniformHandle, 1, GL_FALSE, renderable->GetTransform()->GetTranslateMatrix());
glUniformMatrix4fv(cameraTransformUniformHandle, 1, GL_FALSE, cameraTransform);
glVertexAttribPointer(positionAttributeHandle,
pGeometry->GetNumVertexPositionElements(), GL_FLOAT, GL_FALSE,
pGeometry->GetVertexStride(), pGeometry->GetVertexBuffer());
glEnableVertexAttribArray(positionAttributeHandle);
glVertexAttribPointer(texCoordAttributeHandle,
pGeometry->GetNumTexCoordElements(), GL_FLOAT, GL_FALSE,
pGeometry->GetTextStride(),
pGeometry->GetTextureCoordinates());
glEnableVertexAttribArray(texCoordAttributeHandle);
}
}
Renderer.cpp(维护可渲染实体并渲染它们)
void Renderer::Init()
{
// initialize OpenGL ES and EGL
/*
* Here specify the attributes of the desired configuration.
* Below, we select an EGLConfig with at least 8 bits per color
* component compatible with on-screen windows
*/
const EGLint attribs[] =
{ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE };
EGLint format;
EGLint numConfigs;
EGLConfig config;
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, NULL, NULL);
/* Here, the application chooses the configuration it desires. In this
* sample, we have a very simplified selection process, where we pick
* the first EGLConfig that matches our criteria */
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
* guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
* As soon as we picked a EGLConfig, we can safely reconfigure the
* ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(appState->window, 0, 0, format);
drawingSurface = eglCreateWindowSurface(display, config, appState->window,
NULL);
EGLint contextAttribs[] =
{ EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
context = eglCreateContext(display, config, NULL, contextAttribs);
eglMakeCurrent(display, drawingSurface, drawingSurface, context);
eglQuerySurface(display, drawingSurface, EGL_WIDTH, &width);
eglQuerySurface(display, drawingSurface, EGL_HEIGHT, &height);
this->SetProjectionMatrix();
this->SetCameraTransform();
for (ShaderVectorIterator iter = shaders.begin(); iter != shaders.end();
++iter)
{
Shader* pCurrent = *iter;
pCurrent->Link();
}
initialized = true;
}
void Renderer::Draw(Renderable* pRenderable)
{
assert(pRenderable);
if (pRenderable)
{
Geometry* pGeometry = pRenderable->GetGeometry();
Shader* pShader = pRenderable->GetShader();
assert(pShader && pGeometry);
if (pShader && pGeometry)
{
pShader->Setup(pRenderable, cameraTransform, projectionMatrix);
glDrawElements(GL_TRIANGLES, pGeometry->GetNumIndices(),
GL_UNSIGNED_SHORT, pGeometry->GetIndexBuffer());
}
}
}
void Renderer::Update()
{
if (initialized)
{
glClearColor(0.95f, 0.95f, 0.95f, 1);
glClear(GL_COLOR_BUFFER_BIT);
for (RenderableVectorIterator iter = renderables.begin();
iter != renderables.end(); ++iter)
{
Renderable* pRenderable = *iter;
if (pRenderable)
{
Draw(pRenderable);
}
}
eglSwapBuffers(display, drawingSurface);
}
}
TexturedRectangle.cpp(扩展了Rectangle.cpp)
TexturedRectangle::TexturedRectangle(int posX, int posY, int width, int height, Texture* texture)
: Engine::Rectangle(posX, posY, width, height),
texture(texture),
textCords({0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f})
{
shader = new TextureShader();
auto texShader = (TextureShader*)shader;
texShader->SetTexture(texture);
SetShader(texShader);
GetGeometry()->SetTextureCoordinates(&textCords);
GetGeometry()->SetTexStride(sizeof(float) * 2);
GetGeometry()->SetNumTexCoordElements(2);
}
Rectangle.cpp(verts
是float verts[8]
并包含一个矩形相对坐标列表)
Rectangle::Rectangle(int posX, int posY, int width, int height) :
verts(),
indices( { 0, 2, 1, 2, 3, 1 }),
colors( { 0.8, 0.8, 0.3, 1.0,
0.8, 0.8, 0.3, 1.0,
0.8, 0.8, 0.3, 1.0,
0.8, 0.8, 0.3, 1.0,
0.8, 0.8, 0.3, 1.0,
0.8, 0.8, 0.3, 1.0, }),
shader(new OrthoGraphicShader())
{
float leftX = 0 - (width / 2.f);
float rightX = width / 2.f;
float upperY = 0 - (height / 2.f);
float lowerY = height / 2.f;
verts[0] = leftX;
verts[1] = upperY;
verts[2] = rightX;
verts[3] = upperY;
verts[4] = leftX;
verts[5] = lowerY;
verts[6] = rightX;
verts[7] = lowerY;
this->SetGeometry(&geometry);
this->SetShader(shader);
this->SetTransform(&transform);
this->Translate(posX, posY);
geometry.SetVertexBuffer(verts);
geometry.SetNumVertices(4);
geometry.SetIndexBuffer(indices);
geometry.SetNumIndices(6);
geometry.SetName("quad");
geometry.SetNumVertexPositionElements(2);
geometry.SetVertexStride(sizeof(float) * 2);
geometry.SetColor(colors);
}
由于Rectangle和TexturedRectangle colors
之间的继承从未使用过。是的,我知道它很难看,而且我打算尽快清理整个继承模型。
有没有人知道为什么纹理被完全拉成黑色?我一整天都在看这个代码,所以感谢任何帮助!
答案 0 :(得分:0)
好的,我弄清楚问题是什么。在渲染器创建OpenGL上下文之前,我调用了Texture :: Init()来设置纹理数据。
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, headerData.width, headerData.height, 0, format, GL_UNSIGNED_BYTE, imageData);
创建上下文由以下行完成:
context = eglCreateContext(display, config, NULL, contextAttribs);