forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   C++ (http://forum.boolean.name/forumdisplay.php?f=22)
-   -   2d в OpenGL. вывод тени от спрайта (http://forum.boolean.name/showthread.php?t=9104)

aureli0 08.09.2009 16:49

2d в OpenGL. вывод тени от спрайта
 
Вложений: 1
Сейчас делаю игрушку-скролл шутер. Появились трудности с выводом теней.
На данный момент тени от спрайтов вывожу следующим образом:
Код:

void enemy_air_shadow_draw()//рисование тени от воздушных юнитов
 {
  glColor4f(0,0,0,0.5);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  for(i=0; i < enemy_max; i++)
  {
    if (enemy[i].air==1)
    {
      glBindTexture(GL_TEXTURE_2D,enemy_texture[enemy[i].texture]);
      DrawTXT (enemy[i].x*grid_DX+enemy_move_x[i]+x_cam+0.2*(enemy[i].x*grid_DX+enemy_move_x[i]-win_DX/2),
              enemy[i].y*grid_DY+enemy_move_y[i]+y_cam+40,
              enemy[i].dx,
              enemy[i].dy,
              0,1); 
    }
  }
  glColor4f(1,1,1,1);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
 }

Но здесь есть ряд проблем: тени выводятся на все элементы уровня и задний фон, а также они смешиваються, становясь темнее.
Как сделать так, чтобы тень появлялась ТОЛЬКО на декорациях уровня(зеленые элементы), а не на картинке заднего плана(космос)?
Как исправить смешение теней?

jimon 08.09.2009 17:00

Ответ: 2d в OpenGL. вывод тени от спрайта
 
aureli0
можно использовать буфер трафарета (stencil), принцип простой : рисуем задний фон и в трафарет для пикселя пишется 0, рисуем декорации - в трафарет для пикселя пишется 1, ставим условие что рисуем пиксель только если в трафарете 1 и рисуем тени, таким же способом делается отсечения смешивания - после рисования тени пишем в буфер трафарета 2, в итоге следуйшие пиксели тени не смогут быть выведены на этот место потому что в буфере трафарета стоит не 1, а 2

ps. никогда не юзал stencil (но буду), вышенаписанное это мои теоретические знания

aureli0 08.09.2009 20:34

Re: 2d в OpenGL. вывод тени от спрайта
 
спасибо)
эээээ, значит както так??

//ИНИЦИАЛИЗАЦИЯ
// очищаем все буферы
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// разрешаем тест трафарета
glEnable(GL_STENCIL_TEST);

//Где то в главном цикле программы

рисуем задний фон

//в трафарет для пикселя пишется 0
glStencilFunc(GL_ALWAYS, 0, 0);

рисуем дикорации

//в трафарет для пикселя пишется 1
glStencilFunc(GL_ALWAYS, 1, 0);
//ставим условие что рисуем пиксель только если в трафарете 1
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

рисуем тень

//в трафарет для пикселя пишется 2-делаем отсечение смешивания
glStencilFunc(GL_ALWAYS, 2, 0);

рисуем все остальное


смотрел сюда
http://www.opengl.org.ru/books/open_gl/chapter4.12.html

с синтаксисом glStencilFunc и glStencilFunc я так и не разобрался:((

У себя ы программе сделал так:

//гдето в главном цикле
//в трафарет для пикселя пишется 0
glStencilFunc(GL_ALWAYS, 0, 0);

level_draw();
enemy_ground_draw();//рисование и анимация наземных врагов
starwind_draw();

//в трафарет для пикселя пишется 1
glStencilFunc(GL_ALWAYS, 1, 0);
//ставим условие что рисуем пиксель только если в трафарете 1
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

player_shadow_draw();
enemy_air_shadow_draw();

//в трафарет для пикселя пишется 2-делаем отсечение смешивания
glStencilFunc(GL_ALWAYS, 2, 0);


enemy_air_draw();//рисование и анимация летающих врагов
enemy_blast_draw();//рисуем патрон врага

player_draw();//Рисуем корабль игрока
player_ammo_draw();//Рисуем патрон игрока

effect_draw();

ничего не получилось. картинка осталась без изменения
что делать?

aureli0 08.09.2009 22:22

Re: 2d в OpenGL. вывод тени от спрайта
 
получилось вот таким образом, но тени смешиваются,как это исправить?
Код:


    // Значение, которым будет заполняться буфер стенсила при его очистке
    glClearStencil(0);//значение фона буфера стенсила фона
    glStencilMask(0xFF);//Определяем, какие биты могут писаться в стенсил буфер
    glClear( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);// Очищаем все буферы

    //Задний фон
    glColor4f(1,1,1,1);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,background_texture);
    DrawTXT(win_DX/2,win_DY/2,win_DX,win_DY,0,1);

      level_draw();
      enemy_ground_draw();//рисование и анимация наземных врагов
      starwind_draw();

      glEnable(GL_STENCIL_TEST);//включаем трафарет
      //определяем область где тень рисуется
      glStencilFunc(GL_NEVER, 1, 0);
      //в том месте где рисуется трафарет значение буфера заменяем на 1
      glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
      level_draw();//уровень является трафаретом-только на нем видна тень
      // тень будет рисоваться только в тех местах,где значение в буфере 1
      glStencilFunc(GL_EQUAL, 1, 255);
      player_shadow_draw();
      enemy_air_shadow_draw();
      glDisable(GL_STENCIL_TEST);//отключаем трафарет

      enemy_air_draw();//рисование и анимация летающих врагов
      enemy_blast_draw();//рисуем патрон врага

      player_draw();//Рисуем корабль игрока
      player_ammo_draw();//Рисуем патрон игрока

      effect_draw();


jimon 08.09.2009 22:39

Ответ: 2d в OpenGL. вывод тени от спрайта
 
ммм по-идее так должно работать
Код:

      glEnable(GL_STENCIL_TEST);//включаем трафарет
      //мы в любом случае будем писать в трафарет
      glStencilFunc(GL_ALWAYS, 0, 255);
      //в том месте где рисуется трафарет значение буфера заменяем на 1
      glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
      level_draw();//уровень является трафаретом-только на нем видна тень
      // тень будет рисоваться только в тех местах,где значение в буфере 1
      glStencilFunc(GL_EQUAL, 1, 255);
      glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
      player_shadow_draw();
      enemy_air_shadow_draw();
      glDisable(GL_STENCIL_TEST);//отключаем трафарет


aureli0 08.09.2009 22:50

Re: 2d в OpenGL. вывод тени от спрайта
 
Код:

  // Значение, которым будет заполняться буфер стенсила при его очистке
  glClearStencil(0);//значение фона буфера стенсила фона
  glStencilMask(0xFF);//Определяем, какие биты могут писаться в стенсил буфер
  //Очищаем экран перед рисованием и буфер стенсила
  glClear( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);// Очищаем все буферы

рисуем задник

      glEnable(GL_STENCIL_TEST);//включаем трафарет
      //мы в любом случае будем писать в трафарет
      glStencilFunc(GL_ALWAYS, 1, 255);  //!!!!!!!!!!! не 0 а 1
      //в том месте где рисуется трафарет значение буфера заменяем на 1
      glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
      level_draw();//уровень является трафаретом-только на нем видна тень
      // тень будет рисоваться только в тех местах,где значение в буфере 1
      glStencilFunc(GL_EQUAL, 1, 255);
      glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
      player_shadow_draw();
      enemy_air_shadow_draw();
      glDisable(GL_STENCIL_TEST);//отключаем трафарет

заработало так, причем цвета теней больше не смешиваются ура:)
спасибо)

