как реализовать алгоритм z-fail в opengl?

Я кодирую так, как мне сказали наставники NeHe, урок 27, но это алгоритм z-pass. Когда я в тени, тень исчезает. Кто-то сказал мне, что я могу использовать алгоритм z-fail для решения этой проблемы. поэтому я трачу два дня на исследование алгоритма z-fail. Наконец, я не могу понять это. Моя программа никогда не работает так, как я думаю.

Алгоритм z-fail, как указано в вики:

Ошибка глубины Примерно в 2000 году несколько человек обнаружили, что метод Хайдмана можно заставить работать для всех положений камеры путем изменения глубины на противоположное. Вместо подсчета теневых поверхностей перед поверхностью объекта можно так же легко подсчитать поверхности за ним с тем же конечным результатом. Это решает проблему нахождения глаза в тени, поскольку теневые объемы между глазом и объектом не учитываются, но вводит условие, что задний конец теневого объема должен быть закрыт, иначе тени будут отсутствовать там, где указывает объем. обратно в бесконечность.

  1. Отключите запись в буферы глубины и цвета.

  2. Используйте отбраковку лицевой стороны.

  3. Настройте операцию трафарета на увеличение при сбое глубины (учитываются только тени позади объекта).

  4. Визуализируйте теневые объемы.

  5. Используйте отбраковку обратной стороны.

  6. Установите операцию трафарета на уменьшение при сбое глубины.

  7. Визуализируйте теневые объемы.

Главный вопрос, я думаю, это тест на глубину. На шагах 3 и 6 операция трафарета основана на сбое глубины. Хотя он может отображать тень, но он может быть затенен на объекте перед ним (т.е. на объекте, значение буфера глубины которого меньше его). Таким образом, все эффект тени выглядит беспорядком.

Но в алгоритме z-прохода работа трафарета основана на проходе глубины, что означает, что он может не только показать тень, но и затенить только объект позади него, что соответствует системе глаз.

Итак, как решить эту проблему, чтобы мой алгоритм ошибки глубины показывал тень на нужных объектах.

вот мой код алгоритма z-fail(где-то может быть где-то,пожалуйста помогите узнать,эффект тени ужасный)

