Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++ SFML 2.6.2] Auto-Tiling

Ostatnio zmodyfikowano 2025-03-21 22:26
Autor Wiadomość
DejaVu
» 2025-03-20 15:28:17
Masz 10 tekstur. Trzymaj 10 tekstur w RAM. Musisz połączyć te 10 tekstur z konkretną maską -> generuj teksturę jaka wynika z kombinacji tekstury + maski. Zapisz sobie ją w dictionary i reużywaj.

Innymi słowy: te tekstury, które musisz wygenerować, to wygeneruj, ale nie generuj wszystkich możliwości, bo 99% tekstur i tak nie zostałoby użyte.
P-182174
tBane
Temat założony przez niniejszego użytkownika
» 2025-03-20 15:46:55
Nie wiem w jaki sposób mógłbym przetwarzać tak tekstury jak radzisz.

Jedynym w miarę sensownym rozwiązaniem wydaje mi się generowanie tekstury dla każdego tilesa, ale to jest zasobożerne :-/
P-182175
DejaVu
» 2025-03-20 15:52:03
Generalnie sam wlazłeś w pokrzywy chcąc mieć 'głównego' tilesa, łączonego z 'innym' tilesem. Chcesz, aby coś ładniej wyglądało? masz konsekwencje w postaci zwiększonych obliczeń CPU lub GPU lub użycia RAM. Efekt będzie fajny jak zaimplementujesz rozwiązanie, ale do tego czasu to masz konkretny problem do rozwiązania. Najlepiej by było zapewne, abyś zrobił klasę, która ma metodę:

C/C++
sf::Texture TextureManager::GetCombinedTexture( int texture1, int texture2, unsigned mask )
{
   
//tutaj cache m_cache i jeżeli nie ma w cache-u tekstury: {texture1, texture2, mask}, to generujesz nową i zapisujesz w cache-u i zwracasz wynik.
}
P-182176
tBane
Temat założony przez niniejszego użytkownika
» 2025-03-20 16:24:13
Czyli znowu się wszystko sprowadza do tego, że dla każdego tilesa trzeba osobną teksturę przypisać a to spowolni znacznie działanie programu :-/

Ogólnie to mam trzy metody na to jak rozwiązać ten problem ale każda z nich ma jakiś minus

pierwsza to taka, że każdy kafelek ma sf::Sprite.. (zasobożerność, słaba prędkość)
drugi pomysł to taki, że każdy kafelek ma sf::VertexArray i unikalną teksturę (zasobożerność, średnia prędkość),
trzeci pomysł to taki że każdy kafelek jest zdefiniowany jako sf::VertexArray i odnosi się do głównej tekstury ale ta ma olbrzymi rozmiar :-?

// edit
64*102400 = 6553600
sqrt(6553600) = 2560.
Tekstura się zmieści :-)
P-182177
tBane
Temat założony przez niniejszego użytkownika
» 2025-03-20 19:03:50
Algorytm do generowania wszystkich kombinacji 10 bazowych kafelków z 16 maskami w teksturze o rozmiarach 2816x2816 zamieszczam poniżej. :-)




C/C++
void generateTileSet() {
   
sf::Image masks[ 16 ];
   
   
for( int i = 0; i < 16; i++ ) {
       
masks[ i ].create( 64, 64 );
       
if( !masks[ i ].loadFromFile( "assets/tiles/basic2/" + std::to_string( i ) + ".png" ) )
           
 std::cout << "błąd wczytywania maski: " << i << "\n";
       
   
}
   
   
std::cout << "Wczytano maski\n";
   
   
std::vector < SingleTexture * > tiles = getSingleTextures( "tiles/tile_" );
   
std::cout << "Tiles: " << tiles.size() << "\n";
   
   
// Finalna tekstura 2816x2816
   
unsigned int newWidth = 2816;
   
unsigned int newHeight = 2816;
   
unsigned int tilesPerRow = newWidth / 64; // 44 kafelki na wiersz
   
sf::Image tile_set_image;
   
tile_set_image.create( newWidth, newHeight, sf::Color::Transparent );
   
   
sf::Image first_tile, second_tile, mask, result_tile;
   
first_tile.create( 64, 64 );
   
second_tile.create( 64, 64 );
   
mask.create( 64, 64 );
   
result_tile.create( 64, 64 );
   
   
unsigned int tileIndex = 0; // Licznik kafelków
   
   
for( short tile_1_id = 0; tile_1_id < 11; tile_1_id++ ) {
       
first_tile = tiles[ tile_1_id ]->texture->copyToImage();
       
       
for( short tile_2_id = 0; tile_2_id < 11; tile_2_id++ ) {
           
second_tile = tiles[ tile_2_id ]->texture->copyToImage();
           
           
for( short mask_id = 0; mask_id < 16; mask_id++ ) {
               
mask = masks[ mask_id ];
               
               
// Generowanie kafelka
               
for( unsigned int y = 0; y < 64; y++ ) {
                   
for( unsigned int x = 0; x < 64; x++ ) {
                       
sf::Color pixel = mask.getPixel( x, y );
                       
                       
if( pixel.r == 237 && pixel.g == 28 && pixel.b == 36 ) {
                           
result_tile.setPixel( x, y, first_tile.getPixel( x, y ) );
                       
}
                       
else if( pixel.r == 127 && pixel.g == 127 && pixel.b == 127 ) {
                           
result_tile.setPixel( x, y, second_tile.getPixel( x, y ) );
                       
}
                       
else {
                           
result_tile.setPixel( x, y, pixel );
                       
}
                    }
                }
               
               
// Obliczanie pozycji w finalnej teksturze
               
unsigned int newX =( tileIndex % tilesPerRow ) * 64;
               
unsigned int newY =( tileIndex / tilesPerRow ) * 64;
               
               
if( newY >= newHeight ) {
                   
std::cerr << "Za dużo kafelków! Przekracza rozmiar 2816x2816." << std::endl;
                   
return;
               
}
               
               
tile_set_image.copy( result_tile, newX, newY );
               
tileIndex++;
           
}
        }
    }
   
   
tile_set_image.saveToFile( "assets/tiles/tile_set_final.png" ); }
P-182178
tBane
Temat założony przez niniejszego użytkownika
» 2025-03-21 17:39:18
Wiele kafelków się powtarza. Spróbuję wyeliminować powtórzenia.
P-182179
tBane
Temat założony przez niniejszego użytkownika
» 2025-03-21 20:02:25
Udało się. Wyeliminowałem powtórzenia w tilesecie


