{{notification.text}}

MirGames

26.07.09 17:14
0
Переписал систему частиц с использованием PointSprites. Скорости прибавилось изрядно (особенно заметно на маломощном ноутбуке, а уж когда VBO к ним прикруче, вообще ням будет).
Но возникла... мелкая проблема. Мелкая, но неприятна, аки комар, и столь же зудящая.

Переодически спрайты выводятся так, будто glPointSize не вызывается вообще. Причем проскакивает только изредка. Непонятно. Код и скрины прилагаю, может, кто-то уже с таким сталкивался? GlError молчит в тряпочку.

Скрины (слева - норма, справа - изредка проскакивающая гадость).
Изображение Изображение

Код:
(NEF - это сокращалка, т.к. описание класса находится в загаловочном файле как библиотеки, так и проекта, библиотеку использующая).
Begin3D(), End3D() - это простая комбинация glPushMatrix()/glPopMatrix; и сбрасывание цвета

Код
struct SParticle3D
    {
    GLfloat x,y,z,Size;
    GLfloat Moves[3];
    GLfloat MovesAdd[3];
    GLfloat Angle[3];        //X,Y,Z
    GLfloat AngleAdd[3];
    GLfloat Color[4];
    GLfloat ColorAdd[4];
        GLfloat AddSize;
    int Time;
    };

class TParticlesSystem
{
  protected:
  SParticle3D Parts[3000];
  SParticle3D def;
  TModel model;
  bool ModelUse;
  public:
  GLuint texture;
  TParticlesSystem() {for (int i=0;i<3000;i++)Parts[i].Time=0; ModelUse=false; texture=0;};
  ~TParticlesSystem() {};

  void  NEF Draw();
  void  NEF Process();
  void  NEF Add(SParticle3D Part0);
  void  SetDefault(SParticle3D Part0) {def=Part0;};
  void  NEF SetTexture(GLuint txt0);
  void  SetModel(TModel model0){model=model0; ModelUse=true; model.TextureID=texture;};
  SParticle3D GetDefault() {return (def);};
};

void TParticlesSystem::SetTexture(GLuint Texture0){
texture=Texture0;
};

void TParticlesSystem::Process(){
int j=0;
for (int i=0;i<3000;i++)
        if (Parts[i].Time>0)
        {
          Parts[i].Time--;

              Parts[i].x+=Parts[i].Moves[0];
              Parts[i].y+=Parts[i].Moves[1];
              Parts[i].z+=Parts[i].Moves[2];
         int j;

         for (j=0;j<3;j++)
         Parts[i].Angle[j]+=Parts[i].AngleAdd[j];
//угу, написать операции с векторами я так и не удосужился

         for (j=0;j<3;j++)
         Parts[i].Moves[j]+=Parts[i].MovesAdd[j];

         for (j=0;j<4;j++)
         Parts[i].Color[j]+=Parts[i].ColorAdd[j];
         Parts[i].Size+=Parts[i].AddSize;

         if (Parts[i].Color[3]<=0.0) Parts[i].Time=0;
        };
};



void TParticlesSystem::Draw(){
for (int j=0;j<3000;j++)
        if (Parts[j].Time>0)
{
Begin3D(); glDepthMask(false);

if (ModelUse==false)
{
float maxSize = Parts[j].Size;

glBindTexture(GL_TEXTURE_2D, texture);
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
        // Устанавливаем способ изменения размеров спрайтов
    float quadratic[] =  { 1.0f, 0.0f, 0.01f };
    glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic );
GlError("способ изменения размеров спрайтов");

glPointSize(maxSize );
GlError("размер точки");
    glPointParameterfARB( GL_POINT_FADE_THRESHOLD_SIZE_ARB, 45.0f );
  GlError("FADE");
    glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 1.0f );
    glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, maxSize );
  GlError("min max");


    glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE );
GlError("текстурирование точки");
    //
    // Render point sprites...
    //

    glEnable( GL_POINT_SPRITE_ARB );
glBegin( GL_POINTS );
for (int i=0;i<3000;i++)
        if (Parts[i].Time>0){
  glColor4f(Parts[i].Color[0],Parts[i].Color[1],Parts[i].Color[2],Parts[i].Color[3]);
  glVertex3f(Parts[i].x,Parts[i].y,Parts[i].z );
  };

