Hello everyone,
I’m having trouble sending geometry from Grasshopper to Unity 3D via UDP using the gHowl plugin after upgrading to Rhino 8. This setup was working fine in Rhino 7, but now the serialization/deserialization process is failing.
The error message I’m receiving is:
SerializationException: Unable to read CommonObject from base64 encoded string
Rhino.Runtime.CommonObject.FromBase64String (System.Int32 archive3dm, System.Int32 opennurbs, System.String base64Data) (at <1bbba1e0041c44f6a7adfd08baefb1a6>:0)
It seems like something has changed in how geometry serialization works between Rhino 7 and 8. I’m using Newtonsoft.Json for serialization/deserialization, similar to how it’s done in Rhino Compute, but I haven’t found any updated code examples for Rhino 8.
Are there any changes in Rhino 8 that affect the serialization of geometry?
Here’s the code I’m currently using:
In Grasshopper, inside a C# script component:
#r "C:\Users\bosco\AppData\Roaming\Grasshopper\Libraries\Newtonsoft.Json.dll"
// Grasshopper Script Instance
#region Usings
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using Rhino;
using Rhino.Geometry;
using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
using Newtonsoft.Json;
#endregion
public class Script_Instance : GH_ScriptInstance
{
#region Notes
/*
Members:
RhinoDoc RhinoDocument
GH_Document GrasshopperDocument
IGH_Component Component
int Iteration
Methods (Virtual & overridable):
Print(string text)
Print(string format, params object[] args)
Reflect(object obj)
Reflect(object obj, string method_name)
*/
#endregion
private void RunScript(object geo, ref object json)
{
// Suppose 'input' is a Rhino.Geometry.Mesh object
Mesh mesh = geo as Mesh;
if (mesh != null)
{
string jsonMesh = JsonConvert.SerializeObject(mesh);
json = jsonMesh; // Output the JSON string to send to Unity.
}
else json = "";
}
}
In Unity (relevant portion of code):
public void UpdateGeometry(string json)
{
SerializedGeometry geometryData = JsonConvert.DeserializeObject<SerializedGeometry>(json);
Rhino.Geometry.Mesh rhinoMesh = CommonObject.FromBase64String(geometryData.archive3dm, geometryData.opennurbs, geometryData.data) as Rhino.Geometry.Mesh;
ConvertToGameObject(rhinoMesh);
}
private void ConvertToGameObject(Rhino.Geometry.Mesh mesh)
{
var vertices = mesh.Vertices.ToList().ConvertAll(new Converter<Rhino.Geometry.Point3f, Vector3>(Point3fToVector3)).ToArray();
var normals = mesh.Normals.ToList().ConvertAll(new Converter<Rhino.Geometry.Vector3f, Vector3>(Vector3fToVector3)).ToArray();
var triangleList = new List<int>();
foreach (var face in mesh.Faces)
{
if (face.IsTriangle)
{
triangleList.Add(face.A);
triangleList.Add(face.B);
triangleList.Add(face.C);
triangleList.Add(face.C);
triangleList.Add(face.B);
triangleList.Add(face.A);
}
else
{
triangleList.Add(face.A);
triangleList.Add(face.B);
triangleList.Add(face.C);
triangleList.Add(face.C);
triangleList.Add(face.D);
triangleList.Add(face.A);
triangleList.Add(face.C);
triangleList.Add(face.B);
triangleList.Add(face.A);
triangleList.Add(face.A);
triangleList.Add(face.D);
triangleList.Add(face.C);
}
}
var gb = (GameObject)Instantiate(meshObjPrefab, GHContainer.transform);
var meshFilter = gb.GetComponent<MeshFilter>();
var unityMesh = new UnityEngine.Mesh();
unityMesh.vertices = vertices;
unityMesh.normals = normals;
unityMesh.triangles = triangleList.ToArray();
meshFilter.mesh = unityMesh;
gb.GetComponent<MeshRenderer>().material = defaultBuildingMaterial;
}
public static Vector3 Point3fToVector3(Rhino.Geometry.Point3f pf)
{
return new Vector3(pf.X, pf.Z, pf.Y);
}
public static Vector3 Vector3fToVector3(Rhino.Geometry.Vector3f pf)
{
return new Vector3(pf.X, pf.Z, pf.Y);
}
[Serializable]
public class SerializedGeometry
{
public int version;
public int archive3dm;
public int opennurbs;
public string data;
}
The error occurs in line
Rhino.Geometry.Mesh rhinoMesh = CommonObject.FromBase64String(geometryData.archive3dm, geometryData.opennurbs, geometryData.data) as Rhino.Geometry.Mesh;
Any insights or suggestions would be greatly appreciated. Thanks!