📄 visual_surface.c
字号:
FIX2FLT(eff->ray.dir.x), FIX2FLT(eff->ray.dir.y), FIX2FLT(eff->ray.dir.z)));#endif if (!sr->is_grabbed) sr->hs_grab = NULL; sr->sq_dist = 0; sr->picked = NULL; gf_list_reset(sr->sensors); if (!node_list) { gf_node_render(gf_sg_get_root_node(sr->compositor->scene), eff); } else { while (node_list) { gf_node_render(node_list->node, eff); node_list = node_list->next; } } gf_list_reset(eff->sensors); hs_grabbed = NULL; stype = GF_CURSOR_NORMAL; count = gf_list_count(sr->prev_sensors); for (i=0; i<count; i++) { hs = (SensorHandler*)gf_list_get(sr->prev_sensors, i); if (gf_list_find(sr->sensors, hs) < 0) { /*that's a bit ugly but we need coords if pointer out of the shape when sensor grabbed...*/ if (sr->is_grabbed) { hs_grabbed = hs; sr->hs_grab = hs; } else { hs->OnUserEvent(hs, 0, ev, &sr->hit_info); } } } count = gf_list_count(sr->sensors); for (i=0; i<count; i++) { hs = (SensorHandler*)gf_list_get(sr->sensors, i); hs->OnUserEvent(hs, 1, ev, &sr->hit_info); stype = gf_node_get_tag(hs->owner); if (hs==hs_grabbed) hs_grabbed = NULL; } /*switch sensors*/ tmp = sr->sensors; sr->sensors = sr->prev_sensors; sr->prev_sensors = tmp; /*check if we have a grabbed sensor*/ if (hs_grabbed) { hs_grabbed->OnUserEvent(hs_grabbed, 0, ev, &sr->hit_info); gf_list_reset(sr->prev_sensors); gf_list_add(sr->prev_sensors, hs_grabbed); stype = gf_node_get_tag(hs_grabbed->owner); } /*composite texture*/ if (!stype && sr->hit_info.appear) return r3d_handle_composite_event(sr, ev); /*and set cursor*/ if (sr->last_cursor != GF_CURSOR_COLLIDE) { switch (stype) { case TAG_MPEG4_Anchor: case TAG_X3D_Anchor: stype = GF_CURSOR_ANCHOR; break; case TAG_MPEG4_PlaneSensor2D: case TAG_MPEG4_PlaneSensor: case TAG_X3D_PlaneSensor: stype = GF_CURSOR_PLANE; break; case TAG_MPEG4_CylinderSensor: case TAG_X3D_CylinderSensor: case TAG_MPEG4_DiscSensor: case TAG_MPEG4_SphereSensor: case TAG_X3D_SphereSensor: stype = GF_CURSOR_ROTATE; break; case TAG_MPEG4_ProximitySensor2D: case TAG_MPEG4_ProximitySensor: case TAG_X3D_ProximitySensor: stype = GF_CURSOR_PROXIMITY; break; case TAG_MPEG4_TouchSensor: case TAG_X3D_TouchSensor: stype = GF_CURSOR_TOUCH; break; default: stype = GF_CURSOR_NORMAL; break; } if ((stype != GF_CURSOR_NORMAL) || (sr->last_cursor != stype)) { GF_Event evt; evt.type = GF_EVENT_SET_CURSOR; evt.cursor.cursor_type = stype; sr->compositor->video_out->ProcessEvent(sr->compositor->video_out, &evt); sr->last_cursor = stype; } } else { reset_collide_cursor(sr); } return count ? 1 : 0;}void drawable_do_pick(GF_Node *n, RenderEffect3D *eff) { SFVec3f local_pt, world_pt, vdiff; SFVec3f hit_normal; SFVec2f text_coords; u32 i, count; Fixed sqdist; Bool node_is_over; Render3D *sr; GF_Matrix mx; GF_Ray r; DrawableStack *st = (DrawableStack *)gf_node_get_private(n); u32 cull_bckup = eff->cull_flag; if (!st) return; count = gf_list_count(eff->sensors); sr = eff->surface->render; node_is_over = 0; if (!node_cull(eff, &st->mesh->bounds, 0)) { eff->cull_flag = cull_bckup; return; } eff->cull_flag = cull_bckup; r = eff->ray; gf_mx_copy(mx, eff->model_matrix); gf_mx_inverse(&mx); gf_mx_apply_ray(&mx, &r); /*if we already have a hit point don't check anything below...*/ if (sr->sq_dist && !sr->hs_grab && !eff->collect_layer) { GF_Plane p; SFVec3f hit = sr->hit_info.world_point; gf_mx_apply_vec(&mx, &hit); p.normal = r.dir; p.d = -1 * gf_vec_dot(p.normal, hit); if (gf_bbox_plane_relation(&st->mesh->bounds, &p) == GF_BBOX_FRONT) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Picking: bounding box of node %s (DEF %s) below current hit point - skipping\n", gf_node_get_class_name(n), gf_node_get_name(n))); return; } } if (!st->IntersectWithRay) { node_is_over = gf_mesh_intersect_ray(st->mesh, &r, &local_pt, &hit_normal, &text_coords); } else { node_is_over = st->IntersectWithRay(st->owner, &r, &local_pt, &hit_normal, &text_coords); } if (!node_is_over) { /*store matrices for grabed sensors*/ if (0 && sr->hs_grab && (gf_list_find(eff->sensors, sr->hs_grab)>=0) ) { gf_mx_copy(sr->hit_info.world_to_local, eff->model_matrix); gf_mx_copy(sr->hit_info.local_to_world, mx); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Picking: found grabed sensor - storing matrices\n")); } return; } /*check distance from user and keep the closest hitpoint*/ world_pt = local_pt; gf_mx_apply_vec(&eff->model_matrix, &world_pt); for (i=0; i<eff->num_clip_planes; i++) { if (gf_plane_get_distance(&eff->clip_planes[i], &world_pt) < 0) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Picking: node %s (def %s) is not in clipper half space\n", gf_node_get_class_name(n), gf_node_get_name(n))); return; } } gf_vec_diff(vdiff, world_pt, eff->ray.orig); sqdist = gf_vec_lensq(vdiff); if (sr->sq_dist && (sr->sq_dist+FIX_EPSILON<sqdist)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Picking: node %s (def %s) is farther (%g) than current pick (%g)\n", gf_node_get_class_name(n), gf_node_get_name(n), FIX2FLT(sqdist), FIX2FLT(sr->sq_dist))); return; } sr->sq_dist = sqdist; gf_list_reset(sr->sensors); for (i=0; i<count; i++) { gf_list_add(sr->sensors, gf_list_get(eff->sensors, i)); } gf_mx_copy(sr->hit_info.world_to_local, eff->model_matrix); gf_mx_copy(sr->hit_info.local_to_world, mx); sr->hit_info.local_point = local_pt; sr->hit_info.world_point = world_pt; sr->hit_info.world_ray = eff->ray; sr->hit_info.hit_normal = hit_normal; sr->hit_info.hit_texcoords = text_coords; if (r3d_has_composite_texture(eff->appear)) { sr->hit_info.appear = eff->appear; } else { sr->hit_info.appear = NULL; } sr->picked = n; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Picking: node %s (def %s) is under mouse - hit %g %g %g\n", gf_node_get_class_name(n), gf_node_get_name(n), FIX2FLT(world_pt.x), FIX2FLT(world_pt.y), FIX2FLT(world_pt.z)));}void VS_DoCollisions(RenderEffect3D *eff, GF_ChildNodeItem *node_list){ SFVec3f n, pos, dir; Bool go; Fixed diff, pos_diff; assert(eff->surface && eff->camera); /*don't collide on VP animations or when modes discard collision*/ if ((eff->camera->anim_len && !eff->camera->jumping) || !eff->surface->render->collide_mode || (eff->camera->navigate_mode>=GF_NAVIGATE_EXAMINE)) { /*reset ground flag*/ eff->camera->last_had_ground = 0; /*and avoid reseting move at next collision change*/ eff->camera->last_pos = eff->camera->position; return; } /*don't collide if not moved*/ if (gf_vec_equal(eff->camera->position, eff->camera->last_pos)) { reset_collide_cursor(eff->surface->render); return; } eff->traversing_mode = TRAVERSE_COLLIDE; eff->camera->collide_flags = 0; eff->camera->collide_dist = FIX_MAX; eff->camera->ground_dist = FIX_MAX; if ((eff->camera->navigate_mode==GF_NAVIGATE_WALK) && eff->surface->render->gravity_on) eff->camera->collide_flags |= CF_DO_GRAVITY; gf_vec_diff(dir, eff->camera->position, eff->camera->last_pos); pos_diff = gf_vec_len(dir); gf_vec_norm(&dir); pos = eff->camera->position; diff = 0; go = 1; eff->camera->last_had_col = 0; /*some explanation: the current collision detection algo only checks closest distance to objects, but doesn't attempt to track object cross during a move. If we step more than the collision detection size, we may cross an object without detecting collision. we thus break the move in max collision size moves*/ while (go) { if (pos_diff>eff->camera->avatar_size.x) { pos_diff-=eff->camera->avatar_size.x; diff += eff->camera->avatar_size.x; } else { diff += pos_diff; go = 0; } n = gf_vec_scale(dir, diff); gf_vec_add(eff->camera->position, eff->camera->last_pos, n); if (!node_list) { gf_node_render(gf_sg_get_root_node(eff->surface->render->compositor->scene), eff); } else { while (node_list) { gf_node_render(node_list->node, eff); node_list = node_list->next; } } if (eff->camera->collide_flags & CF_COLLISION) break; eff->camera->collide_flags &= ~CF_DO_GRAVITY; } /*gravity*/ if (eff->camera->collide_flags & CF_GRAVITY) { diff = eff->camera->ground_dist - eff->camera->avatar_size.y; if (eff->camera->last_had_ground && (-diff>eff->camera->avatar_size.z)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: Obstacle detected - too high (dist %g)\n", diff)); eff->camera->position = eff->camera->last_pos; eff->camera->flags |= CAM_IS_DIRTY; } else { if ((eff->camera->jumping && fabs(diff)>eff->camera->dheight) || (!eff->camera->jumping && (ABS(diff)>FIX_ONE/1000) )) { eff->camera->last_had_ground = 1; n = gf_vec_scale(eff->camera->up, -diff); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: Ground detected camera position: %g %g %g - offset: %g %g %g (dist %g)\n", eff->camera->position.x, eff->camera->position.y, eff->camera->position.z, n.x, n.y, n.z, diff)); gf_vec_add(eff->camera->position, eff->camera->position, n); gf_vec_add(eff->camera->target, eff->camera->target, n); gf_vec_add(eff->camera->last_pos, eff->camera->position, n); eff->camera->flags |= CAM_IS_DIRTY; } } } /*collsion found*/ if (eff->camera->collide_flags & CF_COLLISION) { if (eff->surface->render->last_cursor != GF_CURSOR_COLLIDE) { GF_Event evt; eff->camera->last_had_col = 1; evt.type = GF_EVENT_SET_CURSOR; eff->surface->render->last_cursor = evt.cursor.cursor_type = GF_CURSOR_COLLIDE; eff->surface->render->compositor->video_out->ProcessEvent(eff->surface->render->compositor->video_out, &evt); } /*regular collision*/ if (eff->surface->render->collide_mode==GF_COLLISION_NORMAL) { eff->camera->position = eff->camera->last_pos; eff->camera->flags |= CAM_IS_DIRTY; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: Collision detected - restoring previous avatar position\n")); } else { /*camera displacement collision*/ if (eff->camera->collide_dist) { if (eff->camera->collide_dist>=eff->camera->avatar_size.x) GF_LOG(GF_LOG_WARNING, GF_LOG_RENDER, ("[Render 3D] Collision: Collision distance %g greater than avatar collide size %g\n", eff->camera->collide_dist, eff->camera->avatar_size.x)); /*safety check due to precision, always stay below collide dist*/ if (eff->camera->collide_dist>=eff->camera->avatar_size.x) eff->camera->collide_dist = eff->camera->avatar_size.x; gf_vec_diff(n, eff->camera->position, eff->camera->collide_point); gf_vec_norm(&n); n = gf_vec_scale(n, eff->camera->avatar_size.x - eff->camera->collide_dist); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: offseting camera: position: %g %g %g - offset: %g %g %g\n", eff->camera->position.x, eff->camera->position.y, eff->camera->position.z, n.x, n.y, n.z)); gf_vec_add(eff->camera->position, eff->camera->position, n); gf_vec_add(eff->camera->target, eff->camera->target, n); } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: Collision detected and camera on hit point - restoring previous avatar position\n")); eff->camera->position = eff->camera->last_pos; } eff->camera->last_pos = eff->camera->position; eff->camera->flags |= CAM_IS_DIRTY; } } else { reset_collide_cursor(eff->surface->render); eff->camera->last_pos = eff->camera->position; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: no collision found\n")); } if (eff->camera->flags & CAM_IS_DIRTY) VS_SetupProjection(eff);}void drawable_do_collide(GF_Node *node, RenderEffect3D *eff){ SFVec3f pos, v1, v2, collide_pt, last_pos; Fixed dist, m_dist; GF_Matrix mx; u32 ntag, cull_backup; DrawableStack *st = (DrawableStack *)gf_node_get_private(node); if (!st) return; /*no collision with lines & points*/ if (st->mesh->mesh_type != MESH_TRIANGLES) return; /*no collision with text (vrml)*/ ntag = gf_node_get_tag(node); if ((ntag==TAG_MPEG4_Text) || (ntag==TAG_X3D_Text)) return; /*cull but don't use near plane to detect objects behind us*/ cull_backup = eff->cull_flag; if (!node_cull(eff, &st->mesh->bounds, 1)) { eff->cull_flag = cull_backup; return; } eff->cull_flag = cull_backup; /*use up & front to get an average size of the collision dist in this space*/ pos = eff->camera->position; last_pos = eff->camera->last_pos; v1 = camera_get_target_dir(eff->camera); v1 = gf_vec_scale(v1, eff->camera->avatar_size.x); gf_vec_add(v1, v1, pos); v2 = camera_get_right_dir(eff->camera); v2 = gf_vec_scale(v2, eff->camera->avatar_size.x); gf_vec_add(v2, v2, pos); gf_mx_copy(mx, eff->model_matrix); gf_mx_inverse(&mx); gf_mx_apply_vec(&mx, &pos); gf_mx_apply_vec(&mx, &last_pos); gf_mx_apply_vec(&mx, &v1); gf_mx_apply_vec(&mx, &v2); gf_vec_diff(v1, v1, pos); gf_vec_diff(v2, v2, pos); dist = gf_vec_len(v1); m_dist = gf_vec_len(v2); if (dist<m_dist) m_dist = dist; /*check for any collisions*/ if (gf_mesh_closest_face(st->mesh, pos, m_dist, &collide_pt)) { /*get transformed hit*/ gf_mx_apply_vec(&eff->model_matrix, &collide_pt); gf_vec_diff(v2, eff->camera->position, collide_pt); dist = gf_vec_len(v2); if (dist<eff->camera->collide_dist) { eff->camera->collide_dist = dist; eff->camera->collide_flags |= CF_COLLISION; eff->camera->collide_point = collide_pt;#ifndef GPAC_DISABLE_LOG if ((gf_log_get_level() >= GF_LOG_DEBUG) && (gf_log_get_tools() & GF_LOG_RENDER)) { gf_vec_diff(v1, pos, collide_pt); gf_vec_norm(&v1); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: found at %g %g %g (WC) - dist (%g) - local normal %g %g %g\n", eff->camera->collide_point.x, eff->camera->collide_point.y, eff->camera->collide_point.z, dist, v1.x, v1.y, v1.z)); }#endif } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: Existing collision (dist %g) closer than current collsion (dist %g)\n", eff->camera->collide_dist, dist)); } } if (eff->camera->collide_flags & CF_DO_GRAVITY) { GF_Ray r; Bool intersect; r.orig = eff->camera->position; r.dir = gf_vec_scale(eff->camera->up, -FIX_ONE); gf_mx_apply_ray(&mx, &r); if (!st->IntersectWithRay) { intersect = gf_mesh_intersect_ray(st->mesh, &r, &collide_pt, &v1, NULL); } else { intersect = st->IntersectWithRay(st->owner, &r, &collide_pt, &v1, NULL); } if (intersect) { gf_mx_apply_vec(&eff->model_matrix, &collide_pt); gf_vec_diff(v2, eff->camera->position, collide_pt); dist = gf_vec_len(v2); if (dist<eff->camera->ground_dist) { eff->camera->ground_dist = dist; eff->camera->collide_flags |= CF_GRAVITY; eff->camera->ground_point = collide_pt; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: Ground found at %g %g %g (WC) - dist %g - local normal %g %g %g\n", eff->camera->ground_point.x, eff->camera->ground_point.y, eff->camera->ground_point.z, dist, v1.x, v1.y, v1.z)); } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 3D] Collision: Existing ground (dist %g) closer than current (dist %g)\n", eff->camera->ground_dist, dist)); } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -