19
19
layout (local_size_x = _NBL_GLSL_WORKGROUP_SIZE_) in ;
20
20
21
21
#include < nbl/ builtin/ glsl/ shapes/ aabb.glsl>
22
+ #include < nbl/ builtin/ glsl/ math/ quaternions.glsl>
22
23
23
24
#include <../intersection_record.glsl>
24
25
@@ -39,14 +40,6 @@ struct cone_t
39
40
float baseRadius;
40
41
};
41
42
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
-
50
43
cone_t getLightVolume(in nbl_glsl_ext_ClusteredLighting_SpotLight light)
51
44
{
52
45
cone_t cone;
@@ -102,66 +95,141 @@ vec4[PLANE_COUNT] getAABBPlanes(in nbl_glsl_shapes_AABB_t aabb)
102
95
vec3 p1 = vec3 (aabb.maxVx.x, aabb.minVx.y, aabb.maxVx.z);
103
96
vec3 p2 = vec3 (aabb.maxVx.x, aabb.maxVx.y, aabb.maxVx.z);
104
97
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);
106
99
107
100
// 013
108
101
p0 = vec3 (aabb.minVx.x, aabb.minVx.y, aabb.minVx.z);
109
102
p1 = vec3 (aabb.maxVx.x, aabb.minVx.y, aabb.minVx.z);
110
103
p2 = vec3 (aabb.maxVx.x, aabb.maxVx.y, aabb.minVx.z);
111
104
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);
113
106
114
107
// 402
115
108
p0 = vec3 (aabb.minVx.x, aabb.minVx.y, aabb.maxVx.z);
116
109
p1 = vec3 (aabb.minVx.x, aabb.minVx.y, aabb.minVx.z);
117
110
p2 = vec3 (aabb.minVx.x, aabb.maxVx.y, aabb.minVx.z);
118
111
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);
120
113
121
114
// 546
122
115
p0 = vec3 (aabb.maxVx.x, aabb.minVx.y, aabb.maxVx.z);
123
116
p1 = vec3 (aabb.minVx.x, aabb.minVx.y, aabb.maxVx.z);
124
117
p2 = vec3 (aabb.minVx.x, aabb.maxVx.y, aabb.maxVx.z);
125
118
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);
127
120
128
121
// 451
129
122
p0 = vec3 (aabb.minVx.x, aabb.minVx.y, aabb.maxVx.z);
130
123
p1 = vec3 (aabb.maxVx.x, aabb.minVx.y, aabb.maxVx.z);
131
124
p2 = vec3 (aabb.maxVx.x, aabb.minVx.y, aabb.minVx.z);
132
125
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);
134
127
135
128
// 762
136
129
p0 = vec3 (aabb.maxVx.x, aabb.maxVx.y, aabb.maxVx.z);
137
130
p1 = vec3 (aabb.minVx.x, aabb.maxVx.y, aabb.maxVx.z);
138
131
p2 = vec3 (aabb.minVx.x, aabb.maxVx.y, aabb.minVx.z);
139
132
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);
141
134
142
135
return planes;
143
136
}
144
137
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)
146
161
{
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) );
148
163
149
- for (uint i = 0u ; i < PLANE_COUNT ; ++ i)
164
+ for (uint i = 1u ; i < 8u ; ++ i)
150
165
{
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
+ }
162
209
}
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
163
231
164
- return true ;
232
+ return ! cullCone(cone, aabb) ;
165
233
}
166
234
167
235
float getLightImportanceMagnitude(in nbl_glsl_ext_ClusteredLighting_SpotLight light)
0 commit comments