/** * Calculate a 3d location from 2d window coordinates. * \param ar The region (used for the window width and height). * \param depth_pt The reference location used to calculate the Z depth. * \param mval The area relative location (such as event->mval converted to floats). * \param out The resulting world-space location. */ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]) { RegionView3D *rv3d = ar->regiondata; float ray_origin[3]; float ray_direction[3]; float lambda; if (rv3d->is_persp) { float plane[4]; copy_v3_v3(ray_origin, rv3d->viewinv[3]); ED_view3d_win_to_vector(ar, mval, ray_direction); /* note, we could use isect_line_plane_v3() however we want the intersection to be infront of the * view no matter what, so apply the unsigned factor instead */ plane_from_point_normal_v3(plane, depth_pt, rv3d->viewinv[2]); isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, false); lambda = fabsf(lambda); } else { float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f; float dy = (2.0f * mval[1] / (float)ar->winy) - 1.0f; if (rv3d->persp == RV3D_CAMOB) { /* ortho camera needs offset applied */ const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 4.0f; dx += rv3d->camdx * zoomfac; dy += rv3d->camdy * zoomfac; } ray_origin[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0]; ray_origin[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1]; ray_origin[2] = (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2]; copy_v3_v3(ray_direction, rv3d->viewinv[2]); lambda = ray_point_factor_v3(depth_pt, ray_origin, ray_direction); } madd_v3_v3v3fl(out, ray_origin, ray_direction, lambda); }
/** * Sets the depth from #StrokeElem.mval */ static bool stroke_elem_project( const struct CurveDrawData *cdd, const int mval_i[2], const float mval_fl[2], float surface_offset, const float radius, float r_location_world[3], float r_normal_world[3]) { View3D *v3d = cdd->vc.v3d; ARegion *ar = cdd->vc.ar; RegionView3D *rv3d = cdd->vc.rv3d; bool is_location_world_set = false; /* project to 'location_world' */ if (cdd->project.use_plane) { /* get the view vector to 'location' */ float ray_origin[3], ray_direction[3]; ED_view3d_win_to_ray(cdd->vc.ar, v3d, mval_fl, ray_origin, ray_direction, false); float lambda; if (isect_ray_plane_v3(ray_origin, ray_direction, cdd->project.plane, &lambda, true)) { madd_v3_v3v3fl(r_location_world, ray_origin, ray_direction, lambda); if (r_normal_world) { zero_v3(r_normal_world); } is_location_world_set = true; } } else { const ViewDepths *depths = rv3d->depths; if (depths && ((unsigned int)mval_i[0] < depths->w) && ((unsigned int)mval_i[1] < depths->h)) { const double depth = (double)depth_read_zbuf(&cdd->vc, mval_i[0], mval_i[1]); if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { if (depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) { is_location_world_set = true; if (r_normal_world) { zero_v3(r_normal_world); } if (surface_offset != 0.0f) { const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius; float normal[3]; if (depth_read_normal(&cdd->vc, &cdd->mats, mval_i, normal)) { madd_v3_v3fl(r_location_world, normal, offset * surface_offset); if (r_normal_world) { copy_v3_v3(r_normal_world, normal); } } } } } } } if (is_location_world_set) { if (cdd->project.use_offset) { add_v3_v3(r_location_world, cdd->project.offset); } } return is_location_world_set; }