Files
test2/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl
Clément Foucault fe213f80a4 GPU: Shader: Make info files generated
This is the first step of moving the create infos
back inside shader sources.

All info files are now treated as source files.
However, they are not considered in the include tree
yet. This will come in another following PR.

Each shader source file now generate a `.info` file
containing only the create info declarations.

This renames all info files so that they do not
conflict with their previous versions that were
copied (non-generated).

Pull Request: https://projects.blender.org/blender/blender/pulls/146676
2025-09-25 10:57:02 +02:00

219 lines
7.5 KiB
GLSL

/* SPDX-FileCopyrightText: 2017-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "infos/overlay_grid_infos.hh"
FRAGMENT_SHADER_CREATE_INFO(overlay_grid_next)
/**
* Infinite grid:
* Draw anti-aliased grid and axes of different sizes with smooth blending between levels of
* detail. We draw multiple triangles to avoid float precision issues due to perspective
* interpolation.
*/
#include "draw_view_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
float get_grid(float2 co, float2 fwidthCos, float2 grid_scale)
{
float2 half_size = grid_scale / 2.0f;
/* Triangular wave pattern, amplitude is [0, half_size]. */
float2 grid_domain = abs(mod(co + half_size, grid_scale) - half_size);
/* Modulate by the absolute rate of change of the coordinates
* (make line have the same width under perspective). */
grid_domain /= fwidthCos;
/* Collapse waves. */
float line_dist = min(grid_domain.x, grid_domain.y);
return 1.0 - LINE_STEP(line_dist - grid_buf.line_size);
}
float3 get_axes(float3 co, float3 fwidthCos, float line_size)
{
float3 axes_domain = abs(co);
/* Modulate by the absolute rate of change of the coordinates
* (make line have the same width under perspective). */
axes_domain /= fwidthCos;
return 1.0 - LINE_STEP(axes_domain - (line_size + grid_buf.line_size));
}
#define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0f, 1.0f))
void main()
{
float3 P = local_pos * grid_buf.size.xyz;
float3 dFdxPos = gpu_dfdx(P);
float3 dFdyPos = gpu_dfdy(P);
float3 fwidthPos = abs(dFdxPos) + abs(dFdyPos);
P += drw_view_position() * plane_axes;
float dist, fade;
bool is_persp = drw_view().winmat[3][3] == 0.0f;
if (is_persp) {
float3 V = drw_view_position() - P;
dist = length(V);
V /= dist;
float angle;
if (flag_test(grid_flag, PLANE_XZ)) {
angle = V.y;
}
else if (flag_test(grid_flag, PLANE_YZ)) {
angle = V.x;
}
else {
angle = V.z;
}
angle = 1.0f - abs(angle);
angle *= angle;
fade = 1.0f - angle * angle;
fade *= 1.0f - smoothstep(0.0f, grid_buf.distance, dist - grid_buf.distance);
}
else {
dist = gl_FragCoord.z * 2.0f - 1.0f;
/* Avoid fading in +Z direction in camera view (see #70193). */
dist = flag_test(grid_flag, GRID_CAMERA) ? clamp(dist, 0.0f, 1.0f) : abs(dist);
fade = 1.0f - smoothstep(0.0f, 0.5f, dist - 0.5f);
dist = 1.0f; /* Avoid branch after. */
if (flag_test(grid_flag, PLANE_XY)) {
float angle = 1.0f - abs(drw_view().viewinv[2].z);
dist = 1.0f + angle * 2.0f;
angle *= angle;
fade *= 1.0f - angle * angle;
}
}
if (flag_test(grid_flag, SHOW_GRID)) {
/* Using `max(dot(dFdxPos, drw_view().viewinv[0]), dot(dFdyPos, drw_view().viewinv[1]))`
* would be more accurate, but not really necessary. */
float grid_res = dot(dFdxPos, drw_view().viewinv[0].xyz);
/* The grid begins to appear when it comprises 4 pixels. */
grid_res *= 4;
/* For UV/Image editor use grid_buf.zoom_factor. */
if (flag_test(grid_flag, PLANE_IMAGE) &&
/* Grid begins to appear when the length of one grid unit is at least
* (256/grid_size) pixels Value of grid_size defined in `overlay_grid.c`. */
!flag_test(grid_flag, CUSTOM_GRID))
{
grid_res = grid_buf.zoom_factor;
}
/** Keep in sync with `SI_GRID_STEPS_LEN` in `DNA_space_types.h`. */
#define STEPS_LEN 8
int step_id_x = STEPS_LEN - 1;
int step_id_y = STEPS_LEN - 1;
/* Loop backwards a compile-time-constant number of steps. */
for (int i = STEPS_LEN - 2; i >= 0; --i) {
step_id_x = (grid_res < grid_buf.steps[i].x) ? i : step_id_x; /* Branchless. */
step_id_y = (grid_res < grid_buf.steps[i].y) ? i : step_id_y;
}
/* From biggest to smallest. */
float scale0x = step_id_x > 0 ? grid_buf.steps[step_id_x - 1].x : 0.0f;
float scaleAx = grid_buf.steps[step_id_x].x;
float scaleBx = grid_buf.steps[min(step_id_x + 1, STEPS_LEN - 1)].x;
float scaleCx = grid_buf.steps[min(step_id_x + 2, STEPS_LEN - 1)].x;
float scale0y = step_id_y > 0 ? grid_buf.steps[step_id_y - 1].y : 0.0f;
float scaleAy = grid_buf.steps[step_id_y].y;
float scaleBy = grid_buf.steps[min(step_id_y + 1, STEPS_LEN - 1)].y;
float scaleCy = grid_buf.steps[min(step_id_y + 2, STEPS_LEN - 1)].y;
/* Subtract from 1.0 to fix blending when `scale0x == scaleAx`. */
float blend = 1.0f - linearstep(scale0x + scale0y, scaleAx + scaleAy, grid_res + grid_res);
blend = blend * blend * blend;
float2 grid_pos, grid_fwidth;
if (flag_test(grid_flag, PLANE_XZ)) {
grid_pos = P.xz;
grid_fwidth = fwidthPos.xz;
}
else if (flag_test(grid_flag, PLANE_YZ)) {
grid_pos = P.yz;
grid_fwidth = fwidthPos.yz;
}
else {
grid_pos = P.xy;
grid_fwidth = fwidthPos.xy;
}
float gridA = get_grid(grid_pos, grid_fwidth, float2(scaleAx, scaleAy));
float gridB = get_grid(grid_pos, grid_fwidth, float2(scaleBx, scaleBy));
float gridC = get_grid(grid_pos, grid_fwidth, float2(scaleCx, scaleCy));
out_color = theme.colors.grid;
out_color.a *= gridA * blend;
out_color = mix(out_color, mix(theme.colors.grid, theme.colors.grid_emphasis, blend), gridB);
out_color = mix(out_color, theme.colors.grid_emphasis, gridC);
}
else {
out_color = float4(theme.colors.grid.rgb, 0.0f);
}
if (flag_test(grid_flag, (SHOW_AXIS_X | SHOW_AXIS_Y | SHOW_AXIS_Z))) {
/* Setup axes 'domains' */
float3 axes_dist, axes_fwidth;
if (flag_test(grid_flag, SHOW_AXIS_X)) {
axes_dist.x = dot(P.yz, plane_axes.yz);
axes_fwidth.x = dot(fwidthPos.yz, plane_axes.yz);
}
if (flag_test(grid_flag, SHOW_AXIS_Y)) {
axes_dist.y = dot(P.xz, plane_axes.xz);
axes_fwidth.y = dot(fwidthPos.xz, plane_axes.xz);
}
if (flag_test(grid_flag, SHOW_AXIS_Z)) {
axes_dist.z = dot(P.xy, plane_axes.xy);
axes_fwidth.z = dot(fwidthPos.xy, plane_axes.xy);
}
/* Computing all axes at once using float3 */
float3 axes = get_axes(axes_dist, axes_fwidth, 0.1f);
if (flag_test(grid_flag, SHOW_AXIS_X)) {
out_color.a = max(out_color.a, axes.x);
out_color.rgb = (axes.x < 1e-8f) ? out_color.rgb : theme.colors.grid_axis_x.rgb;
}
if (flag_test(grid_flag, SHOW_AXIS_Y)) {
out_color.a = max(out_color.a, axes.y);
out_color.rgb = (axes.y < 1e-8f) ? out_color.rgb : theme.colors.grid_axis_y.rgb;
}
if (flag_test(grid_flag, SHOW_AXIS_Z)) {
out_color.a = max(out_color.a, axes.z);
out_color.rgb = (axes.z < 1e-8f) ? out_color.rgb : theme.colors.grid_axis_z.rgb;
}
}
float2 uv = gl_FragCoord.xy / float2(textureSize(depth_tx, 0));
float scene_depth = texture(depth_tx, uv, 0).r;
float scene_depth_infront = texture(depth_infront_tx, uv, 0).r;
if (scene_depth_infront != 1.0f) {
/* Treat in front objects as if they were on the near plane to occlude the grid. */
scene_depth = 0.0f;
}
if (flag_test(grid_flag, GRID_BACK)) {
fade *= (scene_depth == 1.0f) ? 1.0f : 0.0f;
}
else {
/* Add a small bias so the grid will always be below of a mesh with the same depth. */
float grid_depth = gl_FragCoord.z + 4.8e-7f;
/* Manual, non hard, depth test:
* Progressively fade the grid below occluders
* (avoids popping visuals due to depth buffer precision) */
/* Harder settings tend to flicker more,
* but have less "see through" appearance. */
float bias = max(gpu_fwidth(gl_FragCoord.z), 2.4e-7f);
fade *= linearstep(grid_depth, grid_depth + bias, scene_depth);
}
out_color.a *= fade;
}