Difference between revisions of "User:TomDym"
From The Foundry MODO SDK wiki
Line 791: | Line 791: | ||
} | } | ||
} | } | ||
+ | </pre> | ||
+ | |||
+ | === Raycasting for tools from screen === | ||
+ | |||
+ | <pre> | ||
+ | CLxUser_VectorStack vector_stack (tool_vector); | ||
+ | if (! vector_stack.test ()) | ||
+ | { | ||
+ | return LXe_FALSE; | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // 1. Using CLxUser_Raycast | ||
+ | // | ||
+ | CLxUser_RaycastPacket raycast_packet {}; | ||
+ | if (! vector_stack.ReadObject (raycast_packet_offset_, raycast_packet)) | ||
+ | { | ||
+ | return LXe_FALSE; | ||
+ | } | ||
+ | |||
+ | auto screen_event = static_cast<LXpToolScreenEvent*>(vector_stack.Read (screen_event_packet_offset_)); | ||
+ | if (! screen_event) | ||
+ | { | ||
+ | return LXe_FALSE; | ||
+ | } | ||
+ | |||
+ | LXtHitPolygon hit_polygon {}; | ||
+ | raycast_packet.HitPolygon (vector_stack, LXf_LAYER_ACTIVE, screen_event->fcx, screen_event->fcy, &hit_polygon); | ||
+ | |||
+ | // | ||
+ | // 2. Using LXpToolHitEvent | ||
+ | // | ||
+ | auto hit_event = static_cast<LXpToolHitEvent*>(vector_stack.Read (hitevent_packet_offset_)); | ||
+ | if (! hit_event) | ||
+ | { | ||
+ | return LXe_FALSE; | ||
+ | } | ||
+ | if (! hit_event->hit.pol) | ||
+ | { | ||
+ | return LXe_FALSE; | ||
+ | } | ||
+ | |||
+ | // | ||
+ | // 3. Using CLxUser_View3D and CLxUser_Surface(not shown; must account for item transforms) | ||
+ | // I don't use modo's macro maths in practice. | ||
+ | // | ||
+ | CLxUser_View3DportService view_service {}; | ||
+ | const int view_index_current = view_service.Current (); | ||
+ | |||
+ | CLxUser_View3D view {}; | ||
+ | view_service.View (view_index_current, view); | ||
+ | if (! view.test ()) | ||
+ | { | ||
+ | return LXe_FALSE; | ||
+ | } | ||
+ | |||
+ | auto screen_event = static_cast<LXpToolScreenEvent*>(vector_stack.Read (screen_event_packet_offset_)); | ||
+ | if (! screen_event) | ||
+ | { | ||
+ | return LXe_FALSE; | ||
+ | } | ||
+ | |||
+ | const int pos_flags {0}; // alternatives: LXi_VPTO3D_SNAP; LXi_VPTO3D_WORK | ||
+ | LXtVector point_from_screen {}; | ||
+ | if (LXx_FAIL (view.To3D (screen_event->fcx, screen_event->fcy, point_from_screen, pos_flags))) | ||
+ | { | ||
+ | return LXe_FALSE; | ||
+ | } | ||
+ | |||
+ | LXtVector ray_direction {}; | ||
+ | const double dist_to_point_from_ray_origin = view.EyeVector (point_from_screen, ray_direction); | ||
+ | |||
+ | LXtVector ray_origin {}; | ||
+ | LXx_VCPY (ray_origin, point_from_screen); | ||
+ | LXx_VADDS (ray_origin, ray_direction, dist_to_point_from_ray_origin * -1.0); | ||
+ | |||
+ | // pass ray to function that uses CLxUser_Surface::RayCast | ||
</pre> | </pre> |
Revision as of 08:21, 21 April 2020
Contents
- 1 DoWhileUserIsIdle
- 2 Toggle Command
- 3 Path of Selected Preset Item
- 4 View3dService Example
- 5 Listeners
- 6 StartCommands Config
- 7 Polygon Itersect Ray
- 8 Undo Command
- 9 lx.object.Polygon()
- 10 Selection Packets
- 11 Layer Scan
- 12 Channels
- 13 Command Example
- 14 Notifier
- 15 Check if command Enabled
- 16 Get mesh from meshop
DoWhileUserIsIdle
//If you try to execute a script while holding down a modifier like ctrl or shift, it will postpone execution until you release the modifier #python import lx, lxifc class visitor(lxifc.Visitor): def __init__(self): # The initial setup method pass def vis_Evaluate(self): lx.out("Visitor") pSrv = lx.service.Platform() vis = visitor() com_visitor = lx.object.Unknown(vis) pSrv.DoWhenUserIsIdle(com_visitor, lx.symbol.fUSERIDLE_MODIFIER_KEYS_UP) //Too cancel it you need to pass exactly the same com object and flags pSrv.CancelDoWhenUserIsIdle(com_visitor, lx.symbol.fUSERIDLE_MODIFIER_KEYS_UP )
Toggle Command
lx.eval('tool.set falloff.linear ?+')
Path of Selected Preset Item
#!python ppaths = lxu.select.PresetPathSelection().current() print ppaths
View3dService Example
import modo, lx viewSvc = lx.service.View3Dport() currentView = lx.object.View3D(viewSvc.View(viewSvc.Current())) for i in range(viewSvc.Count()): view = lx.object.View3D(viewSvc.View(i)) print view.Matrix(0) print view.Angles() print view.Axis() print view.EyeVector() lx.out(view.WorkPlane()) a = view.To3D(150.0,150.0,2000) a = view.Center() a = view.WorkPlane()
Listeners
#python import lx import lxifc import modo class ListenerTwo(lxifc.NavigationListener): def __init__(self): self.listenerService = lx.service.Listener() self.listenerService.AddListener(self) self.item = modo.Mesh() self.view = lx.object.View lx.out('hey') def nav_Wheel(self,view, item): lx.out('Worked') def nav_Up(self, view, item): #is Called when move is started lx.out('nav_up') def nav_Move(self, view, item, hot, pos, rot, zoom): pass #is called every "move" while held down #lx.out('nav_move') def nav_Delta(self, view, item, hot, pos, rot, zoom): lx.out('nav_Delta') def nav_Down(self, view, item): #is Called when move is ended lx.out('nav_down') def nav_HotSyncPre(self, view, item): lx.out('nav_HotSyncPre') def nav_HotSyncPost(self, view, item): lx.out('nav_HotSyncPost') ListenerTwo() #instance a Listener to initialize it
Mesh Listener
#python import lx import lxifc import modo geo = modo.MeshGeometry("Mesh").internalMesh port = lx.object.ListenerPort(geo) class mesh_listener(lxifc.MeshListener): undoService = lx.service.Undo() def __init__(self): self.listenerService = lx.service.Listener() self.COM_object = lx.object.Unknown(port) def ml_Changes(self, event): print "change" l = mesh_listener() port.AddListener(l)
Command Listener
#python import lx import lxifc import modo svc_listen = lx.service.Listener() class CmdListener(lxifc.CmdSysListener): def __init__(self): svc_listen = lx.service.Listener() svc_listen.AddListener(self) self.armed = True def cmdsysevent_UserRedo(self): #pass #is called everytime a redo is called lx.out('cmdsysevent_UserRedo') def cmdsysevent_UserUndo(self): #pass #is called everytime a undo is called lx.eval('log.masterClear') lx.out('cmdsysevent_UserUndo') def cmdsysevent_ExecutePre(self,cmd,type,isSandboxed,isPostCmd): if self.armed: cmd = lx.object.Command(cmd) # lx.out("'%s' will fire shortly" % cmd.Name()) if cmd.Name() == "app.quit": lx.eval('replay.fileClose') def cmdsysevent_ExecutePost(self,cmd,isSandboxed,isPostCmd): if self.armed: cmd = lx.object.Command(cmd) lx.out("'%s' has finished" % cmd.Name()) lx.out('cmdsysevent_ExecutePost') pass def cmdsysevent_RefireBegin(self): # we don't want a bunch of events when the user is # dragging a minislider or something like that, # so we disarm the listener on RefireBegin... self.armed = False cmdListener1 = CmdListener()
Scene Item Listener
#python import lx import lxifc import modo class ListenerTwo(lxifc.SceneItemListener): def __init__(self): self.listenerService = lx.service.Listener() self.COM_object = lx.object.Unknown(self) self.listenerService.AddListener(self.COM_object) def sil_ItemAdd(self, item): lx.out('sil_ItemAdd') def __del__(self): self.listenerService.RemoveListener(self.COM_object) list = ListenerTwo() #instance a Listener to initialize it
Selection Listener
#python import lx import lxifc import modo class ListenerTwo(lxifc.SelectionListener): def __init__(self): self.listenerService = lx.service.Listener() self.COM_object = lx.object.Unknown(self) self.listenerService.AddListener(self.COM_object) self.type = modo.Item.type def selevent_Add(self, type, subtType): lx.eval('log.MasterClear') lx.out('selevent_Add') pass def selevent_Current(self, type): lx.eval('log.MasterClear') lx.out('selevent_Current') pass def selevent_Remove(self, type, subtType): lx.eval('log.MasterClear') lx.out('selevent_Remove') pass def selevent_Time(self, time): lx.out(time) pass def selevent_TimeRange(self, type): pass list = ListenerTwo() #instance a Listener to initialize it
Command System Listener
#python import lx import lxifc import modo svc_listen = lx.service.Listener() class CmdListener(lxifc.CmdSysListener): def __init__(self): svc_listen = lx.service.Listener() svc_listen.AddListener(self) self.armed = True def cmdsysevent_UserRedo(self): #pass #is called everytime a redo is called lx.out('cmdsysevent_UserRedo') def cmdsysevent_UserUndo(self): #pass #is called everytime a undo is called lx.eval('log.masterClear') lx.out('cmdsysevent_UserUndo') def cmdsysevent_ExecutePre(self,cmd,type,isSandboxed,isPostCmd): if self.armed: cmd = lx.object.Command(cmd) # lx.out("'%s' will fire shortly" % cmd.Name()) if cmd.Name() == "app.quit": lx.eval('replay.fileClose') def cmdsysevent_ExecutePost(self,cmd,isSandboxed,isPostCmd): if self.armed: cmd = lx.object.Command(cmd) lx.out("'%s' has finished" % cmd.Name()) lx.out('cmdsysevent_ExecutePost') pass def cmdsysevent_RefireBegin(self): # we don't want a bunch of events when the user is # dragging a minislider or something like that, # so we disarm the listener on RefireBegin... self.armed = False cmdListener1 = CmdListener()
User Value Listener
#python import lx import lxifc import modo class ListenerTwo(lxifc.UserValueListener?): def __init__(self): self.listenerService = lx.service.Listener() self.COM_object = lx.object.Unknown(self) self.listenerService.AddListener(self.COM_object) self.userValue = lx.eval('user.value someValue ?') def uvl_Added(self, userValue): lx.out('uvl_Added') pass def uvl_DefChanged(self, userValue): lx.out('uvl_DefChanged') pass def uvl_Deleted(self, name): lx.out('uvl_Deleted') pass def uvl_ValueChanged(self, userValue): lx.out('uvl_ValueChanged') pass list = ListenerTwo() #instance a Listener to initialize it
Session Listener
# python import lx, lxifc svc_listen = lx.service.Listener() class sesListener(lxifc.SessionListener): def __init__(self): svc_listen = lx.service.Listener() svc_listen.AddListener(self) def sesl_SystemReady(self): lx.out('Session Listener: system was ready') sesListener = sesListener()
StartCommands Config
<?xml version="1.0" encoding="UTF-8"?> <configuration> <atom type="StartupCommands"> <list type="Command">sl</list> </atom> </configuration>
Polygon Itersect Ray
import modo, lx,lxu mesh = modo.Mesh() for poly in mesh.geometry.polygons: polygon = lx.object.Polygon(poly) print polygon.Index() pos = modo.Vector3(0,0, 0.0, 0.0) dir = modo.Vector3(0.0, 1.0, 0.0) bool_test, hit_nrm, hit_dist = polygon.IntersectRay(pos, dir) print bool_test, hit_dist
Undo Command
import lx import lxu class myUndoCommand(lxu.command.BasicCommand): def basic_Execute(self, msg, flags): undo_svc = lx.service.Undo() if undo_svc.State() != lx.symbol.iUNDO_INVALID: undo_svc.Apply(myUndo(someData)) mesh = modo.Mesh() with cube.geometry as geo: for v in geo.vertices: v += (0, 0.5, 0) cube.geometry.setMeshEdits() def cmd_Flags(self): return lx.symbol.fCMD_UNDO class myUndo(lxifc.Undo): def __init__(self, data): self.data = data def undo_Forward(self): # do stuff for running command and redo pass def undo_Reverse(self): # do stuff here for undo pass lx.bless(myUndoCommand, "undoCommand")
lx.object.Polygon()
#python import modo scene = modo.Scene() for mesh in scene.meshes: poly_list = mesh.geometry.polygons.selected if poly_list: for poly in poly_list: lx.object.Polygon(poly) poly_mesh = poly.Mesh() scene.select(mesh, True) else: print 'For mesh %s - No Polygons Selected' % mesh.name
Selection Packets
import lx,lxu,lxifc lx.eval('log.masterClear') svcSel = lx.service.Selection() type = svcSel.LookupType(lx.symbol.sSELTYP_ITEM) name = svcSel.LookupName(type) lx.out(name) pkt = svcSel.Recent(type) lx.out(pkt) pkt = svcSel.ByIndex(type,0) #lx.out(pkt) n = svcSel.Count(type) #for i in range(0,n): # pkt = svcSel.ByIndex(type,i) # lx.out('Packet: %s' % pkt) stateFlags = svcSel.State(type,pkt) lx.out(stateFlags) if stateFlags and lx.symbol.f_SELECTION_PRIMARY: lx.out('pkt: %s' % pkt) sel_type_item = svcSel.LookupType (lx.symbol.sSELTYP_ITEM) # Set up a polygon selection packet translator, which lets us read information about a polygon selection packet. item_pkt_trans = lx.object.ItemPacketTranslation (svcSel.Allocate(lx.symbol.sSELTYP_ITEM)) # Grab the polygon selection packet by index (0 in this case, first selected polygon). selection_pkt = svcSel.ByIndex(sel_type_item, 0) # This will get the item this polygon belongs to. item = item_pkt_trans.Item(selection_pkt) pkt = item_pkt_trans.Packet(item) type_item = svcSel.LookupType (lx.symbol.sSELTYP_ITEM) if svcSel.Test (type_item, pkt) == True: lx.out('selected') ######################################################## lx.eval('log.masterClear') sel_svc = lx.service.Selection () sel_type_polygon = sel_svc.LookupType (lx.symbol.sSELTYP_POLYGON) # Set up a polygon selection packet translator, which lets us read information about a polygon selection packet. polygon_pkt_trans = lx.object.PolygonPacketTranslation (sel_svc.Allocate(lx.symbol.sSELTYP_POLYGON)) # Grab the polygon selection packet by index (0 in this case, first selected polygon). selection_pkt = sel_svc.ByIndex(sel_type_polygon, 0) # This will get the item this polygon belongs to. item = polygon_pkt_trans.Item(selection_pkt) temp = item.SetName('Trial') lx.out(temp)
Layer Scan
layer_svc = lx.service.Layer() layer_scan = lx.object.LayerScan(layer_svc.ScanAllocate(lx.symbol.f_LAYERSCAN_EDIT)) if layer_scan.test() == False: return #Some Editing Code Here layer_scan.SetMeshChange(0, lx.symbol.f_MESHEDIT_GEOMETRY) layer_scan.Apply()
Channels
import lxu.select import modo #scene = lxu.select.SceneSelection().current() #chan_read = scene.Channels(lx.symbol.s_ACTIONLAYER_EDIT, 0.0) #mesh = modo.Mesh() #chan_read.set? #lx.out(chanVal) lx.eval('log.masterClear') sel_svc = lx.service.Selection() scene = item.Context() index = item.ChannelLookup('size') action_layer = lx.symbol.s_ACTIONLAYER_EDIT chan_read_obj = scene.Channels (action_layer, sel_svc.GetTime()) temp = scene.Channels(action_layer,sel_svc.GetTime()) mesh = modo.Mesh() chans = mesh.channels() for chan in chans: lx.out(chan.name) channelID = mesh.ChannelLookup('wsclMatrix') # Get the Channel type chan_type = mesh.ChannelEvalType(channelID) # Return the appropiate value depending on the Channel Type if chan_type == "float": lx.out(chan_read_obj.Double(mesh, channel_id)) if chan_type == "integer": lx.out(chan_read_obj.Integer(mesh, channel_id)) if chan_type == "string": lx.out(chan_read_obj.String(mesh, channel_id)) lx.out('--------------------') matrixObject = mesh.channel('wsclMatrix').get() matrix = modo.Matrix4(matrixObject) mesh.scale.set(matrix.scale() * 2) for vector in matrix.scale(): lx.out(vector)
Command Example
import modo class MyCommand_Cmd(lxu.command.BasicCommand): def __init__(self): lxu.command.BasicCommand.__init__ (self) def basic_ButtonName(self): return "My Command" def cmd_Tooltip(self): return "Tooltip for my command." def cmd_UserName(self): return "My Command Dialog" def cmd_Flags(self): return lx.symbol.fCMD_UNDO | lx.symbol.fCMD_MODEL | lx.symbol.fCMD_REPEAT | lx.symbol.iUNDO_ACTIVE def basic_Execute(self, msg, flags): lx.out('basic execute') undoService = lx.service.Undo() if not undoService.State() == lx.symbol.iUNDO_ACTIVE: return with mesh.geometry as geo: for v in geo.vertices: v += (0, 0.5, 0) mesh.geometry.setMeshEdits() mesh.geometry._UNDO_SVC def cmd_PreExecute(self): #execute stuff before basix eceute lx.out('pre Execute') lx.bless (MyCommand_Cmd, "my.commandH")
Notifier
- Notifier Based on the example by Tim Vasquez
import lx import lxifc import lxu.command import random class MyNotifier(lxifc.Notifier): masterList = {} def noti_Name(self): return "my.notifier4" def noti_AddClient(self,event): self.masterList[event.__peekobj__()] = event def noti_RemoveClient(self,event): del self.masterList[event.__peekobj__()] def Notify(self, flags): for event in self.masterList: evt = lx.object.CommandEvent(self.masterList[event]) evt.Event(flags) lx.bless(MyNotifier,"my.notifier4") class notify_Send(lxu.command.BasicCommand): def __init__(self): lxu.command.BasicCommand.__init__(self) def basic_Execute(self, msg, flags): notifier = MyNotifier() notifier.Notify(lx.symbol.fCMDNOTIFY_LABEL) def basic_Enable(self,msg): return True lx.bless(notify_Send, "notify.send4") class CmdNotifiers(lxu.command.BasicHints): def __init__(self): self._notifiers = [('my.notifier4','')] class notify_Receiver(lxu.command.BasicCommand): def __init__(self): lxu.command.BasicCommand.__init__(self) def basic_Execute(self, msg, flags): pass def arg_UIValueHints(self, index): return CmdNotifiers() def basic_ButtonName(self): rstr = "Hello: %s" % str(random.randrange(1,10000)) return "Dog: %s" % rstr def basic_Enable(self,msg): return True lx.bless(notify_Receiver, "notify.recv4")
Check if command Enabled
import modo, lx, lxu msg = lx.object.Message() msg = lx.service.Message().Allocate() msg.SetCode(lx.symbol.iCM_ACT_DONE) cmd_svc = lx.service.Command() cmd = cmd_svc.Spawn(lx.symbol.iCTAG_NULL, 'set.sceneAsDefault') try: test = cmd.Enable(msg) lx.out('worked') except Exception as e: dialog = modo.dialogs.alert("Look Here", "Error: %s" % e) lx.out('We continued on')
Get mesh from meshop
I use this in a tool i made, that checks for mesh, then checks for a defomered mesh,. then if thats off it checks for a morphed mesh etc. Answer to: Is there any way to check a procedural mesh's mesh? I want to check if a mesh, that is getting its geo via a mesh merge, contains some specific data. I am grabbing the mesh via the sICHAN_MESH_MESH channel and using the Edit Action. I just end up getting an empty mesh.
for (unsigned meshIter = 0; meshIter < outCount; meshIter++) { CLxUser_MeshService msh_srv; CLxUser_Locator mesh_locator; CLxUser_Mesh morph_mesh, deform_mesh; bool bUseDeformedMesh = false; scan.BaseMeshByIndex(meshIter, scan_mesh); // get mesh msh_srv.ItemFromMesh(scan_mesh, scan_item); // get mesh item scan.MeshInstance(meshIter, morph_mesh); // We are getting the item position, so that we can compare vert pos in world space, which the lasso falloff seems to need. CLxUser_ChannelRead read; mesh_locator.set(scan_item); scan_item.GetContext(scene); if (!scene.test()) { return; } scene.GetChannels(read, time); CLxUser_ItemGraph graph; scene.GetGraph(LXsGRAPH_DEFORMERS, graph); unsigned int dfrm_count_fwd, dfrm_count_rev = 0; graph.FwdCount(scan_item, &dfrm_count_fwd); graph.RevCount(scan_item, &dfrm_count_rev); if (dfrm_count_fwd > 0 || dfrm_count_rev > 0) { if (viewevent->type == LXi_VIEWTYPE_3D) { // Todo: Presumably I can get the view from the viewevent somehow? CLxUser_View3DportService srv_vp; int idxVP = srv_vp.Current(); CLxUser_View3D view; srv_vp.View(idxVP, view); // if we have deformers on, we want the deformer mesh, instead of the edit mesh. LxResult deformers = view.Deformers(); if (deformers == LXe_TRUE) { // Get deformed version of the mesh. CLxUser_MeshFilter mesh_filter; CLxUser_MeshFilterIdent meshIdent_filter; read.Object(scan_item, LXsICHAN_MESH_MESH, mesh_filter); const char* ident = NULL; scan_item.Ident(&ident); mesh_filter.GetMesh(deform_mesh); if (deform_mesh.test()) { bUseDeformedMesh = true; scan_mesh = deform_mesh; } } } } if (!bUseDeformedMesh) { // we have no deformers, or they are off, so now we want to see if we have a morph map selected LXtID4 morphType = LXi_VMAP_MORPH; CLxUser_VMapPacketTranslation vmap_pkt_trans; void* pkt; vmap_pkt_trans.autoInit(); unsigned vmapCount = srv_sel.Count(vmapType); if (vmapCount > 0) { for (unsigned vmapIter = 0; vmapIter < vmapCount; vmapIter++) { pkt = srv_sel.ByIndex(vmapType, vmapIter); LXtID4 outVmapType; vmap_pkt_trans.Type(pkt, &outVmapType); if (outVmapType == morphType) { if (morph_mesh.test()) { scan_mesh = morph_mesh; } break; } } } }
Raycasting for tools from screen
CLxUser_VectorStack vector_stack (tool_vector); if (! vector_stack.test ()) { return LXe_FALSE; } // // 1. Using CLxUser_Raycast // CLxUser_RaycastPacket raycast_packet {}; if (! vector_stack.ReadObject (raycast_packet_offset_, raycast_packet)) { return LXe_FALSE; } auto screen_event = static_cast<LXpToolScreenEvent*>(vector_stack.Read (screen_event_packet_offset_)); if (! screen_event) { return LXe_FALSE; } LXtHitPolygon hit_polygon {}; raycast_packet.HitPolygon (vector_stack, LXf_LAYER_ACTIVE, screen_event->fcx, screen_event->fcy, &hit_polygon); // // 2. Using LXpToolHitEvent // auto hit_event = static_cast<LXpToolHitEvent*>(vector_stack.Read (hitevent_packet_offset_)); if (! hit_event) { return LXe_FALSE; } if (! hit_event->hit.pol) { return LXe_FALSE; } // // 3. Using CLxUser_View3D and CLxUser_Surface(not shown; must account for item transforms) // I don't use modo's macro maths in practice. // CLxUser_View3DportService view_service {}; const int view_index_current = view_service.Current (); CLxUser_View3D view {}; view_service.View (view_index_current, view); if (! view.test ()) { return LXe_FALSE; } auto screen_event = static_cast<LXpToolScreenEvent*>(vector_stack.Read (screen_event_packet_offset_)); if (! screen_event) { return LXe_FALSE; } const int pos_flags {0}; // alternatives: LXi_VPTO3D_SNAP; LXi_VPTO3D_WORK LXtVector point_from_screen {}; if (LXx_FAIL (view.To3D (screen_event->fcx, screen_event->fcy, point_from_screen, pos_flags))) { return LXe_FALSE; } LXtVector ray_direction {}; const double dist_to_point_from_ray_origin = view.EyeVector (point_from_screen, ray_direction); LXtVector ray_origin {}; LXx_VCPY (ray_origin, point_from_screen); LXx_VADDS (ray_origin, ray_direction, dist_to_point_from_ray_origin * -1.0); // pass ray to function that uses CLxUser_Surface::RayCast