簡體   English   中英

使用 openGL 着色器 (glsl) 在 LibGDX 中將紋理內部邊框淡化為透明

[英]Fade texture inner borders to transparent in LibGDX using openGL shaders (glsl)

我目前正在開發 LibGDX 中的瓷磚游戲,我試圖通過遮蓋未開發的瓷磚來獲得“戰爭迷霧”效果。 我從中得到的結果是動態生成的屏幕大小的黑色紋理,它只覆蓋未探索的圖塊,使背景的 rest 可見。 這是在白色背景上渲染的霧紋理示例:

在白色背景上渲染的霧紋理

我現在想要實現的是動態淡化這個紋理的內部邊界,使它看起來更像是慢慢變厚的霧,而不是一堆黑盒子放在背景上。

谷歌搜索問題我發現我可以使用着色器來做到這一點,所以我嘗試學習一些 glsl(我剛開始使用着色器)並且我想出了這個着色器:

頂點着色器:

//attributes passed from openGL
attribute vec3 a_position;
attribute vec2 a_texCoord0;

//variables visible from java
uniform mat4 u_projTrans;

//variables shared between fragment and vertex shader
varying vec2 v_texCoord0;

void main() {

    v_texCoord0 = a_texCoord0;
    gl_Position = u_projTrans * vec4(a_position, 1f);
}

片段着色器:

//variables shared between fragment and vertex shader
varying vec2 v_texCoord0;

//variables visible from java
uniform sampler2D u_texture;
uniform vec2 u_textureSize;
uniform int u_length;

void main() {

    vec4 texColor = texture2D(u_texture, v_texCoord0);
    vec2 step = 1.0 / u_textureSize;

    if(texColor.a > 0) {

        int maxNearPixels = (u_length * 2 + 1) * (u_length * 2 + 1) - 1;
        for(int i = 0; i <= u_length; i++) {

            for(float j = 0; j <= u_length; j++) {

                if(i != 0 || j != 0) {

                    texColor.a -= (1 - texture2D(u_texture, v_texCoord0 + vec2(step.x * float(i), step.y * float(j))).a) / float(maxNearPixels);
                    texColor.a -= (1 - texture2D(u_texture, v_texCoord0 + vec2(-step.x * float(i), step.y * float(j))).a) / float(maxNearPixels);
                    texColor.a -= (1 - texture2D(u_texture, v_texCoord0 + vec2(step.x * float(i), -step.y * float(j))).a) / float(maxNearPixels);
                    texColor.a -= (1 - texture2D(u_texture, v_texCoord0 + vec2(-step.x * float(i), -step.y * float(j))).a) / float(maxNearPixels);
                }
            }
        }
    }

    gl_FragColor = texColor;
}

這是我設置長度為 20 的結果:

褪色的霧

所以我寫的着色器有點工作,但性能很差,因為它是 O(n^2),其中 n 是以像素為單位的淡入淡出的長度(所以它可以非常高,比如 60 甚至 80)。 它也有一些問題,比如邊緣仍然有點太尖銳(我想要一個令人窒息的過渡),並且邊框的一些角度比其他角度更不褪色(我想到處都有一個褪色制服) .

在這一點上我有點迷茫:我能做些什么來讓它變得更好更快? 就像我說的我是着色器的新手,所以:它甚至是使用着色器的正確方法嗎?

正如評論中的其他人所提到的,您應該在平鋪空間中進行過濾,而不是在屏幕空間中進行模糊處理,同時可能利用 GPU 雙線性過濾。 讓我們通過圖像 go 通過它。

首先定義一個紋理,使每個像素對應一個單獨的瓦片,黑/白取決於該瓦片上的霧。 這是一個被炸毀的紋理:

平鋪地圖

在應用屏幕到瓷磚坐標變換並使用GL_NEAREST插值對該紋理進行采樣后,我們得到類似於您所擁有的塊狀結果:

float t = texture2D(u_tiles, M*uv).r;
gl_FragColor = vec4(t,t,t,1.0);

最近的

如果我們切換到GL_LINEAR而不是GL_NEAREST ,我們會得到更好的結果:

線性的

這看起來仍然有點塊狀。 為了改進這一點,我們可以應用smoothstep

float t = texture2D(u_tiles, M*uv).r;
t = smoothstep(0.0, 1.0, t);
gl_FragColor = vec4(t,t,t,1.0);

平滑步

或者這里是一個帶有線性陰影映射 function 的版本:

float t = texture2D(u_tiles, M*uv).r;
t = clamp((t-0.5)*1.5 + 0.5, 0.0, 1.0);
gl_FragColor = vec4(t,t,t,1.0);

夾鉗

注意:這些圖像是在伽馬校正管道中生成的(即啟用 sRGB 幀緩沖區)。 然而,這是少數幾個場景之一,忽略 gamma 可能會產生更好的結果,因此歡迎您進行實驗。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM