【发布时间】:2022-08-16 13:03:25
【问题描述】:
我目前正在 LibGDX 中开发一款瓷砖游戏,并且试图通过遮盖未开发的瓷砖来获得“战争迷雾”效果。我从中得到的结果是动态生成的屏幕大小的黑色纹理,它只覆盖未探索的瓷砖,而其余的背景可见。这是在白色背景上渲染的雾纹理示例:
我现在想要实现的是动态淡化这个纹理的内部边界,使它看起来更像是一个慢慢变厚的雾,而不是一堆黑盒子放在背景上。
谷歌搜索问题我发现我可以使用着色器来做到这一点,所以我尝试学习一些 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)。它也有一些问题,比如边缘仍然有点太尖锐(我想要一个令人窒息的过渡),并且边框的一些角度比其他角度更少褪色(我想要一个淡化制服到处)。
在这一点上我有点迷茫:我能做些什么来让它变得更好更快?就像我说的我是着色器的新手,所以:它甚至是使用着色器的正确方法吗?
-
它总是居中吗?也许你可以做一个径向模糊?
-
边框是否与游戏的图块网格对齐?也许您可以将其渲染为每个图块 1 个像素的纹理,然后免费获得 1 个图块的模糊值,您还可以在每个着色器循环中执行 1 个整个图块,而不仅仅是 1 个像素。注意:如果你每像素做 1 个平铺,则纹理像素必须相对于屏幕像素进行旋转和拉伸,因此你必须计算出纹理坐标
-
@vtastek 雾可以有各种形状,并不总是居中,所以我不能使用径向模糊
-
也许您可以使用根本不模糊的技巧,而只是使用淡入淡出的纹理,您可以在所有边界上渲染它。
-
@SirNiculino 每个采样点都将被双线性插值,因为这就是 GPU 在像素之间采样时对纹理所做的事情(假设您使用 GL_LINEAR 创建纹理)。因此,瓦片中的一个采样点会告诉您边缘有多远。
标签: opengl libgdx glsl shader fade