SFML 2.X GLSL - Shader wody resetuje się co 512px

SFML 2.X GLSL - Shader wody resetuje się co 512px

Wątek przeniesiony 2024-10-24 19:08 z Inne języki programowania przez flowCRANE.

tBane
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poznań
  • Postów: 539
0

Witam. Znalazłem pewien Shader, który planuję użyć w swoim programie.
link
Problem polega na tym, że shader resetuje się co 512 px w pionie jak i poziomie.
Dlaczego tak się dzieje ?

RPG2D 143.png

Kod w SFML 2.X GLSL:

Kopiuj
uniform vec2 resolution;
uniform float time;

float random(float x) {
 
    return fract(sin(x) * 10000.);
          
}

float noise(vec2 p) {

    return random(p.x + p.y * 10000.);
            
}

vec2 sw(vec2 p) { return vec2(floor(p.x), floor(p.y)); }
vec2 se(vec2 p) { return vec2(ceil(p.x), floor(p.y)); }
vec2 nw(vec2 p) { return vec2(floor(p.x), ceil(p.y)); }
vec2 ne(vec2 p) { return vec2(ceil(p.x), ceil(p.y)); }

float smoothNoise(vec2 p) {

    vec2 interp = smoothstep(0., 1., fract(p));
    float s = mix(noise(sw(p)), noise(se(p)), interp.x);
    float n = mix(noise(nw(p)), noise(ne(p)), interp.x);
    return mix(s, n, interp.y);
        
}

float fractalNoise(vec2 p) {

    float x = 0.;
    x += smoothNoise(p      );
    x += smoothNoise(p * 2. ) / 2.;
    x += smoothNoise(p * 4. ) / 4.;
    x += smoothNoise(p * 8. ) / 8.;
    x += smoothNoise(p * 16.) / 16.;
    x /= 1. + 1./2. + 1./4. + 1./8. + 1./16.;
    return x;
            
}

float movingNoise(vec2 p) {
 
    float x = fractalNoise(p + time);
    float y = fractalNoise(p - time);
    return fractalNoise(p + vec2(x, y));   
    
}

float nestedNoise(vec2 p) {
    
    float x = movingNoise(p);
    float y = movingNoise(p + 100.);
    return movingNoise(p + vec2(x, y));
    
}
void main()
{
    vec2 uv = gl_TexCoord[0].xy / resolution.xy;
    float n = nestedNoise(uv * 25600.);
    gl_FragColor = vec4(mix(vec3(.4, .6, 1.), vec3(.1, .2, 1.), n), 1.);
}
Spine
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6967
2

Woda jest jednokolorowa i shader nakłada na nią szum, prawda?
Każdy sprite wody to duży prostokąt, tak?

Tak na szybko, wydaje m się, że stosujesz shader na każdym prostokącie w jego lokalnej przestrzeni.

Gdyby shader korzystał z przestrzeni globalnej, to by generował szum bezszwowo, o ile jest w ten sposób napisany.

tBane
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poznań
  • Postów: 539
1

@Spine eksperymentowałem z teksturami o różnym rozmiarze i zawsze jest taki sam efekt. Czyli to gdzieś po stronie shadera jest problem. A ja go niestety nie rozumiem, dlatego na forum się odezwałem.

No ale w Map Edytorze tego nie widać xD
screenshot-20241024151913.png

Spine
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6967
0
tBane napisał(a):

No ale w Map Edytorze tego nie widać xD

Ale chyba wiesz dlaczego :) ?
Szwy są zakrywane liniami.
Nie ma różnicy między 0x0 i 2x0, 0x1 i 2x1, itd...

DD
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 29
0

Lepiej finalizuj to i przejdz do kolejnego kroku, bo przed toba jeszcze 1000 takich problemow. Lepiej nie zawieszaj sie na tym, lepiej wroc do tego typu problemow jak juz gra bedzie gotowa i potraktuj to jako szlifowanie efektu. Kazdy ci to powie

