Я пытаюсь показать простую текстуру в OpenGL ES 2.0 (Android 4.0.4, Galaxy Nexus) в качестве полноэкранного фона с использованием вершин и фрагментарного шейдера. Конечным результатом должно быть отображение изображения с камеры там, но для начала достаточно простой текстуры из файла. Я тестировал много вещей, и на короткое время он работал, поскольку я использовал OpenGL ES 1.x, но поскольку я планирую использовать шейдер для преобразования YUV-> RGB, мне нужно идти с 2.0.
У меня есть следующий вершинный шейдер:
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main() {
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy
}
и этот фрагментарный шейдер:
varying highp vec2 textureCoordinate;
uniform sampler2D videoFrame;
void main() {
gl_FragColor = texture2D(videoFrame, textureCoordinate);
}
Создание gl_FragColor=vec4(1,0,0,0)
как таковое должно быть в порядке, потому что когда я пишу gl_FragColor=vec4(1,0,0,0)
он отлично работает и показывает мне красный фон.
OnSurfaceCreated
Я делаю следующее:
a = makeFloatBuffer(squareVertices);
b = makeFloatBuffer(textureVertices);
с squareVertices
и textureVertices
следующим образом:
static float squareVertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
1.0f, 1.0f, };
static float textureVertices[] = { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, };
OnSurfaceChanged
Я делаю следующее:
GLES20.glViewport(0, 0, width, height);
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.raw.htc);
GLES20.glGenTextures(1, textures, 0);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
R.raw.htc - 128x128 пикселей.
И OnDrawFrame
:
GLES20.glUseProgram(program);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glUniform1i(GLES20.glGetUniformLocation(program, "videoFrame"),0);
GLES20.glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
GLES20.glClearDepthf(1.0f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
int x = GLES20.glGetAttribLocation(program, "position");
int y = GLES20.glGetAttribLocation(program, "inputTextureCoordinate");
GLES20.glEnableVertexAttribArray(x);
GLES20.glVertexAttribPointer(x, 2, GLES20.GL_FLOAT, false, 0, a);
GLES20.glEnableVertexAttribArray(y);
GLES20.glVertexAttribPointer(y, 4, GLES20.GL_FLOAT, false, 0, b);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
Единственное, что я вижу, это полностью черный экран, и я понятия не имею, почему. Я видел некоторые другие сообщения здесь с похожими проблемами, но ни одно из предложенных решений не помогло мне или вообще не было найдено решение.
Как уже было сказано выше, мы могли бы найти решение проблемы, хотя мы не знаем точно, почему она работает сейчас и не была раньше (мы изменили несколько вещей и вдруг это сработало). Тем не менее я хочу поделиться нашей рабочей версией:
Теперь шейдер завершен, чтобы выполнить YUV-> преобразование RGB: вершинный шейдер:
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main() {
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
};
Фрагментный шейдер:
varying highp vec2 textureCoordinate;
uniform sampler2D videoFrame;
uniform sampler2D videoFrame2;
void main(void) {
highp float nx,ny,r,g,b,y,u,v;
highp vec2 uv;
highp vec4 txl,ux,vx;"
nx=(textureCoordinate.x)/1024.0*720.0;
ny=(textureCoordinate.y)/1024.0*480.0;
y=texture2D(videoFrame,vec2(nx,ny)).r;
uv=texture2D(videoFrame2,vec2(nx,ny)).ag;
y=1.1643*(y-0.0625);
u=uv[0]-0.5;
v=uv[1]-0.5;
r=y+1.5958*v;
g=y-0.39173*u-0.81290*v;
b=y+2.017*u;
gl_FragColor=vec4(r,g,b,1);
};
OnSurfaceCreated
все тот же, но определение вершин немного изменилось:
static float squareVertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
1.0f, 1.0f, };
private float textureVertices[] = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
1.0f, 0.0f, };
OnSurfaceChanged
:
buffer = new int[2];
GLES20.glGenTextures(2, buffer, 0);
for (int i = 0; i < 2; i++) {
int texture = buffer[i];
Log.v("Texture", "Texture is at " + texture);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, GLES20.GL_TRUE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
}
buf = new byte[1024 * 1024];
for (int i = 0; i < 1024 * 1024; i++) {
buf[i] = 0;
}
buf2 = new byte[1024 * 1024];
for (int i = 0; i < 1024 * 1024; i++) {
buf2[i] = -128;
}
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, buffer[0]);
GLES20.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_LUMINANCE, 1024,
1024, 0, GL10.GL_LUMINANCE, GL10.GL_UNSIGNED_BYTE,
ByteBuffer.wrap(buf));
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, buffer[1]);
GLES20.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_LUMINANCE_ALPHA,
512, 512, 0, GL10.GL_LUMINANCE_ALPHA, GL10.GL_UNSIGNED_BYTE,
ByteBuffer.wrap(buf2));
OnDrawFrame
:
GLES20.glViewport(0, 0, mWidth, mHeight);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, buffer[0]);
GLES20.glTexSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, Util.CAMWIDTH,
Util.CAMHEIGHT, GL10.GL_LUMINANCE, GL10.GL_UNSIGNED_BYTE,
ByteBuffer.wrap(mBuffer, 0, Util.CAMWIDTH * Util.CAMHEIGHT));
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, buffer[1]);
GLES20.glTexSubImage2D(
GL10.GL_TEXTURE_2D,
0,
0,
0,
Util.CAMWIDTH / 2,
Util.CAMHEIGHT / 2,
GL10.GL_LUMINANCE_ALPHA,
GL10.GL_UNSIGNED_BYTE,
ByteBuffer.wrap(mBuffer, Util.CAMWIDTH * Util.CAMHEIGHT,
Util.CAMWIDTH / 2 * Util.CAMHEIGHT).slice());
GLES20.glClearColor(1.0f, .0f, .0f, .0f);
GLES20.glUseProgram(program);
GLES20.glUniform1i(GLES20.glGetUniformLocation(program, "videoFrame"),
0);
GLES20.glUniform1i(GLES20.glGetUniformLocation(program, "videoFrame2"),
1);
GLES20.glClearDepthf(1.0f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
int x = GLES20.glGetAttribLocation(program, "position");
int y = GLES20.glGetAttribLocation(program, "inputTextureCoordinate");
GLES20.glEnableVertexAttribArray(x);
GLES20.glVertexAttribPointer(x, 2, GLES20.GL_FLOAT, false, 0, a);
GLES20.glEnableVertexAttribArray(y);
GLES20.glVertexAttribPointer(y, 2, GLES20.GL_FLOAT, false, 0, b);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
decodeResource
должен получить BitmapFactory Options
со значением isScaled
false
чтобы он isScaled
2. Для любого, кто проверяет этот фрагмент и думает «Привет, мой код правильный».
a
, b
, x
, y
. buf
выглядит огромным среди других.
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
Эти две строки кода сделали трюк для меня
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
Мне также нужны эти 2, чтобы отобразить PNG файл
Вы объявляете свою координату текстуры как 4 компонента, вместо того, чтобы выглядеть так, как будто она должна быть 2. Код выглядит иначе.
GLES20.glVertexAttribPointer(y, 4, GLES20.GL_FLOAT, false, 0, b);
GLES20.glVertexAttribPointer(y, 2, GLES20.GL_FLOAT, false, 0, b);
? К сожалению, это ничего не меняет.
gl_FragColor = vec4( textureCoordinate.x, textureCoordinate.y, 0.0, 1.0);
), чтобы увидеть, верны ли они.