node based incremental cond scheduling

This commit is contained in:
David
2023-12-06 22:45:59 -08:00
parent 3a14cea15e
commit c2873b2abf
2 changed files with 186 additions and 0 deletions
+4
View File
@@ -2,13 +2,17 @@
from .core import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
from .debug import NODE_CLASS_MAPPINGS as ncm0, NODE_DISPLAY_NAME_MAPPINGS as ndnm0
from .entangled import NODE_CLASS_MAPPINGS as ncm1, NODE_DISPLAY_NAME_MAPPINGS as ndnm1
from .schedule import NODE_CLASS_MAPPINGS as ncm2, NODE_DISPLAY_NAME_MAPPINGS as ndnm2
# there's probably a cleaner, more-dummy-proof way to do this.
# feels like an accident waiting to happen. low risk though.
NODE_CLASS_MAPPINGS.update(ncm0)
NODE_CLASS_MAPPINGS.update(ncm1)
NODE_CLASS_MAPPINGS.update(ncm2)
NODE_DISPLAY_NAME_MAPPINGS.update(ndnm0)
NODE_DISPLAY_NAME_MAPPINGS.update(ndnm1)
NODE_DISPLAY_NAME_MAPPINGS.update(ndnm2)
__all__ =["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
+182
View File
@@ -0,0 +1,182 @@
import keyframed as kf
from functools import total_ordering
from sortedcontainers import SortedDict, SortedList
from .core import CATEGORY as RootCategory
CATEGORY=RootCategory + "/schedule"
@total_ordering
class ScheduleKeyframe(kf.Keyframe):
def __lt__(self, other):
return self.t < other
def update_schedule(schedule, keyframe):
bl_idx = schedule.bisect_left(keyframe.t)
try:
if schedule[bl_idx].t == keyframe.t:
#del schedule[bl_idx]
schedule.pop(bl_idx)
except IndexError:
pass
schedule.add(keyframe)
return schedule
# schedule = SortedList()
# x0 = ScheduleKeyframe(t=0, value="a")
# x1 = ScheduleKeyframe(t=5, value="b")
# x2 = ScheduleKeyframe(t=5, value="c")
# x3 = ScheduleKeyframe(t=6, value="d")
# schedule = update_schedule(schedule, x0)
# schedule = update_schedule(schedule, x3) #
# schedule = update_schedule(schedule, x2)
# schedule = update_schedule(schedule, x1)
# schedule
###################################################################################
class KfKeyframedCondition:
"""
Attaches a condition to a keyframe
"""
CATEGORY=CATEGORY
FUNCTION = 'main'
RETURN_TYPES = ("KEYFRAMED_CONDITION",)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"conditioning": ("CONDITIONING", {}),
"time": ("FLOAT", {"default": 0}),
"weight": ("FLOAT", {"default": 1}), # maybe i should hide this attribute
"interpolation_method": (list(kf.interpolation.INTERPOLATORS.keys()),),
},
}
def main(self, conditioning, time, weight, interpolation_method):
keyframe = kf.Keyframe(t=time, value=weight, interpolation_method=interpolation_method)
return (keyframe, conditioning)
class KfSetKeyframe:
CATEGORY=CATEGORY
FUNCTION = 'main'
RETURN_TYPES = ("SCHEDULE",)
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"keyframed_condition": ("KEYFRAMED_CONDITION", {}),
},
"optional": {
"schedule": ("SCHEDULE", {}),
}
}
def main(keyframed_condition, schedule=None):
#keyframe, kf_condition = keyframed_condition
if schedule is None:
schedule = SortedDict
schedule = update_schedule(schedule, keyframed_condition)
return (schedule,)
class KfGetScheduleConditionAtTime:
CATEGORY=CATEGORY
FUNCTION = 'main'
RETURN_TYPES = ("CONDITIONING",)
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"schedule": ("SCHEDULE",{}),
"time": ("FLOAT",{}),
}
}
def main(self, schedule, time):
bl_idx = schedule.bisect_left(time)
left_kf, left_cond = schedule[bl_idx]
if left_kf.t == time: # hit time exactly, return
return (left_kf, left_cond)
if bl_idx == len(schedule): # there's nothing to our right, return
return (left_kf, left_cond)
right_kf, right_cond = schedule[bl_idx+1]
start, end = left_kf.t, right_kf.t
interval_length = end - start
elapsed = time-start
perc_complete = elapsed / interval_length
# TODO: use interpolation method on keyframe to compute transition weight
# For now, simple lerp
lerped_cond = perc_complete * right_cond + (1-perc_complete)*left_cond
# TODO: we could also interpolate and return an associated weight
return (lerped_cond,)
NODE_CLASS_MAPPINGS = {
"KfKeyframedCondition": KfKeyframedCondition,
"KfSetKeyframe": KfSetKeyframe,
"KfGetScheduleConditionAtTime": KfGetScheduleConditionAtTime,
}
NODE_DISPLAY_NAME_MAPPINGS = {}
###################################################################################
# class KfSetKeyframe:
# CATEGORY=CATEGORY
# FUNCTION = 'main'
# RETURN_TYPES = ("SCHEDULE",)
# @classmethod
# def INPUT_TYPES(cls):
# return {
# "required": {
# "keyframed_condition": ("KEYFRAMED_CONDITION", {}),
# },
# "optional": {
# "schedule": ("SCHEDULE", {}),
# }
# }
# def main(keyframed_condition, schedule=None):
# keyframe, kf_condition = keyframed_condition
# if schedule is None:
# schedule = SortedDict
# schedule[keyframe.t] = keyframed_condition
# return (schedule,)
# class KfGetScheduleConditionAtTime:
# CATEGORY=CATEGORY
# FUNCTION = 'main'
# RETURN_TYPES = ("KEYFRAME",)
# @classmethod
# def INPUT_TYPES(cls):
# return {
# "required": {
# "schedule": ("SCHEDULE",{}),
# "time": ("FLOAT",{}),
# }
# }
# def main(self, schedule, time):
# # right_index = self._data.bisect_right(k)
# # left_index = right_index - 1
# # if right_index > 0:
# # _, left_value = self._data.peekitem(left_index)
# # else: