【问题标题】:How to handle OpenGL additive blending and depth test with particles and deeper objects如何使用粒子和更深的对象处理 OpenGL 附加混合和深度测试
【发布时间】:2016-01-21 05:29:28
【问题描述】:

我有一个用 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 指出的那样,启用深度测试并禁用深度写入解决了我的第二个问题。现在关于加法混合问题,我仍然不知道如何在场景中管理加法混合。即使场景中可能没有这样的基本颜色,问题仍然存在,因为火焰仍然是白色的,我愿意知道我必须按照建议使用像素着色器。

【问题讨论】:

  • "只有普通的 OpenGL":OpenGL 2.1+ 它普通的 OpenGL 来编写着色器。
  • @CoffeeandCode 我认为我们可以通过引用带有 GLSL 的着色器来区分 OpenGL 和着色器。抱歉使用的术语具有误导性...无论如何,我的意思是我没有为此编写任何着色器,并且想知道如果不编写着色器是否有可能。
  • 如果您正在学习 OpenGL 并希望将来真正使用您的知识,我建议您忘记所有固定功能的东西,只学习 OpenGL 3.3 核心配置文件并进行扩展测试。

标签: c++ c opengl shader particle-system


【解决方案1】:
  1. 对于添加剂混合问题,它可能不是问题。在真实场景中,您永远不会出现青色块。但是,如果你真的需要一个解决方案,你可以尝试一个预乘的 alpha 混合 (glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);),然后你就有了更多的控制权。在您的像素着色器中,您可以手动将输出 RGB 乘以源 alpha,然后您可以选择输出 alpha。输出 alpha 为零会产生与您目前一样的添加剂混合。输出完整的 alpha 值(顶点 alpha * 纹理 alpha)为您提供标准的调制 alpha 混合。您可能能够在这两个极端之间找到一些值,使背景变暗,使您的火焰即使在青色背景下看起来也呈黄色,而不会使其看起来很垃圾。如果您不使用像素着色器,我相信可以通过在纹理加载期间操纵纹理来使用固定功能管道。这一切都相当繁琐,我建议不值得这样做,因为在完成的照明场景中不会有这样的原色。更正确的解决方案是使用 HDR 和色调映射,但这涉及到一些非常先进的渲染技术。

  2. 解决深度问题很简单。您需要为火焰启用深度测试,但禁用深度写入。 glEnable(GL_DEPTH_TEST) 和 glDepthMask(GL_FALSE) 是相关的命令。

【讨论】:

  • 谢谢!正如您提到的 glDepthMask(GL_FALSE) 解决了深度问题。关于混合,我按照您的建议尝试了预乘 alpha 混合,仅使用固定功能管道并失去了加法效果......我使用的纹理也有黑色环境,改变了最终效果......什么样的操作是你指的是加载纹理时?另外,我是关于着色器的新手,您能否将我链接到任何带有示例的参考或解释如何实现您正在谈论的像素着色器处理?感谢您提供有关 HDR 和色调映射的提示!
猜你喜欢
  • 1970-01-01
  • 2018-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
  • 2015-10-12
相关资源
最近更新 更多