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

RGB i HSV - operacje na palecie kolorów

Ostatnio zmodyfikowano 2025-11-13 17:52
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
RGB i HSV - operacje na palecie kolorów
» 2025-11-10 18:46:26
Witam. Posiadam kod na generowanie palety kolorów, który zamieszczam poniżej. Moje pytanie brzmi jak wyznaczyć funkcję odwrotną do RGB->HUE w taki sposób, by zwrócić koordynaty danego piksela.

chodzi o to że jak podamy wartość np. 255, 0, 0 to zwróci nam 0,0.

Czy da się to obliczyć czy lepiej zastosować spradzenie dla każdego piksela ?


kod:
C/C++
std::string palette_colors_shader_source = R"( uniform sampler2D texture; // SFML podstawi teksturę sprite'a uniform vec4 texRectUV; // (u0, v0, u1, v1) – NORMALIZOWANE granice wycinka // --- HSV -> RGB (oficjalne) --- vec3 hsv2rgb(in vec3 c) { vec3 rgb = clamp(abs(mod(c.x*6.0 + vec3(0.0,4.0,2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0); return c.z * mix(vec3(1.0), rgb, c.y); } // --- HSV -> RGB (wygładzone) --- vec3 hsv2rgb_smooth(in vec3 c) { vec3 rgb = clamp(abs(mod(c.x*6.0 + vec3(0.0,4.0,2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0); rgb = rgb * rgb * (3.0 - 2.0 * rgb); return c.z * mix(vec3(1.0), rgb, c.y); } void main() { vec2 uvAtlas = gl_TexCoord[0].xy; vec2 uv = (uvAtlas - texRectUV.xy) / (texRectUV.zw - texRectUV.xy); float hue = fract(uv.x); vec3 hsv = vec3(hue, 1.2 - uv.y, 1.3); vec3 hsvRgb = hsv2rgb_smooth(hsv); gl_FragColor = vec4(hsvRgb, 1.0); } )";

C/C++
#include "Dialogs/Palette.hpp"
#include "Filters.hpp"
#include "Time.hpp"
#include "Window.hpp"
#include "Cursor.hpp"
#include "Tools/Toolbar.hpp"
#include "SFML/Graphics.hpp"
#include "Theme.hpp"

PaletteValues::PaletteValues( sf::Vector2i position, sf::Vector2i size, std::string shader, sf::Color color ) {
   
_shader = sf::Shader();
   
_shader.loadFromMemory( shader, sf::Shader::Type::Fragment );
   
   
////////////////////////////////////////////
   
   
_rect = sf::IntRect( position, size );
   
   
loadTexture( color );
   
   
_state = PaletteState::None;
}

PaletteValues::~PaletteValues() {
   
}

void PaletteValues::loadTexture( sf::Color color ) {
   
// create image && texture
   
sf::Image img;
   
img.resize( sf::Vector2u( _rect.size ), color );
   
   
sf::Texture tex;
   
tex.loadFromImage( img );
   
   
// set the uniforms in shader
   
sf::IntRect r = sf::IntRect( sf::Vector2i( 0, 0 ), sf::Vector2i( tex.getSize().x, tex.getSize().y ) );
   
sf::Vector2u ts = tex.getSize();
   
   
sf::Glsl::Vec4 texRectUV(
   
float( r.position.x ) / ts.x,
   
float( r.position.y ) / ts.y,
   
float( r.position.x + r.size.x ) / ts.x,
   
float( r.position.y + r.size.y ) / ts.y
    );
   
   
_shader.setUniform( "texRectUV", texRectUV );
   
   
// create palette render texture
   
_renderTexture.resize( tex.getSize() );
   
   
sf::Sprite spr( tex );
   
_renderTexture.clear( sf::Color::White );
   
_renderTexture.draw( spr, & _shader );
   
_renderTexture.display();
}

void PaletteValues::setPosition( sf::Vector2i position ) {
   
_rect.position = position;
}

void PaletteValues::cursorHover() {
   
if( _rect.contains( cursor->_worldMousePosition ) ) {
       
ElementGUI_hovered = this->shared_from_this();
   
}
}

void PaletteValues::handleEvent( const sf::Event & event ) {
   
   
if( const auto * mbr = event.getIf < sf::Event::MouseButtonReleased >(); mbr && mbr->button == sf::Mouse::Button::Left ) {
       
_state = PaletteState::None;
       
ElementGUI_pressed = nullptr;
   
}
   
   
if( _rect.contains( cursor->_worldMousePosition ) ) {
       
       
       
if( const auto * mbp = event.getIf < sf::Event::MouseButtonPressed >(); mbp && mbp->button == sf::Mouse::Button::Left ) {
           
_state = PaletteState::Selecting;
           
ElementGUI_pressed = this->shared_from_this();
       
}
       
       
if( const auto * mbp = event.getIf < sf::Event::MouseMoved >(); mbp && sf::Mouse::isButtonPressed( sf::Mouse::Button::Left ) ) {
           
_state = PaletteState::Selecting;
           
ElementGUI_pressed = this->shared_from_this();
       
}
       
       
    }
}

