GLSL:根据与相机的距离淡化二维网格
GLSL: Fade 2D grid based on distance from camera
我目前正在尝试仅使用着色器在单个四边形上绘制二维网格。我使用 SFML 作为图形库并使用 sf::View 来控制相机。到目前为止,我已经能够绘制抗锯齿多级网格。第一层(蓝色)勾勒出一个块,第二层(灰色)勾勒出块内的图块。
我现在想根据与相机的距离淡化网格级别。例如,当相机放大时,块网格应该淡入。在块网格完全淡入后,块网格也应该这样做。
我不确定如何实现,因为我对 OpenGL 和 GLSL 还是个新手。如果有人对如何实现此功能有任何指示,请告诉我。
顶点着色器
#version 130
out vec2 texCoords;
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
texCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
}
片段着色器
#version 130
uniform vec2 chunkSize = vec2(64.0, 64.0);
uniform vec2 tileSize = vec2(16.0, 16.0);
uniform vec3 chunkBorderColor = vec3(0.0, 0.0, 1.0);
uniform vec3 tileBorderColor = vec3(0.5, 0.5, 0.5);
uniform bool drawGrid = true;
in vec2 texCoords;
void main() {
vec2 uv = texCoords.xy * chunkSize;
vec3 color = vec3(1.0, 1.0, 1.0);
if(drawGrid) {
float aa = length(fwidth(uv));
vec2 halfChunkSize = chunkSize / 2.0;
vec2 halfTileSize = tileSize / 2.0;
vec2 a = abs(mod(uv - halfChunkSize, chunkSize) - halfChunkSize);
vec2 b = abs(mod(uv - halfTileSize, tileSize) - halfTileSize);
color = mix(
color,
tileBorderColor,
smoothstep(aa, .0, min(b.x, b.y))
);
color = mix(
color,
chunkBorderColor,
smoothstep(aa, .0, min(a.x, a.y))
);
}
gl_FragColor.rgb = color;
gl_FragColor.a = 1.0;
}
您需要将顶点着色器中的乘法拆分为两部分:
// have a variable to be interpolated per fragment
out vec2 vertex_coordinate;
...
{
// this will store the coordinates of the vertex
// before its projected (i.e. its "world" coordinates)
vertex_coordinate = gl_ModelViewMatrix * gl_Vertex;
// get your projected vertex position as before
gl_Position = gl_ProjectionMatrix * vertex_coordinate;
...
}
然后在片段着色器中根据世界顶点坐标和相机位置更改颜色:
in vec2 vertex_coordinate;
// have to update this value, every time your camera changes its position
uniform vec2 camera_world_position = vec2(64.0, 64.0);
...
{
...
// calculate the distance from the fragment in world coordinates to the camera
float fade_factor = length(camera_world_position - vertex_coordinate);
// make it to be 1 near the camera and 0 if its more then 100 units.
fade_factor = clamp(1.0 - fade_factor / 100.0, 0.0, 1.0);
// update your final color with this factor
gl_FragColor.rgb = color * fade_factor;
...
}
第二种方法是使用投影坐标 w
。我个人更喜欢以space为单位来计算距离。我没有测试这段代码,它可能有一些琐碎的语法错误,但如果你理解这个想法,你可以以任何其他方式应用它。
我目前正在尝试仅使用着色器在单个四边形上绘制二维网格。我使用 SFML 作为图形库并使用 sf::View 来控制相机。到目前为止,我已经能够绘制抗锯齿多级网格。第一层(蓝色)勾勒出一个块,第二层(灰色)勾勒出块内的图块。
我现在想根据与相机的距离淡化网格级别。例如,当相机放大时,块网格应该淡入。在块网格完全淡入后,块网格也应该这样做。
我不确定如何实现,因为我对 OpenGL 和 GLSL 还是个新手。如果有人对如何实现此功能有任何指示,请告诉我。
顶点着色器
#version 130
out vec2 texCoords;
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
texCoords = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
}
片段着色器
#version 130
uniform vec2 chunkSize = vec2(64.0, 64.0);
uniform vec2 tileSize = vec2(16.0, 16.0);
uniform vec3 chunkBorderColor = vec3(0.0, 0.0, 1.0);
uniform vec3 tileBorderColor = vec3(0.5, 0.5, 0.5);
uniform bool drawGrid = true;
in vec2 texCoords;
void main() {
vec2 uv = texCoords.xy * chunkSize;
vec3 color = vec3(1.0, 1.0, 1.0);
if(drawGrid) {
float aa = length(fwidth(uv));
vec2 halfChunkSize = chunkSize / 2.0;
vec2 halfTileSize = tileSize / 2.0;
vec2 a = abs(mod(uv - halfChunkSize, chunkSize) - halfChunkSize);
vec2 b = abs(mod(uv - halfTileSize, tileSize) - halfTileSize);
color = mix(
color,
tileBorderColor,
smoothstep(aa, .0, min(b.x, b.y))
);
color = mix(
color,
chunkBorderColor,
smoothstep(aa, .0, min(a.x, a.y))
);
}
gl_FragColor.rgb = color;
gl_FragColor.a = 1.0;
}
您需要将顶点着色器中的乘法拆分为两部分:
// have a variable to be interpolated per fragment
out vec2 vertex_coordinate;
...
{
// this will store the coordinates of the vertex
// before its projected (i.e. its "world" coordinates)
vertex_coordinate = gl_ModelViewMatrix * gl_Vertex;
// get your projected vertex position as before
gl_Position = gl_ProjectionMatrix * vertex_coordinate;
...
}
然后在片段着色器中根据世界顶点坐标和相机位置更改颜色:
in vec2 vertex_coordinate;
// have to update this value, every time your camera changes its position
uniform vec2 camera_world_position = vec2(64.0, 64.0);
...
{
...
// calculate the distance from the fragment in world coordinates to the camera
float fade_factor = length(camera_world_position - vertex_coordinate);
// make it to be 1 near the camera and 0 if its more then 100 units.
fade_factor = clamp(1.0 - fade_factor / 100.0, 0.0, 1.0);
// update your final color with this factor
gl_FragColor.rgb = color * fade_factor;
...
}
第二种方法是使用投影坐标 w
。我个人更喜欢以space为单位来计算距离。我没有测试这段代码,它可能有一些琐碎的语法错误,但如果你理解这个想法,你可以以任何其他方式应用它。