forked from enlightenment/efl
evas: optimize Canvas3D calculation of bounding space
Summary: Bounding box and sphere will calculate if user need callback of collision or data of box or data of sphere. Reviewers: sri.hebbar, cedric Subscribers: cedric, jpeg Differential Revision: https://phab.enlightenment.org/D3643 Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
This commit is contained in:
parent
61f7236a62
commit
5af22ba27a
|
@ -382,104 +382,6 @@ _node_item_update(Evas_Canvas3D_Node *node, void *data EINA_UNUSED)
|
|||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_rotate_vertices(Eina_Quaternion* orientation, int vertex_count, Evas_Vec3* vertex_position)
|
||||
{
|
||||
int i;
|
||||
if (orientation->x || orientation->y || orientation->z)
|
||||
for (i = 0; i < vertex_count; i++)
|
||||
evas_vec3_quaternion_rotate(&vertex_position[i], &vertex_position[i], orientation);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_scale_vertices(Evas_Vec3* scale, int vertex_count, Evas_Vec3* vertex_position)
|
||||
{
|
||||
int i;
|
||||
if ((scale->x != 1) || (scale->y != 1) || (scale->z != 1))
|
||||
for (i = 0; i < vertex_count; i++)
|
||||
evas_vec3_multiply(&vertex_position[i], &vertex_position[i], scale);
|
||||
}
|
||||
|
||||
static void
|
||||
_calculate_sphere(Evas_Sphere *sphere, int vertex_count, Evas_Vec3 *vertex_position)
|
||||
{
|
||||
float radius = 0.0001f;
|
||||
Evas_Vec3 center, pos, diff;
|
||||
float len, alpha, alpha2;
|
||||
int i, k;
|
||||
|
||||
// shuffle array for averaging algorithms error
|
||||
for (i = 0; i < vertex_count; i++)
|
||||
{
|
||||
k = i + rand()%(vertex_count-i);
|
||||
pos = vertex_position[i];
|
||||
vertex_position[i] = vertex_position[k];
|
||||
vertex_position[k] = pos;
|
||||
}
|
||||
|
||||
center = vertex_position[0];
|
||||
|
||||
for (k = 0; k < 2; k++)
|
||||
{
|
||||
for (i = 0; i < vertex_count; ++i)
|
||||
{
|
||||
pos = vertex_position[i];
|
||||
evas_vec3_subtract(&diff, &pos, ¢er);
|
||||
len = evas_vec3_length_get(&diff);
|
||||
if (len > radius)
|
||||
{
|
||||
alpha = len / radius;
|
||||
alpha2 = alpha * alpha;
|
||||
radius = 0.5f * (alpha + 1 / alpha) * radius;
|
||||
evas_vec3_scale(&pos, &pos, 1 - 1 / alpha2);
|
||||
evas_vec3_scale(¢er, ¢er, (1 + 1 / alpha2));
|
||||
evas_vec3_add(¢er, ¢er, &pos);
|
||||
evas_vec3_scale(¢er, ¢er, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < vertex_count; ++i)
|
||||
{
|
||||
pos = vertex_position[i];
|
||||
evas_vec3_subtract(&diff, &pos, ¢er);
|
||||
len = evas_vec3_length_get(&diff);
|
||||
|
||||
if (len > radius)
|
||||
{
|
||||
radius = (radius + len) / 2.0f;
|
||||
evas_vec3_scale(&diff, &diff, (len - radius) / len);
|
||||
evas_vec3_add(¢er, ¢er, &diff);
|
||||
}
|
||||
}
|
||||
|
||||
sphere->radius = radius;
|
||||
sphere->center = center;
|
||||
}
|
||||
|
||||
static void
|
||||
_calculate_box(Evas_Box3 *box3, int vertex_count, Evas_Vec3 *vertex_position)
|
||||
{
|
||||
int i = 0;
|
||||
float vxmin, vymin, vzmin, vxmax, vymax, vzmax;
|
||||
|
||||
vxmax = vxmin = vertex_position[0].x;
|
||||
vymax = vymin = vertex_position[0].y;
|
||||
vzmax = vzmin = vertex_position[0].z;
|
||||
|
||||
for (i = 1; i < vertex_count; ++i)
|
||||
{
|
||||
if (vxmin > vertex_position[i].x) vxmin = vertex_position[i].x;
|
||||
if (vxmax < vertex_position[i].x) vxmax = vertex_position[i].x;
|
||||
if (vymin > vertex_position[i].y) vymin = vertex_position[i].y;
|
||||
if (vymax < vertex_position[i].y) vymax = vertex_position[i].y;
|
||||
if (vzmin > vertex_position[i].z) vzmin = vertex_position[i].z;
|
||||
if (vzmax < vertex_position[i].z) vzmax = vertex_position[i].z;
|
||||
}
|
||||
evas_box3_set(box3, vxmin, vymin, vzmin, vxmax, vymax, vzmax);
|
||||
}
|
||||
|
||||
static void
|
||||
_pack_meshes_vertex_data(Evas_Canvas3D_Node *node, Evas_Vec3 **vertices, int *count)
|
||||
{
|
||||
|
@ -542,21 +444,18 @@ _pack_meshes_vertex_data(Evas_Canvas3D_Node *node, Evas_Vec3 **vertices, int *co
|
|||
static void
|
||||
_update_node_shapes(Evas_Canvas3D_Node *node)
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
Evas_Vec3 *vertices = NULL;
|
||||
Evas_Canvas3D_Node_Data *pd = eo_data_scope_get(node, EVAS_CANVAS3D_NODE_CLASS);
|
||||
Eina_Bool transform_orientation_dirty;
|
||||
Eina_Bool transform_position_dirty;
|
||||
Eina_Bool transform_scale_dirty;
|
||||
Eina_Bool mesh_geom_dirty;
|
||||
Evas_Vec3 scale;
|
||||
Evas_Vec3 position = pd->position_world;
|
||||
evas_vec3_set(&scale, pd->scale_world.x, pd->scale.y, pd->scale.z);
|
||||
|
||||
if (pd->type != EVAS_CANVAS3D_NODE_TYPE_MESH)
|
||||
{
|
||||
evas_box3_empty_set(&pd->local_aabb);
|
||||
evas_box3_empty_set(&pd->local_obb);
|
||||
pd->local_bsphere.radius = 0;
|
||||
evas_vec3_set(&pd->local_bsphere.center, 0, 0, 0);
|
||||
|
||||
pd->aabb.p0 = position;
|
||||
pd->aabb.p1 = position;
|
||||
pd->obb.p0 = position;
|
||||
|
@ -569,66 +468,43 @@ _update_node_shapes(Evas_Canvas3D_Node *node)
|
|||
eo_do(node,
|
||||
transform_orientation_dirty = evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_TRANSFORM_ORIENTATION),
|
||||
transform_orientation_dirty |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_PARENT_ORIENTATION),
|
||||
transform_position_dirty = evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_TRANSFORM_POSITION),
|
||||
transform_position_dirty |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_PARENT_POSITION),
|
||||
transform_scale_dirty = evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_TRANSFORM_SCALE),
|
||||
transform_scale_dirty |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_PARENT_SCALE),
|
||||
mesh_geom_dirty = evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_MESH_GEOMETRY),
|
||||
mesh_geom_dirty |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_MESH_FRAME));
|
||||
|
||||
if ( transform_orientation_dirty || transform_scale_dirty || mesh_geom_dirty)
|
||||
{
|
||||
int count;
|
||||
Evas_Vec3 *vertices = NULL;
|
||||
|
||||
_pack_meshes_vertex_data(node, &vertices, &count);
|
||||
if (count > 0)
|
||||
{
|
||||
//For aabb calculate to need all transformations(scale, orientation, position) of primary data of vertices.
|
||||
_scale_vertices(&pd->scale_world, count, vertices);
|
||||
_calculate_box(&pd->local_obb, count, vertices);
|
||||
_rotate_vertices(&pd->orientation_world, count, vertices);
|
||||
_calculate_box(&pd->local_aabb, count, vertices);
|
||||
if (transform_scale_dirty || mesh_geom_dirty)
|
||||
{
|
||||
_calculate_sphere(&pd->local_bsphere, count, vertices);
|
||||
}
|
||||
calculate_box(&pd->obb, count, vertices);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
evas_vec3_homogeneous_position_transform(&vertices[i], &vertices[i], &pd->data.mesh.matrix_local_to_world);
|
||||
}
|
||||
calculate_box(&pd->aabb, count, vertices);
|
||||
if (transform_position_dirty || transform_scale_dirty || mesh_geom_dirty)
|
||||
{
|
||||
calculate_sphere(&pd->bsphere, count, vertices);
|
||||
}
|
||||
evas_vec3_homogeneous_position_transform(&pd->obb.p0, &pd->obb.p0, &pd->data.mesh.matrix_local_to_world);
|
||||
evas_vec3_homogeneous_position_transform(&pd->obb.p0, &pd->obb.p0, &pd->data.mesh.matrix_local_to_world);
|
||||
}
|
||||
free(vertices);
|
||||
}
|
||||
|
||||
pd->bsphere.radius = pd->local_bsphere.radius;
|
||||
evas_vec3_quaternion_rotate(&pd->bsphere.center, &pd->local_bsphere.center, &pd->orientation_world);
|
||||
evas_vec3_quaternion_rotate(&pd->obb.p0, &pd->local_obb.p0, &pd->orientation_world);
|
||||
evas_vec3_quaternion_rotate(&pd->obb.p1, &pd->local_obb.p1, &pd->orientation_world);
|
||||
evas_vec3_add(&pd->obb.p0, &position, &pd->local_obb.p0);
|
||||
evas_vec3_add(&pd->obb.p1, &position, &pd->local_obb.p1);
|
||||
evas_vec3_add(&pd->aabb.p0, &position, &pd->local_aabb.p0);
|
||||
evas_vec3_add(&pd->aabb.p1, &position, &pd->local_aabb.p1);
|
||||
evas_vec3_add(&pd->bsphere.center, &position, &pd->local_bsphere.center);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_node_aabb_update(Evas_Canvas3D_Node *node, void *data EINA_UNUSED)
|
||||
Eina_Bool
|
||||
node_aabb_update(Evas_Canvas3D_Node *node, void *data EINA_UNUSED)
|
||||
{
|
||||
Evas_Canvas3D_Node_Data *pd = eo_data_scope_get(node, EVAS_CANVAS3D_NODE_CLASS);
|
||||
Eina_Bool need_recalc;
|
||||
Eina_List *current;
|
||||
Evas_Canvas3D_Node *datanode;
|
||||
const Eo_Event_Description *eo_desc = NULL;
|
||||
|
||||
eo_do(node,
|
||||
need_recalc = evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_TRANSFORM_ORIENTATION),
|
||||
need_recalc |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_PARENT_ORIENTATION),
|
||||
need_recalc |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_TRANSFORM_POSITION),
|
||||
need_recalc |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_PARENT_POSITION),
|
||||
need_recalc |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_TRANSFORM_SCALE),
|
||||
need_recalc |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_PARENT_SCALE),
|
||||
need_recalc |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_MESH_GEOMETRY),
|
||||
need_recalc |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_MESH_FRAME),
|
||||
need_recalc |= evas_canvas3d_object_dirty_get(EVAS_CANVAS3D_STATE_NODE_MEMBER));
|
||||
|
||||
if (!need_recalc) return EINA_TRUE;
|
||||
|
||||
_update_node_shapes(node);
|
||||
|
||||
EINA_LIST_FOREACH(pd->members, current, datanode)
|
||||
{
|
||||
Evas_Canvas3D_Node_Data *datapd = eo_data_scope_get(datanode, EVAS_CANVAS3D_NODE_CLASS);
|
||||
|
@ -662,8 +538,11 @@ _evas_canvas3d_node_evas_canvas3d_object_update_notify(Eo *obj, Evas_Canvas3D_No
|
|||
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_ANY_ORDER, EINA_FALSE,
|
||||
_node_billboard_update, NULL);
|
||||
/* Update AABB. */
|
||||
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_POST_ORDER, EINA_FALSE,
|
||||
_node_aabb_update, NULL);
|
||||
if(eo_base_legacy_only_event_description_get("collision,private"))
|
||||
{
|
||||
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_POST_ORDER, EINA_FALSE,
|
||||
node_aabb_update, NULL);
|
||||
}
|
||||
|
||||
/* Update node item. */
|
||||
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_ANY_ORDER, EINA_FALSE,
|
||||
|
@ -1744,6 +1623,9 @@ EOLIAN static void
|
|||
_evas_canvas3d_node_bounding_box_get(Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd, Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *x2, Evas_Real *y2, Evas_Real *z2)
|
||||
{
|
||||
eo_do(obj, evas_canvas3d_object_update());
|
||||
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_FALSE,
|
||||
node_aabb_update, NULL);
|
||||
|
||||
if (x) *x = pd->aabb.p0.x;
|
||||
if (y) *y = pd->aabb.p0.y;
|
||||
if (z) *z = pd->aabb.p0.z;
|
||||
|
@ -1756,6 +1638,9 @@ EOLIAN static void
|
|||
_evas_canvas3d_node_bounding_sphere_get(Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd, Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *r)
|
||||
{
|
||||
eo_do(obj, evas_canvas3d_object_update());
|
||||
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_FALSE,
|
||||
node_aabb_update, NULL);
|
||||
|
||||
if (x) *x = pd->bsphere.center.x;
|
||||
if (y) *y = pd->bsphere.center.y;
|
||||
if (z) *z = pd->bsphere.center.z;
|
||||
|
|
|
@ -558,6 +558,9 @@ _node_pick(Evas_Canvas3D_Node *node, void *data)
|
|||
Eina_Matrix4 mvp;
|
||||
Evas_Canvas3D_Node_Data *pd_node = eo_data_scope_get(node, EVAS_CANVAS3D_NODE_CLASS);
|
||||
|
||||
evas_canvas3d_node_tree_traverse(node, EVAS_CANVAS3D_TREE_TRAVERSE_POST_ORDER, EINA_FALSE,
|
||||
node_aabb_update, NULL);
|
||||
|
||||
if (! evas_box3_ray3_intersect(&pd_node->aabb, &pick->ray_world))
|
||||
{
|
||||
/* Skip entire subtree. */
|
||||
|
|
|
@ -2016,3 +2016,82 @@ evas_tangent_space_get(float *data, float *tex_data, float *normal_data, unsigne
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
calculate_box(Evas_Box3 *box3, int vertex_count, Evas_Vec3 *vertex_position)
|
||||
{
|
||||
int i = 0;
|
||||
float vxmin, vymin, vzmin, vxmax, vymax, vzmax;
|
||||
|
||||
vxmax = vxmin = vertex_position[0].x;
|
||||
vymax = vymin = vertex_position[0].y;
|
||||
vzmax = vzmin = vertex_position[0].z;
|
||||
|
||||
for (i = 1; i < vertex_count; ++i)
|
||||
{
|
||||
if (vxmin > vertex_position[i].x) vxmin = vertex_position[i].x;
|
||||
if (vxmax < vertex_position[i].x) vxmax = vertex_position[i].x;
|
||||
if (vymin > vertex_position[i].y) vymin = vertex_position[i].y;
|
||||
if (vymax < vertex_position[i].y) vymax = vertex_position[i].y;
|
||||
if (vzmin > vertex_position[i].z) vzmin = vertex_position[i].z;
|
||||
if (vzmax < vertex_position[i].z) vzmax = vertex_position[i].z;
|
||||
}
|
||||
evas_box3_set(box3, vxmin, vymin, vzmin, vxmax, vymax, vzmax);
|
||||
}
|
||||
|
||||
static inline void
|
||||
calculate_sphere(Evas_Sphere *sphere, int vertex_count, Evas_Vec3 *vertex_position)
|
||||
{
|
||||
float radius = 0.0001f;
|
||||
Evas_Vec3 center, pos, diff;
|
||||
float len, alpha, alpha2;
|
||||
int i, k;
|
||||
|
||||
// shuffle array for averaging algorithms error
|
||||
for (i = 0; i < vertex_count; i++)
|
||||
{
|
||||
k = i + rand()%(vertex_count-i);
|
||||
pos = vertex_position[i];
|
||||
vertex_position[i] = vertex_position[k];
|
||||
vertex_position[k] = pos;
|
||||
}
|
||||
|
||||
center = vertex_position[0];
|
||||
|
||||
for (k = 0; k < 2; k++)
|
||||
{
|
||||
for (i = 0; i < vertex_count; ++i)
|
||||
{
|
||||
pos = vertex_position[i];
|
||||
evas_vec3_subtract(&diff, &pos, ¢er);
|
||||
len = evas_vec3_length_get(&diff);
|
||||
if (len > radius)
|
||||
{
|
||||
alpha = len / radius;
|
||||
alpha2 = alpha * alpha;
|
||||
radius = 0.5f * (alpha + 1 / alpha) * radius;
|
||||
evas_vec3_scale(&pos, &pos, 1 - 1 / alpha2);
|
||||
evas_vec3_scale(¢er, ¢er, (1 + 1 / alpha2));
|
||||
evas_vec3_add(¢er, ¢er, &pos);
|
||||
evas_vec3_scale(¢er, ¢er, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < vertex_count; ++i)
|
||||
{
|
||||
pos = vertex_position[i];
|
||||
evas_vec3_subtract(&diff, &pos, ¢er);
|
||||
len = evas_vec3_length_get(&diff);
|
||||
|
||||
if (len > radius)
|
||||
{
|
||||
radius = (radius + len) / 2.0f;
|
||||
evas_vec3_scale(&diff, &diff, (len - radius) / len);
|
||||
evas_vec3_add(¢er, ¢er, &diff);
|
||||
}
|
||||
}
|
||||
|
||||
sphere->radius = radius;
|
||||
sphere->center = center;
|
||||
}
|
||||
|
|
|
@ -258,9 +258,6 @@ struct _Evas_Canvas3D_Node
|
|||
Evas_Box3 aabb;
|
||||
Evas_Box3 obb;
|
||||
Evas_Sphere bsphere;
|
||||
Evas_Box3 local_aabb;
|
||||
Evas_Box3 local_obb;
|
||||
Evas_Sphere local_bsphere;
|
||||
|
||||
Evas_Canvas3D_Node_Type type;
|
||||
|
||||
|
@ -1753,6 +1750,7 @@ void evas_canvas3d_node_scene_root_add(Evas_Canvas3D_Node *node, Evas_Canvas3D_S
|
|||
void evas_canvas3d_node_scene_root_del(Evas_Canvas3D_Node *node, Evas_Canvas3D_Scene *scene);
|
||||
void evas_canvas3d_node_scene_camera_add(Evas_Canvas3D_Node *node, Evas_Canvas3D_Scene *scene);
|
||||
void evas_canvas3d_node_scene_camera_del(Evas_Canvas3D_Node *node, Evas_Canvas3D_Scene *scene);
|
||||
Eina_Bool node_aabb_update(Evas_Canvas3D_Node *node, void *data EINA_UNUSED);
|
||||
|
||||
/* Camera functions. */
|
||||
void evas_canvas3d_camera_node_add(Evas_Canvas3D_Camera *camera, Evas_Canvas3D_Node *node);
|
||||
|
|
Loading…
Reference in New Issue