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

[SFML GLSL] Fragment Shader - Animowanie Wody

Ostatnio zmodyfikowano 2024-09-23 18:40
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[SFML GLSL] Fragment Shader - Animowanie Wody
» 2024-09-20 18:54:41
Witam. Chciałbym animować wodę z następującej funkcji.
void surf (Input IN, inout SurfaceOutputStandard o) {
   float2 uv = IN.worldPos.xz;
   uv.y += _Time.y;
   float4 noise = tex2D(_MainTex, uv * 0.025);
   float waves = noise.z;

   fixed4 c = saturate(_Color + waves);
   o.Albedo = c.rgb;
   o.Metallic = _Metallic;
   o.Smoothness = _Glossiness;
   o.Alpha = c.a;
  }

Potrzebuję przerobić ten kod:
C/C++
class Water
    : public sf::Drawable
    , public sf::Transformable
{
public:
   
int width, height;
   
sf::Vector2i coords;
   
   
sf::VertexArray vertexes;
   
sf::Texture waterset;
   
   
std::vector < int > waters;
   
   
Water( int x, int y, int width, int height ) {
       
       
coords.x = x;
       
coords.y = y;
       
       
this->width = width;
       
this->height = height;
       
       
waterset = sf::Texture();
       
waterset = * getTexture( "floors/0_floorset" )->texture;
       
       
vertexes.setPrimitiveType( sf::Triangles );
       
vertexes.resize( width * height * 6 ); // widthMap * heightMap * TwoTrianglesVertices
       
       
waters.resize( width * height );
       
       
int coord_x, coord_y;
       
       
for( int y = 0; y < height; y++ )
       
for( int x = 0; x < width; x++ ) {
           
           
sf::Vertex * triangles = & vertexes[( y * width + x ) * 6 ];
           
           
coord_x =( coords.x + x );
           
coord_y =( coords.y + y );
           
           
triangles[ 0 ].position = sf::Vector2f( coord_x * tileSide, coord_y * tileSide );
           
triangles[ 1 ].position = sf::Vector2f(( coord_x + 1 ) * tileSide, coord_y * tileSide );
           
triangles[ 2 ].position = sf::Vector2f( coord_x * tileSide,( coord_y + 1 ) * tileSide );
           
triangles[ 3 ].position = sf::Vector2f( coord_x * tileSide,( coord_y + 1 ) * tileSide );
           
triangles[ 4 ].position = sf::Vector2f(( coord_x + 1 ) * tileSide, coord_y * tileSide );
           
triangles[ 5 ].position = sf::Vector2f(( coord_x + 1 ) * tileSide,( coord_y + 1 ) * tileSide );
           
           
edit( x, y, 0 );
       
}
       
       
    }
   
   
void edit( int x, int y, int value ) {
       
       
if( x < 0 || x >= width || y < 0 || y >= height )
           
 return;
       
       
if( value > 3 || value < 0 )
           
 return;
       
       
waters[ y * width + x ] = value;
       
       
int global_x = coords.x + x;
       
int global_y = coords.y + y;
       
       
sf::Vertex * triangles = & vertexes[( y * width + x ) * 6 ];
       
       
int tu =( int( global_x * tileSide ) % 64 ) +( value * 64 );
       
int tv =( int( global_y * tileSide ) % 64 );
       
       
//cout << "tu: " << tu << ", tv: " << tv << "\n";
       
       
triangles[ 0 ].texCoords = sf::Vector2f( tu, tv );
       
triangles[ 1 ].texCoords = sf::Vector2f( tu + tileSide, tv );
       
triangles[ 2 ].texCoords = sf::Vector2f( tu, tv + tileSide );
       
triangles[ 3 ].texCoords = sf::Vector2f( tu, tv + tileSide );
       
triangles[ 4 ].texCoords = sf::Vector2f( tu + tileSide, tv );
       
triangles[ 5 ].texCoords = sf::Vector2f( tu + tileSide, tv + tileSide );
   
}
   
P-181608
pekfos
» 2024-09-20 19:10:44
P-181609
tBane
Temat założony przez niniejszego użytkownika
» 2024-09-20 19:13:34
Tak. Właśnie na tej podstawie chciałbym  stworzyć podobną funkcję.
P-181610
pekfos
» 2024-09-20 19:19:50
Zatem poczytaj o użyciu fragment shadera w SFML: https://www.sfml-dev.org/tutorials/2.6/graphics-shader.php
P-181611
tBane
Temat założony przez niniejszego użytkownika
» 2024-09-22 16:36:07
Co nieco poczytałem. Posiłkowalem się również Chatem GPT i potrafię stworzyć już prosty shader.

// assets/fragment_shader.frag
uniform sampler2D texture;
uniform float time;

void main()
{
    vec4 texColor = texture2D(texture, gl_TexCoord[0].xy);
   
    // Zmiana intensywności koloru w zależności od czasu
    float intensity = 0.5 + 0.5 * sin(time);
    gl_FragColor = vec4(0.0, 0.0, texColor.b * intensity, texColor.a);
}

użycie shadera w SFML 2.X
C/C++
void testGLSL() {
   
// Tworzenie okna
   
sf::RenderWindow window( sf::VideoMode( 800, 600 ), "GLSL Shader Animation" );
   
   
// Wczytywanie tekstury
   
sf::Texture texture;
   
if( !texture.loadFromFile( "assets/noise.png" ) )
       
 return;
   
   
// Tworzenie sprite'a
   
sf::Sprite sprite( texture );
   
   
// Wczytywanie shadera
   
sf::Shader shader;
   
if( !shader.loadFromFile( "assets/fragment_shader.frag", sf::Shader::Fragment ) )
       
 return;
   
   
// Zegar do animacji
   
sf::Clock clock;
   
   
// Zmienna przechowująca aktualny kolor (niebieski)
   
sf::Vector3f color( 0.0f, 0.0f, 1.0f );
   
   
// Główna pętla
   
while( window.isOpen() )
   
{
       
sf::Event event;
       
while( window.pollEvent( event ) )
       
{
           
if( event.type == sf::Event::Closed )
               
 window.close();
           
           
// Zmiana koloru na czerwony po naciśnięciu spacji
           
if( event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space )
           
{
               
if( color == sf::Vector3f( 0.0f, 0.0f, 1.0f ) )
                   
 color = sf::Vector3f( 1.0f, 0.0f, 0.0f ); // czerwony
               
else
                   
 color = sf::Vector3f( 0.0f, 0.0f, 1.0f ); // niebieski
               
           
}
        }
       
       
window.clear();
       
       
// Pobieranie czasu i wysyłanie do shadera
       
float time = clock.getElapsedTime().asSeconds();
       
shader.setUniform( "time", time );
       
       
// Zmiana koloru
       
shader.setUniform( "texture", texture );
       
       
// Rysowanie sprite'a z shaderem
       
window.draw( sprite, & shader );
       
       
window.display();
   
}
   
}
P-181614
tBane
Temat założony przez niniejszego użytkownika
» 2024-09-22 17:55:38
Przepisałem shader na GLSL i nie działa tak jak powinien. Po pierwsze, fale są "prostokątne" i nie wiem dlaczego, a po drugie po dłuższym czasie shader wypełnia całą teksturę statycznym niebieskim kolorem zamiast "płynąć".

Kod mojego shadera:

// assets/fragment_shader.frag
uniform sampler2D texture;
uniform float time;

void main()
{
    vec2 uv = gl_TexCoord[0].xy;
    uv.y += time;
    vec4 noise = texture2D(texture, uv * 0.025);
    float waves = noise.z;

    vec4 color = texture2D(texture, gl_TexCoord[0].xy);
    gl_FragColor = vec4(waves, waves, color.z+waves, 1.0);
}
P-181617
tBane
Temat założony przez niniejszego użytkownika
» 2024-09-22 17:55:38
Udało się.

Fale były prostokątne ponieważ ograniczałem współrzędne tekstury:
vec4 noise = texture2D(texture, uv * 0.025);


A shader wypełniał niebieskim kolorem statycznym bo dodawałem czas do wartości blue w nieskończoność :
uv.y += time;


Ponizej za to wrzucam kod animowanej wody. Jest to prymitywna animacja polegająca na utworzeniu dwóch fal pionowej i poziomej

C/C++
void testGLSL() {
   
// Tworzenie okna
   
sf::RenderWindow window( sf::VideoMode( 512, 512 ), "GLSL Shader Animation" );
   
   
// Wczytywanie tekstury
   
sf::Texture texture;
   
if( !texture.loadFromFile( "assets/noise.png" ) )
       
 return;
   
   
// Tworzenie sprite'a
   
sf::Sprite sprite( texture );
   
   
// Wczytywanie shadera
   
sf::Shader shader;
   
if( !shader.loadFromFile( "assets/fragment_shader.frag", sf::Shader::Fragment ) )
       
 return;
   
   
// Zegar do animacji
   
sf::Clock clock;
   
   
// Główna pętla
   
while( window.isOpen() )
   
{
       
sf::Event event;
       
while( window.pollEvent( event ) )
       
{
           
if( event.type == sf::Event::Closed )
               
 window.close();
           
       
}
       
       
window.clear();
       
       
// Pobieranie czasu i wysyłanie do shadera
       
float time = clock.getElapsedTime().asSeconds();
       
shader.setUniform( "time", time );
       
       
// Przypisanie tekst
       
shader.setUniform( "texture", texture );
       
// Rysowanie sprite'a z shaderem
       
window.draw( sprite, & shader );
       
       
window.display();
   
}
   
}


// assets/fragment_shader.frag

uniform sampler2D texture;
uniform float time;

void main()
{
    vec2 uv1 = gl_TexCoord[0].xy;
    uv1.y -= time*0.25;
    uv1.y = mod(uv1.y, 1.0);    // in range 0.0 - 1.0
    vec4 noise1 = texture2D(texture, uv1);
   
    vec2 uv2 = gl_TexCoord[0].xy;
    uv2.x -= time*0.25;
    uv2.x = mod(uv2.x, 1.0);    // in range 0.0 - 1.0
    vec4 noise2 = texture2D(texture, uv2);
   

    float waves = noise1.z + noise2.x;
    waves = smoothstep(0.75, 2, waves);

    vec4 color = vec4(0.125, 0.125, 0.6, 1.0);

    gl_FragColor = vec4(color.x + waves, color.y + waves, color.z + waves, color.w);
}
P-181618
tBane
Temat założony przez niniejszego użytkownika
» 2024-09-23 18:05:40
Dobra. Tak jak pisałem na początku wątku, potrzebuję przerobić funkcję odpowiedzialną za renderowanie wody. Napisałem i generuje jakieś kropki zamiast renderować teksturę szumu.

Zabrałem się za to w najprostszy sposób tzn. taki, że funkcja update za każdym razem resetuje zbiór wierzchołków do renderowania.


C/C++
#ifndef Water_hpp
#define Water_hpp

class Water
    : public sf::Drawable
    , public sf::Transformable
{
public:
   
int width, height;
   
sf::Vector2i coords;
   
sf::VertexArray vertexes;
   
Texture * noiseTexture;
   
   
std::vector < std::vector < bool > > waters;
   
   
Water( int x, int y, int width, int height ) {
       
       
coords.x = x;
       
coords.y = y;
       
       
this->width = width;
       
this->height = height;
       
       
// resize the array of water
       
waters.resize( height );
       
for( auto & water: waters )
           
 water.resize( width );
       
       
// all the water is false
       
for( int y = 0; y < height; y++ )
       
for( int x = 0; x < width; x++ ) {
           
waters[ y ][ x ] = false;
       
}
       
       
noiseTexture = getTexture( "noise" );
       
       
   
}
   
   
void edit( int x, int y, bool haveWater ) {
       
waters[ y ][ x ] = haveWater;
       
update();
   
}
   
   
void update() {
       
       
vertexes.clear();
       
       
for( int y = 0; y < height; y++ )
       
for( int x = 0; x < width; x++ ) {
           
           
if( waters[ y ][ x ] == true ) {
               
               
sf::Vertex tile[ 6 ];
               
               
int coord_x =( coords.x + x );
               
int coord_y =( coords.y + y );
               
               
tile[ 0 ].position = sf::Vector2f( coord_x * tileSide, coord_y * tileSide );
               
tile[ 1 ].position = sf::Vector2f(( coord_x + 1 ) * tileSide, coord_y * tileSide );
               
tile[ 2 ].position = sf::Vector2f( coord_x * tileSide,( coord_y + 1 ) * tileSide );
               
tile[ 3 ].position = sf::Vector2f( coord_x * tileSide,( coord_y + 1 ) * tileSide );
               
tile[ 4 ].position = sf::Vector2f(( coord_x + 1 ) * tileSide, coord_y * tileSide );
               
tile[ 5 ].position = sf::Vector2f(( coord_x + 1 ) * tileSide,( coord_y + 1 ) * tileSide );
               
               
int tu =( int( coord_x * tileSide ) % noiseTexture->texture->getSize().x );
               
int tv =( int( coord_y * tileSide ) % noiseTexture->texture->getSize().y );
               
               
tile[ 0 ].texCoords = sf::Vector2f( tu, tv );
               
tile[ 1 ].texCoords = sf::Vector2f( tu + tileSide, tv );
               
tile[ 2 ].texCoords = sf::Vector2f( tu, tv + tileSide );
               
tile[ 3 ].texCoords = sf::Vector2f( tu, tv + tileSide );
               
tile[ 4 ].texCoords = sf::Vector2f( tu + tileSide, tv );
               
tile[ 5 ].texCoords = sf::Vector2f( tu + tileSide, tv + tileSide );
               
               
for( int i = 0; i < 6; i++ )
                   
 vertexes.append( tile[ i ] );
               
           
}
           
           
        }
    }
   
private:
   
   
virtual void draw( sf::RenderTarget & target, sf::RenderStates states ) const
   
{
       
       
states.transform *= getTransform();
       
states.texture = &( * noiseTexture->texture );
       
target.draw( vertexes, states );
       
       
   
}
}
;

#endif
P-181619
« 1 » 2
  Strona 1 z 2 Następna strona