Navigation

    • Register
    • Login
        No matches found
    • Search
    1. Home
    2. m_adam
    3. Posts
    • Profile
    • More
      • Following
      • Followers
      • Topics
      • Posts
      • Best
      • Groups

    Posts made by m_adam

    RE: Struggling on SetParameter for OLight

    Hi @mocoloco for such a parameter, using the bracket operator will be more easy.
    Find bellow the code within a Python Scripting tag, this work as expected.

    from typing import Optional
    import c4d
    
    doc: c4d.documents.BaseDocument # The document evaluating this tag
    op: c4d.BaseTag # The Python scripting tag
    flags: int # c4d.EXECUTIONFLAGS
    priority: int # c4d.EXECUTIONPRIORITY
    tp: Optional[c4d.modules.thinkingparticles.TP_MasterSystem] # Particle system
    thread: Optional[c4d.threading.BaseThread] # The thread executing this tag
    
    def main() -> None:
        obj = op.GetObject()
        previousLightColor = obj[c4d.LIGHT_COLOR]
        print(previousLightColor)
        newLightColor = c4d.Vector(0.0, 1.0, 1.9)
        obj[c4d.LIGHT_COLOR] = newLightColor
    

    But if you really want to use G/SetParameter you can do it with the code bellow. The issue with your code is that DESCFLAGS_GET_PARAM_GET mean to be used within the implementation to notify the system that this parameter have been already retrieved so no need to retrieve it again. So if you pass this flag as an input therefor you will have nothing in return.

        obj = op.GetObject()
        previousLightColor = obj.GetParameter(c4d.DescID(c4d.DescLevel(c4d.LIGHT_COLOR, c4d.DTYPE_VECTOR, 0)), c4d.DESCFLAGS_GET_NONE)
        print(previousLightColor)
        newLightColor = c4d.Vector(0.0, 0.0, 1.9)
        obj.SetParameter( c4d.DescID(c4d.DescLevel(c4d.LIGHT_COLOR, c4d.DTYPE_VECTOR, 0)), newLightColor, c4d.DESCFLAGS_SET_NONE )
    

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Set PYP file syntax highlighting in VS Code?

    Btw if you install the Cinema 4D Vs Code extension, pyp extension should be added as Python.

    posted in General Talk •
    RE: Set PYP file syntax highlighting in VS Code?

    How to make VS Code treat a file extensions as a certain language?

    Cheers,
    Maxime.

    posted in General Talk •
    RE: PyCharm Plugin on MacOs starts multiple Interpreter Instances

    Hi @FSS first of all happy new year ! 🙂

    And I'm glad that you found a solution however even if this is in the documentation we don't explicitly support PyCharm and only provide a dummy package to have autocompletion working with any Python instance. But C4dpy is not supported by all IDE and we can't provide any support there.

    If you want to have a better IDE workflow we released a plugin for Visual Studio Code, requiring a Cinema 4D plugin and a VS Code plugin.

    Finally I moved this topic to general talk as it this is nothing related to Cinema 4D API.

    Cheers,
    Maxime.

    posted in General Talk •
    RE: Switch render engine to Redshift (In memory)

    Hi you need to insert the video post as shown in the C++ manual - Redshift Renderer - Set Render Engine to Redshift, adapting it to Python should be pretty straightforward.

    Have a nice weekend.
    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Set the Preview of an Asset using an Image file.

    Ok nervermind it is possible to overwrite the ASSET_PREVIEWIMAGEURL in Python it's just that AssetDescription.StoreUrlMetaData, AssetDescription.StoreMetaData, AssetDescription.EraseMetaData are bugged in Python. So find bellow a workaround for that (it will be fixed in the next version and StoreUrlMetaData will work out of the box).

    import c4d
    import maxon
    
    # --- AssetDescriptionInterface monkey patching fix for AssetDescriptionInterface.StoreUrlMetaData() --------------------------
    @maxon.interface.MAXON_INTERFACE(maxon.consts.MAXON_REFERENCE_COPY_ON_WRITE, "net.maxon.interface.assetdescription")
    class AssetDescriptionInterface(maxon.AssetBaseInterface):
    
        @maxon.interface.MAXON_FUNCTION_EXTEND("net.maxon.interface.assetdescription.StoreUrlMetaData")
        def StoreUrlMetaData(self, metaId, source, kind):
            return self.GetRepository().StoreUrlMetaData(self, metaId, source, kind)
    
    maxon.AssetDescriptionInterface.StoreUrlMetaData = AssetDescriptionInterface.StoreUrlMetaData
    # --- AssetDescriptionInterface monkey patching fix for AssetDescriptionInterface.StoreUrlMetaData() --------------------------
    
    
    def main():
        repository = maxon.AssetInterface.GetUserPrefsRepository()
        assetId = maxon.Id("Id of the asset")
        lst = repository.FindAssets("net.maxon.node.assettype.nodetemplate", assetId, maxon.Id(),
                      maxon.ASSET_FIND_MODE.LATEST)
        assetDescription = lst[0]
    
        currentLanguage = maxon.Resource.GetCurrentLanguage()
        name = assetDescription.GetMetaString(maxon.OBJECT.BASE.NAME, currentLanguage)
        print(name)
    
        metadata = assetDescription.GetMetaData()
        imagepUrl = maxon.Url("C:/Users/m_adam/picture.png")
    
        # Stores the Url Meta Data, if there was no preview stored previously (aka the default png file for the given category) then it will be refreshed right away
        # Otherwise Cinema 4D need to be restarted
        maxon.AssetDescriptionInterface.StoreUrlMetaData = AssetDescriptionInterface.StoreUrlMetaData
        assetDescription.StoreUrlMetaData(maxon.ASSETMETADATA.ASSET_PREVIEWIMAGEURL, imagepUrl, maxon.AssetMetaData.KIND.PERSISTENT)
        
        # Turn off automatic preview
        metaProperties.Set(maxon.ASSET.METAPROPERTIES.BASE.AUTOMATICPREVIEW, False)
        assetDescription.StoreMetaData(maxon.ASSETMETADATA.MetaProperties, metaProperties, maxon.AssetMetaData.KIND.PERSISTENT)
        
    
    if __name__ == '__main__':
        main()
    

    However the limitation for InvalidateCache not being exposed is still there and as said will need a Cinema 4D update to make it work, so for the moment the only way to see new icons is to restart Cinema 4D.

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Set the Preview of an Asset using an Image file.

    I confirm that overwriting ASSET_PREVIEWIMAGEURL does not work in Python, and InvalidateCache is not exposed to the Python API and would need some internal change to the Cinema 4D code source to make it public so there is no possible workaround for you for the moment.

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Cinema 4D R2023 - c4d.plugins.RegisterObjectPlugin issue

    @baca said in Cinema 4D R2023 - c4d.plugins.RegisterObjectPlugin issue:

    Any suggestion how to properly handle that kind of issues --
    just catch exception and warn user using message box somehow?

    Correct you can catch the OsError and check if there is the word 50 in the exception message.

    Would it be reasonable to switch to NodeData from ObjectData --
    It depends of your plugin if this is at the end an ObjectData then it's irrelevant, if this is just an object that you store in a list in memory or in a custom GeListHead then NodeData is perfectly relevant.

    does RegisterNodePlugin has separate 50 plugins registrations?

    Yes each type have 50 plugins.

    What's the logic behind plugin initialization order -- alphabetical, date-based, random?

    Folders from g_additionalModulePath are iterated by alphabetical order and each files are then iterated by alphabetical order too.

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Cinema 4D R2023 - c4d.plugins.RegisterObjectPlugin issue

    As explained in the post I linked the limitation is about Python and for each plugin type you have a limitation of 50 (call to RegisterXXXPlugin), wherever they are installed.
    So you can have 50 ObjectData and 50 TagData. But you can't have 51 ObjectData (the number of C++ plugins does not count).
    And there is no workaround.

    The limitation is there since R11.
    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Cinema 4D R2023 - c4d.plugins.RegisterObjectPlugin issue

    Hi @baca there was always the limitation of 50 python plugins by plugin types. So the only solution is to remove some. This topic have been already discussed here.

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: CreateRepositoryFromUrl results in TypeError in 2023

    Hi @till-niese you are indeed right, the method was updated in C++ but not in Python although the dynamic handling of the python Maxon API make it possible to use it but the maxon.AssetRepositoryTypes.AssetDatabase was not exposed. I will fix it for the next version and properly make the BackgroundEntryTuple optional.

    In the meantime you can use the script bellow. GetRepositoryName also changed and is now taking 2 arguments.

    #coding: utf-8
    import c4d
    import maxon
    
    # The command id for the Asset Browser.
    CID_ASSET_BROWSER = 1054225
    
    
    @maxon.MAXON_REGISTRY("net.maxon.registry.assetrepositorytypes")
    class AssetRepositoryTypes(maxon.Registry):
        AssetDatabase = maxon.MAXON_DECLARATION("net.maxon.assets.repositorytype.database")
    
    
    def CreateRepositories():
        """Creates repositories for all user databases.
        Doing this is usually not necessary for performing light- to medium-sized asset operations, and
        the user preferences repository can then be used instead. Only when there is a substantial
        amount of assets that must be processed, a repository should be constructed to limit the
        search space for search operations. The method CreateRepositoryFromUrl() used in this example
        can also be used to create a repository and its underlying database from scratch when the
        provided URL points to location where no database has been established yet.
        """
        # Wait for all asset databases to be loaded, abort when this is not possible.
        if not maxon.AssetDataBasesInterface.WaitForDatabaseLoading():
            return RuntimeError("Could not load asset databases.")
    
        # Get the default language of Cinema 4D (en-US) for retrieving the repository names.
        defaultLanguage = maxon.Resource.GetDefaultLanguage()
    
        # Iterate over all currently mounted databases and create an asset repository for each of them.
        # Doing this is usually not necessary as user asset databases are automatically part of the
        # the user preferences repository which is easier to retrieve. Creating a repository for a
        # specific user asset database can be useful to speed up asset searches.
        for database in maxon.AssetDataBasesInterface.GetDatabases():
            # Create a unique identifier for the repository.
            rid = maxon.AssetInterface.MakeUuid(str(database._dbUrl), True)
    
            # Repositories can be composed out of other repositories which are called bases. In this
            # case no bases are used to construct the repository. But with bases a repository for all
            # user databases could be constructed for example.
            bases = maxon.BaseArray(maxon.AssetRepositoryRef)
    
            # Create a writable and persistent repository for the database URL. If #_dbUrl would point
            # to a location where no database has been yet stored, the necessary data would be created.
            assetDb = AssetRepositoryTypes.AssetDatabase
            assetDb = maxon.RegistryInterface.FindEntryValue(assetDb._registry, assetDb._ids)
    
            repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                rid, assetDb, bases, database._dbUrl, True, False, False, None)
            if not repository:
                raise RuntimeError("Repository construction failed.")
    
            # Access some properties of the newly created repository.
            repoId = repository.GetId()
            isWriteable = repository.IsWritable()
            name = repository.GetRepositoryName(defaultLanguage, True)
    
            print(f"{repository} ({name}): id - {repoId}, writeable: {isWriteable}")
    
    
    if __name__ == "__main__":
        CreateRepositories()
        c4d.EventAdd()
    

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: SplineMask Render Visibility Not Working

    Hi @InterfaceGuy, this forum is only about Cinema 4D Scripting and plugins, please reach the user support via the maxon website.

    Cheers,
    Maxime.

    posted in General Talk •
    RE: Editing RS Nodes with Python

    Hi @cgweasel hope you had a nice Christmas time 🙂

    Regarding your question, this has been answered in this post Change the ColorSpace of Redshift Texture Node?
    Then you can find example about nodes graph in our GitHub repository, And I would advice you to look at modify_port_value.

    I think with that you have all the information needed to make it work, if you struggle please let me know and I will be happy to help you. For the future please specify which node system you are using, since you mentioned GvNode I guessed that you used xpresso.

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Editing RS Nodes with Python

    Hi @cgweasel, to retrieve the selected node, like all BaseList2D (BaseOject,BaseTag,BaseMaterial, etc...) you can know there selection state with the method node.GetBit(c4d.BIT_ACTIVE).

    So find bellow the complete code to do what you want:

    import c4d
    
    
    def main():
        # Checks if selected material is valid
        mat = doc.GetActiveMaterial()
        if not mat or not mat.CheckType(1036224) :
            raise ValueError("There is no xpresso redshift material selected")
        
        # Retrieve the output nodes, which is also the first node in the node hierarchy. 
        # Therefor we can iterate them as usual BaseList2D
        node = mat[c4d.REDSHIFT_GRAPH_NODES]
        while node:
            # Check if this is a texture node and its selected
            if node[c4d.GV_REDSHIFT_SHADER_META_CLASSNAME] == 'TextureSampler' and node.GetBit(c4d.BIT_ACTIVE):
                # Set to Raw, to know the Id and the value I left click on the Filename parameter, User Interface -> Show SubChannel
                # Then I dragged the ColorSpace parameter to the python console
                node[c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0,c4d.REDSHIFT_FILE_COLORSPACE] = "RS_INPUT_COLORSPACE_RAW"
                
            node = node.GetNext()
    
        c4d.EventAdd()
    
    if __name__=='__main__':
        main()
    

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Detect Hirarchy Change in a tag

    Hi @cgweasel I forked your topic, in the future please create a new topic each time you have a question with a topic that is unrelated to the current discussion.

    With that said there is no 100% reliable way to do it, the best way would be to store the neighbor hierarchy (GetUp,GetPred,GetNext) and then add an execution step as Initial so within the Execute method you can check for these objects.

    Find bellow and example adapted from py-look-at-camera example. The important methods to check are:

    • __init__ to initialize the cache value
    • AddToExecution to add the Initial state execution
    • isHierarchyChanged to check if the cache changed
    • updateCachedHierarchy to update the cache
    • Execute with priority == c4d.EXECUTIONPRIORITY_INITIAL that will check the cache, and print a message when the hierarchy changed.
    import os
    import c4d
    
    # Be sure to use a unique ID obtained from www.plugincafe.com
    PLUGIN_ID = 1028284
    
    
    class LookAtCamera(c4d.plugins.TagData):
        """Look at Camera"""
    
        def __init__(self):
            self._up = None
            self._pred = None
            self._next = None
    
        def Init(self, node):
            """Called when Cinema 4D Initialize the TagData (used to define, default values).
    
            Args:
                node (c4d.GeListNode): The instance of the TagData.
    
            Returns:
                True on success, otherwise False.
            """
            self.InitAttr(node, bool, c4d.PYLOOKATCAMERA_PITCH)
            node[c4d.PYLOOKATCAMERA_PITCH] = True
    
            pd = c4d.PriorityData()
            if pd is None:
                raise MemoryError("Failed to create a priority data.")
    
            pd.SetPriorityValue(c4d.PRIORITYVALUE_CAMERADEPENDENT, True)
            node[c4d.EXPRESSION_PRIORITY] = pd
            return True
    
        def AddToExecution(self, tag, prioList):
            """Called By Cinema 4D to determine when in the Execution Pipeline the Execute method of this tag should be called.
    
            Args:
                tag (c4d.BaseTag): The instance of the TagData.
                prioList (c4d.plugins.PriorityList): The priority list to add your tag’s execution points to.
    
            Returns:
                True if the hierarchy changed, otherwise False.
            """
    
            # Retrieve the user defined priority
            storedPriority = tag[c4d.EXPRESSION_PRIORITY]
            storedPriorityValue = storedPriority.GetPriorityValue(c4d.PRIORITYVALUE_MODE) + \
                                  storedPriority.GetPriorityValue(c4d.PRIORITYVALUE_PRIORITY)
    
            # Add an execution during the Initial phase, this is when we will check for hierarchy change
            prioList.Add(tag, c4d.EXECUTIONPRIORITY_INITIAL, 0)
    
            # Add the user defined execution phase, therefor the Execute method will be called 2 times.
            prioList.Add(tag, storedPriorityValue, 0)
            return True
    
        def isHierarchyChanged(self, obj):
            """Check if any of the cached neighbor hierarchy is different from the actual one.
    
            Args:
                obj (c4d.BaseObject): The host object to compare the hierarchy from.
                
            Returns:
                True if the hierarchy changed, otherwise False.
            """
            up = obj.GetUp()
            if up != self._up:
                return True
    
            pred = obj.GetPred()
            if pred != self._pred:
                return True
    
            next = obj.GetNext()
            if next != self._next:
                return True
    
            return False
    
        def updateCachedHierarchy(self, obj):
            """Update the cached neighbor hierarchy.
    
            Args:
                obj (c4d.BaseObject): The host object to retrieve the hierarchy from.
            """
            self._up = obj.GetUp()
            self._pred = obj.GetPred()
            self._next = obj.GetNext()
    
        def Execute(self, tag, doc, op, bt, priority, flags):
            """Called by Cinema 4D at each Scene Execution, this is the place where calculation should take place.
    
            Args:
                tag (c4d.BaseTag): The instance of the TagData.
                doc (c4d.documents.BaseDocument): The host document of the tag's object.
                op (c4d.BaseObject): The host object of the tag.
                bt (c4d.threading.BaseThread): The Thread that execute the this TagData.
                priority (EXECUTIONPRIORITY): Information about the execution priority of this TagData.
                flags (EXECUTIONFLAGS): Information about when this TagData is executed.
            """
            if priority == c4d.EXECUTIONPRIORITY_INITIAL:
                if self.isHierarchyChanged(op):
                    self.updateCachedHierarchy(op)
                    print("Hierarchy Changed")
    
                    # We don't want to execute the logic of our tag during this phase except if the user asked for it
                    storedPriority = tag[c4d.EXPRESSION_PRIORITY]
                    storedPriorityValue = storedPriority.GetPriorityValue(c4d.PRIORITYVALUE_MODE) + \
                                          storedPriority.GetPriorityValue(c4d.PRIORITYVALUE_PRIORITY)
                    if storedPriorityValue != c4d.EXECUTIONPRIORITY_INITIAL:
                        return c4d.EXECUTIONRESULT_OK
    
            # Retrieves the current active base draw
            bd = doc.GetRenderBaseDraw()
            if bd is None:
                return c4d.EXECUTIONRESULT_OK
    
            # Retrieves the active camera
            cp = bd.GetSceneCamera(doc) if bd.GetSceneCamera(doc) is not None else bd.GetEditorCamera()
            if cp is None:
                return c4d.EXECUTIONRESULT_OK
    
            # Calculates the position to target
            local = cp.GetMg().off * (~(op.GetUpMg() * op.GetFrozenMln())) - op.GetRelPos()
    
            # Calculates the rotation to target
            hpb = c4d.utils.VectorToHPB(local)
    
            if not tag[c4d.PYLOOKATCAMERA_PITCH]:
                hpb.y = op.GetRelRot().y
            hpb.z = op.GetRelRot().z
    
            # Defines the rotation
            op.SetRelRot(hpb)
            
            return c4d.EXECUTIONRESULT_OK
    
    
    if __name__ == "__main__":
        # Retrieves the icon path
        directory, _ = os.path.split(__file__)
        fn = os.path.join(directory, "res", "tpylookatcamera.tif")
    
        # Creates a BaseBitmap
        bmp = c4d.bitmaps.BaseBitmap()
        if bmp is None:
            raise MemoryError("Failed to create a BaseBitmap.")
    
        # Init the BaseBitmap with the icon
        if bmp.InitWith(fn)[0] != c4d.IMAGERESULT_OK:
            raise MemoryError("Failed to initialize the BaseBitmap.")
    
        c4d.plugins.RegisterTagPlugin(id=PLUGIN_ID,
                                      str="Py - LookAtCamera",
                                      info=c4d.TAG_EXPRESSION | c4d.TAG_VISIBLE,
                                      g=LookAtCamera,
                                      description="Tpylookatcamera",
                                      icon=bmp)
    

    Side note, we will be away the 26th and 27th December, so don't be surprise by the delay if you have follow-up questions, for more information see No support on 26/12 and 27/12.

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    No support on 26/12 and 27/12

    Hello everybody,

    On the 26th and 27th of December, the SDK support team will be enjoying their Christmas vacations, which means that we will not be providing support services during these two days. We apologize for any inconvenience this may cause and wish you all the best.
    We’ll get back with standard support levels on Wednesday, December 28.

    We wish a Merry Christmas and a Happy New Year to everybody in this community. For us it was a pleasure to work with you and we are already looking forward to 2023 to see the cool stuff, you can come up with.

    See you in 2023,
    The MAXON SDK Team.

    posted in Maxon Announcements •
    RE: How to detectflip normals of object inwardoutward?

    Hi @FSS there is no such built-in function to detect this things, however there is the command MCOMMAND_ALIGNNORMALS that can be used to align the normals.

    settings = c4d.BaseContainer()  # Settings
    settings[c4d.MDATA_ALIGNNORMALS_USERNORMALS] =  True  # Align user normals.
    
    res = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_ALIGNNORMALS,
                                    list=[op],
                                    mode=c4d.MODELINGCOMMANDMODE_ALL,
                                    bc=settings,
                                    doc=doc)
    c4d.EventAdd()
    

    To know if a face is inwards or outwards you can cast a ray with GeRayCollider having origin in that vertex and direction of vertex normal. Find how many times ray intersects the current polygon object. If it intersects it even number of times ( including 0 ) - normal is facing outwards.

    Side note, we will be away the 26th and 27th December, so don't be surprise by the delay if you have follow-up questions, for more information see No support on 26/12 and 27/12.

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Assign Render Path

    Hi @wanderingstan first of all welcome in hte plugin cafe community. Please create your own topic, it's easier for us to track it. moreover you don't need to post on different topic the same subject. We usually answers within a day. Finally please read our support guideline.

    Regarding your question here it work as expected when I run the next code in the Python Console.
    doc.GetActiveRenderData().GetDataInstance().SetFilename(c4d.RDATA_PATH, r"test")

    One crucial information to share when you give us code sample is the context (the python console, a plugin ,the script manager, etc...) In your case at least the second one I expect it to run from the Python Console, so it should be fine.

    Regarding your issue I would say please try to restart Cinema 4D, while you tested you may have corrupted the c4d python module by writing something like c4d.RDATA_PATH = "my filename".

    Side note, we will be away the 26th and 27th December, so don't be surprise by the delay if you have follow-up questions, for more information see No support on 26/12 and 27/12.

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •
    RE: Load XGroup via Python

    Hi @cgweasel unfortunately this is not exposed, Xpresso is no longer developed except for critical issues, it is very likely that this will not be added to the API.

    Cheers,
    Maxime.

    posted in Cinema 4D SDK •