Start render in PictureViewer at the moment when a certain file has changed
-
Hi All,
First - i'm trying Python since two days - so my brain is pretty empty to this topic
I've a textfile *.txt where are some values stored.
Once a day one of the values is going to change.
the values are being imported in cinema 4d (via python-node in expresso) where they are mapped on some object parameters.Now my issue:
how can i get cinema 4d to start the render after the change in the values of the textfile is occured and the parameter has also done its correspondent change?two things are seeming to be a problem for me:
ยท how i get a continuous check for the textfile has changed?
ยท how i can start the CallCommand(12099) #for RenderInPictureviewer from this codeHope you can help me
Thanks a lot so farMatthias
-
Hi @daltonmonaie for a 2day programmer it's indeed a not easy task to do and you will need to train a bit or be ready to read/learn a lot before doing what you want.
May I ask you when should you monitor a file for a change? Only when a given scene is opened or as long as Cinema 4D is opened?
With that's said the C4D API does not provide anything for tracking file change, you have to do it yourself. You can find information about it https://blog.magrathealabs.com/filesystem-events-monitoring-with-python-9f5329b651c3
But you will need to get pip working in order to install watchdog module.
For that you should use c4dpy as explained in the c4dpy manuel.
And run the get-pip.py with c4dpy in order to install pip.
Then you will be able to writec4dpy -m pip install watchdog
so pip will download and install watchdog module so you will be able to import and use watchdog in your script.Then regarding how to trigger a render, the best way to either directly call the command with CallCommand or either run RenderDocument to render the document and then display the result into the PictureViewer.
But please consider to do it step by step and firstly get the file monitor to works then the render is the other part.
Cheers,
Maxime. -
Hi Maxime,
Thank you very much for taking your time answering my questions.
It was quiet a journey for me to install the watchdog module - but i've got it. Now it's there, inside my Cinema4D-Skript-Manager yay!
First, as you suggested, i'm just care about this watchdog.thingy and try to find out, how to use this. I think/hope the rest of my stuff is not that hard to do, because it seems much simpler to me. (In some pretty primitve skript-stuff i've got some experience. - so as i've got the text-import working in the Python-Expresso-Node.)
...but this watchdog.stuff seems to start a background-routine witch is not directly dependent to the Cinema4D-Environment. But i can start it from the Skript Manager and i can get the file-change event back into the skript - am i right there? ...or do i think wrong about?
I've found this manual for watchdog:
https://pythonhosted.org/watchdog/quickstart.html#a-simple-exampleIf you should have some more time: Could you give me a hint, how to implement this inside my c4d-script?
Once again: Thank you so far
Matthias -
The main issue is that a GvNode or a Script Manager is not persistent. Meaning, for example, the script manager.
Things only exist for the time you execute your command. At the moment your script finishes being executed everything is deleted this is due to the GIL.Same things for Xpresso Node (GvNode) the python code is only executed when the scene calls the execution of the Xpresso tag. So that's means again the data are somehow not persistent. A quick hack is to define a variable as global so you will be available to access this variable along with multiple executions of the Xpresso Tag see Python Global, Local and NonLocal variable.
So with that's said, an important thing to understand, Xpresso Tag execution and actually the whole scene execution (aka retrieving the cache of objects, executing tags, Xpresso Tag, Xpresso Node) is multithreaded. And as described in the
Threading Information, you can't do whatever you want in a thread and for example trigger a render have no sense. Here some background about what is a thread Thread Wikipedia.
So some stuffs are executed in parallel,in your case, it will make no sense to render the scene (from the execution of Xpresso Tag) if the cube geometry is not yet created.So that means we need a way to say once you have finished to build the scene, do something. Such things in Cinema 4D is usually done with Message and message stack. So typically in your Xpresso node you will put a MessageID on a stack of others Cinema 4D MessageId that will be executed at the end of the current scene execution (actually a scene execution is also launched from another message, so literally Cinema 4D has a list of operation to do in the main thread and it simply iterate over theses things to do).
Then you will create a MessageData plugin in order to receive this message, that will be executed in the main thread and there you will be able to render the document.
So long story short. Here is a scene file with a python node the code is inspired by this post in stackoverflow:
test.c4dAnd the plugin to create your own message that will render into the picture viewer. You have to put it into your plugin folder and name it "WhateverYouWant.pyp"
import c4d # Make sure to have an Unique ID from https://developers.maxon.net/forum/pid PLUGIN_ID = 1000001 class MyMessagePlugin(c4d.plugins.MessageData): def CoreMessage(self, id, msg) : if id == PLUGIN_ID: # Render the document if there is not actually another render running if not c4d.CheckIsRunning(c4d.CHECKISRUNNING_EXTERNALRENDERING): c4d.CallCommand(12099) return True if __name__ == "__main__": c4d.plugins.RegisterMessagePlugin(PLUGIN_ID, "MyMessagePlugin", 0, MyMessagePlugin())
I know it can be a bit hard for a beginner if you have any questions, please don't hesitate to ask.
Cheers,
Maxime -
Hi Maxime,
Wow! I'm completly blown away
What would be, one asks you to do a full job and not only to give a hint? World Peace?
So you've done pretty much the whole work for me - just out of kindness - Thank you so much!Yes, it works now exactly as i wanted - so i'm going to use my spared time to explore your solution and try to understand it more deeply than just seeing: "Ah, here i've to put my directory in and here i have to generate a text file with this text inside..."
Thanks again &
i wish you beautifull days in your life
when there should be anything i can do for you - just say it (most i can do is 3D-Graphics-Stuff)
for sure, when this project i'm working on is finaly done in every aspect i'll give you a message, so you can at least see the result. But that will take some months.Matthias
-
Hi Maxime - it's me once again
I've got a new (but i recon rather small) problem with my automated rendering-issue:
Inside an Expresso-tag i'm putting a string together to generate a specific path for the renderoutput.
This string should go to rDat[c4d.RDATA_PATH]. So far: no Problem.But it's only no Problem as long as i'm klicking in the timeline "one step forward".
When i'm doing this, the Path in the render settings is being updated.
Without that klick, the path-string stays the same.But i would need it updated automaticaly before the c4d.CallCommand(12099) starts the renderengine.
So i've tried to put a c4d.AddEvent(c4d.EVENT_FORCEREDRAW) in the Line before CallCommand(12099).There are no Errors - but also no Updates of the path...
Could you help me once again?
Greetings
Matthias -
Hello Matthias,
have you tried
c4d.C4DAtom.Message(c4d.MSG_CHANGE)
(see MSG flags for details) on yourrdata
node andc4d.EventAdd()
without any flags?Cheers
zipit -
Hi Zipit,
I've tried to place c4d.C4DAtom.Message(c4d.MSG_CHANGE) inside the Python-node where i try to set the render data. The node is going yellow and it's not working...
And yes, i've tried many ways to use c4d.EventAdd(). But while there is no error it also seem not to force an update of the renderdata. -
Hi,
I've tried to place c4d.C4DAtom.Message(c4d.MSG_CHANGE) inside the Python-node where i try to set the render data.
just for clarification: Your wording is a bit ambiguous to me regarding what you actually did. I was suggesting to invoke
c4d.C4DAtom.Message(c4d.MSG_CHANGE)
on yourRenderData
(RenderData
are derived from the atomic type) . Using the variable name you posted above, it would be something like this:rDat[c4d.RDATA_PATH] = my_path rDat.Message(c4d.MSG_CHANGE) c4d.EventAdd()
Updating nodes can be a bit tricky, you might have to try other message ids.
Cheers
zipit -
Hi @daltonmonaie, could you open a new topic for the last things regarding the update of the render path and post all your code if possible so like that we are sure we speak about the same things.
Cheers,
Maxime.I've created the new topic, please continue the discussion on this one: Update Render Path in an Xpresso Node.