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

[SFML 2.X] Grid - pozycjonowanie linii oraz wierzchołków

Ostatnio zmodyfikowano 2025-04-05 18:11
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[SFML 2.X] Grid - pozycjonowanie linii oraz wierzchołków
» 2025-04-04 23:42:51
Witam.
Mam problem z rysowaniem grida. Renderuje go nierówno. Nie wiem co jest tego powodem. Zerknie ktoś na kod?

Obecnie tak działa program:

Sprajt:

C/C++
float screenWidth = 1280;
float screenHeight = 720;

sf::RenderWindow * window = new sf::RenderWindow( sf::VideoMode( int( screenWidth ), int( screenHeight ) ), "THE BAD GRID" );

void drawThickLine( sf::Vector2f start, sf::Vector2f end, float thickness, sf::Color color ) {
   
sf::Vector2f direction = end - start;
   
sf::Vector2f unitDirection = direction / std::sqrt( direction.x * direction.x + direction.y * direction.y );
   
sf::Vector2f normal( - unitDirection.y, unitDirection.x );
   
sf::Vector2f offset =( thickness / 2.f ) * normal;
   
   
sf::Vertex vertices[ 4 ];
   
vertices[ 0 ].position = start + offset;
   
vertices[ 1 ].position = end + offset;
   
vertices[ 2 ].position = end - offset;
   
vertices[ 3 ].position = start - offset;
   
   
for( int i = 0; i < 4; ++i ) {
       
vertices[ i ].color = color;
   
}
   
   
window->draw( vertices, 4, sf::Quads );
}

void render() {
   
float cx = 129; // środek podstawy drzewa
   
float cy = 213; // środek podstawy drzewa
   
   
float scale = 2.0f;
   
   
sf::Texture texture;
   
texture.loadFromFile( "tree9.png" );
   
   
window->clear( sf::Color::Black );
   
   
sf::Sprite spr;
   
spr.setTexture( texture );
   
spr.setOrigin( cx, cy );
   
spr.setScale( scale, scale );
   
spr.setPosition( 0, 0 );
   
window->draw( spr );
   
   
// render grid
   
sf::FloatRect spr_rect = spr.getGlobalBounds();
   
   
sf::Vector2f start, end;
   
for( short x = - spr_rect.width / 2; x <= spr_rect.width / 2; x += 16 ) {
       
start.x = x;
       
start.y = spr_rect.top;
       
end.x = x;
       
end.y = spr_rect.top + spr_rect.height;
       
drawThickLine( start, end, 2, sf::Color( 64, 64, 64 ) );
   
}
   
   
for( short y = spr_rect.top; y <= spr_rect.top + spr_rect.height; y += 16 ) {
       
start.x = spr_rect.left;
       
start.y = y;
       
end.x = spr_rect.left + spr_rect.width;
       
end.y = y;
       
drawThickLine( start, end, 2, sf::Color( 64, 64, 64 ) );
       
       
window->display();
   
}
}
P-182198
tBane
Temat założony przez niniejszego użytkownika
» 2025-04-04 23:56:19
Teraz będzie równo renderować grid, ale nadal nierówno renderuje punkty sf::CircleShape. Później wrzucę kod całego programu.

C/C++
// render grid
sf::FloatRect bounds = spr.getGlobalBounds();

float gridSize = 16.0f;

// linie pionowe
for( float x = bounds.left; x <= bounds.left + bounds.width; x += gridSize ) {
   
sf::Vector2f start( x, bounds.top );
   
sf::Vector2f end( x, bounds.top + bounds.height );
   
drawThickLine( start, end, 1.0f, sf::Color( 64, 64, 64 ) );
}

// linie poziome
for( float y = bounds.top; y <= bounds.top + bounds.height; y += gridSize ) {
   
sf::Vector2f start( bounds.left, y );
   
sf::Vector2f end( bounds.left + bounds.width, y );
   
drawThickLine( start, end, 1.0f, sf::Color( 64, 64, 64 ) );
}

P-182200
tBane
Temat założony przez niniejszego użytkownika
» 2025-04-05 06:19:05
Sterowanie
LPM - dodaj punkst
PPM - usuń punkt

Problem
Nierówno rozmieszczone punkty na siatce .. Ale ważne jest to, że wierzchołki vertices powinny być 2x mniejsze niż globalne współrzędne, gdyż później przenoszę te współrzędne do innego programu o skali 1.0f (obecny program ma skalę 2.0f)

