DRW: Split ViewProjectionMatrix in order to increase precision

This also removes the need to compute the persmat and saves some memory
from the `ViewInfos` struct. This is needed to allow multiview support.

Initial testing found no major performance regression during vertex
heavy workload.

Test file: {F13610017}

Results:
| Platform | Master | Split Matrix|
| Linux + Mesa + AMD W6600 | 48 fps | 47 fps |
| Macbook Pro M1 | 50 fps | 51 fps |
| Linux + NVidia 1080Ti | 51 fps | 52 fps |
| Linux + Radeon Vega 64 | 25.6 fps | 26.7 fps |

Increased precision when far from origin:
{F13610024}

{F13610025}

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D16125
This commit is contained in:
Clément Foucault 2022-10-05 20:28:51 +02:00
parent 74ff0aeea0
commit 6306d747b7
26 changed files with 52 additions and 50 deletions

@ -1 +1 @@
Subproject commit 726d08c9036b939f46b59bceb72a61e3102600cc
Subproject commit 67f1fbca1482d9d9362a4001332e785c3fd5d230

View File

@ -39,6 +39,6 @@ void main()
vec3 screen_pos = screen_vecs[0] * quadCoord.x + screen_vecs[1] * quadCoord.y;
ws_location += screen_pos * sphere_size;
gl_Position = ViewProjectionMatrix * vec4(ws_location, 1.0);
gl_Position = ProjectionMatrix * (ViewMatrix * vec4(ws_location, 1.0));
gl_Position.z += 0.0001; /* Small bias to let the icon draw without zfighting */
}

View File

@ -42,6 +42,6 @@ void main()
vec3 screen_pos = screen_vecs[0] * quadCoord.x + screen_vecs[1] * quadCoord.y;
ws_cell_location += screen_pos * sphere_size;
gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0);
gl_Position = ProjectionMatrix * (ViewMatrix * vec4(ws_cell_location, 1.0));
gl_Position.z += 0.0001; /* Small bias to let the icon draw without zfighting */
}

View File

@ -203,7 +203,7 @@ vec3 probe_evaluate_planar(int id, PlanarData pd, vec3 P, vec3 N, vec3 V, float
vec3 ref_pos = point_on_plane + proj_ref;
/* Reproject to find texture coords. */
vec4 refco = ViewProjectionMatrix * vec4(ref_pos, 1.0);
vec4 refco = ProjectionMatrix * (ViewMatrix * vec4(ref_pos, 1.0));
refco.xy /= refco.w;
/* TODO: If we support non-ssr planar reflection, we should blur them with gaussian

View File

@ -10,7 +10,7 @@ out vec4 FragColor;
void main()
{
vec4 refco = ViewProjectionMatrix * vec4(worldPosition, 1.0);
vec4 refco = ProjectionMatrix * (ViewMatrix * vec4(worldPosition, 1.0));
refco.xy /= refco.w;
FragColor = vec4(
textureLod(probePlanars, vec3(refco.xy * vec2(-0.5, 0.5) + 0.5, float(probeIdx)), 0.0).rgb,

View File

@ -12,6 +12,6 @@ flat out int probeIdx;
void main()
{
worldPosition = (probe_mat * vec4(-pos.x, pos.y, 0.0, 1.0)).xyz;
gl_Position = ViewProjectionMatrix * vec4(worldPosition, 1.0);
gl_Position = ProjectionMatrix * (ViewMatrix * vec4(worldPosition, 1.0));
probeIdx = probe_id;
}

View File

@ -52,8 +52,8 @@ void main()
/* Use jittered projmatrix to be able to match exact sample depth (depth equal test).
* Note that currModelMatrix needs to also be equal to ModelMatrix for the samples to match. */
#ifndef HAIR
gl_Position = ViewProjectionMatrix * vec4(currWorldPos, 1.0);
gl_Position = ProjectionMatrix * (ViewMatrix * vec4(currWorldPos, 1.0));
#else
gl_Position = ViewProjectionMatrix * vec4(wpos, 1.0);
gl_Position = ProjectionMatrix * (ViewMatrix * vec4(wpos, 1.0));
#endif
}

View File

@ -181,7 +181,7 @@ vec3 coordinate_screen(vec3 P)
window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
#else /* MESH */
window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5;
window.xy = project_point(ProjectionMatrix, transform_point(ViewMatrix, P)).xy * 0.5 + 0.5;
window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
#endif
return window;

View File

@ -52,7 +52,7 @@ vec3 coordinate_camera(vec3 P)
vec3 coordinate_screen(vec3 P)
{
vec3 window = vec3(0.0);
window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5;
window.xy = project_point(ProjectionMatrix, transform_point(ViewMatrix, P)).xy * 0.5 + 0.5;
window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
return window;
}

