Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login
    1. Maxon Developers Forum
    2. GillesKontrol
    3. Topics
    G
    • Profile
    • Following 0
    • Followers 0
    • Topics 5
    • Posts 11
    • Best 0
    • Controversial 0
    • Groups 0

    Topics created by GillesKontrol

    • G

      Merging all polygon selectiontags per material on an object

      Cinema 4D SDK
      • python 2024 windows • • GillesKontrol
      2
      0
      Votes
      2
      Posts
      1.1k
      Views

      ferdinandF

      Hello @GillesKontrol,

      Thank you for reaching out to us. Jesus Christ, that is a lot of tags! While we do have quite a few topics on selections here on the forum, we have no dedicated Python code examples for selections on GitHub (we probably should change that).

      Selections are merged with BaseSelect.Merge. But there are some hoops to jump through here, which is why I have written a code example. Although my example is probably pretty close to what you want, I must remind you that we do not provide solutions in the SDK group. Any modification or improvement must be done by yourself.

      You should also show your code in the future, no matter how little your progress has been.

      Cheers,
      Ferdinand

      Scene: select.c4d
      Before:
      15ec7661-afbb-4fe0-889c-dd5ee6d3622b-image.png
      After:
      cb1ed039-3e64-4da1-8e01-653ac47dc953-image.png

      Code:

      """Consolidates material assignments on all selected objects. Run with at least one object selected. The script will merge all texture tags using a restriction, i.e., a selection tag, that reference the same material. The operation will be wrapped into one undo item. Note: As always, the SDK group does not provide finished solutions. If you want things to be changed, that would be up to you. Here are some short-comings. * I did not deal with the case that there is a material M referenced on an object both as a texture tag with and without a restriction. Does not make too much sense but I ignored it. * I also ignored differences in projections. The script assumes that all material assignments are just unmodified UVW projections. * Finally, I determine the "sameness" of materials by identity and not by (quasi)-equality. When there are two absolutely identical materials in a scene, or two materials which are only differentiated by their name, they and their tags will not be merged. """ import c4d import mxutils import time doc: c4d.documents.BaseDocument # The active document. def ConsolidateMaterialsOnObject(op: c4d.BaseObject) -> None: """Consolidates the texture tags and selection tags used by them on #op by reference of material. Note: In the API material tags are called texture tags. """ # The first thing we do, is build a map where we associate materials assigned to #op with the # texture tags of #op assigning them. I.e., we collect the texture tags which should be # consolidated as they are assigning the same material. # # NOTE: We use here a 2023.2 feature, C4DAtom.__hash__, to insert the materials as keys into the # dict. In earlier versions we would have to use node UUIDs for that. groups: dict[c4d.BaseMaterial, list[c4d.TextureTag]] = {} # Iterate over all texture tags in #op and store them under the material they assign. for tag in [t for t in op.GetTags() if t.CheckType(c4d.Ttexture)]: material: c4d.BaseMaterial = tag[c4d.TEXTURETAG_MATERIAL] groups[material] = groups.get(material, []) + [tag] # Now we iterate over our build mappings as pairs of a material and the texture tags which # assign it. for material, textureTags in groups.items(): # Step over materials which are assigned by less than two tags. if len(textureTags) < 2: continue # Now we pull all the selection tags of #op which are referenced in the texture tags. selectionTags: list[c4d.SelectionTag] = [] for tag in textureTags: # Since selection tags are referenced a bit weirdly as a string in texture tags, # we cannot just grab their base link and instead must search for them. restriction: str = tag[c4d.TEXTURETAG_RESTRICTION] candidates: list[c4d.SelectionTag] = [t for t in op.GetTags() if t.CheckType(c4d.Tpolygonselection) and t.GetName() == restriction] if len(candidates) != 1: raise RuntimeError( f"Found texture tag {tag} with ambiguous restriction '{restriction}'.") selectionTags.append(candidates[0]) # Now we have all the input data we need. The first thing we do is establish a unique name # for the new selection tag, the 'restriction' referenced in the texture tag, and then # create the selection tag. restriction: str = f"{material.GetName()}_{time.perf_counter_ns()}" selectionTag: c4d.SelectionTag = op.MakeTag(c4d.Tpolygonselection) selectionTag.SetName(restriction) doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, selectionTag) # Now we get the BaseSelect for our new selection tag and copy over all the selection states # of the selection tags we have collected. selection: c4d.BaseSelect = selectionTag.GetBaseSelect() res: bool = all([selection.Merge(t.GetBaseSelect()) for t in selectionTags]) if not res: raise RuntimeError(f"Copying a selection tag for {material} failed.") # We do not need the old selection and texture tags anymore and therefore remove them. for t in (selectionTags + textureTags): doc.AddUndo(c4d.UNDOTYPE_DELETE, t) t.Remove() # We create a new texture tag and reference the current material from the loop and our new # selection tag in it. textureTag: c4d.TextureTag = op.MakeTag(c4d.Ttexture) textureTag[c4d.TEXTURETAG_MATERIAL] = material textureTag[c4d.TEXTURETAG_RESTRICTION] = restriction doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, textureTag) def main() -> None: """ """ # Get all directly selected objects in the scene, bail when there is no selection. selection: list[c4d.BaseObject] = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE) if not selection: print ("no objects selected to consolidate selection tags for.") return # Wrapped in an undo, iterate over them and compact the material assignments on them. doc.StartUndo() for obj in doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN): ConsolidateMaterialsOnObject(obj) doc.EndUndo() # Push an update event. c4d.EventAdd() if __name__ == "__main__": main()
    • G

      How to use external libraries inside of a plugin

      Cinema 4D SDK
      • python • • GillesKontrol
      4
      0
      Votes
      4
      Posts
      794
      Views

      G

      Thankyou! Noted!

    • G

      Listening to the status of the Pictureviewer (like when Rendering Multiple Takes to Pictureviewer)

      Cinema 4D SDK
      • python project tool • • GillesKontrol
      5
      0
      Votes
      5
      Posts
      908
      Views

      J

      Hello @GillesKontrol ,

      without further questions or postings, we will consider this topic as solved by Friday, the 11th of august 2023 and flag it accordingly.

      Thank you for your understanding,
      Maxon SDK Group

    • G

      Loading in a framesequence to the pictureviewer (EXRs)

      Cinema 4D SDK
      • python • • GillesKontrol
      5
      0
      Votes
      5
      Posts
      891
      Views

      G

      Loud and clear! Thankyou!

    • G

      Websockets / Threading

      Cinema 4D SDK
      • python • • GillesKontrol
      3
      0
      Votes
      3
      Posts
      743
      Views

      ferdinandF

      Hello @gilleskontrol,

      welcome to the forum and thank you for reaching out to us.

      Websocket client in C4D - best practice for this?

      You must use a third party library, e.g., the popular websockets as our NetworkWebSocketConnectionInterface has not been ported to Python and CPython does not support the WebSocket protocol out of the box.

      Plugin_ID - why do I need to do this, how do I properly do this?

      You can get them here in the forum with the little plug icon at the top. See How to get Plugin IDs[URL-REMOVED] for details.

      If it won't work in the scriptmanager, (because scriptmanager will freeze up even with threading) how do I do it without the scriptmanager?

      The script manager is blocking by nature. It is not your thread which is blocking, but the fact that you have likely put some code into your script which wait for the spawned thread to end. Which will then run as all Script Manager scripts on the main thread therefore block it. You could technically omit waiting for your threads to end and therefore have a non-blocking script, but that would result in dangling and never ended threads which is a bad thing.

      When you launch your thread in a plugin, this problem can either persist or go away, depending on what you do. There is no general answer to that. Let's assume you have the method MyPlugin.Foo. When you spawn the thread T in Foo, you wait for T to end before you exit Foo, and Foo runs on the main thread, as for example CommandData.Execute, you will experience the same problem. What you can do is:

      Wait for a thread T to end from a function f which runs on the non-main thread S. Doing this makes rarely sense in Python but you would not block the main thread doing this. You check for being on the main thread c4d.threading.GeIsMainThread. The more common and sensible approach is to defer reacting to your thread having ended to other places. In a dialog or MessageData plugin this could be a timer to parodically check in Message for your threads having ended. For nodes you could simply make the thread send the node a message once it has ended.

      Your documentation could really benefit from some step by step examples as searching for things you don't know the names of or why you even need them is next to impossible.

      Hm, I agree that our documentation lacks an abstract subject-matter access which can make traversing its content over subjects something in between laborious and impossible. However, the solution to that would be subject indexing and not having a perfectly matching tutorial for every possible information need of users (although that is of course what all users want). In which area did you find step-by-step information to be lacking in your case?

      Cheers,
      Ferdinand

      [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.