From: Oleksandr Shcherbina Date: Mon, 1 Dec 2014 05:26:28 +0000 (+0100) Subject: evas: Evas_3D - add bounding sphere, revision frustum culling X-Git-Tag: upstream/1.12.0+179+gc1eb5de~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=54c1667d4e4dfc160fa8a7ce6118d6032645314a;p=platform%2Fupstream%2Fefl.git evas: Evas_3D - add bounding sphere, revision frustum culling Summary: Move check visibility of node from evas_3d_node to evas_3d_camera Move functionality (normalize, check distance, calculate frustum) in evas_3d_utils.h (we are planing use evas_is_sphere_in_frustum in evas_gl_3d.c - don't render mesh if it non visible) Add possibility check frustum by box, aabb, central point Refactor example frustum culling @feature Reviewers: Hermet, raster, cedric Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D1420 Signed-off-by: Cedric BAIL --- diff --git a/src/lib/evas/Evas_Eo.h b/src/lib/evas/Evas_Eo.h index fd48f74..9d8e93f 100644 --- a/src/lib/evas/Evas_Eo.h +++ b/src/lib/evas/Evas_Eo.h @@ -566,6 +566,20 @@ typedef enum _Evas_3D_Index_Format } Evas_3D_Index_Format; /** + * Frustum modes + * + * @since 1.12 + * @ingroup Evas_3D_Types + */ +typedef enum _Evas_3D_Frustum_Mode +{ + EVAS_3D_FRUSTUM_MODE_BSPHERE, + EVAS_3D_FRUSTUM_MODE_AABB, + EVAS_3D_FRUSTUM_MODE_CENTRAL_POINT +} Evas_3D_Frustum_Mode; + + +/** * Vertex assembly modes * * Vertex assembly represents how the vertices are organized into geometric diff --git a/src/lib/evas/canvas/evas_3d_camera.c b/src/lib/evas/canvas/evas_3d_camera.c index d8a7d24..c6da2d3 100644 --- a/src/lib/evas/canvas/evas_3d_camera.c +++ b/src/lib/evas/canvas/evas_3d_camera.c @@ -140,5 +140,49 @@ _evas_3d_camera_projection_ortho_set(Eo *obj, Evas_3D_Camera_Data *pd, eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_CAMERA_PROJECTION, NULL)); } +EOLIAN static Eina_Bool +_evas_3d_camera_node_visible_get(Eo *obj EINA_UNUSED, Evas_3D_Camera_Data *pd, Evas_3D_Node *camera_node, Evas_3D_Node *node, Evas_3D_Frustum_Mode key) +{ + Evas_Mat4 matrix_vp; + Evas_Vec4 planes[6]; + Evas_3D_Node_Data *pd_node = eo_data_scope_get(node, EVAS_3D_NODE_CLASS); + Evas_3D_Node_Data *pd_camera = eo_data_scope_get(camera_node, EVAS_3D_NODE_CLASS); + Evas_Vec3 central_point; + + if (!node || pd_node->type != EVAS_3D_NODE_TYPE_MESH) + { + ERR("Mesh node %p type mismatch.", node); + return EINA_FALSE; + } + + if (!camera_node || pd_camera->type != EVAS_3D_NODE_TYPE_CAMERA) + { + ERR("Camera node %p type mismatch.", camera_node); + return EINA_FALSE; + } + + /*get need matrix like multiply projection matrix with view matrix*/ + evas_mat4_multiply(&matrix_vp, &pd->projection, &pd_camera->data.camera.matrix_world_to_eye); + + evas_frustum_calculate(planes, &matrix_vp); + + if (key == EVAS_3D_FRUSTUM_MODE_BSPHERE) + return evas_is_sphere_in_frustum(&pd_node->bsphere, planes); + else if (key == EVAS_3D_FRUSTUM_MODE_AABB) + return evas_is_box_in_frustum(&pd_node->aabb, planes); + else if (key == EVAS_3D_FRUSTUM_MODE_CENTRAL_POINT) + { + central_point.x = (pd_node->aabb.p0.x + pd_node->aabb.p1.x) / 2; + central_point.y = (pd_node->aabb.p0.y + pd_node->aabb.p1.y) / 2; + central_point.z = (pd_node->aabb.p0.z + pd_node->aabb.p1.z) / 2; + return evas_is_point_in_frustum(¢ral_point, planes); + } + else + { + ERR("Unknown frustun mode."); + return EINA_TRUE; + } +} + #include "canvas/evas_3d_camera.eo.c" diff --git a/src/lib/evas/canvas/evas_3d_camera.eo b/src/lib/evas/canvas/evas_3d_camera.eo index 4b4d95e..45e9e9a 100644 --- a/src/lib/evas/canvas/evas_3d_camera.eo +++ b/src/lib/evas/canvas/evas_3d_camera.eo @@ -96,6 +96,25 @@ class Evas_3D_Camera (Evas_3D_Object, Evas.Common_Interface) Evas_Real dfar; /*@ Distance to far clipping plane. */ } } + node_visible_get { + /*@ + Check is bounding sphere of given node inside frustum of camera node. + * + * @param camera The given camera node. + * @param node The given node. + * @return @c EINA_TRUE in frustum, @c EINA_FALSE otherwise + + * If the nodes are @ NULL or nodes type mismatch error wrong type of nodes will be generated and returned @ EINA_FALSE. + + * @ingroup Evas_3D_Camera + */ + return: bool; + params { + @in Evas_3D_Node *camera_node; + @in Evas_3D_Node *node; + @in Evas_3D_Frustum_Mode key; + } + } } implements { diff --git a/src/lib/evas/canvas/evas_3d_node.c b/src/lib/evas/canvas/evas_3d_node.c index 7b30486..bcbb1db 100644 --- a/src/lib/evas/canvas/evas_3d_node.c +++ b/src/lib/evas/canvas/evas_3d_node.c @@ -204,6 +204,7 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED) Eina_Bool transform_dirty = EINA_FALSE, mesh_geom_dirty = EINA_FALSE; Eina_Bool mesh_frame_dirty = EINA_FALSE, member_dirty = EINA_FALSE; Eina_Bool frame_found = EINA_FALSE, is_change_orientation = EINA_FALSE; + Eina_Bool parent_dirty = EINA_FALSE; const Eina_List *m, *l; Evas_3D_Mesh *mesh; int frame, count, size, i, j; @@ -217,19 +218,21 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED) transform_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_TRANSFORM), mesh_geom_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_MESH_GEOMETRY), mesh_frame_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_MESH_FRAME), + parent_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_PARENT), member_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_MEMBER)); - if (transform_dirty || + if (transform_dirty || mesh_geom_dirty || mesh_frame_dirty || - member_dirty) + member_dirty || + parent_dirty) { if (pd->type == EVAS_3D_NODE_TYPE_MESH) { - if (pd->orientation.x || pd->orientation.y || pd->orientation.z) + if (pd->orientation_world.x || pd->orientation_world.y || pd->orientation_world.z) { - evas_vec4_set(&orientation, pd->orientation.x, pd->orientation.y, pd->orientation.z, pd->orientation.w); + evas_vec4_set(&orientation, pd->orientation_world.x, pd->orientation_world.y, pd->orientation_world.z, pd->orientation_world.w); is_change_orientation = EINA_TRUE; } @@ -347,19 +350,19 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED) evas_vec3_quaternion_rotate(&pd->obb.p0, &pd->obb.p0, &orientation); evas_vec3_quaternion_rotate(&pd->obb.p1, &pd->obb.p1, &orientation); } - if ((pd->scale.x != 1 || pd->scale.y != 1 || pd->scale.z != 1)) + if ((pd->scale_world.x != 1 || pd->scale_world.y != 1 || pd->scale_world.z != 1)) { Evas_Vec3 scale; - evas_vec3_set(&scale, pd->scale.x, pd->scale.y, pd->scale.z); + evas_vec3_set(&scale, pd->scale_world.x, pd->scale_world.y, pd->scale_world.z); evas_vec3_multiply(&pd->obb.p0, &scale, &pd->obb.p0); evas_vec3_multiply(&pd->obb.p1, &scale, &pd->obb.p1); evas_vec3_multiply(&pd->aabb.p0, &scale, &pd->aabb.p0); evas_vec3_multiply(&pd->aabb.p1, &scale, &pd->aabb.p1); } - if ((pd->position.x || pd->position.y || pd->position.z)) + if ((pd->position_world.x || pd->position_world.y || pd->position_world.z)) { Evas_Vec3 position; - evas_vec3_set(&position, pd->position.x, pd->position.y, pd->position.z); + evas_vec3_set(&position, pd->position_world.x, pd->position_world.y, pd->position_world.z); evas_vec3_add(&pd->obb.p0, &position, &pd->obb.p0); evas_vec3_add(&pd->obb.p1, &position, &pd->obb.p1); evas_vec3_add(&pd->aabb.p0, &position, &pd->aabb.p0); @@ -372,7 +375,7 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED) Eina_List *current; Evas_3D_Node *datanode; - /* Update AABB and OBB of this node. */ + /* Update AABB, OBB, bounding sphere of this node. */ evas_box3_empty_set(&pd->aabb); evas_box3_empty_set(&pd->obb); @@ -383,6 +386,7 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED) evas_box3_union(&pd->aabb, &pd->aabb, &datapd->aabb); } } + evas_build_sphere(&pd->obb, &pd->bsphere); } return EINA_TRUE; @@ -1362,99 +1366,13 @@ _evas_3d_node_bounding_box_get(Eo *obj EINA_UNUSED, Evas_3D_Node_Data *pd, Evas_ if (z2) *z2 = pd->aabb.p1.z; } -EOLIAN static int -_evas_3d_node_obb_frustum_check(Eo *obj EINA_UNUSED, Evas_3D_Node_Data *pd, Evas_3D_Node *camera_node) +EOLIAN static void +_evas_3d_node_bounding_sphere_get(Eo *obj EINA_UNUSED, Evas_3D_Node_Data *pd, Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *r) { - Evas_Mat4 matrix_eye = { { 0 } }; - Evas_Mat4 matrix_local_to_world; - Evas_Mat4 matrix_mv; - Evas_Mat4 matrix_mvp; - Evas_Vec4 plane_right, plane_left, plane_bottom, plane_top, plane_far, plane_near, tmp; - int frustum = 0; - Evas_3D_Node_Data *camera_pd = eo_data_scope_get(camera_node, EVAS_3D_CAMERA_CLASS); - Evas_3D_Camera_Data *camera = eo_data_scope_get(camera_pd->data.camera.camera, EVAS_3D_CAMERA_CLASS); - - - if (camera_pd->type != EVAS_3D_NODE_TYPE_CAMERA) - { - ERR("Nodes type mismatch."); - return -1; - } - -#define CHECK_IN_FRUSTUM_MIN(name) \ - (((plane_##name.x * pd->obb.p0.x + plane_##name.y * pd->obb.p0.y + plane_##name.z * pd->obb.p0.z + plane_##name.w) >= 0) ? EINA_TRUE : EINA_FALSE) - -#define CHECK_IN_FRUSTUM_MAX(name) \ - (((plane_##name.x * pd->obb.p1.x + plane_##name.y * pd->obb.p1.y + plane_##name.z * pd->obb.p1.z + plane_##name.w) >= 0) ? EINA_TRUE : EINA_FALSE) - -#define NORMALIZE(name) \ - evas_vec4_copy(&tmp, &plane_##name); \ - plane_##name.x = plane_##name.x / sqrtf(evas_vec4_length_square_get(&tmp)); \ - plane_##name.y = plane_##name.y / sqrtf(evas_vec4_length_square_get(&tmp)); \ - plane_##name.z = plane_##name.z / sqrtf(evas_vec4_length_square_get(&tmp)); \ - plane_##name.w = plane_##name.w / sqrtf(evas_vec4_length_square_get(&tmp)); - - /*get need matrix like multiply view matrix with projection matrix*/ - evas_mat4_inverse_build(&matrix_eye, &camera_pd->position_world, &camera_pd->orientation_world, &camera_pd->scale_world); - evas_mat4_build(&matrix_local_to_world, &pd->position_world, &pd->orientation_world, &pd->scale_world); - evas_mat4_multiply(&matrix_mv, &matrix_eye, &matrix_local_to_world); - evas_mat4_multiply(&matrix_mvp, &camera->projection, &matrix_mv); - - /*get planes and normilize results*/ - evas_vec4_set(&plane_right, matrix_mvp.m[3] - matrix_mvp.m[0], - matrix_mvp.m[7] - matrix_mvp.m[4], - matrix_mvp.m[11] - matrix_mvp.m[8], - matrix_mvp.m[15] - matrix_mvp.m[12]); - NORMALIZE(right) - - evas_vec4_set(&plane_left, matrix_mvp.m[3] + matrix_mvp.m[0], - matrix_mvp.m[7] + matrix_mvp.m[4], - matrix_mvp.m[11] + matrix_mvp.m[8], - matrix_mvp.m[15] + matrix_mvp.m[12]); - NORMALIZE(left) - - evas_vec4_set(&plane_bottom, matrix_mvp.m[3] + matrix_mvp.m[1], - matrix_mvp.m[7] + matrix_mvp.m[5], - matrix_mvp.m[11] + matrix_mvp.m[9], - matrix_mvp.m[15] + matrix_mvp.m[13]); - NORMALIZE(bottom) - - evas_vec4_set(&plane_top, matrix_mvp.m[3] - matrix_mvp.m[1], - matrix_mvp.m[7] - matrix_mvp.m[5], - matrix_mvp.m[11] - matrix_mvp.m[9], - matrix_mvp.m[15] - matrix_mvp.m[13]); - NORMALIZE(top) - - evas_vec4_set(&plane_far, matrix_mvp.m[3] - matrix_mvp.m[2], - matrix_mvp.m[7] - matrix_mvp.m[6], - matrix_mvp.m[11] - matrix_mvp.m[10], - matrix_mvp.m[15] - matrix_mvp.m[14]); - NORMALIZE(far) - - evas_vec4_set(&plane_near, matrix_mvp.m[3] + matrix_mvp.m[2], - matrix_mvp.m[7] + matrix_mvp.m[6], - matrix_mvp.m[11] + matrix_mvp.m[10], - matrix_mvp.m[15] + matrix_mvp.m[14]); - NORMALIZE(near) - -#undef NORMALIZE - - /*check OBB points in frustum (Ax + By + Cz + D >= 0)*/ - if (CHECK_IN_FRUSTUM_MIN(right) && CHECK_IN_FRUSTUM_MIN(left) - && CHECK_IN_FRUSTUM_MIN(bottom) && CHECK_IN_FRUSTUM_MIN(top) - && CHECK_IN_FRUSTUM_MIN(far) && CHECK_IN_FRUSTUM_MIN(near)) - frustum |= 1; - - if (CHECK_IN_FRUSTUM_MAX(right) && CHECK_IN_FRUSTUM_MAX(left) - && CHECK_IN_FRUSTUM_MAX(bottom) && CHECK_IN_FRUSTUM_MAX(top) - && CHECK_IN_FRUSTUM_MAX(far) && CHECK_IN_FRUSTUM_MAX(near)) - frustum |= 2; - -#undef CHECK_IN_FRUSTUM_MIN -#undef CHECK_IN_FRUSTUM_MAX - - return frustum; + if (x) *x = pd->bsphere.center.x; + if (y) *y = pd->bsphere.center.y; + if (z) *z = pd->bsphere.center.z; + if (r) *r = pd->bsphere.radius; } - #include "canvas/evas_3d_node.eo.c" diff --git a/src/lib/evas/canvas/evas_3d_node.eo b/src/lib/evas/canvas/evas_3d_node.eo index 5046f44..b82b90e 100644 --- a/src/lib/evas/canvas/evas_3d_node.eo +++ b/src/lib/evas/canvas/evas_3d_node.eo @@ -324,13 +324,12 @@ class Evas_3D_Node (Evas_3D_Object, Evas.Common_Interface) bounding_box_get{ /* - - * Get axis-aligned bounding box (AABB) of the given node. + Get axis-aligned bounding box (AABB) of the given node. * * @param node The given node. - * @param x Pointer to receive X coordinate of the first point of AABB. - * @param y Pointer to receive Y coordinate of the first point of AABB. - * @param z Pointer to receive Z coordinate of the first point of AABB. + * @param x Pointer to receive X coordinate of the first point of AABB. + * @param y Pointer to receive Y coordinate of the first point of AABB. + * @param z Pointer to receive Z coordinate of the first point of AABB. * @param x2 Pointer to receive X coordinate of the second point of AABB. * @param y2 Pointer to receive Y coordinate of the second point of AABB. * @param z2 Pointer to receive Z coordinate of the second point of AABB. @@ -347,23 +346,25 @@ class Evas_3D_Node (Evas_3D_Object, Evas.Common_Interface) } } - obb_frustum_check { + bounding_sphere_get { /* - - * Check is the obb of node in frustum of camera node. + Get bounding sphere of the given node. * - * @param camera_node The given node of camera. - * @param node The given node. - * @return @c 0 if the obb is not in frustum, @c 1 if only min coordinate of obb is in frustum, - * @c 2 if only max coordinate of obb is in frustum, @c 3 if both coordinates of obb is in frustum. + * @param node The given node. - * If the camera_node is not of type EVAS_3D_NODE_TYPE_CAMERA error wrong type of node will be generated and returned @ -1. + * @param x Pointer to receive X coordinate of the center of sphere. + * @param y Pointer to receive Y coordinate of the center of sphere. + * @param z Pointer to receive Z coordinate of center of sphere. + * @param r Pointer to receive radius of center of sphere. - * @ingroup Evas_3D_Node + @ingroup Evas_3D_Node */ - return: int; params { - @in Evas_3D_Node *camera_node; + + @in Evas_Real *x; /*@ Coordinates of vector.*/ + @in Evas_Real *y; + @in Evas_Real *z; + @in Evas_Real *r; } } } diff --git a/src/lib/evas/include/evas_3d_utils.h b/src/lib/evas/include/evas_3d_utils.h index 8e02a07..139351d 100644 --- a/src/lib/evas/include/evas_3d_utils.h +++ b/src/lib/evas/include/evas_3d_utils.h @@ -17,8 +17,10 @@ typedef struct _Evas_Mat3 Evas_Mat3; typedef struct _Evas_Mat4 Evas_Mat4; typedef struct _Evas_Box2 Evas_Box2; typedef struct _Evas_Box3 Evas_Box3; +typedef struct _Evas_Line3 Evas_Line3; typedef struct _Evas_Triangle3 Evas_Triangle3; typedef struct _Evas_Ray3 Evas_Ray3; +typedef struct _Evas_Sphere Evas_Sphere; struct _Evas_Color { @@ -79,6 +81,12 @@ struct _Evas_Box3 Evas_Vec3 p1; }; +struct _Evas_Line3 +{ + Evas_Vec3 point; + Evas_Vec3 direction; +}; + struct _Evas_Triangle3 { Evas_Vec3 p0; @@ -92,6 +100,12 @@ struct _Evas_Ray3 Evas_Vec3 dir; }; +struct _Evas_Sphere +{ + Evas_Vec3 center; + Evas_Real radius; +}; + /* 2D vector */ static inline void evas_vec2_set(Evas_Vec2 *dst, Evas_Real x, Evas_Real y) @@ -1594,6 +1608,17 @@ evas_box2_intersect_2d(const Evas_Box2 *box, const Evas_Vec2 *org, const Evas_Ve return EINA_TRUE; } +static inline Evas_Real +evas_determinant_3D(Evas_Real matrix[3][3]) +{ + return (matrix[0][0] * matrix[1][1] * matrix[2][2]) + + (matrix[0][1] * matrix[1][2] * matrix[2][0]) + + (matrix[0][2] * matrix[1][0] * matrix[2][1]) - + (matrix[0][2] * matrix[1][1] * matrix[2][0]) - + (matrix[0][1] * matrix[1][0] * matrix[2][2]) - + (matrix[0][0] * matrix[1][2] * matrix[2][1]); +} + static inline Eina_Bool evas_box3_ray3_intersect(const Evas_Box3 *box, const Evas_Ray3 *ray) { @@ -1722,3 +1747,242 @@ evas_reciprocal_sqrt(Evas_Real x) u.i = 0x5f3759df - (u.i >> 1); return u.f * (1.5f - u.f * u.f * x * 0.5f); } + +static inline void +evas_build_sphere(const Evas_Box3 *box, Evas_Sphere *sphere) +{ + Evas_Vec3 tmp; + + evas_vec3_set(&sphere->center, (0.5 * (box->p0.x + box->p1.x)), (0.5 * (box->p0.y + box->p1.y)), (0.5 * (box->p0.z + box->p1.z))); + evas_vec3_set(&tmp, sphere->center.x - box->p0.x, sphere->center.y - box->p0.y, sphere->center.z - box->p0.z); + + sphere->radius = sqrtf(evas_vec3_dot_product(&tmp, &tmp)); +} + +static inline void +evas_plane_normalize(Evas_Vec4 *plane) +{ + Evas_Vec3 tmp; + Evas_Real length; + evas_vec3_set(&tmp, plane->x, plane->y, plane->z); + length = evas_vec3_length_get(&tmp); + plane->x = plane->x / length; + plane->y = plane->y / length; + plane->z = plane->z / length; + plane->w = plane->w / length; +} + +static inline Eina_Bool +evas_intersection_line_of_two_planes(Evas_Line3 *line, Evas_Vec4 *plane1, Evas_Vec4 *plane2) +{ + //TODO:parallel case + Evas_Vec3 planes3D[2]; + + evas_vec3_set(&planes3D[0], plane1->x, plane1->y, plane1->z); + evas_vec3_set(&planes3D[1], plane2->x, plane2->y, plane2->z); + + evas_vec3_cross_product(&line->direction, &planes3D[0], &planes3D[1]); + +#define SOLVE_EQUATION(x, y, z) \ + line->point.x = 0; \ + line->point.y = (plane2->w * plane1->z - plane1->w * plane2->z) / line->direction.x; \ + line->point.z = (plane2->y * plane1->w - plane1->y * plane2->w) / line->direction.x; + + if (line->direction.x && plane1->z) + { + SOLVE_EQUATION(x, y, z) + } + else if (line->direction.y && plane1->x) + { + SOLVE_EQUATION(y, z, x) + } + else + { + SOLVE_EQUATION(z, x, y) + } +#undef SOLVE_EQUATION + + return EINA_TRUE; +} + +static inline Eina_Bool +evas_intersection_point_of_three_planes(Evas_Vec3 *point, Evas_Vec4 *plane1, Evas_Vec4 *plane2, Evas_Vec4 *plane3) +{ + //TODO:parallel case + int i; + Evas_Real delta, deltax, deltay, deltaz; + Evas_Real matrix_to_det[3][3]; + Evas_Vec4 planes[3]; + + planes[0] = *plane1; + planes[1] = *plane2; + planes[2] = *plane3; + + for (i = 0; i < 3; i++) + { + matrix_to_det[0][i] = planes[i].x; + matrix_to_det[1][i] = planes[i].y; + matrix_to_det[2][i] = planes[i].z; + } + delta = evas_determinant_3D(matrix_to_det); + + for (i = 0; i < 3; i++) + matrix_to_det[0][i] = planes[i].w; + deltax = evas_determinant_3D(matrix_to_det); + + for (i = 0; i < 3; i++) + { + matrix_to_det[0][i] = planes[i].x; + matrix_to_det[1][i] = planes[i].w; + } + deltay = evas_determinant_3D(matrix_to_det); + + for (i = 0; i < 3; i++) + { + matrix_to_det[1][i] = planes[i].y; + matrix_to_det[2][i] = planes[i].w; + } + deltaz = evas_determinant_3D(matrix_to_det); + + evas_vec3_set(point, -deltax/delta, -deltay/delta, -deltaz/delta); + + return EINA_TRUE; +} + +static inline Evas_Real +evas_point_plane_distance(Evas_Vec3 *point, Evas_Vec4 *plane) +{ + return plane->x * point->x + plane->y * point->y + plane->z * point->z + plane->w; +} + +static inline Evas_Real +evas_point_line_distance(Evas_Vec3 *point, Evas_Line3 *line) +{ + Evas_Vec3 temp, sub; + + evas_vec3_subtract(&sub, point, &line->point); + evas_vec3_cross_product(&temp, &sub, &line->direction); + + return evas_vec3_length_get(&temp) / evas_vec3_length_get(&line->direction); +} + +static inline Eina_Bool +evas_is_sphere_in_frustum(Evas_Sphere *bsphere, Evas_Vec4 *planes) +{ + int i; + Evas_Line3 line; + Evas_Vec3 point, sub; + Evas_Real distances[6] = {0}; + int intersected_planes[3]; + int intersected_planes_count = 0; + + for (i = 0; i < 6; i++) + { + distances[i] = evas_point_plane_distance(&bsphere->center, &planes[i]); + } + + for (i = 0; i < 6; i++) + { + if (distances[i] <= -bsphere->radius) + { + return EINA_FALSE; + } + else if (distances[i] <= 0) + { + intersected_planes[intersected_planes_count] = i; + intersected_planes_count++; + } + } + + if ((intersected_planes_count == 0) || (intersected_planes_count == 1)) + return EINA_TRUE; + else if (intersected_planes_count == 2) + { + evas_intersection_line_of_two_planes(&line, &planes[intersected_planes[0]], &planes[intersected_planes[1]]); + return (evas_point_line_distance(&bsphere->center, &line) < bsphere->radius) ? EINA_TRUE : EINA_FALSE; + } + else if (intersected_planes_count == 3) + { + evas_intersection_point_of_three_planes(&point, &planes[intersected_planes[0]], &planes[intersected_planes[1]], &planes[intersected_planes[2]]); + evas_vec3_subtract(&sub, &point, &bsphere->center); + return (evas_vec3_length_get(&sub) < bsphere->radius) ? EINA_TRUE : EINA_FALSE; + } + + return EINA_FALSE; +} + +static inline Eina_Bool +evas_is_point_in_frustum(Evas_Vec3 *point, Evas_Vec4 *planes) +{ + int i; + for (i = 0; i < 6; i++) + if (evas_point_plane_distance(point, &planes[i]) <= 0) return EINA_FALSE; + return EINA_TRUE; +} + +static inline Eina_Bool +evas_is_box_in_frustum(Evas_Box3 *box, Evas_Vec4 *planes) +{ + int i; + for (i = 0; i < 6; i++) + { + if (planes[i].x * box->p0.x + planes[i].y * box->p0.y + planes[i].z * box->p0.z + planes[i].w > 0) + continue; + if (planes[i].x * box->p1.x + planes[i].y * box->p0.y + planes[i].z * box->p0.z + planes[i].w > 0) + continue; + if (planes[i].x * box->p1.x + planes[i].y * box->p1.y + planes[i].z * box->p0.z + planes[i].w > 0) + continue; + if (planes[i].x * box->p0.x + planes[i].y * box->p1.y + planes[i].z * box->p0.z + planes[i].w > 0) + continue; + if (planes[i].x * box->p0.x + planes[i].y * box->p0.y + planes[i].z * box->p1.z + planes[i].w > 0) + continue; + if (planes[i].x * box->p1.x + planes[i].y * box->p0.y + planes[i].z * box->p1.z + planes[i].w > 0) + continue; + if (planes[i].x * box->p1.x + planes[i].y * box->p1.y + planes[i].z * box->p1.z + planes[i].w > 0) + continue; + if (planes[i].x * box->p0.x + planes[i].y * box->p1.y + planes[i].z * box->p1.z + planes[i].w > 0) + continue; + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static inline void +evas_frustum_calculate(Evas_Vec4 *planes, Evas_Mat4 *matrix_vp) +{ + int i; + evas_vec4_set(&planes[0], matrix_vp->m[3] - matrix_vp->m[0], + matrix_vp->m[7] - matrix_vp->m[4], + matrix_vp->m[11] - matrix_vp->m[8], + matrix_vp->m[15] - matrix_vp->m[12]); + + evas_vec4_set(&planes[1], matrix_vp->m[3] + matrix_vp->m[0], + matrix_vp->m[7] + matrix_vp->m[4], + matrix_vp->m[11] + matrix_vp->m[8], + matrix_vp->m[15] + matrix_vp->m[12]); + + evas_vec4_set(&planes[2], matrix_vp->m[3] + matrix_vp->m[1], + matrix_vp->m[7] + matrix_vp->m[5], + matrix_vp->m[11] + matrix_vp->m[9], + matrix_vp->m[15] + matrix_vp->m[13]); + + evas_vec4_set(&planes[3], matrix_vp->m[3] - matrix_vp->m[1], + matrix_vp->m[7] - matrix_vp->m[5], + matrix_vp->m[11] - matrix_vp->m[9], + matrix_vp->m[15] - matrix_vp->m[13]); + + evas_vec4_set(&planes[4], matrix_vp->m[3] - matrix_vp->m[2], + matrix_vp->m[7] - matrix_vp->m[6], + matrix_vp->m[11] - matrix_vp->m[10], + matrix_vp->m[15] - matrix_vp->m[14]); + + evas_vec4_set(&planes[5], matrix_vp->m[3] + matrix_vp->m[2], + matrix_vp->m[7] + matrix_vp->m[6], + matrix_vp->m[11] + matrix_vp->m[10], + matrix_vp->m[15] + matrix_vp->m[14]); + for (i = 0; i < 6; i++) + { + evas_plane_normalize(&planes[i]); + } +} diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 50f9fa5..6cf5c06 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -219,6 +219,7 @@ struct _Evas_3D_Node Evas_Box3 aabb; Evas_Box3 obb; + Evas_Sphere bsphere; Evas_3D_Node_Type type;