VECTOR vec;        
void shadowvolume(SECTOR &sec,float *lp)
{
    unsigned int    p1, p2;
    VECTOR          v1, v2;
    int i, j, k, jj;
    for (i=0; i<sec.numplanes;i++)
    {
        if (sec.planes[i].visible)
        {
            for (j=0;j<3;j++)
            {
                k = sec.planes[i].neigh[j];
                if ((!k) || (!sec.planes[k-1].visible))//如果以第k个点开始的邻边没有相邻平面或者相邻平面不可见
                {
                    // here we have an edge, we must draw a polygon
                    p1 = sec.planes[i].p[j]-1;//邻边的起点
                    jj = (j+1)%3;           
                    p2 = sec.planes[i].p[jj]-1;//邻边的终点

                    //calculate the length of the vector
                    v1.x = (sec.points[p1].vec.x - lp[0])*100;
                    v1.y = (sec.points[p1].vec.y - lp[1])*100;
                    v1.z = (sec.points[p1].vec.z - lp[2])*100;

                    v2.x = (sec.points[p2].vec.x - lp[0])*100;
                    v2.y = (sec.points[p2].vec.y - lp[1])*100;
                    v2.z = (sec.points[p2].vec.z - lp[2])*100;

                    glBegin(GL_TRIANGLE_STRIP);//将光源连到邻边的起点并延长,将光源连到邻边的终点的并延长,最后延长出来的梯形,画了过后模板缓冲区的值加1
                    glVertex3f(sec.points[p1].vec.x,sec.points[p1].vec.y,sec.points[p1].vec.z);
                    glVertex3f(sec.points[p1].vec.x + v1.x,sec.points[p1].vec.y + v1.y,sec.points[p1].vec.z + v1.z);
                    glVertex3f(sec.points[p2].vec.x,sec.points[p2].vec.y,sec.points[p2].vec.z);
                    glVertex3f(sec.points[p2].vec.x + v2.x,sec.points[p2].vec.y + v2.y,sec.points[p2].vec.z + v2.z);
                    glEnd();
                }
            }
            // caps
            glBegin(GL_TRIANGLES);  
            for(k=0;k<3;k++)
                glVertex3fv((float*)&sec.points[sec.planes[i].p[k]-1].vec);
            glEnd();
            glBegin(GL_TRIANGLES);  

            for(k=2;k>=0;k--)
            {
                vec.x=sec.points[sec.planes[i].p[k]-1].vec.x+(sec.points[sec.planes[i].p[k]-1].vec.x-lp[0])*100;
                vec.y=sec.points[sec.planes[i].p[k]-1].vec.y+(sec.points[sec.planes[i].p[k]-1].vec.y-lp[1])*100;
                vec.z=sec.points[sec.planes[i].p[k]-1].vec.z+(sec.points[sec.planes[i].p[k]-1].vec.z-lp[2])*100;
                glVertex3fv((float*)&vec);
            }
            glEnd();

        }
    }



}
void  CastShadow(SECTOR &sec, float *lp)
{//lp是光源相对于物体的位置
    float           side;

    glEnable(GL_CULL_FACE); 
    int i;
    for (i=0;i<sec.numplanes;i++)
    {
        side =sec.planes[i].planeeq.a*lp[0]+sec.planes[i].planeeq.b*lp[1]+sec.planes[i].planeeq.c*lp[2]+sec.planes[i].planeeq.d*lp[3];
        if (side>0) 
            sec.planes[i].visible = TRUE;
        else
            sec.planes[i].visible = FALSE;
    }

    glDisable(GL_LIGHTING);
    glDepthMask(GL_FALSE);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_STENCIL_TEST);
    glColorMask(0, 0, 0, 0);
    glStencilFunc(GL_ALWAYS, 0, 0xffffffff);

    glCullFace(GL_FRONT);
    glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
    //glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
    shadowvolume(sec,lp);

    glCullFace(GL_BACK);
    glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
    //glStencilOp(GL_KEEP,GL_KEEP,  GL_INCR);
    shadowvolume(sec,lp);



    glColorMask(1, 1, 1, 1);

    //draw a shadowing rectangle covering the entire screen
    glColor4f(0.0f, 0.0f, 0.0f,0.4f);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glStencilFunc(GL_NOTEQUAL, 0, 0xffffffff);
    //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
    glPushMatrix();
    glLoadIdentity();
    glBegin(GL_TRIANGLE_STRIP);
        glVertex3f(-0.1f, 0.1f,-0.0010f);
        glVertex3f(-0.1f,-0.1f,-0.0010f);
        glVertex3f( 0.1f, 0.1f,-0.0010f);
        glVertex3f( 0.1f,-0.1f,-0.0010f);
    glEnd();
    glPopMatrix();
    glDisable(GL_BLEND);

    glDepthFunc(GL_LEQUAL);
    glDepthMask(GL_TRUE);
    glEnable(GL_LIGHTING);
    glDisable(GL_STENCIL_TEST);
    glShadeModel(GL_SMOOTH);
    glDisable(GL_CULL_FACE);
}

класс VECTOR выглядит следующим образом:

class VECTOR
{
public:
    float x,y,z;
    bool operator==(VECTOR vec)
    {
        if(x==vec.x && y==vec.y && z==vec.z)
            return true;
        return false;
    }
};

класс SECTOR и другие выглядят так:

class PLANEEQ
{
public:
    float a,b,c,d;
};
class PLANE
{
public:
    unsigned int p[3];//点的序号
    VECTOR normal[3];
    unsigned int neigh[3];//平面3个相依平面的序号
    PLANEEQ planeeq;
    bool visible;
    PLANE()
    {
        neigh[0]=0;
        neigh[1]=0;
        neigh[2]=0;
        planeeq.a=0;
        planeeq.b=0;
        planeeq.c=0;
        planeeq.d=0;
        visible=false;
    }
};

class SECTOR
{
public:
    int numpoints;
    int numplanes;
    vector<VERTEX> points;
    vector<PLANE> planes;
    MATERIAL material;
    bool read();
    bool loadtexture();
    bool build();
    bool plane_calc();
    void SetConnectivity();
    SECTOR& SECTOR::subdivide(long depth);
    SECTOR(string str1,string str2):modelfilename(str1),texturefilename(str2)
    {
        numpoints=0;
        numplanes=0;

    }
    SECTOR()
    {
        numpoints=0;
        numplanes=0;

    }

private:
    FILE *modelfilein,*texturefilein;
    string modelfilename,texturefilename;
    char oneline[255];
    UINT texturename;
    AUX_RGBImageRec *TextureImage;
};
class POSITION
{
public:
    float x,y,z,w;
};

