diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.fbx.meta b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.fbx.meta index 2344878..ec07c99 100644 --- a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.fbx.meta +++ b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.fbx.meta @@ -5,7 +5,7 @@ ModelImporter: internalIDToNameTable: [] externalObjects: {} materials: - materialImportMode: 0 + materialImportMode: 2 materialName: 0 materialSearch: 1 materialLocation: 1 @@ -52,7 +52,7 @@ ModelImporter: useFileUnits: 1 keepQuads: 0 weldVertices: 1 - bakeAxisConversion: 0 + bakeAxisConversion: 1 preserveHierarchy: 0 skinWeightsMode: 0 maxBonesPerVertex: 4 @@ -67,7 +67,7 @@ ModelImporter: secondaryUVMinLightmapResolution: 40 secondaryUVMinObjectScale: 1 secondaryUVPackMargin: 4 - useFileScale: 1 + useFileScale: 0 strictVertexDataChecks: 0 tangentSpace: normalSmoothAngle: 60 diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.mat b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.mat index 956d50c..e4f6346 100644 --- a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.mat +++ b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.mat @@ -14,6 +14,7 @@ Material: m_ValidKeywords: - _METALLICSPECGLOSSMAP - _NORMALMAP + - _OCCLUSIONMAP m_InvalidKeywords: [] m_LightmapFlags: 4 m_EnableInstancingVariants: 0 diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.prefab b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.prefab index 5c90c9f..62b14cc 100644 --- a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.prefab +++ b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer.prefab @@ -27,8 +27,8 @@ Transform: m_GameObject: {fileID: 4818435621640061303} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0.02, z: 0} - m_LocalScale: {x: 0.7, y: 0.015, z: 0.7} + m_LocalPosition: {x: 0, y: -0.0000000011313807, z: 0} + m_LocalScale: {x: 0.55, y: 0.012, z: 0.55} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 7751142206369119175} @@ -50,7 +50,7 @@ MeshRenderer: m_GameObject: {fileID: 4818435621640061303} m_Enabled: 1 m_CastShadows: 0 - m_ReceiveShadows: 1 + m_ReceiveShadows: 0 m_DynamicOccludee: 1 m_StaticShadowCaster: 0 m_MotionVectors: 1 @@ -61,7 +61,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 0} + - {fileID: 2100000, guid: 6b337463b30a15d4e9f2e50f5690082b, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -93,23 +93,23 @@ PrefabInstance: m_Modifications: - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalScale.x - value: 1.6454926 + value: 1.6463469 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalScale.y - value: 1.6454926 + value: 1.6463469 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalScale.z - value: 1.6454926 + value: 1.6463469 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalPosition.x - value: -0 + value: 0 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalPosition.y - value: 0 + value: -0.00093483925 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalPosition.z @@ -117,11 +117,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalRotation.w - value: 0.7071067 + value: 0.7071068 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalRotation.x - value: -0.7071068 + value: 0.7071068 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalRotation.y @@ -129,7 +129,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalRotation.z - value: -0 + value: 0 objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3} propertyPath: m_LocalEulerAnglesHint.x diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_Shadow.mat b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_Shadow.mat new file mode 100644 index 0000000..cd4c4de --- /dev/null +++ b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_Shadow.mat @@ -0,0 +1,133 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MaleExplorer_Shadow + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _WorkflowMode: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.12, g: 0.12, b: 0.14, a: 1} + - _Color: {r: 0.11999995, g: 0.11999995, b: 0.13999996, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] +--- !u!114 &323412783105867235 +MonoBehaviour: + m_ObjectHideFlags: 11 + 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: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 7 diff --git a/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_Shadow.mat.meta b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_Shadow.mat.meta new file mode 100644 index 0000000..65407e5 --- /dev/null +++ b/AIClient/Assets/Bundles/Characters/MaleExplorer/MaleExplorer_Shadow.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6b337463b30a15d4e9f2e50f5690082b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Editor/M3/FixAndDiagnoseMaleExplorer.cs b/AIClient/Assets/Editor/M3/FixAndDiagnoseMaleExplorer.cs new file mode 100644 index 0000000..47468cc --- /dev/null +++ b/AIClient/Assets/Editor/M3/FixAndDiagnoseMaleExplorer.cs @@ -0,0 +1,55 @@ +using System.Globalization; +using System.Text; +using UnityEditor; +using UnityEngine; + +public static class FixAndDiagnoseMaleExplorer +{ + public static string Diagnose() + { + const string fbx = "Assets/Bundles/Characters/MaleExplorer/MaleExplorer.fbx"; + var sb = new StringBuilder(); + var importer = AssetImporter.GetAtPath(fbx) as ModelImporter; + if (importer != null) + { + sb.AppendLine($"globalScale={importer.globalScale} useFileScale={importer.useFileScale} " + + $"bakeAxisConversion={importer.bakeAxisConversion} " + + $"meshCompression={importer.meshCompression}"); + } + + foreach (var obj in AssetDatabase.LoadAllAssetsAtPath(fbx)) + { + if (obj is not Mesh mesh) continue; + var vs = mesh.vertices; + var min = vs[0]; + var max = vs[0]; + for (var i = 1; i < vs.Length; i++) + { + min = Vector3.Min(min, vs[i]); + max = Vector3.Max(max, vs[i]); + } + var size = max - min; + sb.AppendLine(string.Format(CultureInfo.InvariantCulture, + "mesh={0} verts={1} min=({2:F6},{3:F6},{4:F6}) max=({5:F6},{6:F6},{7:F6}) size=({8:F6},{9:F6},{10:F6})", + mesh.name, vs.Length, min.x, min.y, min.z, max.x, max.y, max.z, size.x, size.y, size.z)); + } + return sb.ToString(); + } + + public static string FixImportAndPrefab() + { + const string fbx = "Assets/Bundles/Characters/MaleExplorer/MaleExplorer.fbx"; + var importer = AssetImporter.GetAtPath(fbx) as ModelImporter; + if (importer == null) return "no importer"; + + // Blender 已按米导出时,关掉 Unity 默认 0.01 厘米换算 + importer.globalScale = 1f; + importer.useFileScale = false; + importer.bakeAxisConversion = true; + importer.materialImportMode = ModelImporterMaterialImportMode.None; + importer.SaveAndReimport(); + + // 重建 Prefab + return SetupM3Character.SetupAll() + " | " + Diagnose(); + } +} diff --git a/AIClient/Assets/Editor/M3/FixAndDiagnoseMaleExplorer.cs.meta b/AIClient/Assets/Editor/M3/FixAndDiagnoseMaleExplorer.cs.meta new file mode 100644 index 0000000..416b846 --- /dev/null +++ b/AIClient/Assets/Editor/M3/FixAndDiagnoseMaleExplorer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2cbb60d5fbecac4e8270e0acc5afba7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Editor/M3/InspectMaleExplorer.cs b/AIClient/Assets/Editor/M3/InspectMaleExplorer.cs new file mode 100644 index 0000000..8966359 --- /dev/null +++ b/AIClient/Assets/Editor/M3/InspectMaleExplorer.cs @@ -0,0 +1,52 @@ +using System.Text; +using UnityEditor; +using UnityEngine; + +public static class InspectMaleExplorer +{ + public static string Execute() + { + const string path = "Assets/Bundles/Characters/MaleExplorer/MaleExplorer.prefab"; + var prefab = AssetDatabase.LoadAssetAtPath(path); + if (prefab == null) return "prefab null"; + + var go = (GameObject)PrefabUtility.InstantiatePrefab(prefab); + go.name = "MaleExplorer_Inspect"; + go.transform.position = new Vector3(0f, 0f, 2.5f); + + var sb = new StringBuilder(); + sb.AppendLine($"root scale={go.transform.localScale} pos={go.transform.position}"); + foreach (var r in go.GetComponentsInChildren(true)) + { + var mat = r.sharedMaterial; + sb.AppendLine( + $"renderer={r.GetType().Name} path={GetPath(r.transform)} enabled={r.enabled} " + + $"bounds={r.bounds} mat={(mat ? mat.name : "null")} " + + $"shader={(mat && mat.shader ? mat.shader.name : "null")}"); + } + foreach (var mf in go.GetComponentsInChildren(true)) + { + sb.AppendLine( + $"meshFilter={GetPath(mf.transform)} mesh={(mf.sharedMesh ? mf.sharedMesh.name : "null")} " + + $"verts={(mf.sharedMesh ? mf.sharedMesh.vertexCount : 0)}"); + } + foreach (var smr in go.GetComponentsInChildren(true)) + { + sb.AppendLine( + $"skinned={GetPath(smr.transform)} mesh={(smr.sharedMesh ? smr.sharedMesh.name : "null")} " + + $"verts={(smr.sharedMesh ? smr.sharedMesh.vertexCount : 0)}"); + } + return sb.ToString(); + } + + static string GetPath(Transform t) + { + var p = t.name; + while (t.parent != null) + { + t = t.parent; + p = t.name + "/" + p; + } + return p; + } +} diff --git a/AIClient/Assets/Editor/M3/InspectMaleExplorer.cs.meta b/AIClient/Assets/Editor/M3/InspectMaleExplorer.cs.meta new file mode 100644 index 0000000..9d05d00 --- /dev/null +++ b/AIClient/Assets/Editor/M3/InspectMaleExplorer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 67665e6ccf39f084db66b0fcb9db296c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Editor/M3/InspectMaleExplorerFinal.cs b/AIClient/Assets/Editor/M3/InspectMaleExplorerFinal.cs new file mode 100644 index 0000000..82260f3 --- /dev/null +++ b/AIClient/Assets/Editor/M3/InspectMaleExplorerFinal.cs @@ -0,0 +1,31 @@ +using System.Globalization; +using System.Text; +using UnityEditor; +using UnityEngine; + +public static class InspectMaleExplorerFinal +{ + public static string Execute() + { + const string path = "Assets/Bundles/Characters/MaleExplorer/MaleExplorer.prefab"; + var prefab = AssetDatabase.LoadAssetAtPath(path); + var go = (GameObject)PrefabUtility.InstantiatePrefab(prefab); + go.transform.position = new Vector3(0f, go.transform.position.y, 2.5f); + var sb = new StringBuilder(); + sb.AppendLine(string.Format(CultureInfo.InvariantCulture, + "root pos={0} rot={1} scale={2}", + go.transform.position, go.transform.eulerAngles, go.transform.localScale)); + foreach (var r in go.GetComponentsInChildren(true)) + { + if (r.name == "ShadowDisc") continue; + var b = r.bounds; + sb.AppendLine(string.Format(CultureInfo.InvariantCulture, + "{0} bounds center=({1:F3},{2:F3},{3:F3}) size=({4:F3},{5:F3},{6:F3}) mat={7} shader={8}", + r.name, b.center.x, b.center.y, b.center.z, b.size.x, b.size.y, b.size.z, + r.sharedMaterial ? r.sharedMaterial.name : "null", + r.sharedMaterial && r.sharedMaterial.shader ? r.sharedMaterial.shader.name : "null")); + } + Object.DestroyImmediate(go); + return sb.ToString(); + } +} diff --git a/AIClient/Assets/Editor/M3/InspectMaleExplorerFinal.cs.meta b/AIClient/Assets/Editor/M3/InspectMaleExplorerFinal.cs.meta new file mode 100644 index 0000000..91e1a9d --- /dev/null +++ b/AIClient/Assets/Editor/M3/InspectMaleExplorerFinal.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 738db76e9c64f9f4e8098e561a800597 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Editor/M3/InspectMaleExplorerMesh.cs b/AIClient/Assets/Editor/M3/InspectMaleExplorerMesh.cs new file mode 100644 index 0000000..96e59cf --- /dev/null +++ b/AIClient/Assets/Editor/M3/InspectMaleExplorerMesh.cs @@ -0,0 +1,47 @@ +using System.Text; +using UnityEditor; +using UnityEngine; + +public static class InspectMaleExplorerMesh +{ + public static string Execute() + { + const string fbx = "Assets/Bundles/Characters/MaleExplorer/MaleExplorer.fbx"; + const string prefabPath = "Assets/Bundles/Characters/MaleExplorer/MaleExplorer.prefab"; + var sb = new StringBuilder(); + + foreach (var obj in AssetDatabase.LoadAllAssetsAtPath(fbx)) + { + if (obj is Mesh mesh) + { + sb.AppendLine( + $"assetMesh={mesh.name} verts={mesh.vertexCount} bounds={mesh.bounds} " + + $"tris={mesh.triangles.Length / 3}"); + } + } + + var prefab = AssetDatabase.LoadAssetAtPath(prefabPath); + var go = (GameObject)PrefabUtility.InstantiatePrefab(prefab); + go.transform.position = Vector3.zero; + go.transform.localScale = Vector3.one; + foreach (var mf in go.GetComponentsInChildren(true)) + { + var m = mf.sharedMesh; + if (m == null) continue; + sb.AppendLine($"filter={mf.name} localScale={mf.transform.lossyScale} meshBounds={m.bounds} worldBounds={mf.GetComponent().bounds}"); + // sample a few verts + var vs = m.vertices; + var min = vs[0]; + var max = vs[0]; + for (int i = 1; i < vs.Length; i++) + { + min = Vector3.Min(min, vs[i]); + max = Vector3.Max(max, vs[i]); + } + sb.AppendLine($"vertMin={min} vertMax={max} size={max - min}"); + } + + Object.DestroyImmediate(go); + return sb.ToString(); + } +} diff --git a/AIClient/Assets/Editor/M3/InspectMaleExplorerMesh.cs.meta b/AIClient/Assets/Editor/M3/InspectMaleExplorerMesh.cs.meta new file mode 100644 index 0000000..5800818 --- /dev/null +++ b/AIClient/Assets/Editor/M3/InspectMaleExplorerMesh.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 31f77e98524d70941a004800305764f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Editor/M3/RebuildMaleExplorerNow.cs b/AIClient/Assets/Editor/M3/RebuildMaleExplorerNow.cs new file mode 100644 index 0000000..3d602e3 --- /dev/null +++ b/AIClient/Assets/Editor/M3/RebuildMaleExplorerNow.cs @@ -0,0 +1,15 @@ +using UnityEditor; +using UnityEngine; + +public static class RebuildMaleExplorerNow +{ + public static string Execute() + { + foreach (var go in Object.FindObjectsOfType()) + { + if (go != null && go.name.Contains("MaleExplorer")) + Object.DestroyImmediate(go); + } + return SetupM3Character.SetupAll(); + } +} diff --git a/AIClient/Assets/Editor/M3/RebuildMaleExplorerNow.cs.meta b/AIClient/Assets/Editor/M3/RebuildMaleExplorerNow.cs.meta new file mode 100644 index 0000000..6db65f8 --- /dev/null +++ b/AIClient/Assets/Editor/M3/RebuildMaleExplorerNow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f063866d20ac6894f9667aad85ef937a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Editor/M3/SetupM3Character.cs b/AIClient/Assets/Editor/M3/SetupM3Character.cs index 6388882..5a7772e 100644 --- a/AIClient/Assets/Editor/M3/SetupM3Character.cs +++ b/AIClient/Assets/Editor/M3/SetupM3Character.cs @@ -64,6 +64,10 @@ public static class SetupM3Character var model = AssetImporter.GetAtPath(FbxPath) as ModelImporter; if (model != null) { + // Blender 按米导出;FBX 文件单位常带 0.01,useFileScale 会把角色缩成 ~1cm + model.globalScale = 1f; + model.useFileScale = false; + model.bakeAxisConversion = true; // XPbr:保留 externalObjects 材质重映射;无 .mat 时再 None model.materialImportMode = File.Exists(MatPath) ? ModelImporterMaterialImportMode.ImportViaMaterialDescription @@ -154,36 +158,93 @@ public static class SetupM3Character foreach (var renderer in instance.GetComponentsInChildren()) renderer.sharedMaterial = mat; - // 落地参考盘 - var ground = GameObject.CreatePrimitive(PrimitiveType.Cylinder); - ground.name = "ShadowDisc"; - ground.transform.SetParent(instance.transform, false); - ground.transform.localPosition = new Vector3(0f, 0.02f, 0f); - ground.transform.localScale = new Vector3(0.7f, 0.015f, 0.7f); - Object.DestroyImmediate(ground.GetComponent()); - var gMat = new Material(urpLit != null ? urpLit : shader); - if (gMat.HasProperty("_BaseColor")) gMat.SetColor("_BaseColor", new Color(0.12f, 0.12f, 0.14f, 1f)); - if (gMat.HasProperty("_Color")) gMat.color = new Color(0.12f, 0.12f, 0.14f, 1f); - ground.GetComponent().sharedMaterial = gMat; - ground.GetComponent().shadowCastingMode = ShadowCastingMode.Off; + // Blender/混元 FBX:身高常在本地 Z。转到 Unity Y-up,并面向 -Z(相机常见朝向)。 + UprightBlenderMesh(instance); - // 粗略归一化身高约 1.8m - var bounds = new Bounds(instance.transform.position, Vector3.zero); - var renderers = instance.GetComponentsInChildren(); - foreach (var r in renderers) - { - if (r.name == "ShadowDisc") continue; - bounds.Encapsulate(r.bounds); - } - if (bounds.size.y > 0.01f) - { - var scale = 1.8f / bounds.size.y; - instance.transform.localScale = Vector3.one * scale; - } + // 落地参考盘(扶正定标后再放) + PlaceShadowDisc(instance, urpLit != null ? urpLit : shader); PrefabUtility.SaveAsPrefabAsset(instance, PrefabPath); Object.DestroyImmediate(instance); - return PrefabPath; + return PrefabPath + (useXpbr ? " (XPbr)" : " (URP Lit)"); + } + + static void UprightBlenderMesh(GameObject instance) + { + instance.transform.localPosition = Vector3.zero; + instance.transform.localScale = Vector3.one; + // 混元/Blender:头在 +Z。Unity 用 +90°X 扶正;Y=0 使正面朝向相机(-Z)。 + instance.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); + + var bounds = EncapsulateMeshBounds(instance); + if (bounds.size.y < 0.001f) + { + if (bounds.size.z >= bounds.size.x) + instance.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); + else + instance.transform.localRotation = Quaternion.Euler(0f, 0f, 90f); + bounds = EncapsulateMeshBounds(instance); + } + + if (bounds.size.y > 0.001f) + instance.transform.localScale = Vector3.one * (1.8f / bounds.size.y); + + bounds = EncapsulateMeshBounds(instance); + instance.transform.position = new Vector3(0f, -bounds.min.y, 0f); + } + + static Bounds EncapsulateMeshBounds(GameObject root) + { + Bounds bounds = default; + var has = false; + foreach (var r in root.GetComponentsInChildren()) + { + if (r.name == "ShadowDisc") continue; + if (!has) + { + bounds = r.bounds; + has = true; + } + else bounds.Encapsulate(r.bounds); + } + return has ? bounds : new Bounds(root.transform.position, Vector3.one * 0.01f); + } + + static void PlaceShadowDisc(GameObject instance, Shader shader) + { + var existing = instance.transform.Find("ShadowDisc"); + if (existing != null) + Object.DestroyImmediate(existing.gameObject); + + const string shadowMatPath = ActorRoot + "/" + ActorName + "_Shadow.mat"; + var gMat = AssetDatabase.LoadAssetAtPath(shadowMatPath); + if (gMat == null) + { + gMat = new Material(shader); + AssetDatabase.CreateAsset(gMat, shadowMatPath); + } + else gMat.shader = shader; + if (gMat.HasProperty("_BaseColor")) gMat.SetColor("_BaseColor", new Color(0.12f, 0.12f, 0.14f, 1f)); + if (gMat.HasProperty("_Color")) gMat.color = new Color(0.12f, 0.12f, 0.14f, 1f); + // 不透明,避免 URP 透明洋红 + if (gMat.HasProperty("_Surface")) gMat.SetFloat("_Surface", 0f); + gMat.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); + gMat.renderQueue = -1; + EditorUtility.SetDirty(gMat); + + var ground = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + ground.name = "ShadowDisc"; + ground.transform.SetParent(instance.transform, false); + var bounds = EncapsulateMeshBounds(instance); + var localY = instance.transform.InverseTransformPoint(new Vector3(0f, bounds.min.y + 0.02f, 0f)).y; + ground.transform.localPosition = new Vector3(0f, localY, 0f); + ground.transform.localRotation = Quaternion.identity; + ground.transform.localScale = new Vector3(0.55f, 0.012f, 0.55f); + Object.DestroyImmediate(ground.GetComponent()); + var mr = ground.GetComponent(); + mr.sharedMaterial = gMat; + mr.shadowCastingMode = ShadowCastingMode.Off; + mr.receiveShadows = false; } static string EnsureBillboardPrefab() diff --git a/AIClient/Assets/HotUpdate/Scripts/CharacterSpawner.cs b/AIClient/Assets/HotUpdate/Scripts/CharacterSpawner.cs index 11507e0..c80e4c1 100644 --- a/AIClient/Assets/HotUpdate/Scripts/CharacterSpawner.cs +++ b/AIClient/Assets/HotUpdate/Scripts/CharacterSpawner.cs @@ -67,26 +67,26 @@ namespace HotUpdate _instance = Instantiate(prefab); _instance.name = "MaleExplorer_Runtime"; - _instance.transform.position = new Vector3(0f, 0f, 2.5f); + var y = _instance.transform.position.y; + _instance.transform.position = new Vector3(0f, y, 2.5f); DontDestroyOnLoad(_instance); - // 简易朝向相机 - var billboard = _instance.GetComponentInChildren(); - if (billboard != null && Camera.main != null) + // 仅对概念图 Billboard 子节点做朝向;真 3D 网格不要转,否则会拧成纸片 + var billboardTf = _instance.transform.Find("Billboard"); + if (billboardTf != null && Camera.main != null) { - var t = billboard.transform; var cam = Camera.main.transform; - var dir = cam.position - t.position; + var dir = cam.position - billboardTf.position; dir.y = 0f; if (dir.sqrMagnitude > 0.001f) - t.rotation = Quaternion.LookRotation(-dir.normalized); + billboardTf.rotation = Quaternion.LookRotation(-dir.normalized); } // 调整主相机看向角色(竖屏) if (Camera.main != null) { var cam = Camera.main; - cam.transform.position = new Vector3(0f, 1.4f, -1.2f); + cam.transform.position = new Vector3(0f, 1.2f, -2.2f); cam.transform.rotation = Quaternion.Euler(8f, 0f, 0f); cam.fieldOfView = 50f; cam.backgroundColor = new Color(0.45f, 0.62f, 0.78f); diff --git a/Tools/model_tools/unity_assets.py b/Tools/model_tools/unity_assets.py index 2d949f4..d701c97 100644 --- a/Tools/model_tools/unity_assets.py +++ b/Tools/model_tools/unity_assets.py @@ -265,7 +265,7 @@ ModelImporter: useFileUnits: 1 keepQuads: 0 weldVertices: 1 - bakeAxisConversion: 0 + bakeAxisConversion: 1 preserveHierarchy: 0 skinWeightsMode: 0 maxBonesPerVertex: 4 @@ -280,7 +280,7 @@ ModelImporter: secondaryUVMinLightmapResolution: 40 secondaryUVMinObjectScale: 1 secondaryUVPackMargin: 4 - useFileScale: 1 + useFileScale: 0 strictVertexDataChecks: 0 tangentSpace: normalSmoothAngle: 60