Android OpenGL UV mapping error after triangulating - android

I'm building an Android app to render 3d (wavefront.obj) model. By using tinyobjloader, I can successfully load the model.
Code:
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> uvs;
std::vector<glm::vec3> normals;
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
for(size_t s =0; s < shapes.size(); s++)
{
size_t index_offset = 0;
for(size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++)
{
int fv = shapes[s].mesh.num_face_vertices[f];
for(size_t v = 0; v < fv; v++)
{
tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
tinyobj::real_t vx = attrib.vertices[3*idx.vertex_index+0];
tinyobj::real_t vy = attrib.vertices[3*idx.vertex_index+1];
tinyobj::real_t vz = attrib.vertices[3*idx.vertex_index+2];
tinyobj::real_t nx = attrib.normals[3*idx.normal_index+0];
tinyobj::real_t ny = attrib.normals[3*idx.normal_index+1];
tinyobj::real_t nz = attrib.normals[3*idx.normal_index+2];
tinyobj::real_t ux = attrib.texcoords[2*idx.texcoord_index+0];
tinyobj::real_t uy = attrib.texcoords[2*idx.texcoord_index+1];
vertices.push_back(glm::vec3(vx,vy,vz));
normals.push_back(glm::vec3(nx,ny,nz));
uvs.push_back(glm::vec2(ux,uy));
}
index_offset += fv;
}
}
Because the original .obj file has multiple faces format, i.e:
f 1/2/3 3/2/1 3/2/3
f 1/2/3 1/3/4 1/4/5 6/7/2
so that I use Blender Triangulate with 'Beauty' option to convert quad to triangle. But the rendered result is weird
I have built two function to initOpenGL (run once) and render().
initOpenGL code:
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &UVBO);
glBindBuffer(GL_ARRAY_BUFFER, UVBO);
glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(glm::vec2), &uvs[0], GL_STATIC_DRAW);
//Linking Vertex Attribute
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
//bind texture
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, UVBO);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
//load texture
//texture1
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
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);
if(patternSrc1)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, patWidth1, patHeight1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
patternSrc1);
//glGenerateMipmap(GL_TEXTURE_2D);
}
render() code:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram);
camera.ProcessOneFinger(moveStpX, moveStpY);
camera.ProcessTwoFinger(move2X, move2Y);
projection = glm::perspective(camera.GetZoom(), (GLfloat)600/(GLfloat)1024, nearPlane, farPlane);
view = camera.GetViewMatrix();
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view));
glm::mat4 model;
model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));
GLfloat angle = 20.0f;
model = glm::rotate(model, angle, glm::vec3( 1.0f, 0.3f, 0.5f));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr( model ) );
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
Model detail
Texture:
Model.obj file after triangulated:
https://pastebin.com/vUjHv8Fr
Thank you!!!

This looks to me like your texture is upside down. There's basically two potential errors that could each lead to this happening. Most likely, the texture image itself is upside down, e.g., because the image data passed to glTexImage2D() is in the wrong order. Unlike most other APIs, OpenGL (by default) expects pixel data in row-wise order starting from the bottom row. Check the way you load the texture data to make sure it's in the right order.
If this is not the problem, then it might be that your texture coordinates are for a left-handed texture coordinate system. OpenGL, however, uses right-handed texture coordinates where the origin is the lower-left corner of the texture image rather than the upper left corner. I'm not a Blender guy, but there's probably an export setting for this…

Related

opengl es multi-pass blurring the second pass overrides the first pass

I am not very good with opengl es so any beginner mistake in the code is justified. I have implemented the draw function to execute the same fragment shader with different uniform variable called blurringDirection, if I execute the horizontal blurring alone(by setting the blurringDirection to 0) it works fine, also the same for the vertical but when I try to combine them together the second overrides the first. Here is my draw() function:
fun draw(
mvpMatrix: FloatArray?,
vertexBuffer: FloatBuffer?,
firstVertex: Int,
vertexCount: Int,
coordsPerVertex: Int,
vertexStride: Int,
texMatrix: FloatArray?,
texBuffer: FloatBuffer?,
textureId: Int,
texStride: Int,
) {
//creating an intermediate texture
val intermediateTexIdArr = IntArray(1)
GLES20.glGenTextures(1, intermediateTexIdArr, 0)
glBindTexture(GL_TEXTURE_2D, intermediateTexIdArr[0])
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 640, 360, 0, GL_RGBA, GL_UNSIGNED_BYTE, null)
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)
glBindTexture(GL_TEXTURE_2D, 0)
//creating a framebuffer and attaching the newly created texture to it.
val frameBufferIdArr = IntArray(1)
GLES20.glGenFramebuffers(1, frameBufferIdArr, 0)
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferIdArr[0])
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTexIdArr[0], 0)
val status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
Timber.d("KingArmstring: Framebuffer status is complete? ${status == GL_FRAMEBUFFER_COMPLETE}") //this prints true
if (status != GL_FRAMEBUFFER_COMPLETE) throw Exception("Framebuffer is not setup correctly")
//bind to the framebuffer instead of to the screen.
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferIdArr[0])
glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
// Select the program.
glUseProgram(programHandle)
checkGlError("glUseProgram")
// Set the texture.
glActiveTexture(GL_TEXTURE0)
glBindTexture(textureTarget, textureId) //textureId is the main id that has the original image
// Copy the model / view / projection matrix over.
glUniformMatrix4fv(mvpMatrixLoc, 1, false, mvpMatrix, 0)
checkGlError("glUniformMatrix4fv")
// Copy the texture transformation matrix over.
glUniformMatrix4fv(texMatrixLoc, 1, false, texMatrix, 0)
checkGlError("glUniformMatrix4fv")
// Enable the "aPosition" vertex attribute.
glEnableVertexAttribArray(positionLoc)
checkGlError("glEnableVertexAttribArray")
// Connect vertexBuffer to "aPosition".
glVertexAttribPointer(
positionLoc, coordsPerVertex,
GL_FLOAT, false, vertexStride, vertexBuffer
)
checkGlError("glVertexAttribPointer")
// Enable the "aTextureCoord" vertex attribute.
glEnableVertexAttribArray(textureCoordLoc)
checkGlError("glEnableVertexAttribArray")
// Connect texBuffer to "aTextureCoord".
glVertexAttribPointer(
textureCoordLoc, 2,
GL_FLOAT, false, texStride, texBuffer
)
checkGlError("glVertexAttribPointer")
if (programType == VIDEO_STREAM) {
glUniform1f(brightnessLoc, brightness)
glUniform1f(contrastLoc, contrast)
glUniform1f(saturationLoc, saturation)
glUniform1f(gammaLoc, gamma)
glUniform1f(whiteBalanceTempLoc, whiteBalanceTemp)
glUniform1f(whiteBalanceTintLoc, whiteBalanceTint)
glUniform1f(whiteBalanceEnabledLoc, whiteBalanceEnabled)
glUniform1f(hueAdjLoc, hueAdj)
glUniform1f(hueAdjEnabledLoc, hueAdjEnabled)
glUniform1f(sharpnessLoc, sharpness)
glUniform1f(imageWidthFactorLoc, imageWidthFactor)
glUniform1f(imageHeightFactorLoc, imageHeightFactor)
}
glUniform1i(blurringDirectionLoc, 0)
// Draw the rect.
glDrawArrays(GL_TRIANGLE_STRIP, firstVertex, vertexCount)//rendering to the framebuffer with the blurringDirection = 0
checkGlError("glDrawElements")
glBindFramebuffer(GL_FRAMEBUFFER, 0)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, intermediateTexIdArr[0])
glUniform1i(blurringDirectionLoc, 1)
glDrawArrays(GL_TRIANGLE_STRIP, firstVertex, vertexCount)//drawing on the screen second pass with the blurringDirection = 1.
glDisableVertexAttribArray(positionLoc)
glDisableVertexAttribArray(textureCoordLoc)
GLES20.glDeleteFramebuffers(1, frameBufferIdArr, 0)
GLES20.glDeleteTextures(1, intermediateTexIdArr, 0)
}

Freetype Library gives triple textures and weird symbols