Spine
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6967
0

@Donsacz Donośny: Masz rację, ale nie do końca.

Może przy którymś problemie przejrzy na oczy, zobaczy z jaką prymitywną technologią ma do czynienia i przejdzie na coś współczesnego, co lepiej wspiera tworzenie gier, pracę nad shaderami itd...

Im szybciej, tym lepiej. Przesiadka z łopaty na koparkę naprawdę przyspieszy pracę.

99xmarcin
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 2420
0

A ta twoja textura to jakie ma wymiary?

tBane
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poznań
  • Postów: 539
0

@99xmarcin 256x256

99xmarcin
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 2420
0

Szukał bym bug'a w linijce:

Kopiuj
vec2 uv = gl_TexCoord[0].xy / resolution.xy;

być może resolution źle ustawiasz i się "zawija"

Spine
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6967
0

@99xmarcin: A ta linijka nie konwertuje po prostu uv z pikselowych wymiarów na zakres (0.0, 1.0)?

i potem float n = nestedNoise(uv * 25600.); mnoży jednostkowe uv przez 25600, bo np. viewport SFML jest ustawiony na bardzo duże liczby i w ten sposób zagęszczane są piksele szumu.

@tBane: Spróbuj rozwinąć linijkę vec2 uv = gl_TexCoord[0].xy / resolution.xy; w

Kopiuj
vec2 uv = abs((gl_TexCoord[0].xy / resolution.xy) + vec2(-0.5, -0.5));

Powinno to zmienić pattern w bardziej powtarzalny, ale za to będzie tileable.

Spine
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6967
0

@tBane: Przerobiłem Twój shader, żeby działał w shadertoy.

1. Wklej ten kod zamiast shadera ze strony https://www.shadertoy.com/view/XdXBRH :

Kopiuj
float random(float x) {
 
    return fract(sin(x) * 10000.);
          
}

float noise(vec2 p) {

    return random(p.x + p.y * 10000.);
            
}

vec2 sw(vec2 p) { return vec2(floor(p.x), floor(p.y)); }
vec2 se(vec2 p) { return vec2(ceil(p.x), floor(p.y)); }
vec2 nw(vec2 p) { return vec2(floor(p.x), ceil(p.y)); }
vec2 ne(vec2 p) { return vec2(ceil(p.x), ceil(p.y)); }

float smoothNoise(vec2 p) {

    vec2 interp = smoothstep(0., 1., fract(p));
    float s = mix(noise(sw(p)), noise(se(p)), interp.x);
    float n = mix(noise(nw(p)), noise(ne(p)), interp.x);
    return mix(s, n, interp.y);
        
}

float fractalNoise(vec2 p) {

    float x = 0.;
    x += smoothNoise(p      );
    x += smoothNoise(p * 2. ) / 2.;
    x += smoothNoise(p * 4. ) / 4.;
    x += smoothNoise(p * 8. ) / 8.;
    x += smoothNoise(p * 16.) / 16.;
    x /= 1. + 1./2. + 1./4. + 1./8. + 1./16.;
    return x;
            
}

float movingNoise(vec2 p) {
 
    float x = fractalNoise(p + iTime);
    float y = fractalNoise(p - iTime);
    return fractalNoise(p + vec2(x, y));   
    
}

float nestedNoise(vec2 p) {
    
    float x = movingNoise(p);
    float y = movingNoise(p + 100.);
    return movingNoise(p + vec2(x, y));
    
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    //vec2 uv = fragCoord / iResolution.xy;
    vec2 uv = abs((fragCoord / iResolution.xy) + vec2(-0.5, -0.5));
    float n = nestedNoise(uv * 25.61);
    fragColor = vec4(mix(vec3(.4, .6, 1.), vec3(.1, .2, 1.), n), 1.);
}

2. I daj play (lewy dolny róg pola tekstowego):

screenshot-20241024182955.png

