Fix MaleExplorer setup with shadow material and editor diagnostics.
Improve FBX/prefab import setup, CharacterSpawner, and add M3 inspect/rebuild helpers. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,7 +5,7 @@ ModelImporter:
|
|||||||
internalIDToNameTable: []
|
internalIDToNameTable: []
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
materials:
|
materials:
|
||||||
materialImportMode: 0
|
materialImportMode: 2
|
||||||
materialName: 0
|
materialName: 0
|
||||||
materialSearch: 1
|
materialSearch: 1
|
||||||
materialLocation: 1
|
materialLocation: 1
|
||||||
@@ -52,7 +52,7 @@ ModelImporter:
|
|||||||
useFileUnits: 1
|
useFileUnits: 1
|
||||||
keepQuads: 0
|
keepQuads: 0
|
||||||
weldVertices: 1
|
weldVertices: 1
|
||||||
bakeAxisConversion: 0
|
bakeAxisConversion: 1
|
||||||
preserveHierarchy: 0
|
preserveHierarchy: 0
|
||||||
skinWeightsMode: 0
|
skinWeightsMode: 0
|
||||||
maxBonesPerVertex: 4
|
maxBonesPerVertex: 4
|
||||||
@@ -67,7 +67,7 @@ ModelImporter:
|
|||||||
secondaryUVMinLightmapResolution: 40
|
secondaryUVMinLightmapResolution: 40
|
||||||
secondaryUVMinObjectScale: 1
|
secondaryUVMinObjectScale: 1
|
||||||
secondaryUVPackMargin: 4
|
secondaryUVPackMargin: 4
|
||||||
useFileScale: 1
|
useFileScale: 0
|
||||||
strictVertexDataChecks: 0
|
strictVertexDataChecks: 0
|
||||||
tangentSpace:
|
tangentSpace:
|
||||||
normalSmoothAngle: 60
|
normalSmoothAngle: 60
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Material:
|
|||||||
m_ValidKeywords:
|
m_ValidKeywords:
|
||||||
- _METALLICSPECGLOSSMAP
|
- _METALLICSPECGLOSSMAP
|
||||||
- _NORMALMAP
|
- _NORMALMAP
|
||||||
|
- _OCCLUSIONMAP
|
||||||
m_InvalidKeywords: []
|
m_InvalidKeywords: []
|
||||||
m_LightmapFlags: 4
|
m_LightmapFlags: 4
|
||||||
m_EnableInstancingVariants: 0
|
m_EnableInstancingVariants: 0
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ Transform:
|
|||||||
m_GameObject: {fileID: 4818435621640061303}
|
m_GameObject: {fileID: 4818435621640061303}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0.02, z: 0}
|
m_LocalPosition: {x: 0, y: -0.0000000011313807, z: 0}
|
||||||
m_LocalScale: {x: 0.7, y: 0.015, z: 0.7}
|
m_LocalScale: {x: 0.55, y: 0.012, z: 0.55}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 7751142206369119175}
|
m_Father: {fileID: 7751142206369119175}
|
||||||
@@ -50,7 +50,7 @@ MeshRenderer:
|
|||||||
m_GameObject: {fileID: 4818435621640061303}
|
m_GameObject: {fileID: 4818435621640061303}
|
||||||
m_Enabled: 1
|
m_Enabled: 1
|
||||||
m_CastShadows: 0
|
m_CastShadows: 0
|
||||||
m_ReceiveShadows: 1
|
m_ReceiveShadows: 0
|
||||||
m_DynamicOccludee: 1
|
m_DynamicOccludee: 1
|
||||||
m_StaticShadowCaster: 0
|
m_StaticShadowCaster: 0
|
||||||
m_MotionVectors: 1
|
m_MotionVectors: 1
|
||||||
@@ -61,7 +61,7 @@ MeshRenderer:
|
|||||||
m_RenderingLayerMask: 1
|
m_RenderingLayerMask: 1
|
||||||
m_RendererPriority: 0
|
m_RendererPriority: 0
|
||||||
m_Materials:
|
m_Materials:
|
||||||
- {fileID: 0}
|
- {fileID: 2100000, guid: 6b337463b30a15d4e9f2e50f5690082b, type: 2}
|
||||||
m_StaticBatchInfo:
|
m_StaticBatchInfo:
|
||||||
firstSubMesh: 0
|
firstSubMesh: 0
|
||||||
subMeshCount: 0
|
subMeshCount: 0
|
||||||
@@ -93,23 +93,23 @@ PrefabInstance:
|
|||||||
m_Modifications:
|
m_Modifications:
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalScale.x
|
propertyPath: m_LocalScale.x
|
||||||
value: 1.6454926
|
value: 1.6463469
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalScale.y
|
propertyPath: m_LocalScale.y
|
||||||
value: 1.6454926
|
value: 1.6463469
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalScale.z
|
propertyPath: m_LocalScale.z
|
||||||
value: 1.6454926
|
value: 1.6463469
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalPosition.x
|
propertyPath: m_LocalPosition.x
|
||||||
value: -0
|
value: 0
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalPosition.y
|
propertyPath: m_LocalPosition.y
|
||||||
value: 0
|
value: -0.00093483925
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalPosition.z
|
propertyPath: m_LocalPosition.z
|
||||||
@@ -117,11 +117,11 @@ PrefabInstance:
|
|||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalRotation.w
|
propertyPath: m_LocalRotation.w
|
||||||
value: 0.7071067
|
value: 0.7071068
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalRotation.x
|
propertyPath: m_LocalRotation.x
|
||||||
value: -0.7071068
|
value: 0.7071068
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalRotation.y
|
propertyPath: m_LocalRotation.y
|
||||||
@@ -129,7 +129,7 @@ PrefabInstance:
|
|||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalRotation.z
|
propertyPath: m_LocalRotation.z
|
||||||
value: -0
|
value: 0
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
- target: {fileID: -8679921383154817045, guid: 4e7306923b3941041b15fc08a96215f4, type: 3}
|
||||||
propertyPath: m_LocalEulerAnglesHint.x
|
propertyPath: m_LocalEulerAnglesHint.x
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6b337463b30a15d4e9f2e50f5690082b
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b2cbb60d5fbecac4e8270e0acc5afba7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -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<GameObject>(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<Renderer>(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<MeshFilter>(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<SkinnedMeshRenderer>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 67665e6ccf39f084db66b0fcb9db296c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -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<GameObject>(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<Renderer>(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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 738db76e9c64f9f4e8098e561a800597
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -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<GameObject>(prefabPath);
|
||||||
|
var go = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
|
||||||
|
go.transform.position = Vector3.zero;
|
||||||
|
go.transform.localScale = Vector3.one;
|
||||||
|
foreach (var mf in go.GetComponentsInChildren<MeshFilter>(true))
|
||||||
|
{
|
||||||
|
var m = mf.sharedMesh;
|
||||||
|
if (m == null) continue;
|
||||||
|
sb.AppendLine($"filter={mf.name} localScale={mf.transform.lossyScale} meshBounds={m.bounds} worldBounds={mf.GetComponent<Renderer>().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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 31f77e98524d70941a004800305764f6
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public static class RebuildMaleExplorerNow
|
||||||
|
{
|
||||||
|
public static string Execute()
|
||||||
|
{
|
||||||
|
foreach (var go in Object.FindObjectsOfType<GameObject>())
|
||||||
|
{
|
||||||
|
if (go != null && go.name.Contains("MaleExplorer"))
|
||||||
|
Object.DestroyImmediate(go);
|
||||||
|
}
|
||||||
|
return SetupM3Character.SetupAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f063866d20ac6894f9667aad85ef937a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -64,6 +64,10 @@ public static class SetupM3Character
|
|||||||
var model = AssetImporter.GetAtPath(FbxPath) as ModelImporter;
|
var model = AssetImporter.GetAtPath(FbxPath) as ModelImporter;
|
||||||
if (model != null)
|
if (model != null)
|
||||||
{
|
{
|
||||||
|
// Blender 按米导出;FBX 文件单位常带 0.01,useFileScale 会把角色缩成 ~1cm
|
||||||
|
model.globalScale = 1f;
|
||||||
|
model.useFileScale = false;
|
||||||
|
model.bakeAxisConversion = true;
|
||||||
// XPbr:保留 externalObjects 材质重映射;无 .mat 时再 None
|
// XPbr:保留 externalObjects 材质重映射;无 .mat 时再 None
|
||||||
model.materialImportMode = File.Exists(MatPath)
|
model.materialImportMode = File.Exists(MatPath)
|
||||||
? ModelImporterMaterialImportMode.ImportViaMaterialDescription
|
? ModelImporterMaterialImportMode.ImportViaMaterialDescription
|
||||||
@@ -154,36 +158,93 @@ public static class SetupM3Character
|
|||||||
foreach (var renderer in instance.GetComponentsInChildren<Renderer>())
|
foreach (var renderer in instance.GetComponentsInChildren<Renderer>())
|
||||||
renderer.sharedMaterial = mat;
|
renderer.sharedMaterial = mat;
|
||||||
|
|
||||||
// 落地参考盘
|
// Blender/混元 FBX:身高常在本地 Z。转到 Unity Y-up,并面向 -Z(相机常见朝向)。
|
||||||
var ground = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
UprightBlenderMesh(instance);
|
||||||
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<Collider>());
|
|
||||||
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<MeshRenderer>().sharedMaterial = gMat;
|
|
||||||
ground.GetComponent<MeshRenderer>().shadowCastingMode = ShadowCastingMode.Off;
|
|
||||||
|
|
||||||
// 粗略归一化身高约 1.8m
|
// 落地参考盘(扶正定标后再放)
|
||||||
var bounds = new Bounds(instance.transform.position, Vector3.zero);
|
PlaceShadowDisc(instance, urpLit != null ? urpLit : shader);
|
||||||
var renderers = instance.GetComponentsInChildren<Renderer>();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrefabUtility.SaveAsPrefabAsset(instance, PrefabPath);
|
PrefabUtility.SaveAsPrefabAsset(instance, PrefabPath);
|
||||||
Object.DestroyImmediate(instance);
|
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<Renderer>())
|
||||||
|
{
|
||||||
|
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<Material>(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<Collider>());
|
||||||
|
var mr = ground.GetComponent<MeshRenderer>();
|
||||||
|
mr.sharedMaterial = gMat;
|
||||||
|
mr.shadowCastingMode = ShadowCastingMode.Off;
|
||||||
|
mr.receiveShadows = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string EnsureBillboardPrefab()
|
static string EnsureBillboardPrefab()
|
||||||
|
|||||||
@@ -67,26 +67,26 @@ namespace HotUpdate
|
|||||||
|
|
||||||
_instance = Instantiate(prefab);
|
_instance = Instantiate(prefab);
|
||||||
_instance.name = "MaleExplorer_Runtime";
|
_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);
|
DontDestroyOnLoad(_instance);
|
||||||
|
|
||||||
// 简易朝向相机
|
// 仅对概念图 Billboard 子节点做朝向;真 3D 网格不要转,否则会拧成纸片
|
||||||
var billboard = _instance.GetComponentInChildren<MeshRenderer>();
|
var billboardTf = _instance.transform.Find("Billboard");
|
||||||
if (billboard != null && Camera.main != null)
|
if (billboardTf != null && Camera.main != null)
|
||||||
{
|
{
|
||||||
var t = billboard.transform;
|
|
||||||
var cam = Camera.main.transform;
|
var cam = Camera.main.transform;
|
||||||
var dir = cam.position - t.position;
|
var dir = cam.position - billboardTf.position;
|
||||||
dir.y = 0f;
|
dir.y = 0f;
|
||||||
if (dir.sqrMagnitude > 0.001f)
|
if (dir.sqrMagnitude > 0.001f)
|
||||||
t.rotation = Quaternion.LookRotation(-dir.normalized);
|
billboardTf.rotation = Quaternion.LookRotation(-dir.normalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调整主相机看向角色(竖屏)
|
// 调整主相机看向角色(竖屏)
|
||||||
if (Camera.main != null)
|
if (Camera.main != null)
|
||||||
{
|
{
|
||||||
var cam = Camera.main;
|
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.transform.rotation = Quaternion.Euler(8f, 0f, 0f);
|
||||||
cam.fieldOfView = 50f;
|
cam.fieldOfView = 50f;
|
||||||
cam.backgroundColor = new Color(0.45f, 0.62f, 0.78f);
|
cam.backgroundColor = new Color(0.45f, 0.62f, 0.78f);
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ ModelImporter:
|
|||||||
useFileUnits: 1
|
useFileUnits: 1
|
||||||
keepQuads: 0
|
keepQuads: 0
|
||||||
weldVertices: 1
|
weldVertices: 1
|
||||||
bakeAxisConversion: 0
|
bakeAxisConversion: 1
|
||||||
preserveHierarchy: 0
|
preserveHierarchy: 0
|
||||||
skinWeightsMode: 0
|
skinWeightsMode: 0
|
||||||
maxBonesPerVertex: 4
|
maxBonesPerVertex: 4
|
||||||
@@ -280,7 +280,7 @@ ModelImporter:
|
|||||||
secondaryUVMinLightmapResolution: 40
|
secondaryUVMinLightmapResolution: 40
|
||||||
secondaryUVMinObjectScale: 1
|
secondaryUVMinObjectScale: 1
|
||||||
secondaryUVPackMargin: 4
|
secondaryUVPackMargin: 4
|
||||||
useFileScale: 1
|
useFileScale: 0
|
||||||
strictVertexDataChecks: 0
|
strictVertexDataChecks: 0
|
||||||
tangentSpace:
|
tangentSpace:
|
||||||
normalSmoothAngle: 60
|
normalSmoothAngle: 60
|
||||||
|
|||||||
Reference in New Issue
Block a user