From a06c12277219d7877df82825962091ac08c50dcc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 9 Jul 2006 14:44:54 +0000 Subject: [PATCH] needed this file for Gradient tool (Window/3d ray picking function) --- release/scripts/bpymodules/BPyWindow.py | 166 ++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100755 release/scripts/bpymodules/BPyWindow.py diff --git a/release/scripts/bpymodules/BPyWindow.py b/release/scripts/bpymodules/BPyWindow.py new file mode 100755 index 00000000000..537873ea04d --- /dev/null +++ b/release/scripts/bpymodules/BPyWindow.py @@ -0,0 +1,166 @@ +import Blender +from Blender import Mathutils, Window, Scene, Draw, Mesh +from Blender.Mathutils import CrossVecs, Matrix, Vector, Intersect, LineIntersect + + +# DESCRIPTION: +# screen_x, screen_y the origin point of the pick ray +# it is either the mouse location +# localMatrix is used if you want to have the returned values in an objects localspace. +# this is usefull when dealing with an objects data such as verts. +# or if useMid is true, the midpoint of the current 3dview +# returns +# Origin - the origin point of the pick ray +# Direction - the direction vector of the pick ray +# in global coordinates +epsilon = 1e-3 # just a small value to account for floating point errors + +def mouseViewRay(screen_x, screen_y, localMatrix=None, useMid = False): + + # Constant function variables + p = mouseViewRay.p + d = mouseViewRay.d + + for win3d in Window.GetScreenInfo(Window.Types.VIEW3D): # we search all 3dwins for the one containing the point (screen_x, screen_y) (could be the mousecoords for example) + win_min_x, win_min_y, win_max_x, win_max_y = win3d['vertices'] + # calculate a few geometric extents for this window + + win_mid_x = (win_max_x + win_min_x + 1.0) * 0.5 + win_mid_y = (win_max_y + win_min_y + 1.0) * 0.5 + win_size_x = (win_max_x - win_min_x + 1.0) * 0.5 + win_size_y = (win_max_y - win_min_y + 1.0) * 0.5 + + #useMid is for projecting the coordinates when we subdivide the screen into bins + if useMid: # == True + screen_x = win_mid_x + screen_y = win_mid_y + + # if the given screencoords (screen_x, screen_y) are within the 3dwin we fount the right one... + if (win_max_x > screen_x > win_min_x) and ( win_max_y > screen_y > win_min_y): + # first we handle all pending events for this window (otherwise the matrices might come out wrong) + Window.QHandle(win3d['id']) + + # now we get a few matrices for our window... + # sorry - i cannot explain here what they all do + # - if you're not familiar with all those matrices take a look at an introduction to OpenGL... + pm = Window.GetPerspMatrix() # the prespective matrix + pmi = Matrix(pm); pmi.invert() # the inverted perspective matrix + + if (1.0 - epsilon < pmi[3][3] < 1.0 + epsilon): + # pmi[3][3] is 1.0 if the 3dwin is in ortho-projection mode (toggled with numpad 5) + hms = mouseViewRay.hms + ortho_d = mouseViewRay.ortho_d + + # ortho mode: is a bit strange - actually there's no definite location of the camera ... + # but the camera could be displaced anywhere along the viewing direction. + + ortho_d.x, ortho_d.y, ortho_d.z = Window.GetViewVector() + ortho_d.w = 0 + + # all rays are parallel in ortho mode - so the direction vector is simply the viewing direction + #hms.x, hms.y, hms.z, hms.w = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0 + hms[:] = (screen_x-win_mid_x) /win_size_x, (screen_y-win_mid_y) / win_size_y, 0.0, 1.0 + + # these are the homogenious screencoords of the point (screen_x, screen_y) ranging from -1 to +1 + p=(hms*pmi) + (1000*ortho_d) + p.resize3D() + d[:] = ortho_d[:3] + + + # Finally we shift the position infinitely far away in + # the viewing direction to make sure the camera if outside the scene + # (this is actually a hack because this function + # is used in sculpt_mesh to initialize backface culling...) + else: + # PERSPECTIVE MODE: here everything is well defined - all rays converge at the camera's location + vmi = Matrix(Window.GetViewMatrix()); vmi.invert() # the inverse viewing matrix + fp = mouseViewRay.fp + + dx = pm[3][3] * (((screen_x-win_min_x)/win_size_x)-1.0) - pm[3][0] + dy = pm[3][3] * (((screen_y-win_min_y)/win_size_y)-1.0) - pm[3][1] + + fp[:] = \ + pmi[0][0]*dx+pmi[1][0]*dy,\ + pmi[0][1]*dx+pmi[1][1]*dy,\ + pmi[0][2]*dx+pmi[1][2]*dy + + # fp is a global 3dpoint obtained from "unprojecting" the screenspace-point (screen_x, screen_y) + #- figuring out how to calculate this took me quite some time. + # The calculation of dxy and fp are simplified versions of my original code + #- so it's almost impossible to explain what's going on geometrically... sorry + + p[:] = vmi[3][:3] + + # the camera's location in global 3dcoords can be read directly from the inverted viewmatrix + #d.x, d.y, d.z =normalize_v3(sub_v3v3(p, fp)) + d[:] = p.x-fp.x, p.y-fp.y, p.z-fp.z + + #print 'd', d, 'p', p, 'fp', fp + + + # the direction vector is simply the difference vector from the virtual camera's position + #to the unprojected (screenspace) point fp + + # Do we want to return a direction in object's localspace? + + if localMatrix: + localInvMatrix = Matrix(localMatrix) + localInvMatrix.invert() + p = p*localInvMatrix + d = d*localInvMatrix # normalize_v3 + p.x += localInvMatrix[3][0] + p.y += localInvMatrix[3][1] + p.z += localInvMatrix[3][2] + + #else: # Worldspace, do nothing + + d.normalize() + return True, p, d # Origin, Direction + + # Mouse is not in any view, return None. + return False, None, None + +# Constant function variables +mouseViewRay.d = Vector(0,0,0) # Perspective, 3d +mouseViewRay.p = Vector(0,0,0) +mouseViewRay.fp = Vector(0,0,0) + +mouseViewRay.hms = Vector(0,0,0,0) # ortho only 4d +mouseViewRay.ortho_d = Vector(0,0,0,0) # ortho only 4d + +def spaceRect(): + ''' + Returns the space rect + xmin,ymin,width,height + ''' + + __UI_RECT__ = Blender.BGL.Buffer(Blender.BGL.GL_FLOAT, 4) + Blender.BGL.glGetFloatv(Blender.BGL.GL_SCISSOR_BOX, __UI_RECT__) + __UI_RECT__ = __UI_RECT__.list + __UI_RECT__ = int(__UI_RECT__[0]), int(__UI_RECT__[1]), int(__UI_RECT__[2])-1, int(__UI_RECT__[3]) + + return __UI_RECT__ + +def mouseRelativeLoc2d(__UI_RECT__= None): + if not __UI_RECT__: + __UI_RECT__ = spaceRect() + + mco = Window.GetMouseCoords() + if mco[0] > __UI_RECT__[0] and\ + mco[1] > __UI_RECT__[1] and\ + mco[0] < __UI_RECT__[0] + __UI_RECT__[2] and\ + mco[1] < __UI_RECT__[1] + __UI_RECT__[3]: + + return (mco[0] - __UI_RECT__[0], mco[1] - __UI_RECT__[1]) + + else: + return None + + + + + + + + + \ No newline at end of file