Currently working on an android ndk/ opengl project and I'm trying to use freetype as my font rendering library, but I keep getting a weird error when I render text to the screen. Here is what it is showing for a few sample texts: (note: the bottom one is supposed to say "This is")
Setup:
void TextRenderer::SetupGlyphs(std::string fontPath, int size){
__android_log_print(ANDROID_LOG_INFO, "SetupGlyphs", "Font location: %s", fontPath.c_str());
if(shadersInitialized == 0)
CreateShader();
glUseProgram(this->shader);
// FreeType
FT_Library ft;
if (FT_Init_FreeType(&ft))
__android_log_print(ANDROID_LOG_INFO, "SetupGlyphs", "ERROR::FREETYPE: Could not init FreeType Library.");
FT_Face face;
if (FT_New_Face(ft, fontPath.c_str(), 0, &face))
__android_log_print(ANDROID_LOG_INFO, "SetupGlyphs", "ERROR::FREETYPE: Failed to load font: %s", fontPath.c_str());
FT_Set_Pixel_Sizes(face, 0, size);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (GLubyte c = 0; c < 128; c++){
if(FT_Load_Char(face, c, FT_LOAD_RENDER)){
__android_log_print(ANDROID_LOG_INFO, "SetupGlyphs", "ERROR::FREETYPE: Failed to load Glyph");
continue;
}
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
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);
Character character = {
texture,
ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
static_cast<GLuint>(face->glyph->advance.x)
};
characters.insert(std::pair<GLchar, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
FT_Done_Face(face);
FT_Done_FreeType(ft);
}
Rendering:
void TextRenderer::RenderTexts()
{
if(shadersInitialized == 0)
CreateShader();
// Activate corresponding render state
glUseProgram(this->shader);
GLuint projectionLocation = glGetUniformLocation(this->shader, "projection");
glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, projectionMatrix);
for (int i=0; i<projects.size(); i++) {
ProjectLabel project = projects.at(i);
glUniform3f(glGetUniformLocation(this->shader, "textColor"), project.textColor.x, project.textColor.y, project.textColor.z);
glActiveTexture(GL_TEXTURE0);
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
/* Set up the VBO for our vertex data */
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Iterate through all characters
std::string::const_iterator c;
GLuint x = project.x;
for (c = project.text.begin(); c != project.text.end(); c++)
{
Character ch = characters[*c];
GLfloat xpos = x + ch.Bearing.x;
GLfloat ypos = project.y - (ch.Size.y - ch.Bearing.y);
GLfloat w = ch.Size.x;
GLfloat h = ch.Size.y;
// Update VBO for each character
GLfloat vertices[6*4] = {
xpos, ypos + h, 0.0, 0.0 ,
xpos, ypos, 0.0, 1.0 ,
xpos + w, ypos, 1.0, 1.0 ,
xpos, ypos + h, 0.0, 0.0 ,
xpos + w, ypos, 1.0, 1.0 ,
xpos + w, ypos + h, 1.0, 0.0
};
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, 6);
x += (ch.Advance / 64); // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
}
glDisableVertexAttribArray(0);
}
glBindTexture(GL_TEXTURE_2D, 0);
}
So, to anyone that may find this post, scowering the web for hours on end, trying to figure out why everything looks funky, I found the answer. Freetype is not aligned (at least not in my project) through GL_RGB, instead is aligned through GL_LUMINANCE. By changing such things in glTexImage2D I solved on the above issues, as well as SIGABRT errors I was also getting.
TLDR;
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB, => GL_LUMINANCE
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RGB, => GL_LUMINANCE
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);

Android OpenGL ES 2.0 - Textures not showing on some devices

Riddle me this,
I recently published a game for Android (play.google.com/store/apps/details?id=com.quackers if you want to witness the problems first hand), and initial feedback suggests that the thing doesn't run properly on some devices. I've since got ahold of one of the offending tablets (a Samsung Galaxy Tab 2 7.0) and it turns out it does run, it just wasn't rendering things properly.
A few digs later and I've discovered that it's a texturing issue. Textures are being loaded okay, but they're not being rendered - not the usual black squares you often get with OpenGL when something goes wrong - nothing at all.
This is OpenGL ES 2.0, doing an SDL/C++/ndk thing. While there are similar problems on the net, much of it involves ES 1.0 and regards a different issue - texture dimensions not being powers of two (e.g. 64x64, 128x128, 256x256 etc.) or some wacky compression stuff which doesn't apply here.
I've stripped out all of my rendering code and have gone back to basics - rendering a textured square (in a not particularly optimised manner).
Pre-loop code:
SDL_Init(SDL_INIT_VIDEO);
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_DisplayMode mode;
SDL_GetDisplayMode(0,0, &mode);
_currentWidth = mode.w;
_currentHeight = mode.h;
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
_screen = SDL_CreateWindow("window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _currentWidth, _currentHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE);
SDL_GLContext context = SDL_GL_CreateContext(_screen);
SDL_GL_MakeCurrent(_screen, context);
glViewport(0, 0, _currentWidth, _currentHeight);
//---
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
const char *vs_source = "attribute highp vec2 coord2d; "
"attribute highp vec2 texcoord;"
"varying highp vec2 f_texcoord;"
"void main(void) { "
"gl_Position = vec4(coord2d, 0.0, 1.0); "
"f_texcoord = texcoord;"
"}";
glShaderSource(vs, 1, &vs_source, NULL);
glCompileShader(vs);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
const char *fs_source = "varying highp vec2 f_texcoord;"
"uniform sampler2D texture;"
"void main(void) { "
"vec2 flipped_texcoord = vec2(f_texcoord.x, 1.0 - f_texcoord.y);"
"gl_FragColor = texture2D(texture, flipped_texcoord);"
"}";
glShaderSource(fs, 1, &fs_source, NULL);
glCompileShader(fs);
_program = glCreateProgram();
glAttachShader(_program, vs);
glAttachShader(_program, fs);
glLinkProgram(_program);
//---
GLuint vs2 = glCreateShader(GL_VERTEX_SHADER);
const char *vs_source2 = "attribute vec2 coord2d; "
"void main(void) { "
"gl_Position = vec4(coord2d, 0.0, 1.0); "
"}";
glShaderSource(vs2, 1, &vs_source2, NULL);
glCompileShader(vs2);
GLuint fs2 = glCreateShader(GL_FRAGMENT_SHADER);
const char *fs_source2 = "uniform lowp vec4 u_colour;"
"void main(void) { "
"gl_FragColor = u_colour;"
"}";
glShaderSource(fs2, 1, &fs_source2, NULL);
glCompileShader(fs2);
_flatProgram = glCreateProgram();
glAttachShader(_flatProgram, vs2);
glAttachShader(_flatProgram, fs2);
glLinkProgram(_flatProgram);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
//---------------------------------------
_screenRect.x = -1.0;
_screenRect.y = -1.0;
_screenRect.w = 2.0;
_screenRect.h = 2.0;
_superDuperFrameBuffer = 0;
_depthRenderBuffer = 0;
glGenTextures(1, &_screenTexture);
glBindTexture(GL_TEXTURE_2D, _screenTexture);
if(_currentWidth < SCREENWIDTH*2 || _currentHeight < SCREENHEIGHT*2) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCREENWIDTH, SCREENHEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glGenRenderbuffers(1, &_depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, SCREENWIDTH, SCREENHEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// create a framebuffer object
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glGenFramebuffers(1, &_superDuperFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _superDuperFrameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _screenTexture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
_defaultFrameBuffer = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFrameBuffer);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
SDL_Surface* testSurface = IMG_Load("graphics/bg_01_0.png");
uint32_t rmask;
uint32_t gmask;
uint32_t bmask;
uint32_t amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
SDL_Surface *tempSurface = SDL_CreateRGBSurface(0, testSurface->w, testSurface->h, 32, rmask, gmask, bmask, amask);
SDL_SetSurfaceBlendMode(tempSurface, SDL_BLENDMODE_BLEND);
SDL_BlitSurface(testSurface, NULL, tempSurface, NULL);
testSurface = tempSurface;
SDL_FreeSurface(tempSurface);
GLint uniformTexture = glGetUniformLocation(_program, "texture");
_testTexture = 0;
glGenTextures(1, &_testTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _testTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniform1i(uniformTexture, /*GL_TEXTURE*/0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, testSurface->pixels);
_vboTest = 0;
_vbo_cube_texcoords = 0;
glGenBuffers(1, &_vboTest);
glGenBuffers(1, &_vbo_cube_texcoords);
loop:
...
_quadColour[0] = 0.0f;
_quadColour[1] = 255.0f;
_quadColour[2] = 0.0f;
_quadColour[3] = 1.0f;
drawSquare(0, 0, 20, 20);
glViewport(0, 0, SCREENWIDTH, SCREENHEIGHT);
GLfloat x1 = 0, x2 = 8, y1 = 0, y2 = 8;
glUseProgram(_program);
GLint attributeCoord2d = glGetAttribLocation(_program, "coord2d");
GLint attributeTexcoord = glGetAttribLocation(_program, "texcoord");
glEnableVertexAttribArray(attributeTexcoord);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _testTexture);
GLfloat cube_texcoords[] = {
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
};
glBindBuffer(GL_ARRAY_BUFFER, _vbo_cube_texcoords);
glVertexAttribPointer(attributeTexcoord, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_texcoords), cube_texcoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(attributeCoord2d);
GLfloat triangle_vertices[] = {
x1, y2,
x1, y1,
x2, y1,
x2, y2,
};
glBindBuffer(GL_ARRAY_BUFFER, _vboTest);
glVertexAttribPointer(attributeCoord2d, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_vertices), triangle_vertices, GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
SDL_GL_SwapWindow(_screen);
...
obviously there's some stuff I've only added for testing purposes, like converting textures to RGBA and whatever. It draws a little green square, then a textured square.
Code might be messy but the point is this - two different results:
Galaxy Tab 2 7.0 (bork)
http://i.imgur.com/ht6LvFV.png
Nexus 7 (correct)
http://i.imgur.com/p4acmIq.png
How do I fix this?
Power-of-two textures are still required on many GLES 2.0 devices. From section 3.8.2 of the GLES 2.0 spec (https://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf):
"Calling a sampler from a fragment shader will return (R; G;B;A) =
(0; 0; 0; 1) if any of the following conditions are true: ... A two-dimensional sampler is called, the corresponding texture image is a non-power-of-two image (as described in the Mipmapping discussion of section 3.7.7), and either the texture wrap mode is not CLAMP_TO_EDGE, or the minification filter is neither NEAREST nor LINEAR."
Assuming SCREENHEIGHT/SCREENWIDTH are the dimensions of your device, you're violating this restriction. You can ignore this restriction if your device supports some NPOT extension, for instance GL_OES_texture_npot (https://www.khronos.org/registry/gles/extensions/OES/OES_texture_npot.txt), although in my experience, some devices that report this extension still sample textures as black when the npot texture is the color target of a framebuffer. The best course is to just always use POT render targets in ES 2.0.
There are a few errors and possible issues in this code:
Your fragment shader should not compile if the GLSL compiler is strict about error checking. Since you do not specify a default precision, and there is no default precision for float/vector/matrix types, you need an explicit precision for all declarations. It is missing for this variable:
vec2 flipped_texcoord = vec2(f_texcoord.x, 1.0 - f_texcoord.y);
If you want to stick with highp, this should be:
highp vec2 flipped_texcoord = vec2(f_texcoord.x, 1.0 - f_texcoord.y);
This call has a bad argument:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _screenTexture, 0);
Since you're attaching a texture, the 3rd argument must be GL_TEXTURE_2D (you would need to use glFramebufferRenderbuffer for attaching a renderbuffer):
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0);
Make sure that the OES_packed_depth_stencil extension is supported on the device, since you're using it here:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, SCREENWIDTH, SCREENHEIGHT);
This code sequence does not make much sense:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
_defaultFrameBuffer = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFrameBuffer);
You just bound framebuffer 0, so the current framebuffer binding will always be 0 here. If you're concerned that the default framebuffer might not be 0, you have to query the value before the first time you change the binding.
This is not a valid call in ES 2.0:
glEnable(GL_TEXTURE_2D);
Enabling textures was only needed in fixed function OpenGL. Once you use shader, it will just use textures anytime the shader... uses textures. No need to explicitly enable anything.