glEnd();
glDisable( GL_POINT_SPRITE_ARB );
glDisable(GL_BLEND);
glBlendFunc ( GL_ONE, GL_ONE );
glPointSize(1.0);
}else
for (int i=0;i<3000;i++)
        if (Parts[i].Time>0)
           {
      Begin3D();
         model.Move(Parts[i].x,Parts[i].y,Parts[i].z);
       GlError("перемещение модели");
         model.Size=Parts[i].Size;
       GlError("изменение размера модели");
         model.AngleX=Parts[i].Angle[0];
         model.AngleY=Parts[i].Angle[1];
         model.AngleZ=Parts[i].Angle[2];
         GlError("вращение модели");
             SetColor(Parts[i].Color[0],Parts[i].Color[1],Parts[i].Color[2],Parts[i].Color[3]);
         model.DrawStatic();
         GlError("рисование модели");
      End3D();
      }

              glDepthMask(true);
        End3D();
break;
};
}

void TParticlesSystem::Add(SParticle3D Part0){
for (int i=0;i<3000;i++)
        if (Parts[i].Time<=0) {Parts[i]=Part0; goto konec;};
konec:
};
#1
Программир Всия Руси!
26.07.09 21:34
0
Расскажи че за поинт спрайты, никогда не юзал )
#2
аксакал
26.07.09 22:02
0
На современных видеокартах PointSize = 64px - потолок )
#3
27.07.09 00:16
0
DRON
расширение. передаёшь только координаты спрайта и цвет, а видюха сама рисует билдодры квадратные. :)

XProger
Хм. А вот с какого то примера:
Код

    // Clamp size to 100.0f or the sprites could get a little too big on some  
    // of the newer graphic cards. My ATI card at home supports a max point
    // size of 1024.0f!
    if( maxSize > 100.0f )
        maxSize = 100.0f;

    glPointSize( maxSize );


А чем ещё лучше партиклы делать? VBO+билборды? Просто меня несколько напрягает, что каждый кадр придётся создавать структуру, пихать в неё данные по партиклам, а уже её в VBO. (у меня же не подряд идут живые и мёртвые спрайты).
#4
аксакал
27.07.09 00:44
0
ATI карточки вообще в старых дровах текстурили поинт-спрайты неверно... )
Настоящие поцаны делают простой буфер по 4 вершинки на элемент (биллборд), каждая вершинка хранит порядковый индекс элемента. Кладут этот буфер в VBO. Затем пишется шейдер в который юниформами загоняются координаты биллбордов, а он их там сопоставляет и растягивает 4 вершинки по текстурным координатам 8)
#5
27.07.09 00:49
0
Ну неверно так неверно, без них обойдусь.
А я пока изучаю не-пацанксие методы, или "как жить без шейдеров" ;)

"юниформами" - чем?
Отредактировано: 27.07.09 00:52
#6
аксакал
27.07.09 00:57
0
Nubilius
Вот и зря, видеокарт без шейдеров практически не осталось, а убивать производительность из-за каких-то предрассудков - глупо по меньшей мере.
В шейдер передаются аттрибуты (повершинные параметры), и юниформы (константы на время выполнения шейдера)
Отредактировано: 27.07.09 00:59
#7
27.07.09 01:10
0
Да не предрассудки, просто ведь как то раньше жили без шейдеров и вполне симпатишные эффекты делали!
Мне особенно запомнились K.I.S.S. (размытие экрана при ранениях), Shadowgrounds и Silent Hill 2 (отличные динамические тени), все отлично работающие на GeForce 2 GTS без тормозов. :)

Только вот один фиг осталось непонятно, какого черта нестабильно работают поинтспрайты. %)
#8
27.07.09 01:25
0
лучше не юзать эту фичу.. на некоторых радеонах подвешивает комп в мёртвую, ток ресет спасает. имхо, лучше шейдеры..
#9
27.07.09 01:30
0
Ладно. Убедили. Добили. Ушел качать SDK шейдерный мучить.
Версии 1.1, ибо совместимость превыше всего :D
#10
27.07.09 01:46
0
Цитата
Версии 1.1

угу, кул. сам всё хател освоить этот полуасм, но пока чота никак, тока глсл..
#11
27.07.09 01:54
0
Woolf
Э, чет я проморгал, но ить CG 1.1 даже близко не полуасм? o_O Или опять я что-то не то понял...

