Warsztat - Programowanie gier

Lipiec 30, 2010, 17:27:36 *
Witamy, Gość. Zaloguj się, lub zarejestruj proszę.

Zaloguj się podając nazwę użytkownika, hasło i długość sesji
Aktualności: Warsztat, Regulamin forum, #warsztat, Wiki, FAQ, NoPaste, Mapa
 
   Strona główna   Pomoc Szukaj Zaloguj się Rejestracja  
Strony: [1]
  Drukuj  
Autor Wątek: [GLSL] Problem z shadow mappingiem  (Przeczytany 599 razy)
Witek9002
Full Member
***

wiadomości: 161


Zobacz profil
« : Luty 14, 2010, 15:32:25 »

Witam

Mam problem z shadow mappingiem. Mianowicie, mam parę spotlightów i każdy rzuca cień. Gdy używam w shaderze czegoś takiego dla każdego światła:
Kod:
uniform sampler2D Shadow0;
uniform sampler2D Shadow1;
// itd

float GetShadow0Value(vec3 Coords) // Coords jest w-divided
{
if (texture2D(Shadow0, Coords.xy).r < Coords.z)
return 0.0;
else
return 1.0;
}

to wszystko działa OK. Jednak cienie są poszarpane, a chce mieć miękkie cienie. Więc przerobiłem ten fragment na to:
Kod:
uniform sampler2DShadow Shadow0;
uniform sampler2DShadow Shadow1;
// itd

float GetShadow0Value(vec3 Coords) // Coords jest w-divided
{
return shadow2D(Shadow0, Coords).r;
}

i dodałem w kodzie programu przy tworzeniu shadow mapy:
Kod:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);

Jednak wtedy niektóre cienie znikają. Gdy zostawię tylko jedno światło, to działa, ale przy dwóch już nie. Może ktoś pomóc?

PS. Kod towrzenia Shadow Mappy i Framebuffera:
Kod:
glGenTextures(1, &ShadowMap.DepthTexture);
glBindTextureEXT(GL_TEXTURE_2D, ShadowMap.DepthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
//glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, Size, Size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glBindTextureEXT(GL_TEXTURE_2D, 0);


glGenFramebuffersEXT(1, &ShadowMap.FBO);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowMap.FBO);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, ShadowMap.DepthTexture, 0);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
« Ostatnia zmiana: Luty 14, 2010, 15:35:52 wysłane przez Witek9002 » Zapisane
Witek9002
Full Member
***

wiadomości: 161


Zobacz profil
« Odpowiedz #1 : Luty 14, 2010, 17:35:28 »

Zauważyłem jeszcze jedną dziwną rzecz: gdy światło jest włączone od początku to nic się złego nie dzieje. Natomiast, gdy światło jest przy inicjacji wyłączone, a następnie podczas gry włączone, to znikają niektóre cienie (z wyjątkiem światła, które włączyłem). Wie ktoś co może być przyczyną? W kodzie programu raczej nie ma błędu, bo jak już mówiłem gdy w shaderze użyję "texture2D" to wszystko jest OK.

Podejrzewam, że coś z Framebufferem jest źle...
« Ostatnia zmiana: Luty 14, 2010, 17:42:22 wysłane przez Witek9002 » Zapisane
Kuba D.
Hero Member
*****

wiadomości: 978


Zobacz profil
« Odpowiedz #2 : Luty 14, 2010, 18:08:56 »

Bo musisz się zdecydować czy robisz porównywanie głębi w shaderze czy nie. A nie i tu i tu Wink Tzn jak masz w parametrach tekstury GL_COMPARE_R_TO_TEXTURE to nie używasz shadow2D(...) tylko texture2D(...). A jak masz surową teksturę głębi, przekazujesz ją do shadera i używasz shadow2D() a nie texture2D(...).
Wywal to:
Kod:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
Zapisane
Witek9002
Full Member
***

wiadomości: 161


Zobacz profil
« Odpowiedz #3 : Luty 14, 2010, 21:41:21 »

Dla shadow2D(...) używam
Kod:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);

Bez tego nie ma żadnych cieni.

A teraz ciekawostka:
Gdy wywalę Framebuffer i użyję nieszczęsnego glCopyTexImage2D do kopiowania shadowmapy, to wszystko działa.

I kolejna ciekawostka:
Gdy używam Framebuffera dla SN i po narysowaniu juz WSZYSTKIEGO dopiszę:
Kod:
// NIE WIEM PO CO TO, ALE BEZ TEGO NIE DZIALAJA CIENIE Z FRAMEBUFFEREM
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
for (int i = 0; i<Lights.GetSize(); i++)
{
glBindTextureEXT(GL_TEXTURE_2D, Lights[i]->ShadowMap.DepthTexture);
}
glDisable(GL_TEXTURE_2D);
o dziwo wszystko działa. Niech mi to ktoś wytłumaczy.  Huh

