Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Appliquer un sf::Transform à un sf::Sprite et à un sf::shape dans un draw.  (Lu 8809 fois)

0 Membres et 1 Invité sur ce sujet

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Salut,

j'ai une classe EntitéDessinable qui hérite de sf::Drawable et sf::Transformable.
De là en dérive une classe Tile qui contient et sprite et d'autres classes.

Je voudrai faire en sorte qu'on puisse modifier la géométrie à partir de cette classe EntitéDessinable et faire un draw directement sur un objet de type EntitéDessinable afin d'éviter de devoir à chaque fois vérifier le type d'entité et de faire un cast avant de dessiner.

Je voudrais aussi éviter de devoir modifier mon code, c'est à dire remplacer mon sf::Sprite par un sf::VertexArray.

Mais je n'ai trouvé aucune moyen de redéfinir la méthode draw en appliquant une transformation directement à un sprite, j'ai essayé ceci mais ça ne marche pas :

void Tile::draw (RenderTarget &target, RenderStates states) const {
    states.transform = getTransform();
    target.draw(sprite, states);
}
 

Même en appelant setPosition dans le constructeur de ma classe tile pour mettre à jour la position du sprite dans la classe sf::Transformable, le sprite ne s'afficher pas.

Que dois je faire ???

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Bon c'est bizarre j'ai fais ça :
void Tile::draw (RenderTarget &target, RenderStates states) const {
    states.transform = states.transform * getTransform();
    target.draw(sprite, states);
}
 

Et les 4 première tiles que je veux ajouter sur la map ne s'ajoutent pas, mais à partir de la 5ème ça marche.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
C'est en effet le bon code (pour ce genre de chose n'hésite pas à regarder les exemples dans les tutoriels, ou le code source de SFML directement).

Pour ce qui est des 4 premières tuiles, ça doit être un tout autre problème.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Oui, le problème vient d'ailleurs pour les 1ères tiles, bon bah voilà j'ai améliorer la classe ainsi, je peux définir la position de mes sprite à partir de leur origin mais aussi à partir de leur coin supérieur gauche maintenant.

