animation management very optimized

i had make a system that basically replace the action as a shadow.
ie, very shortly the actions continue to update all layer, and all frames, but the bones are update only if the armature is visible .

i have used 2 check :
distance to camera(is actually at 50mt) and sphereinsideFrustum(5.0 mt)
to me seem particularly useful if you have game with many characters (with relatively complex armature as humanoid)
the function for this check is out of class to make it more visible since the value can be too low, etc

that is the blend, switc the variable OPTIMIZED to 0/1 to witch mode, and see the differences.
press WSAD to move the camera

PS: the speed is tic-based actually anyway can be changed(just i fear that cost)
AAAAA.blend (121 KB)

that is the code:




















def INCAM(gob):
    #return False
    cam = gob.scene.active_camera
    if cam.getDistanceTo(gob) > 50:
        return False
    if cam.sphereInsideFrustum(gob.worldPosition, 5.0) is 2:
        return False
    return True




    










class Animator:
    def __init__(self, gob):
        self.gob = gob
        self.actions = {}
        for a in [a for a in gob.actuators if hasattr(a,"action")]:
            self.actions[a.name] = Animator.Action(self, gob, a.action, a.frameStart, a.frameEnd, a.blendIn, a.layer, {False:0, True:1}[bool(a.mode)])
        self.layers = {}
        self.incam = True
        
    def update(self):
        if not self.layers:
            return
        self.incam = self.gob["incam"] = INCAM(self.gob)
        
        
        d = self.layers
        for k in d.copy():
            if not d[k].is_running:
                d.pop(k)
                continue
            d[k].update()
        
    def play(self, name):
        a = self.actions[name] 
        if a.ly in self.layers:
            self.layers[a.ly].stop()
        self.layers[a.ly] = a
        a.play()
            
    def stop(self, name):
        self.actions[name].stop()
            
    def stop_all(self):
        for l in self.layers.values():
            l.stop()
        if [1 for n in range(8) if self.gob.isPlayingAction(n)]:
            print("BUG! in ", self.__class__.__name__, " ..def stop_all(self)..")
            print("layers actives:" [[n for n in range(8) if self.gob.isPlayingAction(n)]])


            
            


        


    class Action:
        def __init__(self, animator, gob, an, fs, fe, bi, ly, pm, sp=0.4):
            self.animator = animator
            self.gob = gob
            self.an = an
            self.fs = fs
            self.fr = fs
            self.fe = fe
            self.bi = bi
            self.ly = ly
            self.pm = pm
            self.sp = sp
            self.frame_mode = self.frame_mode_play if not pm else self.frame_mode_loop
            
            self.old_int = int(self.fs)
            self.is_running = False
            self.incam = False
        
        @property
        def incam(self):
            return self._incam


        @incam.setter
        def incam(self, incam):
            if incam:
                self.gob.playAction(self.an, 0.0, 99999999.0, layer=self.ly, speed=0.001)
                self.gob_mode = self.gob_mode_incam
            else:
                self.gob.stopAction(self.ly)
                self.gob_mode = self.gob_mode_outcam
            self._incam = incam
                
        def play(self):
            self.is_running = True
            if self.pm:
                self.fr = self.fs
            if self.animator.incam:
                self.incam = True
                self.gob.playAction(self.an, self.fs,self.fe,blendin=self.bi, layer=self.ly, play_mode=self.pm, speed=0.4)


                
        def stop(self):
            self.is_running = False
            self.gob.stopAction(self.ly)
        
        def update(self):
            gobincam = self.animator.incam  
            if self.incam != gobincam:
                self.incam = gobincam




                    
            self.frame_mode()
            self.gob_mode()
            
            fr_int = int(self.fr)
            if fr_int != self.old_int:
                self.old_int = fr_int
            
            
        def frame_mode_play(self):
            self.fr += self.sp
            if self.fr > self.fe:
                self.stop()
        
        def frame_mode_loop(self):
            self.fr += self.sp
            if self.fr > self.fe:
                self.fr = self.fs
                
        def gob_mode_incam(self):
            self.gob.setActionFrame(self.fr, self.ly)
            
        def gob_mode_outcam(self):
            pass



Interesting idea, I’ll have to make something similar myself. It’s such a waste to process animations for objects off screen and animations are one of the biggest bottlenecks in game right now.

yes, also if the more recurrent bottleneck is ever the rasterizer, it is simple to “adjust” with few clicks (ie removing lights or other eye candy stuff)

while the animations require much more work (afaik)
and is frequently the bottleneck

PS: anyway that system work only for armature that has not physic object parented or that has some task matter (since as the bone is stopped is stopped also the object attached)

…added the code to run frame time-based (framerate fix at 24.0) , plus priority of animation and layer_wheigt…all seem working correctly but not tested yet on a “normal game” , it need to be fast, but also overall simple to use! :wink:

Just a note about this, removing lights if you have a lot of them don’t actually decrease the time needed to render the graphics.

The way it’s set up in the engine, the shaders are compiled to take every light in the scene into account from the get-go even after the object is deleted, the way to resolve this would be actual source changes that either recompile the GLSL for every light added or removed or intelligently add or remove instructions from the program.

Ace Dragon

i mean remove lights ,brutally in the UI :smiley:

i know that add or remove new light obj in runtime not change absolutely NOTHING O.O (better so, “move” the current light present, rather than add/remove)
(but i was not sure if is a problem of PC/graphyc card/driver …or current behaviour of blender)

if is not wasting slow, will be better recompile something

Could you run this like my list based alpha manager?

so one script does all this that is much smaller?

always-------------(if in futurism add to list and set timer)

if timer = 0 remove from list?

Attachments

AlphaLogicWithRecast.blend (495 KB)