So what happened is I tried to start making a Dancing Line fan layout, but when I tried to Probuilderize the cubes (The white ones), I got errors saying “Value cannot be null.” and “ProBuilderMesh is already added to GameObject!”. No matter what I try, I can never fix it. Should I install an older version of Unity & Visual Studio? I’m on 2022.3.29f1
Hi @Muffinly, it’s a bit tough to say what’s wrong here by just looking at the screenshot. Could you please share the callstack for both the message and the warning? Also I could take a look at the scene if you can export it as a package and share it. Thanks!
The package:
The code for the message & warning:
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
using UnityEngine.ProBuilder;
using UnityEngine.ProBuilder.MeshOperations;
namespace UnityEditor.ProBuilder.Actions
{
sealed class ProBuilderize : MenuAction
{
bool m_Enabled;
Pref m_Quads = new Pref(“meshImporter.quads”, true);
Pref m_Smoothing = new Pref(“meshImporter.smoothing”, true);
Pref m_SmoothingAngle = new Pref(“meshImporter.smoothingAngle”, 1f);
public ProBuilderize()
{
MeshSelection.objectSelectionChanged += OnObjectSelectionChanged;
OnObjectSelectionChanged(); // invoke once as we might already have a selection in Hierarchy
}
private void OnObjectSelectionChanged()
{
// can't just check if any MeshFilter is present because we need to know whether or not it's already a
// probuilder mesh
int meshCount = Selection.transforms.SelectMany(x => x.GetComponentsInChildren<MeshFilter>()).Count();
m_Enabled = meshCount > 0 && meshCount != MeshSelection.selectedObjectCount;
}
public override ToolbarGroup group
{
get { return ToolbarGroup.Object; }
}
public override Texture2D icon
{
get { return IconUtility.GetIcon("Toolbar/Object_ProBuilderize", IconSkin.Pro); }
}
public override TooltipContent tooltip
{
get { return s_Tooltip; }
}
GUIContent m_QuadsTooltip = new GUIContent("Import Quads", "Create ProBuilder mesh using quads where " +
"possible instead of triangles.");
GUIContent m_SmoothingTooltip = new GUIContent("Import Smoothing", "Import smoothing groups by " +
"testing adjacent faces against an angle threshold.");
GUIContent m_SmoothingThresholdTooltip = new GUIContent("Smoothing Threshold", "When importing " +
"smoothing groups any adjacent faces with an adjoining angle difference of less than this value will be " +
"grouped together in a smoothing group.");
private static readonly TooltipContent s_Tooltip = new TooltipContent
(
"ProBuilderize",
@"Creates ProBuilder-modifiable objects from meshes."
);
public override bool enabled
{
get { return base.enabled && m_Enabled; }
}
protected override MenuActionState optionsMenuState
{
get { return MenuActionState.VisibleAndEnabled; }
}
protected override void OnSettingsGUI()
{
GUILayout.Label("ProBuilderize Options", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("When Preserve Faces is enabled ProBuilder will try to group adjacent triangles into faces.", MessageType.Info);
EditorGUI.BeginChangeCheck();
m_Quads.value = EditorGUILayout.Toggle(m_QuadsTooltip, m_Quads);
m_Smoothing.value = EditorGUILayout.Toggle(m_SmoothingTooltip, m_Smoothing);
GUI.enabled = m_Smoothing;
EditorGUILayout.PrefixLabel(m_SmoothingThresholdTooltip);
m_SmoothingAngle.value = EditorGUILayout.Slider(m_SmoothingAngle, 0.0001f, 45f);
GUI.enabled = true;
if (EditorGUI.EndChangeCheck())
ProBuilderSettings.Save();
GUILayout.FlexibleSpace();
GUI.enabled = enabled;
if (GUILayout.Button("ProBuilderize"))
EditorUtility.ShowNotification(PerformAction().notification);
GUI.enabled = true;
}
protected override ActionResult PerformActionImplementation()
{
IEnumerable<MeshFilter> top = Selection.transforms.Select(x => x.GetComponent<MeshFilter>()).Where(y => y != null);
IEnumerable<MeshFilter> all = Selection.gameObjects.SelectMany(x => x.GetComponentsInChildren<MeshFilter>()).Where(x => x != null);
MeshImportSettings settings = new MeshImportSettings()
{
quads = m_Quads,
smoothing = m_Smoothing,
smoothingAngle = m_SmoothingAngle
};
if (top.Count() != all.Count())
{
int result = UnityEditor.EditorUtility.DisplayDialogComplex("ProBuilderize Selection",
"ProBuilderize children of selection?",
"Yes",
"No",
"Cancel");
if (result == 0)
return DoProBuilderize(all, settings);
else if (result == 1)
return DoProBuilderize(top, settings);
else
return ActionResult.UserCanceled;
}
return DoProBuilderize(all, settings);
}
[System.Obsolete("Please use DoProBuilderize(IEnumerable<MeshFilter>, pb_MeshImporter.Settings")]
public static ActionResult DoProBuilderize(
IEnumerable<MeshFilter> selected,
bool preserveFaces)
{
return DoProBuilderize(selected, new MeshImportSettings()
{
quads = preserveFaces,
smoothing = false,
smoothingAngle = 1f
});
}
/// <summary>
/// Adds pb_Object component without duplicating the objcet. Is undo-able.
/// </summary>
/// <param name="selected"></param>
/// <param name="settings"></param>
/// <returns></returns>
public static ActionResult DoProBuilderize(
IEnumerable<MeshFilter> selected,
MeshImportSettings settings)
{
int i = 0;
float count = selected.Count();
// Return immediately from the action so that the GUI can resolve. Displaying a progress bar interrupts the
// event loop causing a layoutting error.
EditorApplication.delayCall += () =>
{
foreach (var mf in selected)
{
if (mf.sharedMesh == null)
continue;
GameObject go = mf.gameObject;
Mesh sourceMesh = mf.sharedMesh;
Material[] sourceMaterials = go.GetComponent<MeshRenderer>()?.sharedMaterials;
try
{
var destination = Undo.AddComponent<ProBuilderMesh>(go);
var meshImporter = new MeshImporter(sourceMesh, sourceMaterials, destination);
meshImporter.Import(settings);
destination.Rebuild();
destination.Optimize();
i++;
}
catch (System.Exception e)
{
Debug.LogWarning("Failed ProBuilderizing: " + go.name + "\n" + e.ToString());
}
UnityEditor.EditorUtility.DisplayProgressBar("ProBuilderizing", mf.gameObject.name, i / count);
}
UnityEditor.EditorUtility.ClearProgressBar();
MeshSelection.OnObjectSelectionChanged();
ProBuilderEditor.Refresh();
};
if (i < 1)
return new ActionResult(ActionResult.Status.Canceled, "Nothing Selected");
return new ActionResult(ActionResult.Status.Success, "ProBuilderize " + i + (i > 1 ? " Objects" : " Object").ToString());
}
}
}
Looked at your scene. My understanding is that what you tried to do is “probuilderizing” the parent that contains all the cubes? You’re getting the warnings because the child cubes are already probuilder meshes therefore there’s nothing to probuilderize.
What is your goal by doing this? If you want to have a single ProBuilder mesh that contains all the cubes you can do Tools -> ProBuilder -> Object -> Merge Objects
after selecting all the cubes. If you then need to center pivot: Tools -> ProBuilder -> Object -> Center Pivot
. If you want the pivot to be at the parent’s origin, then move the parent to (0,0,0) and then do Tools -> ProBuilder -> Object -> Freeze Transform
on the merged mesh.
This is still marked unresolved. There is always the option to delete probuilder scripts in an object and then probuilderize it. You can do this per object or for the whole scene. Not sure about newer versions, but this is usually under tools → probuilder → actions.