Navigation

    • Register
    • Login
    • Search
    1. Home
    2. till.niese
    3. Posts
    • Profile
    • More
      • Following
      • Followers
      • Topics
      • Posts
      • Best
      • Groups

    Posts made by till.niese

    RE: Control whether a redshift shader node port is collapsed or not.

    Hello @ferdinand

    Thank you for your detailed answer.

    What do you want to do with them?

    If we create a Standard Material Node, and connect Texture nodes to "Subsurface > Color" and "Subsurface > Weight" the resulting Node looks like this:

    1068a261-66d6-4787-a3ea-c2f5fb46e04c-grafik.png

    We however want that all ports that have a connection are visible. So that the node looks this way instead:
    e697500a-6536-4290-9ea2-d1df60f7b7ca-grafik.png

    That's the reason why we would like to control wheter the a layer like "Subsurface" is collapsed/closed or not.

    But if I understand this part of your answer correctly:

    That is not possible/intended just as for example you are not supposed to set directly the position of a node.

    it is at least not possible/intended to control those layers directly.

    Is there a way to in general tell a node - or the whole graph - that all connected ports should be shown, so that we have the desired result without controlling the layers manually?

    Best,
    Till Niese

    posted in Cinema 4D SDK •
    Control whether a redshift shader node port is collapsed or not.

    Hi,

    We create Redshift shader nodes programmatically in C++ and would like to control whether groups like Subsurface are collapsed or not:

    7a234e8c-36ac-4bfb-b9dc-d7ca2798af3c-image.png a605bd97-7e1f-4d77-9068-06709a956d08-image.png

    Setting up the node space, getting its graph, creating the nodes and their connections works fine.
    I however don't know how to find the groups like Base, Reflection, Subsurface, ... and how to set whether those are collapsed or not.

    Based on GraphModelInterface Class Reference I thought that Base, Reflection, Subsurface, ... might be NODE_KIND::INPORT with the other ports as children, however when I iterate over the ports of the node I can only find their child nodes.

    So for the node in the below reduced code example, how do I get e.g. the Subsurface "port-group" and how to I control whether it is collapsed or not?

    maxon::Id nodeSpaceID = maxon::Id("com.redshift3d.redshift4c4d.class.nodespace");
    const maxon::nodes::NodesGraphModelRef& graph = nodeMaterial->GetGraph(nodeSpaceID) iferr_return;
    
    maxon::GraphNode node = graph.AddChild(maxon::Id(), maxon::Id("com.redshift3d.redshift4c4d.nodes.core.standardmaterial"), maxon::DataDictionary()) iferr_return;
    
    

    Best
    Till Niese

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

    @m_adam Hi, this partially works for me.

    When I manually run your script for the assets we have already created, the preview images are set and displayed after a restart of Cinema 4D.

    However if I insert the code directly into our script, then sometimes one object has the preview image correctly set and displayed after a restart. But most of the time it is the preview image created by Cinema 4D itself, which is almost completely black.

    To clarify what we do:
    Within a batch process (a script executed within Cinema 4D) we create multiple textured objects and add each of those to a newly created database. The object to be added to the Database have Redshift materials.

    So if we create for example 9 object within that batch process then all 9 object most of the time have a black image, sometimes one of those has the correct image.

    The database is create this way:

            bases = maxon.BaseArray(maxon.AssetRepositoryRef)
            assetDb = AssetRepositoryTypes.AssetDatabase
            assetDb = maxon.RegistryInterface.FindEntryValue(assetDb._registry, assetDb._ids)
    
            repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                rid, assetDb, bases, maxon.Url(self.databasePath), True, False, False, None)
            if not repository:
                raise RuntimeError("Repository construction failed.")
    

    In a loop we iterate objects and create an Asset from that object, at that part I added the above code.

    for objectVaraint in variants:
            assetMetadata = maxon.AssetMetaData()
            assetCategoryId = maxon.Id(self.categoryId)
    
            # A StoreAssetStruct is a helper data structure for storing assets which bundles up an asset
            # category and storage and lookup repository for the operation.
            storeAssetStruct = maxon.StoreAssetStruct(assetCategoryId, self.repository, self.repository)
    
            # Use the convenience method AssetCreationInterface.CreateObjectAsset() to create and store an
            # object asset in one operation. The instantiation of a FileAsset for the object is hidden
            # away, and instead we deal directly with the AssetDescription which is representing the object
            # file asset.
            assetDescription = maxon.AssetCreationInterface.CreateObjectAsset(
                objectVaraint, doc, storeAssetStruct, assetId, assetName, assetVersion, assetMetadata, True)
    
            metadata = assetDescription.GetMetaData()
            
            imagepUrl = maxon.Url("C:/Users/Till Niese/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 = metadata.Get(maxon.ASSETMETADATA.MetaProperties)
            metaProperties.Set(maxon.ASSET.METAPROPERTIES.BASE.AUTOMATICPREVIEW, False)
            assetDescription.StoreMetaData(maxon.ASSETMETADATA.MetaProperties, metaProperties, maxon.AssetMetaData.KIND.PERSISTENT)
    

    Right after the imports I have added this:

    # --- 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
    
    @maxon.MAXON_REGISTRY("net.maxon.registry.assetrepositorytypes")
    class AssetRepositoryTypes(maxon.Registry):
        AssetDatabase = maxon.MAXON_DECLARATION("net.maxon.assets.repositorytype.database")
    

    Kind regards,
    Till

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

    Hi. In the UI of the Asset Browser there is the option to set a preview image using "Update Preview From File ...", and I would like to do the same thing this command does in Python without showing an File Chooser Dialog but by using a known path.

    I know that I can get an existing preview image using this code:

    metadata = assetDescription.GetMetaData()
    previewUrl = metadata.Get(maxon.ASSETMETADATA.ASSET_PREVIEWIMAGEURL)
    

    And setting other meta data of the asset works fine, but I don't know how to properly set/create/update the preview image.

    I tried to set it with:

    assetDescription.StoreMetaData(maxon.ASSETMETADATA.ASSET_PREVIEWIMAGEURL, maxon.Url("file:///C:/path/to/image.png"), maxon.AssetMetaData.KIND.PERSISTENT)
    

    or

    assetDescription.StoreUrlMetaData(maxon.ASSETMETADATA.ASSET_PREVIEWIMAGEURL, maxon.Url("file:///C:/path/to/image.png"), maxon.AssetMetaData.KIND.PERSISTENT)
    

    I also tried to disable the automatic preview before setting ASSET_PREVIEWIMAGEURL using:

    metaProperties = metadata.Get(maxon.ASSETMETADATA.MetaProperties)
    metaProperties.Set(maxon.ASSET.METAPROPERTIES.BASE.AUTOMATICPREVIEW, False)
    

    The only example code related to the ASSET_PREVIEWIMAGEURL that I was able to find was in the examples_dots.cpp so I tried to use that code and instead of maxon::Url newPreviewUrl = presetAsset.GeneratePreview(previewWidth, dummy, 0) iferr_return; I used newPreviewUrl = maxon.Url("file:///C:/path/to/image.png") in python, but that didn't work either.

    I think assetDescription.StoreUrlMetaData and maxon.ASSETMETADATA.ASSET_PREVIEWIMAGEURL is right, but I guess maxon.Url must be something different than a file:/// URL?

    Kind regards,
    Till

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

    Hi @m_adam, this works perfectly. Thank you for your fast response.

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

    I just figured out that the API changed in 2023 from:

    static MAXON_METHOD Result<UpdatableAssetRepositoryRef> CreateRepositoryFromUrl(const Id& rid, const Block<const AssetRepositoryRef>& bases, const Url& url, Bool writable, Bool derivedInPrefs, Bool tempRepository);
    

    to:

    static MAXON_METHOD Result<UpdatableAssetRepositoryRef> CreateRepositoryFromUrl(const Id& rid, const Class<AssetRepositoryRef>& repoType, const Block<const AssetRepositoryRef>& bases, const Url& url, Bool writable, Bool derivedInPrefs, Bool tempRepository, const BackgroundEntryTuple& backgroundJob = {});
    

    In the c++ section of GitHub - PluginCafe there is an updated version:

    		maxon::UpdatableAssetRepositoryRef repository = maxon::AssetInterface::CreateRepositoryFromUrl(
    			uuid, maxon::AssetRepositoryTypes::AssetDatabase(), bases, database._dbUrl, true, true, true) iferr_return;
    

    I however don't know how to translate that to Python.

    In particular, what should I use for maxon::AssetRepositoryTypes::AssetDatabase(), and BackgroundEntryTuple?

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

    Hi. I have some troubles with the example code on GitHub - PluginCafe that shows how to create a Repository using Python.

    The code itself runs fine in R26 (R26.012 and R26.110), but results in an error in 2023.1.3.

    Did something change from R26 to 2023 how a repository has to be created using CreateRepositoryFromUrl or is that a problem with the python API? If it is a problem with the API is there a way around that?

    The code:

    
    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.
            repository = maxon.AssetInterface.CreateRepositoryFromUrl(
                rid, bases, database._dbUrl, True, False, False)
            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)
    
            print(f"{repository} ({name}): id - {repoId}, writeable: {isWriteable}")
    

    Error message I receive in C4D 2023:

    Traceback (most recent call last):
      File "scriptmanager", line 558, in <module>
      File "scriptmanager", line 234, in CreateRepositories
      File "C:\Program Files\Maxon Cinema 4D 2023\resource\modules\python\libs\python39\maxon\decorators.py", line 383, in Auto
        ExecStaticMethod(*args)
    TypeError: unable to convert builtins.NativePyData to @net.maxon.interface.class-cR
    
    posted in Cinema 4D SDK •
    RE: Path delimiter behaves differntly on macOS and Windows for HyperFile ReadFilename

    Hello @ferdinand thank you for your response.

    You have also tagged your posting as maxon API although the types you are mentioning, HyperFile and FileName, are both classic API. What are the maxon API types you are using?

    Yes, it should have been classic api and not maxon api.

    Your question is a bit hard to answer in this form. I assume you are in some kind of NodeData plugin and must serialize and deserialize some data manually with NodeData::Read and NodeData::Write. In this context you are encountering the described behavior of Windows 'changing' the path delimiters written on MacOS.

    I guess that answers my question.

    But just in case, here is a simplified version of the code that hopefully illustrates better what is done:

    class MyData: public iCustomDataType<MyData>
    {
    	Filename _assetPath;
    public:
        Bool Read(HyperFile* hf, Int32 level) {
          hf->ReadFilename(&_assetPath);
         // inpsecting _assetPath and _assetPath.GetFile()
    
          return TRUE; 
        }
    
        Bool Write(HyperFile* hf, Int32 level) {
          // inpsecting _assetPath
          hf->WriteFilename(_assetPath);
          return TRUE; 
        }
    };
    
    class MyDataDataType : public CustomDataTypeClass
    {
      INSTANCEOF(MyDataDataType , CustomDataTypeClass)
    
    public:
      virtual Bool WriteData(const CustomDataType* d, HyperFile* hf) {
        return static_cast<const MyData*>(d)->Write(hf);
      }
    	
      virtual Bool ReadData(CustomDataType* d, HyperFile* hf, Int32 level) {
        return static_cast<MyData*>(d)->Read(hf, level);
      }  
    };
    

    So yes WriteFilename and ReadFilename are called for the serialization/deserialize process.

    For completeness a slightly rephrased description of the observation from the initial question:

    Project created on windows:

    • WriteData is called and _assetPath - that contains C:\Program Files\MyAssets\somefile.dat (when inspecting it in Write) - is written.
    • opening that same project on windows then _assetPath is again C:\Program Files\MyAssets\somefile.dat when inspected in Read and _assetPath.GetFile() returns somefile.dat.
    • copying that project to macOS and opening it there _assetPath is also C:\Program Files\MyAssets\somefile.dat and _assetPath.GetFile() returns C:\Program Files\MyAssets\somefile.dat.

    Project created on macOS:

    • WriteData is called and _assetPath - that contains /Library/Application Support/MyAssets/somefile.dat when inspecting it in Write- is written.
    • opening that same project on macOS then _assetPath is again /Library/Application Support/MyAssets/somefile.dat when inspected in Read and _assetPath.GetFile() returns somefile.dat.
    • copying that project to windows and opening it there_assetPath it now \Library\Application Support\MyAssets\somefile.dat and _assetPath.GetFile() returns somefile.dat.

    But based on your answer I think this behavior is expected.

    Kind regards,
    Till

    posted in Cinema 4D SDK •
    RE: MSG_MULTI_CLEARSUGGESTEDFOLDER not called for TeamRender

    @m_magalhaes Thank you for your response.

    So on the client-side, I always have to assume that I might get absolute paths that refer to the files on the server (MSG_MULTI_CLEARSUGGESTEDFOLDER is not called and MSG_RENAMETEXTURES is only called in case of name conflicts)?

    If I'm confident that a file that is found on the client-side at such an absolute path matches the one on the server I could use it, but if I want to avoid mismatches of the assets between client and server I should check if net rendering is active for the document and if so only use the file part ( Filename::GetFile) of the file to check if the Asset is in the project directory and if not request it using only that file part through NetRenderGetFileFromServer?

    So a possible implementation of the Asset lookup in the plugin code would look like this?

    Filename filename = /* retrieved e.g. from HyperFile */
    
    // Check if net rendering is active for document
    NetRenderDocumentContent * const context = doc->GetNetRenderDocumentContext();
    if (context != nullptr) {
       // net rendering: check if file is missing in project directory
       if (!GeFExists( doc->GetDocumentPath() + filename.GetFile() ) {
           Filename fnNet;
    
           // request file from the server
           if (NetRenderGetFileFromServer(context->_service,  filename.GetFile(), fnNet) {
                // use path returned by NetRenderGetFileFromServer
               filename = fnNet;
           } else {
               // handle error case
           }
       } else {
           // use the file in the project directory
           filename =  doc->GetDocumentPath() + filename.GetFile();
       }
    } else {
       // no net rendering: regular check if asset exists at path + error handling
    }
    
    posted in Cinema 4D SDK •
    MSG_MULTI_CLEARSUGGESTEDFOLDER not called for TeamRender

    Hello,

    I have some questions about the messages sent for TeamRendering. I already found these topics, but those don't fully answer my question:

    • Changing Asset References to Absolute
    • Set preference parameters
    • Weird filenames when using make project
    • MSG_GETALLASSETS calls?
    • TeamRender&MSG_MULTI_CLEARSUGGESTEDFOLDER
    • questions about network rendering.

    When TeamRendering is used (Add to Render Queue... and TeamRender to Picture Viewer...) MSG_GETALLASSETS is emmited and the Resources are transferred to the render client(s). But MSG_MULTI_CLEARSUGGESTEDFOLDER does not seem to be emitted (For Save Project with Assets... it is). Due to that, the paths on the render client are absolute referring to the file on the PC initiating TeamRendering.

    Should one expect that this message is not sent? And if so is that due to the possibility to request assets on-demand from the server for which the absolute path would be required? Is there a case for which MSG_MULTI_CLEARSUGGESTEDFOLDER would be sent whenTeamRendering is used?

    Kind regards,
    Till

    posted in Cinema 4D SDK •
    Path delimiter behaves differntly on macOS and Windows for HyperFile ReadFilename

    Hello,

    We use HyperFile to store some absolute paths related to our plugin. We, therefore, write the Filename using WriteFilename and upon loading read it back using ReadFilename.

    When exchanging the saved c4d files between windows and macOS I noticed that the path delimiters behave differently.

    If the Filename that is written to the HyperFile under Windows is C:\Program Files\MyAssets\somefile.dat and the c4d file is then loaded on macOS the Filename read is C:\Program Files\MyAssets\somefile.dat (path delimiter did not change).

    If the Filename that is written to the HyperFile under macOS is /Library/Application Support/MyAssets/somefile.dat and the c4d file is then loaded on windows the Filename read is \Library\Application Support\MyAssets\somefile.dat (path delimiter changed from /, \)

    Why is the delimiter only changing when loading a file saved on macOS on windows and not the other way round? Is that an expected behavior? And can this be made consistent (that the delimiter is changed on both or on none)?

    Kind regards,
    Till

    posted in Cinema 4D SDK •