ToolPlugin Problems
-
Hello!
I used utils.GeRayCollider in the ToolData.MouseInput() and ToolData.Draw() functions.
When the specified object is a high poly object then the scene will be calculated very slowly.
I don't know what causes this. Is there any way to optimize the codes?This is my code:
def UnderCursor(self,doc,bd,mx,my,plane): """ doc = Current document; bd = Current BaseDraw mx = mouseX my = mouseY plane = The object to check for intersections. """ pos = bd.SW(c4d.Vector(mx,my,0.1)) #screen to world conversion cam_pos = bd.GetSceneCamera(doc).GetAbsPos() pmg = plane.GetMg() pOlocal = cam_pos * ~pmg p1local = pos * ~pmg ldir = p1local-pOlocal collider = c4d.utils.GeRayCollider() collider.Init(plane,False) length = 2147483647 direction = -(cam_pos - pos).GetNormalized() did_intersect = collider.Intersect(pOlocal, ldir, length) if did_intersect: p = collider.GetNearestIntersection()['hitpos'] nrm = collider.GetNearestIntersection()['f_normal'] dst = collider.GetNearestIntersection()['distance'] mg = plane.GetMg() position = mg.Mul(p) return position,nrm,dst def MouseInput(self, doc, data, bd, win, msg): mx = msg[c4d.BFM_INPUT_X] my = msg[c4d.BFM_INPUT_Y] device = 0 if msg[c4d.BFM_INPUT_CHANNEL]==c4d.BFM_INPUT_MOUSELEFT: device = c4d.KEY_MLEFT elif msg[c4d.BFM_INPUT_CHANNEL]==c4d.BFM_INPUT_MOUSERIGHT: device = c4d.KEY_MRIGHT else: return True plane = doc.SearchObject("plane") c4d.DrawViews(c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_ANIMATION) dx = 0.0 dy = 0.0 win.MouseDragStart(button=device, mx=int(mx), my=int(my), flags=c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE|c4d.MOUSEDRAGFLAGS_NOMOVE) result, dx, dy, channel = win.MouseDrag() while result==c4d.MOUSEDRAGRESULT_CONTINUE: mx += dx my += dy position = self.UnderCursor(doc,bd,mx,my,plane)[0] c4d.DrawViews(c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_ANIMATION) result, dx, dy, channel = win.MouseDrag() if win.MouseDragEnd()==c4d.MOUSEDRAGRESULT_ESCAPE: doc.DoUndo(True) return True def Draw(self, doc, data, bd, bh, bt, flags): bd.SetMatrix_Matrix(None, c4d.Matrix()) bc = c4d.BaseContainer() gui.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, bc) mouse_x=bc.GetInt32(c4d.BFM_INPUT_X) mouse_y=bc.GetInt32(c4d.BFM_INPUT_Y) # Convert MouseCoordinates to Viewport Coordinates win= bd.GetEditorWindow() Editor_x, Editor_y = win.Global2Local() mx = mouse_x-abs(Editor_x) my = mouse_y-abs(Editor_y) bd.SetPen(c4d.Vector(1)) p = self.GetObj()[1] obj = self.GetObj()[0] dst = self.UnderCursor(doc,bd,mx,my,p)[2] off = self.UnderCursor(doc,bd,mx,my,p)[0] size = dst*0.005 nrm = self.UnderCursor(doc,bd,mx,my,p)[1].GetNormalized() nrm_hpb = c4d.utils.VectorToHPB(nrm) rm = c4d.utils.HPBToMatrix(nrm_hpb) v1 = rm.v1*size v2 = rm.v2*size v3 = rm.v3*size mat = c4d.Matrix(off,v1,v2,v3) bd.DrawCircle(mat)
low poly fast;
high poly slow;
-
You are initialising the GeRayCollider every time you move your mouse. This rebuilds it every single time you move. Try moving the initialisation out of the UnderCursor method.
First try making the GeRayCollider a local variable of your tool and initialise it when you mouse click on the surface the first time. Then once you have that working look at detecting when the dirty flag changes and then you can initialize it again only when it is marked as dirty. Once you have that going then change it to doing this check when you activate your tool as well. Then update your code to perhaps work on all selected objects.
Hope that helps!
Kent -
@kbar
First of all, thank you for your reply.
but I still don't quite understand, because I think if only after the mouse click to initialize, it seems that you can't Draw the circle in the viewport, because the ToolData.Draw() function needs to keep drawing the circle.
Could you can give me an example? -
I was only suggesting small incremental steps to help you solve your problem. First step is to refactor your code so that the GeRayCollider is not being initialised every time you move your mouse. So the click to initialize is not your final end solution. Just a step to get you started to show you that the slow down is with the call to Init and that you need to find a place to initialize that only when you absolutely need to. You can still access it in the UnderCursor method, after it has been initialized, allowing you to get draw your cursor. Just iterate through the problem one step at a time. I will let other devs post up a working solution. I only jump in here and answer when I can and don't have much time to code up anything unfortunately.
-
@kbar
I get you point now, I thought too much before.
Thank you!
Cheers~ -
@kbar
I've almost solved my problem!
Thank you again! -
@gheyret great to hear! Looking forward to seeing what it is you are creating.