Formalize material-driven panoramic skybox path

This commit is contained in:
2026-04-06 00:39:08 +08:00
parent 8151be0f45
commit 66a6818b89
18 changed files with 860 additions and 82 deletions

View File

@@ -1,8 +1,13 @@
#pragma once
#include <XCEngine/Components/Component.h>
#include <XCEngine/Core/Asset/AssetRef.h>
#include <XCEngine/Core/Asset/ResourceHandle.h>
#include <XCEngine/Core/Math/Color.h>
#include <XCEngine/Core/Math/Rect.h>
#include <XCEngine/Resources/Material/Material.h>
#include <string>
namespace XCEngine {
namespace Components {
@@ -67,6 +72,14 @@ public:
bool IsSkyboxEnabled() const { return m_skyboxEnabled; }
void SetSkyboxEnabled(bool value) { m_skyboxEnabled = value; }
const Resources::ResourceHandle<Resources::Material>& GetSkyboxMaterialHandle() const { return m_skyboxMaterial; }
Resources::Material* GetSkyboxMaterial() const { return m_skyboxMaterial.Get(); }
const std::string& GetSkyboxMaterialPath() const { return m_skyboxMaterialPath; }
const Resources::AssetRef& GetSkyboxMaterialAssetRef() const { return m_skyboxMaterialRef; }
void SetSkyboxMaterialPath(const std::string& materialPath);
void SetSkyboxMaterial(const Resources::ResourceHandle<Resources::Material>& material);
void SetSkyboxMaterial(Resources::Material* material);
const Math::Color& GetSkyboxTopColor() const { return m_skyboxTopColor; }
void SetSkyboxTopColor(const Math::Color& value) { m_skyboxTopColor = value; }
@@ -93,6 +106,9 @@ private:
Math::Rect m_viewportRect = Math::Rect(0.0f, 0.0f, 1.0f, 1.0f);
Math::Color m_clearColor = Math::Color(0.192f, 0.302f, 0.475f, 1.0f);
bool m_skyboxEnabled = false;
Resources::ResourceHandle<Resources::Material> m_skyboxMaterial;
std::string m_skyboxMaterialPath;
Resources::AssetRef m_skyboxMaterialRef;
Math::Color m_skyboxTopColor = Math::Color(0.18f, 0.36f, 0.74f, 1.0f);
Math::Color m_skyboxHorizonColor = Math::Color(0.78f, 0.84f, 0.92f, 1.0f);
Math::Color m_skyboxBottomColor = Math::Color(0.92f, 0.93f, 0.95f, 1.0f);

View File

@@ -4,12 +4,19 @@
#include <cstdint>
namespace XCEngine {
namespace Resources {
class Material;
} // namespace Resources
} // namespace XCEngine
namespace XCEngine {
namespace Rendering {
enum class RenderEnvironmentMode : uint32_t {
None = 0,
ProceduralSkybox
ProceduralSkybox,
MaterialSkybox
};
struct ProceduralSkyboxData {
@@ -18,13 +25,30 @@ struct ProceduralSkyboxData {
Math::Color bottomColor = Math::Color(0.92f, 0.93f, 0.95f, 1.0f);
};
struct MaterialSkyboxData {
const Resources::Material* material = nullptr;
bool IsValid() const {
return material != nullptr;
}
};
struct RenderEnvironmentData {
RenderEnvironmentMode mode = RenderEnvironmentMode::None;
ProceduralSkyboxData skybox = {};
MaterialSkyboxData materialSkybox = {};
bool HasProceduralSkybox() const {
return mode == RenderEnvironmentMode::ProceduralSkybox;
}
bool HasMaterialSkybox() const {
return mode == RenderEnvironmentMode::MaterialSkybox && materialSkybox.IsValid();
}
bool HasSkybox() const {
return HasProceduralSkybox() || HasMaterialSkybox();
}
};
} // namespace Rendering

View File

@@ -16,6 +16,12 @@ struct BuiltinForwardMaterialData {
Math::Vector4 baseColorFactor = Math::Vector4::One();
};
struct BuiltinSkyboxMaterialData {
Math::Vector4 tint = Math::Vector4::One();
float exposure = 1.0f;
float rotationDegrees = 0.0f;
};
struct MaterialConstantLayoutView {
const Resources::MaterialConstantFieldDesc* fields = nullptr;
size_t count = 0;
@@ -134,6 +140,129 @@ inline BuiltinForwardMaterialData BuildBuiltinForwardMaterialData(const Resource
return data;
}
inline const Resources::Texture* ResolveSkyboxTexture(const Resources::Material* material) {
if (material == nullptr) {
return nullptr;
}
if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "SkyboxTexture")) {
const Resources::ResourceHandle<Resources::Texture> textureHandle = material->GetTexture(property->name);
if (textureHandle.Get() != nullptr && textureHandle->IsValid()) {
return textureHandle.Get();
}
}
static const char* kSkyboxTexturePropertyNames[] = {
"_MainTex",
"_PanoramicTex",
"_SkyboxTexture",
"panoramicTexture",
"skyboxTexture",
"texture"
};
for (const char* propertyName : kSkyboxTexturePropertyNames) {
const Resources::ResourceHandle<Resources::Texture> textureHandle =
material->GetTexture(Containers::String(propertyName));
if (textureHandle.Get() != nullptr && textureHandle->IsValid()) {
return textureHandle.Get();
}
}
return nullptr;
}
inline Math::Vector4 ResolveSkyboxTint(const Resources::Material* material) {
if (material == nullptr) {
return Math::Vector4::One();
}
if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "Tint")) {
if (material->HasProperty(property->name) &&
(property->type == Resources::ShaderPropertyType::Color ||
property->type == Resources::ShaderPropertyType::Vector)) {
return material->GetFloat4(property->name);
}
}
static const char* kTintPropertyNames[] = {
"_Tint",
"tint",
"_Color",
"color"
};
for (const char* propertyName : kTintPropertyNames) {
if (material->HasProperty(Containers::String(propertyName))) {
return material->GetFloat4(Containers::String(propertyName));
}
}
return Math::Vector4::One();
}
inline float ResolveSkyboxExposure(const Resources::Material* material) {
if (material == nullptr) {
return 1.0f;
}
if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "Exposure")) {
if (material->HasProperty(property->name) &&
(property->type == Resources::ShaderPropertyType::Float ||
property->type == Resources::ShaderPropertyType::Range)) {
return material->GetFloat(property->name);
}
}
static const char* kExposurePropertyNames[] = {
"_Exposure",
"exposure"
};
for (const char* propertyName : kExposurePropertyNames) {
if (material->HasProperty(Containers::String(propertyName))) {
return material->GetFloat(Containers::String(propertyName));
}
}
return 1.0f;
}
inline float ResolveSkyboxRotationDegrees(const Resources::Material* material) {
if (material == nullptr) {
return 0.0f;
}
if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "Rotation")) {
if (material->HasProperty(property->name) &&
(property->type == Resources::ShaderPropertyType::Float ||
property->type == Resources::ShaderPropertyType::Range)) {
return material->GetFloat(property->name);
}
}
static const char* kRotationPropertyNames[] = {
"_Rotation",
"rotation"
};
for (const char* propertyName : kRotationPropertyNames) {
if (material->HasProperty(Containers::String(propertyName))) {
return material->GetFloat(Containers::String(propertyName));
}
}
return 0.0f;
}
inline BuiltinSkyboxMaterialData BuildBuiltinSkyboxMaterialData(const Resources::Material* material) {
BuiltinSkyboxMaterialData data = {};
data.tint = ResolveSkyboxTint(material);
data.exposure = ResolveSkyboxExposure(material);
data.rotationDegrees = ResolveSkyboxRotationDegrees(material);
return data;
}
inline MaterialConstantPayloadView ResolveSchemaMaterialConstantPayload(const Resources::Material* material) {
if (material == nullptr || material->GetShader() == nullptr) {
return {};

View File

@@ -109,6 +109,11 @@ private:
Math::Vector4 cameraForwardAndUnused = Math::Vector4::Zero();
};
struct SkyboxMaterialConstants {
Math::Vector4 tintAndExposure = Math::Vector4(1.0f, 1.0f, 1.0f, 1.0f);
Math::Vector4 rotationRadiansAndMode = Math::Vector4::Zero();
};
struct PassLayoutKey {
const Resources::Shader* shader = nullptr;
Containers::String passName;
@@ -243,9 +248,11 @@ private:
void DestroyPassResourceLayout(PassResourceLayout& passLayout);
const Resources::Texture* ResolveTexture(const Resources::Material* material) const;
RHI::RHIResourceView* ResolveTextureView(const Resources::Texture* texture);
RHI::RHIResourceView* ResolveTextureView(const VisibleRenderItem& visibleItem);
static LightingConstants BuildLightingConstants(const RenderLightingData& lightingData);
static AdditionalLightConstants BuildAdditionalLightConstants(const RenderAdditionalLightData& lightData);
bool HasSkybox(const RenderSceneData& sceneData) const;
bool HasProceduralSkybox(const RenderSceneData& sceneData) const;
bool BeginForwardScenePass(const RenderPassContext& context);
void EndForwardScenePass(const RenderPassContext& context);
@@ -282,8 +289,11 @@ private:
RHI::RHIResourceView* m_fallbackTextureView = nullptr;
RHI::RHIPipelineLayout* m_skyboxPipelineLayout = nullptr;
RHI::RHIPipelineState* m_skyboxPipelineState = nullptr;
RHI::RHIDescriptorPool* m_skyboxConstantPool = nullptr;
RHI::RHIDescriptorSet* m_skyboxConstantSet = nullptr;
OwnedDescriptorSet m_skyboxEnvironmentSet = {};
OwnedDescriptorSet m_skyboxMaterialSet = {};
OwnedDescriptorSet m_skyboxTextureSet = {};
OwnedDescriptorSet m_skyboxSamplerSet = {};
RHI::RHIResourceView* m_skyboxBoundTextureView = nullptr;
RenderPassSequence m_passSequence;
};