1. #1
    Nouveau membre du Club
    Homme Profil pro
    Cimentage
    Inscrit en
    septembre 2014
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Cimentage
    Secteur : Associations - ONG

    Informations forums :
    Inscription : septembre 2014
    Messages : 44
    Points : 31
    Points
    31

    Par défaut Comment réaliser un bon FloorCasting ?

    Salut à tous ! :-)

    Alors voilà, je travaille avec la librairie SFML 2.3 et actuellement, j'essaie tant bien que mal de mettre en place un système de projection d'un sol en " fausse 3D ", autrement-dit, donner une impression de perspective tel que le fameux Mode 7.

    Je m'explique, je voudrais partir d'une texture classique ( donc un fichier image tout bénin ) et lui donner une impression de perspective selon la position de ma caméra.

    Cette image par exemple :
    https://www.coranac.com/tonc/img/mode7/m7_map.png

    Une fois projetée donnerait donc ça :
    https://www.coranac.com/tonc/img/mode7/m7_persp.png

    J'ai procédé comme suit :

    Je récupère la distance de chaque point (donc 4 au total) du cube sur la vue 2D et j'en déduis la forme sur mon écran de rendu 3D / perspective par rapport à ces distances.

    Mais comme vous pouvez le constater, le calcul des distances n'est pas top car j'ai une distorsion visuelle lorsque je bouge.. ( regardez un peu le coin inférieur gauche et droit lorsque je me rapproche dans mon GIF... )

    Voici le GIF de mon programme en question :

    https://gyazo.com/ec0aa6f6a9f3d06df2c90d778bb66bd5

    Ainsi que mon code source :

    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    #include <iostream>
    #include <math.h>
     
    #include <SFML/Graphics.hpp>
     
    const float PI = 3.1415f;
    unsigned int WIDTHSCREEN = 800, HEIGHTSCREEN = 600;
     
    inline float toRadian(float degree) { return (PI/180)*degree; }
    inline float dCos(float degree) { return cos(toRadian(degree)); }
    inline float dSin(float degree) { return sin(toRadian(degree)); }
     
    int main()
    {
        sf::RenderWindow m_window(sf::VideoMode(WIDTHSCREEN, HEIGHTSCREEN, 32), "FloorCasting", sf::Style::Titlebar);
        m_window.setFramerateLimit(60);
     
        sf::RenderWindow m_renderWindow(sf::VideoMode(WIDTHSCREEN, HEIGHTSCREEN, 32), "Render", sf::Style::Titlebar);
        m_renderWindow.setFramerateLimit(60);
     
        sf::Texture m_textureGround;
        m_textureGround.loadFromFile("ground.PNG");
     
        ///MISCEALLENOUS SFML///
        sf::Clock m_clock;
     
        std::vector<sf::VertexArray>m_vecBox;
     
        for (unsigned int i = 0 ; i < 1 ; i++)
        {
            sf::VertexArray m_2dBox(sf::Quads, 4);
                m_2dBox[0].position = {224+(i*32), 224};
                m_2dBox[1].position = {256+(i*32), 224};
                m_2dBox[2].position = {256+(i*32), 256};
                m_2dBox[3].position = {224+(i*32), 256};
            m_vecBox.push_back(m_2dBox);
        }
     
        ///BOXES///
        sf::VertexArray m_renderBox(sf::Quads, 4);
            m_renderBox[0].texCoords = {0, 0};
            m_renderBox[1].texCoords = {900, 0};
            m_renderBox[2].texCoords = {900, 900};
            m_renderBox[3].texCoords = {0, 900};
     
        ///VARIABLES///
        float m_fov = 60.0f;
        float m_angle = 0.0f;
        float m_rayLength = 200.0f;
        float m_speedMove = 100.0f;
        float m_speedAngle = 120.0f;
        sf::Vector2f m_position = {150,150};
     
        ///RAYS///
        sf::VertexArray m_rayLeft(sf::Lines, 2);
        sf::VertexArray m_rayRight(sf::Lines, 2);
     
        while(m_window.isOpen())
        {
            sf::Time dt = m_clock.restart();
            sf::Event event;
            while (m_window.pollEvent(event))
            {
                switch(event.type)
                {
                case sf::Event::Closed:
                    m_window.close();
                    break;
                case sf::Event::KeyReleased:
                    if (event.key.code == sf::Keyboard::Escape)
                        m_window.close();
                    break;
                }
            }
     
            ///MOVES///
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Z))
            {
                m_position.x += (m_speedMove*dt.asSeconds()*dCos(m_angle));
                m_position.y += (m_speedMove*dt.asSeconds()*dSin(m_angle));
            }
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
            {
                m_position.x -= (m_speedMove*dt.asSeconds()*dCos(m_angle));
                m_position.y -= (m_speedMove*dt.asSeconds()*dSin(m_angle));
            }
     
            ///ROTATION///
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
                m_angle-=m_speedAngle*dt.asSeconds();
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                m_angle+=m_speedMove*dt.asSeconds();
     
            ///ANGLE PROTECTION///
            if (m_angle<0) m_angle = 360;
            if (m_angle>360) m_angle = 0;
     
            ///UPDATE POSITION///
            m_rayLeft[0].position = m_position;
            m_rayRight[0].position = m_position;
     
            ///UPDATE ANGLE///
            m_rayLeft[1].position = {m_position.x+m_rayLength*dCos(m_angle+m_fov/2),
                                     m_position.y+m_rayLength*dSin(m_angle+m_fov/2)};
            m_rayRight[1].position = {m_position.x+m_rayLength*dCos(m_angle-m_fov/2),
                                      m_position.y+m_rayLength*dSin(m_angle-m_fov/2)};
     
            m_renderWindow.clear();
     
            ///CLOSE RENDERWINDOW///
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                m_renderWindow.close();
     
            ///MAIN FUNCTION///
            for (unsigned int t = 0 ; t < m_vecBox.size() ; t++)
            {
                for (unsigned int i = 0 ; i < 4 ; i++)
                {
                float d = atan2(m_vecBox[t][i].position.y-m_position.y,
                                m_vecBox[t][i].position.x-m_position.x) * 180/PI;
     
                if (d<0) d+= 360;
     
                float k = (d-m_angle)+m_fov/2;
     
                if (k<0) k+= 360;
     
                float distance = sqrt((m_position.x-m_vecBox[t][i].position.x)*(m_position.x-m_vecBox[t][i].position.x)+
                                      (m_position.y-m_vecBox[t][i].position.y)*(m_position.y-m_vecBox[t][i].position.y));
     
                float propWidth = (k/m_fov)*WIDTHSCREEN;
                float propHeight = 4000/((distance/1000)*HEIGHTSCREEN/2);
     
                if (propWidth>(360/m_fov)*WIDTHSCREEN/2)
                    propWidth-=(360/m_fov)*WIDTHSCREEN;
     
                m_renderBox[i].position = {propWidth, propHeight+HEIGHTSCREEN/2};
     
                if (propWidth>-200 && propWidth<1000 && propHeight<300)
                    m_renderWindow.draw(m_renderBox);
                }
            }
     
            m_window.clear();
     
            m_window.draw(m_rayLeft);
            m_window.draw(m_rayRight);
     
            for (auto& vvec : m_vecBox)
                m_window.draw(vvec);
     
            m_window.display();
     
            m_renderWindow.display();
        }
    }
    Une idée sur la manière dont je pourrais corriger cette vilaine distorsion visuelle ? Sinon une autre idée de comment je pourrais procéder ? Je tiens à préciser que je suis d'un niveau particulièrement affligeant en maths, je comprends les bases de la trigonométrie et l'utilisation des racines carrés pour évaluer les distances, sait calculer des proportions, mais je suis vite limité.. ( Aucune connaissance dans l'utilisation des vecteurs polaires par exemple ).

    Merci énormément à vous de bien vouloir m'aider et ne me sortez pas des " Pourquoi tu n'utilises pas de moteur 3D directement ? ", je trouve ça moins fun et j'ai envie de comprendre & de réussir par réussite personnelle ! :-D

    A bientôt les amis !

  2. #2
    Expert éminent
    Homme Profil pro
    Développeur informatique
    Inscrit en
    février 2005
    Messages
    4 325
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : février 2005
    Messages : 4 325
    Points : 9 554
    Points
    9 554

    Par défaut

    Je suis trop vieux pour voir la "distorsion visuelle".
    Pouvez-vous faire une série d'image statique avec de gros ronds rouges avec des flèches pour guider mes yeux vieillissant ?

    Sinon, juste une remarque, vous faites beaucoup de calcul qui s'enchainent sur des float "simple précision", est-ce que le passage à des doubles à la place de tout ces float ne règle ou ne réduit pas le problème ?

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Cimentage
    Inscrit en
    septembre 2014
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Cimentage
    Secteur : Associations - ONG

    Informations forums :
    Inscription : septembre 2014
    Messages : 44
    Points : 31
    Points
    31

    Par défaut

    Merci beaucoup de m'avoir répondu :-)

    Ton raisonnement quant à l'utilisation de double au lieu du float afin d'avoir une valeur plus précise n'est pas bête du tout !
    Néanmoins, ce n'est pas ce qui cause le problème.

    J'arrive à projeter des murs avec la technique du raycasting et à me débarrasser de la distorsion visuelle ( eyefishing effect ) en calculant la distance obtenue par le cosinus de l'angle actuel.

    Avant, j'avais des murs comme ça :

    https://image.noelshack.com/fichiers...0-probleme.png

    Puis j'ai réussi à corriger ce défaut avec la fonction suivante :

    m_wallDistance*= cos(-m_fov*(PI/180)/2 + (m_fov*(PI/180)/WIDTHSCREEN)*it);


    Cette distorsion est logique dans la mesure où les rayons sur les côtés parcourent davantage de distance que ceux qui sont projetés davantage vers le centre d'où cette impression de décors " bombé ".

    Mais alors concernant mon principe de FloorCasting cette fois-ci, je suis paumé ... Afin que tu te rendes comptes davantage de la distorsion de la dalle, je te l'ai texturé, tu vas mieux te rendre compte du problème dorénavant :

    https://gyazo.com/4366125b289ca5566bc1d88cd88e4232

    Quand je fais les va-et-vient, tu pourras constater la déformation visuelle ( qui est perceptible également sans texture, en tout cas moi je la vois bien donc ce n'est pas un problème de texturing ! )

  4. #4
    Expert éminent
    Homme Profil pro
    Développeur informatique
    Inscrit en
    février 2005
    Messages
    4 325
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : février 2005
    Messages : 4 325
    Points : 9 554
    Points
    9 554

    Par défaut

    Néanmoins, ce n'est pas ce qui cause le problème.

    J'arrive à projeter des murs avec la technique du raycasting
    Les calculs ne sont pas les mêmes, donc les probabilités d'erreurs d'opération sur virgule flottante ne sont pas les mêmes.

    Je ne vois toujours pas "l'anomalie"

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Cimentage
    Inscrit en
    septembre 2014
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Cimentage
    Secteur : Associations - ONG

    Informations forums :
    Inscription : septembre 2014
    Messages : 44
    Points : 31
    Points
    31

    Par défaut

    Pourtant elle est belle et bien présente et m'enquiquine au plus haut point.....

  6. #6
    Expert confirmé
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    mai 2010
    Messages
    2 007
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : mai 2010
    Messages : 2 007
    Points : 5 611
    Points
    5 611

    Par défaut

    Ayant bossé sur la SNES et ayant fait le fameux mode 7 sur cette console je sais bien comment cela marche.
    Le Mode 7 ne fait pas de la perspective en faite , il permet juste de faire un rotation /zoom sur le background , pour faire l'effet de perspective , il faut faire un zoom/dezoom sur chaque ligne de l'écran(ce que fait la SNES ).

    Après effectivement j'aurais proposé d'utiliser OpenGL , le Mode 7 était utilisé justement parce que la 3D était quasi-impossible sur console , d'ailleurs la SNES est si peu puissante que il fallait un coprocesseur sur les cartouches (comme Mario Kart) pour pouvoir exploiter pleinement le Mode 7 !

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    septembre 2005
    Messages
    26 473
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : septembre 2005
    Messages : 26 473
    Points : 38 201
    Points
    38 201

    Par défaut

    Citation Envoyé par FrostfallDelphi Voir le message
    Mais alors concernant mon principe de FloorCasting cette fois-ci, je suis paumé ... Afin que tu te rendes comptes davantage de la distorsion de la dalle, je te l'ai texturé, tu vas mieux te rendre compte du problème dorénavant :

    https://gyazo.com/4366125b289ca5566bc1d88cd88e4232

    Quand je fais les va-et-vient, tu pourras constater la déformation visuelle ( qui est perceptible également sans texture, en tout cas moi je la vois bien donc ce n'est pas un problème de texturing ! )
    Le problème ici, c'est justement l'absence de distorsion: C'est ce qui fait que tes deux demi-textures sont en perspective cavalière au lieu d'être en vraie perspective! Tu dois corriger ton calcul pour que les lignes du parquet n'apparaissent plus parallèles sur l'écran.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Cimentage
    Inscrit en
    septembre 2014
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Cimentage
    Secteur : Associations - ONG

    Informations forums :
    Inscription : septembre 2014
    Messages : 44
    Points : 31
    Points
    31

    Par défaut

    Bonsoir les gars,

    Justement, je sais pertinemment que je dois " corriger mes calculs " .. mais j'aimerais avoir une / des idée(s) pour ce cas de figure :-) Votre imagination et votre savoir-faire sont probablement bien supérieurs aux miens, d'où ma sollicitation de votre sainte aide :-D

    Kannagi > D'accord, j'aimerais que tu m'expliques davantage le procédé en termes de calculs :-) ( en y allant doucement, hein ! haha )
    J'adore ce type de rendu et j'adorerais pouvoir le faire en mode oldschool et non en faisant appel à une lib me facilitant le boulot ( c'est par plaisir avant tout / curiosité / apprentissage / défi personnel.. entre autre ! )

    Encore merci pour vos futurs réponses !

Discussions similaires

  1. msi ou comment réaliser un installeur?
    Par herzleid dans le forum Delphi
    Réponses: 11
    Dernier message: 09/04/2007, 19h27
  2. [FLASH MX] Comment réaliser une forme dentelée
    Par celina5880 dans le forum Flash
    Réponses: 4
    Dernier message: 04/11/2004, 17h48
  3. [DBGrid avec Cumul]Comment réaliser un cumul dans un DBGrid
    Par Eric SAULNIER dans le forum Bases de données
    Réponses: 2
    Dernier message: 21/07/2004, 17h56
  4. Comment réaliser des modèles de documentations avec XML ?
    Par Dams76 dans le forum XML/XSL et SOAP
    Réponses: 6
    Dernier message: 29/08/2003, 02h15

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