Я хочу применить шейдер к выходу внешнего и закрытого SDK (FLIR Android SDK). Я нахожусь в том же контексте OpenGL, что и рендер SDK, моя идея состоит в том, чтобы загрузить вывод их кадрового буфера в мою текстуру и применить к ней шейдер.
Мой первый вопрос: действительно ли это самый быстрый способ достижения моей цели?
И, во-вторых, почему при вызове GLES31.glCopyTexSubImage2D(GLES31.GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height)
?
происходит недопустимая операция К сожалению, я абсолютный новичок в OpenGL, и большинство из следующих копий и вставок из разных учебных пособий.
Метод onDraw()
следующего класса рендеринга вызывается после рендерера FLIR SDK onDraw()
и до swap()
из GLSurfaceView.
Мой класс рендеринга:
public class BasicRenderer implements GLSurfaceView.Renderer {
//flir texture size
private static int width = 1080;
private static int height = 1440;
//gl handles
private int positionHandle;
private int vPMatrixHandle;
private int mTexCoordHandle;
private int mSamplerHandle;
//vertices
private FloatBuffer vertexBuffer;
private ShortBuffer drawListBuffer;
private static int COORDS_PER_VERTEX = 3;
private int vertexCount;
private static int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
//texture
private FloatBuffer uvBuffer;
private int[] textureName;
//shader program
private int mProgram;
//shaders
private static String vertShader = "uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 a_texCoord;" +
"varying vec2 v_texCoord;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
" v_texCoord = a_texCoord;" +
"}";
private static String fragShader = "precision mediump float;" +
"varying vec2 v_texCoord;" +
"uniform sampler2D s_texture;" +
"void main() {" +
"vec4 pixel = texture2D( s_texture, v_texCoord );" +
"gl_FragColor = pixel;" +
"}";
// vPMatrix -> "Model View Projection Matrix"
private final float[] vPMatrix = new float[16];
private final float[] projectionMatrix = new float[16];
private final float[] viewMatrix = new float[16];
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
initVertices();
initTextureCoords();
initTexture();
setUpShader();
}
@Override
public void onSurfaceChanged(GL10 gl, int externWidth, int externHeight) {
//projection matrix
Matrix.orthoM(projectionMatrix, 0, 0, width, 0f, height, 0f, 7);
//camera view
Matrix.setLookAtM(viewMatrix, 0, 0, 0, 1f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//combine projection and camera view
Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl) {
int err;
GLES31.glViewport(0, 0, width, height);
//use this shader
GLES31.glUseProgram(mProgram);
//apply projection and camera view
vPMatrixHandle = GLES31.glGetUniformLocation(mProgram, "uMVPMatrix");
GLES31.glUniformMatrix4fv(vPMatrixHandle, 1, false, vPMatrix, 0);
//vertices to position
positionHandle = GLES31.glGetAttribLocation(mProgram, "vPosition");
GLES31.glEnableVertexAttribArray(positionHandle);
GLES31.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES31.GL_FLOAT, false, 0, vertexBuffer); //TODO: stride necessary?
// apply texture coords
mTexCoordHandle = GLES31.glGetAttribLocation(mProgram, "a_texCoord");
GLES31.glEnableVertexAttribArray(mTexCoordHandle);
GLES31.glVertexAttribPointer(mTexCoordHandle, 2, GLES31.GL_FLOAT, false, 0, uvBuffer);
if ((err = GLES31.glGetError()) != GLES31.GL_NO_ERROR) {
Log.e("GL ERROR", "1->" + GLU.gluErrorString(err));
}
//GLES31.glEnable(GLES31.GL_TEXTURE_2D);
GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, textureName[0]);
GLES31.glCopyTexSubImage2D(GLES31.GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height);
if ((err = GLES31.glGetError()) != GLES31.GL_NO_ERROR) {
Log.e("GL ERROR", "2->" + GLU.gluErrorString(err));
}
// tell gl to use this active texture as sampler
mSamplerHandle = GLES31.glGetUniformLocation(mProgram, "s_texture");
GLES31.glUniform1i(mSamplerHandle, 0);
if ((err = GLES31.glGetError()) != GLES31.GL_NO_ERROR) {
Log.e("GL ERROR", "3->" + GLU.gluErrorString(err));
}
//draw triangles
//6 => drawOrder.length
GLES31.glDrawElements(GLES31.GL_TRIANGLES, 6, GLES31.GL_SHORT, drawListBuffer);
if ((err = GLES31.glGetError()) != GLES31.GL_NO_ERROR) {
Log.e("GL ERROR", "4->" + GLU.gluErrorString(err));
}
//disable attrip arrays
GLES31.glDisableVertexAttribArray(positionHandle);
GLES31.glDisableVertexAttribArray(mTexCoordHandle);
}
private void setUpShader() {
int vertexShader = loadShader(GLES31.GL_VERTEX_SHADER, vertShader);
int fragmentShader = loadShader(GLES31.GL_FRAGMENT_SHADER, fragShader);
mProgram = GLES31.glCreateProgram(); // create empty OpenGL ES Program
GLES31.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES31.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES31.glLinkProgram(mProgram); // creates OpenGL ES program executables
String vS = GLES31.glGetShaderInfoLog(vertexShader);
String fS = GLES31.glGetShaderInfoLog(fragmentShader);
if (!vS.isEmpty() || !fS.isEmpty()) {
Log.e("setUpShader", "shader program failed");
}
}
static int loadShader(int type, String shaderCode) {
int shader = GLES31.glCreateShader(type);
GLES31.glShaderSource(shader, shaderCode);
GLES31.glCompileShader(shader);
return shader;
}
private void initVertices() {
//see width (1080) and height (1440) of flir texture
float squareCoords[] = {
0f, 0f, 0.0f, // top left
0f, 1440f, 0.0f, // bottom left
1080f, 1440f, 0.0f, // bottom right
1080f, 0f, 0.0f}; // top right
short drawOrder[] = {0, 1, 2, 0, 2, 3}; // order to draw vertices
vertexCount = squareCoords.length / COORDS_PER_VERTEX;
// (# of coordinate values * 4 bytes per float)
ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
// (# of coordinate values * 2 bytes per short)
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
}
private void initTextureCoords() {
// (# of coordinate values * 4 bytes per float)
float[] uvs = new float[]{
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f
};
ByteBuffer bb3 = ByteBuffer.allocateDirect(uvs.length * 4);
bb3.order(ByteOrder.nativeOrder());
uvBuffer = bb3.asFloatBuffer();
uvBuffer.put(uvs);
uvBuffer.position(0);
}
private void initTexture() {
textureName = new int[1];
GLES31.glGenTextures(1, textureName, 0);
GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, textureName[0]);
// params if texture needs to scale up/down
GLES31.glTexParameterf(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_MIN_FILTER, GLES31.GL_NEAREST);
GLES31.glTexParameterf(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_MAG_FILTER, GLES31.GL_NEAREST);
//GLES31.glTexParameterf(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_WRAP_S, GLES31.GL_CLAMP_TO_EDGE);
GLES31.glTexImage2D(GLES31.GL_TEXTURE_2D, 0, GLES31.GL_RGBA, width, height, 0, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, null);
}
}