Voilà cela fait quelques jours que je me bats avec les ombres dans Nazara, j'ai enfin réussi à en obtenir mais elles ne sont pas correctes.
Il y a divers bugs, notamment le fait que l'ombre ne semble pas vraiment correspondre, disparaît parfois, que le frustum de shadow mapping est plus petit que la lumière produite par le spotlight (et là j'avoue je suis toujours un peu wtf).
Voici une vidéo pour montrer tout ça (une image valant mille mots, cette vidéo vaut 3300 000 mots ! ):
http://youtu.be/B-GXQSSr7_A
Alors côté implémentation, c'est du shadow mapping bête et méchant pour l'instant, avec la génération de la shadow map ici:
Lors du rendu normal, les lumières sont ajoutées à la RenderQueue avec la shadow map et les matrices qui vont avec (oui il y a duplication, de toute façon mon objectif est surtout d'avoir un truc qui marche là ):
Voilà, tout ceci donne le résultat en vidéo, je donne aussi le code responsable du calcul d'éclairage (j'ai renommé quelques variables pour rendre ça plus compréhensible):
case LIGHT_SPOT:
{
vec3 lightDir = LightPos - vWorldPos;
float lightDirLength = length(lightDir);
lightDir /= lightDirLength; // Normalisation
float att = max(LightAttenuation - LightInvRadius*lightDirLength, 0.0);
// Ambient
lightAmbient += att * LightColor * LightAmbientFactor * (MaterialAmbient.rgb + SceneAmbient.rgb);
// Modification de l'atténuation pour gérer le spot
float curAngle = dot(LightDirection, -lightDir);
float innerMinusOuterAngle = LightInnerAngle - LightOuterAngle; // Ce sont des cosinus
att *= max((curAngle - LightOuterAngle) / innerMinusOuterAngle, 0.0);
// Diffuse
float lambert = max(dot(normal, lightDir), 0.0);
lightDiffuse += att * lambert * LightColor * LightDiffuseFactor;
// Specular
vec3 reflection = reflect(-lightDir, normal);
float specularFactor = max(dot(reflection, eyeVec), 0.0);
specularFactor = pow(specularFactor, MaterialShininess);
lightSpecular += att * specularFactor * LightColor;
break;
}
Si quelqu'un pouvait me donner un coup de main pour le coup, ça m'arrangerait beaucoup, ce problème va me rendre fou.
Je poste aussi le code, si quelqu'un veut voir quelle fonction fait quoi:
Dépôt Github (Branche shadow sans une partie du code plus haut).
Matrix4.inl (algorithme de génération des matrices).
Pour le reste (RTT) c'est basiquement de l'OpenGL (m_shadowRT.AttachTexture fait appel à glFrameBufferTexture2D par exemple), voilà.
Si besoin de plus d'information, aucun souci n'hésitez pas à demander
Votre texture de profondeur semble correcte. Du coup, je ne sais pas trop. Dans les bogues que j'ai vu dans la vidéo, cela me semble être causé par le test que vous faites, qui est trop stricte (?).
En fait, si j'affiche le frustum et le cone de projection, on se rend très vite compte qu'il y a un problème de ce côté-là aussi:
Il faut que je double l'angle que j'envoie pour construire le frustum si je veux que ça corresponde, mais évidemment ça ne corrige pas les ombres (ou alors je corrige mal ?).
Quant au bias, si je l'enlève ça ne corrige malheureusement pas le problème :-/
C'est ultra étrange. Ça voudrait dire que dans ce cas, le depthbuffer utilisé par la shadow map, donne des valeurs à un.
J'oserai croire que le souci est un souci de configuration du depthbuffer/depthtest. Pour l'instant, je n'arrive pas du tout à saisir le souci. Vous parlez du faceculling ? Mais la face est tout de même affichée ? N'est ce pas le backface culling ?
Jusque là j'ai relu le code 3 fois mais je vois pas le problème... Je passe juste rapidement pour dire que c'est bien normal que le bias réduise et décale de 0.5, c'est pour passer des coordonnées de l'écran [-1;1] à celles d'une texture [0;1].
Mais sinon t'as essayé d'enlever quelques uns de tes tests dans le fragment buffer ? Ils m'ont pas l'air incohérents mais pas nécessaires non plus, dans le doute... Tiens et puis le filtre bilinéaire sur la shadow map ça change rien non plus, je sais pas si c'est un oubli de ta part.
C'est quand même assez bizarre que l'ombre ait l'air de passer sous le sol comme ça, vu que ton FBO à l'air correct. Après faut voir aussi si t'utilises bien la même matrice pour le FBO et le rendu ou ce genre de choses. Si comme le suggère LittleWhite c'est un problème de Depth Buffer tu peux aussi faire ton propre rendu de profondeur avec une texture 32 bits.
Sinon t'as essayé avec une lumière type unidirectionnelle (genre soleil, je sais plus si c'est le terme) ? Ça sera peut être plus facile de dire à quel niveau est le problème ?
Voilà après tu t'y connais probablement mieux que moi donc pas totalement sûr de pouvoir aider beaucoup plus.
C'est ultra étrange. Ça voudrait dire que dans ce cas, le depthbuffer utilisé par la shadow map, donne des valeurs à un.
J'oserai croire que le souci est un souci de configuration du depthbuffer/depthtest. Pour l'instant, je n'arrive pas du tout à saisir le souci. Vous parlez du faceculling ? Mais la face est tout de même affichée ? N'est ce pas le backface culling ?
Je crois avoir compris, en fait l'ombre est correcte mais elle est décalée, c'est je pense le seul problème de mon implémentation actuelle. (Ou alors pas du tout parce que c'est normalement du point de vue caméra, la forme est la même, wtf).
Donc oui, en temps normal je désactive le face culling pour la génération du depth buffer pour éviter ça.
LeParp a écrit:
Mais sinon t'as essayé d'enlever quelques uns de tes tests dans le fragment buffer ? Ils m'ont pas l'air incohérents mais pas nécessaires non plus, dans le doute... Tiens et puis le filtre bilinéaire sur la shadow map ça change rien non plus, je sais pas si c'est un oubli de ta part.
J'ai enlevé les tests de coordonnées, depuis que j'ai corrigé le bug de projection ils ne servent en effet plus à rien.
En revanche, à la base le code était bien plus optimisé que ça, j'ai enlevé optimisation sur optimisation en espérant que ça fonctionne, pourquoi le filtre bilinéaire ne fonctionnerait pas au juste ? À cause du format de la texture ?
LeParp a écrit:
Si comme le suggère LittleWhite c'est un problème de Depth Buffer tu peux aussi faire ton propre rendu de profondeur avec une texture 32 bits.
Je suis déjà en 24 bits et à une telle distance je doute vraiment que ce soit ça le problème, mais j'essaierai.
(Mais sinon, c'est déjà "mon propre rendu de profondeur" hein).
LeParp a écrit:
Sinon t'as essayé avec une lumière type unidirectionnelle (genre soleil, je sais plus si c'est le terme) ? Ça sera peut être plus facile de dire à quel niveau est le problème ?
À tester, de ce que j'en sais c'est pas forcément plus facile à mettre en place, mais ça élimine la perspective donc ça pourrait aiguiller sur le problème, j'essaierai ça dès que possible.
Si vous avez des idées à me faire tester n'hésitez pas
pourquoi le filtre bilinéaire ne fonctionnerait pas au juste ?
C'est pas que ça fonctionne pas, c'est juste que tu fais un test binaire au final donc c'est pas utile (sauf peut être dans des cas extrêmes). D'ailleurs c'est tout l'intérêt des VSMde pouvoir "être linéaire" et faire de l'interpolation.
Lynix a écrit:
Je suis déjà en 24 bits et à une telle distance je doute vraiment que ce soit ça le problème, mais j'essaierai.
(Mais sinon, c'est déjà "mon propre rendu de profondeur" hein).
C'était pas forcé. Mais oui effectivement je doute que ça change quelque chose pour le coup.
Merci LeParp, pour le rappel/l'explication sur le bias.
@Lynix : je crois deviner le problème. C'est que lors de l'écriture dans la shadowmap, il y a une face qui n'est pas écrite, car elle n'est pas dessiné (la face arrière). Par contre, il faut comprendre pourquoi la face avant n'est pas dessinée (je me trompe peut être d'ordre dans les faces). êtes vous sur que vous avez la même configuration de faceculling lors du rendu de la scène à l'écran, et lots du rendu de la scène dans la shadowmap ?
De plus, pouvez vous nous montrer le shader écrivant dans la shadowmap. Il y a peut être un test encore un peu trop stricte ?
Note : faire des tests (et donc des embranchements) dans les shaders, ce n'est pas super conseillé en terme de performances. Notamment car les pixel shader sont exécutés en parallèle et que l'optimisation est que c'est rapide car ils sont sensés faire toujours la même chose pour chaque pixel. L'embranchement viendra contredire cette hypothèse. J'espère que j'ai été clair :aie:
pourquoi le filtre bilinéaire ne fonctionnerait pas au juste ?
C'est pas que ça fonctionne pas, c'est juste que tu fais un test binaire au final donc c'est pas utile (sauf peut être dans des cas extrêmes).
Ce n'est pas parce que le test est binaire que les valeurs testées elles ne sont pas interpolées, d'ailleurs le filtre bilinéaire permet ici d'adoucir les ombres (j'ai comparé)
LittleWhite a écrit:
@Lynix : je crois deviner le problème. C'est que lors de l'écriture dans la shadowmap, il y a une face qui n'est pas écrite, car elle n'est pas dessiné (la face arrière). Par contre, il faut comprendre pourquoi la face avant n'est pas dessinée (je me trompe peut être d'ordre dans les faces). êtes vous sur que vous avez la même configuration de faceculling lors du rendu de la scène à l'écran, et lots du rendu de la scène dans la shadowmap ?
Ah non, le faceculling doit être différent entre le rendu de la scène (backface culling) et le rendu de la shadow map (frontface culling).
Voici une comparaison entre le front culling et le back culling (avec le depth buffer l'ombre générée), les deux screenshots sont pris avec exactement le même angle de vue (pour comparer).
Pas de test, absolument rien n'est effectué de spécial.
LittleWhite a écrit:
Note : faire des tests (et donc des embranchements) dans les shaders, ce n'est pas super conseillé en terme de performances. Notamment car les pixel shader sont exécutés en parallèle et que l'optimisation est que c'est rapide car ils sont sensés faire toujours la même chose pour chaque pixel. L'embranchement viendra contredire cette hypothèse. J'espère que j'ai été clair :aie:
Je suis parfaitement au courant
Mais comme je l'ai dit, mon but premier est d'abord une implémentation fonctionnelle, et l'optimisation uniquement par la suite.
J'ai effectué plusieurs tests, notamment augmenter la profondeur du depth buffer, ou virer le bias du test de profondeur, rien n'y fait.
Je commence à me dire que le problème viendrait plus de ma matrice de projection:
template<typename T>
NzMatrix4<T>& NzMatrix4<T>::MakeViewMatrix(const NzVector3<T>& translation, const NzQuaternion<T>& rotation)
{
// Une matrice de vue doit appliquer une transformation opposée à la matrice "monde"
NzQuaternion<T> invRot = rotation.GetConjugate(); // Inverse de la rotation
return MakeTransform(-(invRot*translation), invRot);
}
Ces deux matrices sont également utilisées lors du rendu, donc ça serait étonnant, mais sait-on jamais.
Le face culling (et non pas l'object culling) doit l'être, pour éviter le self-shadowing.
fabien sanglar a écrit:
A good technique to reduce self-shadowing is to cull front facing polygons during the shadowmap rendition step, using glCullFace(GL_FRONT) and switch back to glCullFace(GL_BACK) during the second step. Here is the result:
Par contre, avec vos deux nouvelles captures, je ne vois pas du tout quoi en tirer. Les deux ont un résultat faux ?
Oui, et en fait je me suis rendu compte que c'est extrêmement difficile à voir sur un écran non-calibré/pas très lumineux.
Dans les deux cas on se rend bien compte que la forme est la même, juste que la profondeur change (ce qui est logique), mais que la profondeur du cube est bien supérieure (plus foncée) que celle du sol, ça ne devrait donc pas se produire, le problème doit donc être au niveau du test, ou en tout cas des valeurs testées, je vais regarder du côté de la multiplication matricielle dans le VS.
LittleWhite a écrit:
Faites vous du débogage avec gDEBugger (ou autre) ? Notamment pour inspecter les différentes étapes du rendu.
Non, je ne vois pas ce que ça m'apporterait ici étant donné que je peux voir directement la depth-map et le résultat aussi.
LittleWhite a écrit:
Si la matrice de projection est fausse, cela va se voir dans le cibles de rendu, non ?
En effet ça aurait dû se voir depuis longtemps si c'était ça, mais bon, à ce stade je ne sais plus vraiment quoi penser.
C'est dans ce cas là, que je me demande ce que contient la shadow map. En effet, il manque un morceau d'ombre et pour moi, cela veut dire qu'elle n'est pas écrit dans la shadowmap. Pouvez-vous confirmer que la shadowmap est correct ou pas, dans un tel cas ?
Peut être vous avez une mauvaise configuration du RTT et que votre depthbuffer que vous utilisez est un ancien depthbuffer (???).
(En vérifiant l'état de la shadowmap, on saura si le problème vient de 1) avant la génération de la shadowmap, 2) après la génération (donc lors de l'application)).
Petite update, si je cast l'ombre en l'air, j'obtiens ça:
Ce qui est parfaitement correct.
Par contre, si je mets le sol au niveau du cube:
Il y aurait donc vraiment un défaut au niveau du test.
LittleWhite a écrit:
C'est dans ce cas là, que je me demande ce que contient la shadow map. En effet, il manque un morceau d'ombre et pour moi, cela veut dire qu'elle n'est pas écrit dans la shadowmap. Pouvez-vous confirmer que la shadowmap est correct ou pas, dans un tel cas ?
Peut être vous avez une mauvaise configuration du RTT et que votre depthbuffer que vous utilisez est un ancien depthbuffer (???).
(En vérifiant l'état de la shadowmap, on saura si le problème vient de 1) avant la génération de la shadowmap, 2) après la génération (donc lors de l'application)).
Non la shadow map est correctement générée (je la vois tout le temps, c'est le carré blanc à côté de la source de lumière), ma pause vient de se finir donc je posterai des images détaillées de la shadow map (en boostant un peu) s'il le faut ce soir.
C'est très visible sur les deux derniers, l'ombre est plus correcte avec un zFar plus faible, ça ressemble vraiment à un problème de précision (mais comme le depth buffer apparaît de façon visible sur la seconde image, on voit bien que la précision est correcte à ce niveau, non ?).
Si quelqu'un sait où se trouve le problème, moi je commence un peu à désespérer
J'ai aussi posté le problème sur Stackoverflow, il se produit sur toutes les configurations testées, il y a quelque chose qui m'échappe mais je ne sais vraiment pas quoi..
Le bias ne sert-il pas aussi à éviter le self-shadowing ? Ce n'est pas simplement le culling + bias qui fait que lorsque tu rapproches trop la surface qui cast et celle qui reçoit l'ombre disparaît ?
Le bias ne sert-il pas aussi à éviter le self-shadowing ? Ce n'est pas simplement le culling + bias qui fait que lorsque tu rapproches trop la surface qui cast et celle qui reçoit l'ombre disparaît ?
Le bias sert à éviter le "moire pattern" (je viens de me lever donc je dis peut-être des conneries), mais même si je l'enlève le résultat ne bouge pas d'un poil :-/
Est ce que ce n'est pas simplement que tu n'as pas la précision nécessaire avec un frumstrum de cette taille pour détecter la différence de distance entre la surface d'émission et celle de réception ? Dans ce cas soit tu prends un zFar = 100 soit abandonne le front culling ?
Si il s'agit effectivement d'un problème de précision tu peux aussi distribuer la profondeur sur les différents composantes de ta shadow maps et la reconstituer au moment du test.
EDIT : En fait ça me fait penser à un cas extrême de Peter panning, qui se résoud en n'ayant que des objets épais dans la scène et en ne faisant pas de front culling. Et puis je dois avouer que je ne sais pas vraiment pourquoi tu veux éviter le self-shadowing, le bias suffit normalement à éviter le seul problème dont il est responsable...
Après vérification, ça ressemble quand même beaucoup à du peter panning (source) :
Tu peux toujours enlever le bias en plus de ce que tu as déjà fais pour être sûr que ça ne soit pas ça, même si tu auras du coup du shadow acne (si ça marche il suffira de régler le bias !).
Au passage, je parlais d'un truc de ce genre pour distribuer la précision (c'est du hlsl, source) :
// Where to split the value. 8 bits works well for most situations.
Que je sache, le bug dont tu me parles est un décalage de l'ombre, or moi elle n'est pas décalée, elle est coupée (ça se voit particulièrement sur la dernière vidéo).
En plus, j'ai déjà viré le bias du shader, ça n'a eu aucun effet. Ce truc va me rendre fou.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)