Bitmap texture filename modification

Hello everyone,

I’m trying something like this code to modify the path to the image used for a texture:

string referenceImageDir = "path/to/reference/dir"

foreach(var material in doc.Materials) {
  var texturePath = material.GetBitmapTexture().FileReference.FullPath
                    ?? material.GetBitmapTexture().FileName;
  var textureDir = Path.GetDirectoryName(texturePath);
  if (textureDir == referenceImageDir) continue;
  var textureFileName = Path.GetFileName(texturePath);
  var newTexturePath = Path.Combine(referenceImageDir, textureFileName);
  if (File.Exists(newTexturePath)) {
    var texture = material.GetBitmapTexture();
    texture.FileName = newTexturePath;
    texture.FileReference = FileReference.CreateFromFullPath(newTexturePath);
    material.SetBitmapTexture(texture);
    material.CommitChanges();
  }
}

When I check my objects the path is updated:

foreach(var rhinoObject in objs) {
  var matIndex = rhinoObject.Attributes.MaterialIndex;
  var material = doc.Materials.FindIndex(matIndex);
  if (material == null) continue;
  var texturePath = material.GetBitmapTexture().FileReference.FullPath
                    ?? material.GetBitmapTexture().FileName;
}

But then when I check the materials in the app, it is not updated and naturally, when I save and reload the file, all the filenames are reset.

What am I missing?

It is better to do this through the newer RenderContent system, meaning RenderMaterials in your case.

I wrote a simple tutorial for Python here: https://jesterking.github.io/rhipy/change_texture_filepath.html

It is straightforward to adapt for C#, the same RhinoCommon SDK is used.

Thanks. So I implemented a C# version of your code:

private static void HandleRenderContent(RenderContent renderMaterial, string referenceImageDir) {
    RenderContent? child = renderMaterial.FirstChild;
    while (child != null) {
        HandleRenderContent(child, referenceImageDir);
        string oldFilePath = child.Filename;
        if (child is {
                CanBeEdited: true,
                Category: "image-based"
            } && !string.IsNullOrEmpty(oldFilePath)) {
            string fileName = Path.GetFileName(oldFilePath);
            string newFilePath = Path.Combine(referenceImageDir, fileName);
            if (oldFilePath != newFilePath) {
                try {
                    child.BeginChange(RenderContent.ChangeContexts.Program);
                    child.Filename = newFilePath;
                } finally {
                    child.EndChange();
                }
            }
        }
        child = child.NextSibling;
    }
}

Calling it from EndOpenDocument event:

private void RhinoDoc_EndOpenDocument(object? sender, DocumentOpenEventArgs e) {
    string referenceImageDir = "Reference/Images/Dir";
    foreach(var material in e.Document.RenderMaterials) {
        HandleRenderContent(material, referenceImageDir);
    }
}

And it works just fine, apart from the Found at value of the texture when I check it in the Rhino UI. It is still loading it from the old path. I tried to save and reload the doc but no luck. Is there anyway to force a reload or change the found at value manually ?

@maxsoder , @johnc - any ideas here?