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: 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 ); 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 ); 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 ); } |
|
pekfos |
» 2024-09-20 19:10:44 |
|
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ę. |
|
pekfos |
» 2024-09-20 19:19:50 |
|
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 void testGLSL() { sf::RenderWindow window( sf::VideoMode( 800, 600 ), "GLSL Shader Animation" ); sf::Texture texture; if( !texture.loadFromFile( "assets/noise.png" ) ) return; sf::Sprite sprite( texture ); sf::Shader shader; if( !shader.loadFromFile( "assets/fragment_shader.frag", sf::Shader::Fragment ) ) return; sf::Clock clock; sf::Vector3f color( 0.0f, 0.0f, 1.0f ); while( window.isOpen() ) { sf::Event event; while( window.pollEvent( event ) ) { if( event.type == sf::Event::Closed ) window.close(); 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 ); else color = sf::Vector3f( 0.0f, 0.0f, 1.0f ); } } window.clear(); float time = clock.getElapsedTime().asSeconds(); shader.setUniform( "time", time ); shader.setUniform( "texture", texture ); window.draw( sprite, & shader ); window.display(); } }
|
|
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); }
|
|
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 void testGLSL() { sf::RenderWindow window( sf::VideoMode( 512, 512 ), "GLSL Shader Animation" ); sf::Texture texture; if( !texture.loadFromFile( "assets/noise.png" ) ) return; sf::Sprite sprite( texture ); sf::Shader shader; if( !shader.loadFromFile( "assets/fragment_shader.frag", sf::Shader::Fragment ) ) return; sf::Clock clock; while( window.isOpen() ) { sf::Event event; while( window.pollEvent( event ) ) { if( event.type == sf::Event::Closed ) window.close(); } window.clear(); float time = clock.getElapsedTime().asSeconds(); shader.setUniform( "time", time ); shader.setUniform( "texture", texture ); 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); }
|
|
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. #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; waters.resize( height ); for( auto & water: waters ) water.resize( width ); 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
|
|
« 1 » 2 |