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 !