Kombinowałem jeszcze z glFlush i glFinish miejąc nadzieję że pomoże, lecz bezskutecznie.
« Ostatnia zmiana: Luty 14, 2010, 23:40:23 wysłane przez Witek9002 » Zapisane
Kuba D.
Hero Member
*****

wiadomości: 978


Zobacz profil
« Odpowiedz #4 : Luty 14, 2010, 22:03:34 »

Chwila chwila... Ty na pewno wiesz jak to działa/ nie działa ?

1. Tworzenie FBO dla shadowmapy ( zwyczajna depth-tekstura bez żadnych udziwnień w stylu compare_mode itp).
2. bind FBO z shadowmapą dla danego światła, ustawienie macierzy itp, i rendering do niej. ( Dla wydajności color mask na false)
3. unbind FBO.
4. Przy rysowaniu obiektów na których mają być cienie bindujesz shadowmapę jako teksturę, przesyłasz ją do shadera i tu się bawisz z nią.
Jak używasz wielu jednostek teksturujących to może się okazać, że dana shadowmapa jest nie na tej jednostce co powinna. Dlatego wywołujesz
Kod:
glActiveTextureARB(GL_TEXTURE0_ARB);

Poza tym rzuć więcej kodu renderującego bo te kawałki to za mało.
Może po prostu gdzieś jakaś głupota jest i dlatego to wygląda tak jak wygląda.

Btw jestem też ciekaw po co stosujesz glBindTextureEXT() ?
« Ostatnia zmiana: Luty 14, 2010, 22:10:29 wysłane przez Kuba D. » Zapisane
Witek9002
Full Member
***

wiadomości: 161


Zobacz profil
« Odpowiedz #5 : Luty 14, 2010, 22:19:04 »

Robię właśnie tak, jak mówisz. Wzorowałem się na tym: http://www.fabiensanglard.net/shadowmappingPCF/index.php

Fragment shader:
Kod:
float GetShadow0Value(vec4 Coords)
{
float Result = 0.0;

for (float x = -Shadow0PCFsize; x<=Shadow0PCFsize; x += 1.0)
{
for (float y = -Shadow0PCFsize; y<=Shadow0PCFsize; y += 1.0)
{
Result += shadow2DProj(Shadow0, Coords + Coords.w *  vec4(x * ShadowMap0ResInv, y * ShadowMap0ResInv, 0.0, 0.0)).w;
}
}

Result /= (2.0 * Shadow0PCFsize + 1.0) * (2.0 * Shadow0PCFsize + 1.0);
return Result;
}

//podobnie jest dla innych śwateł

Inicjowanie shadow mapy i FBO:
Kod:
glGenTextures(1, &ShadowMap.DepthTexture);
glBindTextureEXT(GL_TEXTURE_2D, ShadowMap.DepthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

//to musi być bo inaczej nie ma ŻADNYCH cieni
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, Size, Size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glBindTextureEXT(GL_TEXTURE_2D, 0);



glGenFramebuffersEXT(1, &ShadowMap.FBO);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowMap.FBO);

glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, ShadowMaps[i].DepthTexture, 0);
//glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ShadowMaps[i].ColorTexture, 0);

//glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

Renderowanie Shadow Mapy:
Kod:
void CCamera::RenderShadow()
{
glViewport(0, 0, Width, Height);

//ustawienie macierzy (oblicznoych wczesniej)
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(ProjMatrix.data);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(ViewMatrix.data);

glColorMask(0, 0, 0, 0);

glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);

//wyczyszczenie framebuffera
glClear(GL_DEPTH_BUFFER_BIT);


glEnableClientState(GL_VERTEX_ARRAY);

...  //renderowanie obiektów po kolei
glDisableClientState(GL_VERTEX_ARRAY);

glColorMask(1, 1, 1, 1);
}

Przed wywołaniem RenderShadow() binduję framebuffer.

Zamiana glBindTextureEXT -> glBindTexture nic nie daje.
« Ostatnia zmiana: Luty 14, 2010, 22:21:24 wysłane przez Witek9002 » Zapisane
_OskaR
Hero Member
*****

wiadomości: 718



Zobacz profil
« Odpowiedz #6 : Luty 14, 2010, 23:17:20 »

Taka moja mała rada - zrób sobie quada na cały ekran, wyrenderuj scenę do tekstury, a potem quada z tą teksturą. Przynajmniej zobaczysz czy depthmapa wygląda poprawnie (możesz sobie walnąć colormapę) - może to ułatwi szukanie błędów.
Zapisane

