Hello McNeel Forum community,
I need some help with developing a plugin for Rhino 8 using C#. Specifically, I’m trying to write a command that will smoothly morph a geometric pattern between two boundary curves. I’m aiming for a result similar to professional shoe design plugins (like Orang or xShoe).
However, I am constantly getting compilation errors when trying to use modern RhinoCommon commands in my project. Even though I am using Rhino 8, the compiler says it cannot find fundamental classes like FlowMorph, SplineMorph, and methods like Mesh.Morph() (errors CS0246, CS1061).
Here are the steps we have already tried to solve this issue:
- We created a brand new project from scratch in Visual Studio using the official Rhino 8 plugin template.
- We completely removed the RhinoCommon NuGet package from the project and added a manual, direct file reference to
RhinoCommon.dllfrom the"C:\Program Files\Rhino 8\System"folder. - To bypass this setup problem, we also tried writing numerous manual deformation algorithms (Bounding Box, Centroid-Ray, Barycentric Coordinates) that use only the basic functions found even in older Rhino versions. However, these manual methods did not provide the desired smoothness.
After all these steps, what could be the reason the compiler still cannot find the Rhino 8 commands? Could there be an installation detail or project setting that I am missing? Does this point to a deeper issue with Visual Studio or .NET?
I can provide my project file (.zip) and the Rhino file (.3dm) I am testing with. The final code block that should work but fails to compile in my environment is attached below.
Thank you in advance for your help and guidance.
**3. Code Block
using Rhino;
using Rhino.Commands;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.Geometry.Morphs;
using Rhino.Input;
using Rhino.Input.Custom;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MorphPlusV2
{
public class MorphPlusV2Command : Command
{
public override string EnglishName => "MorphPlus";
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
#region User Input
ObjRef[] objectRefs;
Result get_obj_rc = RhinoGet.GetMultipleObjects("Select objects to morph", false, ObjectType.Brep | ObjectType.Mesh | ObjectType.Surface | ObjectType.Curve, out objectRefs);
if (get_obj_rc != Result.Success) return get_obj_rc;
var morphObjects = objectRefs.Select(r => r.Object()).ToList();
ObjRef oldCurveRef;
Result get_old_rc = RhinoGet.GetOneObject("Select OLD boundary CURVE", false, ObjectType.Curve, out oldCurveRef);
if (get_old_rc != Result.Success) return get_old_rc;
Curve oldBoundaryCurve = oldCurveRef.Curve();
if (oldBoundaryCurve == null || !oldBoundaryCurve.IsClosed || !oldBoundaryCurve.IsPlanar()) { RhinoApp.WriteLine("Old boundary curve must be closed and planar."); return Result.Failure; }
ObjRef newCurveRef;
Result get_new_rc = RhinoGet.GetOneObject("Select NEW boundary CURVE", false, ObjectType.Curve, out newCurveRef);
if (get_new_rc != Result.Success) return get_new_rc;
Curve newBoundaryCurve = newCurveRef.Curve();
if (newBoundaryCurve == null || !newBoundaryCurve.IsClosed || !newBoundaryCurve.IsPlanar()) { RhinoApp.WriteLine("New boundary curve must be closed and planar."); return Result.Failure; }
#endregion
bool deleteOriginal = true;
NurbsCurve baseCurve = oldBoundaryCurve.ToNurbsCurve();
NurbsCurve targetCurve = newBoundaryCurve.ToNurbsCurve();
int rebuild_point_count = 100;
baseCurve.Rebuild(rebuild_point_count, baseCurve.Degree, true);
targetCurve.Rebuild(rebuild_point_count, targetCurve.Degree, true);
var morph = new FlowSpaceMorph(baseCurve, targetCurve, true, true, false);
doc.Objects.UnselectAll();
var newGeometries = new List<GeometryBase>();
var newObjectAttributes = new List<ObjectAttributes>();
foreach (var rhinoObject in morphObjects)
{
GeometryBase geom = rhinoObject.Geometry.Duplicate();
if (geom is Curve curve)
{
var nurbsCurve = curve.ToNurbsCurve();
if (nurbsCurve != null)
{
for (int i = 0; i < nurbsCurve.Points.Count; i++) { nurbsCurve.Points.SetPoint(i, morph.MorphPoint(nurbsCurve.Points[i].Location)); }
geom = nurbsCurve;
}
}
else if (geom is Mesh mesh)
{
for (int i = 0; i < mesh.Vertices.Count; i++) { mesh.Vertices[i] = (Point3f)morph.MorphPoint(mesh.Vertices[i]); }
}
else if (geom is Brep brep)
{
var fullMesh = new Mesh();
var brepMeshes = Mesh.CreateFromBrep(brep, MeshingParameters.Default);
if (brepMeshes != null)
{
fullMesh.Append(brepMeshes);
for (int i = 0; i < fullMesh.Vertices.Count; i++) { fullMesh.Vertices[i] = (Point3f)morph.MorphPoint(fullMesh.Vertices[i]); }
geom = fullMesh;
}
}
newGeometries.Add(geom);
newObjectAttributes.Add(rhinoObject.Attributes.Duplicate());
}
for (int i = 0; i < newGeometries.Count; i++) doc.Objects.Add(newGeometries[i], newObjectAttributes[i]);
if (deleteOriginal) foreach (var rhinoObject in morphObjects) doc.Objects.Delete(rhinoObject.Id, true);
doc.Views.Redraw();
return Result.Success;
}
}
}
deneme-1.3dm (158.4 KB)