FBO纹理副本不适用于Android - 渲染纹理填充了纹理坐标0,0处的任何内容

时间:2013-12-04 07:52:02

标签: android opengl-es unity3d opengl-es-2.0 fbo

问题在于FBO副本的结果填充了源纹理的纹理坐标0,0处的任何像素。

  1. 如果我编辑着色器以根据纹理坐标位置渲染渐变,则片段着色器会填充整个结果,就好像它有纹理坐标0,0一样。

  2. 如果我编辑三角形条带顶点,事情就像预期的那样,所以我认为相机和几何体设置正确。当它应该反映我的输入纹理或者至少我的位置渐变着色器时,2-tri四边形都是相同的颜色!

  3. 我已经将这段代码移植到了一个有效的iOS示例中。

  4. 这与Unity3D一起运行,因此不要假设任何GL设置是默认设置,因为引擎可能在我的代码启动之前摆弄它们。

  5. 这是FBO复制操作

        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer);
        checkGlError("glBindFramebuffer");
        GLES20.glViewport(0, 0, TEXTURE_WIDTH*4, TEXTURE_HEIGHT*4);
        checkGlError("glViewport");
        GLES20.glDisable(GLES20.GL_BLEND);
        GLES20.glDisable(GLES20.GL_DEPTH_TEST);
        GLES20.glDepthMask(false);
        GLES20.glDisable(GLES20.GL_CULL_FACE);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
        GLES20.glPolygonOffset(0.0f, 0.0f);
        GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
        checkGlError("fbo setup");
    
        // Load the shaders if we have not done so
        if (mProgram <= 0) {
            createProgram();
            Log.i(TAG, "InitializeTexture created program with ID: " + mProgram);
            if (mProgram <= 0)
                Log.e(TAG, "Failed to initialize shaders!");
        }
    
        // Set up the program
        GLES20.glUseProgram(mProgram);
        checkGlError("glUseProgram");
        GLES20.glUniform1i(mUniforms[UNIFORM_TEXTURE], 0);
        checkGlError("glUniform1i");
    
        // clear the scene
        GLES20.glClearColor(0.0f,0.0f, 0.1f, 1.0f);
        checkGlError("glClearColor");
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    
        // Bind out source texture
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        checkGlError("glActiveTexture");
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mSourceTexture);
        checkGlError("glBindTexture");
    
        GLES20.glFrontFace( GLES20.GL_CW );
    
        // Our object to render
        ByteBuffer imageVerticesBB = ByteBuffer.allocateDirect(8 * 4);
        imageVerticesBB.order(ByteOrder.nativeOrder());
        FloatBuffer imageVertices = imageVerticesBB.asFloatBuffer();
    
        imageVertices.put(new float[]{
                  -1.0f, -1.0f,
                1.0f,  -1.0f,
                -1.0f,  1.0f,
                1.0f,   1.0f}
        );
        imageVertices.position(0);
    
        // The object's texture coordinates
        ByteBuffer textureCoordinatesBB = ByteBuffer.allocateDirect(8 * 4);
        imageVerticesBB.order(ByteOrder.nativeOrder());
        FloatBuffer textureCoordinates = textureCoordinatesBB.asFloatBuffer();
    
        textureCoordinates.put(new float[]{
                  0.0f, 1.0f,
                1.0f, 1.0f,
                0.0f, 0.0f,
                1.0f, 0.0f}
        );
        textureCoordinates.position(0); 
    
        // Update attribute values.
        GLES20.glEnableVertexAttribArray(ATTRIB_VERTEX);
        GLES20.glVertexAttribPointer(ATTRIB_VERTEX, 2, GLES20.GL_FLOAT, false, 0, imageVertices);
        GLES20.glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);
        GLES20.glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GLES20.GL_FLOAT, false, 0, textureCoordinates);
        // Draw the quad
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    

    如果你想深入了解,我在这里提出了更新循环,设置和着色器的好主意:https://gist.github.com/acgourley/7783624

    我正在检查这个结果作为UnityFBO(MIT许可证)的Android端口,因此所有帮助都受到赞赏,并将更广泛地分享。

1 个答案:

答案 0 :(得分:1)

顶点着色器 输出 和片段着色器 输入 的声明不会因纹理坐标变化而变化(不同的精度限定符)。通常情况下这不是一个问题,但由于我将在下面使用highp在你的片段着色器中讨论的原因,可能会回来咬你的屁股。


顶点着色器:

attribute         vec4 position;
attribute mediump vec4 textureCoordinate;

varying   mediump vec2 coordinate;

void main()
{
  gl_Position = position;
  coordinate  = textureCoordinate.xy;
}

片段着色器:

varying highp vec2      coordinate;

uniform       sampler2D texture;

void main()
{
  gl_FragColor = texture2D(texture, coordinate);
}

<小时/> 在OpenGL ES 2.0中,highp是片段着色器中的可选功能。除非预处理器定义highp,否则不应在片段着色器中声明任何GL_FRAGMENT_PRECISION_HIGH

GLSL ES 1.0 Specification - 4.5.4:可用精度限定符 - 第36页

  

内置宏 GL_FRAGMENT_PRECISION_HIGH 定义为支持片段语言 highp 精度的系统

     
     #define GL_FRAGMENT_PRECISION_HIGH 1
         

并且未在不支持片段语言中的highp精度的系统上定义。定义时,此宏在顶点和片段语言中都可用。 highp 限定符是片段语言中的可选功能,未通过 #extension 启用。

  

最重要的是,您需要在声明某些内容highp之前检查片段着色器是否支持highp精度,或者在片段着色器中重新编写声明以使用mediump。我无法看到在片段着色器中任意增加顶点着色器坐标精度的太多理由,老实说,我希望在 中将其写为highp顶点着色器和片段着色器或保留mediump