View File

@ -117,7 +117,7 @@ vec3 light_volume_light_vector(LightData ld, vec3 P)
vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction)
{
/* Waiting for proper volume shadowmaps and out of frustum shadow map. */
vec3 ndc = project_point(ViewProjectionMatrix, wpos);
vec3 ndc = project_point(ProjectionMatrix, transform_point(ViewMatrix, wpos));
vec3 volume_co = ndc_to_volume(ndc * 0.5 + 0.5);
/* Let the texture be clamped to edge. This reduce visual glitches. */
@ -147,12 +147,15 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v
if (ld.l_type == SUN) {
/* For sun light we scan the whole frustum. So we need to get the correct endpoints. */
vec3 ndcP = project_point(ViewProjectionMatrix, ray_wpos);
vec3 ndcL = project_point(ViewProjectionMatrix, ray_wpos + l_vector.xyz) - ndcP;
vec3 ndcP = project_point(ProjectionMatrix, transform_point(ViewMatrix, ray_wpos));
vec3 ndcL = project_point(ProjectionMatrix,
transform_point(ViewMatrix, ray_wpos + l_vector.xyz)) -
ndcP;
vec3 frustum_isect = ndcP + ndcL * line_unit_box_intersect_dist_safe(ndcP, ndcL);
L = project_point(ViewProjectionMatrixInverse, frustum_isect) - ray_wpos;
vec4 L_hom = ViewMatrixInverse * (ProjectionMatrixInverse * vec4(frustum_isect, 1.0));
L = (L_hom.xyz / L_hom.w) - ray_wpos;
L /= volShadowSteps;
dd = length(L);
}

View File

@ -17,7 +17,7 @@ void main()
gl_Position = vec4(pos, 1.0, 1.0);
viewPosition = project_point(ProjectionMatrixInverse, vec3(pos, 0.0));
worldPosition = project_point(ViewProjectionMatrixInverse, vec3(pos, 0.0));
worldPosition = transform_point(ViewMatrixInverse, viewPosition);
/* Not usable. */
viewNormal = vec3(0.0);
worldNormal = vec3(0.0);

View File

@ -344,7 +344,7 @@ vec3 coordinate_screen(vec3 P)
}
else {
/* TODO(fclem): Actual camera transform. */
window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5;
window.xy = project_point(ProjectionMatrix, transform_point(ViewMatrix, P)).xy * 0.5 + 0.5;
window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
}
return window;

View File

@ -5,5 +5,5 @@ void main()
int v = gl_VertexID % 3;
float x = -1.0 + float((v & 1) << 2);
float y = -1.0 + float((v & 2) << 1);
gl_Position = drw_view.persmat * (model_matrix * vec4(x, y, 0.0, 1.0));
gl_Position = drw_view.winmat * (drw_view.viewmat * (model_matrix * vec4(x, y, 0.0, 1.0)));
}

View File

@ -38,5 +38,5 @@ void main()
view_clipping_distances(sp);
vec4 pos_4d = vec4(sp, 1.0);
gl_Position = drw_view.persmat * pos_4d;
gl_Position = drw_view.winmat * (drw_view.viewmat * pos_4d);
}

View File

@ -25,7 +25,7 @@ void main()
finalColor.a = 1.0;
vec4 world_pos = model_mat * vec4(pos, 1.0);
gl_Position = drw_view.persmat * world_pos;
gl_Position = drw_view.winmat * (drw_view.viewmat * world_pos);
view_clipping_distances(world_pos.xyz);
}

View File

@ -9,7 +9,7 @@ void main()
vec3 up = normalize(imat * screenVecs[1].xyz);
vec3 screen_pos = (right * pos.x + up * pos.z) * size;
vec4 pos_4d = ModelMatrix * vec4(local_pos + screen_pos, 1.0);
gl_Position = drw_view.persmat * pos_4d;
gl_Position = drw_view.winmat * (drw_view.viewmat * pos_4d);
/* Manual stipple: one segment out of 2 is transparent. */
finalColor = ((gl_VertexID & 1) == 0) ? colorSkinRoot : vec4(0.0);

View File

@ -39,5 +39,5 @@ void main()
local_pos.z = clamp(local_pos.z, -1.0, 0.0);
}
gl_Position = drw_view.persmat * vec4(real_pos, 1.0);
gl_Position = drw_view.winmat * (drw_view.viewmat * vec4(real_pos, 1.0));
}

View File

