AddEditNumberArrows Stops Working on Keyed objects
-
Hi,
I have
AddEditNumberArrows
element where it modifies an object at real time. The problem is it stops working on keyed objects.You can see the problem here:
https://www.dropbox.com/s/icqinbldrr0pn67/c4d216_addeditnumberarrows_stops_working_on_keyed_object.mp4?dl=0You can check the working code here:
import c4d import sys from c4d import bitmaps, documents, gui, plugins, threading, utils class MyDialog(c4d.gui.GeDialog): def __init__(self): doc = c4d.documents.GetActiveDocument() self.finger_B_01_L_con = doc.SearchObject('Cylinder') def CreateLayout(self): self.AddEditNumberArrows(id=404040, flags=c4d.BFH_LEFT, initw=100, inith=0) return True def InitValues(self): val = self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] self.SetDegree(404040, val, min=-180, max=180, step=1, tristate=False) return True def Message(self, msg, result): if msg.GetId() == c4d.BFM_ACTION: self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = self.GetFloat(404040) c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW | c4d.DRAWFLAGS_NO_THREAD | c4d.DRAWFLAGS_NO_REDUCTION | c4d.DRAWFLAGS_STATICBREAK) if msg.GetId() == c4d.BFM_INTERACTEND: self.InitValues() return True return c4d.gui.GeDialog.Message(self, msg, result) def Command (self, id, msg): return True if __name__ == "__main__": dlg = MyDialog() dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC)
-
Hello,
The animation track "erase" the value you are setting with your code, and that's normal.
you can probably deactivate the track while you are setting those keys.
I've picked the example from our git repo and tweak it a little bit.
import c4d #Welcome to the world of Python def DesactivateTracks(op): # Retrieves the tracks. tracks = op.GetCTracks() # Track list that we want to desactivate. trackListToDIsable = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE] for track in tracks: did = track.GetDescriptionID() # If the Parameter ID of the current CTracks is not on the trackListToDIsable we go to the next one. if not did[0].id in trackListToDIsable: continue track.SetBit(c4d.BIT_ANIM_OFF) def main(): obj = op.GetObject() if obj is None: raise ValueError("couldn't find the parent object") # Desactivates the tracks DesactivateTracks(obj) # Adds a rotation to the current one. rot = obj.GetRelRot() + c4d.Vector(0,.2,0) obj.SetRelRot(rot)
Cheers,
Manuel -
Hi @m_magalhaes
Thanks for the response.
I tried your code. It does work with the keyed object.
The problem is it overrides the previous values.
For instance,Frame 0: Value 0
. Then key somethin inFrame 12: Value 20
TheFrame 0
now hasValue 20
You can see the problem here:
https://www.dropbox.com/s/fn7b1ti7s4f8sk9/c4d216_addeditnumberarrows_stops_working_on_keyed_object02.mp4?dl=0I initially thought it was just
Activating
the track again. So I added that snippet but I still have the same problem. You can check the working code here:import c4d import sys from c4d import bitmaps, documents, gui, plugins, threading, utils class MyDialog(c4d.gui.GeDialog): def __init__(self): doc = c4d.documents.GetActiveDocument() self.finger_B_01_L_con = doc.SearchObject('Cylinder') def DesactivateTracks(self, op): # Retrieves the tracks. tracks = op.GetCTracks() # Track list that we want to desactivate. trackListToDIsable = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE] for track in tracks: did = track.GetDescriptionID() # If the Parameter ID of the current CTracks is not on the trackListToDIsable we go to the next one. if not did[0].id in trackListToDIsable: continue track.SetBit(c4d.BIT_ANIM_OFF) def ActivateTracks(self, op): # Retrieves the tracks. tracks = op.GetCTracks() # Track list that we want to desactivate. trackListToDIsable = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE] for track in tracks: did = track.GetDescriptionID() # If the Parameter ID of the current CTracks is not on the trackListToDIsable we go to the next one. if not did[0].id in trackListToDIsable: continue track.SetBit(c4d.BIT_ACTIVE) def CreateLayout(self): self.AddEditNumberArrows(id=404040, flags=c4d.BFH_LEFT, initw=100, inith=0) return True def InitValues(self): val = self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] self.SetDegree(404040, val, min=-180, max=180, step=1, tristate=False) return True def Message(self, msg, result): if msg.GetId() == c4d.BFM_ACTION: self.DesactivateTracks(self.finger_B_01_L_con) self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = self.GetFloat(404040) self.ActivateTracks(self.finger_B_01_L_con) c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW | c4d.DRAWFLAGS_NO_THREAD | c4d.DRAWFLAGS_NO_REDUCTION | c4d.DRAWFLAGS_STATICBREAK) if msg.GetId() == c4d.BFM_INTERACTEND: self.InitValues() return True return c4d.gui.GeDialog.Message(self, msg, result) def Command (self, id, msg): return True if __name__ == "__main__": dlg = MyDialog() dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC)
-
hello,
- opening a
DLG_TYPE_ASYNC
shouldn't be done in a script, you should create aCommandeDataPlugin
to store yourGeDialog
- your
ActivateTracks
isn't right,track.SetBit(c4d.BIT_ACTIVE)
is not the right command to "activate" a track. In that case, activate mean "selected" Have a look at this page for more information about BITs. Because you have set the bit toBIT_ANIM_OFF
you have to delete that bit using DelBit - In your vidéo, the yellow point mean "the field value is not the same as the track value" That also mean your track is not enabled.
Your script, as you are trying to do it, will never work. Disabling the track, change the value, reactivate the track = the object will go back to the defined value of the track. So you have never the change to create a keyframe with the right value.
Get a look at those examples if you want to add keys to your tracks (or manage tracks).
there's this one in particular that could help you.
But maybe you can have a look at TranslateDescID and we have an example here
This could allow to create a tool (instead of a gedialog) where you can route your description value to another parameter of another object. So the track and keys will not be created for your tools'parameters, but on your target's parameters. (maybe it's not clear)
Cheers,
Manuel.`
- opening a
-
@m_magalhaes
Thanks for the response.
So, I guess the workflow above would be to set the keys manually.Is there a way I can leverage the "Auto-Key" function?
I don't mind if its hack. I just want it to work and just want to animate for now.So basically, change the value and have the auto-key handled the keying much the same way when changing value using the default UI (i.e. not using script/plugin).
-
hello,
see this thread about using the autokey
Let me know if you have any questions.
Cheers,
Manuel -
Hi @m_magalhaes
Thanks for the response.
RE: Your script, as you are trying to do it, will never work. Disabling the track, change the value, reactivate the track
Oh okay. The "reactivation part" was just my hunch since you deactivate it first. I was thinking to reactivate it again.That said, I tried doing only
Disabling Track
andChange Value
but the result is still the same (i.e. It does work with the keyed object. The problem is it overrides the previous values. )RE: your ActivateTracks isn't right, track.SetBit(c4d.BIT_ACTIVE) is not the right command to "activate" a track.
So I guess this part is irrelevant since I don't need to activate/reactive it?RE: this thread about using the autokey
I tried the autokey with the
doc.AutoKey
and even with thedoc.Record
but I still get the same result ( .e. It does work with the keyed object. The problem is it overrides the previous values.)Here is the working code in a plugin form as you suggested:
It only works on the object named "Cylinder" same as before:import c4d import sys from c4d import bitmaps, documents, gui, plugins, threading, utils PLUGIN_ID = 18113999 # Just test ID. Not for production. class MyDialog(c4d.gui.GeDialog): def __init__(self): self.doc = c4d.documents.GetActiveDocument() self.finger_B_01_L_con = self.doc.SearchObject('Cylinder') def DesactivateTracks(self, op): # Retrieves the tracks. tracks = op.GetCTracks() # Track list that we want to desactivate. trackListToDIsable = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE] for track in tracks: did = track.GetDescriptionID() # If the Parameter ID of the current CTracks is not on the trackListToDIsable we go to the next one. if not did[0].id in trackListToDIsable: continue track.SetBit(c4d.BIT_ANIM_OFF) def ActivateTracks(self, op): # Retrieves the tracks. tracks = op.GetCTracks() # Track list that we want to desactivate. trackListToDIsable = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE] for track in tracks: did = track.GetDescriptionID() # If the Parameter ID of the current CTracks is not on the trackListToDIsable we go to the next one. if not did[0].id in trackListToDIsable: continue track.SetBit(c4d.BIT_ACTIVE) def CreateLayout(self): self.AddEditNumberArrows(id=404040, flags=c4d.BFH_LEFT, initw=100, inith=0) return True def InitValues(self): val = self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] self.SetDegree(404040, val, min=-180, max=180, step=1, tristate=False) return True def Message(self, msg, result): if msg.GetId() == c4d.BFM_ACTION: ID_AUTOKEYING_COMMAND = 12425 previousAutokeyEnableState = c4d.IsCommandChecked(ID_AUTOKEYING_COMMAND) if not previousAutokeyEnableState: c4d.CallCommand(ID_AUTOKEYING_COMMAND) self.DesactivateTracks(self.finger_B_01_L_con) self.doc.StartUndo() self.doc.AddUndo(c4d.UNDOTYPE_CHANGE, self.finger_B_01_L_con) undoObj = self.doc.GetUndoPtr() self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = self.GetFloat(404040) #self.ActivateTracks(self.finger_B_01_L_con) self.doc.AutoKey(self.finger_B_01_L_con, undoObj, False, True, True, True, True, True) self.doc.Record() c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW | c4d.DRAWFLAGS_NO_THREAD | c4d.DRAWFLAGS_NO_REDUCTION | c4d.DRAWFLAGS_STATICBREAK) self.doc.EndUndo() if not previousAutokeyEnableState: c4d.CallCommand(ID_AUTOKEYING_COMMAND) if msg.GetId() == c4d.BFM_INTERACTEND: self.InitValues() return True return c4d.gui.GeDialog.Message(self, msg, result) def Command (self, id, msg): return True class MyMenuPlugin(plugins.CommandData): dialog = None def Execute(self, doc): # create the dialog if self.dialog is None: self.dialog = MyDialog() return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=200, defaulth=150, xpos=-1, ypos=-1) def RestoreLayout(self, sec_ref): # manage the dialog if self.dialog is None: self.dialog = MyDialog() return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref) if __name__ == "__main__": okyn = plugins.RegisterCommandPlugin(PLUGIN_ID, "Key Objects Interactively",0, None, "Key Objects Interactively", MyMenuPlugin()) if (okyn): print "Key Objects Interactively"
-
@bentraje said in AddEditNumberArrows Stops Working on Keyed objects:
It does work with the keyed object. The problem is it overrides the previous values.)
sorry i wasn't clear with what i said (or i can't reproduce the issue) :
In your vidéo, the yellow point mean "the field value is not the same as the track value" That also mean your track is not enabled.
In our help you will find what colors mean and full circle or not.
the value of the parameter is -2° but the point is yellow and full, that mean the track have a key at that frame but the value isn't the same as the parameter.
Your track is deactivate. But the key value is still there
Cheers,
Manuel -
@m_magalhaes
Thanks for the response.
Can I clear the previous queries?
- So is it correct to
DeactiveTrack
,Change Value
and not Activate it again?
or Do I have toDeactiveTrack
,Change Value
andActivateTrack
? - I understand what
yellow circle
means which is my problem. I thought thedoc.AutoKey
ordoc.Record
will handle that, but it didn't.
Overall, I'm confused about the overall workflow.
So far what I understand is two methods:- Manually:
A) Deactivate Track
B) Change Value
C) Key Value
D) Activate Track - Automatically.
A) Change Value
B) Dodoc.Autokey
anddoc.Record
I just want the second want because it is easier. Is this possible?
- So is it correct to
-
hello,
With the second method (automatically) you will not be able to see the change while you are dragging the value of the parameter because the track will erase what you are doing.
I've modified a bit your code (specially now creating the key is on
Command
and not onMessage
).
I also added the CoreMessage function to react to a EVMSG_TIMECHANGEDWhat i'm doing,
disable the track (so we can have a feedback of the changes)
update the parameter
create a key (so we still have the feedback)
enable the track(as we have created a key, the object doesn't move)
I've also create a "FindCylinder" function so you can create the cylinder after you have launch your GeDialog. And it's easier (but maybe not optimized) to check if the cylinder exist or not.import c4d import sys from c4d import bitmaps, documents, gui, plugins, threading, utils PLUGIN_ID = 18113999 # Just test ID. Not for production. class MyDialog(c4d.gui.GeDialog): def __init__(self): self.tracklist = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE] self.finger_B_01_L_con = None def DesactivateTracks(self, op): ''' Disable a track if it is on the tracklist''' # Retrieves the tracks. tracks = op.GetCTracks() # For each track check if it's on the tracklist for track in tracks: did = track.GetDescriptionID() # If the Parameter ID of the current CTracks is not on the self.tracklist we go to the next one. if not did[0].id in self.tracklist: continue track.SetBit(c4d.BIT_ANIM_OFF) def ActivateTracks(self, op): ''' Enable on of the track in the tracklist if founded''' # Retrieves the tracks. tracks = op.GetCTracks() # For each track check if it's on the tracklist for track in tracks: did = track.GetDescriptionID() # If the Parameter ID of the current CTracks is not on the self.tracklist we go to the next one. if not did[0].id in self.tracklist: continue track.DelBit(c4d.BIT_ANIM_OFF) def FindCylinder(self, name): ''' function that will help to find an object in the document''' self.doc = c4d.documents.GetActiveDocument() self.finger_B_01_L_con = self.doc.SearchObject(name) return self.finger_B_01_L_con def CreateLayout(self): self.AddEditNumberArrows(id=404040, flags=c4d.BFH_LEFT, initw=100, inith=0) return True def InitValues(self): if self.FindCylinder('Cylinder') is None: return True val = self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] self.SetDegree(404040, val, min=-180, max=180, step=1, tristate=False) return True def Message(self, msg, result): if msg.GetId() == c4d.BFM_INTERACTEND: self.InitValues() return True return c4d.gui.GeDialog.Message(self, msg, result) def Command (self, id, msg): if id == 404040: if self.FindCylinder('Cylinder') is None: print "no object found" return True ID_AUTOKEYING_COMMAND = 12425 previousAutokeyEnableState = c4d.IsCommandChecked(ID_AUTOKEYING_COMMAND) if not previousAutokeyEnableState: c4d.CallCommand(ID_AUTOKEYING_COMMAND) self.DesactivateTracks(self.finger_B_01_L_con) self.doc.StartUndo() self.doc.AddUndo(c4d.UNDOTYPE_CHANGE, self.finger_B_01_L_con) undoObj = self.doc.GetUndoPtr() self.finger_B_01_L_con[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = self.GetFloat(404040) #self.ActivateTracks(self.finger_B_01_L_con) self.doc.AutoKey(self.finger_B_01_L_con, undoObj, False, True, True, True, True, True) self.doc.Record() c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW | c4d.DRAWFLAGS_NO_THREAD | c4d.DRAWFLAGS_NO_REDUCTION | c4d.DRAWFLAGS_STATICBREAK) self.ActivateTracks(self.finger_B_01_L_con) self.doc.EndUndo() if not previousAutokeyEnableState: c4d.CallCommand(ID_AUTOKEYING_COMMAND) return True def CoreMessage(self, id, msg): # react to the core message time changed so we can update the UI with the correct value. if id == c4d.EVMSG_TIMECHANGED: self.InitValues() return True class MyMenuPlugin(plugins.CommandData): dialog = None def Execute(self, doc): # create the dialog if self.dialog is None: self.dialog = MyDialog() return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=200, defaulth=150, xpos=-1, ypos=-1) def RestoreLayout(self, sec_ref): # manage the dialog if self.dialog is None: self.dialog = MyDialog() return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref) if __name__ == "__main__": okyn = plugins.RegisterCommandPlugin(PLUGIN_ID, "Key Objects Interactively",0, None, "Key Objects Interactively", MyMenuPlugin()) if (okyn): print "Key Objects Interactively"
cheers,
Manuel. -
Hi @m_magalhaes
Thanks for the update and sorry for the trouble.
I can confirm that it is working as expected.Thank you again.
-
hi,
no trouble at all, you are here to ask questions, we are here to answer.
Cheers,
Manuel.