Screenshot

Sprajt Drzewa

Kod
C/C++
void drawThickLine( sf::RenderWindow * window, sf::Vector2f start, sf::Vector2f end, float thickness, sf::Color color ) {
   
sf::Vector2f direction = end - start;
   
sf::Vector2f unitDirection = direction / std::sqrt( direction.x * direction.x + direction.y * direction.y );
   
sf::Vector2f normal( - unitDirection.y, unitDirection.x );
   
sf::Vector2f offset =( thickness / 2.f ) * normal;
   
   
sf::Vertex vertices[ 4 ];
   
vertices[ 0 ].position = start + offset;
   
vertices[ 1 ].position = end + offset;
   
vertices[ 2 ].position = end - offset;
   
vertices[ 3 ].position = start - offset;
   
   
for( int i = 0; i < 4; ++i ) {
       
vertices[ i ].color = color;
   
}
   
   
window->draw( vertices, 4, sf::Quads );
}

void test_grid() {
   
   
float screenWidth = 1280;
   
float screenHeight = 720;
   
   
sf::RenderWindow * window = new sf::RenderWindow( sf::VideoMode( screenWidth, screenHeight ), "test grid" );
   
   
sf::Texture texture;
   
texture.loadFromFile( "tree9.png" );
   
   
// tree params
   
float tree_height = 185;
   
float cx = 129; // środek podstawy pnia drzewa
   
float cy = 213;
   
   
std::vector < sf::Vector2f > vertices;
   
   
while( window->isOpen() ) {
       
       
sf::Vector2i mousePosition = sf::Mouse::getPosition( * window ); // Pobierz aktualną pozycję myszy względem bieżącego okna
       
sf::Vector2f worldMousePosition = window->mapPixelToCoords( mousePosition );
       
       
// EVENTS
       
sf::Event event;
       
while( window->pollEvent( event ) ) {
           
           
if( event.type == sf::Event::Closed ) {
               
window->close();
           
}
           
           
if( event.type == sf::Event::MouseButtonPressed ) {
               
if( event.mouseButton.button == sf::Mouse::Left ) {
                   
                   
                   
                   
                   
sf::Vector2f position;
                   
position.x =( int( worldMousePosition.x ) / 16 ) * 16;
                   
position.y =( int( worldMousePosition.y ) / 16 ) * 16;
                   
                   
bool pointExists = false;
                   
                   
for( auto & v: mesh_to_edit_vertices ) {
                       
if( abs( v.x - position.x ) < 16.0f && abs( v.y - position.y ) < 16.0f )
                           
 pointExists = true;
                       
                   
}
                   
                   
if( !pointExists ) {
                       
sf::Vector2f p = sf::Vector2f( position.x / 2, position.y / 2 );
                       
vertices.push_back( p );
                       
std::cout << "added point " << position.x << ", " << position.y << "\n";
                   
}
                   
                }
               
else if( event.mouseButton.button == sf::Mouse::Right ) {
                   
sf::Vector2f position;
                   
position.x =( int( worldMousePosition.x ) / 16 ) * 16;
                   
position.y =( int( worldMousePosition.y ) / 16 ) * 16;
                   
sf::Vector2f p = sf::Vector2f( position.x / 2, position.y / 2 );
                   
                   
auto v = std::find( vertices.begin(), vertices.end(), p );
                   
                   
if( v != vertices.end() ) {
                       
vertices.erase( v );
                       
std::cout << "delete point " << position.x << ", " << position.y << "\n";
                   
}
                   
                }
            }
        }
       
       
       
// RENDER
       
sf::View view;
       
view.setSize( sf::Vector2f( screenWidth, screenHeight ) );
       
view.setCenter( sf::Vector2f( 0, - tree_height ) );
       
window->setView( view );
       
       
float scale = 2.0f;
       
       
window->clear( sf::Color::Black );
       
       
sf::Sprite spr;
       
spr.setTexture( texture );
       
spr.setOrigin( cx, cy );
       
spr.setScale( scale, scale );
       
spr.setPosition( 0, 0 );
       
window->draw( spr );
       
       
// render grid
       
sf::FloatRect bounds = spr.getGlobalBounds();
       
       
float gridSize = 16.0f;
       
       
// linie pionowe
       
for( float x = bounds.left; x <= bounds.left + bounds.width; x += gridSize ) {
           
sf::Vector2f start( x, bounds.top );
           
sf::Vector2f end( x, bounds.top + bounds.height );
           
drawThickLine( window, start, end, 1.0f, sf::Color( 64, 64, 64 ) );
       
}
       
       
// linie poziome
       
for( float y = bounds.top; y <= bounds.top + bounds.height; y += gridSize ) {
           
sf::Vector2f start( bounds.left, y );
           
sf::Vector2f end( bounds.left + bounds.width, y );
           
drawThickLine( window, start, end, 1.0f, sf::Color( 64, 64, 64 ) );
       
}
       
       
for( auto & v: vertices ) {
           
sf::CircleShape point( 4.0f );
           
point.setFillColor( sf::Color::Blue );
           
point.setOrigin( 4.0f, 4.0f );
           
point.setScale( 1.0f, 1.0f );
           
point.setPosition( v.x * scale, v.y * scale );
           
window->draw( point );
       
}
       
       
sf::CircleShape cursor( 4.0f );
       
cursor.setFillColor( sf::Color::Magenta );
       
cursor.setOrigin( 4.0f, 4.0f );
       
cursor.setScale( 1.0f, 1.0f );
       
sf::Vector2f pos( int( worldMousePosition.x ) / 16 * 16, int( worldMousePosition.y ) / 16 * 16 );
       
cursor.setPosition( pos );
       
       
window->display();
   
}
}
P-182202
nanoant20
» 2025-04-05 12:03:39
może program jest technicznie poprawny, ale warto przyjrzeć się i sprawdzić dokładność obliczeń:
jest:
for( float x = bounds.left; x <= bounds.left + bounds.width; x += gridSize )