функция DrawGLScene в моем main.cpp выглядит так:

int DrawGLScene(GLvoid)                                 
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |GL_STENCIL_BUFFER_BIT);  
    glLoadIdentity();
    DrawGLRoom();
    glLoadIdentity();
    GLfloat xtrans = -xpos;
    GLfloat ztrans = -zpos;
    GLfloat ytrans = -ypos-1.2f;
    GLfloat sceneroty = 360.0f - yrot;  

    glRotatef(lookupdown,1.0f,0,0);
    glRotatef(sceneroty,0,1.0f,0);
    glTranslatef(xtrans, ytrans, ztrans);
    brick_sec.build();
    floor_sec.build();
    //wall_sec.build();

    //CastShadow(wall_sec,(float *)&lightgroup.lights[0].pos);
    CastShadow(brick_sec,(float*)&lightgroup.lights[0].pos);
    CastShadow(floor_sec,(float*)&lightgroup.lights[0].pos);    


    lightgroup.build(); 
    glColor4f(0.7f, 0.4f, 0.0f, 1.0f);  
    glDisable(GL_LIGHTING);                             
    glDepthMask(GL_FALSE);                              
    glTranslatef(lightgroup.lights[0].pos.x, lightgroup.lights[0].pos.y, lightgroup.lights[0].pos.z);               
    gluSphere(q, 0.2f, 16, 8);  
    glEnable(GL_LIGHTING);  
    glDepthMask(GL_TRUE);
    if(space_time>0)
    {
        ypos=sin(space_time*3.1415926/180);
        space_time-=4;
    }
    else
    {
        sp=false;
    }
    //glFlush();
    return TRUE;                                        // Everything Went OK
}

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

Спасибо Najzero за то, что дал мне 5 репутации, теперь я могу сделать снимок экрана, чтобы показать эффект. Я добавлю подробное описание ниже.

эффект алгоритма z-pass: когда я не в эффекте, все в порядке! (оранжевый горшок представляет свет) введите описание изображения здесь

но когда я нахожусь в wall_shadow, это не нормально! wall_shadow пропал, хотя кирпичная тень осталась.

введите здесь описание изображения

поэтому мне нужен алгоритм z-fail для решения этой проблемы. Но последний эффект, реализованный моим кодом, выглядит следующим образом: введите описание изображения  здесь галочка означает, что эффект тени правильный, крестик означает, что тень не должна появляться на объекте.

другой снимок экрана, введите здесь описание изображения


person nomorefancy    schedule 23.09.2012    source источник
comment
о, это должно быть интересно. У нас была адская проблема с похожей проблемой. На что настроен ваш ближний самолет? не вижу вызова gluPerspective(), чтобы сделать предположение. Когда ближняя плоскость равна 0, получаются сумасшедшие результаты для всего, что связано с Z-рендерингом.   -  person Najzero    schedule 23.09.2012
comment
вот моя функция gluPerspective: моя ближняя плоскость установлена ​​на 0.001f gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.001f,100.0f); ближняя плоскость не может быть 0, вместо этого вы можете использовать 0,00001.   -  person nomorefancy    schedule 23.09.2012
comment
Этот код ужасно устарел.   -  person Bartek Banachewicz    schedule 23.09.2012


Ответы (1)


ха, наконец-то я нашел проблему в своем коде. Я так счастлив, лол!!!!!!!!!!

проблема в gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.001f,100.0f);

как сказал Гюнтер Красс в http://www.opengl.org/discussion_boards/showthread.php/146157-Z-Fail-Stencil-Shadow-Volumes

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

поэтому я просто меняю код выше на

gluPerspective(45.0f,(GLfloat)ширина/(GLfloat)высота,0.001f,1000000.0f);

ладно,выглядит идеально!!!!!!!!!!!!!!!!111 хахахахааа

два дня, не ложиться спать, лапша быстрого приготовления .. черт возьми, это того стоит !!

хорошо, я выложу последнее изображение эффекта. Если кому-то нужен мой код, просто напишите мне ([email protected])

введите здесь описание изображениявведите здесь описание изображения введите здесь описание изображениявведите здесь описание изображения

внимание: тень кирпича не зависит от тени стены.

person nomorefancy    schedule 23.09.2012