【问题标题】:OpenGL - ES drawing and blendingOpenGL - ES 绘图和混合
【发布时间】:2017-02-17 18:47:40
【问题描述】:

我正在开发下面描述的程序。 我画了两个不同深度的三角形。 对于下面的示例,我想将绿色三角形拆分为可见部分和隐藏部分。然后,最后使用混合功能,将绿色三角形的隐藏部分着色为透明,可见部分着色为原始颜色。

现在,我使用 opengl-ES(使用 JNI)编写代码。 还有,我有两个问题。

第一:

glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glUseProgram(gProgram);
glGetUniformLocation(gProgram, "vColor");


const GLfloat gTriangleVertices1[] =
{
    -0.5f, -0.5f, -0.5f,
    0.0f, 0.5f, -0.5f,
    0.5f, -0.5f, -0.5f,
};
float color1[] = {1.0f, 0.0f, 0.0f};
const GLfloat gTriangleVertices2[] =
{
    -0.7f, 0.0f, 0.3f,
    0.5f, 0.3f, 0.3f,
    0.5f, 0.0f, 0.3f,
};
float color2[] = {0.0f, 1.0f, 0.0f};



int mColorHandle1;
int mColorHandle2;

glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glClearDepthf(1.0f);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glUniform4f(mColorHandle1, color1[0], color1[1], color1[2], color1[3]);
glVertexAttribPointer(gvPositionHandle, 3, GL_FLOAT, GL_FALSE, 0, gTriangleVertices1);
glEnableVertexAttribArray(gvPositionHandle);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDepthFunc(GL_GREATER);
//glDepthFunc(GL_LESS);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glUniform4f(mColorHandle2, color2[0], color2[1], color2[2], color2[3]);
glDrawArrays(GL_TRIANGLES, 3, 3);
glDisableVertexAttribArray(gvPositionHandle);

从这段代码中,如果我将 glDepthFunc(GL_GREATER) 更改为 glDepthFunc(GL_LESS),结果会正确显示可见和隐藏部分。 但是,我不明白为什么它显示正确答案。 因为,我添加了顶点gTriangleVertices1,但我没有添加gTriangleVertices2。 即使我不添加三角形 2 的顶点,它也给了我正确的答案。为什么?

第二个问题,我认为使用混合功能是正确的(我检查过它适用于 glut / freeglut)。但是为什么它在 gl-es 上不起作用。

///////////////////////// visible part ///////////////////////// 
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glClearDepthf(1.0f);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glUniform4f(mColorHandle1, color1[0], color1[1], color1[2], color1[3]);
glVertexAttribPointer(gvPositionHandle, 3, GL_FLOAT, GL_FALSE, 0, gTriangleVertices1);
glEnableVertexAttribArray(gvPositionHandle);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDepthFunc(GL_LESS);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glUniform4f(mColorHandle2, color2[0], color2[1], color2[2], color2[3]);
glDrawArrays(GL_TRIANGLES, 3, 3);
glDisableVertexAttribArray(gvPositionHandle);
glDisable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS); // same to initialize depth func
///////////////////////// visible part ///////////////////////// 


///////////////////////// hidden part ///////////////////////// 
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glClearDepthf(1.0f);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glUniform4f(mColorHandle1, color1[0], color1[1], color1[2], color1[3]);
glVertexAttribPointer(gvPositionHandle, 3, GL_FLOAT, GL_FALSE, 0, gTriangleVertices1);
glEnableVertexAttribArray(gvPositionHandle);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDepthFunc(GL_GREATER);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glUniform4f(mColorHandle2, color2[0], color2[1], color2[2], 0.5f);
glDrawArrays(GL_TRIANGLES, 3, 3);
glDisableVertexAttribArray(gvPositionHandle);
///////////////////////// hidden part ///////////////////////// 

我刚刚添加了混合功能。如果我单独使用可见/隐藏部分,它会给出正确的结果。但是,如果我使用混合功能,它会给出如下所示的奇怪结果:它给出透明的隐藏绿色三角形。 怎么了?

【问题讨论】:

    标签: opengl-es


    【解决方案1】:

    第一个问题:

    您通过说glDrawArrays(GL_TRIANGLES, 3, 3); 创建了一个主要错误,因为这会在您的缓冲区上产生溢出。结果出乎意料,但在您的情况下,您的编译器似乎已经确定您定义的两个数组是紧密打包的:

    const GLfloat gTriangleVertices1[] =
    {
        -0.5f, -0.5f, -0.5f,
        0.0f, 0.5f, -0.5f,
        0.5f, -0.5f, -0.5f,
    };
    const GLfloat gTriangleVertices2[] =
    {
        -0.7f, 0.0f, 0.3f,
        0.5f, 0.3f, 0.3f,
        0.5f, 0.0f, 0.3f,
    };
    

    并且被认为是

    const GLfloat gTriangleVertices[] =
    {
        -0.5f, -0.5f, -0.5f,
        0.0f, 0.5f, -0.5f,
        0.5f, -0.5f, -0.5f,
        -0.7f, 0.0f, 0.3f,
        0.5f, 0.3f, 0.3f,
        0.5f, 0.0f, 0.3f,
    };
    

    所以溢出实际上是跳转到内存中第二个顶点数据所在的部分。不要误以为你所做的事情是错误的。这是不正确的,这可能会在不同的版本或任何其他原因、平台、设备上中断......所以修复它。

    第二个问题:

    混合和深度缓冲区不能一起使用。您需要避免这种组合。我不会在这里解释原因(搜索一下),但结果是未定义的,你可能不会使用它。使用其中一种。

    如果您在网上搜索如何解决这个问题,您将找不到适合您情况的正确答案,因为它非常独特。对于您的情况,我建议的一般解决方案是添加模板缓冲区。

    第一次调用也应该绘制到模板缓冲区,然后在最后一次调用中也可以使用该缓冲区进行绘制。所以最后一次调用应该禁用深度测试但启用模板。但是这样做你很可能应该简单地删除深度并只使用模板。

    我确信通过使用 Alpha 通道也有其他可能的解决方案,但无论如何请记住,深度缓冲区与混合相结合是被严格禁止的,并且行为是未定义的。这意味着它甚至可以在 GPU 之间变化。

    【讨论】:

    • 为什么在不同的 GPU 上使用混合和深度测试会产生不同的结果?如果你在它前面画一个半透明的东西和另一个半透明的物体,那么没有问题,如果你在它后面画它,那么深度测试就开始了。
    • @Bálint 我也这么认为,但后来我看到一些结果似乎完全破坏了深度缓冲区。检查这个问题的结果:stackoverflow.com/questions/35893742/…
    猜你喜欢
    • 2013-11-16
    • 2018-10-13
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多