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;
    fast.gif

    high poly slow;
    slow.gif



  • 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.