void PaletteValues::update() {
   
if( _state == PaletteState::Selecting ) {
       
_state = PaletteState::Selecting;
       
sf::Image pixels = _renderTexture.getTexture().copyToImage();
       
       
sf::Vector2i pixelPos;
       
pixelPos.x = std::clamp( cursor->_worldMousePosition.x - _rect.position.x, 0, _rect.size.x - 1 );
       
pixelPos.y = std::clamp( cursor->_worldMousePosition.y - _rect.position.y, 0, _rect.size.y - 1 );
       
       
sf::Color color = pixels.getPixel( sf::Vector2u( pixelPos ) );
       
toolbar->_selectedColorButton->setColor( color );
   
}
   
}

void PaletteValues::draw() {
   
sf::Sprite sprite( _renderTexture.getTexture() );
   
sprite.setPosition( sf::Vector2f( _rect.position ) );
   
window->draw( sprite );
}

Palette::Palette()
    :
Dialog( L"Palette", sf::Vector2i( 192 + 24 + 8, dialog_title_rect_height + 192 + basic_text_rect_height + 8 ) )
{
   
   
sf::Vector2i size = sf::Vector2i( sf::Vector2u( sf::Vector2i( 192 - 16, 192 - 16 ) ) );
   
sf::Vector2i position = getContentPosition() + sf::Vector2i( 8, 8 );
   
_hues = std::make_shared < PaletteValues >( position, size, palette_colors_shader_source, sf::Color::White );
   
   
position = sf::Vector2i( _hues->_rect.position + sf::Vector2i( _hues->_rect.size.x + 8, 0 ) );
   
size.x = 24;
   
_values = std::make_shared < PaletteValues >( position, size, palette_values_shader_source, sf::Color::White );
   
   
_r = std::make_unique < sf::Text >( basicFont, L"R", basic_text_size );
   
_g = std::make_unique < sf::Text >( basicFont, L"G", basic_text_size );
   
_b = std::make_unique < sf::Text >( basicFont, L"B", basic_text_size );
   
_r->setFillColor( basic_text_color );
   
_g->setFillColor( basic_text_color );
   
_b->setFillColor( basic_text_color );
   
   
_red = std::make_shared < TextInput >( sf::Vector2i( 32, basic_text_rect_height ), 3, basic_text_size );
   
_green = std::make_shared < TextInput >( sf::Vector2i( 32, basic_text_rect_height ), 3, basic_text_size );
   
_blue = std::make_shared < TextInput >( sf::Vector2i( 32, basic_text_rect_height ), 3, basic_text_size );
   
   
setPosition( _position );
}

Palette::~Palette() {
   
}

void Palette::setPosition( sf::Vector2i position ) {
   
Dialog::setPosition( position );
   
_hues->setPosition( getContentPosition() + sf::Vector2i( 8, 8 ) );
   
_values->setPosition( sf::Vector2i( _hues->_rect.position + sf::Vector2i( _hues->_rect.size.x + 8, 0 ) ) );
   
   
sf::Vector2i textInputsPosistion;
   
textInputsPosistion.x = position.x + 32;
   
textInputsPosistion.y = _values->_rect.position.y + _values->_rect.size.y + 8;
   
   
_red->setPosition( textInputsPosistion );
   
_green->setPosition( textInputsPosistion + sf::Vector2i( 32 * 2, 0 ) );
   
_blue->setPosition( textInputsPosistion + sf::Vector2i( 32 * 4, 0 ) );
   
   
_r->setPosition( sf::Vector2f( _red->getPosition() ) - sf::Vector2f( 16, 0 ) );
   
_g->setPosition( sf::Vector2f( _green->getPosition() ) - sf::Vector2f( 16, 0 ) );
   
_b->setPosition( sf::Vector2f( _blue->getPosition() ) - sf::Vector2f( 16, 0 ) );
}

void Palette::cursorHover() {
   
Dialog::cursorHover();
   
_hues->cursorHover();
   
_values->cursorHover();
   
   
_red->cursorHover();
   
_green->cursorHover();
   
_blue->cursorHover();
}

void Palette::handleEvent( const sf::Event & event ) {
   
Dialog::handleEvent( event );
   
   
_hues->handleEvent( event );
   
_values->handleEvent( event );
   
   
_red->handleEvent( event );
   
_green->handleEvent( event );
   
_blue->handleEvent( event );
}

void Palette::update() {
   
Dialog::update();
   
   
_hues->update();
   
if( _hues->_state == PaletteState::Selecting ) {
       
_values->loadTexture( toolbar->_selectedColorButton->_color );
   
}
   
_values->update();
   
   
_red->update();
   
_green->update();
   
_blue->update();
}

