GLSL: Исчезающая 2D-сетка, основанная на расстоянии от камеры

#c #opengl #glsl #2d #sfml

Вопрос:

В настоящее время я пытаюсь нарисовать 2D-сетку на одном квадрате, используя только шейдеры. Я использую 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; }   

Ответ №1:

Вам нужно разделить умножение в шейдере вершин на две части:

 // 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 . Лично я предпочитаю вычислять расстояние в единицах пространства. Я не тестировал этот код, в нем могут быть некоторые тривиальные синтаксические ошибки, но если вы понимаете идею, вы можете применить ее любым другим способом.