Как обрабатывать аддитивное смешивание OpenGL и тест глубины с частицами и более глубокими объектами

У меня есть небольшая система частиц спрайтов, созданная с помощью OpenGL, и я использую текстуры для рисования основного пламени. Пламя воспроизведено симметрично, чтобы показать, как оно ведет себя в небольшой коробке/сцене. И, как показано на рисунках ниже, есть две проблемы:

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).

ОБНОВЛЕНИЕ:

Может быть, я был неясен, меня не обязательно интересует решение со строго фиксированным конвейером, я хочу знать, как управлять аддитивным смешиванием в сцене, даже если это означает добавление кода шейдеров в мой проект.

Теперь, как указал Коломбо, включение тестирования глубины и отключение записи глубины решило мою вторую проблему. Теперь, что касается проблемы аддитивного смешивания, я до сих пор понятия не имею, как управлять аддитивным смешиванием в сцене. Несмотря на то, что в сцене может не быть таких основных цветов, проблема все еще остается, поскольку пламя по-прежнему будет белым, и я открыт, чтобы узнать, что мне делать с пиксельным шейдером, как было предложено.


person pandaman1234    schedule 22.10.2015    source источник
comment
с простым OpenGL: OpenGL 2.1+ является простым OpenGL для написания шейдеров.   -  person RamblingMad    schedule 22.10.2015
comment
@CoffeeandCode Я думал, что мы можем отличить OpenGL от шейдеров, ссылаясь на шейдеры с GLSL. Извините за вводящий в заблуждение используемый термин... В любом случае, я имел в виду, что я не писал для этого никакого шейдера и задавался вопросом, возможно ли это без написания шейдеров.   -  person pandaman1234    schedule 22.10.2015
comment
Если вы изучаете OpenGL и действительно хотите использовать свои знания в будущем, я бы порекомендовал вам забыть все свои фиксированные функции и изучить только базовый профиль OpenGL 3.3 и провести тестирование расширений.   -  person RamblingMad    schedule 23.10.2015


Ответы (1)


  1. Для проблемы смешивания добавок это может не быть проблемой. У вас никогда не будет блока голубого в реальной сцене. Однако, если вам действительно нужно решение, вы можете попробовать альфа-смесь с предварительным умножением (glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);), тогда у вас будет немного больше контроля. В вашем пиксельном шейдере вы можете умножить выходной RGB на исходную альфу вручную, затем вы можете выбрать выходную альфу. Выходная альфа, равная нулю, дает аддитивную смесь, как у вас на данный момент. Вывод полного альфа-значения (альфа вершины * альфа текстуры) дает стандартное модулирующее альфа-смешивание. Возможно, вы сможете найти какое-то значение между этими двумя крайностями, которое затемнит фон настолько, что ваше пламя будет выглядеть желтым даже на голубом фоне, не заставляя его выглядеть мусором. Если вы не используете пиксельные шейдеры, я считаю, что это возможно с фиксированным конвейером функций, манипулируя вашей текстурой во время загрузки текстуры. Это все довольно хлопотно, и я бы посоветовал не делать этого, потому что у вас не будет таких основных цветов в готовой освещенной сцене. Более правильное решение — использовать HDR и тональную компрессию, но это связано с некоторыми довольно продвинутыми методами рендеринга.

  2. Исправить проблему с глубиной просто. Вам нужно включить тестирование глубины для вашего пламени, но отключить запись глубины. glEnable(GL_DEPTH_TEST) и glDepthMask(GL_FALSE) являются соответствующими командами.

person Columbo    schedule 22.10.2015
comment
Спасибо! Как вы упомянули, glDepthMask(GL_FALSE) решил проблему глубины. Что касается смешивания, я попробовал предварительно умноженное альфа-смешивание, как вы предложили, только с использованием конвейера фиксированной функции и потерял аддитивный эффект ... также текстуры, которые я использую, имеют черное окружение, которое изменяет конечный эффект ... какие манипуляции вы имеете в виду при загрузке текстур? Кроме того, я новичок в шейдерах, не могли бы вы связать меня с какой-либо ссылкой с примером или объяснением того, как добиться обработки пиксельных шейдеров, о которой вы говорите? Спасибо за подсказку по HDR и тональной компрессии! - person pandaman1234; 22.10.2015