tBane Temat założony przez niniejszego użytkownika |
[SFML 2.X] Motion Blur - rozmycie sprajta w ruchu » 2025-04-11 06:26:23 Cześć. Próbuję osiągnąć efekt Motion Blur czyli rozmycie podczas przesuwania obiektu. Jak na razie napisałem shader oraz klasę pod renderer. W zasadzie algorytm działa tak, że wszystkie sprajty są rysowane na ostatniej teksturze renderera, a suma wagowa tych tekstur daje nam teksturę finalną, czyli tą którą renderuje. Moje pytanie brzmi, jak poprawnie wyrenderować efekt Motion Blur, bo u mnie migają sprajty :-/ Poniżej zamieszczam kod shadera oraz Renderera. shaders\motion_blur.fraguniform sampler2D render_texture_0; uniform sampler2D render_texture_1; uniform sampler2D render_texture_2;
void main() { vec4 c0 = texture2D(render_texture_0, gl_TexCoord[0].xy); vec4 c1 = texture2D(render_texture_1, gl_TexCoord[0].xy); vec4 c2 = texture2D(render_texture_2, gl_TexCoord[0].xy);
gl_FragColor = c0*0.7 + c1*0.2 + c2*0.1; }
Camera.hpp#ifndef Camera_hpp #define Camera_hpp float screenWidth = 1280; float screenHeight = 720;
class Camera { public: sf::Vector2f position; sf::View view; Camera() { position = sf::Vector2f( 0, 0 ); view.setSize( sf::Vector2f( screenWidth, screenHeight ) ); view.setCenter( position ); } }; #endif
Renderer.hpp#ifndef Renderer_hpp #define Renderer_hpp
class Renderer { public: const short frames = 3; std::vector < sf::RenderTexture * > render_textures; sf::Shader * sh; sf::Color frame_color = sf::Color( 0, 0, 0, 128 ); Renderer() { for( short i = 0; i < frames; i++ ) { sf::RenderTexture * r = new sf::RenderTexture(); r->create( screenWidth, screenHeight ); r->clear( frame_color ); r->setView( cam->view ); render_textures.push_back( r ); } sh = new sf::Shader(); sh->loadFromFile( "shaders\\motion_blur.frag", sf::Shader::Fragment ); } ~Renderer() { for( auto & r: render_textures ) delete r; render_textures.clear(); } sf::RenderTexture * getTheCurrentFrame() { return render_textures.back(); } void update() { delete render_textures.front(); render_textures.erase( render_textures.begin() ); sf::RenderTexture * rtex = new sf::RenderTexture(); rtex->create( screenWidth, screenHeight ); rtex->clear( frame_color ); rtex->setView( cam->view ); render_textures.push_back( rtex ); } void draw() { getTheCurrentFrame()->display(); sh->setUniform( "render_texture_0", render_textures[ 0 ]->getTexture() ); sh->setUniform( "render_texture_1", render_textures[ 1 ]->getTexture() ); sh->setUniform( "render_texture_2", render_textures[ 2 ]->getTexture() ); sf::Sprite spr; spr.setTexture( getTheCurrentFrame()->getTexture() ); spr.setOrigin( screenWidth / 2, screenHeight / 2 ); spr.setPosition( cam->position ); window->draw( spr, sh ); } };
Renderer * renderer = nullptr;
#endif
main.cpp#include "Camera.hpp" #include "Renderer.hpp"
sf::RenderWindow * window; Camera * cam;
int main() { window = new sf::RenderWindow( sf::VideoMode( screenWidth, screenHeight ), "test motion blur" ); cam = new Camera(); renderer = new Renderer(); sf::Texture texture; texture.loadFromFile( "assets\\natures\\tree9.png" ); sf::Sprite tree; tree.setTexture( texture ); tree.setOrigin( texture.getSize().x / 2, texture.getSize().y / 2 ); while( window->isOpen() ) { sf::Vector2i mousePosition = sf::Mouse::getPosition( * window ); sf::Vector2f worldMousePosition = window->mapPixelToCoords( mousePosition ); cam->update(); window->setView( cam->view ); sf::Event event; while( window->pollEvent( event ) ) { if( event.type == sf::Event::Closed ) { window->close(); } } renderer->update(); tree.setPosition( worldMousePosition ); window->clear(); renderer->getTheCurrentFrame()->draw( tree ); renderer->getTheCurrentFrame()->display(); renderer->draw(); window->display(); } return 0; }
|
|
pekfos |
» 2025-04-11 21:19:26 Podajesz do shadera te tekstury w złej kolejności, poza tym nie widzę żadnego migania. #include <SFML/Graphics.hpp>
float screenWidth = 1280; float screenHeight = 720;
class Camera { public: sf::Vector2f position; sf::View view; Camera() { position = sf::Vector2f( 0, 0 ); view.setSize( sf::Vector2f( screenWidth, screenHeight ) ); view.setCenter( position ); } };
sf::RenderWindow * window; Camera * cam;
class Renderer { public: const short frames = 3; std::vector < sf::RenderTexture * > render_textures; sf::Shader * sh; sf::Color frame_color = sf::Color( 0, 0, 0, 128 ); Renderer() { for( short i = 0; i < frames; i++ ) { sf::RenderTexture * r = new sf::RenderTexture(); r->create( screenWidth, screenHeight ); r->clear( frame_color ); r->setView( cam->view ); render_textures.push_back( r ); } sh = new sf::Shader(); sh->loadFromMemory( R"(
uniform sampler2D render_texture_0;
uniform sampler2D render_texture_1;
uniform sampler2D render_texture_2;
void main()
{
vec4 c0 = texture2D(render_texture_0, gl_TexCoord[0].xy);
vec4 c1 = texture2D(render_texture_1, gl_TexCoord[0].xy);
vec4 c2 = texture2D(render_texture_2, gl_TexCoord[0].xy);
gl_FragColor = c0*0.7 + c1*0.2 + c2*0.1;
}
)", sf::Shader::Fragment ); } ~Renderer() { for( auto & r: render_textures ) delete r; render_textures.clear(); } sf::RenderTexture * getTheCurrentFrame() { return render_textures.back(); } void update() { auto rtex = render_textures[ 0 ]; render_textures.erase( render_textures.begin() ); rtex->clear( frame_color ); rtex->setView( cam->view ); render_textures.push_back( rtex ); } void draw() { getTheCurrentFrame()->display(); sh->setUniform( "render_texture_0", render_textures[ 2 ]->getTexture() ); sh->setUniform( "render_texture_1", render_textures[ 1 ]->getTexture() ); sh->setUniform( "render_texture_2", render_textures[ 0 ]->getTexture() ); sf::Sprite spr; spr.setTexture( getTheCurrentFrame()->getTexture() ); spr.setOrigin( screenWidth / 2, screenHeight / 2 ); spr.setPosition( cam->position ); window->draw( spr, sh ); } };
Renderer * renderer = nullptr;
int main() { window = new sf::RenderWindow( sf::VideoMode( screenWidth, screenHeight ), "test motion blur" ); cam = new Camera(); renderer = new Renderer(); sf::CircleShape tree( 30 ); tree.setFillColor( sf::Color::White ); tree.setOrigin( 30, 30 ); window->setFramerateLimit( 20 ); while( window->isOpen() ) { sf::Vector2i mousePosition = sf::Mouse::getPosition( * window ); sf::Vector2f worldMousePosition = window->mapPixelToCoords( mousePosition ); window->setView( cam->view ); sf::Event event; while( window->pollEvent( event ) ) { if( event.type == sf::Event::Closed ) { window->close(); } } renderer->update(); tree.setPosition( worldMousePosition ); window->clear(); renderer->getTheCurrentFrame()->draw( tree ); renderer->draw(); window->display(); } return 0; } Wrzucaj takie przykłady jako jeden ciągły kod, najlepiej bez zależności do osobnych plików. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-04-12 10:52:36 Ok. Następnym razem wrzucę jako jeden kod. Podmieniłem kolejność tekstur w shaderze i migotanie nadal występuje. Szczególnie mocno to widac z meshem, który robie się cieńszy/węższy. Nie wiem czy ten motion blur to dobry pomysł podczas przesuwania mapy ... jak myślicie? Czy może jakoś inaczej napisać ten motion blur ? Najgorzej, że to przykład z książki "OpenGL Programowanie Gier" i nie działa tak jak oczekiwałem :-/ uniform sampler2D render_texture_0; uniform sampler2D render_texture_1; uniform sampler2D render_texture_2;
uniform float brightness; uniform float contrast; uniform float gamma;
void main() { vec4 c0 = texture2D(render_texture_0, gl_TexCoord[0].xy); vec4 c1 = texture2D(render_texture_1, gl_TexCoord[0].xy); vec4 c2 = texture2D(render_texture_2, gl_TexCoord[0].xy);
vec4 color = c2*0.7 + c1*0.2 + c0*0.1; // podmieniona kolejność color.rgb += brightness; color.rgb = (color.rgb - 0.5) * contrast + 0.5; color.rgb = pow(color.rgb, vec3(1.0 / gamma));
gl_FragColor = color; }
|
|
DejaVu |
» 2025-04-12 13:40:13 Ja bym na Twoim miejscu dążył do maksymalnej ostrości, tj. nie robił żadnych 'motion blur' bo: 1. monitor zrobi to za Ciebie jako side effect refresh rate (obecnie rzadziej spotykane) 2. oko doda 'monition blur' 3. Takie efekty to raczej nie są zbyt przyjemne w grach (chyba, że znasz grę, w której to dobrze się sprawdza?) |
|
tBane Temat założony przez niniejszego użytkownika |
» 2025-04-12 13:44:49 Ok. W takim razie zrezygnuję z tego efektu. Dzięki za rady :-) |
|
« 1 » |