glTranslatef/2D viewport setup issue

When i try glTranslatef(1,-1,0); it pushes my quad's lefthand corner to the center of the screen instead of what im trying to do, moving it 1 pixel to the left and 1 down. Im pretty sure this is because my viewport isnt set correctly but im unsure why. pic, view setup code and drawing code below.
setupView:
-(void)setupView:(GLView*)view
{
printf("setup view");
glClearColor(0,1,1, 1);
// Enable Smooth Shading, default not really needed.
glShadeModel(GL_SMOOTH);
// Depth buffer setup.
glClearDepthf(1.0f);
//enable textures.
glEnable(GL_TEXTURE_2D);
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_FASTEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
CGRect rect = view.bounds;
glOrthof( 0,rect.size.width,-rect.size.height, 0, -1, 1 ) ;
glViewport(0, 0,rect.size.width,rect.size.height);
glMatrixMode(GL_PROJECTION);
// Bind the number of textures we need, in this case one.
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP,GL_TRUE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glLoadIdentity();
NSString *path = [[NSBundle mainBundle] pathForResource:#"cm2" ofType:#"jpg"];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil)
NSLog(#"Do real error checking here");
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
// Flip the Y-axis
CGContextTranslateCTM (context, 0, height);
CGContextScaleCTM (context, 1.0, -1.0);
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(context);
free(imageData);
[image release];
[texData release];
}
drawView:
- (void)drawView:(GLView*)view
{
//draw calls
glColor4f(1,1,1,1);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
static const Vertex3D vertices[] = {
{0, 0, 1}, //TL
{ 1024.0f,0, 1}, //TR
{0, -1024.0f, 1}, //BL
{ 1024.0f, -1024.0f, 1} //BR
};
static const GLfloat texCoords[] = {
0.0, 1.0,
1.0, 1.0,
0.0, 0.0,
1.0, 0.0
};
glTranslatef(1,-1, 1);
glScalef(scale,scale,1);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
You need to first set up your viewport, then set the matrix mode to projection, then call glOrtho, like so:
glViewPort (0, 0, width, height);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, width, 0, height, -1, 1); // Usually this is -width/2,width/2,-height/2,height/2
Also, you probably want to set the matrix mode to ModelView after that to draw your model.

Fastest 2D frame rate possible with android NDK, my try included, better options available?

Fastest 2D frame rate possible with android NDK, my try included, better options available?
I used the NDK and OpenGL ES 2.0 to display a frame as a texture on a GL_TRIANGLE_STRIP.
This was done on a HTC Desire, same hardware as Nexus One.
I tried to load multiple GL_RGBA textures and switch between the textures, because the normal fill rate with a single texture was disappointingly low:
1 texture: 4.78 fps
2 textures: 19.68 fps
3 textures: 20.18 fps
4 textures: 28.52 fps
5 textures: 29.01 fps
6 textures: 30.32 fps
I think even 30.32 fps RGBA is still too slow.
So is this the way to go to achieve the fastest 2D frame rate (with same quality)?
Any suggestions to speed it up?
Here is the relevant code, it is based on the hello-gl2 NDK example:
=== GL2JNIView.java :
init(false, 0, 0);
ConfigChooser(5, 6, 5, 0, depth, stencil);
=== gl_code.cpp :
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <android/log.h>
#include <stdlib.h>
#include <time.h>
typedef unsigned char byte;
static int view_width, view_height;
static byte* framebuffer;
static int framebuffer_size;
static GLuint texture_id[6];
static const char* vertexSrc =
"precision highp float;\n"
"precision highp int;\n"
"attribute vec4 vertexCoords;\n"
"attribute vec2 textureCoords;\n"
"varying vec2 f_textureCoords;\n"
"void main() {\n"
" f_textureCoords = textureCoords;\n"
" gl_Position = vertexCoords;\n"
"}\n";
static const char* fragmentSrc =
"precision highp float;\n"
"precision highp int;\n"
"uniform sampler2D texture;\n"
"varying vec2 f_textureCoords;\n"
"void main() {\n"
" gl_FragColor = texture2D(texture, f_textureCoords);\n"
"}\n";
static GLuint shaderProgram;
static GLint attrib_vertexCoords;
static GLint attrib_textureCoords;
static GLint uniform_texture;
static const GLfloat vertexCoords[] = {-1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0};
static const GLfloat textureCoords[] = {0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0};
JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height) {
view_width = width;
view_height = height;
framebuffer_size = 4*view_width*view_height;
framebuffer = (byte*)calloc(framebuffer_size, sizeof(byte));
for (int i = 0; i < framebuffer_size; i++) framebuffer[i] = 0;
glViewport(0, 0, view_width, view_height);
glGenTextures(6, &texture_id[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_id[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture_id[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, texture_id[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texture_id[3]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, texture_id[4]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, texture_id[5]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
shaderProgram = glCreateProgram();
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSrc, NULL);
glCompileShader(vertexShader);
glAttachShader(shaderProgram, vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSrc, NULL);
glCompileShader(fragmentShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
uniform_texture = glGetUniformLocation(shaderProgram, "texture");
glUniform1i(uniform_texture, 0);
attrib_vertexCoords = glGetAttribLocation(shaderProgram, "vertexCoords");
glEnableVertexAttribArray(attrib_vertexCoords);
glVertexAttribPointer(attrib_vertexCoords, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
attrib_textureCoords = glGetAttribLocation(shaderProgram, "textureCoords");
glEnableVertexAttribArray(attrib_textureCoords);
glVertexAttribPointer(attrib_textureCoords, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
}
JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj) {
static int frame_count = 0;
static clock_t last_time = clock();
static int last_frame_count = 0;
frame_count++;
if (clock()-last_time > 1e7) {
__android_log_print(ANDROID_LOG_INFO, "libgl2jni", "fps: %f", ((float)frame_count-last_frame_count)/(clock()-last_time)*1e6);
last_time = clock();
last_frame_count = frame_count;
}
static byte val = 0;
val++;
if (val == 256) val = 0;
for (int i = 0; i < framebuffer_size; i++) framebuffer[i] = val;
int tst = frame_count%6;
if (tst == 0) {
glActiveTexture(GL_TEXTURE0);
} else if (tst == 1) {
glActiveTexture(GL_TEXTURE1);
} else if (tst == 2) {
glActiveTexture(GL_TEXTURE2);
} else if (tst == 3) {
glActiveTexture(GL_TEXTURE3);
} else if (tst == 4) {
glActiveTexture(GL_TEXTURE4);
} else if (tst == 5) {
glActiveTexture(GL_TEXTURE5);
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
I realize your question is rather old, and you've likely either solved it or moved onto something else, but I'll give a suggestion in case if anyone else comes across this.
First of all, glTexImage2D requires the graphics subsystem to perform a memory free and reallocation of the texture object every time you call it, since the texture parameters can change between calls. An optimized driver might look at the width, height and format, and if they are all the same then the reallocation could be skipped, but it's not likely that the Android driver implementers are actually doing this.
To avoid the texture reallocation completely, you can use glTexSubImage2D to replace the complete bitmap, or just a portion of it. If you combine this with your above texture buffering scheme, you should see a fairly large speed increase. You could even extend this to detect the modified areas of your display and only update the rectangular portions that have changed between frames.
To summarize, change your texture initialization code to call glTexImage2D with a NULL bitmap pointer, so OpenGL only allocates the memory for the texture and doesn't actually copy any data into it like so:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
Then update every frame in your game loop with:
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, view_width, view_height, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
Fastest possible onscreen frame rate is effectively capped by screen refresh rate, which is vendor-specific. My guess would be at least 60 Hz (60 frames per second).
Off-screen rendering is not capped by refresh-rate and depends on the intensity of computing you are performing. Endless loop with some gl code may run significantly faster than 60 Hz, or, for that matter, slower.

Categories

Resources