点对点
This commit is contained in:
78
Assets/Scripts/Editor/MeshAssetObjExporter.cs
Normal file
78
Assets/Scripts/Editor/MeshAssetObjExporter.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Editor/MeshAssetObjExporter.cs.meta
Normal file
3
Assets/Scripts/Editor/MeshAssetObjExporter.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b31d593151854995a593d8ed391e8941
|
||||
timeCreated: 1751770498
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
27
Assets/Scripts/Utils/ModelUtils.cs
Normal file
27
Assets/Scripts/Utils/ModelUtils.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
public static class ModelUtils
|
||||
{
|
||||
public static void AlignmentParentCenter(this Transform transform)
|
||||
{
|
||||
// 获取子物体所有渲染器的边界
|
||||
Renderer[] renderers = transform.GetComponentsInChildren<Renderer>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Utils/ModelUtils.cs.meta
Normal file
3
Assets/Scripts/Utils/ModelUtils.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11d82f3861f442f3a96a5cdee975bc04
|
||||
timeCreated: 1750947982
|
||||
@@ -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
|
||||
|
||||
20
UserSettings/HDRPUserSettings.asset
Normal file
20
UserSettings/HDRPUserSettings.asset
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user