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: []
|
||||
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
|
||||
|
||||
@@ -14,6 +14,7 @@ Material:
|
||||
m_ValidKeywords:
|
||||
- _METALLICSPECGLOSSMAP
|
||||
- _NORMALMAP
|
||||
- _OCCLUSIONMAP
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
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>())
|
||||
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<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;
|
||||
// Blender/混元 FBX:身高常在本地 Z。转到 Unity Y-up,并面向 -Z(相机常见朝向)。
|
||||
UprightBlenderMesh(instance);
|
||||
|
||||
// 粗略归一化身高约 1.8m
|
||||
var bounds = new Bounds(instance.transform.position, Vector3.zero);
|
||||
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;
|
||||
}
|
||||
// 落地参考盘(扶正定标后再放)
|
||||
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<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()
|
||||
|
||||
@@ -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<MeshRenderer>();
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user