New Grid : Feature parity with old grid.

Removed infinite details and went for decreasing details with the distance instead (like the axis aligned ortho view auto sized grid).
Separate drawing of the Z axis into 2 pass (using shading group) to render ordered transparency with the main grid pass.
This commit is contained in:
Clément Foucault 2017-03-25 02:46:23 +01:00
parent d2c94c7873
commit 0495e689e6
3 changed files with 267 additions and 48 deletions

View File

@ -35,6 +35,7 @@
#include "BKE_camera.h"
#include "BKE_global.h"
#include "ED_view3d.h"
#include "ED_view3d.h"
#include "GPU_shader.h"
@ -164,8 +165,24 @@ static struct {
float camera_pos[3];
float grid_settings[4];
float grid_mat[4][4];
int grid_flag;
int zpos_flag;
int zneg_flag;
} e_data = {NULL}; /* Engine data */
enum {
SHOW_AXIS_X = (1 << 0),
SHOW_AXIS_Y = (1 << 1),
SHOW_AXIS_Z = (1 << 2),
SHOW_GRID = (1 << 3),
PLANE_XY = (1 << 4),
PLANE_XZ = (1 << 5),
PLANE_YZ = (1 << 6),
CLIP_ZPOS = (1 << 7),
CLIP_ZNEG = (1 << 8),
};
/* *********** FUNCTIONS *********** */
static void OBJECT_engine_init(void)
@ -206,7 +223,20 @@ static void OBJECT_engine_init(void)
}
{
float viewinvmat[4][4], winmat[4][4], viewmat[4][4];
/* Grid precompute */
float viewinvmat[4][4], winmat[4][4], invwinmat[4][4], viewmat[4][4];
const bContext *C = DRW_get_context();
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float grid_scale = ED_view3d_grid_scale(scene, v3d, NULL);
float grid_res, offs;
const bool show_axis_x = v3d->gridflag & V3D_SHOW_X;
const bool show_axis_y = v3d->gridflag & V3D_SHOW_Y;
const bool show_axis_z = v3d->gridflag & V3D_SHOW_Z;
const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR);
DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
DRW_viewport_matrix_get(viewinvmat, DRW_MAT_VIEWINV);
@ -214,29 +244,113 @@ static void OBJECT_engine_init(void)
/* Setup camera pos */
copy_v3_v3(e_data.camera_pos, viewinvmat[3]);
/* grid settings */
const bContext *C = DRW_get_context();
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
/* if perps */
if (winmat[3][3] == 0.0f) {
float fov;
float viewvecs[2][4] = {
{1.0f, -1.0f, -1.0f, 1.0f},
{-1.0f, 1.0f, -1.0f, 1.0f}
};
/* invert the proj matrix */
invert_m4_m4(invwinmat, winmat);
e_data.grid_settings[0] = 100.0f; /* gridDistance */
e_data.grid_settings[1] = 2.0f; /* gridResolution */
e_data.grid_settings[2] = ED_view3d_grid_scale(scene, v3d, NULL); /* gridScale */
e_data.grid_settings[3] = v3d->gridsubdiv; /* gridSubdiv */
/* convert the view vectors to view space */
for (int i = 0; i < 2; i++) {
mul_m4_v4(invwinmat, viewvecs[i]);
mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); /* normalize */
}
/* Grid matrix polygon offset (fix depth fighting) */
/* see ED_view3d_polygon_offset */
float offs;
if (winmat[3][3] > 0.5f) {
float viewdist = 1.0f / max_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
offs = 0.00001f * viewdist;
fov = angle_v3v3(viewvecs[0], viewvecs[1]) / 2.0f;
grid_res = fabsf(tanf(fov)) / grid_scale;
/* Grid matrix polygon offset (fix depth fighting) */
/* see ED_view3d_polygon_offset */
offs = winmat[3][2] * -0.0025f;
e_data.grid_flag = (1 << 4); /* XY plane */
if (show_axis_x)
e_data.grid_flag |= SHOW_AXIS_X;
if (show_axis_y)
e_data.grid_flag |= SHOW_AXIS_Y;
if (show_floor)
e_data.grid_flag |= SHOW_GRID;
}
else {
offs = winmat[3][2] * -0.0025f;
}
winmat[3][2] -= offs;
float viewdist = 1.0f / max_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
grid_res = viewdist / grid_scale;
/* Grid matrix polygon offset (fix depth fighting) */
/* see ED_view3d_polygon_offset */
offs = 0.00001f * viewdist;
if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) {
e_data.grid_flag = PLANE_YZ;
e_data.grid_flag |= SHOW_AXIS_Y;
e_data.grid_flag |= SHOW_AXIS_Z;
e_data.grid_flag |= SHOW_GRID;
}
else if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
e_data.grid_flag = PLANE_XY;
e_data.grid_flag |= SHOW_AXIS_X;
e_data.grid_flag |= SHOW_AXIS_Y;
e_data.grid_flag |= SHOW_GRID;
}
else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
e_data.grid_flag = PLANE_XZ;
e_data.grid_flag |= SHOW_AXIS_X;
e_data.grid_flag |= SHOW_AXIS_Z;
e_data.grid_flag |= SHOW_GRID;
}
else { /* RV3D_VIEW_USER */
e_data.grid_flag = PLANE_XY;
if (show_axis_x)
e_data.grid_flag |= SHOW_AXIS_X;
if (show_axis_y)
e_data.grid_flag |= SHOW_AXIS_Y;
if (show_floor)
e_data.grid_flag |= SHOW_GRID;
}
}
/* Z axis if needed */
if ((rv3d->view == RV3D_VIEW_USER) && show_axis_z) {
e_data.zpos_flag = SHOW_AXIS_Z;
float zvec[4] = {0.0f, 0.0f, -1.0f, 0.0f};
mul_m4_v4(viewinvmat, zvec);
/* z axis : chose the most facing plane */
if (fabsf(zvec[0]) > fabsf(zvec[1])) {
e_data.zpos_flag |= (PLANE_XZ | SHOW_AXIS_X);
}
else {
e_data.zpos_flag |= (PLANE_YZ | SHOW_AXIS_Y);
}
e_data.zneg_flag = e_data.zpos_flag;
/* Persp : If camera is below floor plane, we switch clipping
* Ortho : If eye vector is looking up, we switch clipping */
if (((winmat[3][3] == 0.0f) && (e_data.camera_pos[2] > 0.0f)) ||
((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f))) {
e_data.zpos_flag |= CLIP_ZPOS;
e_data.zneg_flag |= CLIP_ZNEG;
}
else {
e_data.zpos_flag |= CLIP_ZNEG;
e_data.zneg_flag |= CLIP_ZPOS;
}
}
else {
e_data.zneg_flag = e_data.zpos_flag = 0;
}
winmat[3][2] -= offs;
mul_m4_m4m4(e_data.grid_mat, winmat, viewmat);
e_data.grid_settings[0] = v3d->far / 2.0f; /* gridDistance */
e_data.grid_settings[1] = grid_res; /* gridResolution */
e_data.grid_settings[2] = grid_scale; /* gridScale */
e_data.grid_settings[3] = v3d->gridsubdiv; /* gridSubdiv */
}
}
@ -382,12 +496,22 @@ static void OBJECT_cache_init(void)
struct Batch *quad = DRW_cache_fullscreen_quad_get();
/* Create 3 quads to render ordered transparency Z axis */
DRWShadingGroup *grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zneg_flag, 1);
DRW_shgroup_uniform_mat4(grp, "ViewProjectionOffsetMatrix", (float *)e_data.grid_mat);
DRW_shgroup_uniform_vec3(grp, "cameraPos", e_data.camera_pos, 1);
DRW_shgroup_uniform_vec4(grp, "gridSettings", e_data.grid_settings, 1);
DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo, 0);
DRW_shgroup_call_add(grp, quad, NULL);
grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.grid_flag, 1);
DRW_shgroup_call_add(grp, quad, NULL);
grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zpos_flag, 1);
DRW_shgroup_call_add(grp, quad, NULL);
}
{

View File

@ -15,19 +15,29 @@ uniform vec4 gridSettings;
#define gridScale gridSettings.z
#define gridSubdiv gridSettings.w
uniform int gridFlag;
#define AXIS_X (1 << 0)
#define AXIS_Y (1 << 1)
#define AXIS_Z (1 << 2)
#define GRID (1 << 3)
#define PLANE_XY (1 << 4)
#define PLANE_XZ (1 << 5)
#define PLANE_YZ (1 << 6)
#define GRID_LINE_SMOOTH 1.15
float grid(vec2 uv, vec2 fwidthUvs, float grid_size)
float grid(vec3 uv, vec3 fwidthCos, float grid_size)
{
float half_size = grid_size / 2.0;
/* triangular wave pattern, amplitude is [0, grid_size] */
vec2 grid_domain = abs(mod(uv + half_size, grid_size) - half_size);
vec3 grid_domain = abs(mod(uv + half_size, grid_size) - half_size);
/* modulate by the absolute rate of change of the uvs
* (make lines have the same width under perspective) */
grid_domain /= fwidthUvs;
grid_domain /= fwidthCos;
/* collapse waves and normalize */
grid_domain.x = min(grid_domain.x, grid_domain.y) / grid_size;
grid_domain.x = min(grid_domain.x, min(grid_domain.y, grid_domain.z)) / grid_size;
return 1.0 - smoothstep(0.0, GRID_LINE_SMOOTH / grid_size, grid_domain.x);
}
@ -44,43 +54,78 @@ float axis(float u, float fwidthU, float line_size)
void main()
{
vec2 fwidthUvs = fwidth(wPos.xy);
float blend, lvl, fade;
vec3 fwidthCos = fwidth(wPos);
float fade, grid_res;
/* if persp */
if (ProjectionMatrix[3][3] == 0.0) {
float dist = distance(cameraPos, wPos);
float log2dist = -log2(dist / (2.0 * gridDistance));
blend = fract(log2dist / gridResolution);
lvl = floor(log2dist / gridResolution);
float dist_norm = dist / (2.0 * gridDistance);
grid_res = log(dist * gridResolution) / log(gridSubdiv);
fade = 1.0 - smoothstep(0.0, gridDistance, dist - gridDistance);
}
else {
/* todo find a better way */
blend = 0.0;
lvl = 0.0;
fade = 1.0;
float dist = abs(gl_FragCoord.z * 2.0 - 1.0);
grid_res = log(gridResolution) / log(gridSubdiv);
fade = 1.0 - smoothstep(0.0, 0.5, dist - 0.5);
}
/* from smallest to biggest */
float scaleA = gridScale * pow(gridSubdiv, min(-lvl + 1.0, 1.0));
float scaleB = gridScale * pow(gridSubdiv, min(-lvl + 2.0, 1.0));
float scaleC = gridScale * pow(gridSubdiv, min(-lvl + 3.0, 1.0));
/* fix division by 0 (log(1) = 0) */
if (gridSubdiv == 1.0) {
grid_res = 0.0;
}
float gridA = grid(wPos.xy, fwidthUvs, scaleA);
float gridB = grid(wPos.xy, fwidthUvs, scaleB);
float gridC = grid(wPos.xy, fwidthUvs, scaleC);
if ((gridFlag & GRID) > 0) {
float blend = fract(-max(grid_res, 0.0));
float lvl = floor(grid_res);
float xAxis = axis(wPos.y, fwidthUvs.y, 0.1); /* Swapped */
float yAxis = axis(wPos.x, fwidthUvs.x, 0.1); /* Swapped */
/* from smallest to biggest */
float scaleA = gridScale * pow(gridSubdiv, max(lvl - 1.0, 0.0));
float scaleB = gridScale * pow(gridSubdiv, max(lvl + 0.0, 0.0));
float scaleC = gridScale * pow(gridSubdiv, max(lvl + 1.0, 1.0));
FragColor = vec4(colorGrid.rgb, gridA * blend);
FragColor = mix(FragColor, vec4(mix(colorGrid.rgb, colorGridEmphasise.rgb, blend), 1.0), gridB);
FragColor = mix(FragColor, vec4(colorGridEmphasise.rgb, 1.0), gridC);
float gridA = grid(wPos, fwidthCos, scaleA);
float gridB = grid(wPos, fwidthCos, scaleB);
float gridC = grid(wPos, fwidthCos, scaleC);
FragColor = vec4(colorGrid.rgb, gridA * blend);
FragColor = mix(FragColor, vec4(mix(colorGrid.rgb, colorGridEmphasise.rgb, blend), 1.0), gridB);
FragColor = mix(FragColor, vec4(colorGridEmphasise.rgb, 1.0), gridC);
}
else {
FragColor = vec4(colorGrid.rgb, 0.0);
}
if ((gridFlag & AXIS_X) > 0) {
float xAxis;
if ((gridFlag & AXIS_Y) > 0) {
xAxis = axis(wPos.y, fwidthCos.y, 0.1);
}
else {
xAxis = axis(wPos.z, fwidthCos.z, 0.1);
}
FragColor = mix(FragColor, colorGridAxisX, xAxis);
}
if ((gridFlag & AXIS_Y) > 0) {
float yAxis;
if ((gridFlag & AXIS_X) > 0) {
yAxis = axis(wPos.x, fwidthCos.x, 0.1);
}
else {
yAxis = axis(wPos.z, fwidthCos.z, 0.1);
}
FragColor = mix(FragColor, colorGridAxisY, yAxis);
}
if ((gridFlag & AXIS_Z) > 0) {
float zAxis;
if ((gridFlag & AXIS_Y) > 0) {
zAxis = axis(wPos.y, fwidthCos.y, 0.1);
}
else {
zAxis = axis(wPos.x, fwidthCos.x, 0.1);
}
FragColor = mix(FragColor, colorGridAxisZ, zAxis);
}
FragColor = mix(FragColor, colorGridAxisX, xAxis);
FragColor = mix(FragColor, colorGridAxisY, yAxis);
FragColor.a *= fade;
}

View File

@ -3,6 +3,22 @@
* Clément Foucault */
uniform mat4 ViewProjectionOffsetMatrix;
uniform mat4 ProjectionMatrix;
uniform vec3 cameraPos;
uniform vec4 gridSettings;
#define gridDistance gridSettings.x
#define gridResolution gridSettings.y
#define gridScale gridSettings.z
#define gridSubdiv gridSettings.w
uniform int gridFlag;
#define PLANE_XY (1 << 4)
#define PLANE_XZ (1 << 5)
#define PLANE_YZ (1 << 6)
#define CLIP_Z_POS (1 << 7)
#define CLIP_Z_NEG (1 << 8)
in vec3 pos;
@ -10,7 +26,41 @@ out vec3 wPos;
void main()
{
vec3 realPos = pos * 1e3;
vec3 vert_pos, proj_camera_pos;
/* Project camera pos to the needed plane */
if ((gridFlag & PLANE_XY) > 0) {
vert_pos = vec3(pos.x, pos.y, 0.0);
proj_camera_pos = vec3(cameraPos.x, cameraPos.y, 0.0);
}
else if ((gridFlag & PLANE_XZ) > 0) {
vert_pos = vec3(pos.x, 0.0, pos.y);
proj_camera_pos = vec3(cameraPos.x, 0.0, cameraPos.z);
}
else {
vert_pos = vec3(0.0, pos.x, pos.y);
proj_camera_pos = vec3(0.0, cameraPos.y, cameraPos.z);
}
/* if persp */
if (ProjectionMatrix[3][3] == 0.0) {
vert_pos *= gridDistance * 2.0;
}
else {
float viewdist = 1.0f / min(abs(ProjectionMatrix[0][0]), abs(ProjectionMatrix[1][1]));
vert_pos *= viewdist * gridDistance * 2.0;
}
vec3 realPos = proj_camera_pos + vert_pos;
/* Used for additional Z axis */
if ((gridFlag & CLIP_Z_POS) > 0) {
realPos.z = max(realPos.z, 0.0);
}
else if ((gridFlag & CLIP_Z_NEG) > 0) {
realPos.z = min(realPos.z, 0.0);
}
gl_Position = ViewProjectionOffsetMatrix * vec4(realPos, 1.0);
wPos = realPos;
}