Prawdziwy programista wiesza się razem ze swoim programem.
Witek9002
Full Member
***

wiadomości: 161


Zobacz profil
« Odpowiedz #7 : Luty 14, 2010, 23:38:59 »

Taka moja mała rada - zrób sobie quada na cały ekran, wyrenderuj scenę do tekstury, a potem quada z tą teksturą. Przynajmniej zobaczysz czy depthmapa wygląda poprawnie (możesz sobie walnąć colormapę) - może to ułatwi szukanie błędów.

Będzie działać - przypominam, że  zbindowanie shadow mapy (nawet bez używania jej) powoduje, że cienie są pojawiają. W 4 poście to napisałem w "I kolejna ciekawostka:".
« Ostatnia zmiana: Luty 14, 2010, 23:41:34 wysłane przez Witek9002 » Zapisane
_OskaR
Hero Member
*****

wiadomości: 718



Zobacz profil
« Odpowiedz #8 : Luty 15, 2010, 00:01:12 »

Gdy używam Framebuffera dla SN i po narysowaniu juz WSZYSTKIEGO dopiszę:
Kod:
// NIE WIEM PO CO TO, ALE BEZ TEGO NIE DZIALAJA CIENIE Z FRAMEBUFFEREM
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
for (int i = 0; i<Lights.GetSize(); i++)
{
glBindTextureEXT(GL_TEXTURE_2D, Lights[i]->ShadowMap.DepthTexture);
}
glDisable(GL_TEXTURE_2D);
A co masz na myśli przez "wszystko"? Może jest tak, że te dane maja wpływ na następną klatkę, a nie aktualną. Dajesz to po czyszczeniu buforów etc. czy przed?
Zapisane

Prawdziwy programista wiesza się razem ze swoim programem.
Witek9002
Full Member
***

wiadomości: 161


Zobacz profil
« Odpowiedz #9 : Luty 15, 2010, 01:30:07 »

Daję to tuż przed SwapBuffers. Nie może to mieć wpływu na kolejną klatkę, bo i tak "nadbindowuję" nowymi teksturami. Poza tym tu używat GL_TEXTURE0, natomias shadowmapy przy rysowaniu sceny binduję do GL_TEXTURE4-9
Zapisane
Kuba D.
Hero Member
*****

wiadomości: 978


Zobacz profil
« Odpowiedz #10 : Luty 15, 2010, 01:36:20 »

A karta obsługuje powyżej ośmiu jednostek teksturujących ? Zakładam, że jak je do shadera przekazujesz to i numerek jednostki też podajesz do shadera prawidłowy dla TEXTURE0 - 0, TEXTURE5 - 5 itd, prawda ?

EDIT: A czy w vs liczysz coordy dla każdej shadowmapy osobno ?
I jeszcze raz zaznaczę, że te wszystkie COMPARE wywal z kodu bo jest to niepotrzebne i bez sensu na dodatek. Jak cienie się nie wyświetlają bez tego to znaczy, że masz skopane shadery.
Spróbuj najpierw zrobić cień dla jednego światła, wyświetlić go i przetestować, potem dodawaj kolejne światła aż do momentu jak przestanie działać i wtedy trzeba zobaczyć co się spieprzyło po drodze.
« Ostatnia zmiana: Luty 15, 2010, 01:44:49 wysłane przez Kuba D. » Zapisane
Witek9002
Full Member
***

wiadomości: 161


Zobacz profil
« Odpowiedz #11 : Luty 15, 2010, 17:44:22 »

Karta obsługuje 16 jednostek teksturujących (ATI Radeon HD 4850). Numerki tekstury przesyłam do shadera proprzez glUniform1i(...). Ja muszę użyć shadow2D(...) i gdy wywalę
Kod:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
To cienie są nieprawidłowe (ledwo widoczne). Zauważyłem też, że gdy mam więcej świateł na scenie, to tylko 1 cień jest prawidłowy, reszta jest słabo widoczna - zupełenie tak jak by dla pozostałych shadow map ten kod powyżej nie został zastosowany (mimo że wywołuję go dla każdej shadowmapy). Pozatym sprawdziłem wszystko i nie znalazłem błędu w kodzie programu.


Vertex Shader:
Kod:
varying vec4 pos;
varying vec3 normal;

uniform ivec4 UseTexture;

