I’m modifying the topology of a mesh which has a picture mapped to it (decal) using Grasshopper.
In the GH component I first make a copy of the mesh, but I just can’t find a way to copy also the texture to make the new mesh a full copy. How is that done in C#?
The mesh I copied like so:
var newMesh = oldMesh.DuplicateMesh();
// Now, how to copy also the texture?
You will likely need to copy the material to the new object. Without an example file, here is a guess and maybe a hint ObjectAttributes.MaterialIndex property
This is how I finally coded the copying of the Decal to a Mesh copy.
First I copied the mesh, and sent both the original and the copy to the following method, which duplicated and returned the original Decal for later insertion into the mesh copy:
var mesh = M.DuplicateMesh();
if(!GetDecalCopyFromMesh(M, mesh, out mesh, out Decal newDecal, out Guid copyId))
{
PrintError(“Error - Copying Mesh Texture failed.”);
return;
}
// Creates a Decal from the original mesh and returns the id (Guid) of the pre-created mesh copy.
// The decal is not applied here directly, since it requires Baking the copy, which is left to
// the caller to do decide later. If baking, the decal is then applied to the copy after it
// has been added to Rhino Document (this is not always a given, if the calling code is aborted
// for so reason)
//
private bool GetDecalCopyFromMesh(Mesh originalMesh, Mesh meshCopy, out Mesh texturedMesh, out Decal newDecal, out Guid copyId)
{
// --------------------------------------------------
// initialize out-params in case aborting prematurely
// --------------------------------------------------
texturedMesh = null;
newDecal = null;
copyId = Guid.Empty;
// --------------------------------------------------
// Retrieve the original mesh (must already exist in
// the Rhino doc in order to access its object and decals)
// --------------------------------------------------
//Guid originalId = RhinoDoc.ActiveDoc.Objects.AddMesh(originalMesh);
if (!FindObjectGuidForMesh(originalMesh, out Guid originalId))
{
PrintError("The input (original) Mesh doesn't seem to exist in the Rhino Document");
return false;
}
RhinoObject originalObj = RhinoDoc.ActiveDoc.Objects.FindId(originalId);
if (originalObj == null)
{
PrintError("The input (original) Mesh doesn't seem to exist as a RhinoObject (Mesh)");
return false;
}
// --------------------------------------------------
// Get decals from the original object
// --------------------------------------------------
var decals = originalObj.Attributes.Decals;
if (decals.Count() == 0)
{
PrintError("No decals found on the original mesh.");
return false;
}
// --------------------------------------------------
// Duplicate the geometry (ensure it's a clean copy)
// --------------------------------------------------
Mesh copy_mesh = meshCopy.DuplicateMesh();
// ----------------------------------------------
// Copy decal data
// ----------------------------------------------
foreach (Rhino.Render.Decal decal in decals)
{
// Create a new decal instance with the same properties
var decal_params = new Rhino.Render.DecalCreateParams();
decal_params.DecalMapping = decal.Mapping;
decal_params.DecalProjection = decal.Projection;
decal_params.EndLatitude = decal.EndLatitude;
decal_params.EndLongitude = decal.EndLongitude;
decal_params.Height = decal.Height;
decal_params.MapToInside = decal.MapToInside;
decal_params.MaxU = 1.0; //decal.MaxU;
decal_params.MaxV = 1.0; //decal.MaxV;
decal_params.MinU = 0.0; //decal.MinU;
decal_params.MinV = 0.0; //decal.MinV;
decal_params.Origin = decal.Origin;
decal_params.Radius = decal.Radius;
decal_params.StartLatitude = decal.StartLatitude;
decal_params.StartLongitude = decal.StartLongitude;
decal_params.TextureInstanceId = decal.TextureInstanceId;
decal_params.Transparency = decal.Transparency;
decal_params.VectorAcross = decal.VectorAcross;
decal_params.VectorUp = decal.VectorUp;
newDecal = Decal.Create(decal_params);
if (newDecal == null)
{
PrintError("Failed to create decal copy.");
return false;
}
}
texturedMesh = copy_mesh;
return true;
}
Then, when (if) the manipulation of the mesh copy was accepted, the Mesh was Baked and the Decal copy applied to it, like so:
// Bakes a mesh to the Rhino Document. Applies a (prepared) Decal Texture to
// the mesh and places the Mesh on a dedicated Layer ("toLayer")
//
private Guid BakeMesh(Mesh newMesh, Decal decal, string toLayer)
{
// Ensure that a target Layer actually exists
const int notFoundValue = -1;
var toLayerIndex = RhinoDoc.ActiveDoc.Layers.FindByFullPath(toLayer, -1);
if (toLayerIndex == notFoundValue)
{
PrintError("The target Layer doesn't exist in the Rhino Document");
return Guid.Empty;
}
ObjectAttributes attrs = new ObjectAttributes();
if (decal != null)
{
attrs.LayerIndex = toLayerIndex;
attrs.Decals.Add(decal);
// newMesh.Attributes.Decals.Add(newDecal);
}
// Bake
var guid = RhinoDoc.ActiveDoc.Objects.AddMesh(newMesh, attrs);
// Find the baked instance reference inside the Rhino document.
var meshObj = RhinoDoc.ActiveDoc.Objects.FindId(guid);
meshObj.CommitChanges();
// Update display
RhinoDoc.ActiveDoc.Views.Redraw();
return guid;
}
Edit: Corrected a (copied) comments to mention “Layer”, not Mesh, etc.