|
Witek9002
|
 |
« : 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: 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: 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: 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: 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
|
 |
« 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.
|
 |
« 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  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: 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
|
 |
« Odpowiedz #3 : Luty 14, 2010, 21:41:21 » |
|
Dla shadow2D(...) używam 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ę: // 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.  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.
|
 |
« 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 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 glBindTexture EXT() ?
|
|
|
|
« Ostatnia zmiana: Luty 14, 2010, 22:10:29 wysłane przez Kuba D. »
|
Zapisane
|
|
|
|
|
Witek9002
|
 |
« 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.phpFragment shader: 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: 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: 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
|
 |
« 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
|
 |
« 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
|
 |
« Odpowiedz #8 : Luty 15, 2010, 00:01:12 » |
|
Gdy używam Framebuffera dla SN i po narysowaniu juz WSZYSTKIEGO dopiszę: // 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
|
 |
« 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.
|
 |
« 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
|
 |
« 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ę 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: 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): 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: float GetShadowValue(in sampler2DShadow ShadowMap, vec3 Coords) { return shadow2D(ShadowMap, Coords).w; } na to: 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
|
|
|
|
|