do iteracji używasz typu float co może prowadzić do błędów zaokrągleń. Dla pewności dodałbym epsilon
C/C++
const float epsilon = 0.0001f; // możesz dostosować wartość
for( float x = bounds.left; std::abs( x -( bounds.left + bounds.width ) ) > epsilon; x += gridSize )

// może prowadzić do błędów, szczególnie w przypadku bardzo małych różnic między nimi

if( abs( v.x - position.x ) < 16.0f && abs( v.y - position.y ) < 16.0f )

// zamiast abs może lepiej użyj fabs i epsilon

   
 if( fabs( v.x - position.x ) < 16.0f + epsilon ...
P-182203
tBane
Temat założony przez niniejszego użytkownika
» 2025-04-05 17:10:17
Dla zmiennych cx, cy, tree_height podzielnych przez 16 program działa poprawnie.

P-182207
tBane
Temat założony przez niniejszego użytkownika
» 2025-04-05 18:11:10
Ok. Zrobione ale ... już zrozumiałem swój błąd. Nie da się wyrównać siatki tak jak chciałem.

C/C++
void drawThickLine( sf::RenderWindow * window, sf::Vector2f start, sf::Vector2f end, float thickness, sf::Color color ) {
   
sf::Vector2f direction = end - start;
   
sf::Vector2f unitDirection = direction / std::sqrt( direction.x * direction.x + direction.y * direction.y );
   
sf::Vector2f normal( - unitDirection.y, unitDirection.x );
   
sf::Vector2f offset =( thickness / 2.f ) * normal;
   
   
sf::Vertex vertices[ 4 ];
   
vertices[ 0 ].position = start + offset;
   
vertices[ 1 ].position = end + offset;
   
vertices[ 2 ].position = end - offset;
   
vertices[ 3 ].position = start - offset;
   
   
for( int i = 0; i < 4; ++i ) {
       
vertices[ i ].color = color;
   
}
   
   
window->draw( vertices, 4, sf::Quads );
}

void test_grid() {
   
   
float screenWidth = 1280;
   
float screenHeight = 720;
   
   
sf::RenderWindow * window = new sf::RenderWindow( sf::VideoMode( screenWidth, screenHeight ), "test grid" );
   
   
sf::Texture texture;
   
texture.loadFromFile( "assets/natures/tree9.png" );
   
   
// tree params
   
float tree_height = 185 / 16 * 16;
   
float cx = 129 / 16 * 16; // środek podstawy pnia drzewa
   
float cy = 213 / 16 * 16;
   
   
std::vector < sf::Vector2f > vertices;
   
   
while( window->isOpen() ) {
       
       
sf::Vector2i mousePosition = sf::Mouse::getPosition( * window ); // Pobierz aktualną pozycję myszy względem bieżącego okna
       
sf::Vector2f worldMousePosition = window->mapPixelToCoords( mousePosition );
       
       
// EVENTS
       
sf::Event event;
       
while( window->pollEvent( event ) ) {
           
           
if( event.type == sf::Event::Closed ) {
               
window->close();
           
}
           
           
if( event.type == sf::Event::MouseButtonPressed ) {
               
if( event.mouseButton.button == sf::Mouse::Left ) {
                   
                   
sf::Vector2f position;
                   
position.x =( int( worldMousePosition.x ) / 16 ) * 16;
                   
position.y =( int( worldMousePosition.y ) / 16 ) * 16;
                   
                   
bool pointExists = false;
                   
                   
for( auto & v: mesh_to_edit_vertices ) {
                       
if( abs( v.x - position.x ) < 16 && abs( v.y - position.y ) < 16 )
                           
 pointExists = true;
                       
                   
}
                   
                   
if( !pointExists ) {
                       
sf::Vector2f p = sf::Vector2f( position.x / 2, position.y / 2 );
                       
vertices.push_back( p );
                       
std::cout << "added point " << position.x << ", " << position.y << "\n";
                   
}
                }
               
else if( event.mouseButton.button == sf::Mouse::Right ) {
                   
sf::Vector2f position;
                   
position.x =( int( worldMousePosition.x ) / 16 ) * 16;
                   
position.y =( int( worldMousePosition.y ) / 16 ) * 16;
                   
sf::Vector2f p = sf::Vector2f( position.x / 2, position.y / 2 );
                   
                   
auto v = std::find( vertices.begin(), vertices.end(), p );
                   
                   
if( v != vertices.end() ) {
                       
vertices.erase( v );
                       
std::cout << "delete point " << position.x << ", " << position.y << "\n";
                   
}
                   
                }
            }
        }
       
       
       
// RENDER
       
sf::View view;
       
view.setSize( sf::Vector2f( screenWidth, screenHeight ) );
       
view.setCenter( sf::Vector2f( 0, - tree_height ) );
       
window->setView( view );
       
       
float scale = 2.0f;
       
       
window->clear( sf::Color::Black );
       
       
sf::Sprite spr;
       
spr.setTexture( texture );
       
spr.setOrigin( cx, cy );
       
spr.setScale( scale, scale );
       
spr.setPosition( 0, 0 );
       
window->draw( spr );
       
       
// render grid
       
sf::FloatRect bounds = spr.getGlobalBounds();
       
       
float gridSize = 16.0f;
       
sf::Vector2u tex_size = texture.getSize();
       
// linie pionowe
       
for( float x = bounds.left; x <= bounds.left + bounds.width; x += gridSize ) {
           
sf::Vector2f start( x, bounds.top );
           
sf::Vector2f end( x, bounds.top + bounds.height );
           
drawThickLine( window, start, end, 1.0f, sf::Color( 64, 64, 64 ) );
       
}
       
       
// linie poziome
       
for( float y = bounds.top; y <= bounds.top + bounds.height; y += gridSize ) {
           
sf::Vector2f start( bounds.left, y );
           
sf::Vector2f end( bounds.left + bounds.width, y );
           
drawThickLine( window, start, end, 1.0f, sf::Color( 64, 64, 64 ) );
       
}
       
       
for( auto & v: vertices ) {
           
sf::CircleShape point( 4.0f );
           
point.setFillColor( sf::Color::Blue );
           
point.setOrigin( 4.0f, 4.0f );
           
point.setPosition( v.x * scale, v.y * scale );
           
window->draw( point );
       
}
       
       
sf::CircleShape cursor( 4.0f );
       
cursor.setFillColor( sf::Color::Magenta );
       
cursor.setOrigin( 4.0f, 4.0f );
       
cursor.setScale( 1.0f, 1.0f );
       
sf::Vector2f pos( int( worldMousePosition.x ) / 16 * 16, int( worldMousePosition.y ) / 16 * 16 );
       
cursor.setPosition( pos );
       
window->draw( cursor );
       
       
window->display();
   
}
}
P-182208
« 1 »
  Strona 1 z 1