@ -18,7 +18,7 @@ vec2 proj(vec4 pos)
void main()
{
gl_Position = drw_view.persmat * vec4(pos, 1.0);
gl_Position = drw_view.winmat * (drw_view.viewmat * vec4(pos, 1.0));
interp.ss_pos = proj(gl_Position);

View File

@ -108,8 +108,8 @@ void main()
vec3 in_pos0 = vertex_fetch_attribute(base_vertex_id, pos, vec3);
vec3 in_pos1 = vertex_fetch_attribute(base_vertex_id + 1, pos, vec3);
vec4 out_pos0 = ViewProjectionMatrix * vec4(in_pos0, 1.0);
vec4 out_pos1 = ViewProjectionMatrix * vec4(in_pos1, 1.0);
vec4 out_pos0 = ProjectionMatrix * (ViewMatrix * vec4(in_pos0, 1.0));
vec4 out_pos1 = ProjectionMatrix * (ViewMatrix * vec4(in_pos1, 1.0));
/* Final calculations required for Geometry Shader alternative.
* We need to calculate values for each vertex position to correctly determine the final output

View File

@ -9,7 +9,7 @@
void main()
{
gl_Position = drw_view.persmat * vec4(pos, 1.0);
gl_Position = drw_view.winmat * (drw_view.viewmat * vec4(pos, 1.0));
gl_PointSize = float(pointSize + 2);
int frame = gl_VertexID + cacheStart;

View File

@ -25,7 +25,7 @@ void main()
bool is_persp = drw_view.winmat[3][3] == 0.0;
vec2 uvs = vec2(gl_FragCoord.xy) * drw_view.viewport_size_inverse;
vec3 pos_ndc = vec3(uvs, gl_FragCoord.z) * 2.0 - 1.0;
vec4 pos_world = drw_view.persinv * vec4(pos_ndc, 1.0);
vec4 pos_world = drw_view.viewinv * (drw_view.wininv * vec4(pos_ndc, 1.0));
vec3 pos = pos_world.xyz / pos_world.w;
vec3 ray_ori = pos;

View File

@ -442,6 +442,9 @@ struct DRWView {
struct DRWView *parent;
ViewInfos storage;
float4x4 persmat;
float4x4 persinv;
/** Number of active clip planes. */
int clip_planes_len;
/** Does culling result needs to be updated. */

View File

@ -695,7 +695,7 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
drw_call_calc_orco(ob, ob_infos->orcotexfac);
/* Random float value. */
uint random = (DST.dupli_source) ?
DST.dupli_source->random_id :
DST.dupli_source->random_id :
/* TODO(fclem): this is rather costly to do at runtime. Maybe we can
* put it in ob->runtime and make depsgraph ensure it is up to date. */
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
@ -2133,18 +2133,20 @@ static void draw_frustum_bound_sphere_calc(const BoundBox *bbox,
}
}
static void draw_view_matrix_state_update(ViewInfos *storage,
static void draw_view_matrix_state_update(DRWView *view,
const float viewmat[4][4],
const float winmat[4][4])
{
ViewInfos *storage = &view->storage;
copy_m4_m4(storage->viewmat.values, viewmat);
invert_m4_m4(storage->viewinv.values, storage->viewmat.values);
copy_m4_m4(storage->winmat.values, winmat);
invert_m4_m4(storage->wininv.values, storage->winmat.values);
mul_m4_m4m4(storage->persmat.values, winmat, viewmat);
invert_m4_m4(storage->persinv.values, storage->persmat.values);
mul_m4_m4m4(view->persmat.values, winmat, viewmat);
invert_m4_m4(view->persinv.values, view->persmat.values);
const bool is_persp = (winmat[3][3] == 0.0f);
@ -2260,7 +2262,7 @@ void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float w
view->is_dirty = true;
view->is_inverted = (is_negative_m4(viewmat) == is_negative_m4(winmat));
draw_view_matrix_state_update(&view->storage, viewmat, winmat);
draw_view_matrix_state_update(view, viewmat, winmat);
}
void DRW_view_update(DRWView *view,
@ -2277,7 +2279,7 @@ void DRW_view_update(DRWView *view,
view->is_dirty = true;
view->is_inverted = (is_negative_m4(viewmat) == is_negative_m4(winmat));
draw_view_matrix_state_update(&view->storage, viewmat, winmat);
draw_view_matrix_state_update(view, viewmat, winmat);
/* Prepare frustum culling. */
@ -2318,7 +2320,7 @@ void DRW_view_update(DRWView *view,
}
draw_frustum_boundbox_calc(viewinv, winmat, &view->frustum_corners);
draw_frustum_culling_planes_calc(view->storage.persmat.values, view->frustum_planes);
draw_frustum_culling_planes_calc(view->persmat.values, view->frustum_planes);
draw_frustum_bound_sphere_calc(
&view->frustum_corners, viewinv, winmat, wininv, &view->frustum_bsphere);
@ -2433,8 +2435,7 @@ void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse)
void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse)
{
view = (view) ? view : DST.view_default;
const ViewInfos *storage = &view->storage;
copy_m4_m4(mat, (inverse) ? storage->persinv.values : storage->persmat.values);
copy_m4_m4(mat, (inverse) ? view->persinv.values : view->persmat.values);
}
/** \} */

View File

@ -52,8 +52,6 @@ typedef enum eObjectInfoFlag eObjectInfoFlag;
struct ViewInfos {
/* View matrices */
float4x4 persmat;
float4x4 persinv;
float4x4 viewmat;
float4x4 viewinv;
float4x4 winmat;
@ -86,8 +84,6 @@ BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
/* Do not override old definitions if the shader uses this header but not shader info. */
#ifdef USE_GPU_SHADER_CREATE_INFO
/* TODO(@fclem): Mass rename. */
# define ViewProjectionMatrix drw_view.persmat
# define ViewProjectionMatrixInverse drw_view.persinv
# define ViewMatrix drw_view.viewmat
# define ViewMatrixInverse drw_view.viewinv
# define ProjectionMatrix drw_view.winmat

View File

@ -21,8 +21,6 @@ void View::sync(const float4x4 &view_mat, const float4x4 &win_mat)
data_.viewinv = view_mat.inverted();
data_.winmat = win_mat;
data_.wininv = win_mat.inverted();
data_.persmat = data_.winmat * data_.viewmat;
data_.persinv = data_.persmat.inverted();
/* Should not be used anymore. */
data_.viewcamtexcofac = float4(1.0f, 1.0f, 0.0f, 0.0f);
@ -83,7 +81,8 @@ void View::frustum_boundbox_calc(BoundBox &bbox)
void View::frustum_culling_planes_calc()
{
planes_from_projmat(data_.persmat.ptr(),
float4x4 persmat = data_.winmat * data_.viewmat;
planes_from_projmat(persmat.ptr(),
data_.frustum_planes[0],
data_.frustum_planes[5],
data_.frustum_planes[1],
@ -298,7 +297,8 @@ void View::compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool d
}
#ifdef DEBUG
if (debug_freeze) {
drw_debug_matrix_as_bbox(data_freeze_.persinv, float4(0, 1, 0, 1));
float4x4 persmat = data_freeze_.winmat * data_freeze_.viewmat;
drw_debug_matrix_as_bbox(persmat.inverted(), float4(0, 1, 0, 1));
}
#endif
frozen_ = debug_freeze;

View File

@ -11,9 +11,6 @@
/* keep in sync with DRWManager.view_data */
layout(std140) uniform viewBlock
{
/* Same order as DRWViewportMatrixType */
mat4 ViewProjectionMatrix;
mat4 ViewProjectionMatrixInverse;
mat4 ViewMatrix;
mat4 ViewMatrixInverse;
mat4 ProjectionMatrix;
@ -61,8 +58,9 @@ vec3 cameraVec(vec3 P)
/* TODO move to overlay engine. */
float mul_project_m4_v3_zfac(in vec3 co)
{
return pixelFac * ((ViewProjectionMatrix[0][3] * co.x) + (ViewProjectionMatrix[1][3] * co.y) +
(ViewProjectionMatrix[2][3] * co.z) + ViewProjectionMatrix[3][3]);
vec3 vP = (ViewMatrix * vec4(co, 1.0)).xyz;
return pixelFac * ((ProjectionMatrix[0][3] * vP.x) + (ProjectionMatrix[1][3] * vP.y) +
(ProjectionMatrix[2][3] * vP.z) + ProjectionMatrix[3][3]);
}
#endif
@ -267,13 +265,14 @@ uniform mat4 ModelMatrixInverse;
#define normal_world_to_view(n) (mat3(ViewMatrix) * n)
#define normal_view_to_world(n) (mat3(ViewMatrixInverse) * n)
#define point_object_to_ndc(p) (ViewProjectionMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0))
#define point_object_to_ndc(p) \
(ProjectionMatrix * (ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)))
#define point_object_to_view(p) ((ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)).xyz)
#define point_object_to_world(p) ((ModelMatrix * vec4(p, 1.0)).xyz)
#define point_view_to_ndc(p) (ProjectionMatrix * vec4(p, 1.0))
#define point_view_to_object(p) ((ModelMatrixInverse * (ViewMatrixInverse * vec4(p, 1.0))).xyz)
#define point_view_to_world(p) ((ViewMatrixInverse * vec4(p, 1.0)).xyz)
#define point_world_to_ndc(p) (ViewProjectionMatrix * vec4(p, 1.0))
#define point_world_to_ndc(p) (ProjectionMatrix * (ViewMatrix * vec4(p, 1.0)))
#define point_world_to_object(p) ((ModelMatrixInverse * vec4(p, 1.0)).xyz)
#define point_world_to_view(p) ((ViewMatrix * vec4(p, 1.0)).xyz)