-
J'ai un soucis lors de l'affichage de mes couches tilemap uniquement quand j'utilise une texture atlas ( commune à tout les tiles ) généré via cette méthode :
void tileManager::generateAtlasTexture(sf::Int32 edgeSize)
{
int x = 0;
int y = 0;
int nl = int(((sqrt( mTileArray.size() )*.5f)*2))+1;
sf::Int32 atlasSquare = nl * edgeSize;
mAtlasTexture.create(atlasSquare,atlasSquare);
std::vector<tile*>::iterator it;
for(it=mTileArray.begin(); it<mTileArray.end(); ++it)
{
// retrieve tile
tile * t = *it;
// get pixel
const sf::Uint8 * pixels = t->getTexture().copyToImage().getPixelsPtr();
// update them into atlas texture
mAtlasTexture.update (pixels,edgeSize,edgeSize,x,y);
t->mAtlasCoordinate.left = x;
t->mAtlasCoordinate.top = y;
t->mAtlasCoordinate.width = edgeSize;
t->mAtlasCoordinate.height = edgeSize;
t->mSprite.setTexture(mAtlasTexture);
t->mSprite.setTextureRect(t->mAtlasCoordinate);
x += edgeSize;
if (x>=atlasSquare)
{
x = 0;
y+=edgeSize;
}
}
// control
//mAtlasTexture.copyToImage().saveToFile("ctrl.png");
}
mAtlasCoordinate est un sf::IntRect , l'effet obtenu est le suivant :
(http://img4.hostingpics.net/pics/294142borderEffect.png)
je voudrais obtenir :
(http://img4.hostingpics.net/pics/450801borderEffect1.png)
pour le résultat qui fonctionne , je découpe chaque tuile dans une image que je copie et que j'ajoute dans un sf::Texture , chaque tuile a donc un sf::Texture & sf::Image propre , mais en vue d'optimisé le tout
je dois passé par une texture atlas pour faire ensuite l'optimisation avec un vertex array.
j'ai fait le tour de la question , setSmooth() n'est pas activé , ce n'est pas un problème de positionnement des tuilles puisque sinon cela apparaîtrait avec la méthode de base , une texture & une image par tile.
je pense plus à un soucis d'uv au niveau sfml , clamp de texture ?
merci de m'apporté un oeil neuf sur ce problème.
-
j'ai résolu le problème en passant de
mSprite.setPosition(sf::Vector2f(position.x, position.y));
a
mSprite.setPosition((int)position.x, (int)position.y);
Edit :
Quand je change la vue , le problème reviens...
-
Comme tu l'as remarqué, le problème arrive quand une image est affichée à des coordonnées non entière. Le problème peut revenir si ta vue induit un décalage d'un nombre non entier de pixels.
-
le problème arrive dans les cas suivants :
- Coordonnées flottante & texture commune à tout les sprites ( découpage a l'aide de setTextureRect() )
- Coordonnées entière & changement de vue ( zoom ) & texture commune aussi.
- Coordonnées flottante & changement de vue ( zoom ) & texture commune aussi.
ca marche uniquement si chaque sprite possède sa propre texture & image. ( que je découpe aussi au passage )
le point commun du problème , c'est la texture commune a tout les sprites , j'ai vérifier les sources de la sfml , il "clampe" correctement , je suis bloqué à réfléchir la dessus... :/
je me demande si lui passer les coordonnées de texture (int) que sfml convertit en UV (float) induit un décalage lors des zooms , je vais trafiqué en ce sens...
-
C'est un problème insoluble, ne vous cassez pas trop la tête dessus. C'est même une "fonctionnalité" : dans certains cas on a besoin que ça bave un peu (pour des sprites en mouvement ou en rotation, ça évite un effet saccadé).
-
c'est bien ce que je me disait. je me tate à essayer le vertexArray pour voir si cela change quelque chose.
je pense que le soucis pourrais être régler si on pouvais passer des floats pour les uv.
setTextureRect( sf::IntRect() ) // coordonnées en pixels
setTextureRect( sf::IntFloat() ) // coordonnées entre 0-1
le problème interne a sfml serais de connaitre la taille de la texture , car l'update interne se base sur ces valeurs (intrect).
-
je me tate à essayer le vertexArray pour voir si cela change quelque chose.
Ca ne changerait rien, tout est déjà basé sur des vertex arrays.
je pense que le soucis pourrais être régler si on pouvais passer des floats pour les uv.
OpenGL prend des floats pour les UVs, je dois donc déjà faire cette conversion en interne.
-
Salut,
Tu pourrais faire le rendu sur une RenderTexture avec des coordonnées entières, puis appliquer les transformations.
-
le rtt résoud le problème , effectivement , mais c'est du bricolage & les perfs en prenne un coup.
je pense que le soucis viens de la SFML , il ne prend pas en compte la taille des texels lors d'un redim de texture.
je fouille de ce coté http://gamedev.stackexchange.com/questions/46963/how-to-avoid-texture-bleeding-in-a-texture-atlas (http://gamedev.stackexchange.com/questions/46963/how-to-avoid-texture-bleeding-in-a-texture-atlas)
-
Résolu ! 3 jours que je suis dessus ! c'est à cause de l'antialiasing dans le contexte.
merci de m'avoir aidé ;)
-
Au fait, ton code est incorrect (comportement indéterminé). Tu prends trop de raccourcis là :
const sf::Uint8 * pixels = t->getTexture().copyToImage().getPixelsPtr();
Tu gardes un pointeur sur les pixels d'une image que tu ne stockes même pas, et qui est du coup détruite dès la fin de l'exécution de cette ligne de code. Sois tu stockes l'image, soit tu ne stockes rien et passes tout le bazar directement à texture.update.
-
l'image est déjà stocké dans t. la copie de pixel part sur ma texture atlas qui possède sa propre image.
quand *pixels est détruit à la fin de la méthode , il ne représentait qu'une copie, pas une référence.
-
Non, t stocke un sf::Texture. Les pixels vers lesquels tu pointes sont stockés dans le sf::Image éphémère qui est créé par l'appel copyToImage().
-
oui , mais update fait une copie de l’éphémère ?
-
Mais il n'existe déjà plus à ce moment. Tu ne l'as pas stocké, il a été détruit dès la fin de la ligne de code sur laquelle il a été créé.
-
J'avoue ne pas te suivre.
- je récupère des pixels dans un tableau temporaire
- je les update dans une texture ( qui as une image )
- je passe à la prochaine itération et je recommence
en tout cas, pas de soucis à ce niveau là. pour moi il n'y a pas de problème.
-
Au moment de l'appel de cette ligne
const sf::Uint8 * pixels = t->getTexture().copyToImage().getPixelsPtr();
Il se passe ceci:
on appelle
getTexture()
qui te renvoie une référence vers la texture courante de t.
Puis on appelle
copyToImage()
qui va créer une image au moment de cet appel (qui est donc une fonction lente). L'usage normal de cette fonction est la construction d'une véritable image comme ceci
sf::Image myImage(t->getTexture().copyToImage());
Finalement, tu récupères le pointeur de l'image que tu viens de créer, et c'est celui ci que tu stockes. A aucun moment tu ne récupères réellement l'image.
A chaque appel de copyToImage() tu récrées une image à partir de la texture actuelle, avec à chaque fois une adresse différente.
-
Demande-toi qui possède (crée / détruit) le tableau de pixels vers lequel tu pointes. Quelle instance de quelle classe. Et ensuite demande-toi si l'instance en question existe encore dans ton code au moment où tu utilises le pointeur.
-
@gostron , je ne veut pas créer de véritable image.
j'ai compris que *pixels est temporaire a la fonction , je m'en sers uniquement pour récupéré les pixels que je colle dans une texture non temporaire a la fonction ( la texture atlas )
lorsque je passe *pixel a update , opengl m'en fait une copie avec glTexSubImage2D.
je ne veut pas gardé les portions que je découpe , j'en ai pas besoin par la suite.
-
Il comprend pas...
Avant l'appel à copyToImage(), le tableau de pixels n'existe pas. Après l'appel à copyToImage(), le tableau de pixels n'existe plus. Donc quand tu arrives dans ton appel à texture.update, ça fait belle lurette (une ligne de code tout entière !) que les pixels vers lesquels tu pointes ont été détruits.
C'est comme de faire ça :
const char* ptr = std::string("blop").c_str();
C'est tout aussi incorrect, parce que le tableau de caractères est stocké dans le std::string, mais celui-ci n'est stocké nulle part et est donc détruit dès la fin de l'exécution de cette ligne de code.
-
d'accord , pourquoi ça marche ? il faut donc que je passe par une image , et pas un raccourci comme je le fait donc.
-
"Ca marche" est une manifestation tout à fait valide d'un comportement indéterminé. J'ai envie de dire que c'est la pire, puisque ça te cache complètement l'erreur. Avec un bon vieux crash, au moins, tu as le nez dans ton erreur directement.
Si tu veux des détails un peu plus techniques : tant que personne n'est allé réallouer et écrire par dessus la zone mémoire où se trouvaient les pixels, ceux-ci s'y trouvent toujours.
-
ok , donc , si je m'amuse à modifier *pixel après mon update , je devrais voir le résultat.
Merci de ta patience ;D