// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #include "SkyLight.h" #include "Engine/Core/Log.h" #include "Engine/Platform/FileSystem.h" #include "Engine/Graphics/RenderView.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/Textures/TextureData.h" #include "Engine/Renderer/RenderList.h" #include "Engine/Renderer/ProbesRenderer.h" #include "Engine/Content/Content.h" #include "Engine/Serialization/Serialization.h" #include "Engine/ContentImporters/AssetsImportingManager.h" #include "Engine/Level/Scene/Scene.h" SkyLight::SkyLight(const SpawnParams& params) : Light(params) , _radius(1000000.0f) { _drawNoCulling = 1; Brightness = 2.0f; UpdateBounds(); } void SkyLight::SetRadius(float value) { value = Math::Max(0.0f, value); if (Math::NearEqual(value, _radius)) return; _radius = value; UpdateBounds(); } float SkyLight::GetScaledRadius() const { return _radius * _transform.Scale.MaxValue(); } CubeTexture* SkyLight::GetSource() const { if (Mode == Modes::CaptureScene) return _bakedProbe; if (Mode == Modes::CustomTexture) return CustomTexture.Get(); return nullptr; } void SkyLight::Bake(float timeout) { ProbesRenderer::Bake(this, timeout); } void SkyLight::SetProbeData(TextureData& data) { // Validate input data ASSERT(data.GetArraySize() == 6); // Check if was using custom probe if (Mode == Modes::CustomTexture) { // Set Mode = Modes::CaptureScene; _bakedProbe = nullptr; } Guid id = Guid::New(); #if COMPILE_WITH_ASSETS_IMPORTER // Create asset file const String path = GetScene()->GetDataFolderPath() / TEXT("SkyLights/") / GetID().ToString(Guid::FormatType::N) + ASSET_FILES_EXTENSION_WITH_DOT; AssetInfo info; if (FileSystem::FileExists(path) && Content::GetAssetInfo(path, info)) id = info.ID; if (AssetsImportingManager::Create(AssetsImportingManager::CreateCubeTextureTag, path, id, &data)) { LOG(Error, "Cannot import generated sky light!"); return; } #else // TODO: create or reuse virtual texture and use it LOG(Error, "Changing probes at runtime in game is not supported."); return; #endif // Check if has loaded probe and it has different ID if (_bakedProbe && _bakedProbe->GetID() != id) { const auto prevId = _bakedProbe->GetID(); _bakedProbe = nullptr; LOG(Warning, "New sku light cube texture has different ID={0} than old one={1}.", id, prevId); } // Link probe texture _bakedProbe = Content::LoadAsync(id); } void SkyLight::UpdateBounds() { _sphere = BoundingSphere(GetPosition(), GetScaledRadius()); BoundingBox::FromSphere(_sphere, _box); } void SkyLight::Draw(RenderContext& renderContext) { float brightness = Brightness; AdjustBrightness(renderContext.View, brightness); const Float3 position = GetPosition() - renderContext.View.Origin; if ((renderContext.View.Flags & ViewFlags::SkyLights) != 0 && renderContext.View.Pass & DrawPass::GBuffer && brightness > ZeroTolerance && (ViewDistance < ZeroTolerance || Vector3::DistanceSquared(renderContext.View.Position, position) < ViewDistance * ViewDistance)) { RendererSkyLightData data; data.Position = position; data.Color = Color.ToFloat3() * (Color.A * brightness); data.VolumetricScatteringIntensity = VolumetricScatteringIntensity; data.CastVolumetricShadow = CastVolumetricShadow; data.RenderedVolumetricFog = 0; data.AdditiveColor = AdditiveColor.ToFloat3() * (AdditiveColor.A * brightness); data.IndirectLightingIntensity = IndirectLightingIntensity; data.Radius = GetScaledRadius(); data.Image = GetSource(); data.StaticFlags = GetStaticFlags(); data.ID = GetID(); renderContext.List->SkyLights.Add(data); } } #if USE_EDITOR #include "Engine/Debug/DebugDraw.h" void SkyLight::OnDebugDrawSelected() { // Draw influence range DEBUG_DRAW_WIRE_SPHERE(_sphere, Color::AliceBlue, 0, true); // Base Light::OnDebugDrawSelected(); } #endif void SkyLight::Serialize(SerializeStream& stream, const void* otherObj) { // Base Light::Serialize(stream, otherObj); SERIALIZE_GET_OTHER_OBJ(SkyLight); SERIALIZE(AdditiveColor); SERIALIZE_MEMBER(Radius, _radius); SERIALIZE(SkyDistanceThreshold); SERIALIZE_MEMBER(BakedProbe, _bakedProbe); SERIALIZE(Mode); SERIALIZE(CustomTexture); } void SkyLight::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) { // Base Light::Deserialize(stream, modifier); DESERIALIZE(AdditiveColor); DESERIALIZE_MEMBER(Radius, _radius); DESERIALIZE(SkyDistanceThreshold); DESERIALIZE_MEMBER(BakedProbe, _bakedProbe); DESERIALIZE(Mode); DESERIALIZE(CustomTexture); } bool SkyLight::HasContentLoaded() const { if (Mode == Modes::CaptureScene) return _bakedProbe == nullptr || _bakedProbe->IsLoaded(); if (Mode == Modes::CustomTexture) return CustomTexture == nullptr || CustomTexture->IsLoaded(); return true; } void SkyLight::OnEnable() { GetSceneRendering()->AddActor(this, _sceneRenderingKey, SceneRendering::PreRender); #if USE_EDITOR GetSceneRendering()->AddViewportIcon(this); #endif // Base Light::OnEnable(); } void SkyLight::OnDisable() { #if USE_EDITOR GetSceneRendering()->RemoveViewportIcon(this); #endif GetSceneRendering()->RemoveActor(this, _sceneRenderingKey, SceneRendering::PreRender); // Base Light::OnDisable(); } void SkyLight::OnTransformChanged() { // Base Light::OnTransformChanged(); UpdateBounds(); }