А как сделать чтобы тени еще не выводились на дырах(альфа канал) в спрайтах?

jimon 08.09.2009 23:05

Ответ: 2d в OpenGL. вывод тени от спрайта
 
Цитата:

А как сделать чтобы тени еще не выводились на дырах(альфа канал) в спрайтах?
хм, ну можно сделать такой альфа тест что при alpha < 0.5 пиксель не будет выводится, собсно в буфере трафарета будет 0 и не будет там тень рисоваться

aureli0 08.09.2009 23:08

Re: 2d в OpenGL. вывод тени от спрайта
 
Вложений: 1
тоже теперь не все хорошо тени от объектов одного типа режут друг друга

jimon 08.09.2009 23:15

Ответ: 2d в OpenGL. вывод тени от спрайта
 
aureli0
так приделай еще альфа тест для теней тоже с каким нибудь условием что если альфа = 0 то не рисовать пиксель

aureli0 08.09.2009 23:35

Re: Ответ: 2d в OpenGL. вывод тени от спрайта
 
Цитата:

Сообщение от jimon (Сообщение 118019)
aureli0
так приделай еще альфа тест для теней тоже с каким нибудь условием что если альфа = 0 то не рисовать пиксель

эт я понял только опять же какие параметры давать в glAlphaFunc?

