Forum de la communauté SFML

Général => Discussions générales => Discussion démarrée par: DexArio le Mars 03, 2016, 10:35:38 pm

Titre: Rapidité des transformations avec SFML
Posté par: DexArio le Mars 03, 2016, 10:35:38 pm
Salut,

Je suis actuellement entrain de créer mes propres classes graphiques (= Sprites...) avec OpenGL. En comparant mes classes à celles d'SFML, j'ai remarqué que celles d'SFML étaient bien plus rapides (je parle ici des sprites). Après investigations, j'ai trouvé que calculer les transformations pour mes sprites prenait beaucoup de temps (j'utilise GLM). La différence est vraiment notable: j'ai fait une application test pour comparer et les résultats sont frappants: SFML -> 240 FPS, Moi -> 39 FPS. Quand J'enlève les transformations sur mes classes, je monte à 260 FPS. C'est donc le fait de calculer les transformations avec GLM qui cause énormément de lag. Je me demandais donc comment est-ce que SFML fait pour être aussi rapide. J'ai déjà épluché le code de sf::RenderTarger::draw(...) et de sf::Transformable::getTransform() mais mis à part le fait que SFML n'utilise pas GLM, je n'ai pas vu de différences notables (ex: SFML recalcule aussi les transformations à chaque fois qu'elles changent).

Je ne sais pas si c'est important mais voici comment est-ce que je calcule les transformations:

        if (m_updateNeeded)
        {
                glm::mat4 model, projection;

                /* Model matrix */
                /* Translating the sprite to its position and scaling it */
                model = glm::translate(model, glm::vec3(m_position.x, m_position.y, 0.0f));
                model = glm::scale(model, glm::vec3(m_scale.x, m_scale.y, 0.0f));

                /* Rotating the sprite (we translate it to its origin, rotate it and translate it back to where it was) */
                model = glm::translate(model, glm::vec3(m_rotationOrigin.x, m_rotationOrigin.y, 0.0f));
                model = glm::rotate(model, m_rotation, glm::vec3(0.0f, 0.0f, 1.0f));
                model = glm::translate(model, glm::vec3(-m_rotationOrigin.x, -m_rotationOrigin.y, 0.0f));

                /* Projection matrix */
                projection = glm::ortho(0.0f, (float)screenWidth, (float)screenHeight, 0.0f);

                m_mvp = projection * model;

                m_updateNeeded = false;
        }

        return m_mvp;

Sinon, pour le test que j'ai réalisé pour comparer marche de la manière suivante: j'ai un sprite de 32x32, que je draw() 768 fois (avec à chaque fois une position différente) pour couvrir une surface de 1024x768 px. Ainsi, les transformations doivent être recalculées 768 fois, ce qui crée beaucoup de lag avec mes classes.

(Aussi, je ne sais pas vraiment si ce topic est dans la bonne catégorie, de mon point de vue, je ne vois pas ça comme une demande d'aide mais plus comme une question, une inquisition).

Merci.
Titre: Re : Rapidité des transformations avec SFML
Posté par: Laurent le Mars 03, 2016, 10:51:05 pm
Tu as regardé le code source, mais pas au bon endroit apparemment :
https://github.com/SFML/SFML/blob/master/src/SFML/Graphics/Transformable.cpp#L181-L203

Les transformations ne sont pas calculées et multipliées les une derrière les autres : puisque ce sont toujours les mêmes et combinées dans le même ordre (en ce qui concerne sf::Transformable), elles sont déjà pré-combinées et uniquement le calcul final optimisé est implémenté.

Fais la même chose avec sf::Transform, et tu devrais obtenir le même genre de performances qu'avec GLM.
Titre: Re : Rapidité des transformations avec SFML
Posté par: DexArio le Mars 04, 2016, 06:51:10 pm
J'ai joué un peu avec les transformations et j'ai fini par faire ça:

        float angle = -m_rotation * 3.141592654f / 180.f;
                float cosine = std::cos(angle);
                float sine = std::sin(angle);

                float x1 = m_scale.x * cosine;
                float y1 = m_scale.y * sine;
                float z1 = 0.f;
                float w1 = 0.f;
               
                float x2 = m_scale.x * -sine;
                float y2 = m_scale.y * cosine;
                float z2 = 0.f;
                float w2 = 0.f;

                float x3 = 0.f;
                float y3 = 0.f;
                float z3 = 1.f;
                float w3 = 0.f;

                float x4 = -m_rotationOrigin.x * x1 - m_rotationOrigin.y * -y1 + m_position.x + m_rotationOrigin.x * m_scale.x;
                float y4 = -m_rotationOrigin.x * -x2 - m_rotationOrigin.y * y2 + m_position.y + m_rotationOrigin.y * m_scale.y;
                float z4 = 0.0f;
                float w4 = 1.0f;


                m_mvp = glm::ortho(0.0f, (float)screenWidth, (float)screenHeight, 0.0f) *
                        glm::mat4(x1, y1, z1, w1, x2, y2, z2, w2, x3, y3, z3, w3, x4, y4, z4, w4);

Ce code est 2.4x plus rapide que l'ancien, c'est pas mal, mais c'est moins qu'SFML, qui est 6,4x plus rapide  :o
Cependant, il me reste d'autres optimisations à faire concernant d'autres fonctionnalités liées aux sprites.