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

RGB i HUE - operacje na palecie kolorów

Ostatnio zmodyfikowano wczoraj o godz. 22:26
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
RGB i HUE - 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?
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
« 1 »
  Strona 1 z 1