275 lines
12 KiB
C#
275 lines
12 KiB
C#
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
* All rights reserved.
|
|
*
|
|
* Licensed under the Oculus SDK License Agreement (the "License");
|
|
* you may not use the Oculus SDK except in compliance with the License,
|
|
* which is provided at the time of installation or download, or which
|
|
* otherwise accompanies this software in either electronic or hard copy form.
|
|
*
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* https://developer.oculus.com/licenses/oculussdk/
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/************************************************************************************
|
|
* Filename : MetaXRAcousticGeometryEditor.cs
|
|
* Content : Geometry editor class
|
|
Attach to geometry to define material properties
|
|
***********************************************************************************/
|
|
|
|
//#define ENABLE_DEBUG_EXPORT_OBJ
|
|
|
|
using System;
|
|
using System.IO;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
[CustomEditor(typeof(MetaXRAcousticGeometry))]
|
|
public class MetaXRAcousticGeometryEditor : Editor
|
|
{
|
|
private bool showAdvancedControls = false;
|
|
private bool needsRebake = false;
|
|
|
|
private void OnEnable()
|
|
{
|
|
MetaXRAcousticGeometry geo = target as MetaXRAcousticGeometry;
|
|
|
|
// Determine if the geometry needs rebaking based on time stamp.
|
|
bool isInvalid = geo.VertexCount == 0;
|
|
DateTime timeStamp = DateTime.MinValue;
|
|
string newFilePath = geo.AbsoluteFilePath;
|
|
if (newFilePath != null)
|
|
{
|
|
// Get file time stamp.
|
|
FileInfo fileInfo = new FileInfo(newFilePath);
|
|
long fileSize = fileInfo.Exists ? fileInfo.Length : 0;
|
|
timeStamp = System.IO.File.GetLastWriteTime(newFilePath);
|
|
isInvalid = isInvalid && (fileSize == 0);
|
|
}
|
|
|
|
// The .IsOlder() function can take a long time. Call it just once when GUI is enabled.
|
|
needsRebake = isInvalid ? true : geo.IsOlder(timeStamp);
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
MetaXRAcousticGeometry geo = (MetaXRAcousticGeometry)target;
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
bool newIncludeChildMeshes = EditorGUILayout.Toggle(new GUIContent("Include Child Meshes", "Include all child meshes into single geometry instance"), geo.IncludeChildMeshes);
|
|
|
|
// Update controls to change Mesh Simplification Flags
|
|
bool newEnableDiffraction = geo.EnableDiffraction;
|
|
// Use default setting for advanced parameters if the settings are hidden
|
|
float newMaxSimplifyError = geo.MaxSimplifyError;
|
|
float newMinDiffractionEdgeAngle = geo.MinDiffractionEdgeAngle;
|
|
float newMinDiffractionEdgeLength = geo.MinDiffractionEdgeLength;
|
|
float newFlagLength = geo.FlagLength;
|
|
bool newEnableMeshSimplification = geo.EnableSimplification;
|
|
int newLODSelection = geo.LodSelection;
|
|
bool newUseColliders = geo.UseColliders;
|
|
bool newOverrideExcludeTagsEnabled = geo.OverrideExcludeTagsEnabled;
|
|
string[] newOverrideExcludeTags = geo.ExcludeTags;
|
|
bool newFileEnabled = geo.FileEnabled;
|
|
bool pathChanged = false;
|
|
string newFilePath = geo.AbsoluteFilePath;
|
|
bool shouldWriteMesh = false;
|
|
|
|
showAdvancedControls = EditorGUILayout.Foldout(showAdvancedControls, "Advanced Controls");
|
|
if (showAdvancedControls)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
newUseColliders = EditorGUILayout.Toggle(new GUIContent("Use Colliders", "Use the physics MeshColliders instead of the Visual geometry."), newUseColliders);
|
|
newOverrideExcludeTagsEnabled = EditorGUILayout.Toggle(new GUIContent("Override Exclude Tags", "Override the Project Settings exclude tags to define custom exclude tags only for this geometry."), newOverrideExcludeTagsEnabled);
|
|
|
|
using (new EditorGUI.DisabledGroupScope(!newOverrideExcludeTagsEnabled))
|
|
{
|
|
newOverrideExcludeTags = MetaXRAcousticSettingsProvider.ExcludeTagAsFlagsField(newOverrideExcludeTags);
|
|
}
|
|
Separator();
|
|
|
|
EditorGUILayout.LabelField("Mesh Simplification", EditorStyles.boldLabel);
|
|
newMaxSimplifyError = EditorGUILayout.Slider(new GUIContent("Max Error", "Maximum tolerable mesh simplification error in mesh-local units"), newMaxSimplifyError, 0.0f, 1.0f);
|
|
newEnableMeshSimplification = (newMaxSimplifyError > 0.0f);
|
|
const int LOD_LEVEL_MAX = 7; // https://docs.unity3d.com/Manual/LevelOfDetail.html
|
|
newLODSelection = EditorGUILayout.IntSlider(new GUIContent("LOD", "Which LOD to use for the acoustic geometry when using an LOD Group. The lowest value of 0 corresponds to the highest quality mesh."), newLODSelection, 0, LOD_LEVEL_MAX);
|
|
Separator();
|
|
|
|
using (new EditorGUI.DisabledGroupScope(Application.isPlaying))
|
|
{
|
|
bool showFilePicker = false;
|
|
using (new EditorGUILayout.HorizontalScope())
|
|
{
|
|
EditorGUILayout.PrefixLabel(new GUIContent("File Path:", "The path to the serialized mesh file, relative to the StreamingAssets directory"));
|
|
|
|
int indentLevelPrev = EditorGUI.indentLevel;
|
|
EditorGUI.indentLevel = 0;
|
|
EditorGUILayout.LabelField(geo.RelativeFilePath, EditorStyles.wordWrappedLabel);
|
|
|
|
if (GUILayout.Button("...", GUILayout.ExpandWidth(false)))
|
|
{
|
|
// defer displaying dialog to avoid layout error
|
|
showFilePicker = true;
|
|
}
|
|
|
|
EditorGUI.indentLevel = indentLevelPrev;
|
|
}
|
|
|
|
if (showFilePicker)
|
|
{
|
|
if (!System.IO.Directory.Exists(Application.streamingAssetsPath))
|
|
{
|
|
System.IO.Directory.CreateDirectory(Application.streamingAssetsPath);
|
|
}
|
|
|
|
string directory = Application.streamingAssetsPath;
|
|
string fileName = geo.gameObject.name + "." + MetaXRAcousticGeometry.FILE_EXTENSION;
|
|
|
|
if (newFilePath != "")
|
|
{
|
|
string suggestedDirectory = System.IO.Path.GetDirectoryName(newFilePath);
|
|
while (!System.IO.Directory.Exists(suggestedDirectory))
|
|
{
|
|
suggestedDirectory = System.IO.Path.GetFullPath(suggestedDirectory + "/..");
|
|
Debug.Log($"suggest: {suggestedDirectory}");
|
|
}
|
|
directory = suggestedDirectory;
|
|
fileName = System.IO.Path.GetFileName(newFilePath);
|
|
}
|
|
|
|
newFilePath = EditorUtility.SaveFilePanel(
|
|
"Save baked mesh to file", directory, fileName,
|
|
MetaXRAcousticGeometry.FILE_EXTENSION);
|
|
|
|
// If the user canceled, use the old path.
|
|
if (string.IsNullOrEmpty(newFilePath))
|
|
newFilePath = geo.AbsoluteFilePath;
|
|
else
|
|
pathChanged = true;
|
|
}
|
|
|
|
#if ENABLE_DEBUG_EXPORT_OBJ
|
|
// this allows you to export the geometry to a .obj for viewing
|
|
// in an external model viewer for debugging/validation
|
|
if (GUILayout.Button("Write to .obj (debug)"))
|
|
{
|
|
mesh.WriteToObj();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
} // Advanced Controls
|
|
|
|
using (new EditorGUILayout.HorizontalScope())
|
|
{
|
|
EditorGUILayout.PrefixLabel(" ");
|
|
shouldWriteMesh = GUILayout.Button("Bake Mesh");
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Statistics
|
|
bool isInvalid = geo.VertexCount == 0;
|
|
DateTime timeStamp = DateTime.MinValue;
|
|
EditorGUILayout.LabelField(new GUIContent("Vertices:", "The number of precomputed data points"), new GUIContent(geo.VertexCount.ToString()));
|
|
if (newFilePath != null)
|
|
{
|
|
FileInfo fileInfo = new FileInfo(newFilePath);
|
|
long fileSize = fileInfo.Exists ? fileInfo.Length : 0;
|
|
timeStamp = System.IO.File.GetLastWriteTime(newFilePath);
|
|
isInvalid = isInvalid && (fileSize == 0);
|
|
EditorGUILayout.LabelField(new GUIContent("Data Size:", "The total size of the serialized data"), new GUIContent(MetaXRAcousticMapEditor.GetSizeString(fileSize)));
|
|
}
|
|
if (isInvalid)
|
|
{
|
|
char warning = '\u26A0';
|
|
EditorGUILayout.LabelField($"{warning} Geometry contains no mesh data!", new GUIStyle
|
|
{
|
|
alignment = TextAnchor.MiddleLeft,
|
|
fontStyle = FontStyle.Bold,
|
|
wordWrap = true,
|
|
normal = new GUIStyleState { textColor = Color.yellow },
|
|
});
|
|
}
|
|
else if (needsRebake)
|
|
{
|
|
char warning = '\u24D8';
|
|
EditorGUILayout.LabelField($"{warning} Geometry stale, needs rebake!", new GUIStyle
|
|
{
|
|
alignment = TextAnchor.MiddleLeft,
|
|
fontStyle = FontStyle.Bold,
|
|
wordWrap = true,
|
|
normal = new GUIStyleState { textColor = Color.cyan },
|
|
});
|
|
}
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Undo.RecordObject(geo, "Edited MetaXRAcousticGeometry");
|
|
|
|
geo.IncludeChildMeshes = newIncludeChildMeshes;
|
|
geo.FileEnabled = newFileEnabled;
|
|
geo.EnableSimplification = newEnableMeshSimplification;
|
|
geo.EnableDiffraction = newEnableDiffraction;
|
|
geo.MaxSimplifyError = newMaxSimplifyError;
|
|
geo.MinDiffractionEdgeAngle = newMinDiffractionEdgeAngle;
|
|
geo.MinDiffractionEdgeLength = newMinDiffractionEdgeLength;
|
|
geo.FlagLength = newFlagLength;
|
|
geo.LodSelection = newLODSelection;
|
|
geo.UseColliders = newUseColliders;
|
|
geo.OverrideExcludeTagsEnabled = newOverrideExcludeTagsEnabled;
|
|
if (newOverrideExcludeTags != null)
|
|
geo.OverrideExcludeTags = newOverrideExcludeTags;
|
|
|
|
if (pathChanged)
|
|
{
|
|
string prevPath = geo.AbsoluteFilePath;
|
|
string newRelativeFilePath = newFilePath.Substring(Application.dataPath.Length + 1).Replace('\\', '/');
|
|
if (File.Exists(prevPath) && string.Compare(newRelativeFilePath, geo.RelativeFilePath, true) != 0)
|
|
{
|
|
Debug.Log($"Move/rename Geometry file\n to:\t{newRelativeFilePath} from:\t{geo.RelativeFilePath}\n");
|
|
if (UnityEditor.VersionControl.Provider.isActive)
|
|
{
|
|
UnityEditor.VersionControl.Provider.Move(prevPath, newFilePath);
|
|
}
|
|
else
|
|
{
|
|
File.Move(prevPath, newFilePath);
|
|
if (File.Exists(prevPath + ".meta"))
|
|
File.Move(prevPath + ".meta", newFilePath + ".meta");
|
|
}
|
|
}
|
|
|
|
geo.AbsoluteFilePath = newFilePath;
|
|
}
|
|
|
|
if (pathChanged || shouldWriteMesh)
|
|
{
|
|
if (geo.WriteFile())
|
|
{
|
|
needsRebake = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Application.isPlaying && GUILayout.Button("Upload Mesh"))
|
|
{
|
|
geo.GatherGeometryRuntime();
|
|
}
|
|
}
|
|
public static void Separator()
|
|
{
|
|
GUI.color = new Color(1, 1, 1, 0.25f);
|
|
GUILayout.Box("", "HorizontalSlider", GUILayout.Height(16));
|
|
GUI.color = Color.white;
|
|
}
|
|
}
|