1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
22 "region_2d_to_vector_3d",
23 "region_2d_to_location_3d",
24 "location_3d_to_region_2d",
25 "location_3d_to_region_2d",
28 def region_2d_to_vector_3d(region, rv3d, coord):
30 Return a direction vector from the viewport at the spesific 2d region
33 :arg region: region of the 3D viewport, typically bpy.context.region.
34 :type region: :class:`Region`
35 :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d.
36 :type rv3d: :class:`RegionView3D`
37 :arg coord: 2d coordinates relative to the region:
38 (event.mouse_region_x, event.mouse_region_y) for example.
39 :type coord: 2d vector
40 :return: normalized 3d vector.
41 :rtype: :class:`Vector`
43 from mathutils import Vector
45 if rv3d.is_perspective:
46 persinv = rv3d.perspective_matrix.inverted()
48 out = Vector(((2.0 * coord[0] / region.width) - 1.0,
49 (2.0 * coord[1] / region.height) - 1.0,
53 w = (out[0] * persinv[0][3]) + \
54 (out[1] * persinv[1][3]) + \
55 (out[2] * persinv[2][3]) + persinv[3][3]
57 return ((out * persinv) / w) - rv3d.view_matrix.inverted()[3].xyz
59 return rv3d.view_matrix.inverted()[2].xyz.normalized()
62 def region_2d_to_location_3d(region, rv3d, coord, depth_location):
64 Return a 3d location from the region relative 2d coords, aligned with
67 :arg region: region of the 3D viewport, typically bpy.context.region.
68 :type region: :class:`Region`
69 :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d.
70 :type rv3d: :class:`RegionView3D`
71 :arg coord: 2d coordinates relative to the region;
72 (event.mouse_region_x, event.mouse_region_y) for example.
73 :type coord: 2d vector
74 :arg depth_location: the returned vectors depth is aligned with this since
75 there is no defined depth with a 2d region input.
76 :type depth_location: 3d vector
77 :return: normalized 3d vector.
78 :rtype: :class:`Vector`
80 from mathutils import Vector
81 from mathutils.geometry import intersect_point_line
83 persmat = rv3d.perspective_matrix.copy()
84 coord_vec = region_2d_to_vector_3d(region, rv3d, coord)
85 depth_location = Vector(depth_location)
87 if rv3d.is_perspective:
88 from mathutils.geometry import intersect_line_plane
90 origin_start = rv3d.view_matrix.inverted()[3].to_3d()
91 origin_end = origin_start + coord_vec
92 view_vec = rv3d.view_matrix.inverted()[2]
93 return intersect_line_plane(origin_start, origin_end, depth_location, view_vec, 1)
95 dx = (2.0 * coord[0] / region.width) - 1.0
96 dy = (2.0 * coord[1] / region.height) - 1.0
97 persinv = persmat.inverted()
98 viewinv = rv3d.view_matrix.inverted()
99 origin_start = (persinv[0].xyz * dx) + (persinv[1].xyz * dy) + viewinv[3].xyz
100 origin_end = origin_start + coord_vec
101 return intersect_point_line(depth_location, origin_start, origin_end)[0]
104 def location_3d_to_region_2d(region, rv3d, coord):
106 Return the *region* relative 2d location of a 3d position.
108 :arg region: region of the 3D viewport, typically bpy.context.region.
109 :type region: :class:`Region`
110 :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d.
111 :type rv3d: :class:`RegionView3D`
112 :arg coord: 3d worldspace location.
113 :type coord: 3d vector
115 :rtype: :class:`Vector`
117 prj = Vector((coord[0], coord[1], coord[2], 1.0)) * rv3d.perspective_matrix
119 width_half = region.width / 2.0
120 height_half = region.height / 2.0
122 return Vector((width_half + width_half * (prj.x / prj.w),
123 height_half + height_half * (prj.y / prj.w),