I'm having trouble with eliminating artifacts from this fragment shader. I'm trying to simulate a radial blur/crepuscular rays effect and it works, except for the artifacts. I've found that when the RenderWindow's antialiasing is 0, they are most prominent, and they are still prominent until antialiasing is set to 8. In sf::Style::Fullscreen mode they are more prominent. Also, when the number of samples is higher than 65 (64 loop iterations), the shader goes haywire and displays nonsensical graphics. Finally, the artifacts have a slight blue tint to them even though the entire scene is just white with a black circle.
Here's the code for my fragment shader:
uniform float exposure;
uniform float decay;
uniform float density;
uniform float weight;
uniform vec2 lightPositionOnScreen;
uniform sampler2D firstPass;
const int NUM_SAMPLES = 65;
out vec4 color;
void main()
{
vec2 pixel = gl_FragCoord.xy;
pixel.x /= 1920.0;
pixel.y /= 1080.0;
vec2 lpos = lightPositionOnScreen;
lpos.x /= 1920.0;
lpos.y /= 1080.0;
vec2 deltaTextCoord = vec2( lpos.xy - pixel.xy );
deltaTextCoord *= density / float(NUM_SAMPLES);
float illuminationDecay = 1.0;
for(int i=0; i < NUM_SAMPLES ; i++)
{
pixel += deltaTextCoord;
vec4 sample = texture2D(firstPass, pixel);
sample *= illuminationDecay * weight;
color += sample;
illuminationDecay *= decay;
}
color *= exposure;
}
And here is the code for the project:
#include <SFML/Graphics.hpp>
#include <iostream>
int main()
{
sf::ContextSettings cs;
cs.antialiasingLevel = 0;
int scrHeight = sf::VideoMode::getDesktopMode().height;
int scrWidth = sf::VideoMode::getDesktopMode().width;
sf::RenderWindow Window(sf::VideoMode( scrWidth, scrHeight ), "SFML", sf::Style::Default, cs );
Window.setVerticalSyncEnabled(true);
sf::Clock clock;
srand( time(NULL) );
sf::Shader rayShader;
rayShader.loadFromFile("data\\shaders\\radial.FRAG", sf::Shader::Fragment);
rayShader.setParameter("exposure", 0.5f);
rayShader.setParameter("decay", 0.97f);
rayShader.setParameter("density", 0.97f);
rayShader.setParameter("weight", 0.5f);
sf::RenderTexture buffer1;
sf::Sprite buffer1Sprite;
buffer1.create( 1920, 1080 );
buffer1.setSmooth( true );
buffer1Sprite = sf::Sprite( buffer1.getTexture() );
sf::RenderTexture buffer2;
sf::Sprite buffer2Sprite;
buffer2.create( 1920, 1080 );
buffer2.setSmooth( true );
buffer2Sprite = sf::Sprite( buffer2.getTexture() );
sf::CircleShape test;
test.setRadius( 40 );
test.setOrigin( 40, 40 );
test.setFillColor( sf::Color::Black );
test.setPosition( 400, 400 );
sf::RenderStates states;
while( Window.isOpen() )
{
if( sf::Keyboard::isKeyPressed( sf::Keyboard::LControl ) && sf::Keyboard::isKeyPressed( sf::Keyboard::Q ) )
Window.close();
sf::Time dt = clock.restart();
sf::Event Event;
while( Window.pollEvent( Event ) )
{
if( Event.type == sf::Event::Closed )
Window.close();
if( Event.type == sf::Event::Resized )
{
sf::FloatRect visibleArea( 0, 0, Event.size.width, Event.size.height );
Window.setView( sf::View( visibleArea ) );
}
}
float x = sf::Mouse::getPosition(Window).x;
float y = sf::Mouse::getPosition(Window).y;
rayShader.setParameter("lightPositionOnScreen", sf::Vector2f(960.0, 540.0 ));
rayShader.setParameter("firstPass", sf::Shader::CurrentTexture );
rayShader.setParameter("exposure", 0.25f);
rayShader.setParameter("decay", 0.97f);
rayShader.setParameter("density", 0.97f);
rayShader.setParameter("weight", 0.5f);
states.shader = &rayShader;
test.setPosition( x, y );
bg.setColor( sf::Color::Black );
buffer1.clear( sf::Color::Transparent );
buffer1.draw( test );
buffer1.display();
buffer2.clear( sf::Color::Transparent );
buffer2.draw( buffer1Sprite );
buffer2.draw( buffer1Sprite, states );
buffer2.display();
Window.clear( sf::Color::White );
Window.draw( buffer2Sprite );
Window.display();
}
}
Here are the artifacts in question: