点对点

This commit is contained in:
2025-07-26 20:12:34 +08:00
parent 4febfadd56
commit 68182d7764
11 changed files with 253 additions and 38 deletions

View File

@@ -0,0 +1,78 @@
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Text;
public class MeshAssetObjExporter
{
[MenuItem("Assets/Export Mesh (.asset) to OBJ", true)]
static bool ValidateExport()
{
return Selection.activeObject is Mesh;
}
[MenuItem("Assets/Export Mesh (.asset) to OBJ")]
static void ExportMeshAssetToObj()
{
Mesh mesh = Selection.activeObject as Mesh;
if (mesh == null)
{
Debug.LogWarning("Please select a Mesh .asset file in the Project window.");
return;
}
string path = EditorUtility.SaveFilePanel("Export OBJ", "", mesh.name + ".obj", "obj");
if (string.IsNullOrEmpty(path)) return;
ExportMeshToObj(mesh, path);
Debug.Log("Mesh exported to: " + path);
}
static Vector3 ConvertToBlender(Vector3 v)
{
// Unity坐标 (X, Y, Z) → Blender坐标 (X, Z, -Y)
return new Vector3(v.x, v.z, -v.y);
}
static void ExportMeshToObj(Mesh mesh, string path)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("# Exported from Unity MeshAssetObjExporter");
sb.AppendLine("g " + mesh.name);
// 顶点
foreach (Vector3 v in mesh.vertices)
{
Vector3 vBlender = ConvertToBlender(v);
sb.AppendFormat("v {0} {1} {2}\n", vBlender.x, vBlender.y, vBlender.z);
}
// 法线
foreach (Vector3 n in mesh.normals)
{
Vector3 nBlender = ConvertToBlender(n);
sb.AppendFormat("vn {0} {1} {2}\n", nBlender.x, nBlender.y, nBlender.z);
}
// UV
foreach (Vector2 uv in mesh.uv)
{
sb.AppendFormat("vt {0} {1}\n", uv.x, uv.y);
}
// 面
for (int i = 0; i < mesh.subMeshCount; i++)
{
int[] tris = mesh.GetTriangles(i);
for (int j = 0; j < tris.Length; j += 3)
{
int a = tris[j] + 1;
int b = tris[j + 1] + 1;
int c = tris[j + 2] + 1;
sb.AppendFormat("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", a, b, c);
}
}
File.WriteAllText(path, sb.ToString());
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b31d593151854995a593d8ed391e8941
timeCreated: 1751770498

View File

@@ -183,7 +183,7 @@ public class RuntimePreviewEditor : EditorWindow
// 编辑Transform
var newPosition = EditorGUILayout.Vector3Field("位置", runtimeInstance.transform.localPosition);
var newRotation = EditorGUILayout.Vector3Field("旋转", runtimeInstance.transform.localEulerAngles);
var newRotation = EditorGUILayout.Vector3Field("旋转", runtimeInstance.transform.parent.localEulerAngles);
var newScale = EditorGUILayout.Vector3Field("形变", runtimeInstance.transform.localScale);
@@ -202,28 +202,45 @@ public class RuntimePreviewEditor : EditorWindow
// 应用Transform修改
if (EditorGUI.EndChangeCheck())
{
runtimeInstance.transform.localPosition = newPosition;
runtimeInstance.transform.localEulerAngles = newRotation;
runtimeInstance.transform.localPosition = new Vector3(newPosition.x, newPosition.y, 0);
runtimeInstance.transform.parent.localEulerAngles = newRotation;
runtimeInstance.transform.localScale = newScale;
runtimePreviewableAsset.position = newPosition;
runtimePreviewableAsset.position = new Vector3(newPosition.x, newPosition.y, 0);
runtimePreviewableAsset.rotation = newRotation;
runtimePreviewableAsset.scale = newScale;
runtimePreviewableAsset.canZoom = canZoom;
runtimePreviewableAsset.canPan = canPan;
var pos = runtimeInstance.transform.parent.localPosition;
if (canZoom)
{
if (!Mathf.Approximately(runtimeInstance.transform.localPosition.z,
runtimePreviewableAsset.zoom.z))
if (!Mathf.Approximately(pos.z, runtimePreviewableAsset.zoom.z))
{
var pos = runtimeInstance.transform.localPosition;
runtimeInstance.transform.localPosition = new Vector3(pos.x, pos.y, runtimePreviewableAsset.zoom.z);
runtimeInstance.transform.parent.localPosition =
new Vector3(pos.x, pos.y, runtimePreviewableAsset.zoom.z);
}
}
else
{
runtimeInstance.transform.localPosition = Vector3.zero;
runtimeInstance.transform.parent.localPosition = new Vector3(pos.x, pos.y, 0);
}
// if (canZoom)
// {
// if (!Mathf.Approximately(runtimeInstance.transform.localPosition.z,
// runtimePreviewableAsset.zoom.z))
// {
// var pos = runtimeInstance.transform.parent.localPosition;
// runtimeInstance.transform.parent.localPosition =
// new Vector3(pos.x, pos.y, runtimePreviewableAsset.zoom.z);
// }
// }
// else
// {
// runtimeInstance.transform.parent.localPosition = Vector3.zero;
// }
}
EditorGUILayout.Space();
@@ -309,9 +326,9 @@ public class RuntimePreviewEditor : EditorWindow
var previewableAsset = prefab.GetComponent<PreviewableAsset>();
if (previewableAsset && runtimePreviewableAsset)
{
previewableAsset.position = runtimeInstance.transform.localPosition;
previewableAsset.rotation = runtimeInstance.transform.localEulerAngles;
previewableAsset.scale = runtimeInstance.transform.localScale;
previewableAsset.position = runtimePreviewableAsset.position;
previewableAsset.rotation = runtimePreviewableAsset.rotation;
previewableAsset.scale = runtimePreviewableAsset.scale;
previewableAsset.canPan = runtimePreviewableAsset.canPan;
previewableAsset.canZoom = runtimePreviewableAsset.canZoom;
previewableAsset.zoom = runtimePreviewableAsset.zoom;

View File

@@ -1,15 +1,16 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
public class RemoveMissingScripts
{
[MenuItem("Tools/Remove Hierarchy Missing Scripts")]
[MenuItem("Tools/Remove Missing Scripts/From Selected Objects in Hierarchy")]
private static void RemoveMissingScriptsFromSelection()
{
// 获取选中的对象
GameObject[] selectedObjects = Selection.gameObjects;
if (selectedObjects.Length == 0)
{
Debug.LogWarning("No objects selected in Hierarchy.");
@@ -17,33 +18,93 @@ public class RemoveMissingScripts
}
int totalRemoved = 0;
// 遍历所有选中的对象
foreach (GameObject go in selectedObjects)
{
// 包括所有子对象
int removed = RemoveMissingScriptsRecursively(go);
totalRemoved += removed;
Debug.Log($"Removed {removed} missing scripts from {go.name} and its children.");
}
Debug.Log($"Total removed missing scripts: {totalRemoved}");
}
[MenuItem("Tools/Remove Missing Scripts/From Prefabs in Selected Folder")]
private static void RemoveMissingScriptsFromPrefabsInFolder()
{
// 获取选中的文件夹
string[] selectedFolderGUIDs = Selection.assetGUIDs;
if (selectedFolderGUIDs.Length == 0)
{
Debug.LogWarning("No folder selected in Project window.");
return;
}
string folderPath = AssetDatabase.GUIDToAssetPath(selectedFolderGUIDs[0]);
if (!AssetDatabase.IsValidFolder(folderPath))
{
Debug.LogWarning("Selected asset is not a folder.");
return;
}
// 查找所有预制件
string[] prefabPaths = Directory.GetFiles(folderPath, "*.prefab", SearchOption.AllDirectories);
if (prefabPaths.Length == 0)
{
Debug.LogWarning("No prefabs found in selected folder.");
return;
}
int totalRemoved = 0;
int processedPrefabs = 0;
// 处理每个预制件
foreach (string path in prefabPaths)
{
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
if (prefab != null)
{
// 创建预制件的实例
GameObject instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
// 移除缺失脚本
int removed = RemoveMissingScriptsRecursively(instance);
totalRemoved += removed;
if (removed > 0)
{
// 应用修改到预制件
PrefabUtility.SaveAsPrefabAsset(instance, path);
Debug.Log($"Removed {removed} missing scripts from prefab: {path}");
}
// 销毁实例
Object.DestroyImmediate(instance);
processedPrefabs++;
}
}
Debug.Log($"Processed {processedPrefabs} prefabs. Total removed missing scripts: {totalRemoved}");
}
private static int RemoveMissingScriptsRecursively(GameObject gameObject)
{
int removedCount = 0;
// 处理当前对象
removedCount += GameObjectUtility.RemoveMonoBehavioursWithMissingScript(gameObject);
// 递归处理所有子对象
foreach (Transform child in gameObject.transform)
{
removedCount += RemoveMissingScriptsRecursively(child.gameObject);
}
return removedCount;
}
}

View File

@@ -3,7 +3,7 @@ using UnityEditor;
public class ReplaceStandardShaderWithURP : Editor
{
[MenuItem("Tools/Replace Standard Shader with URP")]
[MenuItem("Tools/一键转换Standard为URP材质")]
private static void ReplaceShadersInSelectedMaterials()
{
Material[] selectedMaterials = Selection.GetFiltered<Material>(SelectionMode.Assets);