From 68182d7764b5207d54d6c750becf29bb3a1a1637 Mon Sep 17 00:00:00 2001 From: BobSong <605277374@qq.com> Date: Sat, 26 Jul 2025 20:12:34 +0800 Subject: [PATCH] =?UTF-8?q?=E7=82=B9=E5=AF=B9=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/Editor/MeshAssetObjExporter.cs | 78 +++++++++++++++++++ .../Editor/MeshAssetObjExporter.cs.meta | 3 + .../Editor/Preview/PreviewEditWindow.cs | 41 +++++++--- Assets/Scripts/Editor/RemoveMissingScripts.cs | 75 ++++++++++++++++-- .../Editor/ReplaceStandardShaderWithURP.cs | 2 +- Assets/Scripts/UI/Common/ModelRenderImage.cs | 6 +- Assets/Scripts/UI/Common/ModelTexture.cs | 16 +++- Assets/Scripts/Utils/ModelUtils.cs | 27 +++++++ Assets/Scripts/Utils/ModelUtils.cs.meta | 3 + UserSettings/EditorUserSettings.asset | 20 ++--- UserSettings/HDRPUserSettings.asset | 20 +++++ 11 files changed, 253 insertions(+), 38 deletions(-) create mode 100644 Assets/Scripts/Editor/MeshAssetObjExporter.cs create mode 100644 Assets/Scripts/Editor/MeshAssetObjExporter.cs.meta create mode 100644 Assets/Scripts/Utils/ModelUtils.cs create mode 100644 Assets/Scripts/Utils/ModelUtils.cs.meta create mode 100644 UserSettings/HDRPUserSettings.asset diff --git a/Assets/Scripts/Editor/MeshAssetObjExporter.cs b/Assets/Scripts/Editor/MeshAssetObjExporter.cs new file mode 100644 index 000000000..b34102724 --- /dev/null +++ b/Assets/Scripts/Editor/MeshAssetObjExporter.cs @@ -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()); + } +} diff --git a/Assets/Scripts/Editor/MeshAssetObjExporter.cs.meta b/Assets/Scripts/Editor/MeshAssetObjExporter.cs.meta new file mode 100644 index 000000000..e8ec05cf5 --- /dev/null +++ b/Assets/Scripts/Editor/MeshAssetObjExporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b31d593151854995a593d8ed391e8941 +timeCreated: 1751770498 \ No newline at end of file diff --git a/Assets/Scripts/Editor/Preview/PreviewEditWindow.cs b/Assets/Scripts/Editor/Preview/PreviewEditWindow.cs index 70f715a4b..b02a1011b 100644 --- a/Assets/Scripts/Editor/Preview/PreviewEditWindow.cs +++ b/Assets/Scripts/Editor/Preview/PreviewEditWindow.cs @@ -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(); 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; diff --git a/Assets/Scripts/Editor/RemoveMissingScripts.cs b/Assets/Scripts/Editor/RemoveMissingScripts.cs index 2a89f3c61..e1e784f26 100644 --- a/Assets/Scripts/Editor/RemoveMissingScripts.cs +++ b/Assets/Scripts/Editor/RemoveMissingScripts.cs @@ -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(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; } } \ No newline at end of file diff --git a/Assets/Scripts/Editor/ReplaceStandardShaderWithURP.cs b/Assets/Scripts/Editor/ReplaceStandardShaderWithURP.cs index 747d493c2..cbaac8e46 100644 --- a/Assets/Scripts/Editor/ReplaceStandardShaderWithURP.cs +++ b/Assets/Scripts/Editor/ReplaceStandardShaderWithURP.cs @@ -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(SelectionMode.Assets); diff --git a/Assets/Scripts/UI/Common/ModelRenderImage.cs b/Assets/Scripts/UI/Common/ModelRenderImage.cs index bcfb2acf5..f9b0dbfc7 100644 --- a/Assets/Scripts/UI/Common/ModelRenderImage.cs +++ b/Assets/Scripts/UI/Common/ModelRenderImage.cs @@ -192,9 +192,7 @@ namespace NBF this.UnloadModel(); _model = model.transform; _model.SetParent(this.modelRoot, false); - var h = CalculateModelHeight(model); //计算包围盒高度 - var pos = _model.localPosition; - _model.localPosition = new Vector3(pos.x, pos.y - h * 0.5f, pos.z); + _model.AlignmentParentCenter(); } public void UnloadModel() @@ -250,7 +248,7 @@ namespace NBF _renderTexture = new RenderTexture(_width, _height, 24, RenderTextureFormat.ARGB32) { - antiAliasing = 1, + antiAliasing = 2, filterMode = FilterMode.Bilinear, anisoLevel = 0, useMipMap = false diff --git a/Assets/Scripts/UI/Common/ModelTexture.cs b/Assets/Scripts/UI/Common/ModelTexture.cs index cf92982ac..7611ac16e 100644 --- a/Assets/Scripts/UI/Common/ModelTexture.cs +++ b/Assets/Scripts/UI/Common/ModelTexture.cs @@ -17,6 +17,8 @@ namespace NBF private SwipeGesture _swipeGesture; private bool _focus; + private bool _canZoom; + private bool _canPan; private Vector3 _zoomLimit; private Rect _panLimit; @@ -83,15 +85,19 @@ namespace NBF { _zoomLimit = previewableAsset.zoom; _panLimit = previewableAsset.pan; - model.transform.localPosition = previewableAsset.position; + _canPan = previewableAsset.canPan; + _canZoom = previewableAsset.canZoom; + // model.transform.localPosition = previewableAsset.position; model.transform.localScale = previewableAsset.scale; model.transform.localRotation = Quaternion.Euler(previewableAsset.rotation); } else { + _canPan = false; + _canZoom = false; _zoomLimit = Vector3.zero; _panLimit = Rect.zero; - model.transform.localPosition = previewableAsset.position; + // model.transform.localPosition = previewableAsset.position; model.transform.localScale = Vector3.one; model.transform.localRotation = Quaternion.Euler(Vector3.zero); } @@ -135,11 +141,12 @@ namespace NBF v.y = 0; if (Mathf.Abs(v.z) < 1) //消除手抖影响 v.z = 0; + _renderImage.StartRotate(v); } - else + else if (_canPan) { - v.y = -gesture.delta.y * 0.005f; + v.y = gesture.delta.y * 0.005f; v.x = gesture.delta.x * 0.005f; //平移 var pos = _renderImage.modelRoot.localPosition; @@ -170,6 +177,7 @@ namespace NBF private void OnMouseWheel(EventContext context) { + if (!_canZoom) return; if (!_focus) return; float delta = context.inputEvent.mouseWheelDelta / Stage.devicePixelRatio; SetZoom(delta * 0.2f); diff --git a/Assets/Scripts/Utils/ModelUtils.cs b/Assets/Scripts/Utils/ModelUtils.cs new file mode 100644 index 000000000..980afccc9 --- /dev/null +++ b/Assets/Scripts/Utils/ModelUtils.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +namespace NBF +{ + public static class ModelUtils + { + public static void AlignmentParentCenter(this Transform transform) + { + // 获取子物体所有渲染器的边界 + Renderer[] renderers = transform.GetComponentsInChildren(); + Bounds bounds = new Bounds(transform.transform.position, Vector3.zero); + foreach (Renderer renderer in renderers) + { + bounds.Encapsulate(renderer.bounds); + } + + Vector3 center = bounds.center; + + // 将子物体设为父对象的子物体 + transform.transform.SetParent(transform.parent.transform); + + // 计算偏移量并调整位置 + Vector3 offset = center - transform.parent.transform.position; + transform.transform.localPosition = -offset; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Utils/ModelUtils.cs.meta b/Assets/Scripts/Utils/ModelUtils.cs.meta new file mode 100644 index 000000000..d95751e46 --- /dev/null +++ b/Assets/Scripts/Utils/ModelUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 11d82f3861f442f3a96a5cdee975bc04 +timeCreated: 1750947982 \ No newline at end of file diff --git a/UserSettings/EditorUserSettings.asset b/UserSettings/EditorUserSettings.asset index 6fb98ad3e..432ed6201 100644 --- a/UserSettings/EditorUserSettings.asset +++ b/UserSettings/EditorUserSettings.asset @@ -9,32 +9,32 @@ EditorUserSettings: value: 18134705175a055722080a3115371d4a0d55006876786860616b0471b8b07a68ffab74f9ee2a3a30300cea1a11320d0beb1a0c25f7060f494b4cc80018eb09361fc211cb1f862d19c51d19dcc413d6ade0d8ddfcddf9f4d9d29195fcfde6ebeae6f0a9c9afa6f8c5b89ff7a1aacececac4eba4d7c9d28bda flags: 0 RecentlyUsedSceneGuid-0: - value: 06540050040c085a5e0b0d7741755d44454f4b732d7e75607e2b4a67b5b6316a - flags: 0 - RecentlyUsedSceneGuid-1: value: 5302565f50030d0f0f595f2315250944444e4c2c2e797562742c4a32b3b16c3b flags: 0 - RecentlyUsedSceneGuid-2: + RecentlyUsedSceneGuid-1: value: 0704555600540b5d58575c73427b59444515407879792766752b4c66e1b9613e flags: 0 - RecentlyUsedSceneGuid-3: + RecentlyUsedSceneGuid-2: value: 0152510407025f025d0b5f77477706444315482e2f7970602c7a4c62e3b96d6a flags: 0 - RecentlyUsedSceneGuid-4: + RecentlyUsedSceneGuid-3: value: 025005075d000f0c095c0f7145730b4447161e2c787923327a7c4965e0b66669 flags: 0 - RecentlyUsedSceneGuid-5: + RecentlyUsedSceneGuid-4: value: 5703055552020f5a595608704870594445151d7e29292233782f1b36e0e6366c flags: 0 - RecentlyUsedSceneGuid-6: + RecentlyUsedSceneGuid-5: value: 5309035757065a0a54575f7216265c4444151d28792e72627d2f1935bbb8673a flags: 0 - RecentlyUsedSceneGuid-7: + RecentlyUsedSceneGuid-6: value: 020056535456585e0f0d0a7541210d441215482c2d297f36752c1b65b3b0376e flags: 0 - RecentlyUsedSceneGuid-8: + RecentlyUsedSceneGuid-7: value: 020801035c53500a580c0f7145700c4444164d2e797d7f332c704963b0b06260 flags: 0 + RecentlyUsedSceneGuid-8: + value: 5a09065056055c0e595d0a20447b0b4415164e2b297c75682f7c1866b0b3656c + flags: 0 RecentlyUsedSceneGuid-9: value: 5505015f5c515a085f5b092149760f441716407a787d7564287b1b36e7e1366e flags: 0 diff --git a/UserSettings/HDRPUserSettings.asset b/UserSettings/HDRPUserSettings.asset new file mode 100644 index 000000000..1f491a259 --- /dev/null +++ b/UserSettings/HDRPUserSettings.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 53 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 88da235ee80df394e99ee865506eb9e0, type: 3} + m_Name: + m_EditorClassIdentifier: + m_WizardPopupAlreadyShownOnce: 0 + m_WizardNeedRestartAfterChangingToDX12: 0 + m_WizardNeedToRunFixAllAgainAfterDomainReload: 0 + m_WizardFixAllAfterDomainReloadInclusiveMode: 0 + m_WizardPopupAtStart: 1 + m_OpenConfigs: 01000000