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
146 lines
5.2 KiB
GLSL
146 lines
5.2 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_infos.hh"
|
|
|
|
#include "draw_view_lib.glsl"
|
|
#include "gpu_shader_math_matrix_transform_lib.glsl"
|
|
|
|
COMPUTE_SHADER_CREATE_INFO(draw_view_finalize)
|
|
|
|
void projmat_dimensions(float4x4 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.0f;
|
|
if (is_persp) {
|
|
float near = winmat[3][2] / (winmat[2][2] - 1.0f);
|
|
r_left = near * ((winmat[2][0] - 1.0f) / winmat[0][0]);
|
|
r_right = near * ((winmat[2][0] + 1.0f) / winmat[0][0]);
|
|
r_bottom = near * ((winmat[2][1] - 1.0f) / winmat[1][1]);
|
|
r_top = near * ((winmat[2][1] + 1.0f) / winmat[1][1]);
|
|
r_near = near;
|
|
r_far = winmat[3][2] / (winmat[2][2] + 1.0f);
|
|
}
|
|
else {
|
|
r_left = (-winmat[3][0] - 1.0f) / winmat[0][0];
|
|
r_right = (-winmat[3][0] + 1.0f) / winmat[0][0];
|
|
r_bottom = (-winmat[3][1] - 1.0f) / winmat[1][1];
|
|
r_top = (-winmat[3][1] + 1.0f) / winmat[1][1];
|
|
r_near = (winmat[3][2] + 1.0f) / winmat[2][2];
|
|
r_far = (winmat[3][2] - 1.0f) / winmat[2][2];
|
|
}
|
|
}
|
|
|
|
void frustum_boundbox_calc(float4x4 winmat, float4x4 viewinv, out FrustumCorners frustum_corners)
|
|
{
|
|
float left = 0.0f, right = 0.0f, bottom = 0.0f, top = 0.0f, near = 0.0f, far = 0.0f;
|
|
bool is_persp = winmat[3][3] == 0.0f;
|
|
|
|
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(float4x4 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(float4x4 winmat,
|
|
float4x4 viewmat,
|
|
out FrustumPlanes frustum_planes)
|
|
{
|
|
float4x4 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);
|
|
}
|
|
}
|
|
|
|
float4 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. */
|
|
|
|
float4 bsphere;
|
|
bsphere.xyz = (frustum_corners.corners[0].xyz + frustum_corners.corners[6].xyz) * 0.5f;
|
|
bsphere.w = 0.0f;
|
|
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, float3(0.0f)))) {
|
|
/* Views with negative radius are treated as disabled. */
|
|
view_culling_buf[drw_view_id].bound_sphere = float4(-1.0f);
|
|
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);
|
|
}
|