• is it possible for me to create a script, outside of c4d

    python 2024 windows
    2
    1
    0 Votes
    2 Posts
    498 Views
    M
    Hi @pyxelrigger there is no real way to execute a script outside of Cinema 4D without Cinema 4D. The only option is to execute c4dpy which is a complete Cinema 4D instance run as a python interpreter. For more information about it, please read c4dpy manual. Note that you have the same limitation as a standalone Cinema 4D so you can't execute multiple c4dpy instance at the same time or they need to be in different folders. Except that note that tkinter does not come by default with Cinema 4D, so you will need to install manually and don't really officially support, so it may or may not works, but from our personal experience in the SDK team, it should work. Cheers, Maxime.
  • Particle modifier plugin type

    2024
    7
    0 Votes
    7 Posts
    1k Views
    ferdinandF
    Hey @spedler, only the simulation team can speak to the exact details here, but my guess for why it is how it is, is the pesky cpu-gpu upload penalty. If you would upload pre sampled data, or even worse sample on the CPU, this would really slow down any GPU advantage you have. I doubt that this is any different for the GPU part of Xparticles. One could think about plugin access for CPU-sims but most users are likely never going to use that if they can avoid it. The simulation device is set in the simulation scene and by default GPU. [image: 1713257356914-08c2f454-96fb-4d92-9adc-8247e47fc44f-image.png] The more realistic thing would be that we provide some compute shader like access. I could go here into the details of the new particles and the challenges of providing such compute shader access to them but that would be the famous "counting chickens before they hatch". Let's first see how many users and which user type (scripting technical artist vs. C++ development professional) wants a deeper API access for particles. Cheers, Ferdinand
  • 0 Votes
    2 Posts
    746 Views
    ferdinandF
    Hey @ThomasB, Thank you for reaching out to us. Without your code we cannot really help you, we are not the oracle of Delphi There are many things which could go wrong in your plugin. But in general what you are doing is correct; add a dummy point object with your snap points to your cache, when you want to introduce special snapping points for your custom generator object. Snapping onto the points of the returned geometry should work out of the box (but snapping sometimes struggles a bit with deep caches). There is however only limited support for adding special snapping points, as it is not really intended to add you own snap logic in that manner. The snapping module both in Python and C++ does not allow you to implement your own snapping logic, you can just read some data. You should also keep in mind that the snapping is an older part of Cinema 4D which has its flaws. You should check if your problem also does occur when you try to snap onto the converted cache of your object (current state to object). If that is the case, you know it is not something your plugin does, but simply the fact that the snapping struggles with that specific geometry/scenario. Cheers, Ferdinand
  • 0 Votes
    3 Posts
    685 Views
    pyxelriggerP
    Thanks, buddy! It worked. To be honest, I never really understood what Message(c4d.MSG_UPDATE) was all about, and now ExecutePasses is new to me
  • Copying/Pasting GvNodes?

    c++ 2023
    3
    0 Votes
    3 Posts
    666 Views
    F
    "PS: There are also the copy buffer methods on GvNodeMaster if you want to preserve connections, copy multiple nodes at once etc.:" -That looks like it might be exactly what I need! Thanks a lot!
  • How do I get the cache of a cloner in an ObjectData Plugin

    2023 2024 r23 r25 python
    4
    0 Votes
    4 Posts
    1k Views
    ferdinandF
    Good to hear!
  • Rendering debug UI in the viewport via plugin

    2024 c++ windows macos
    8
    0 Votes
    8 Posts
    2k Views
    C
    @ferdinand Thank you very much! I got the min and max distances also working with your input! I used the code example from the docs to traverse through the DeformCache and it worked instantly
  • Copy children to selection with GetClone()

    python 2024
    3
    0 Votes
    3 Posts
    758 Views
    John_DoJ
    Hi @ferdinand, thanks for the feedback, I've got it working with your suggestion. The method B was correct but the undo part was wrong ( the undo step was applied on the original objects instead of the new ones, thus leading to a mess when performing an undo). I also added the bit part to keep new objects folded in the OM. Here is the code : # CopyDeformers import c4d doc = c4d.documents.GetActiveDocument() def main(): doc.StartUndo() objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER) if len(objs) >= 2: # Get the last selected object active = objs.pop(-1) # Get the deformers deformers = [i for i in active.GetChildren()] # Copy deformers to selection if deformers: for o in objs: for d in deformers[::-1]: dcopy = d.GetClone(c4d.COPYFLAGS_NO_BITS) doc.InsertObject(dcopy, parent=o) doc.AddUndo(c4d.UNDOTYPE_NEW, dcopy) o.SetBit(c4d.BIT_MFOLD) doc.EndUndo() c4d.EventAdd() if __name__ == '__main__': main()
  • Create folder in Volume Builder

    windows python 2023
    3
    0 Votes
    3 Posts
    672 Views
    D
    hi @i_mazlov, thanks for the answer. good to know about this status / limitation. for my current case I found a solution without folders..
  • How to LoadDocument from string in memory? 🤔

    python
    3
    0 Votes
    3 Posts
    1k Views
    mikeudinM
    Cool! Thank you!
  • fieldlayer with variable tag

    windows python 2023
    2
    1
    0 Votes
    2 Posts
    526 Views
    D
    found the solution ... the corresponding type is called: FLweight
  • Plugins Search Path from Preferences

    python
    3
    0 Votes
    3 Posts
    771 Views
    merkvilsonM
    Thanks @ferdinand I wrote this little script for those who want to add one plugin path via the C4D script. I will update it later. It will NOT overwrite existing paths. Restart is required for instant result. import c4d import os import json def add_plugin_path(path, restart = False): if os.path.exists(path): new_path = path.replace("\\", "/") else: print("Path does not exists") return prefs_folder = c4d.storage.GeGetC4DPath(c4d.C4D_PATH_PREFS) prefs_path = os.path.dirname(prefs_folder) plugins_json_path = os.path.join(prefs_path, 'plugins.json') if os.path.exists(plugins_json_path): with open(plugins_json_path,'r',encoding="utf-8-sig") as plugins: plugins_json_raw = plugins.read() plugins_dict = json.loads(plugins_json_raw) content_dict = plugins_dict["content"]["_impl"]["_data"][1]["content"] # Check if the new path is already in Plugins Path for content_path in content_dict: if os.path.normpath(content_path["_0"]["_path"]) == os.path.normpath(new_path): print(f"'{new_path}' is already in Plugins Path.") return else: plugins_dict = { 'identification': 'plugins', 'content': { 'referenceDataType': 'net.maxon.interface.datadictionary-C', '_impl': { '_mode': 2, '_data': [ { 'dataType': 'net.maxon.datatype.id', 'content': 'searchPaths' }, { 'dataType': '(net.maxon.interface.url-C,bool)', 'isArray': True, 'content': []}]}}} # Create new path content new_content = { "_0": { "referenceIndex": len(plugins_dict["content"]["_impl"]["_data"][1]["content"]), "referenceDataType": "net.maxon.interface.url-C", "_scheme": "file", "_path": new_path, "_authority": {}, "_data": {} }, "_1": True } # Append the new path to the list of paths plugins_dict["content"]["_impl"]["_data"][1]["content"].append(new_content) # Convert the dictionary back to a JSON string updated_plugins_dict = json.dumps(plugins_dict, indent=4) # Write the updated dictionary back to a JSON file with open(plugins_json_path, 'w') as plugins_json: plugins_json.write(updated_plugins_dict) if restart: c4d.RestartMe() custom_path = r"/Path/To/Plugin/Directory/" add_plugin_path(path = custom_path, restart = False)
  • how to store/serialize custom data type?

    c++
    4
    0 Votes
    4 Posts
    855 Views
    ferdinandF
    Hey @aghiad322, as I said, classic API CustomDataType types (e.g., the "dots" example) realize their serialization via CustomDatatypeClass::Read and ::Write. The DotsDataClass example implements both methods to read and write the dots data. If you want things to be stored, e.g., your gradient, you will have to implement it there. E.g., it could look like this: Bool MyDataTypeClass::WriteData(const CustomDataType* t_d, HyperFile* hf) { // Cast the passed in data to your datatype. const MyDataType* const data = static_cast<const MyDataType*>(t_d); // Bail when #data is malformed, has no gradient. _gradient is a member of MyDataType and supposed // to be of type Gradient* just as in your case. if (!data || !data->_gradient) return false; // Wrap the dereferenced _gradient as a GeData instance. GeData geData; geData.SetCustomDataType(*data->_gradient); // Write your data into the hyper file and bail if it somehow fails. if (!hf->WriteGeData(geData)) return false; // Write other data members of your datatype. if (!hf->WriteInt32(data->_someInt32)) return false; if (!hf->WriteFloat(data->_someFloat)) return false; if (!hf->WriteBool(data->_someBool)) return false; return true; } Cheers, Ferdinand
  • 0 Votes
    2 Posts
    556 Views
    ferdinandF
    Hey @BretBays, Thank you for reaching out to us. You might want to have a look at the Python Libraries Manual. Since Cinema 4D 2024.0 there is also mxutils.LocalImportPath which automates injecting module paths and reloading such imported modules (I probably should update the Python libraries manual). The "flaw" of all these approaches is that while you still encrypt your plugins pyp file, the imported module(s) py file(s) will not and cannot be encrypted. You can either ship your common functions unencrypted or develop your plugin as a multi module solution (so that you do not have to replicate your code across plugins) and then package up the plugin into a singular file. There are some Python tools like pysconcat and pymerger which can help you with that. But you should be aware that these can fail when you have complex dependencies. You could also serve the py-cache of your modules, but that will not really stop anyone who wants to read your code. Cheers, Ferdinand
  • Sampling Redshift Materials

    2024 c++ macos
    3
    0 Votes
    3 Posts
    822 Views
    D
    Hi Ilia, At this point this seems a bit over my head, but it seems to be what I need, thanks! Dan
  • Clone orientation without a "Up Vector"

    windows c++ 2024
    8
    0 Votes
    8 Posts
    3k Views
    justinleducJ
    @ferdinand Oh wow! Thank you so much for letting me know about Keenan Crane, as I was not familiar with him. I am in awe of the exhaustive list of tools he and his lab have published. The Globally Optimal Direction Fields paper seems indeed to be exactly what I am looking for. I was also surprised to see that I had already skimmed the Youtube video of the paper back in December. Thank you so much @ferdinand for this invaluable piece of information. Time to dive in! Cheers!
  • 0 Votes
    6 Posts
    1k Views
    S
    Okay. I'll ask the support center
  • Encrypt .pyp file to .pypv with script or command line?

    2024 python
    4
    0 Votes
    4 Posts
    1k Views
    F
    Thank you, it works perfectly!
  • document bug | GeDialog.SetString flags mismatch

    python 2024
    2
    1
    0 Votes
    2 Posts
    426 Views
    ferdinandF
    Hey @JACK0319, Thank you for your issue report, I have fixed it and it will be shipped with the next release. Cheers, Ferdinand
  • Accessing Parameters of Filters in a Volume Builder

    windows python 2023
    3
    0 Votes
    3 Posts
    613 Views
    ferdinandF
    Hey @datamilch, Thank you for reaching out to us and answering your own question. In general we prefer it when topics do not get deleted, so that other users can benefit from a topic. You should also not be able to delete this topic anymore since more than three hours have passed since you posted and because your topic has replies. Cheers, Ferdinand