Код:

//цвета теней не смешиваються!!!
      glEnable(GL_STENCIL_TEST);//включаем трафарет
      //мы в любом случае будем писать в трафарет
      glStencilFunc(GL_ALWAYS, 1, 255);
      //в том месте где рисуется трафарет значение буфера заменяем на 1
      glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

      level_draw();//уровень является трафаретом-только на нем видна тень

      // тень будет рисоваться только в тех местах,где значение в буфере 1
      glStencilFunc(GL_EQUAL, 1, 255);
      glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_EQUAL,1);//выводить тени только на видимых пикселях с альфа 1
      player_shadow_draw();
      enemy_air_shadow_draw();
glDisable(GL_ALPHA_TEST);
      glDisable(GL_STENCIL_TEST);//отключаем трафарет

по идее тени должны рисоваться только на пикселях с альфа=1, но тени просто полностью пропали(( опять я чето перепутал)

jimon 08.09.2009 23:39

Ответ: 2d в OpenGL. вывод тени от спрайта
 
хм
Код:

//цвета теней не смешиваються!!!
      glEnable(GL_STENCIL_TEST);//включаем трафарет
      //мы в любом случае будем писать в трафарет
      glStencilFunc(GL_ALWAYS, 1, 255);
      //в том месте где рисуется трафарет значение буфера заменяем на 1
      glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

//ну вообще-то нам надо отсечь рисования прозрачных пикселей уровня
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER,0.5f); //выводим только те пиксели уровня у которых alpha > 0.5f

      level_draw();//уровень является трафаретом-только на нем видна тень

      // тень будет рисоваться только в тех местах,где значение в буфере 1
      glStencilFunc(GL_EQUAL, 1, 255);
      glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);

glAlphaFunc(GL_GREATER,0.2f); //выводим только те пиксели тени у которых alpha > 0.2f

      player_shadow_draw();
      enemy_air_shadow_draw();
glDisable(GL_ALPHA_TEST);
      glDisable(GL_STENCIL_TEST);//отключаем трафарет

там где 0.2f надо будет эксперементировать, в принципе если тени наложатся то в границе наложения будут небольшие баги, имхо тени надо сумировать

aureli0 09.09.2009 00:02

Re: 2d в OpenGL. вывод тени от спрайта
 
вот спасибо)) теперь все как надо. Да глюки есть. Поменял значение с 0.2 на 0.4 границы пропали но тени стали четче ну и фиг с ним все здорово))
Еще раз спасибо))

aureli0 14.09.2009 22:25

Re: 2d в OpenGL. вывод тени от спрайта
 
опять появились проблемы с тенями. Раньше каждая текстура хранилась в отдельном файле, и все работало без проблем. Теперь я использую для вывода level один файл с несколькими текстурами-появились глюки:
то иень периодически пропадает, то пооявляется. В трафарет помимо level_draw я добавил еще наземных юнитов enemy_groumd_Draw. Так вот они стали тоже "моргать".

Код:

//цвета теней не смешиваються!!! работает с глюками при выводе уровня из 1 текстуры
      glEnable(GL_STENCIL_TEST);//включаем трафарет
      glStencilFunc(GL_ALWAYS, 1, 255);//в том месте где рисуется трафарет значение буфера заменяем на 1
      glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
      glEnable(GL_ALPHA_TEST);      //надо отсечь рисования прозрачных пикселей уровня
      glAlphaFunc(GL_GREATER,0.5f); //выводим только те пиксели уровня у которых alpha > 0.5f
        level_draw();//уровень является трафаретом-только на нем видна тень
    //    enemy_ground_draw();//тоже трафарет
      glStencilFunc(GL_EQUAL, 1, 255);// тень будет рисоваться только в тех местах,где значение в буфере 1
      glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
      glAlphaFunc(GL_GREATER,0.45f); //выводим только те пиксели тени у которых alpha > 0.45f
        player_shadow_draw();
        enemy_air_shadow_draw();
      glDisable(GL_ALPHA_TEST);
      glDisable(GL_STENCIL_TEST);//отключаем трафарет

чето гдето нето:( чтото с альфой?


Часовой пояс GMT +4, время: 04:00.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Перевод: zCarot