如何渲染到GL_TEXTURE_EXTERNAL_OES?

时间:2014-09-02 08:26:33

标签: opengl-es render-to-texture

我需要一种渲染为 GL_TEXTURE_EXTERNAL_OES 纹理的方法。我尝试将纹理绑定到帧缓冲区但是我得到 GL_INVALID_ENUM 错误。以下是一些示例代码:

glEnable(GL_TEXTURE_EXTERNAL_OES);
glGenFramebuffersOES(1, &frameBuffer);
glBindFramebufferOES(GL_FRAMEBUFFER, frameBuffer); 
glFramebufferTexture2DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES, outTexHandle, 0); // I get GL_INVALID_ENUM here
// set viewport, uniforms and draw 
glBindFramebufferOES(GL_FRAMEBUFFER, 0);
glDisable(GL_TEXTURE_EXTERNAL_OES);

我的最终目标是通过在SurfaceTexture上应用一些过滤器来修改相机框架。因此,我的着色器程序既具有输入又输出相同的 GL_TEXTURE_EXTERNAL_OES 纹理。这可能吗?如果没有,有没有解决方法?对于我的应用程序,输出纹理必须 GL_TEXTURE_EXTERNAL_OES ,我不能使用GL_TEXTURE_2D纹理。

1 个答案:

答案 0 :(得分:0)

您无法渲染到GL_TEXTURE_EXTERNAL_OES纹理。 GL_TEXTURE_EXTERNAL_OES是由其他设备(如设备摄像头)渲染的外部纹理。您具有此纹理的读取权限。如果您需要更改纹理的渲染方式,那么您需要编写一个着色器程序来执行此操作。

在访问OES纹理数据之前,必须执行许多步骤。必须按以下方式初始化外部OES纹理:

int[] mTextureHandles = new int[1];
GLES20.glGenTextures(1, mTextureHandles, 0);
mTextureHandle = mTextureHandles[0];

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureHandles[0]);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

然后将OES纹理包装在SurfaceTexture对象中,并将其设置为每帧更新一次。您的类必须实现SurfaceTexture.OnFrameAvailableListener接口:

camTexture = new SurfaceTexture(mTextureHandle);
camTexture.setOnFrameAvailableListener(this);

初始化相机时,必须将其指向使用GL_TEXTURE_EXTERNAL_OES,如此:

mCamera = Camera.open();
try{
    mCamera.setPreviewTexture(camTexture);
}catch(IOException ioe){
    ioe.printStackTrace();
}

现在在您的public void onFrameAvailable(SurfaceTexture surfaceTexture)回调中,您会像以下那样呈现给GL_TEXTURE个对象之一:

GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
camTexture.updateTexImage();
renderFrame();

renderFrame()方法中,您需要执行以下操作:

1 - 设置视口

2 - 绑定到外部纹理:glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId);

3 - 设置着色器程序的所有变量,包括变换矩阵

4 - 最后通过调用glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

渲染纹理

如果您的目标是更改纹理的渲染方式,则必须实现GLES着色器程序才能执行此操作。以下是简单纹理顶点着色器的示例:

uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
attribute vec4 aTextureCoord;
varying vec2 vTextureCoord;
void main() {
    gl_Position = uMVPMatrix * aPosition;
    vTextureCoord = vec2(1.0 - aTextureCoord.s, aTextureCoord.t);
}

这是关联的片段着色器:

#extension GL_OES_EGL_image_external : require
precision mediump float;
uniform samplerExternalOES sTexture;
varying vec2 vTextureCoord;
void main(){
    gl_FragColor = texture2D(sTexture, vTextureCoord);
}

请注意,片段着色器在着色器文件的顶部有#extension GL_OES_EGL_image_external : require。这非常重要,需要允许着色器从GL_TEXTURE_EXTERNAL_OES纹理中读取。您现在可以更改着色器程序以任何方式渲染外部纹理数据。