OpenGL - ES绘图和混合

时间:2017-02-17 09:12:08

标签: opengl-es

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

example

现在,我使用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 ///////////////////////// 

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

enter image description here

1 个答案:

答案 0 :(得分:0)

第一个问题:

您通过说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之间变化。