IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

OpenGL Discussion :

Problème avec gl_FragCoord


Sujet :

OpenGL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Invité
    Invité(e)
    Par défaut Problème avec gl_FragCoord
    Salut, j'essaye d'effectuer un rendu par pixel de la lumière à l'aide d'une normal map.

    Les composantes rgb de la normale map contiennent les composantes x, y et z des normales (vecteurs perpendiculaires à mes tiles) et la composante w contient la hauteur du fragment. (que je défini moi même)

    J'envoie la position de la lumière : x et y contiennent la position de la lumière, z la hauteur de la lumière et j'envoie dans la composante w le rayon de la lumière, j'envoie donc la lumière comme ceci à mon fragment shader :

    perPixLightingShader->setParameter("uLightPos", el->getCenter().x, el->getCenter().y, el->getCenter().z, el->getSize().x);
    perPixLightingShader->setParameter("lightColor", el->getColor().r, el->getColor().g,el->getColor().b,el->getColor().a);

    Je transforme ensuite la position de la lumière dans le vertex shader pour l'avoir en coordonnées écran dans le fragment
    shader :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    "#version 130 \n"
            "uniform vec4 uLightPos;"
            "out vec4 lightPos;"
               "void main () {"
                    "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
                    "gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;"
                    "gl_FrontColor = gl_Color;"
                    "lightPos = gl_ModelViewMatrix * uLightPos;"
                    "lightPos.w = uLightPos.w;"
            "}";

    Le problème survient dans le fragment shader, la distance entre la position de la lumière et le pixel courant est toujours > au rayon et je ne comprends vraiment pas pourquoi :
    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    const std::string perPixLightingFragmentShader =
            "#version 130 \n"
            "uniform sampler2D normalMap;"
            "uniform vec3 resolution;"
            "uniform vec4 lightColor;"
            "uniform sampler2D lightMap;"
            "in vec4 lightPos;"
            "void main () { "
                "vec2 position = ( gl_FragCoord.xy / resolution.xy );"
                "vec4 bump = texture2D(normalMap, position);"
                "vec3 pixPos = vec3 (gl_FragCoord.x, gl_FragCoord.y, bump.a);"
                "vec4 lightMapColor = texture2D(lightMap, position);"
                "float ray = lightPos.a;"
                "if (gl_FragCoord.z >= bump.a && distance(lightPos.xyz, pixPos) <= ray) {"
                    "vec3 vertexToLight = lightPos.xyz - pixPos;"
                    "float attenuation = 1.0f - (length(vertexToLight) / ray);"
                    "if (bump.x != 0 || bump.y != 0 || bump.z != 0) {"
                        "vec3 dirToLight = normalize(vertexToLight.xyz);"
                        "float nDotl = dot (dirToLight, bump.xzy);"
                        "attenuation *= nDotl;"
                    "}"
                    "gl_FragColor = lightColor * max(0.0f, attenuation);"
                "} else {"
                    "gl_FragColor = lightMapColor;"
                "}"
            "}";

    Je pense que gl_FragCoord et lightPos ne sont pas dans le même repère, pourtant gl_FragCoord devrait donner la position du fragment par rapport au coin supérieur gauche de la fenêtre non ?
    Dernière modification par LittleWhite ; 26/07/2014 à 11h06. Motif: Tag

  2. #2
    Expert confirmé

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 033
    Billets dans le blog
    12
    Par défaut
    Salut !

    En lisant la doc, je suis tombé sur ceci :
    By default, gl_FragCoord assumes a lower-left origin for window coordinates and assumes pixel centers are located at half-pixel centers.
    Donc position relative au coin inférieur gauche de la fenêtre.
    Cela ne pourrait-il pas venir de là ?

    EDIT:

    Dans la même page de doc (ici), il est dit que tu peux redéclarer gl_FragCoord avec les attributs qui t'intéressent :
    he origin of gl_FragCoord may be changed by redeclaring gl_FragCoord with the origin_upper_left identifier.
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  3. #3
    Invité
    Invité(e)
    Par défaut
    J'ai fais plusieurs choses, la première c'est de faire une fonction qui se charge de passer des coordonnées mondes en coordonnées pixel :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     states.shader = perPixLightingShader;
            states.blendMode = sf::BlendAdd;
            for (unsigned int i = 0; i < lights.size(); i++) {
                EntityLight* el = static_cast<EntityLight*> (lights[i]);
                Vec3f center = frcm->getWindow().mapCoordsToPixel(el->getCenter());
                perPixLightingShader->setParameter("lightPos", center.x, center.y, center.z, el->getSize().x * 0.5f);
                perPixLightingShader->setParameter("lightColor", el->getColor().r, el->getColor().g,el->getColor().b,el->getColor().a);
                lightMap->draw(*el, states);
            }

    Ainsi je passe directement la position de la lumière à mon fragment shader, sans devoir faire des transformations dans le vertex shader sans trop savoir.

    J'ai le x et le z de la lumière qui varient dans le fragment shader, le y reste constant car c'est la hauteur de la lumière (qui correspond au centre en y de la lumière dans mon cas)
    Donc plus on s'éloigne du centre de la lumière, plus la distance entre le centre de la lumière et le pixel sera grand, et donc, plus il y aura atténuation.
    En gros c'est ce que je veux faire.

    Les normales pointent toutes vers le haut (en 0, 1, 0) sauf sur le bord des tiles évidement.

    Ainsi ça me donnerai un éclairage plus atténué sur les bords.

    J'ai essayé de changer et de prendre le coin supérieur gauche tout comme moi je le fais mais ça ne compile pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    layout(origin_upper_left) in vec4 gl_Fragcoord;
    J'ai alors eu l'idée d'inverser la coordonnées en y de la lumière pour qu'elle soient dans l'autre sens en y :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "vec3 nLightPos = vec3 (lightPos.x, lightPos.z, resolution.y - lightPos.y);"

    Mais cela ne fonctionne pas, voici le shader complet :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    "#version 130 \n"
            "uniform sampler2D normalMap;"
            "uniform vec3 resolution;"
            "uniform vec4 lightColor;"
            "uniform sampler2D lightMap;"
            "uniform vec4 lightPos;"
            "void main () { "
                "vec2 position = ( gl_FragCoord.xy / resolution.xy );"
                "vec4 bump = texture2D(normalMap, position);"
                "vec3 pixPos = vec3 (gl_FragCoord.x, bump.a * resolution.z, gl_FragCoord.y);"
                "vec4 lightMapColor = texture2D(lightMap, position);"
                "vec3 nLightPos = vec3 (lightPos.x, lightPos.z, resolution.y - lightPos.y);"
                "float ray = lightPos.w;"
                "if (gl_FragCoord.z >= bump.a && distance(nLightPos, pixPos) <= ray) {"
                    "vec3 vertexToLight = nLightPos - pixPos;"
                    "float attenuation = 1.0f - (length(vertexToLight) / ray);"
                    "if (bump.x != 0 || bump.y != 0 || bump.z != 0) {"
                        "vec3 dirToLight = normalize(vertexToLight.xyz);"
                        "float nDotl = dot (dirToLight, bump.xzy);"
                        "attenuation *= nDotl;"
                    "}"
                    "gl_FragColor = lightColor * max(0.0f, attenuation);"
                "} else {"
                    "gl_FragColor = lightMapColor;"
                "}"
            "}";

    Le fait est que je n'ai pas d'éclairage. :/

  4. #4
    Invité
    Invité(e)
    Par défaut
    En retirant le if ça fonctionne mais je n'ai pas d'atténuation, à croire que tout les fragments sont à la même position. (par rapport au centre de la lumière)
    .....

    Donc c'est juste la distance entre le fragment courant et le centre de la lumière qui n'est pas bonne et je vois pas pourquoi.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bon j'ai essayé cela (en prenant l'inverse de la matrice de projection pour dénormaliser le z) :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    const std::string perPixLightingVertexShader =
            "#version 130 \n"
            "out mat4 invProjMat;"
            "void main () {"
                    "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
                    "gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;"
                    "gl_FrontColor = gl_Color;"
                    "invProjMat = inverse(gl_ProjectionMatrix);"
            "}";
            const std::string perPixLightingFragmentShader =
            "#version 130 \n"
            "uniform sampler2D normalMap;"
            "uniform vec3 resolution;"
            "uniform vec4 lightColor;"
            "uniform sampler2D lightMap;"
            "uniform vec4 lightPos;"
            "in mat4 invProjMat;"
            "void main () { "
                "vec2 position = ( gl_FragCoord.xy / resolution.xy );"
                "vec4 bump = texture2D(normalMap, position);"
                "vec4 cBump = invProjMat * vec4(0, 0, bump.w, 0);"
                "vec3 pixPos = vec3 (gl_FragCoord.x, cBump.z, resolution.y - gl_FragCoord.y);"
                "vec4 lightMapColor = texture2D(lightMap, position);"
                "vec3 nLightPos = vec3 (lightPos.x, lightPos.z, lightPos.y);"
                "float radius = lightPos.w;"
                "if (gl_FragCoord.z >= bump.w && distance(pixPos, nLightPos) <= radius) {"
                    "vec3 vertexToLight = nLightPos - pixPos;"
                    "float attenuation = 1.0f - (length(vertexToLight) / radius);"
                    "if (bump.x != 0 || bump.y != 0 || bump.z != 0) {"
                        "vec3 dirToLight = normalize(vertexToLight.xyz);"
                        "float nDotl = dot (dirToLight, bump.xzy);"
                        "attenuation *= nDotl;"
                    "}"
                    "gl_FragColor = lightColor * max(0.0f, attenuation);"
                "} else {"
                    "gl_FragColor = lightMapColor;"
                "}"
            "}";

    Ca marche déjà mieux à part que la lumière disparaît trop vite de l'écran, comme si elle était trop vite près du "near plane" et du "far plane".

  6. #6
    Invité
    Invité(e)
    Par défaut
    J'ai essayé ça pour avoir le bon pixel sur la normal map et la lightmap:

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    "vec2 position = (gl_FragCoord.xy / resolution.xy);"
    "position.y = resolution.y - position.y;"
    "vec4 bump = texture2D(normalMap, position);"
    "vec4 cBump = inverse(projMat) * vec4(0, 0, bump.w, 0);"
    "vec3 pixPos = vec3 (gl_FragCoord.x, cBump.z, resolution.y - gl_FragCoord.y);"
    "vec4 lightMapColor = texture2D(lightMap, position);"
    "vec3 nLightPos = vec3 (lightPos.x, lightPos.z, lightPos.y);"
    "float radius = lightPos.w;"

    Mais ça ne marche pas, le problème vient vraiment du fait que j'utilise le coin en haut à gauche pour dessiner la lumière comme référence, hors que OpenGL utilise le coin en bas à gauche comme référence pour la position des fragments.

    Etant donné que les layouts ne fonctionnent pas avec la version 130 du langage GLSL, j'ai installé mesa 10.3 qui supporte le GLSL 330 sur ubuntu mais il ne veut pas activer un context GLSL 3. :/
    Dernière modification par LittleWhite ; 12/07/2014 à 14h16.

Discussions similaires

  1. VC++ Direct3D8, problème avec LPD3DXFONT et LPD3DTEXTURE8
    Par Magus (Dave) dans le forum DirectX
    Réponses: 3
    Dernier message: 03/08/2002, 11h10
  2. Problème avec [b]struct[/b]
    Par Bouziane Abderraouf dans le forum CORBA
    Réponses: 2
    Dernier message: 17/07/2002, 10h25
  3. Problème avec le type 'Corba::Any_out'
    Par Steven dans le forum CORBA
    Réponses: 2
    Dernier message: 14/07/2002, 18h48
  4. Problème avec la mémoire virtuelle
    Par Anonymous dans le forum CORBA
    Réponses: 13
    Dernier message: 16/04/2002, 16h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo