gpt4 book ai didi

opengl - 使用 openGL 着色器 (glsl) 在 LibGDX 中将纹理内部边框淡化为透明

转载 作者:行者123 更新时间:2023-12-05 04:25:51 36 4
gpt4 key购买 nike

我目前正在 LibGDX 中开发一款瓷砖游戏,我试图通过遮盖未探索的瓷砖来获得“ war 迷雾”效果。我从中得到的结果是一个动态生成的屏幕大小的黑色纹理,它只覆盖未探索的图 block ,使背景的其余部分可见。这是在白色背景上渲染的雾纹理示例:

Fog texture rendered on top of a white background

我现在想要实现的是动态淡化该纹理的内部边界,使其看起来更像一团慢慢变厚的雾,而不是一堆放在背景顶部的黑框。

谷歌搜索问题我发现我可以使用着色器来做到这一点,所以我尝试学习一些 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 的结果:

Faded fog

所以我写的着色器有点工作,但性能很糟糕,因为它是 O(n^2),其中 n 是以像素为单位的淡入淡出的长度(所以它可以非常高,比如 60 甚至 80)。它也有一些问题,比如边缘仍然有点太尖锐(我想要一个令人窒息的过渡)并且边界的一些角度比其他角度褪色更少(我希望到处都有褪色制服) .

此时我有点迷茫:我能做些什么来让它变得更好更快吗?就像我说的,我是着色器的新手,所以:它甚至是使用着色器的正确方法吗?

最佳答案

正如其他人在评论中提到的那样,您不应在屏幕空间中进行模糊处理,而应在平铺空间中进行过滤,同时可能利用 GPU 双线性过滤。让我们通过图像来了解它。

首先定义一个纹理,使每个像素对应一个图 block ,黑色/白色取决于该图 block 上的雾。这是一个放大的纹理:

tile map

应用屏幕到图 block 的坐标转换并使用 GL_NEAREST 插值对该纹理进行采样后,我们得到类似于您所拥有的 block 状结果:

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

nearest

如果我们切换到 GL_LINEAR 而不是 GL_NEAREST,我们会得到更好的结果:

linear

这看起来还是有点 block 状。为了改进这一点,我们可以应用 smoothstep:

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

smoothstep

或者这是一个具有线性阴影映射功能的版本:

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);

clamp

注意:这些图像是在 Gamma 校正管道中生成的(即启用了 sRGB 帧缓冲区)。然而,这是为数不多的几种情况之一,忽略 gamma 可能会产生更好的结果,因此欢迎您进行试验。

关于opengl - 使用 openGL 着色器 (glsl) 在 LibGDX 中将纹理内部边框淡化为透明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73165790/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com