-
Hello Forum,
I have a brush (CircleShape) and i can draw with it straight to a RenderTexture without any problems.
But now i want to have a Soft Brush like in Photoshop.
So i apply a radial gradient shader to that Brush Circle Shape.
For this i have to set the brush.setFillColor(sf::Color::Transparent);
Now when i do this nothing gets drawn to the RenderTexture anymore although i do:
RT_Layer0.draw(brush, &brush_shader);
RT_Layer0.display();
Since i also do a window.draw(brush, &brush_shader);
I can see the shader correctly applyd to the CircleShape brush.
Iam sure iam missing something here...
Thanks! :)
-
Make sure that your shader doesn't output only fully transparent fragments -- they would disapear with alpha blending when the RT is drawn to the window, but would not have any effect when the shape is drawn directly to the window.
The most efficient way to get help would be to write a complete and minimal code that reproduces the problem, though. Or at least show your fragment shader.
-
This is the shader i use:
const char VertexShader[] =
"void main()"
"{"
"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
"gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;"
"gl_FrontColor = gl_Color;"
"}";
const char RadialGradient[] =
"uniform vec4 color;"
"uniform vec2 center;"
"uniform float radius;"
"uniform float expand;"
"uniform float windowHeight;"
"void main(void)"
"{"
"vec2 centerFromSfml = vec2(center.x, windowHeight - center.y);"
"vec2 p = (gl_FragCoord.xy - centerFromSfml) / radius;"
"float r = sqrt(dot(p, p));"
"if (r < 1.0)"
"{"
"gl_FragColor = mix(color, gl_Color, (r - expand) / (1 - expand));"
"}"
"else"
"{"
"gl_FragColor = gl_Color;"
"}"
"}";
Its from Github https://github.com/SFML/SFML/wiki/Source:-Radial-Gradient-Shader (https://github.com/SFML/SFML/wiki/Source:-Radial-Gradient-Shader)
I think the shader is never completly transparent. But it fades out TO transparent.
When i render to the window i see the shader.
But its not rendered onto the RenderTexture
This is the part where i draw to RT:
brush.setFillColor(sf::Color::Transparent);
brush.setPosition(ML);
sf::Vector2i CTP = window.mapCoordsToPixel(ML); // ML = Mouse Local Coordinates
float multi = ZoomLevel / 100.f;
brush_shader.setUniform("color", sf::Glsl::Vec4(0, 0, 1, 1));
brush_shader.setUniform("center", sf::Vector2f(CTP.x, CTP.y)); // "center" uses Global Coordinates!!
brush_shader.setUniform("radius", brush.getRadius()* multi);
brush_shader.setUniform("expand", 0.25f);
//window.draw(brush);
//brush.setFillColor(ColorBrush);
states.shader = &brush_shader;
if (ToolNow == 0) // Eraser Brush
{
states.blendMode = sf::BlendNone;
if (LayerNR == 0) { RT_Layer0.draw(brush, states); RT_Layer0.display(); }
if (LayerNR == 1) { RT_Layer1.draw(brush, states); RT_Layer1.display(); }
if (LayerNR == 2) { RT_Layer2.draw(brush, states); RT_Layer2.display(); }
if (LayerNR == 3) { RT_Layer3.draw(brush, states); RT_Layer3.display(); }
if (LayerNR == 4) { RT_Layer4.draw(brush, states); RT_Layer4.display(); }
}
if (ToolNow != 0) // Standard Brush
{
states.blendMode = sf::BlendAlpha;
if (LayerNR == 0) { RT_Layer0.draw(brush, &brush_shader); RT_Layer0.display(); } // Shader direct
if (LayerNR == 1) { RT_Layer1.draw(brush, states); RT_Layer1.display(); }
if (LayerNR == 2) { RT_Layer2.draw(brush, states); RT_Layer2.display(); }
if (LayerNR == 3) { RT_Layer3.draw(brush, states); RT_Layer3.display(); }
if (LayerNR == 4) { RT_Layer4.draw(brush, states); RT_Layer4.display(); }
}
...
window.draw(brush, &brush_shader); // <--- This works!
For testing i dont use "states" in "RT_Layer0" but the shader directly.
-
Minimal example which actually works... :o
#include <SFML/Graphics.hpp>
#pragma region Shader
const char VertexShader[] =
"void main()"
"{"
"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
"gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;"
"gl_FrontColor = gl_Color;"
"}";
const char RadialGradient[] =
"uniform vec4 color;"
"uniform vec2 center;"
"uniform float radius;"
"uniform float expand;"
"uniform float windowHeight;"
"void main(void)"
"{"
"vec2 centerFromSfml = vec2(center.x, windowHeight - center.y);"
"vec2 p = (gl_FragCoord.xy - centerFromSfml) / radius;"
"float r = sqrt(dot(p, p));"
"if (r < 1.0)"
"{"
"gl_FragColor = mix(color, gl_Color, (r - expand) / (1 - expand));"
"}"
"else"
"{"
"gl_FragColor = gl_Color;"
"}"
"}";
#pragma endregion
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "Radial Gradient", sf::Style::Default);
sf::Event event;
sf::CircleShape circle;
sf::Shader shader;
circle.setRadius(100.f);
circle.setOrigin(circle.getRadius(), circle.getRadius());
circle.setPosition(sf::Vector2f(window.getSize()) / 2.f);
circle.setFillColor(sf::Color::Transparent);
shader.loadFromMemory(VertexShader, RadialGradient);
shader.setUniform("windowHeight", static_cast<float>(window.getSize().y)); // needs to be set whenever window changes
sf::RenderTexture RT;
RT.create(800, 600);
sf::Sprite SP;
SP.setTexture(RT.getTexture(), true);
while (window.isOpen())
{
while (window.pollEvent(event)) { if (event.type == sf::Event::Closed){ window.close(); }}
shader.setUniform("color", sf::Glsl::Vec4(0, 0, 1, 1));
shader.setUniform("center", circle.getPosition());
shader.setUniform("radius", circle.getRadius());
shader.setUniform("expand", 0.f);
RT.clear();
RT.draw(circle, &shader);
RT.display();
window.clear();
window.draw(SP);
window.display();
//window.draw(circle, &shader);
//window.display();
}
return EXIT_SUCCESS;
}
-
I can draw the shader to a RenderTexture now, but even if the base circle shape is set to transparent
i dont get transparent edges but black ones.
circle.setFillColor(sf::Color::Transparent);
if i set sf::Color
to {1,1,1,0}
i get a white border.
Why is this color picked up when its 100% transparent??
Example:
#include <SFML/Graphics.hpp>
#include <iostream>
#pragma region Shader
const char VertexShader[] =
"void main()"
"{"
"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
"gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;"
"gl_FrontColor = gl_Color;"
"}";
const char RadialGradient[] =
"uniform vec4 color;"
"uniform vec2 center;"
"uniform float radius;"
"uniform float expand;"
"uniform float windowHeight;"
"void main(void)"
"{"
"vec2 centerFromSfml = vec2(center.x, windowHeight - center.y);"
"vec2 p = (gl_FragCoord.xy - centerFromSfml) / radius;"
"float r = sqrt(dot(p, p));"
"if (r < 1.0)"
"{"
"gl_FragColor = mix(color, gl_Color, (r - expand) / (1 - expand));"
"}"
"else"
"{"
"gl_FragColor = gl_Color;"
"}"
"}";
#pragma endregion
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "Radial Gradient", sf::Style::Default);
sf::Event event;
sf::CircleShape circle;
sf::Shader shader;
circle.setRadius(50.f);
circle.setOrigin(circle.getRadius(), circle.getRadius());
circle.setPosition(sf::Vector2f(window.getSize()) / 2.f);
circle.setFillColor(sf::Color::Transparent);
shader.loadFromMemory(VertexShader, RadialGradient);
shader.setUniform("windowHeight", static_cast<float>(window.getSize().y)); // needs to be set whenever windowsize changes
sf::RenderTexture RT;
RT.create(800, 600);
RT.clear(sf::Color::Transparent);
sf::Sprite SP;
SP.setTexture(RT.getTexture(), true);
//--------------------------------------------------------------------------------------------------------------------
sf::Texture TX_BG;
TX_BG.loadFromFile("img/bg.png");
sf::Sprite SP_Backgr;
SP_Backgr.setTexture(TX_BG);
SP_Backgr.setPosition(sf::Vector2f(0, 0));
SP_Backgr.setOrigin(sf::Vector2f(0, 0));
//--------------------------------------------------------------------------------------------------------------------
sf::RenderStates states;
states.shader = &shader;
states.blendMode = sf::BlendAlpha;
while (window.isOpen())
{
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed) { window.close(); }
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Num1) { states.blendMode = sf::BlendAlpha; std::cout << "BlendAlpha" << std::endl; }
if (event.key.code == sf::Keyboard::Num2) { states.blendMode = sf::BlendAdd; std::cout << "BlendAdd" << std::endl; }
if (event.key.code == sf::Keyboard::Num3) { states.blendMode = sf::BlendMultiply; std::cout << "BlendMultiply" << std::endl; }
if (event.key.code == sf::Keyboard::Num4) { states.blendMode = sf::BlendNone; std::cout << "BlendNone" << std::endl; }
}
}
sf::Vector2i MG = sf::Mouse::getPosition(window); // Mouse Global
sf::Vector2f ML = window.mapPixelToCoords(MG); // Mouse Local
circle.setPosition(ML);
shader.setUniform("color", sf::Glsl::Vec4(1, 0, 0, 1.f));
shader.setUniform("center", circle.getPosition());
shader.setUniform("radius", circle.getRadius());
shader.setUniform("expand", 0.f);
//RT.clear(sf::Color::Transparent);
RT.draw(circle, states);
RT.display();
window.clear();
window.draw(SP_Backgr);
window.draw(SP);
window.display();
//window.draw(circle, &shader);
//window.display();
}
return EXIT_SUCCESS;
}