下面的代碼用於我的Android OpenGL-ES遊戲中,在屏幕上繪製帶紋理的矩形。唯一的問題是,不是加載的PNG,而是在矩形上繪製黑色紋理。OpenGL ES繪製黑色紋理
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
。是的,我知道這很醜陋,我打算很快清理整個繼承模型。
有沒有人有任何想法爲什麼紋理被繪製完全黑色?我一直在看這個代碼,所以任何幫助表示讚賞!
這是一個Q&A網站相當多的代碼,我說你需要隔離你的問題有點多。你的紋理是2的權力?如果你用FFFFFF(白色)字節填充它們會發生什麼? – 2014-10-04 17:48:13
紋理是兩個冪(256x256)。用'(char)255'填充圖像數據不會改變。我意識到這是一個很多代碼的事實。但我不知道問題出在哪裏。我認爲片段着色器是正確的。因爲將其更改爲'gl_FragColor = vec4(1,0,0,1)'會產生紅色正方形。由於lodepng返回正確的尺寸,我非常肯定'unsigned char image []'包含正確的字節。但是因爲這是我的第一個OpenGL-ES C++項目,所以我不知道。 – TheDutchDevil 2014-10-04 18:26:25