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

DirectX Discussion :

[Direct3D] Projection de texture


Sujet :

DirectX

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2002
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 18
    Points : 13
    Points
    13
    Par défaut [Direct3D] Projection de texture
    Salut,

    Je suis en train d'essayer de projeter une texture sur une scène avec un shader. J'ai lu des tas de choses sur le sujet, je pense avoir compris comment ça fonctionne mais je n'arrive pas à obtenir un bon résultat. Voilà ce que je fais :

    1. Calcul de la matrice T transformant les coordonnées d'un vertex V de world space en light clip space :
    T = L-1 * PL

    L-1 est la matrice qui permet de passer de world space à light space.
    PL est la matrice de projection de la light.

    2. Je multiplie mon vertex (en world) par cette matrice T et j'obtiens mon vertex en light clip space :
    V' = V*T
    Normalement ici j'ai :
    -V'.w < V'.x < V'.w
    -V'.w < V'.y < V'.w
    0 < V'.z < V'.w

    3. Je procède à la "division de perspective" pour passer en Normalized Device Coordinates :
    V' /= V'.w
    Maintenant j'ai :
    -1.0 < V'.x < 1.0
    -1.0 < V'.y < 1.0
    0 < V'.z < 1.0

    4. Je multiplie enfin V' par la matrice mappant les Normalized Device Coords en coords de texture (entre 0 et 1) :
    B = {
    { 0.5, 0.0, 0.0, 0.0 }
    { 0.0, -0.5, 0.0, 0.0 }
    { 0.0, 0.0, 1.0, 0.0 }
    { 0.5, 0.5, 0.0, 1.0 } }

    V' *= B
    Maintenant j'ai :
    0.0 < V'.x < 1.0
    0.0 < V'.y < 1.0
    0.0 < V'.z < 1.0
    qui sont mes coordonnées de texture.

    Voilà pour ma méthode. Ca a l'air de fonctionner pour une projection orthographique, mais dès que j'utilise une projection en perspective, la texture projeté est déformée et apparait en dehors du frustum de projection.

    Voilà la partie du vertex shader importante :
    Code : 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
    40
    41
    42
     
    // matrice permettant de passer des Normalized Device Coordinates
    // en coordonnées de texture
    static matrix Bias =
    {
    	{ 0.5f, 0.0f, 0.0f, 0.0f },
    	{ 0.0f, -0.5f, 0.0f, 0.0f },
    	{ 0.0f, 0.0f, 1.0f, 0.0f },
    	{ 0.5f, 0.5f, 0.0f, 1.0f }
    };
     
    struct CVertexShaderOutput
    {
    	...
    	// UV pour la texture projetée
    	float2 LightTextureUV		: TEXCOORD2;
    	// UV pour la texture de falloff de la lumière
    	float2 LightTextureW		: TEXCOORD3;
    	...
    };
     
    VertexShader()
    {
    ...
    // World est la matrice permettant de passer de local en world
    float4 UVW = mul(input.Position, World);
    // LightUVMatrix est la matrice T, passant de world en light clip space
    UVW = mul(UVW, LightUVMatrix);
    // division pour passer en Normalized Device Coordinates
    UVW.xyz /= UVW.w;
    // force w à 1
    UVW.w = 1.0f;
    // mapping [-1,1] -> [0,1] pour x et y (z est déjà entre 0 et 1)
    UVW = mul(UVW, Bias);
     
    // coordonnées pour la texture projetée (2D)
    output.LightTextureUV.xy = UVW.xy;
    // La coordonnée y ne sert à rien, la texture de falloff sert de texture 1D,
    // je la mets arbitrairement à 1.0f
    output.LightTextureW.xy = float2(UVW.z,1.0f);
    ...
    }
    La question fatidique : d'où vient le problème ?

  2. #2
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2002
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 18
    Points : 13
    Points
    13
    Par défaut
    Bon j'ai enfin trouvé... Pour ceux que ça intéresse il ne faut pas faire la division de perspective dans le vertex shader. Ca doit être fait à la rasterisation en laissant la carte graphique le faire toute seule. Pour ça il faut que les TEXCOORDS passés au pixel shader soient des float4 en précisant le flag PROJECTED pour les states TextureTransformFlags correspondant.

  3. #3
    Membre expérimenté

    Profil pro
    Programmeur
    Inscrit en
    Août 2002
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Programmeur

    Informations forums :
    Inscription : Août 2002
    Messages : 1 091
    Points : 1 679
    Points
    1 679
    Par défaut
    Faire la division dans le vertex shader c'est censé marcher, à deux trois détails près : il faut que ton modèle ait une tesselation correcte (que chaque polygone couvre peu de Z), pour limiter les problèmes de correction de perspective.
    Si tu as un seul triangle qui couvre tout l'écran avec une profondeur variable alors c'est fichu. C'est le problème bien connu des gens qui faisaient des rasterizer software dans les années 90 .

    Le principal problème de faire une projection conique dans le vertex shader c'est que les attributs calculés seront interpolés linéairement dans l'espace de ton objet mais la division justement introduit un facteur non linéaire dans la variation de ces coordonnées. La correction de perspective usuelle corrige les problèmes de transformation de textures à variation linéaires de l'espace de ton objet à l'espace de l'écran (variation non linéaire) mais pas celles des transformations de textures non linéaires dans l'espace de ton objet (c'est là que ça se complique !).

    ll faut donc effectuer la double perspective correction (tm moi-meme), qui consiste à interpoler non pas deux coordonnées mais quatre attributs. En partant de s et t, tu ajoutes q, ton facteur de division. Tu interpoles s/q, t/q et q séparément. Bien entendu dans ton dos, la carte graphique va faire sa propre perspective correction (espace écran) et plutot que d'interpoler s/q va interpoler s/q/w et w séparément. La deuxième est toujours fait automatiquement et il n'y a pas moyen de désactiver (en fait dans quelques hardwares futurs ça devrait être possible), la première il faut que tu l'indiques à la carte graphique, premièrement en lui filant trois coordonnées (incluant q), et deux soit en utilisant le flag PROJECTED, soit en utilisant une instruction spéciale dans ton pixel shader (suffixe _dw dans les pixel shader 1.4). La dernière solution est la seule possible avec les pixel shader 1.4. Tu peux également si tu utilises des pixel shaders >=2 faire la première division toi-meme, mais c'est généralement plus couteux.

    La projection conique n'est pas la seule transformation non linéaire dont on se soucie mais malheureusement c'est la seule qui est accélérée par les cartes graphiques.

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2002
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 18
    Points : 13
    Points
    13
    Par défaut
    mmmh... c'est bien plus compliqué que je ne le pensais alors. Si je comprends bien, la division s/q, t/q, r/q, q/q est celle qui est faite si je précise le flag PROJECTED. Mais en plus la carte graphique fait une 2e division ? par w ? D'où sort ce w ? Celui des vertices ?

    Aussi si je laisse la carte graphique diviser r par q, j'obtiens un r' qui ne varie pas linéairement (comme le z dans le zbuffer pour les fragments). Comme je fais du per-pixel lighting avec projection de texture (à la doom3), il me faut un r' qui varie linéairement pour la texture de falloff de la lumière. Pour les projections en perspective, je divise alors r manuellement dans le vertex shader par le far de mon spot (j'ai remarqué que la valeur de r est comprise entre 0 et far pour les vertices qui sont dans le frustum de projection). Est-ce que c'est correct ? En tout cas, visuellement, ça a l'air de fonctionner.

    En tout cas, merci pour la réponse qui m'a certe embrouillé, mais qui me donne envie de comprendre :)

  5. #5
    Membre expérimenté

    Profil pro
    Programmeur
    Inscrit en
    Août 2002
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Programmeur

    Informations forums :
    Inscription : Août 2002
    Messages : 1 091
    Points : 1 679
    Points
    1 679
    Par défaut
    Tu peux trouver des infos sur Google à "perspective correct texture"
    comme là par exemple :
    http://www.cs.unc.edu/~andrewz/comp236/hw6/

    En fait les maths à appliquer ne sont pas très compliquées, tu peux penser en terme de rapport d'homothétie, cf le théorème de Thalès : http://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_de_Thal%C3%A8s

    LeGreg

Discussions similaires

  1. Projection de texture ?
    Par Clad3 dans le forum OpenGL
    Réponses: 2
    Dernier message: 13/12/2008, 11h09
  2. Projection de texture avec OSG
    Par cryptage dans le forum OpenSceneGraph
    Réponses: 6
    Dernier message: 23/04/2008, 17h08
  3. Réponses: 3
    Dernier message: 24/10/2005, 15h26
  4. Réponses: 22
    Dernier message: 03/08/2005, 01h28
  5. Réflection - projected texture
    Par Dranor dans le forum DirectX
    Réponses: 2
    Dernier message: 29/05/2004, 14h35

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