[英]How to handle OpenGL additive blending and depth test with particles and deeper objects
我有一个使用OpenGL和glut制作的小精灵粒子系统,使用纹理绘制基本火焰。 火焰是对称复制的,以说明它在小盒子/场景中的行为。 如下图所示,存在两个问题:
1-为了产生看起来不错的火焰效果,我想对我的粒子使用添加剂混合,但是混合还考虑到了较深青色面板的颜色并产生了白色火焰。
2.1-同样,为了正确实现添加剂混合,我必须在绘制粒子时禁用深度测试,但是这样做可以启用粒子的绘制,即使应该“隐藏”它们也是如此。
2.2-如果在绘制粒子时启用深度测试,则外观如下所示。
如果有帮助,这里是我应用于粒子的纹理。
这是显示场景和粒子的相关代码。
void drawParticles()
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glBindTexture(GL_TEXTURE_2D,explosionTexture[0]);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
for (int i = 0; i < particlesNumber; ++i)
{
glPointSize(50.0f);
glBegin(GL_POINTS);
glColor4f(particlesArray[i].color[0],particlesArray[i].color[1],particlesArray[i].color[2],0.5f);
glVertex3f(particlesArray[i].position[0],particlesArray[i].position[1],particlesArray[i].position[2]);
glEnd();
}
glBindTexture(GL_TEXTURE_2D, 0);
glDisable( GL_BLEND );
glEnable( GL_DEPTH_TEST );
glPopAttrib();
}
void drawScene()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60.0f, (GLdouble) g_width / (GLdouble) g_height, 0.1f, 300.0f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt( dist*sin(phi)*sin(theta), dist*cos(phi), dist*sin(phi)*cos(theta), 0, 0, 0, 0, 1, 0 );
glEnable( GL_DEPTH_TEST );
glDisable( GL_BLEND );
glBegin( GL_LINES );
glColor3f( 1.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.5f, 0.0f, 0.0f );
glColor3f( 0.0f, 1.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.5f, 0.0f );
glColor3f( 0.0f, 0.0f, 1.0f );
glVertex3f( 0.0f, 0.0f, 0.0f );
glVertex3f( 0.0f, 0.0f, 0.5f );
glEnd();
glBegin( GL_QUADS );
glColor4f( 1.0f, 1.0f, 1.0f , 0.0f);
glVertex3f( -1.0f, -0.2f, 1.0f );
glVertex3f( 1.0f, -0.2f, 1.0f );
glVertex3f( 1.0f, -0.2f, -1.0f );
glVertex3f( -1.0f, -0.2f, -1.0f );
glColor4f( 1.0f, 1.0f, 0.0f , 0.0f );
glVertex3f( 1.0f, -2.0f, 1.0f );
glVertex3f( 1.0f, -2.0f, -1.0f );
glVertex3f( 1.0f, -0.2f, -1.0f );
glVertex3f( 1.0f, -0.2f, 1.0f );
glColor4f( 1.0f, 0.0f, 1.0f , 0.0f );
glVertex3f( -1.0f, -2.0f, 1.0f );
glVertex3f( -1.0f, -2.0f, -1.0f );
glVertex3f( -1.0f, -0.2f, -1.0f );
glVertex3f( -1.0f, -0.2f, 1.0f );
glColor4f( 0.0f, 1.0f, 1.0f , 1.0f );
glVertex3f( 1.0f, -2.0f, -1.0f );
glVertex3f( -1.0f, -2.0f, -1.0f );
glVertex3f( -1.0f, -0.2f, -1.0f );
glVertex3f( 1.0f, -0.2f, -1.0f );
glEnd();
glPushMatrix();
drawParticles();
glScalef(1.0f, -1.0f, 1.0f);
drawParticles();
glPopMatrix();
glutSwapBuffers();
}
我愿意接受甚至涉及着色器的任何建议(但是我很想知道,即使仅使用纯OpenGL也可以做到)。
更新 :
也许我不清楚,我不一定对严格的固定管道解决方案感兴趣,我想知道如何在场景中管理添加混合,即使这意味着向我的项目中添加着色器代码。
现在,正如Columbo所指出的,启用深度测试和禁用深度写入功能解决了我的第二个问题。 现在关于添加剂混合问题,我仍然不知道如何在场景中管理添加剂混合。 即使场景中可能没有这种基本颜色,问题仍然存在,因为火焰仍将是白色,我很愿意知道我与建议的像素着色器有什么关系。
对于添加剂混合问题,这可能不是问题。 在真实场景中,您永远不会遇到青色块。 但是,如果您确实需要解决方案,则可以尝试预乘alpha混合(glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);),然后您将有更多控制权。 在像素着色器中,您可以将输出RGB手动乘以源alpha,然后可以选择输出alpha。 零输出alpha会产生与您当前相同的加性混合。 输出完整的Alpha值(顶点Alpha *纹理Alpha)会为您提供标准的调制Alpha混合。 您可能能够在这两个极端值之间找到一些值,这些值会使背景变暗,即使在青色背景下,您的火焰也显得发黄,而不会使其看起来像垃圾。 如果您不使用像素着色器,那么我相信使用固定功能管线可以通过在纹理加载期间操纵纹理来实现。 一切都相当怪异,我建议这样做不值得,因为在完成的光线充足的场景中,您不会拥有如此原色。 更加正确的解决方案是使用HDR和色调映射,但这已进入了一些相当高级的渲染技术。
解决深度问题很简单。 您需要为火焰启用深度测试,但要禁用深度写入。 glEnable(GL_DEPTH_TEST)和glDepthMask(GL_FALSE)是相关命令。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.