Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/intern/shaders/common_intersect_lib.glsl')
-rw-r--r--source/blender/draw/intern/shaders/common_intersect_lib.glsl398
1 files changed, 398 insertions, 0 deletions
diff --git a/source/blender/draw/intern/shaders/common_intersect_lib.glsl b/source/blender/draw/intern/shaders/common_intersect_lib.glsl
new file mode 100644
index 00000000000..33378588553
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_intersect_lib.glsl
@@ -0,0 +1,398 @@
+
+/**
+ * Intersection library used for culling.
+ * Results are meant to be conservative.
+ */
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
+#pragma BLENDER_REQUIRE(common_shape_lib.glsl)
+
+/* ---------------------------------------------------------------------- */
+/** \name Plane extraction functions.
+ * \{ */
+
+/** \a v1 and \a v2 are vectors on the plane. \a p is a point on the plane. */
+vec4 isect_plane_setup(vec3 p, vec3 v1, vec3 v2)
+{
+ vec3 normal_to_plane = normalize(cross(v1, v2));
+ return vec4(normal_to_plane, -dot(normal_to_plane, p));
+}
+
+struct IsectPyramid {
+ vec3 corners[5];
+ vec4 planes[5];
+};
+
+IsectPyramid isect_data_setup(Pyramid shape)
+{
+ vec3 A1 = shape.corners[1] - shape.corners[0];
+ vec3 A2 = shape.corners[2] - shape.corners[0];
+ vec3 A3 = shape.corners[3] - shape.corners[0];
+ vec3 A4 = shape.corners[4] - shape.corners[0];
+ vec3 S4 = shape.corners[4] - shape.corners[1];
+ vec3 S2 = shape.corners[2] - shape.corners[1];
+
+ IsectPyramid data;
+ data.planes[0] = isect_plane_setup(shape.corners[0], A2, A1);
+ data.planes[1] = isect_plane_setup(shape.corners[0], A3, A2);
+ data.planes[2] = isect_plane_setup(shape.corners[0], A4, A3);
+ data.planes[3] = isect_plane_setup(shape.corners[0], A1, A4);
+ data.planes[4] = isect_plane_setup(shape.corners[1], S2, S4);
+ for (int i = 0; i < 5; i++) {
+ data.corners[i] = shape.corners[i];
+ }
+ return data;
+}
+
+struct IsectBox {
+ vec3 corners[8];
+ vec4 planes[6];
+};
+
+IsectBox isect_data_setup(Box shape)
+{
+ vec3 A1 = shape.corners[1] - shape.corners[0];
+ vec3 A3 = shape.corners[3] - shape.corners[0];
+ vec3 A4 = shape.corners[4] - shape.corners[0];
+
+ IsectBox data;
+ data.planes[0] = isect_plane_setup(shape.corners[0], A3, A1);
+ data.planes[1] = isect_plane_setup(shape.corners[0], A4, A3);
+ data.planes[2] = isect_plane_setup(shape.corners[0], A1, A4);
+ /* Assumes that the box is actually a box! */
+ data.planes[3] = vec4(-data.planes[0].xyz, -dot(-data.planes[0].xyz, shape.corners[6]));
+ data.planes[4] = vec4(-data.planes[1].xyz, -dot(-data.planes[1].xyz, shape.corners[6]));
+ data.planes[5] = vec4(-data.planes[2].xyz, -dot(-data.planes[2].xyz, shape.corners[6]));
+ for (int i = 0; i < 8; i++) {
+ data.corners[i] = shape.corners[i];
+ }
+ return data;
+}
+
+struct IsectFrustum {
+ vec3 corners[8];
+ vec4 planes[6];
+};
+
+IsectFrustum isect_data_setup(Frustum shape)
+{
+ vec3 A1 = shape.corners[1] - shape.corners[0];
+ vec3 A3 = shape.corners[3] - shape.corners[0];
+ vec3 A4 = shape.corners[4] - shape.corners[0];
+ vec3 B5 = shape.corners[5] - shape.corners[6];
+ vec3 B7 = shape.corners[7] - shape.corners[6];
+ vec3 B2 = shape.corners[2] - shape.corners[6];
+
+ IsectFrustum data;
+ data.planes[0] = isect_plane_setup(shape.corners[0], A3, A1);
+ data.planes[1] = isect_plane_setup(shape.corners[0], A4, A3);
+ data.planes[2] = isect_plane_setup(shape.corners[0], A1, A4);
+ data.planes[3] = isect_plane_setup(shape.corners[6], B7, B5);
+ data.planes[4] = isect_plane_setup(shape.corners[6], B5, B2);
+ data.planes[5] = isect_plane_setup(shape.corners[6], B2, B7);
+ for (int i = 0; i < 8; i++) {
+ data.corners[i] = shape.corners[i];
+ }
+ return data;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name View Intersection functions.
+ * \{ */
+
+bool intersect_view(Pyramid pyramid)
+{
+ bool intersects = true;
+
+ /* Do Pyramid vertices vs Frustum planes. */
+ for (int p = 0; p < 6; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 5; ++v) {
+ float test = dot(drw_view.frustum_planes[p], vec4(pyramid.corners[v], 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+
+ if (!intersects) {
+ return intersects;
+ }
+
+ /* Now do Frustum vertices vs Pyramid planes. */
+ IsectPyramid i_pyramid = isect_data_setup(pyramid);
+ for (int p = 0; p < 5; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 8; ++v) {
+ float test = dot(i_pyramid.planes[p], vec4(drw_view.frustum_corners[v].xyz, 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+ return intersects;
+}
+
+bool intersect_view(Box box)
+{
+ bool intersects = true;
+
+ /* Do Box vertices vs Frustum planes. */
+ for (int p = 0; p < 6; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 8; ++v) {
+ float test = dot(drw_view.frustum_planes[p], vec4(box.corners[v], 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+
+ if (!intersects) {
+ return intersects;
+ }
+
+ /* Now do Frustum vertices vs Box planes. */
+ IsectBox i_box = isect_data_setup(box);
+ for (int p = 0; p < 6; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 8; ++v) {
+ float test = dot(i_box.planes[p], vec4(drw_view.frustum_corners[v].xyz, 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+
+ return intersects;
+}
+
+bool intersect_view(Sphere sphere)
+{
+ bool intersects = true;
+
+ for (int p = 0; p < 6 && intersects; ++p) {
+ float dist_to_plane = dot(drw_view.frustum_planes[p], vec4(sphere.center, 1.0));
+ if (dist_to_plane < -sphere.radius) {
+ intersects = false;
+ }
+ }
+ /* TODO reject false positive. */
+ return intersects;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Shape vs. Shape Intersection functions.
+ * \{ */
+
+bool intersect(IsectPyramid i_pyramid, Box box)
+{
+ bool intersects = true;
+
+ /* Do Box vertices vs Pyramid planes. */
+ for (int p = 0; p < 5; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 8; ++v) {
+ float test = dot(i_pyramid.planes[p], vec4(box.corners[v], 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+
+ if (!intersects) {
+ return intersects;
+ }
+
+ /* Now do Pyramid vertices vs Box planes. */
+ IsectBox i_box = isect_data_setup(box);
+ for (int p = 0; p < 6; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 5; ++v) {
+ float test = dot(i_box.planes[p], vec4(i_pyramid.corners[v], 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+ return intersects;
+}
+
+bool intersect(IsectFrustum i_frustum, Pyramid pyramid)
+{
+ bool intersects = true;
+
+ /* Do Pyramid vertices vs Frustum planes. */
+ for (int p = 0; p < 6; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 5; ++v) {
+ float test = dot(i_frustum.planes[p], vec4(pyramid.corners[v], 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+
+ if (!intersects) {
+ return intersects;
+ }
+
+ /* Now do Frustum vertices vs Pyramid planes. */
+ IsectPyramid i_pyramid = isect_data_setup(pyramid);
+ for (int p = 0; p < 5; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 8; ++v) {
+ float test = dot(i_pyramid.planes[p], vec4(i_frustum.corners[v].xyz, 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+ return intersects;
+}
+
+bool intersect(IsectFrustum i_frustum, Box box)
+{
+ bool intersects = true;
+
+ /* Do Box vertices vs Frustum planes. */
+ for (int p = 0; p < 6; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 8; ++v) {
+ float test = dot(i_frustum.planes[p], vec4(box.corners[v], 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+
+ if (!intersects) {
+ return intersects;
+ }
+
+ /* Now do Frustum vertices vs Box planes. */
+ IsectBox i_box = isect_data_setup(box);
+ for (int p = 0; p < 6; ++p) {
+ bool is_any_vertex_on_positive_side = false;
+ for (int v = 0; v < 8; ++v) {
+ float test = dot(i_box.planes[p], vec4(i_frustum.corners[v].xyz, 1.0));
+ if (test > 0.0) {
+ is_any_vertex_on_positive_side = true;
+ break;
+ }
+ }
+ bool all_vertex_on_negative_side = !is_any_vertex_on_positive_side;
+ if (all_vertex_on_negative_side) {
+ intersects = false;
+ break;
+ }
+ }
+
+ return intersects;
+}
+
+bool intersect(IsectFrustum i_frustum, Sphere sphere)
+{
+ bool intersects = true;
+ for (int p = 0; p < 6; ++p) {
+ float dist_to_plane = dot(i_frustum.planes[p], vec4(sphere.center, 1.0));
+ if (dist_to_plane < -sphere.radius) {
+ intersects = false;
+ break;
+ }
+ }
+ return intersects;
+}
+
+bool intersect(Cone cone, Sphere sphere)
+{
+ /**
+ * Following "Improve Tile-based Light Culling with Spherical-sliced Cone"
+ * by Eric Zhang
+ * https://lxjk.github.io/2018/03/25/Improve-Tile-based-Light-Culling-with-Spherical-sliced-Cone.html
+ */
+ float sphere_distance = length(sphere.center);
+ float sphere_distance_rcp = safe_rcp(sphere_distance);
+ float sphere_sin = saturate(sphere.radius * sphere_distance_rcp);
+ float sphere_cos = sqrt(1.0 - sphere_sin * sphere_sin);
+ float cone_aperture_sin = sqrt(1.0 - cone.angle_cos * cone.angle_cos);
+
+ float cone_sphere_center_cos = dot(sphere.center * sphere_distance_rcp, cone.direction);
+ /* cos(A+B) = cos(A) * cos(B) - sin(A) * sin(B). */
+ float cone_sphere_angle_sum_cos = (sphere.radius > sphere_distance) ?
+ -1.0 :
+ (cone.angle_cos * sphere_cos -
+ cone_aperture_sin * sphere_sin);
+ /* Comparing cosines instead of angles since we are interested
+ * only in the monotonic region [0 .. M_PI / 2]. This saves costly acos() calls. */
+ bool intersects = (cone_sphere_center_cos >= cone_sphere_angle_sum_cos);
+
+ return intersects;
+}
+
+bool intersect(Circle circle_a, Circle circle_b)
+{
+ return distance_squared(circle_a.center, circle_b.center) <
+ sqr(circle_a.radius + circle_b.radius);
+}
+
+/** \} */