void main()
{
gl_Position = ftransform();
pos = gl_ModelViewMatrix * gl_Vertex;
normal =  normalize(gl_NormalMatrix * gl_Normal);

if (UseTexture[1]==1)
{
gl_TexCoord[1].xyz = normalize(gl_NormalMatrix * gl_MultiTexCoord1.xyz);
gl_TexCoord[2].xyz = cross(normal, gl_TexCoord[1].xyz);
}

gl_TexCoord[0] = gl_MultiTexCoord0;
}


Pełny Fragment Shader (skrócony, wcześniej był dłuższy):
Kod:
varying vec4 pos;
varying vec3 normal;

uniform ivec4 UseTexture;


uniform sampler2D Texture1;
uniform sampler2D TextureNorm;
uniform sampler2D TextureSpec;

uniform sampler2DShadow Shadow0;
uniform sampler2DShadow Shadow1;


float GetShadowValue(in sampler2DShadow ShadowMap, vec3 Coords)
{
return shadow2D(ShadowMap, Coords).w;
}

void main()

vec4 color; 
color.a = 1.0;

vec4 TexColor;
if (UseTexture[0]==1)
{
TexColor = texture2D(Texture1, gl_TexCoord[0].st);
}



vec3 diff_color = gl_LightModel.ambient.rgb; 
vec3 spec_color = vec3(0.0f, 0.0f, 0.0f); 
vec3 geom_norm = normalize(normal);
vec3 real_norm;

vec4 LightCoordOrg;
vec3 LightCoord;


//if (UseTexture[1]==1)   
//{
// real_norm = normalize(vec3(mat3(normalize(gl_TexCoord[1].xyz), normalize(gl_TexCoord[2].xyz), geom_norm) * (texture2D (TextureNorm, gl_TexCoord[0].st).xyz * 2.0f - 1.0f))); 
//}
//else 
//{
real_norm = geom_norm; 
//}
 
vec3 light_vec;
float light_dist, NdotHV, rNdotL, att, dist, ShadowValue;
dist = length(pos.xyz);



// SPOT LIGHTS
 
//if (gl_LightSource[0].diffuse.a > 0.0f)
  //{

LightCoordOrg = gl_TextureMatrix[2] * pos;
LightCoord = LightCoordOrg.xyz / LightCoordOrg.w;

if (LightCoord.x<1.0f && LightCoord.x>0.0f && LightCoord.y<1.0f && LightCoord.y>0.0f && LightCoord.z<1.0f && LightCoord.z>0.0f)
{

    light_vec = gl_LightSource[0].position.xyz - pos.xyz;
    light_dist = length(light_vec);
    light_vec /= light_dist;


ShadowValue = GetShadowValue(Shadow0, LightCoord);


          rNdotL = max(0.0f, dot(real_norm, light_vec));
          diff_color += rNdotL  * ShadowValue;
}
//}
 
 


//if (gl_LightSource[1].diffuse.a > 0.0f)
  //{
LightCoordOrg = gl_TextureMatrix[3] * pos;
LightCoord = LightCoordOrg.xyz / LightCoordOrg.w;

if (LightCoord.x<1.0f && LightCoord.x>0.0f && LightCoord.y<1.0f && LightCoord.y>0.0f && LightCoord.z<1.0f && LightCoord.z>0.0f)
{

    light_vec = gl_LightSource[1].position.xyz - pos.xyz;
    light_dist = length(light_vec);
    light_vec /= light_dist;
   
ShadowValue = GetShadowValue(Shadow1, LightCoord);

rNdotL = max(0.0f, dot(real_norm, light_vec));
 
          diff_color += rNdotL  * ShadowValue;

}
//}



color.rgb = diff_color * gl_FrontMaterial.diffuse.rgb;
 
 
if (UseTexture[0]==1)
{
color.rgb *= TexColor.rgb;
}
 

gl_FragColor = color; 
}


Przypominam, że zamiana sampler2DShadow na sampler2D oraz zamiana tego:
Kod:
float GetShadowValue(in sampler2DShadow ShadowMap, vec3 Coords)
{
return shadow2D(ShadowMap, Coords).w;
}
na to:
Kod:
float GetShadowValue(in sampler2D ShadowMap, vec3 Coords)
{
if (texture2D(ShadowMap), Coords.xy).r < Coords.z)
return 0.0;
else
return 1.0;
}
powoduje że wszystko działa.

Edit: Tutaj http://developer.nvidia.com/forums/index.php?showtopic=2782 mają też podobny problem, tylko że w Cg i nic nie jest wytłumaczone.
« Ostatnia zmiana: Luty 15, 2010, 19:18:56 wysłane przez Witek9002 » Zapisane
Strony: [1]
  Drukuj  
 
Skocz do:  

Hosting: Polska Strefa - Ogłoszenia
Powered by SMF 1.1.7 | SMF © 2006, Simple Machines LLC