feat: improve fps controller / add fog and ambient light to the scene
|
After Width: | Height: | Size: 5.3 MiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
@@ -91,16 +91,17 @@ void main()
|
||||
diffuseColor, roughness, metallic, f0, shadow);
|
||||
}
|
||||
|
||||
// emissive
|
||||
vec3 emissiveColor = material.emissiveColor.rgb * sampleTexture2D(material.emissiveTex, samplerID, inUV).rgb;
|
||||
fragColor += emissiveColor;
|
||||
|
||||
// ambient, the specular part keeps metals from turning black without lights
|
||||
float NoV = clamp(dot(n, v), 0.0001, 1.0);
|
||||
vec3 ambientLight = pcs.sceneData.ambientColor * pcs.sceneData.ambientIntensity;
|
||||
vec3 ambientSpecular = envBRDFApprox(f0, roughness, NoV);
|
||||
fragColor += (diffuseColor + ambientSpecular) * ambientLight * ambientOcclusion;
|
||||
|
||||
float fogAmount = pcs.sceneData.fogDensity * length(cameraPos - fragPos);
|
||||
fragColor = mix(pcs.sceneData.fogColor, fragColor, exp(-fogAmount * fogAmount));
|
||||
|
||||
if (pcs.sceneData.debugLightHeatmap != 0) {
|
||||
fragColor = mix(fragColor, lightHeatmapColor(tileLightCount), 0.5);
|
||||
}
|
||||
|
||||
@@ -58,6 +58,9 @@ public:
|
||||
[[nodiscard]] bool AllowsSleep() const { return m_AllowSleep; }
|
||||
void SetAllowSleep(bool allowSleep) { m_AllowSleep = allowSleep; NotifyPhysicsChanged(); }
|
||||
|
||||
[[nodiscard]] bool FreezesRotation() const { return m_FreezeRotation; }
|
||||
void SetFreezeRotation(bool freezeRotation) { m_FreezeRotation = freezeRotation; NotifyPhysicsChanged(); }
|
||||
|
||||
[[nodiscard]] PhysicsWorld* GetPhysicsWorld() const { return m_World; }
|
||||
|
||||
private:
|
||||
@@ -72,4 +75,5 @@ private:
|
||||
|
||||
bool m_UseGravity{true};
|
||||
bool m_AllowSleep{true};
|
||||
bool m_FreezeRotation{false};
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
void init(GfxDevice& gfxDevice, RenderResources& resources, VkFormat drawImageFormat, VkFormat depthImageFormat);
|
||||
void cleanup(VkDevice device);
|
||||
|
||||
void draw(VkCommandBuffer cmd, RenderResources& resources, const Camera& camera);
|
||||
void draw(VkCommandBuffer cmd, RenderResources& resources, const Camera& camera, float rotation);
|
||||
|
||||
void setSkyboxImage(const ImageID skyboxId);
|
||||
|
||||
@@ -30,8 +30,6 @@ private:
|
||||
std::unique_ptr<Pipeline> pipeline;
|
||||
ImageID skyboxTextureId{NULL_IMAGE_ID};
|
||||
|
||||
glm::mat4 skyboxRotation{1.f};
|
||||
|
||||
struct SkyboxPushConstants {
|
||||
glm::mat4 invViewProj;
|
||||
glm::vec4 skyboxRot[3];
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
float ambientIntensity;
|
||||
glm::vec3 fogColor;
|
||||
float fogDensity;
|
||||
float skyboxRotation{0.0f}; // radians around the world up axis
|
||||
};
|
||||
|
||||
explicit GameRenderer();
|
||||
|
||||
@@ -53,7 +53,8 @@ public:
|
||||
bool Raycast(const glm::vec3& origin,
|
||||
const glm::vec3& direction,
|
||||
float maxDistance,
|
||||
PhysicsRaycastHit& hit) const override;
|
||||
PhysicsRaycastHit& hit,
|
||||
PhysicsBodyHandle ignoreBody = {}) const override;
|
||||
|
||||
std::vector<TriggerEvent> ConsumeTriggerEvents() override;
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@ struct PhysicsBodyDesc {
|
||||
float mass{1.0f};
|
||||
bool useGravity{true};
|
||||
bool allowSleep{true};
|
||||
bool freezeRotation{false};
|
||||
};
|
||||
|
||||
struct TriggerEvent {
|
||||
|
||||
@@ -46,10 +46,12 @@ public:
|
||||
virtual void AddForce(PhysicsBodyHandle body, const glm::vec3& force) = 0;
|
||||
virtual void AddImpulse(PhysicsBodyHandle body, const glm::vec3& impulse) = 0;
|
||||
|
||||
// Triggers are never hit. ignoreBody is skipped too, e.g. so a character can cast from inside its own collider
|
||||
virtual bool Raycast(const glm::vec3& origin,
|
||||
const glm::vec3& direction,
|
||||
float maxDistance,
|
||||
PhysicsRaycastHit& hit) const = 0;
|
||||
PhysicsRaycastHit& hit,
|
||||
PhysicsBodyHandle ignoreBody = {}) const = 0;
|
||||
|
||||
// Trigger events accumulated during the last Step().
|
||||
virtual std::vector<TriggerEvent> ConsumeTriggerEvents() { return {}; }
|
||||
|
||||
@@ -46,7 +46,8 @@ public:
|
||||
bool Raycast(const glm::vec3& origin,
|
||||
const glm::vec3& direction,
|
||||
float maxDistance,
|
||||
PhysicsRaycastHit& hit) const override;
|
||||
PhysicsRaycastHit& hit,
|
||||
PhysicsBodyHandle ignoreBody = {}) const override;
|
||||
|
||||
void SyncKinematicBodiesToPhysics();
|
||||
void SyncDynamicBodiesToTransforms();
|
||||
|
||||
@@ -14,6 +14,18 @@
|
||||
|
||||
class CameraComponent;
|
||||
class GameObject;
|
||||
|
||||
|
||||
struct SceneEnvironment {
|
||||
glm::vec3 ambientColor{0.1f};
|
||||
float ambientIntensity{0.5f};
|
||||
|
||||
glm::vec3 fogColor{0.5f};
|
||||
float fogDensity{0.0f};
|
||||
|
||||
float skyboxRotationSpeed{0.01f};
|
||||
float skyboxRotation{0.0f};
|
||||
};
|
||||
class SceneSerializer;
|
||||
class PhysicsWorld;
|
||||
|
||||
@@ -107,6 +119,9 @@ public:
|
||||
|
||||
PhysicsSceneBridge& GetPhysics() { return m_Physics; }
|
||||
|
||||
[[nodiscard]] SceneEnvironment& GetEnvironment() { return m_Environment; }
|
||||
[[nodiscard]] const SceneEnvironment& GetEnvironment() const { return m_Environment; }
|
||||
|
||||
[[nodiscard]] CameraComponent* GetCurrentCamera() const;
|
||||
[[nodiscard]] std::vector<CameraComponent*> GetCameras() const;
|
||||
void SetCurrentCamera(const CameraComponent* camera);
|
||||
@@ -134,6 +149,10 @@ private:
|
||||
|
||||
ObjectId m_CurrentCameraId{InvalidObjectId};
|
||||
|
||||
SceneEnvironment m_Environment{};
|
||||
|
||||
void DrawSettingsImGui();
|
||||
|
||||
std::function<void()> m_registerBindings;
|
||||
std::function<void()> m_unregisterBindings;
|
||||
bool m_bindingsUnloaded{false};
|
||||
|
||||
@@ -14,6 +14,10 @@ public:
|
||||
[[nodiscard]] double FixedDeltaTime() const;
|
||||
[[nodiscard]] double DeltaTime() const;
|
||||
|
||||
// How far the current frame is between the last two fixed steps (0..1), used to interpolate physics objects
|
||||
[[nodiscard]] float FixedAlpha() const { return m_FixedAlpha; }
|
||||
void SetFixedAlpha(float alpha) { m_FixedAlpha = alpha; }
|
||||
|
||||
[[nodiscard]] std::chrono::nanoseconds SleepDuration() const;
|
||||
|
||||
void Update();
|
||||
@@ -25,6 +29,7 @@ private:
|
||||
static constexpr double m_FixedDeltaTime{1.0 / 60.0};
|
||||
static constexpr double FPS{60};
|
||||
double m_DeltaTime{};
|
||||
float m_FixedAlpha{1.0f};
|
||||
std::chrono::high_resolution_clock::time_point m_PrevTime;
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace ImGuiUtils {
|
||||
const std::vector<std::shared_ptr<GameObject>>& pendingAdditions,
|
||||
ObjectId& selectedObjectId,
|
||||
const std::function<GameObject*()>& createGameObject,
|
||||
const std::function<void()>& drawSceneSettings,
|
||||
bool* open = nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <SDL_vulkan.h>
|
||||
@@ -274,8 +275,7 @@ if (!isRunning) break;
|
||||
TracyPlot("Fixed Steps", static_cast<int64_t>(steps));
|
||||
}
|
||||
|
||||
const float alpha = accumulator / fixedDt;
|
||||
(void)alpha;
|
||||
Time::GetInstance().SetFixedAlpha(std::clamp(accumulator / fixedDt, 0.0f, 1.0f));
|
||||
|
||||
{
|
||||
ZoneScopedN("Swapchain Resize Check");
|
||||
|
||||
@@ -106,7 +106,8 @@ nlohmann::json Rigidbody::Serialize() const {
|
||||
{"friction", m_Friction},
|
||||
{"restitution", m_Restitution},
|
||||
{"useGravity", m_UseGravity},
|
||||
{"allowSleep", m_AllowSleep}
|
||||
{"allowSleep", m_AllowSleep},
|
||||
{"freezeRotation", m_FreezeRotation}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -129,6 +130,9 @@ void Rigidbody::Deserialize(const nlohmann::json& data) {
|
||||
if (data.contains("allowSleep")) {
|
||||
m_AllowSleep = data.at("allowSleep").get<bool>();
|
||||
}
|
||||
if (data.contains("freezeRotation")) {
|
||||
m_FreezeRotation = data.at("freezeRotation").get<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
void Rigidbody::ImGuiInspector() {
|
||||
@@ -163,6 +167,11 @@ void Rigidbody::ImGuiInspector() {
|
||||
SetAllowSleep(allowSleep);
|
||||
}
|
||||
|
||||
bool freezeRotation = m_FreezeRotation;
|
||||
if (ImGui::Checkbox("Freeze rotation", &freezeRotation)) {
|
||||
SetFreezeRotation(freezeRotation);
|
||||
}
|
||||
|
||||
if (HasPhysicsBody()) {
|
||||
const glm::vec3 velocity = GetLinearVelocity();
|
||||
ImGui::Text(
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <destrum/FS/AssetFS.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <destrum/Util/DeltaTime.h>
|
||||
|
||||
#include "volk.h"
|
||||
#include "glm/ext/matrix_transform.hpp"
|
||||
@@ -98,26 +97,20 @@ void SkyboxPipeline::cleanup(VkDevice device)
|
||||
void SkyboxPipeline::draw(
|
||||
VkCommandBuffer cmd,
|
||||
RenderResources& resources,
|
||||
const Camera& camera)
|
||||
const Camera& camera,
|
||||
float rotation)
|
||||
{
|
||||
if (skyboxTextureId == NULL_IMAGE_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float rotationSpeed = 0.01f;
|
||||
|
||||
skyboxRotation = glm::rotate(
|
||||
skyboxRotation,
|
||||
rotationSpeed * static_cast<float>(Time::GetInstance().DeltaTime()),
|
||||
glm::vec3(0.f, 1.f, 0.f));
|
||||
|
||||
pipeline->bind(cmd);
|
||||
|
||||
vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL);
|
||||
|
||||
resources.bindBindlessDescSet(cmd, pipelineLayout);
|
||||
|
||||
const glm::mat3 r = glm::mat3(skyboxRotation);
|
||||
const glm::mat3 r = glm::mat3(glm::rotate(glm::mat4{1.f}, rotation, glm::vec3(0.f, 1.f, 0.f)));
|
||||
|
||||
// rotation only, translation in the inverse makes the sky jitter far from the origin
|
||||
const glm::mat4 viewRotation = glm::mat4(glm::mat3(camera.GetViewMatrix()));
|
||||
|
||||
@@ -306,7 +306,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
|
||||
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "SkyboxPipeline::draw");
|
||||
vkutil::ScopedCmdLabel label(cmd, "SkyboxPipeline::draw", vkutil::labelColors::sky);
|
||||
|
||||
skyboxPipeline->draw(cmd, *resources, camera);
|
||||
skyboxPipeline->draw(cmd, *resources, camera, sceneData.skyboxRotation);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <Jolt/Core/JobSystemThreadPool.h>
|
||||
#include <Jolt/Core/TempAllocator.h>
|
||||
#include <Jolt/Physics/Body/BodyCreationSettings.h>
|
||||
#include <Jolt/Physics/Body/BodyFilter.h>
|
||||
#include <Jolt/Physics/Body/BodyInterface.h>
|
||||
#include <Jolt/Physics/Body/MotionType.h>
|
||||
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
|
||||
@@ -95,6 +96,29 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
// Raycasts skip triggers and optionally one body (e.g. the caster's own collider)
|
||||
class RaycastBodyFilter final : public BodyFilter
|
||||
{
|
||||
public:
|
||||
explicit RaycastBodyFilter(const BodyID& ignoredBody)
|
||||
: m_IgnoredBody(ignoredBody)
|
||||
{
|
||||
}
|
||||
|
||||
bool ShouldCollide(const BodyID& inBodyID) const override
|
||||
{
|
||||
return inBodyID != m_IgnoredBody;
|
||||
}
|
||||
|
||||
bool ShouldCollideLocked(const Body& inBody) const override
|
||||
{
|
||||
return !inBody.IsSensor();
|
||||
}
|
||||
|
||||
private:
|
||||
BodyID m_IgnoredBody;
|
||||
};
|
||||
|
||||
namespace Layers
|
||||
{
|
||||
static constexpr ObjectLayer NON_MOVING = 0;
|
||||
@@ -447,6 +471,10 @@ public:
|
||||
settings.mIsSensor = desc.shape.isTrigger;
|
||||
settings.mAllowSleeping = desc.allowSleep;
|
||||
settings.mGravityFactor = desc.useGravity ? 1.0f : 0.0f;
|
||||
if (desc.freezeRotation)
|
||||
{
|
||||
settings.mAllowedDOFs = EAllowedDOFs::TranslationX | EAllowedDOFs::TranslationY | EAllowedDOFs::TranslationZ;
|
||||
}
|
||||
settings.mUserData = reinterpret_cast<JPH::uint64>(desc.owner);
|
||||
|
||||
if (desc.type == RigidbodyType::Dynamic)
|
||||
@@ -631,7 +659,8 @@ public:
|
||||
bool Raycast(const glm::vec3& origin,
|
||||
const glm::vec3& direction,
|
||||
float maxDistance,
|
||||
PhysicsRaycastHit& hit) const
|
||||
PhysicsRaycastHit& hit,
|
||||
PhysicsBodyHandle ignoreBody) const
|
||||
{
|
||||
if (maxDistance <= 0.0f || glm::length2(direction) <= 0.0000001f)
|
||||
{
|
||||
@@ -645,8 +674,12 @@ public:
|
||||
ToJoltVec3(directionNormalized * maxDistance)
|
||||
};
|
||||
|
||||
const BodyRecord* ignored = ignoreBody.IsValid() ? FindBody(ignoreBody) : nullptr;
|
||||
const RaycastBodyFilter bodyFilter(ignored != nullptr ? ignored->bodyID : BodyID{});
|
||||
|
||||
RayCastResult result{};
|
||||
if (!m_PhysicsSystem.GetNarrowPhaseQuery().CastRay(ray, result))
|
||||
if (!m_PhysicsSystem.GetNarrowPhaseQuery().CastRay(
|
||||
ray, result, BroadPhaseLayerFilter{}, ObjectLayerFilter{}, bodyFilter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -838,9 +871,10 @@ void JoltPhysicsWorld::AddImpulse(PhysicsBodyHandle body, const glm::vec3& impul
|
||||
bool JoltPhysicsWorld::Raycast(const glm::vec3& origin,
|
||||
const glm::vec3& direction,
|
||||
float maxDistance,
|
||||
PhysicsRaycastHit& hit) const
|
||||
PhysicsRaycastHit& hit,
|
||||
PhysicsBodyHandle ignoreBody) const
|
||||
{
|
||||
return m_Impl->Raycast(origin, direction, maxDistance, hit);
|
||||
return m_Impl->Raycast(origin, direction, maxDistance, hit, ignoreBody);
|
||||
}
|
||||
|
||||
std::vector<TriggerEvent> JoltPhysicsWorld::ConsumeTriggerEvents()
|
||||
|
||||
@@ -70,6 +70,7 @@ void PhysicsWorld::RegisterRigidbody(Rigidbody& rigidbody) {
|
||||
desc.mass = rigidbody.GetMass();
|
||||
desc.useGravity = rigidbody.UsesGravity();
|
||||
desc.allowSleep = rigidbody.AllowsSleep();
|
||||
desc.freezeRotation = rigidbody.FreezesRotation();
|
||||
desc.material.friction = rigidbody.GetFriction();
|
||||
desc.material.restitution = rigidbody.GetRestitution();
|
||||
|
||||
|
||||
@@ -165,7 +165,8 @@ void SimplePhysicsWorld::SyncDynamicBodiesToTransforms() {
|
||||
bool SimplePhysicsWorld::Raycast(const glm::vec3& origin,
|
||||
const glm::vec3& direction,
|
||||
float maxDistance,
|
||||
PhysicsRaycastHit& hit) const {
|
||||
PhysicsRaycastHit& hit,
|
||||
PhysicsBodyHandle ignoreBody) const {
|
||||
if (maxDistance <= 0.0f) {
|
||||
return false;
|
||||
}
|
||||
@@ -183,7 +184,9 @@ bool SimplePhysicsWorld::Raycast(const glm::vec3& origin,
|
||||
for (const BodyRecord& body : m_Bodies) {
|
||||
if (!body.alive || body.desc.shape.type == PhysicsShapeType::None ||
|
||||
!body.desc.owner || body.desc.owner->IsBeingDestroyed() ||
|
||||
!body.desc.owner->IsActiveInHierarchy()) {
|
||||
!body.desc.owner->IsActiveInHierarchy() ||
|
||||
body.desc.shape.isTrigger ||
|
||||
(ignoreBody.IsValid() && body.handle.id == ignoreBody.id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#include <destrum/Util/ImGuiUtils.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <glm/gtc/constants.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
unsigned int Scene::m_idCounter = 0;
|
||||
|
||||
@@ -131,6 +135,32 @@ void Scene::Update(float dt) {
|
||||
}
|
||||
}
|
||||
|
||||
m_Environment.skyboxRotation = std::fmod(
|
||||
m_Environment.skyboxRotation + m_Environment.skyboxRotationSpeed * dt,
|
||||
glm::two_pi<float>());
|
||||
}
|
||||
|
||||
void Scene::DrawSettingsImGui() {
|
||||
SceneEnvironment& environment = m_Environment;
|
||||
|
||||
ImGui::SeparatorText("Ambient");
|
||||
ImGui::ColorEdit3("Ambient color", &environment.ambientColor.x);
|
||||
ImGui::DragFloat("Ambient intensity", &environment.ambientIntensity, 0.01f, 0.0f, 100.0f);
|
||||
|
||||
ImGui::SeparatorText("Fog");
|
||||
ImGui::ColorEdit3("Fog color", &environment.fogColor.x, ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_Float);
|
||||
ImGui::DragFloat("Fog density", &environment.fogDensity, 0.001f, 0.0f, 1.0f, "%.4f");
|
||||
|
||||
ImGui::SeparatorText("Skybox");
|
||||
float speedDegrees = glm::degrees(environment.skyboxRotationSpeed);
|
||||
if (ImGui::DragFloat("Spin (deg/s)", &speedDegrees, 0.05f)) {
|
||||
environment.skyboxRotationSpeed = glm::radians(speedDegrees);
|
||||
}
|
||||
|
||||
float rotationDegrees = glm::degrees(environment.skyboxRotation);
|
||||
if (ImGui::SliderFloat("Rotation (deg)", &rotationDegrees, -360.0f, 360.0f)) {
|
||||
environment.skyboxRotation = glm::radians(rotationDegrees);
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::FixedUpdate(float dt) {
|
||||
@@ -200,6 +230,7 @@ void Scene::RenderImgui(bool* open) {
|
||||
m_pendingAdditions,
|
||||
m_SelectedObjectId,
|
||||
[this] { return CreateGameObject("GameObject"); },
|
||||
[this] { DrawSettingsImGui(); },
|
||||
open);
|
||||
}
|
||||
|
||||
|
||||
@@ -300,6 +300,15 @@ bool SceneSerializer::Save(Scene& scene, const std::filesystem::path& path) {
|
||||
if (scene.m_CurrentCameraId != InvalidObjectId) {
|
||||
root["currentCamera"] = scene.m_CurrentCameraId;
|
||||
}
|
||||
const SceneEnvironment& environment = scene.GetEnvironment();
|
||||
root["environment"] = {
|
||||
{"ambientColor", {environment.ambientColor.x, environment.ambientColor.y, environment.ambientColor.z}},
|
||||
{"ambientIntensity", environment.ambientIntensity},
|
||||
{"fogColor", {environment.fogColor.x, environment.fogColor.y, environment.fogColor.z}},
|
||||
{"fogDensity", environment.fogDensity},
|
||||
{"skyboxRotationSpeed", environment.skyboxRotationSpeed},
|
||||
{"skyboxRotation", environment.skyboxRotation},
|
||||
};
|
||||
|
||||
for (const auto& objectPtr : scene.GetObjects()) {
|
||||
if (!objectPtr || objectPtr->IsBeingDestroyed()) {
|
||||
@@ -573,6 +582,23 @@ bool SceneSerializer::ConstructScene(Scene& scene, LoadResult& result,
|
||||
scene.m_name = root.at("name").get<std::string>();
|
||||
}
|
||||
scene.m_CurrentCameraId = root.value("currentCamera", InvalidObjectId);
|
||||
scene.m_Environment = SceneEnvironment{};
|
||||
if (root.contains("environment") && root.at("environment").is_object()) {
|
||||
const auto& data = root.at("environment");
|
||||
SceneEnvironment& environment = scene.m_Environment;
|
||||
const auto readColor = [&data](const char* key, glm::vec3& color) {
|
||||
if (data.contains(key) && data.at(key).is_array() && data.at(key).size() == 3) {
|
||||
const auto& value = data.at(key);
|
||||
color = {value.at(0).get<float>(), value.at(1).get<float>(), value.at(2).get<float>()};
|
||||
}
|
||||
};
|
||||
readColor("ambientColor", environment.ambientColor);
|
||||
environment.ambientIntensity = data.value("ambientIntensity", environment.ambientIntensity);
|
||||
readColor("fogColor", environment.fogColor);
|
||||
environment.fogDensity = data.value("fogDensity", environment.fogDensity);
|
||||
environment.skyboxRotationSpeed = data.value("skyboxRotationSpeed", environment.skyboxRotationSpeed);
|
||||
environment.skyboxRotation = data.value("skyboxRotation", environment.skyboxRotation);
|
||||
}
|
||||
|
||||
if (progressCallback) progressCallback(0.9f);
|
||||
|
||||
|
||||
@@ -125,6 +125,7 @@ namespace ImGuiUtils {
|
||||
const std::vector<std::shared_ptr<GameObject>>& pendingAdditions,
|
||||
ObjectId& selectedObjectId,
|
||||
const std::function<GameObject*()>& createGameObject,
|
||||
const std::function<void()>& drawSceneSettings,
|
||||
bool* open) {
|
||||
RegisterEngineComponents();
|
||||
|
||||
@@ -176,6 +177,9 @@ namespace ImGuiUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (drawSceneSettings && ImGui::CollapsingHeader("Scene Settings")) {
|
||||
drawSceneSettings();
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
const float availableWidth = ImGui::GetContentRegionAvail().x;
|
||||
|
||||