void Palette::draw() {
   
Dialog::draw();
   
_hues->draw();
   
_values->draw();
   
   
_red->draw();
   
_green->draw();
   
_blue->draw();
   
   
window->draw( * _r );
   
window->draw( * _g );
   
window->draw( * _b );
   
}

std::shared_ptr < Palette > palette;
P-183435
pekfos
» 2025-11-10 18:56:52
P-183436
tBane
Temat założony przez niniejszego użytkownika
» 2025-11-10 20:08:05
Ok. dzięki, zobacze może się przyda :-) Bo ChatGPT jakoś zaczął działać, a szczerze mówiąc jestem na etapie na którym nie rozumiem już kodu ...
P-183437
tBane
Temat założony przez niniejszego użytkownika
» 2025-11-10 21:00:59
C/C++
struct HSV { float h, s, v; }; // zakresy 0..1

HSV rgbToHsv( sf::Color c ) {
   
float r = c.r / 255.f, g = c.g / 255.f, b = c.b / 255.f;
   
float mx = std::max( { r, g, b } ), mn = std::min( { r, g, b } );
   
float d = mx - mn;
   
   
float h = 0.f;
   
if( d > 0.f ) {
       
if( mx == r ) h = fmodf(( g - b ) / d, 6.f );
       
else if( mx == g ) h =( b - r ) / d + 2.f;
       
else h =( r - g ) / d + 4.f;
       
       
h /= 6.f;
       
if( h < 0.f ) h += 1.f;
       
   
}
   
float s =( mx == 0.f ) ? 0.f
       
:( d / mx );
   
float v = mx;
   
return { h, s, v };
}

sf::Vector2i cursorOnHues( const sf::IntRect & rectHues, sf::Color rgb ) {
   
HSV hsv = rgbToHsv( rgb );
   
   
float x = std::clamp( hsv.h, 0.f, 1.f ); // H -> x
   
float y = std::clamp( 1.0f - hsv.s, 0.f, 1.f ); // S -> 1 - y
   
   
return sf::Vector2i(
   
rectHues.position.x + x * rectHues.size.x,
   
rectHues.position.y + y * rectHues.size.y
    );
}
P-183438
tBane
Temat założony przez niniejszego użytkownika
» 2025-11-10 21:27:24
Ten shader nie generuje poprawnie palety kolorów. Nie działają wartości skrajne takie jak:
 
255,0,0
255,255,255
0,0,0

Jak myślicie poprawić to czy zostawić tak jak jest?

C/C++
std::string palette_colors_shader_source = R"( uniform sampler2D texture; // SFML podstawi teksturę sprite'a uniform vec4 texRectUV; // (u0, v0, u1, v1) – NORMALIZOWANE granice wycinka // --- HSV -> RGB (oficjalne) --- vec3 hsv2rgb(in vec3 c) { vec3 rgb = clamp(abs(mod(c.x*6.0 + vec3(0.0,4.0,2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0); return c.z * mix(vec3(1.0), rgb, c.y); } // --- HSV -> RGB (wygładzone) --- vec3 hsv2rgb_smooth(in vec3 c) { vec3 rgb = clamp(abs(mod(c.x*6.0 + vec3(0.0,4.0,2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0); rgb = rgb * rgb * (3.0 - 2.0 * rgb); return c.z * mix(vec3(1.0), rgb, c.y); } void main() { vec2 uvAtlas = gl_TexCoord[0].xy; vec2 uv = (uvAtlas - texRectUV.xy) / (texRectUV.zw - texRectUV.xy); float hue = fract(uv.x); vec3 hsv = vec3(hue, 1.0 - uv.y, 1.0); vec3 hsvRgb = hsv2rgb_smooth(hsv); gl_FragColor = vec4(hsvRgb, 1.0); } )";
P-183439
skovv
» 2025-11-10 21:29:42
A nie łatwiej Ci zamiast shadera to wygenerować sobie samemu palete na texturze? A jak chcesz wtedy znaleźć pozycje danego koloru to szukasz na texturze i od razu masz pozycje
P-183440
tBane
Temat założony przez niniejszego użytkownika
» 2025-11-10 22:26:52
No właśnie generuje teksturę ale z użyciem shadera. A obliczanie koloru jest po to, bo nie każdy kolor jest na palecie. Paleta nie przechowuje wszystkich kolorów tylko te które widać, dlatego stosuje obliczanie.
P-183441
pekfos
» 2025-11-11 12:14:57
Co znaczy że nie działają te wartości? Nie wyświetlają się piksele w tych kolorach?

No właśnie generuje teksturę ale z użyciem shadera. A obliczanie koloru jest po to, bo nie każdy kolor jest na palecie. Paleta nie przechowuje wszystkich kolorów tylko te które widać, dlatego stosuje obliczanie.
Przekaż brakującą współrzędną HSV jako uniform do shadera, wtedy paleta będzie miała wszystkie kolory. Widzę po screenie że masz już picker dla wartości V.
P-183443
« 1 » 2 3
  Strona 1 z 3 Następna strona