Gles2.0覆盖在Android上

rjee0c15  于 2023-05-27  发布在  Android
关注(0)|答案(2)|浏览(207)

bounty将在5天内到期。回答此问题可获得+100声望奖励。Myles Hollowed正在寻找一个答案从一个有信誉的来源

我正在尝试为使用GLESv 2的Android应用程序构建一个覆盖层。为了在帧完成之前插入渲染代码,我已经挂接了eglSwapBuffers
我可以做一些简单的事情,比如用剪刀测试画一个正方形:

glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, 200, 200);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);

我也用下面的代码成功地绘制了简单的形状,但是一旦我开始使用顶点属性指针,应用程序就停止正确渲染,并显示一个几乎全黑的屏幕,其中一小部分仍然正确显示。我肯定有一些开放的gl状态,我在这里痛击,但我不知道它是什么。我需要在绘制调用之前/之后保存/恢复哪些内容,以允许应用继续使用我的叠加正确渲染?

// Save application state
GLint prev_program;
glGetIntegerv(GL_CURRENT_PROGRAM, &prev_program);

// Do overlay drawing
glUseProgram(program);
glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, RectangleVertices);
glEnableVertexAttribArray(vPosition);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableVertexAttribArray(vPosition);

// Trying to restore application state here - there are probably more things that I'm missing.
glUseProgram(prevProgram);
7rtdyuoh

7rtdyuoh1#

我需要在绘制调用之前/之后保存/恢复哪些内容,以允许应用继续使用我的叠加正确渲染?
你修改过的所有东西...
请注意,对于某些开发人员用例,即使是完整的状态恢复也可能是不够的。通常,这是应用程序中的一个错误(应用程序对对象ID分配进行假设),但在开发工具(如逐字API跟踪重放工具)中也有这样的假设。

p8h8hvxi

p8h8hvxi2#

根据你对我的评论的回应,我相信你正在努力实现这样的效果:

在所示的示例中,首先绘制3D信息,然后使用基于图块的渲染着色器以正交模式绘制左下方的按钮。基于tile的部分不是必需的,但是如果你感兴趣的话,Sprite Tile Maps on GPU有一个很好的例子来说明如何实现。
抱歉,我使用了一些Javaisms(你看到的大多数是手机)
尝试在可能的情况下切换到c++约定。
渲染循环的一般结构如下所示:

public void onDrawFrame() {
    // Do any updates you need to do before you would start rendering
    // In my case I update the erosion on the planetary surface
    // and do fluid simulations of rainfall

    // Draw background color
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    // Enable face culling so we don't draw a lot of unnecessary triangles
    // Won't draw any triangles whose normal would face away from the camera
    // I do this just in case I turned it off somewhere else
    // I use a lot of offscreen rendering to textures
    glEnable( GL_CULL_FACE );

    // Enable depth buffering
    // Checks pixels for depth in the fragment shader and throws them away
    // if they fail the depth test (IE: something is already drawn in
    // front of them)
    glEnable( GL_DEPTH_TEST );

    // glViewport x,y specifies the lower-left corner (not the center)
    // scaling is not uniform around the center
    // (extends up-right with positive numbers)
    glViewport( 0, 0, viewport_w, viewport_h );

    // Draw all the geometry
    geometry.draw( camera.getVPMatrix(), mModelMatrix );

    // Start changes for portions of the user interface that depend
    // on the geometry viewport
    glViewport( 0, 0, screen_w, screen_h );

    // Disable depth buffering
    // Because you're going to draw in orthographic mode,
    // you don't want to check for depth because it may fail unexpectedly,
    // since you're using a different type of matrix transform
    glDisable( GL_DEPTH_TEST );

    // Draw the portions of the user interface that are
    // only related to the screen dimensions
    // This portion is drawn using orthographic coordinates
    // (flat, no perspective)
    // The orthographic matrix is just an identity matrix
    ui.draw( ui.mMVPMatrix_Identity );

    // Do any updates you need to do after the User Interface gets drawn
}

在每个几何体组中,我有draw()调用来执行该类型几何体的绘制操作,因此我可以收集并保存所有必要的着色器输入、glEnable调用等。一个典型的例子如下所示:

//--------------------------------
// Do anything that needs to be done to this specific
// object before we start rendering
//
// (Your update actions)
//
//-------------------------------- 

// Add program to OpenGL environment
// I keep a reference to each compiled shader with
// the object I'm going to draw so I can just
// call it whenever I draw
glUseProgram( shader.getProgram() );