C/C++
void generateTileSet() {
   
sf::Image masks[ 16 ];
   
   
for( int i = 0; i < 16; i++ ) {
       
masks[ i ].create( 64, 64 );
       
if( !masks[ i ].loadFromFile( "assets/tiles/basic2/" + std::to_string( i ) + ".png" ) ) {
           
std::cout << "Błąd wczytywania maski: " << i << "\n";
           
return;
       
}
    }
   
   
std::cout << "Wczytano maski\n";
   
   
std::vector < SingleTexture * > tiles = getSingleTextures( "tiles/tile_" );
   
std::cout << "Tiles: " << tiles.size() << "\n";
   
   
unsigned int N = tiles.size();
   
unsigned int M = 14; // Liczba masek
   
unsigned int totalTiles =( N *( N - 1 ) / 2 ) * M;
   
   
// Obliczanie wymiarów wynikowej tekstury
   
unsigned int tileSize = 64;
   
unsigned int tilesPerRow = std::ceil( std::sqrt( totalTiles ) ); // Najbardziej kwadratowy układ
   
unsigned int rows =( totalTiles + tilesPerRow - 1 ) / tilesPerRow;
   
   
sf::Image tile_set_image;
   
tile_set_image.create( tilesPerRow * tileSize, rows * tileSize, sf::Color::Transparent );
   
   
sf::Image first_tile, second_tile, mask, result_tile;
   
first_tile.create( tileSize, tileSize );
   
second_tile.create( tileSize, tileSize );
   
result_tile.create( tileSize, tileSize );
   
   
// Na początku zapiszemy bazowe kafelki, by się nie powtarzały
   
unsigned int tileIndex = 0;
   
   
for( short tile_id = 0; tile_id < N; tile_id++ ) {
       
unsigned int newX =( tileIndex % tilesPerRow ) * tileSize;
       
unsigned int newY =( tileIndex / tilesPerRow ) * tileSize;
       
       
tile_set_image.copy( tiles[ tile_id ]->texture->copyToImage(), newX, newY );
       
tileIndex++;
   
}
   
   
// Teraz generujemy przejściowe kafelki
   
for( short tile_1_id = 0; tile_1_id < N; tile_1_id++ ) {
       
for( short tile_2_id = tile_1_id + 1; tile_2_id < N; tile_2_id++ ) {
           
first_tile = tiles[ tile_1_id ]->texture->copyToImage();
           
second_tile = tiles[ tile_2_id ]->texture->copyToImage();
           
           
for( short mask_id = 1; mask_id < 15; mask_id++ ) { // Pomiń 0 i 15
               
mask = masks[ mask_id ];
               
               
for( unsigned int y = 0; y < tileSize; y++ ) {
                   
for( unsigned int x = 0; x < tileSize; x++ ) {
                       
sf::Color pixel = mask.getPixel( x, y );
                       
                       
if( pixel.r == 237 && pixel.g == 28 && pixel.b == 36 ) {
                           
result_tile.setPixel( x, y, first_tile.getPixel( x, y ) );
                       
}
                       
else if( pixel.r == 127 && pixel.g == 127 && pixel.b == 127 ) {
                           
result_tile.setPixel( x, y, second_tile.getPixel( x, y ) );
                       
}
                       
else {
                           
result_tile.setPixel( x, y, pixel );
                       
}
                    }
                }
               
               
unsigned int newX =( tileIndex % tilesPerRow ) * tileSize;
               
unsigned int newY =( tileIndex / tilesPerRow ) * tileSize;
               
               
if( newY >= rows * tileSize ) {
                   
std::cerr << "Za dużo kafelków! Przekracza rozmiar tekstury.\n";
                   
return;
               
}
               
               
tile_set_image.copy( result_tile, newX, newY );
               
tileIndex++;
           
}
        }
    }
   
   
// Zapisujemy obraz do pliku
   
tile_set_image.saveToFile( "assets/tiles/tile_set_final.png" );
   
std::cout << "Zapisano tile_set_final.png\n";
}
P-182180
tBane
Temat założony przez niniejszego użytkownika
» 2025-03-21 22:26:20
Chyba są rozmieszczone regularnie te kafelki z wstępnych obliczeń. Jutro będę próbował umieśćić je w palecie i zobaczymy czy ten autotiling to dobre rozwiązanie.

left-top | top | right-top
11 13 12
25 27 26
39 41 40
53 55 54

11+0 11+2 11+1
11+14 11+16 11+15
11+28 11+30 11+29
11+42 11+44 11+43
P-182181
1 « 2 »
Poprzednia strona Strona 2 z 2