Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
Dear community,
What is a good way to evaluate a parameter value at a given frame from a threaded context?
I need to get the value of a parameter at a given time within the ModifyObject() function of a class derived from ObjectData. I need to do this when using bucket rendering. The required time is stored in a BaseTime member. The solution I've found so far is to use ExecutePasses(bt, true, true, true, BUILDFLAGS::EXTERNALRENDERER). However, this causes issues because the ModifyObject() function is called again. Additionally, I would like to avoid calculating the entire scene again. Is there a better way to do this?
ModifyObject()
ObjectData
BaseTime
ExecutePasses(bt, true, true, true, BUILDFLAGS::EXTERNALRENDERER)
On a related note, I get a debugbreak when calling ExecutePasses, is this due to the way I'm calling it?
ExecutePasses
Thank you for your attention, danniccs
Hello @danniccs,
thank you for reaching out to us. Your question is a bit ambiguous. You do not mention if the parameter you want to retrieve the value for is animated or not.
CKey
To get a better answer, I would recommend posting executable code and providing more information on the scope of parameter values you want to evaluate.
Cheers, Ferdinand
Hi @ferdinand, thanks a lot for the answer.
The parameter I am trying to evaluate is actually a BaseLink to a BaseObject representing a mesh. As such, I cannot use the CCurve::GetValue approach directly on the parameter. However, if possible I want to avoid running ExecutePass, since this would probably be quite slow.
BaseLink
BaseObject
CCurve::GetValue
ExecutePass
I realized I can solve my issue if I can get access to the world matrix of the mesh at the given time. Is there a way to get the interpolated world matrix at a specific time from a BaseObject? If not, can I get the CTrack associated with that world matrix? I could then interpolate the values between keys and use the resulting matrix. If neither of those is possible I will probably end up using ExecutePasses.
CTrack
Thanks again for the reply, Daniel
@danniccs said in Get parameter value at given time.:
The parameter I am trying to evaluate is actually a BaseLink to a BaseObject representing a mesh. As such, I cannot use the CCurve::GetValue approach directly on the parameter.
BaseLink is a discrete parameter, as you cannot interpolate between two links. Nevertheless, you should be able to find out what link is represented by a CCurve "curve", as you still have keys.
Here is some Python script that reads the currently linked camera from a (selected) stage object:
import c4d from c4d import gui def PrintLinkKey (currentTime, obj, parameterDesc): track = obj.FindCTrack(parameterDesc) if track == None: return curve = track.GetCurve() cat = track.GetTrackCategory() if cat != c4d.CTRACK_CATEGORY_DATA: return key = None currentKey = curve.FindKey(currentTime, c4d.FINDANIM_LEFT) if currentKey: key = currentKey['key'] else: currentKey = curve.FindKey(currentTime, c4d.FINDANIM_RIGHT) if currentKey: key = currentKey['key'] if key != None: data = key.GetGeData() print (data) def main(): if op == None : return descCamLink = c4d.DescID(c4d.DescLevel(c4d.STAGEOBJECT_CLINK, c4d.DTYPE_BASELISTLINK, 0)) PrintLinkKey (doc.GetTime(), op, descCamLink) if __name__=='__main__': main()
(Yes, I know you tagged C++ but you can use the same calls and logic - not going to create a full plugin for that...)
I might not have been clear in my previous post. The parameter is a BaseLink to a mesh, and that parameter is not animated. It should always be a link to the same BaseObject. The mesh itself has animated parameters, and I need to access the mesh object at a specified time t. At the very least, I need to know its position, rotation and scale values at t.
t
I have tried using CCurve.FindKey() and CKey.GetGeData()/CKey.GetValue() to get the mesh position at t, but the parameters in obase.h don't have tracks themselves. What I was wondering is if there is a way to get the world matrix of an object at time t without using ExecutePasses().
CCurve.FindKey()
CKey.GetGeData()
CKey.GetValue()
ExecutePasses()
Okay, you are right, that wasn't totally clear But anyway, in my understanding now: you have some undefined things that drive a value that does not have a track and therefore neither a curve nor keys, and you want the value itself. In my experience C4D will evaluate such a situation dynamically (unless cached) since there may be any kind of stuff used as driver: Python tags, XPresso tags, dynamics, particles, cloners, etc etc. So, unless you replicate the evaluation in your own code, you cannot access the result without actually allowing C4D to execute the evaluation.
Maybe Ferdinand will have a better idea once you provide the details he asked for, I am not yet seeing quite what you are going for.
Hi @danniccs,
So, effectively you do want to evaluate the global transform T of an object O at some arbitrary time t? I am afraid ExecutePasses is indeed the only viable solution here, as the transform of an object can be influenced indirectly by many things, as for example ancestor nodes, constraints, or simulations. There is no meaningful way to resolve this other than executing the passes.
This is also a case where you should not execute the passes for frame n, but all frames up to n, when you want to support simulations. In order to avoid extreme overhead by doing this over and over in ModifyObject, you should cache such information. In the simplest form this could be a button 'Build Time Cache' in the GUI of the object.
ModifyObject
All in all, this also sounds very much like a plugin that is in violation of design principles for ObjectData plugins. An object that can look omniscient into the past and future for any object in the scene, is in principle a quite expensive idea; it does not really matter that it is only the transform you want to know. This also could open a whole can of worms of feedback loops, depending on what you intend to do with that transform. When the vertices of object P rely on the transform T of object Q, and T relies in turn in some form on the vertices of P, you are going to have a problem, especially when you make this also time dependent.
I would also first check if there are simpler ways to achieve a similar effect. We cannot provide support on designing plugins, and we also do not known the greater context here, but I am sure that there is a simpler or at least more performant solution.
Hi @ferdinand and @Cairyn, thanks for the answers.
There may be a simpler way to achieve an effect similar to what we want (for example, by caching the world matrix at the time t) but I'm still thinking of alternate ways to be able to access the full mesh information at time t. Caching the full mesh is probably not a good option since we would have to update that cache every time the mesh is changed at any time before t (since this might change the mesh at t). A possible option is to restrict the usability a bit and always evaluate the mesh at time 0, I'm checking if this is something we can do.
Feedback loops could be an issue, but it should never happen that (using the example @ferdinand wrote) P relies on T and T also relies on P in this specific plugin. Also, t should always be a time before the current time, although that might not alleviate this particular problem.
In any case, I'm going to go ahead and mark this as solved, I think I got all the information I need to find a solution.
Thank you both very much for helping me out, Daniel