// Do tests for any conditional attributes or uniforms
// that might differ from object to object
// Ex: sometimes, two similar objects may use a
// a slightly different shader with slightly
// different inputs
//
// Note, I also tend to get a lot of objects as
// references where I instantiate the object a
// single time and then grab a pointer to the
// object based on the class type
// (your mileage may vary on this coding pattern)
// 
// PreRenderArgs are collections of arguments for
// shader attributes and uniforms that are going to
// be set prior to rendering.  They're kept on a
// per-group or per-object basis while the shader
// itself is handled seperately
//
// Below are two examples
if( shader.uniforms.containsKey( "cameraPos" ) ){
    PreRenderArgs.get( "cameraPos" )[ 1 ] = CameraGLES.getRef().eye.toArray();
}

if( shader.uniforms.containsKey( "lightPos" ) ){
    PreRenderArgs.get( "lightPos" )[ 1 ] = Renderer.getRef().ambientLightPos.toArray();
}

// Loop through all the shader attributes and uniforms
// Each attribute or uniform has a certain set of steps
// and inputs that need to be called each time that
// attribute or uniform is activated prior to rendering
// I call these preRenderSteps
// (I include an example of an attribute pre- and post- steps below)

for( String attr : shader.attributes.keySet() ){
    RefMethodwArgs preRenderStep = shader.attributes.get( attr )[ "pre" ];
    if( preRenderStep != null ){
        preRenderStep.invoke( PreRenderArgs.get( attr ) );
    }
}
for( String uni : shader.uniforms.keySet() ){
    RefMethodwArgs preRenderStep = shader.uniforms.get( uni )[ "pre" ];
    if( preRenderStep != null ){
        preRenderStep.invoke( PreRenderArgs.get( uni ) );
    }
}

//--------------------------
// Actually draw your object
// In this case I'm using glDrawElements with GL_TRIANGLES
// and a drawListBuffer so it goes through and calls
// attributes based on indices for vertices in the drawList
//--------------------------

geomObj.drawListBuffer.position( 0 );
glDrawElements( GL_TRIANGLES, geomObj.drawOrder.length, GL_UNSIGNED_INT, geomObj.drawListBuffer );

// Loop through all the shader attributes and uniforms
// Each attribute or uniform has a certain set of steps
// that need to be called after rendering is complete
// to make sure you go back to a neutral state
// I call these postRenderSteps

for( String attr : shader.attributes.keySet() ){
    RefMethodwArgs postRenderStep = shader.attributes.get( attr )[ "post" ];
    if( postRenderStep != null ){
        postRenderStep.invoke();
    }
}
for( String uni : shader.uniforms.keySet() ){
    RefMethodwArgs postRenderStep = shader.uniforms.get( uni )[ "post" ];
    if( postRenderStep != null ){
        postRenderStep.invoke();
    }
}

下面是一个在属性Pre-和Post-步骤中调用的示例,在本例中是AttributeBuffer

void AttributeBufferPreActions( int attrHandle, ByteBuffer attrBuffer, int attrSize ){
    // Pre-rendering actions
    glEnableVertexAttribArray( attrHandle );
    attrBuffer.position(0);

    // Prepare the coordinate data
    // Note: Size is usually coordinates per vertex x,y (2) or x,y,z (3)
    // Note: Stride is almost always Size * 4 bytes per vertex (if its not then change this function)
    int attrStride = 4 * attrSize;
    glVertexAttribPointer(
            attrHandle, attrSize,
            GL_FLOAT, false,
            attrStride, attrBuffer );
}

void AttributeBufferPostActions( int attrHandle ){
    // Post-rendering actions
    // Disable vertex array
    glDisableVertexAttribArray( attrHandle );
}

用户界面的绘制调用几乎相同,除了它循环通过MenuElements的树结构(可能有子元素),然后使用正交投影绘制所有这些元素,而不进行深度测试。

void draw( float[] mvpMatrix ){ // Note: Identity matrix, no perspective transform
    if( uiMenuElements.size() > 0 ){
        for( int i = 0; i < uiMenuElements.size(); i++ ){
            MenuElement curElement = uiMenuElements.get( i );
            curElement.draw( mvpMatrix );
        }
    }
}

作为最后一点,我提供了一些结构选择,因为我发现处理OpenGL绘图的最佳方法之一是将着色器上每个属性或统一的所有必要的PreRender和PostRender步骤分开,为每个对象或对象组记录它们(许多着色器从不更改其大部分输入),在正在绘制的对象之间传递着色器,然后根据需要为每个着色器指定和执行所有PreRender和PostRender更改。这有助于确保您在每次绘制会话后返回到中性状态。

相关问题