Environment settings become scene entities (UE Skybox/SkyLight semantics)

Skybox/SkyLight are now Actor-carried components instead of resident
global settings, matching UE where SkyAtmosphere/SkyLight/fog are
Actors added from Place Actors and configured in Details.

- New SkyboxComponent (active + envPath asset slot) and SkyLightComponent
  (active + ambientColor); first-active entity wins per frame
- SceneRenderer collects env from components into FrameSceneData
  (DrawSkybox/envPath/ambient); Renderer performs delta sync - env
  reloads only when the resolved path changes, neutral fallback when
  empty or unloadable
- App-side env plumbing removed: kEnvPaths table and getEnvIndex/
  setEnvIndex callbacks deleted; StatsPanel keeps ClearColor + debug
  view, env params move to Details
- Serializer: scene-level Settings stores ClearColor only; env
  components serialize per entity; legacy v1 scenes (Environment header
  + Settings.AmbientColor/DrawSkybox) auto-migrate into an Environment
  entity on load for visual parity
- Inspector: Skybox/Sky Light sections with .hdr asset slot dropdown
  and Add Component entries; Outliner "+ Create" popup offers
  Empty/Light/Camera/Environment
This commit is contained in:
2026-10-05 01:02:21 +08:00
parent b7d6f53591
commit 432089747f
14 changed files with 317 additions and 144 deletions
+3 -39
View File
@@ -108,9 +108,8 @@ void Editor::DoStop()
{
if (!m_Ctx.scene || !m_Ctx.assets || !m_Ctx.renderer) return;
std::string envPath;
if (!Serialization::SceneSerializer::DeserializeFromString(
*m_Ctx.scene, *m_Ctx.assets, m_PlaySnapshot, envPath))
*m_Ctx.scene, *m_Ctx.assets, m_PlaySnapshot))
{
ENGINE_ERROR("PIE: snapshot restore failed (scene is now the "
"played-out state)");
@@ -445,16 +444,8 @@ void Editor::DoSaveScene()
std::filesystem::create_directories(
std::filesystem::path(path).parent_path(), ec);
// 环境路径:引擎序列化器只认字符串,查表由编辑器侧负责
std::string envPath;
if (m_Ctx.getEnvIndex)
{
const int idx = m_Ctx.getEnvIndex();
if (idx >= 0 && idx < kEnvCount) envPath = kEnvPaths[idx];
}
if (Serialization::SceneSerializer::Serialize(*m_Ctx.scene, *m_Ctx.assets,
path, envPath))
path))
{
ENGINE_INFO("Editor: scene saved to '{}'", path);
}
@@ -472,10 +463,8 @@ void Editor::DoLoadScene()
return;
}
std::string envPath;
if (!Serialization::SceneSerializer::Deserialize(*m_Ctx.scene,
*m_Ctx.assets, path,
envPath))
*m_Ctx.assets, path))
{
ENGINE_ERROR("Editor: failed to load scene '{}'", path);
return;
@@ -484,29 +473,4 @@ void Editor::DoLoadScene()
// 旧实体已销毁:清选中(连带清描边,见 SelectEntity)
SelectEntity(entt::null);
// 环境恢复:场景带环境且命中环境表才切换(镜像 StatsPanel 同步路径)
if (!envPath.empty() && m_Ctx.getEnvIndex && m_Ctx.setEnvIndex)
{
int found = -1;
for (int i = 0; i < kEnvCount; ++i)
{
if (envPath == kEnvPaths[i]) { found = i; break; }
}
if (found >= 0)
{
m_Ctx.setEnvIndex(found);
const auto env = m_Ctx.assets->LoadEnvironment(kEnvPaths[found]);
if (env.Valid())
{
m_Ctx.renderer->SetEnvironment(
m_Ctx.assets->GetEnvironment(env));
}
}
else
{
ENGINE_WARN("Editor: scene env '{}' not in env table, "
"keeping current", envPath);
}
}
}