148 lines
5.8 KiB
C#
148 lines
5.8 KiB
C#
#if UNITY_EDITOR
|
|
using System.IO;
|
|
using UnityEditor;
|
|
using UnityEditor.SceneManagement;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
/// <summary>
|
|
/// 历史 Explorer / LmCat 观察场景,保留旧 -Z 资产及相机方向;项目新资源采用 +Z 正面。
|
|
/// unity command run_script --file AgentScripts/BuildModelView.cs --entry BuildModelView.Run
|
|
/// </summary>
|
|
public static class BuildModelView
|
|
{
|
|
const string SceneDir = "Assets/Bundles/Scenes/Test/ModelView";
|
|
const string ScenePath = SceneDir + "/ModelView.unity";
|
|
const string GroundMatPath = SceneDir + "/Ground.mat";
|
|
const string GirlPath = "Assets/Bundles/Characters/Human/Explorer/Explorer.prefab";
|
|
const string CatPath = "Assets/Bundles/Characters/Animal/LmCat/LmCat.prefab";
|
|
|
|
public static string Run()
|
|
{
|
|
var girl = AssetDatabase.LoadAssetAtPath<GameObject>(GirlPath);
|
|
var cat = AssetDatabase.LoadAssetAtPath<GameObject>(CatPath);
|
|
if (girl == null)
|
|
return "missing " + GirlPath;
|
|
if (cat == null)
|
|
return "missing " + CatPath;
|
|
|
|
Directory.CreateDirectory(SceneDir);
|
|
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
|
|
|
var lightGo = new GameObject("Directional Light");
|
|
var light = lightGo.AddComponent<Light>();
|
|
light.type = LightType.Directional;
|
|
light.color = new Color(1f, 0.96f, 0.9f);
|
|
light.intensity = 1.2f;
|
|
light.shadows = LightShadows.Soft;
|
|
lightGo.transform.rotation = Quaternion.Euler(48f, -25f, 0f);
|
|
|
|
var groundMat = AssetDatabase.LoadAssetAtPath<Material>(GroundMatPath);
|
|
if (groundMat == null)
|
|
{
|
|
var shader = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard");
|
|
groundMat = new Material(shader);
|
|
groundMat.color = new Color(0.82f, 0.84f, 0.86f);
|
|
AssetDatabase.CreateAsset(groundMat, GroundMatPath);
|
|
}
|
|
|
|
var ground = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
|
ground.name = "Ground";
|
|
ground.transform.localScale = new Vector3(14f, 1f, 14f);
|
|
ground.GetComponent<MeshRenderer>().sharedMaterial = groundMat;
|
|
|
|
var houses = PlaceHouses();
|
|
|
|
var girlGo = (GameObject)PrefabUtility.InstantiatePrefab(girl);
|
|
girlGo.name = "Explorer";
|
|
girlGo.transform.SetPositionAndRotation(new Vector3(-1.6f, 0f, -36f), Quaternion.identity);
|
|
|
|
var catGo = (GameObject)PrefabUtility.InstantiatePrefab(cat);
|
|
catGo.name = "LmCat";
|
|
catGo.transform.SetPositionAndRotation(new Vector3(1.6f, 0f, -36f), Quaternion.identity);
|
|
|
|
var bounds = RendererBounds(girlGo);
|
|
bounds.Encapsulate(RendererBounds(catGo));
|
|
foreach (var house in houses)
|
|
bounds.Encapsulate(RendererBounds(house));
|
|
var camGo = new GameObject("Main Camera");
|
|
camGo.tag = "MainCamera";
|
|
var cam = camGo.AddComponent<Camera>();
|
|
cam.clearFlags = CameraClearFlags.SolidColor;
|
|
cam.backgroundColor = new Color(0.93f, 0.94f, 0.95f);
|
|
cam.fieldOfView = 32f;
|
|
cam.nearClipPlane = 0.1f;
|
|
cam.farClipPlane = 250f;
|
|
camGo.AddComponent<AudioListener>();
|
|
|
|
var center = bounds.center;
|
|
var halfFov = cam.fieldOfView * 0.5f * Mathf.Deg2Rad;
|
|
var distY = bounds.size.y / (2f * Mathf.Tan(halfFov) * 0.62f);
|
|
var aspect = 16f / 9f;
|
|
var halfFovX = Mathf.Atan(Mathf.Tan(halfFov) * aspect);
|
|
var distX = bounds.size.x / (2f * Mathf.Tan(halfFovX) * 0.72f);
|
|
var dist = Mathf.Max(distY, distX);
|
|
var camPos = center + new Vector3(0f, bounds.size.z * 0.36f, -dist * 1.08f);
|
|
camGo.transform.position = camPos;
|
|
camGo.transform.LookAt(center);
|
|
|
|
RenderSettings.ambientMode = AmbientMode.Trilight;
|
|
RenderSettings.ambientSkyColor = new Color(0.55f, 0.58f, 0.62f);
|
|
RenderSettings.ambientEquatorColor = new Color(0.42f, 0.42f, 0.42f);
|
|
RenderSettings.ambientGroundColor = new Color(0.28f, 0.28f, 0.28f);
|
|
|
|
EditorSceneManager.SaveScene(scene, ScenePath);
|
|
return $"scene={ScenePath} houses={houses.Count} girlH={Height(girlGo):F2} catH={Height(catGo):F2} cam={camPos}";
|
|
}
|
|
|
|
static System.Collections.Generic.List<GameObject> PlaceHouses()
|
|
{
|
|
var names = new[]
|
|
{
|
|
"cream_tile", "cream_red", "white_balcony", "brown_wood",
|
|
"cream_porch", "stone_balcony", "thatched", "white_blue",
|
|
"wood_fence", "shop_awning", "picket", "gate",
|
|
};
|
|
var placed = new System.Collections.Generic.List<GameObject>();
|
|
const float gap = 22f;
|
|
for (var i = 0; i < names.Length; i++)
|
|
{
|
|
var path = $"Assets/Bundles/Scenes/Test/LmHouses/{names[i]}/{names[i]}.prefab";
|
|
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
|
|
if (prefab == null)
|
|
continue;
|
|
var col = i % 4;
|
|
var row = i / 4;
|
|
var go = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
|
|
go.name = names[i];
|
|
go.transform.SetPositionAndRotation(
|
|
new Vector3((col - 1.5f) * gap, 0f, (row - 1f) * gap),
|
|
Quaternion.identity);
|
|
placed.Add(go);
|
|
}
|
|
return placed;
|
|
}
|
|
|
|
static Bounds RendererBounds(GameObject root)
|
|
{
|
|
Bounds bounds = default;
|
|
var has = false;
|
|
foreach (var r in root.GetComponentsInChildren<Renderer>())
|
|
{
|
|
if (!has)
|
|
{
|
|
bounds = r.bounds;
|
|
has = true;
|
|
}
|
|
else bounds.Encapsulate(r.bounds);
|
|
}
|
|
return has ? bounds : new Bounds(root.transform.position, Vector3.one);
|
|
}
|
|
|
|
static float Height(GameObject root)
|
|
{
|
|
return RendererBounds(root).size.y;
|
|
}
|
|
}
|
|
#endif
|