Skip to content

Commit 2bb73bc

Browse files
committed
A new and improved Light vs AABB intersection testing routine. Resurrection of the old debug draw code.
1 parent 9497e5a commit 2bb73bc

File tree

7 files changed

+904
-102
lines changed

7 files changed

+904
-102
lines changed

examples_tests/60.ClusteredRendering/clipmap/first_cull.comp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ void main()
6060
const uvec3 localClusterID = uvec3(clusterX, clusterY, clusterZ);
6161
const nbl_glsl_shapes_AABB_t cluster = getCluster(localClusterID, levelMinVertex, voxelSideLength);
6262

63-
if (coneIntersectAABB(cone, cluster))
63+
if (lightIntersectAABB(cone, cluster))
6464
{
6565
// Record intersection
6666
intersection_record_t record;

examples_tests/60.ClusteredRendering/clipmap/intermediate_cull.comp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void main()
6363
const uvec3 localClusterID = 2u*(parentVoxelID >> 1u) + uvec3(voxelX, voxelY, voxelZ);
6464
const nbl_glsl_shapes_AABB_t cluster = getCluster(localClusterID, levelMinVertex, voxelSideLength);
6565

66-
if (coneIntersectAABB(cone, cluster))
66+
if (lightIntersectAABB(cone, cluster))
6767
{
6868
// Record intersection
6969
intersection_record_t record;

examples_tests/60.ClusteredRendering/clipmap/last_cull.comp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ void main()
5555
const uvec3 localClusterID = 2u*(parentVoxelID >> 1u) + uvec3(voxelX, voxelY, voxelZ);
5656
const nbl_glsl_shapes_AABB_t cluster = getCluster(localClusterID, levelMinVertex, voxelSideLength);
5757

58-
if (coneIntersectAABB(cone, cluster))
58+
if (lightIntersectAABB(cone, cluster))
5959
{
6060
// Record intersection
6161
intersection_record_t record;

examples_tests/60.ClusteredRendering/cull_common.glsl

Lines changed: 97 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
layout(local_size_x = _NBL_GLSL_WORKGROUP_SIZE_) in;
2020

2121
#include <nbl/builtin/glsl/shapes/aabb.glsl>
22+
#include <nbl/builtin/glsl/math/quaternions.glsl>
2223

2324
#include <../intersection_record.glsl>
2425

@@ -39,14 +40,6 @@ struct cone_t
3940
float baseRadius;
4041
};
4142

42-
bool isPointBehindPlane(in vec3 p, in vec4 plane)
43-
{
44-
// As an optimization we can add an epsilon to 0, to ignore cones which have a
45-
// very very small intersecting region with the AABB, could help with FP precision
46-
// too when the point is on the plane
47-
return (dot(p, plane.xyz) + plane.w) <= 0.f /* + EPSILON*/;
48-
}
49-
5043
cone_t getLightVolume(in nbl_glsl_ext_ClusteredLighting_SpotLight light)
5144
{
5245
cone_t cone;
@@ -102,66 +95,141 @@ vec4[PLANE_COUNT] getAABBPlanes(in nbl_glsl_shapes_AABB_t aabb)
10295
vec3 p1 = vec3(aabb.maxVx.x, aabb.minVx.y, aabb.maxVx.z);
10396
vec3 p2 = vec3(aabb.maxVx.x, aabb.maxVx.y, aabb.maxVx.z);
10497
planes[0].xyz = normalize(cross(p1 - p0, p2 - p0));
105-
planes[0].w = -dot(planes[0].xyz, p0);
98+
planes[0].w = dot(planes[0].xyz, p0);
10699

107100
// 013
108101
p0 = vec3(aabb.minVx.x, aabb.minVx.y, aabb.minVx.z);
109102
p1 = vec3(aabb.maxVx.x, aabb.minVx.y, aabb.minVx.z);
110103
p2 = vec3(aabb.maxVx.x, aabb.maxVx.y, aabb.minVx.z);
111104
planes[1].xyz = normalize(cross(p1 - p0, p2 - p0));
112-
planes[1].w = -dot(planes[1].xyz, p0);
105+
planes[1].w = dot(planes[1].xyz, p0);
113106

114107
// 402
115108
p0 = vec3(aabb.minVx.x, aabb.minVx.y, aabb.maxVx.z);
116109
p1 = vec3(aabb.minVx.x, aabb.minVx.y, aabb.minVx.z);
117110
p2 = vec3(aabb.minVx.x, aabb.maxVx.y, aabb.minVx.z);
118111
planes[2].xyz = normalize(cross(p1 - p0, p2 - p0));
119-
planes[2].w = -dot(planes[2].xyz, p0);
112+
planes[2].w = dot(planes[2].xyz, p0);
120113

121114
// 546
122115
p0 = vec3(aabb.maxVx.x, aabb.minVx.y, aabb.maxVx.z);
123116
p1 = vec3(aabb.minVx.x, aabb.minVx.y, aabb.maxVx.z);
124117
p2 = vec3(aabb.minVx.x, aabb.maxVx.y, aabb.maxVx.z);
125118
planes[3].xyz = normalize(cross(p1 - p0, p2 - p0));
126-
planes[3].w = -dot(planes[3].xyz, p0);
119+
planes[3].w = dot(planes[3].xyz, p0);
127120

128121
// 451
129122
p0 = vec3(aabb.minVx.x, aabb.minVx.y, aabb.maxVx.z);
130123
p1 = vec3(aabb.maxVx.x, aabb.minVx.y, aabb.maxVx.z);
131124
p2 = vec3(aabb.maxVx.x, aabb.minVx.y, aabb.minVx.z);
132125
planes[4].xyz = normalize(cross(p1 - p0, p2 - p0));
133-
planes[4].w = -dot(planes[4].xyz, p0);
126+
planes[4].w = dot(planes[4].xyz, p0);
134127

135128
// 762
136129
p0 = vec3(aabb.maxVx.x, aabb.maxVx.y, aabb.maxVx.z);
137130
p1 = vec3(aabb.minVx.x, aabb.maxVx.y, aabb.maxVx.z);
138131
p2 = vec3(aabb.minVx.x, aabb.maxVx.y, aabb.minVx.z);
139132
planes[5].xyz = normalize(cross(p1 - p0, p2 - p0));
140-
planes[5].w = -dot(planes[5].xyz, p0);
133+
planes[5].w = dot(planes[5].xyz, p0);
141134

142135
return planes;
143136
}
144137

145-
bool coneIntersectAABB(in cone_t cone, in nbl_glsl_shapes_AABB_t aabb)
138+
bvec3 and(in bvec3 a, in bvec3 b)
139+
{
140+
return bvec3(a.x && b.x, a.y && b.y, a.z && b.z);
141+
}
142+
143+
bvec3 or(in bvec3 a, in bvec3 b)
144+
{
145+
return bvec3(a.x || b.x, a.y || b.y, a.z || b.z);
146+
}
147+
148+
float projectedSphericalVertex(in vec3 origin, in vec3 planeNormal, in vec3 pos)
149+
{
150+
return dot(normalize(pos - origin), planeNormal);
151+
}
152+
153+
vec3 findFarthestPointOnConeInDirection(in vec3 planeNormal, in cone_t cone)
154+
{
155+
const vec3 m = cross(cross(planeNormal, cone.direction), cone.direction);
156+
const vec3 farthestBasePoint = cone.tip + (cone.direction * cone.height) - (m * cone.baseRadius); // farthest to plane's surface, away from positive half-space
157+
return farthestBasePoint;
158+
}
159+
160+
bool cullCone(in cone_t cone, in nbl_glsl_shapes_AABB_t aabb)
146161
{
147-
vec4 planes[PLANE_COUNT] = getAABBPlanes(aabb);
162+
float maxCosine = projectedSphericalVertex(cone.tip, cone.direction, vec3(aabb.minVx.x, aabb.minVx.y, aabb.minVx.z));
148163

149-
for (uint i = 0u; i < PLANE_COUNT; ++i)
164+
for (uint i = 1u; i < 8u; ++i)
150165
{
151-
const vec3 m = cross(cross(planes[i].xyz, cone.direction), cone.direction);
152-
const vec3 farthestBasePoint = cone.tip + (cone.direction * cone.height) - (m * cone.baseRadius); // farthest to plane's surface, away from positive half-space
153-
154-
// There are two edge cases here:
155-
// 1. When cone's direction and plane's normal are anti-parallel
156-
// There is no reason to check farthestBasePoint in this case, because cone's tip is the farthest point!
157-
// But there is no harm in doing so.
158-
// 2. When cone's direction and plane's normal are parallel
159-
// This edge case will get handled nicely by the farthestBasePoint coming as center of the base of the cone itself
160-
if (isPointBehindPlane(cone.tip, planes[i]) && isPointBehindPlane(farthestBasePoint, planes[i]))
161-
return false;
166+
const uvec3 t = (uvec3(i) >> uvec3(0, 1, 2)) & 0x1u;
167+
const vec3 vertex = mix(aabb.minVx, aabb.maxVx, t);
168+
169+
// assuming cone.direction is normalized
170+
maxCosine = max(projectedSphericalVertex(cone.tip, cone.direction, vertex), maxCosine);
171+
}
172+
173+
const bool allVerticesOutsideCone = maxCosine < cone.cosHalfAngle;
174+
175+
if (cone.cosHalfAngle <= 0.f) // obtuse
176+
{
177+
return allVerticesOutsideCone; // cull if whole AABB is inside complementary acute cone
178+
}
179+
else if (any(or(greaterThan(aabb.minVx, cone.tip), greaterThan(cone.tip, aabb.maxVx))) && allVerticesOutsideCone)
180+
{
181+
// step 1
182+
for (uint i = 0u; i < 8u; ++i)
183+
{
184+
const uvec3 t = (uvec3(i) >> uvec3(0, 1, 2)) & 0x1u;
185+
const vec3 vertex = mix(aabb.minVx, aabb.maxVx, t);
186+
187+
const vec3 waypoint = normalize(vertex - cone.tip);
188+
189+
const vec3 normal = nbl_glsl_slerp_impl_impl(cone.direction, normalize(waypoint), sqrt(1.f - cone.cosHalfAngle * cone.cosHalfAngle));
190+
if (dot(nbl_glsl_shapes_AABB_getFarthestPointInFront(aabb, normal) - cone.tip, normal) < 0.f)
191+
return true;
192+
}
193+
194+
vec4 planes[PLANE_COUNT] = getAABBPlanes(aabb);
195+
196+
for (uint i = 0u; i < PLANE_COUNT; ++i)
197+
{
198+
const vec3 normal = planes[i].xyz;
199+
200+
float farthestPoint = dot(normal, cone.tip);
201+
if (dot(normal, cone.direction) < cone.cosHalfAngle)
202+
farthestPoint = max(dot(normal, findFarthestPointOnConeInDirection(normal, cone)), farthestPoint); // https://www.3dgep.com/forward-plus/#Frustum-Cone_Culling
203+
else
204+
farthestPoint += (cone.height / cone.cosHalfAngle);
205+
206+
if (farthestPoint < planes[i].w)
207+
return true;
208+
}
162209
}
210+
return false;
211+
}
212+
213+
// Todo(achal): Can make this cone_t something like light_volume_t..
214+
bool lightIntersectAABB(in cone_t cone, in nbl_glsl_shapes_AABB_t aabb)
215+
{
216+
#if 1
217+
const vec3 sphereMinPoint = cone.tip - cone.height;
218+
const vec3 sphereMaxPoint = cone.tip + cone.height;
219+
220+
if (!any(and(lessThan(aabb.minVx, sphereMaxPoint),lessThan(sphereMinPoint, aabb.maxVx))))
221+
return false;
222+
223+
const vec3 closestPoint = clamp(cone.tip, aabb.minVx, aabb.maxVx);
224+
225+
if (dot(closestPoint - cone.tip, closestPoint - cone.tip) > (cone.height * cone.height))
226+
return false;
227+
228+
if (cone.cosHalfAngle <= -(1.f - 1e-3f))
229+
return false;
230+
#endif
163231

164-
return true;
232+
return !cullCone(cone, aabb);
165233
}
166234

167235
float getLightImportanceMagnitude(in nbl_glsl_ext_ClusteredLighting_SpotLight light)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#version 460 core
2+
3+
#include <nbl/builtin/glsl/utils/common.glsl>
4+
#include <nbl/builtin/glsl/utils/transform.glsl>
5+
#include <nbl/builtin/glsl/shapes/aabb.glsl>
6+
7+
layout (set = 0, binding = 0) restrict buffer readonly DebugAABBs
8+
{
9+
nbl_glsl_shapes_AABB_t data[];
10+
} debugAABBs;
11+
12+
layout (set = 0, binding = 1, row_major, std140) uniform UBO
13+
{
14+
nbl_glsl_SBasicViewParameters params;
15+
} CamData;
16+
17+
layout(location = 0) out vec3 color;
18+
19+
void main()
20+
{
21+
const nbl_glsl_shapes_AABB_t aabb = debugAABBs.data[gl_InstanceIndex];
22+
23+
const bvec3 mask = bvec3(gl_VertexIndex&0x1u,gl_VertexIndex&0x2u,gl_VertexIndex&0x4u);
24+
vec3 pos = mix(aabb.minVx,aabb.maxVx,mask);
25+
26+
gl_Position = nbl_glsl_pseudoMul4x4with3x1(CamData.params.MVP, pos);
27+
color = vec3(1.f, 0.f, 0.f);
28+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#version 460 core
2+
3+
layout (location = 0) in vec4 VS_in_position;
4+
5+
layout (push_constant, row_major) uniform Block
6+
{
7+
mat4 mvp;
8+
} PushConstants;
9+
10+
layout(location = 0) out vec3 color;
11+
12+
void main()
13+
{
14+
gl_Position = PushConstants.mvp * VS_in_position;
15+
color = vec3(1.f, 1.f, 0.f);
16+
}

0 commit comments

Comments
 (0)