Files
test2/source/blender/draw/intern/shaders/draw_view_finalize_comp.glsl
2025-03-05 15:31:35 +01:00

144 lines
5.1 KiB
GLSL

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* Compute culling data for each views of a given view buffer.
*/
#include "draw_view_info.hh"
#include "draw_view_lib.glsl"
#include "gpu_shader_math_matrix_lib.glsl"
COMPUTE_SHADER_CREATE_INFO(draw_view_finalize)
void projmat_dimensions(mat4 winmat,
out float r_left,
out float r_right,
out float r_bottom,
out float r_top,
out float r_near,
out float r_far)
{
const bool is_persp = winmat[3][3] == 0.0;
if (is_persp) {
float near = winmat[3][2] / (winmat[2][2] - 1.0);
r_left = near * ((winmat[2][0] - 1.0) / winmat[0][0]);
r_right = near * ((winmat[2][0] + 1.0) / winmat[0][0]);
r_bottom = near * ((winmat[2][1] - 1.0) / winmat[1][1]);
r_top = near * ((winmat[2][1] + 1.0) / winmat[1][1]);
r_near = near;
r_far = winmat[3][2] / (winmat[2][2] + 1.0);
}
else {
r_left = (-winmat[3][0] - 1.0) / winmat[0][0];
r_right = (-winmat[3][0] + 1.0) / winmat[0][0];
r_bottom = (-winmat[3][1] - 1.0) / winmat[1][1];
r_top = (-winmat[3][1] + 1.0) / winmat[1][1];
r_near = (winmat[3][2] + 1.0) / winmat[2][2];
r_far = (winmat[3][2] - 1.0) / winmat[2][2];
}
}
void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out FrustumCorners frustum_corners)
{
float left = 0.0, right = 0.0, bottom = 0.0, top = 0.0, near = 0.0, far = 0.0;
bool is_persp = winmat[3][3] == 0.0;
projmat_dimensions(winmat, left, right, bottom, top, near, far);
frustum_corners.corners[0][2] = frustum_corners.corners[3][2] = frustum_corners.corners[7][2] =
frustum_corners.corners[4][2] = -near;
frustum_corners.corners[0][0] = frustum_corners.corners[3][0] = left;
frustum_corners.corners[4][0] = frustum_corners.corners[7][0] = right;
frustum_corners.corners[0][1] = frustum_corners.corners[4][1] = bottom;
frustum_corners.corners[7][1] = frustum_corners.corners[3][1] = top;
/* Get the coordinates of the far plane. */
if (is_persp) {
float sca_far = far / near;
left *= sca_far;
right *= sca_far;
bottom *= sca_far;
top *= sca_far;
}
frustum_corners.corners[1][2] = frustum_corners.corners[2][2] = frustum_corners.corners[6][2] =
frustum_corners.corners[5][2] = -far;
frustum_corners.corners[1][0] = frustum_corners.corners[2][0] = left;
frustum_corners.corners[6][0] = frustum_corners.corners[5][0] = right;
frustum_corners.corners[1][1] = frustum_corners.corners[5][1] = bottom;
frustum_corners.corners[2][1] = frustum_corners.corners[6][1] = top;
/* Transform into world space. */
for (int i = 0; i < 8; i++) {
frustum_corners.corners[i].xyz = transform_point(viewinv, frustum_corners.corners[i].xyz);
}
}
void planes_from_projmat(mat4 mat, out FrustumPlanes frustum_planes)
{
/* References:
*
* https://fgiesen.wordpress.com/2012/08/31/frustum-planes-from-the-projection-matrix/
* http://www8.cs.umu.se/kurser/5DV051/HT12/lab/plane_extraction.pdf
*/
mat = transpose(mat);
frustum_planes.planes[0] = mat[3] + mat[0];
frustum_planes.planes[1] = mat[3] - mat[0];
frustum_planes.planes[2] = mat[3] + mat[1];
frustum_planes.planes[3] = mat[3] - mat[1];
frustum_planes.planes[4] = mat[3] + mat[2];
frustum_planes.planes[5] = mat[3] - mat[2];
}
void frustum_culling_planes_calc(mat4 winmat, mat4 viewmat, out FrustumPlanes frustum_planes)
{
mat4 persmat = winmat * viewmat;
planes_from_projmat(persmat, frustum_planes);
/* Normalize. */
for (int p = 0; p < 6; p++) {
frustum_planes.planes[p] /= length(frustum_planes.planes[p].xyz);
}
}
vec4 frustum_culling_sphere_calc(FrustumCorners frustum_corners)
{
/* Extract Bounding Sphere */
/* TODO(fclem): This is significantly less precise than CPU, but it isn't used in most cases. */
vec4 bsphere;
bsphere.xyz = (frustum_corners.corners[0].xyz + frustum_corners.corners[6].xyz) * 0.5;
bsphere.w = 0.0;
for (int i = 0; i < 8; i++) {
bsphere.w = max(bsphere.w, distance(bsphere.xyz, frustum_corners.corners[i].xyz));
}
return bsphere;
}
void main()
{
drw_view_id = gl_LocalInvocationID.x;
/* Invalid views are disabled. */
if (all(equal(drw_view().viewinv[2].xyz, vec3(0.0)))) {
/* Views with negative radius are treated as disabled. */
view_culling_buf[drw_view_id].bound_sphere = vec4(-1.0);
return;
}
/* Read frustom_corners from device memory, update, and write back. */
FrustumCorners frustum_corners = view_culling_buf[drw_view_id].frustum_corners;
frustum_boundbox_calc(drw_view().winmat, drw_view().viewinv, frustum_corners);
view_culling_buf[drw_view_id].frustum_corners = frustum_corners;
/* Read frustum_planes from device memory, update, and write back. */
FrustumPlanes frustum_planes = view_culling_buf[drw_view_id].frustum_planes;
frustum_culling_planes_calc(drw_view().winmat, drw_view().viewmat, frustum_planes);
view_culling_buf[drw_view_id].frustum_planes = frustum_planes;
view_culling_buf[drw_view_id].bound_sphere = frustum_culling_sphere_calc(frustum_corners);
}