3. Działa...

screenshot-20241024184241.png

tBane
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poznań
  • Postów: 539
0

@Spine ale po konwersji na SFML GLSL już nie działa:

screenshot-20241024190654.png

Kopiuj
uniform vec2 resolution;
uniform float time;

float random(float x) {
 
    return fract(sin(x) * 10000.);
          
}

float noise(vec2 p) {

    return random(p.x + p.y * 10000.);
            
}

vec2 sw(vec2 p) { return vec2(floor(p.x), floor(p.y)); }
vec2 se(vec2 p) { return vec2(ceil(p.x), floor(p.y)); }
vec2 nw(vec2 p) { return vec2(floor(p.x), ceil(p.y)); }
vec2 ne(vec2 p) { return vec2(ceil(p.x), ceil(p.y)); }

float smoothNoise(vec2 p) {

    vec2 interp = smoothstep(0., 1., fract(p));
    float s = mix(noise(sw(p)), noise(se(p)), interp.x);
    float n = mix(noise(nw(p)), noise(ne(p)), interp.x);
    return mix(s, n, interp.y);
        
}

float fractalNoise(vec2 p) {

    float x = 0.;
    x += smoothNoise(p      );
    x += smoothNoise(p * 2. ) / 2.;
    x += smoothNoise(p * 4. ) / 4.;
    x += smoothNoise(p * 8. ) / 8.;
    x += smoothNoise(p * 16.) / 16.;

    x /= 1. + 1./2. + 1./4. + 1./8. + 1./16.;
    return x;
            
}

float movingNoise(vec2 p) {
 
    float x = fractalNoise(p + time);
    float y = fractalNoise(p - time);
    return fractalNoise(p + vec2(x, y));   
    
}

float nestedNoise(vec2 p) {
    
    float x = movingNoise(p);
    float y = movingNoise(p + 100.);
    return movingNoise(p + vec2(x, y));
    
}
void main()
{
    //vec2 uv = gl_TexCoord[0].xy / resolution.xy;
    vec2 uv = abs((gl_TexCoord[0].xy / resolution.xy) + vec2(-0.5, -0.5));
    float n = nestedNoise(uv * 25.61);
    gl_FragColor = vec4(mix(vec3(.4, .6, 1.), vec3(.1, .2, 1.), n), 1.);
}