J'ai juste du ré-écrire mes méthodes de la classe transformable par dessus les siennes.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Au sinon j'ai vu que la position était stockée dans la classe sf::Transformable et non dans la classe sf::Sprite comme je le pensais et ce qui me semblerait plus logique. (Du coup je me retrouve avec 2 positions (celle su sprite et celle du noeud (ma classe Tile).)

Je pense plus tard que je vais utiliser mes propres classes de transformation plutôt que la sfml et faire les transformation directement sur des vertexarray avant d'appeler draw. (Commele font la plupart des framework, je pense même que la plupart des framewors n'utilisent même plus le matrices d'opengl.)

Parce que là je dois réimplémenter toute les méthodes de la classe Transformable. (Je préfère ça que d'utiliser un sf::Transform et de devoir réimplémenter toutes les méthodes setRotation, setScale, etc... si ce n'est pas nécessaire.) de sorte à ce que Transformabe contienne juste les transformations et l'origine, combiner mes transformations avec celle du sprite qui ne contient que la position et l'origine finalement.

Avec l'origine je suis un peu perdu aussi car j'ai 2 origines, celles du sprite et celles de la classe transformable, bref, je mets les 2 mêmes origines pour les 2.

Bref en gros voilà ce que j'ai fais :

#ifndef TILE
#define TILE
#include <SFML/Graphics.hpp>
#include "../Math/vec4.h"

#include "../Math/maths.h"
#include "../Lighting/light.h"
#include "../Math/computer.h"
#include <vector>

class MyCanvas;
class GridMap;
class Shadow;
class Wall;

class Tile : public Entity, public sf::Drawable , public sf::Transformable {
    public :

        //Type principale de la couche.


        Tile (sf::Texture &image, Vec2f position, Vec2f size, sf::IntRect subRect, bool bToAnim);
        sf::Sprite& getSprite ();
        const sf::Texture& getTexture ();
        Vec2f getSize();
        virtual Vec2f getPosition();
        Vec2f getCenter();
        void setZOrder(int zOrder);
        virtual void setPosition (Vec2f pos);
        void setCenter(Vec2f center);
        void setSize(Vec2f size);
        virtual void setOrigin(Vec2f origin);
        sf::IntRect getTextRect();
        void setAltitude (int altitude);
        int getAltitude ();

        bool operator== (Tile &tile);
        bool operator!= (Tile &tile);

        int getZOrder();

        void setSelected(bool selected);
        bool isSelected ();
        void setShadowCenter(int cx, int cy);
        Vec2f getShadowCenter ();
        bool belongToAnim ();

        void popup();
        void popback ();

        virtual ~Tile ();

    private :
        virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const;
        Tile (const Tile* tile);
        int zOrder;
        bool selected, bToAnim;
        sf::Sprite sprite;

};
#endif
 

#include "tile.h"

#include "../world/gridMap.h"
#include "../Lighting/shadow.h"
#include "../Lighting/wall.h"

using namespace sf;
using namespace std;

/*Gère les différents tiles, cette classe hérite de Sprite.
*/

//Crée un tile, avec une image passée en paramètre.
Tile::Tile (sf::Texture &image, Vec2f position, Vec2f size, IntRect subRect, bool bToAnim) : Entity (E_TILE) {
    sprite.setTexture(image);
    sprite.setTextureRect(subRect);
    float factorX = size.x / subRect.width;
    float factorY = size.y / subRect.height;
    sprite.setOrigin(subRect.width * 0.5f, subRect.height * 0.5f);
    sprite.scale(factorX, factorY);
    sprite.setPosition(position.x + size.x * 0.5f, position.y + size.y * 0.5f);
    this->bToAnim = bToAnim;
    zOrder = 0;
    selected = false;
    Transformable::setOrigin(subRect.width * 0.5f, subRect.height * 0.5f);
}
void Tile::setOrigin(Vec2f origin) {
    Transformable::setOrigin(origin.x, origin.y);
    sprite.setOrigin(origin.x, origin.y);
}
IntRect Tile::getTextRect () {
    return sprite.getTextureRect();
}
Vec2f Tile::getSize() {
    Vec2f size(sprite.getGlobalBounds().width, sprite.getGlobalBounds().height);
    return size;
}
void Tile::setSize(Vec2f size) {
    Vec2f actualSize = this->getSize();
    Vec2f scale = size / actualSize;
    this->size = size;
    sprite.setScale(scale.x, scale.y);
}

const Texture& Tile::getTexture () {
    return *sprite.getTexture();
}
Vec2f Tile::getCenter () {
    return Vec2f(sprite.getPosition().x, sprite.getPosition().y);
}
Vec2f Tile::getPosition() {
    return Vec2f(sprite.getGlobalBounds().left, sprite.getGlobalBounds().top);
}

bool Tile::belongToAnim () {
    return bToAnim;
}
void Tile::popup () {
    if (zOrder + 1 <= DEFAULT_SHADOW_Z_ORDER)
        zOrder++;
}
void Tile::popback () {
    if (zOrder - 1 >= 0)
        zOrder--;
}

bool Tile::operator== (Tile &tile) {

    return sprite.getTexture() == tile.sprite.getTexture() &&
           sprite.getPosition().x == tile.sprite.getPosition().x &&
           sprite.getPosition().y == tile.sprite.getPosition().y &&
           getSize().x == tile.getSize().x &&
           getSize().y == tile.getSize().y &&
           getZOrder() == tile.getZOrder() &&
           getType() == tile.getType () &&
           sprite.getTextureRect().left == tile.sprite.getTextureRect().left &&
           sprite.getTextureRect().top == tile.sprite.getTextureRect().top &&
           sprite.getTextureRect().height == tile.sprite.getTextureRect().height &&
           sprite.getTextureRect().width == tile.sprite.getTextureRect().width;

}
bool Tile::operator!= (Tile &tile) {
    return !(*this == tile);
}

//Getter.
Sprite& Tile::getSprite () {
    return sprite;
}

//Renvoie le numéro de la couche du sprite.
int Tile::getZOrder() {
    return zOrder;
}

bool Tile::isSelected () {
    return selected;
}

void Tile::setZOrder(int zOrder) {

    this->zOrder = zOrder;
}

void Tile::setSelected (bool selected) {
    this->selected = selected;
}
void Tile::setPosition(Vec2f pos) {
    Vec2f origin (sprite.getOrigin().x, sprite.getOrigin().y);
    Vec2f originalSize (sprite.getTextureRect().width, sprite.getTextureRect().height);
    Vec2f size = getSize();
    Vec2f scale (size.x / originalSize.x, size.y / originalSize.y);
    Vec2f sub (origin.x * scale.x, origin.y * scale.y);
    sprite.setPosition(Vec2f(sprite.getPosition().x - sub.x, sprite.getPosition().y - sub.y));
}
void Tile::setCenter(Vec2f center) {
    sprite.setPosition(Vector2f(center.x, center.y));
}

void Tile::draw (RenderTarget &target, RenderStates states) const {
    states.transform = states.transform * getTransform();
    target.draw(sprite, states);
}


Tile::~Tile () {


}
 

Un peu compliqué je pense que y'a peut être moyen de faire plus simple. :/

Donc finalement qu'est ce qui est mieux, faire des transformations sur des vertex en utilisant ses propres matrices ou alors faire des transformation sur des vertex en utilisant les matrices d'opengl ?

Je pencherai plutôt pour la 1ère solution moi.
« Modifié: Août 28, 2013, 12:27:40 pm par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Il faut bien entendu faire les transformations via les matrices OpenGL. C'est fait pour ça (= c'est gratuit à l'exécution).

Ensuite j'ai pas vraiment regardé en détail ton code, mais pour faire simple, ignore les transformations du sprite, fais comme s'il n'en avait pas et gère tout avec ton sf::Transformable.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ok mais quand je passerai en 3D et que je devrai faire des transformations autour d'un axe quelconque les matrices d'opengl ne me suffiront plus bref...

Ok je vais faire comme ça, comme si le sprite n'a aucune transformation.

Et je vais faire toutes mes transformations avec le sf::Transformable du noeud que je combine avec celle du  sprite. (Seul le setPosition, le setSize et le setCenter pourront changer la transformation du sprite.)

Je dois juste faire attention à ce que le sprite et le noeud aie la même origine sinon je risque d'avoir des problèmes. :/
« Modifié: Août 28, 2013, 12:33:54 pm par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Citer
Ok mais quand je passerai en 3D et que je devrai faire des transformations autour d'un axe quelconque les matrices d'opengl ne me suffiront plus bref...
Tiens donc, j'aimerais bien savoir pourquoi :P

Citer
Je dois juste faire attention à ce que le sprite et le noeud aie la même origine sinon je risque d'avoir des problèmes. :/
Normalement non justement, pourquoi est-ce que tu aurais des problèmes ?
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Bah en utilisant des quaternions par exemple. (On utilise plutôt ça à l'heure actuelle, mais surtout pour la 3D, pour de la 2D je ne pense pas que tu en ai besoin.)
Sinon ta matrice encapsulée dans sf::Transform tu la passe à opengl et c'est lui qui fait toutes les transformations à l'exécution ?
C'est plus rapide de faire comme ça ?

Maintenant il y a peut être moyen de transformer un quaternion en une matrice et la passer à opengl pour qu'il fasse une rotation autour d'un axe quelconque par exemple, mais ça m'étonnerais fort que ça soit possible les queternions et les matrices c'est complètement différent.

Bon finalement j'ai trouvé comment résoudre le problème avec la globalBox, j'ai regardé dans les sources de la sfml et il suffit d'appeler transformRect sur la localBox.

Je suppose que getLocalBounds ne fait rien d'autre que de renvoyer le textureRect.




Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Citer
Bah en utilisant des quaternions par exemple. (On utilise plutôt ça à l'heure actuelle, mais surtout pour la 3D, pour de la 2D je ne pense pas que tu en ai besoin.)
Les quaternions sont plus adaptés pour certaines manipulations, mais au final tu pourras toujours encoder ta transformation dans une matrice 4D et la passer à OpenGL.

Citer
Sinon ta matrice encapsulée dans sf::Transform tu la passe à opengl et c'est lui qui fait toutes les transformations à l'exécution ?
C'est plus rapide de faire comme ça ?
Oui. Ne pas laisser OpenGL gérer la transformation des vertexs, ce serait vraiment très contre-productif. C'est justement à ça que sert la carte graphique.

Citer
Maintenant il y a peut être moyen de transformer un quaternion en une matrice et la passer à opengl pour qu'il fasse une rotation autour d'un axe quelconque par exemple, mais ça m'étonnerais fort que ça soit possible les queternions et les matrices c'est complètement différent.
Toi tu as besoin de lire quelques articles sur les matrices et les transformations. Là tu pars sur des hypothèses complètement fausses, qui vont te faire concevoir et implémenter des choses inutiles dans ton application.
Avec une matrice 4D tu peux représenter n'importe quelle transformation 3D, linéaire ou non. Et donc bien entendu une rotation quelconque.
« Modifié: Août 28, 2013, 01:29:35 pm par Laurent »
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ha lol, parce que j'ai vu le code source d'un moteur de jeux (JMonkeyEngine) qui utilise ses propres matrices et quaternions pour transformer les vertex.

C'est même sur le code de ce moteur là que je m'étais basé mais il me semblait bien que en lisant le code de ce moteur là ça ne me semblait pas très optimal.

Déjà faire un arbre binaire ou chaque feuille ne contient qu'un vertex n'est pas bon, car, il faut faire une entité par feuille, car, ce n'est pas parce que un vertex de la primitive est en dehors de la zone affichable à l'écran que les pixels qui relient ce vertex aux autes vertex ne sont pas affichable.
Et bon je suppose que c'est opengl qui se charge de savoir si un pixel est visible ou pas au niveau dela carte graphique.

Bref j'ai du m'inspirer d'un mauvais truc.  :-\

Reycan

  • Newbie
  • *
  • Messages: 49
    • Voir le profil
Voici un lien avec les différentes matrices de transformation : http://www.siteduzero.com/informatique/tutoriels/developpez-vos-applications-3d-avec-opengl-3-3/transformations-au-niveau-matricielle

La matrice pour une rotation sur un axe arbitraire est compliquée car c'est en fait le résultat de RotationMatrixAxeX * RotationMatrixAxeY * RotationMatrixAxeZ

Si tu regarde dans le code source de sf::Transform,  tu peux voir que les rotations sont faites seulement à partir de la RotationMatrixAxeZ  car les rotations en 2D ne tourne qu'autour de l'axe Z ==> c'est donc suffisant.

Je suis également en train de coder ma classe Transform3D, donc si il y a moyen d'avoir une petite confirmation que mon explication soit bel est bien correcte ?   :)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Citer
Je suis également en train de coder ma classe Transform3D, donc si il y a moyen d'avoir une petite confirmation que mon explication soit bel est bien correcte ?
Elle l'est quasiment ;)

Une rotation quelconque peut être exprimée de différentes manières ; la combinaison de rotations autour des 3 axes n'en est qu'une parmi d'autres. On pourrait aussi l'obtenir directement via un quaternion, via un axe + angle (ce qui est pratiquement le quaternion), etc. Il y a la formule qui va bien pour transformer chacune de ces choses en une matrice 4D.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ok merci pour l'information je chercherai de ce côté là alors. :)

J'ai une dernière question est il possible que 2 tiles tournent autour d'un même point ?

Je voudrais que ma tile et son ombre tournent autour de l'origine de la tile en fait.

Sinon impéc j'ai pu combiner les transformations pour que mes segments pour les instersections murs lumière et mes points pour les projections des ombres de mes murs tournent en même temps que la tile qui affichent mes mur en utilisant ma propre classe transformMatrix dans la surcharge des méthodes setRotation, setScale et move.

Je peux donc combiner les transformations sur les entités de la SFML et les entités de mon propre framework ce qui est cool.

« Modifié: Août 28, 2013, 04:58:29 pm par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Citer
J'ai une dernière question est il possible que 2 tiles tournent autour d'un même point ?
Oui, il faut juste transformer ce point d'un repère local à l'autre (car l'origine est exprimée en coordonnées locales à l'entité).
Laurent Gomila - SFML developer