Тогда на тему сразу спрошу, а где-нить есть сборная таблица, на каких видеокартах поддерживаются какие версии вершинных шейдеров/VBO ? Не по названиям чипов, а по семействам видеокартах?
#12
аксакал
27.07.09 03:50
0
Nubilius
Cg работает на NV и новеньких ATI. Поддерживается начиная с OpenGL 2.0, впрочем как и GLSL который работает на NV (GF 5200FX) и ATI (Radeon 9600).
SM 1.1 - это ущербный такой ограниченный по самое нихачу ассемблер.
Отредактировано: 27.07.09 03:52
#13
27.07.09 04:25
0
Красотень. Т.е., если нужна совместимость на всём, начиная с GeForce 2 (или intelовские встроенные), придётся юзать шейдеры (речь о вертексных, естественно) на языке, близком к ассемблерному? красотень :D
#14
аксакал
27.07.09 04:34
0
Вот на кой хрен твоей игре на GeForce 2 запускаться? 5% аудитории (причём явно не игровой) тебе погоду сделает?
#15
27.07.09 06:15
0
Моя работает ) правда тормозит и картинка уродливая, но пашет..
#16
Программир Всия Руси!
27.07.09 11:22
0
XProger
Нармальные ассемблерные шейдеры я юзал, не гони на них, они клевые :)))
#17
27.07.09 15:54
0
DRON это как из темы зачем использовать другой язык программирования(ява, си, паскаль), когда есть ассмблер :D:D:DNubilius ниже чем GeForce 5200 даже забудь о их существовании, это прошлое тысячитетие.....а выше уже естьи шейдеры и поинтспрайт и много интересного....
#18
27.07.09 16:17
0
XProger
ну вот хотелось) смысла практического мало конечно, но приятно, когда пашет даже на такой реликвии, мало-ли когда сможет пригодиться ;) Тем более что эта реликвия у меня дома есть :)

lans
Цитата(lans @ Сегодня, 13:54)
[snapback]96726[/snapback]
а выше уже естьи шейдеры и поинтспрайт и много интересного....

вот я поюзал поинт-спрайты, а тут выясняется, что косяков у них много. ща начал шейдеры копать, наверняка тоже много весёлого выяснится на тему совместимостей...
P.S. а всякие WoW, линейки2, флэтауты, Painkiller и иже с ними всё-ещё отлично тянут на GeForce2 GTS без тормозов (пусть и без пачки эффектов и далеко не на максимальном качестве). Так-то :D

DRON
а никто не говорил, что они плохие) просто возиться с ассемблерным кодом, когда под рукой имеется и Си-подобный... только после того, как разберусь с GLSL)
#19
29.07.09 02:22
0
Показанный тут шейдер является оптимальным в общих чертах? (в смысле вычисления положения, остальное дописывать буду сам)
Брал отсюда:
http://www.gamedev.ru/code/terms/Billboard


Код
<vertex>
// ** Пример простейшего шейдера ориентации биллборда
// ** На вход вершинному шейдеру подаются вершины прямоугольника
// ** с координатами( -s, -s, 0 ), ( -s, s, 0 ), ( s, s, 0 ), ( s, -s, 0 ) (прямоугольник в плоскости XY), где s - размер биллборда
uniform vec3 u_Position;

void main( void ) {
    // ** Получаем up & right векторы
    vec3 X = vec3( gl_ModelViewMatrix[0][0], gl_ModelViewMatrix[1][0], gl_ModelViewMatrix[2][0] );
    vec3 Y = vec3( gl_ModelViewMatrix[0][1], gl_ModelViewMatrix[1][1], gl_ModelViewMatrix[2][1] );

    // ** Вычисляем положение вершины
    vec3 vertex = gl_Vertex.x * X + gl_Vertex.y * Y + u_Position;
    gl_Position = gl_ModelViewProjectionMatrix * vec4( vertex, 1.0 );
}



И, второй вопрос. Как дать команду в шейдере не рисовать какие то вершины? (ну если я не хочу, чтобы какие то частицы рисовались, ибо мертвы нафиг).
#20
аксакал
29.07.09 03:14
0
Nubilius
Код шейдера не идеальный, но сойдёт... в будущем позиции вершин всё же через юниформы лучше будет передавать, чем каждый кадр фигачить по 4 вершины в буфер )

Вершины не рисуются, рисуются фрагменты которые отсекаются при помощи discard в фрагментном шейдере. Но тебе это не поможет, передавай на отрисовку уплотнённый буфер, без "мёртвых" биллбордов.
#{{post.Index}}
{{post.Author.Login}}
{{post.CreatedDate | date:'dd.MM.yy HH:mm'}}
{{post.VotesRating}}
Отредактировано: {{post.UpdatedDate | date:'dd.MM.yy HH:mm'}}