Poza tym vec2 uv = abs((fragCoord / iResolution.xy) + vec2(-0.5, -0.5)); zmieniłbym na vec2 uv = abs((fragCoord / iResolution.xy);, bo wtedy nie ma lustrzanego poziomego odbicia

Spine
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6967
0
tBane napisał(a):

Poza tym vec2 uv = abs((fragCoord / iResolution.xy) + vec2(-0.5, -0.5)); zmieniłbym na vec2 uv = abs((fragCoord / iResolution.xy);, bo wtedy nie ma lustrzanego poziomego odbicia

Jak usuniesz + vec2(-0.5, -0.5), to abs() jest zbędny.

To pewnie niewiele zmieni, ale mnożnika uv nie zwiększyłeś. W shadertoy zmniejszyłem go, bo szum miał zbyt duże zagęszczenie.

LukeJL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 8487
0
tBane napisał(a):

@Spine eksperymentowałem z teksturami o różnym rozmiarze i zawsze jest taki sam efekt. Czyli to gdzieś po stronie shadera jest problem.

Nie czytałem całego wątku, ale jak tekstury się powtarzają, to może ustawić wrapping mode na MIRRORED_REPEAT?
Nazewnictwa tutaj używam WebGL (które może być inne w tym API, z którego korzystasz), ale chodzi mi o to, co się ma dziać, jak pobierzesz wartość piksela spoza tekstury. Teraz widzę, że się powtarza:
Chodzi mi o coś takiego:
https://webglfundamentals.org/webgl/webgl-3d-textures-repeat-clamp.html

Taka pierwsza myśl, jednak ty tam robisz coś więcej niż tylko ustawiasz teksturę, więc możliwe, że problem jest w głębi shadera.
Chociaż w sumie taki efekt można by uzyskać również ręcznie.

Spine
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6967
0
LukeJL napisał(a):

Nie czytałem całego wątku, ale jak tekstury się powtarzają, to może ustawić wrapping mode na MIRRORED_REPEAT?

Wątpię aby to było cokolwiek innego niż CLAMP...
W końcu ma edytor, w którym można dodać wodę, więc każda woda to jest pojedynczy kafelek, czyli tutaj żaden REPEAT nie jest potrzebny, ani nie będzie wykorzystywany.

tBane
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poznań
  • Postów: 539
1

No więc problem polegał na tym, że odnosiłem się do współrzędnych tekstury a nie do współrzędnych globalnych. (Prawdopodobnie domyślnie tekstura ma rozmiary 512x512). Rozwiązaniem jest stworzenie vertex shadera, dzięki któremu można otrzymać informację o współrzędnych pixela.

screenshot-20241025110353.png

Kopiuj
// vertex.frag

varying vec2 worldPos;

void main()
{
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
	worldPos = gl_ModelViewMatrix * gl_Vertex;
	gl_FrontColor = gl_Color;
}
Kopiuj
// water2.frag

uniform vec2 resolution;
uniform float time;
varying vec2 worldPos;

float random(float x) {
 
    return fract(sin(x) * 10000.);
          
}

float noise(vec2 p) {

    return random(p.x + p.y * 10000.);
            
}

vec2 sw(vec2 p) { return vec2(floor(p.x), floor(p.y)); }
vec2 se(vec2 p) { return vec2(ceil(p.x), floor(p.y)); }
vec2 nw(vec2 p) { return vec2(floor(p.x), ceil(p.y)); }
vec2 ne(vec2 p) { return vec2(ceil(p.x), ceil(p.y)); }

float smoothNoise(vec2 p) {

    vec2 interp = smoothstep(0., 1., fract(p));
    float s = mix(noise(sw(p)), noise(se(p)), interp.x);
    float n = mix(noise(nw(p)), noise(ne(p)), interp.x);
    return mix(s, n, interp.y);
        
}

float fractalNoise(vec2 p) {

    float x = 0.;
    x += smoothNoise(p      );
    x += smoothNoise(p * 2. ) / 2.;
    x += smoothNoise(p * 4. ) / 4.;
    x += smoothNoise(p * 8. ) / 8.;
    x += smoothNoise(p * 16.) / 16.;

    x /= 1. + 1./2. + 1./4. + 1./8. + 1./16.;
    return x;
            
}

float movingNoise(vec2 p) {
 
    float x = fractalNoise(p + time);
    float y = fractalNoise(p - time);
    return fractalNoise(p + vec2(x, y));   
    
}

float nestedNoise(vec2 p) {
    
    float x = movingNoise(p);
    float y = movingNoise(p + 100.);
    return movingNoise(p + vec2(x, y));
    
}
void main()
{
    vec2 uv = worldPos.xy * 0.05;
    float n = nestedNoise(uv);
    gl_FragColor = vec4(mix(vec3(.4, .6, 1.), vec3(.1, .2, 1.), n), 1.);
}
Spine
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6967
2
tBane napisał(a):

No więc problem polegał na tym, że odnosiłem się do współrzędnych tekstury a nie do współrzędnych globalnych.

Właśnie to napisałem w pierwszej odpowiedzi => SFML 2.X GLSL - Shader wody resetuje się co 512px

Tak na szybko, wydaje m się, że stosujesz shader na każdym prostokącie w jego lokalnej przestrzeni.

Gdyby shader korzystał z przestrzeni globalnej, to by generował szum bezszwowo, o ile jest w ten sposób napisany.

tBane
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Poznań
  • Postów: 539
2

@Spine po prostu nie zrozumiałem :-)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.