2014-12-15 6 views
1

Загадка мне это,Android OpenGL ES 2.0 - текстуры не отображаются на некоторых устройствах

Я недавно опубликовал игру для Android (play.google.com/store/apps/details?id=com.quackers, если вы хотите чтобы убедиться в проблемах из первых рук), а первоначальная обратная связь предполагает, что эта вещь не работает должным образом на некоторых устройствах. С тех пор у меня есть одна из оскорбительных таблеток (Samsung Galaxy Tab 2 7.0), и получается, что она делает run, она просто не отображала вещи должным образом.

Несколько раскопок позже, и я обнаружил, что это проблема текстурирования. Текстуры загружаются нормально, но они не обрабатываются - не обычные черные квадраты, которые вы часто получаете с OpenGL, когда что-то идет не так - ничего.

Это OpenGL ES 2.0, выполняющий SDL/C++/ndk. Хотя в сети есть аналогичные проблемы, большая часть из них связана с ES 1.0 и рассматривает другую проблему - размеры текстур не являются степенями двух (например, 64x64, 128x128, 256x256 и т. Д.) Или некоторыми дурацкими материалами сжатия, которые здесь не применяются.

Я удалил весь свой код рендеринга и вернулся к основам - рендеринг текстурированного квадрата (не особенно оптимизированным образом).

код Pre-петля:

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); 

петля:

... 

_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); 

... 

, очевидно, есть некоторые вещи, я только добавил для целей тестирования, как преобразование текстуры RGBA и любой другой. Он рисует маленький зеленый квадрат, а затем текстурированный квадрат.

код может быть грязным, но дело это - два разных результата:

Galaxy Tab 2 7.0 (Bork) http://i.imgur.com/ht6LvFV.png

Nexus 7 (правильный) http://i.imgur.com/p4acmIq.png

Как исправить это?

+0

Испытывали ли вы свои попытки на других устройствах и получали аналогичные результаты из-за архитектур графического процессора? (Не знаю, связано ли это с немедленным отсроченным рендерингом) –

+0

Я не достаточно богат, чтобы позволить себе использовать устройства bazillion: P Но он работает на все остальное. Я считаю, что могут быть подобные ошибки на старых Kindle HDXes - Amazon просто сообщает «черный экран». Мне также сказали, что это не удается на 2012 Nexus 7 (но не в 2013 году, который у меня есть). На нескольких устройствах HTC были достигнуты успехи, так что это очень популярно. –

+0

Сила 2 текстур по-прежнему требуется на Opengl ES 2. На некоторых устройствах может работать неэнергия из двух текстур. –

ответ

0

Есть несколько ошибок и возможные проблемы в этом коде:

  • Ваш пиксельный шейдер не компилируется, если GLSL компилятора строги проверки ошибок. Поскольку вы не указываете точность по умолчанию, и нет точности по умолчанию для типов float/vector/matrix, вам нужна явная точность для всех объявлений. Он отсутствует для этой переменной:

    vec2 flipped_texcoord = vec2(f_texcoord.x, 1.0 - f_texcoord.y); 
    

    Если вы хотите придерживаться highp, это должно быть:

    highp vec2 flipped_texcoord = vec2(f_texcoord.x, 1.0 - f_texcoord.y); 
    
  • Этот вызов имеет плохой аргумент:

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _screenTexture, 0); 
    

    С вами 'добавление текстуры, 3-й аргумент должен быть GL_TEXTURE_2D (вам нужно будет использовать glFramebufferRenderbuffer для прикрепления рендеринга буфера):

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); 
    
  • Убедитесь, что расширение OES_packed_depth_stencil поддерживается на устройстве, так как вы используете его здесь:

    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, SCREENWIDTH, SCREENHEIGHT); 
    
  • Эта кодовая последовательность не имеет особого смысла:

    glBindFramebuffer(GL_FRAMEBUFFER, 0); 
    
    _defaultFrameBuffer = 0; 
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFrameBuffer); 
    

    Вы просто связали фреймбуфер 0, поэтому текущая привязка фреймбуфера всегда будет 0 здесь. Если вы обеспокоены тем, что фреймбуфер по умолчанию не может быть 0, вам необходимо запросить значение до того, как вы впервые измените привязку.

  • Это не действительный вызов в ES 2.0:

    glEnable(GL_TEXTURE_2D); 
    

    Включение текстур необходима только в фиксированной функции OpenGL. Когда вы используете шейдер, он просто будет использовать текстуры в любое время, когда шейдер ... использует текстуры. Не нужно явно включать что-либо.

+0

Некоторые из них - глупые оплошности или являются результатом того, что я ткнул вещи, чтобы увидеть, что произойдет.Однако это изменение в шейдере фрагмента, похоже, что-то зафиксировало, так что это хорошая новость. –

+0

Да, похоже, проблема заключалась в отсутствии «highp». Я хочу, чтобы в день, когда вы использовали обычный OpenGL, и устройства перестали быть такими разборчивыми. Благодаря кучу, я могу получить исправление к концу недели. –

1

Сила двух текстур по-прежнему требуется на многих устройствах GLES 2.0. Из раздела 3.8.2 в спецификации GLES 2.0 (https://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf):

«Вызов пробник из фрагмента шейдер будет возвращать (R; G, B, A) = (0; 0; 0; 1), если любой из следующих условий: ... Вызывается двумерный сэмплер, соответствующее изображение текстуры - это изображение без энергии двух (как описано в обсуждении Mipmapping раздела 3.7.7), и либо текстура режим обертывания не CLAMP_TO_EDGE, или фильтр минимизации не является ни БЛИЖАЙШИМ, ни ЛИНЕЙНЫМ ».

Предполагая, что SCREENHEIGHT/SCREENWIDTH - это размеры вашего устройства, вы нарушаете это ограничение. Вы можете игнорировать это ограничение, если ваше устройство поддерживает некоторое расширение NPOT, например GL_OES_texture_npot (https://www.khronos.org/registry/gles/extensions/OES/OES_texture_npot.txt), хотя, по моему опыту, некоторые устройства, которые сообщают об этом расширении, по-прежнему демонстрируют текстуры как черные, когда текстура npot является целевой точкой цвета фреймбуфера. Лучший курс - всегда использовать цели рендеринга POT в ES 2.0.

+0

В опубликованном коде режим обёртывания ** является ** 'CLAMP_TO_EDGE', а фильтр фильтрации ** - **' LINEAR'. Таким образом, ни одно из ограничений не нарушается. –

+0

Я столкнулся с этой проблемой на Galaxy Tab 2 P5110 (Android версии 4.2.2). Я неправильно отредактировал PNG, поэтому он имел ширину 226 вместо 256, используемых в качестве текстуры. Телефон Galaxy II и Nexus 4 использовали битмап без проблем, а Tab 2 P5110 ничего не делал. Вызов glGetError возвратил ноль. Я проверил растровое изображение, как вытолкнутое decodeResource, и не сообщило об альфа-версии, премультиплексном ложном и ARGB_8888; –

Смежные вопросы