Ostatnio zmodyfikowano wczoraj o godz. 19:55
tBane Temat założony przez niniejszego użytkownika |
[SFML 2.X] Narzędzie Lasso z użyciem sf::ConvexShape » 2025-08-28 14:14:03 Witam. Próbuję napisać narzędzie Lasso. Narzędzie to ma działać w taki sposób, że można zaznaczać przy jego użyciu dowolny kształt poprzez przesuwanie kursora z naciśniętym lewym przyciskiem myszy. Narzędzie działa poprawnie dla większej ilości punktów, ale przy małej ilości punktów się wykrzacza. Dlaczego ? zarysowany cały kształt  tu także więc jest ok  a tu dopiero co zacząłem zaznaczać w lewo w dół i się wykrzaczyło  #ifndef Lasso_hpp #define Lasso_hpp
enum class LassoState { None, Selecting, Selected, Moving };
class Lasso { public: LassoState state; std::vector < sf::Vector2f > points; sf::ConvexShape outline; Lasso() { state = LassoState::None; points.clear(); outline = sf::ConvexShape(); outline.setOutlineColor( sf::Color::Cyan ); outline.setOutlineThickness( 2.0f ); outline.setFillColor( sf::Color::Transparent ); } ~Lasso() { } void addPoint( sf::Vector2f p ) { if( points.empty() || sqrt( pow( points.back().x - p.x, 2 ) + pow( points.back().y - p.y, 2 ) ) > 4.0f ) { points.push_back( p ); outline.setPointCount( points.size() ); outline.setPoint( points.size() - 1, p ); } } void draw() { if( outline.getPointCount() > 2 ) window->draw( outline ); else { } } };
Lasso * lasso = nullptr; #endif
|
|
DejaVu |
» 2025-08-28 16:01:50 A czy przeczytałeś czy dozwolone jest tworzenie kształtu, gdzie 'obwódka' rysowana się przecina sama ze sobą? np. jeżeli liczbę 8 chciałbyś narysować. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-08-28 16:13:34 No właśnie nie wiem, ale wtedy też się wykrzacza. Czyli co, zastąpić sf::ConvexShape? Tylko czym?  |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-08-28 18:36:06 Dobra. Zrobię to z użyciem sf::VertexArray(sf::LineStrip);. Pomęczę ChatGPT z shaderami na obwódkę (właśnie dlatego chciałem użyć sf::ConvexShape) i dam znać czy się udało |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-08-28 19:00:30 Mam taki kod. Ale czasem przesuwa krawędzie .. #include <SFML/Graphics.hpp> #include <vector> #include <cmath>
std::string lasso_image_width_outline_source = R"(
uniform sampler2D texture;
uniform sampler2D mask;
uniform vec2 maskSize;
uniform float outlineSize;
uniform vec4 outlineColor;
void main() {
vec2 uv = gl_TexCoord[0].xy;
vec2 muv = uv;
muv.y = 1.0 - muv.y;
vec4 base = texture2D(texture, uv);
float aCenter = texture2D(mask, muv).a;
vec2 texel = 1.0 / maskSize;
int r = int(floor(outlineSize + 0.5));
float aMax = 0.0;
float aMin = 1.0;
for (int j = -r; j <= r; ++j) {
for (int i = -r; i <= r; ++i) {
vec2 off = vec2(float(i), float(j)) * texel;
float s = texture2D(mask, muv + off).a;
aMax = max(aMax, s);
aMin = min(aMin, s);
}
}
float dilated = step(0.5, aMax);
float eroded = step(0.5, aMin);
float edge = clamp(dilated - eroded, 0.0, 1.0);
vec4 masked = vec4(base.rgb, base.a * aCenter);
vec3 outRGB = mix(masked.rgb, outlineColor.rgb, edge * outlineColor.a);
float outA = max(masked.a, edge * outlineColor.a);
gl_FragColor = vec4(outRGB, outA);
}
)";
std::string lasso_only_outline_source = R"(
uniform sampler2D mask;
uniform vec2 maskSize;
uniform float outlineSize;
uniform vec4 outlineColor;
void main() {
vec2 uv = gl_TexCoord[0].xy;
float aCenter = texture2D(mask, uv).a;
vec2 texel = 1.0 / maskSize;
int r = int(floor(outlineSize + 0.5));
float aMax = 0.0;
float aMin = 1.0;
for (int j = -r; j <= r; ++j) {
for (int i = -r; i <= r; ++i) {
vec2 off = vec2(float(i), float(j)) * texel;
float s = texture2D(mask, uv + off).a;
aMax = max(aMax, s);
aMin = min(aMin, s);
}
}
float dilated = step(0.5, aMax);
float eroded = step(0.5, aMin);
float edge = clamp(dilated - eroded, 0.0, 1.0);
gl_FragColor = vec4(outlineColor.rgb, outlineColor.a * edge);
}
)";
sf::RenderWindow * window;
sf::Texture texture; sf::Sprite sprite;
sf::RenderTexture mask; sf::Sprite maskSprite;
sf::Shader shader1; sf::Shader shader2;
std::vector < sf::Vector2f > points; sf::VertexArray outline;
bool pointInPolygon( std::vector < sf::Vector2f > & points, sf::Vector2f p ) { bool inside = false; for( int i = 0, j = points.size() - 1; i < points.size(); j = i++ ) { sf::Vector2f A = points[ i ]; sf::Vector2f B = points[ j ]; bool inter =(( A.y > p.y ) !=( B.y > p.y ) ) &&( p.x <( B.x - A.x ) *( p.y - A.y ) /( B.y - A.y ) + A.x ); if( inter ) inside = !inside; } return inside; }
void pushPoint( sf::Vector2f p, std::vector < sf::Vector2f > & points, sf::VertexArray & outline ) { if( points.empty() || std::hypot( points.back().x - p.x, points.back().y - p.y ) > 2.0f ) { points.push_back( p ); outline.append( sf::Vertex( p, sf::Color::Cyan ) ); } }
void generateImage( std::vector < sf::Vector2f > points ) { if( points.size() < 3 ) return; sf::Vector2f centroid( 0.f, 0.f ); for( auto & p: points ) centroid += p; centroid.x /= points.size(); centroid.y /= points.size(); sf::VertexArray fan( sf::TriangleFan ); fan.append( sf::Vertex( centroid, sf::Color::White ) ); for( auto & p: points ) fan.append( sf::Vertex( p, sf::Color::White ) ); fan.append( sf::Vertex( points.front(), sf::Color::White ) ); mask.clear( sf::Color::Transparent ); mask.draw( fan, sf::RenderStates( sf::BlendNone ) ); mask.display(); shader1.setUniform( "mask", mask.getTexture() ); }
void generateOutline( std::vector < sf::Vector2f > points ) { if( points.size() < 3 ) return; sf::Vector2f centroid( 0.f, 0.f ); for( auto & p: points ) centroid += p; centroid.x /= points.size(); centroid.y /= points.size(); sf::VertexArray fan( sf::TrianglesFan ); fan.append( sf::Vertex( centroid, sf::Color::White ) ); for( auto & p: points ) fan.append( sf::Vertex( p, sf::Color::White ) ); fan.append( sf::Vertex( points.front(), sf::Color::White ) ); mask.clear( sf::Color::Transparent ); mask.draw( fan, sf::RenderStates( sf::BlendNone ) ); mask.display(); shader2.setUniform( "mask", mask.getTexture() ); }
int main() { window = new sf::RenderWindow( sf::VideoMode( 1000, 600 ), "Lasso" ); texture.loadFromFile( "image.png" ); sprite = sf::Sprite( texture ); mask.create( texture.getSize().x, texture.getSize().y ); mask.clear( sf::Color::Transparent ); mask.display(); maskSprite = sf::Sprite( mask.getTexture() ); shader1.loadFromMemory( lasso_image_width_outline_source, sf::Shader::Fragment ); shader1.setUniform( "texture", texture ); shader1.setUniform( "mask", mask.getTexture() ); shader1.setUniform( "maskSize", sf::Glsl::Vec2( mask.getSize().x, mask.getSize().y ) ); shader1.setUniform( "outlineSize", 1.f ); shader1.setUniform( "outlineColor", sf::Glsl::Vec4( 0, 1, 1, 1 ) ); shader2.loadFromMemory( lasso_only_outline_source, sf::Shader::Fragment ); shader2.setUniform( "maskSize", sf::Glsl::Vec2( mask.getSize().x, mask.getSize().y ) ); shader2.setUniform( "outlineSize", 1.f ); shader2.setUniform( "outlineColor", sf::Glsl::Vec4( 0, 1, 1, 1 ) ); points.clear(); bool drawing = false; outline = sf::VertexArray( sf::LineStrip ); while( window->isOpen() ) { sf::Vector2i mousePosition = sf::Mouse::getPosition( * window ); sf::Vector2f worldMousePosition = window->mapPixelToCoords( mousePosition ); sf::Event ev; while( window->pollEvent( ev ) ) { if( ev.type == sf::Event::Closed ) window->close(); if( ev.type == sf::Event::MouseButtonPressed && ev.mouseButton.button == sf::Mouse::Left ) { drawing = true; points.clear(); outline.clear(); pushPoint( worldMousePosition, points, outline ); } if( ev.type == sf::Event::MouseMoved && drawing ) { pushPoint( worldMousePosition, points, outline ); generateOutline( points ); } if( ev.type == sf::Event::MouseButtonReleased && ev.mouseButton.button == sf::Mouse::Left ) { drawing = false; generateImage( points ); } if( ev.type == sf::Event::KeyPressed && ev.key.code == sf::Keyboard::C ) { mask.clear( sf::Color::Transparent ); mask.display(); shader1.setUniform( "mask", mask.getTexture() ); points.clear(); outline.clear(); } } window->clear( sf::Color( 30, 30, 34 ) ); if( !drawing && outline.getVertexCount() >= 3 ) { sf::RenderStates rs; rs.shader = & shader1; window->draw( sprite, rs ); } if( drawing && outline.getVertexCount() >= 3 ) { sf::RenderStates rs; rs.shader = & shader2; window->draw( maskSprite, rs ); } window->display(); } return 0; }
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-08-28 19:55:49 Dobra. Udało sie napisać. Obwódka to sf::VertexArray fan( sf::LineStrip ); a obraz to sf::VertexArray fan( sf::TriangleFan ); #include <SFML/Graphics.hpp> #include <vector> #include <cmath>
std::string lasso_image_width_outline_source = R"(
uniform sampler2D texture;
uniform sampler2D mask;
uniform vec2 maskSize;
uniform float outlineSize;
uniform vec4 outlineColor;
void main() {
vec2 uv = gl_TexCoord[0].xy;
vec2 muv = uv;
muv.y = 1.0 - muv.y;
vec4 base = texture2D(texture, uv);
float aCenter = texture2D(mask, muv).a;
vec2 texel = 1.0 / maskSize;
int r = int(floor(outlineSize + 0.5));
float aMax = 0.0;
float aMin = 1.0;
for (int j = -r; j <= r; ++j) {
for (int i = -r; i <= r; ++i) {
vec2 off = vec2(float(i), float(j)) * texel;
float s = texture2D(mask, muv + off).a;
aMax = max(aMax, s);
aMin = min(aMin, s);
}
}
float dilated = step(0.5, aMax);
float eroded = step(0.5, aMin);
float edge = clamp(dilated - eroded, 0.0, 1.0);
vec4 masked = vec4(base.rgb, base.a * aCenter);
vec3 outRGB = mix(masked.rgb, outlineColor.rgb, edge * outlineColor.a);
float outA = max(masked.a, edge * outlineColor.a);
gl_FragColor = vec4(outRGB, outA);
}
)";
std::string lasso_only_outline_source = R"(
uniform sampler2D mask;
uniform vec2 maskSize;
uniform float outlineSize;
uniform vec4 outlineColor;
void main() {
vec2 uv = gl_TexCoord[0].xy;
float aCenter = texture2D(mask, uv).a;
vec2 texel = 1.0 / maskSize;
int r = int(floor(outlineSize + 0.5));
float aMax = 0.0;
float aMin = 1.0;
for (int j = -r; j <= r; ++j) {
for (int i = -r; i <= r; ++i) {
vec2 off = vec2(float(i), float(j)) * texel;
float s = texture2D(mask, uv + off).a;
aMax = max(aMax, s);
aMin = min(aMin, s);
}
}
float dilated = step(0.5, aMax);
float eroded = step(0.5, aMin);
float edge = clamp(dilated - eroded, 0.0, 1.0);
gl_FragColor = vec4(outlineColor.rgb, outlineColor.a * edge);
}
)";
sf::RenderWindow * window;
sf::Texture texture; sf::Sprite sprite;
sf::RenderTexture mask; sf::Sprite maskSprite;
sf::Shader shader1; sf::Shader shader2;
std::vector < sf::Vector2f > points; sf::VertexArray outline;
bool pointInPolygon( std::vector < sf::Vector2f > & points, sf::Vector2f p ) { bool inside = false; for( int i = 0, j = points.size() - 1; i < points.size(); j = i++ ) { sf::Vector2f A = points[ i ]; sf::Vector2f B = points[ j ]; bool inter =(( A.y > p.y ) !=( B.y > p.y ) ) &&( p.x <( B.x - A.x ) *( p.y - A.y ) /( B.y - A.y ) + A.x ); if( inter ) inside = !inside; } return inside; }
void pushPoint( sf::Vector2f p, std::vector < sf::Vector2f > & points, sf::VertexArray & outline ) { if( points.empty() || std::hypot( points.back().x - p.x, points.back().y - p.y ) > 2.0f ) { points.push_back( p ); outline.append( sf::Vertex( p, sf::Color::Cyan ) ); } }
void generateImage( std::vector < sf::Vector2f > points ) { if( points.size() < 3 ) return; sf::Vector2f centroid( 0.f, 0.f ); for( auto & p: points ) centroid += p; centroid.x /= points.size(); centroid.y /= points.size(); sf::VertexArray fan( sf::TriangleFan ); fan.append( sf::Vertex( centroid, sf::Color::White ) ); for( auto & p: points ) fan.append( sf::Vertex( p, sf::Color::White ) ); fan.append( sf::Vertex( points.front(), sf::Color::White ) ); mask.clear( sf::Color::Transparent ); mask.draw( fan, sf::RenderStates( sf::BlendNone ) ); mask.display(); shader1.setUniform( "mask", mask.getTexture() ); }
void generateOutline( std::vector < sf::Vector2f > points ) { if( points.size() < 3 ) return; sf::VertexArray fan( sf::LineStrip ); for( auto & p: points ) fan.append( sf::Vertex( p, sf::Color::White ) ); mask.clear( sf::Color::Transparent ); mask.draw( fan, sf::RenderStates( sf::BlendNone ) ); mask.display(); shader2.setUniform( "mask", mask.getTexture() ); }
int main() { window = new sf::RenderWindow( sf::VideoMode( 1000, 600 ), "Lasso" ); texture.loadFromFile( "image.png" ); sprite = sf::Sprite( texture ); mask.create( texture.getSize().x, texture.getSize().y ); mask.clear( sf::Color::Transparent ); mask.display(); maskSprite = sf::Sprite( mask.getTexture() ); shader1.loadFromMemory( lasso_image_width_outline_source, sf::Shader::Fragment ); shader1.setUniform( "texture", texture ); shader1.setUniform( "mask", mask.getTexture() ); shader1.setUniform( "maskSize", sf::Glsl::Vec2( mask.getSize().x, mask.getSize().y ) ); shader1.setUniform( "outlineSize", 1.f ); shader1.setUniform( "outlineColor", sf::Glsl::Vec4( 0, 1, 1, 1 ) ); shader2.loadFromMemory( lasso_only_outline_source, sf::Shader::Fragment ); shader2.setUniform( "maskSize", sf::Glsl::Vec2( mask.getSize().x, mask.getSize().y ) ); shader2.setUniform( "outlineSize", 1.f ); shader2.setUniform( "outlineColor", sf::Glsl::Vec4( 0, 1, 1, 1 ) ); points.clear(); bool drawing = false; outline = sf::VertexArray( sf::LineStrip ); while( window->isOpen() ) { sf::Vector2i mousePosition = sf::Mouse::getPosition( * window ); sf::Vector2f worldMousePosition = window->mapPixelToCoords( mousePosition ); sf::Event ev; while( window->pollEvent( ev ) ) { if( ev.type == sf::Event::Closed ) window->close(); if( ev.type == sf::Event::MouseButtonPressed && ev.mouseButton.button == sf::Mouse::Left ) { drawing = true; points.clear(); outline.clear(); pushPoint( worldMousePosition, points, outline ); } if( ev.type == sf::Event::MouseMoved && drawing ) { pushPoint( worldMousePosition, points, outline ); generateOutline( points ); } if( ev.type == sf::Event::MouseButtonReleased && ev.mouseButton.button == sf::Mouse::Left ) { drawing = false; generateImage( points ); } if( ev.type == sf::Event::KeyPressed && ev.key.code == sf::Keyboard::C ) { mask.clear( sf::Color::Transparent ); mask.display(); shader1.setUniform( "mask", mask.getTexture() ); points.clear(); outline.clear(); } } window->clear( sf::Color( 30, 30, 34 ) ); if( !drawing && outline.getVertexCount() >= 3 ) { sf::RenderStates rs; rs.shader = & shader1; window->draw( sprite, rs ); } if( drawing && outline.getVertexCount() >= 3 ) { sf::RenderStates rs; rs.shader = & shader2; window->draw( maskSprite, rs ); } window->display(); } return 0; }
|
|
« 1 » |