点对点

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);

View File

@@ -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

View File

@@ -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);

View 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;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 11d82f3861f442f3a96a5cdee975bc04
timeCreated: 1750947982

View File

@@ -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

View 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