add compute shader to auto calculate screen exposure, add SSBO impl
This commit is contained in:
63
Editor/assets/shaders/Exposure.glsl
Normal file
63
Editor/assets/shaders/Exposure.glsl
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#type compute
|
||||||
|
#version 460 core
|
||||||
|
layout(local_size_x = 1, local_size_y = 1) in;
|
||||||
|
|
||||||
|
layout(binding = 0, std430) buffer Histogram {
|
||||||
|
uint bins[64];
|
||||||
|
};
|
||||||
|
layout(binding = 1, std430) buffer Exposure {
|
||||||
|
float exposure;
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform float u_SpeedUp;
|
||||||
|
uniform float u_SpeedDown;
|
||||||
|
uniform float u_Key;
|
||||||
|
uniform float u_LowPercent;
|
||||||
|
uniform float u_HighPercent;
|
||||||
|
uniform float u_MinExposure;
|
||||||
|
uniform float u_MaxExposure;
|
||||||
|
uniform float u_DeltaTime;
|
||||||
|
uniform float u_LogMin;
|
||||||
|
uniform float u_LogMax;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float currentExposure = exposure;
|
||||||
|
|
||||||
|
uint total = 0;
|
||||||
|
uint prefix[64];
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
total += bins[i];
|
||||||
|
prefix[i] = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
float lowCount = u_LowPercent * 0.01 * total;
|
||||||
|
float highCount = u_HighPercent * 0.01 * total;
|
||||||
|
int lowBin = 0, highBin = 63;
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
if (prefix[i] < lowCount) lowBin = i + 1;
|
||||||
|
if (prefix[i] < highCount) highBin = i + 1;
|
||||||
|
}
|
||||||
|
lowBin = clamp(lowBin, 0, 63);
|
||||||
|
highBin = clamp(highBin, 0, 63);
|
||||||
|
|
||||||
|
float sumLum = 0.0;
|
||||||
|
uint count = 0;
|
||||||
|
for (int i = lowBin; i <= highBin; i++) {
|
||||||
|
float t = (float(i) + 0.5) / 64.0;
|
||||||
|
float logLum = u_LogMin + t * (u_LogMax - u_LogMin);
|
||||||
|
float lum = exp2(logLum);
|
||||||
|
sumLum += lum * float(bins[i]);
|
||||||
|
count += bins[i];
|
||||||
|
}
|
||||||
|
float avgLum = count > 0 ? sumLum / count : 0.18;
|
||||||
|
|
||||||
|
float targetExposure = u_Key / max(avgLum, 0.0001);
|
||||||
|
targetExposure = clamp(targetExposure, u_MinExposure, u_MaxExposure);
|
||||||
|
|
||||||
|
float speed = (targetExposure > currentExposure) ? u_SpeedUp : u_SpeedDown;
|
||||||
|
float adaptFactor = 1.0 - exp(-speed * u_DeltaTime);
|
||||||
|
float newExposure = mix(currentExposure, targetExposure, adaptFactor);
|
||||||
|
newExposure = clamp(newExposure, u_MinExposure, u_MaxExposure);
|
||||||
|
|
||||||
|
exposure = newExposure;
|
||||||
|
}
|
||||||
26
Editor/assets/shaders/Histogram.glsl
Normal file
26
Editor/assets/shaders/Histogram.glsl
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#type compute
|
||||||
|
#version 460 core
|
||||||
|
layout(local_size_x = 16, local_size_y = 16) in;
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2D u_SceneColor;
|
||||||
|
layout(binding = 1, std430) buffer Histogram {
|
||||||
|
uint bins[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform float u_LogMin;
|
||||||
|
uniform float u_LogMax;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||||
|
ivec2 size = textureSize(u_SceneColor, 0);
|
||||||
|
if (texel.x >= size.x || texel.y >= size.y) return;
|
||||||
|
|
||||||
|
vec3 color = texelFetch(u_SceneColor, texel, 0).rgb;
|
||||||
|
float lum = max(dot(color, vec3(0.2126, 0.7152, 0.0722)), 0.0001);
|
||||||
|
float logLum = log2(lum);
|
||||||
|
|
||||||
|
float invLogRange = 1.0 / (u_LogMax - u_LogMin);
|
||||||
|
float t = (logLum - u_LogMin) * invLogRange;
|
||||||
|
int bin = int(clamp(t * 64.0, 0.0, 63.0));
|
||||||
|
atomicAdd(bins[bin], 1u);
|
||||||
|
}
|
||||||
@ -23,7 +23,14 @@ in vec2 v_TexCoord;
|
|||||||
|
|
||||||
uniform sampler2DMS u_Texture;
|
uniform sampler2DMS u_Texture;
|
||||||
|
|
||||||
uniform float u_Exposure;
|
|
||||||
|
uniform bool u_EnableAutoExposure;
|
||||||
|
uniform float u_ManualExposure;
|
||||||
|
layout(std430, binding = 2) buffer Exposure
|
||||||
|
{
|
||||||
|
float u_Exposure;
|
||||||
|
};
|
||||||
|
|
||||||
uniform int u_TextureSamples;
|
uniform int u_TextureSamples;
|
||||||
|
|
||||||
uniform bool u_EnableBloom;
|
uniform bool u_EnableBloom;
|
||||||
@ -64,7 +71,10 @@ void main()
|
|||||||
color += bloomColor;
|
color += bloomColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(u_EnableAutoExposure)
|
||||||
color *= u_Exposure;
|
color *= u_Exposure;
|
||||||
|
else
|
||||||
|
color *= u_ManualExposure;
|
||||||
|
|
||||||
// Reinhard tonemapping operator.
|
// Reinhard tonemapping operator.
|
||||||
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
|
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
|
||||||
|
|||||||
@ -44,7 +44,7 @@ namespace Prism
|
|||||||
|
|
||||||
PhysicsMaterial() = default;
|
PhysicsMaterial() = default;
|
||||||
|
|
||||||
PhysicsMaterial(float staticFriction, float dynamicFriction, float bounciness)
|
PhysicsMaterial(const float staticFriction, const float dynamicFriction, const float bounciness)
|
||||||
: StaticFriction(staticFriction), DynamicFriction(dynamicFriction), Bounciness(bounciness)
|
: StaticFriction(staticFriction), DynamicFriction(dynamicFriction), Bounciness(bounciness)
|
||||||
{
|
{
|
||||||
Type = AssetType::PhysicsMaterial;
|
Type = AssetType::PhysicsMaterial;
|
||||||
|
|||||||
@ -41,11 +41,10 @@ namespace Prism
|
|||||||
ScriptEngine::Init("assets/scripts/ExampleApp.dll");
|
ScriptEngine::Init("assets/scripts/ExampleApp.dll");
|
||||||
Physics3D::Init();
|
Physics3D::Init();
|
||||||
|
|
||||||
Renderer::Init();
|
|
||||||
Renderer::WaitAndRender();
|
|
||||||
|
|
||||||
AssetTypes::Init();
|
AssetTypes::Init();
|
||||||
AssetsManager::Init();
|
AssetsManager::Init();
|
||||||
|
Renderer::Init();
|
||||||
|
Renderer::WaitAndRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application()
|
Application::~Application()
|
||||||
|
|||||||
@ -27,6 +27,8 @@ namespace Prism
|
|||||||
return Elapsed() * 1000.0f;
|
return Elapsed() * 1000.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator float() const { return Elapsed(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::chrono::time_point<std::chrono::high_resolution_clock> m_Start;
|
std::chrono::time_point<std::chrono::high_resolution_clock> m_Start;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -188,4 +188,15 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
glLineWidth(thickness);
|
glLineWidth(thickness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RendererAPI::DispatchCompute(int x, int y, int z)
|
||||||
|
{
|
||||||
|
glDispatchCompute(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererAPI::MemoryBarrier(const int barrier)
|
||||||
|
{
|
||||||
|
glMemoryBarrier(barrier);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
73
Prism/src/Prism/Platform/OpenGL/OpenGLStorageBuffer.cpp
Normal file
73
Prism/src/Prism/Platform/OpenGL/OpenGLStorageBuffer.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/3/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OpenGLStorageBuffer.h"
|
||||||
|
|
||||||
|
#include "Prism/Renderer/Renderer.h"
|
||||||
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
namespace Prism {
|
||||||
|
|
||||||
|
static GLenum UsageToGL(const StorageBufferUsage usage)
|
||||||
|
{
|
||||||
|
switch (usage)
|
||||||
|
{
|
||||||
|
case StorageBufferUsage::Static: return GL_STATIC_DRAW;
|
||||||
|
case StorageBufferUsage::Dynamic: return GL_DYNAMIC_DRAW;
|
||||||
|
case StorageBufferUsage::Stream: return GL_STREAM_DRAW;
|
||||||
|
case StorageBufferUsage::DynamicCopy: return GL_DYNAMIC_COPY;
|
||||||
|
default: return GL_DYNAMIC_DRAW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLStorageBuffer::OpenGLStorageBuffer(uint32_t size, const void* data, StorageBufferUsage usage)
|
||||||
|
: m_Size(size), m_Usage(usage)
|
||||||
|
{
|
||||||
|
Renderer::Submit([this, data]() {
|
||||||
|
glCreateBuffers(1, &m_RendererID);
|
||||||
|
glNamedBufferData(m_RendererID, m_Size, data, UsageToGL(m_Usage));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLStorageBuffer::~OpenGLStorageBuffer()
|
||||||
|
{
|
||||||
|
Renderer::Submit([this]() {
|
||||||
|
glDeleteBuffers(1, &m_RendererID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLStorageBuffer::Bind() const
|
||||||
|
{
|
||||||
|
Renderer::Submit([this]() {
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_RendererID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLStorageBuffer::Unbind() const
|
||||||
|
{
|
||||||
|
Renderer::Submit([]() {
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLStorageBuffer::BindBase(uint32_t index) const
|
||||||
|
{
|
||||||
|
Renderer::Submit([this, index]() {
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, index, m_RendererID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLStorageBuffer::SetData(const void* data, uint32_t size, uint32_t offset)
|
||||||
|
{
|
||||||
|
Renderer::Submit([this, data, size, offset]() {
|
||||||
|
glNamedBufferSubData(m_RendererID, offset, size, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLStorageBuffer::GetData(void* outData, const uint32_t size, const uint32_t offset) const
|
||||||
|
{
|
||||||
|
glGetNamedBufferSubData(m_RendererID, offset, size, outData);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
35
Prism/src/Prism/Platform/OpenGL/OpenGLStorageBuffer.h
Normal file
35
Prism/src/Prism/Platform/OpenGL/OpenGLStorageBuffer.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/3/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef PRISM_OPENGLSTORAGEBUFFER_H
|
||||||
|
#define PRISM_OPENGLSTORAGEBUFFER_H
|
||||||
|
|
||||||
|
#include "Prism/Renderer/StorageBuffer.h"
|
||||||
|
|
||||||
|
namespace Prism {
|
||||||
|
|
||||||
|
class OpenGLStorageBuffer : public StorageBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OpenGLStorageBuffer(uint32_t size, const void* data, StorageBufferUsage usage);
|
||||||
|
virtual ~OpenGLStorageBuffer();
|
||||||
|
|
||||||
|
virtual void Bind() const override;
|
||||||
|
virtual void Unbind() const override;
|
||||||
|
virtual void BindBase(uint32_t index) const override;
|
||||||
|
virtual void SetData(const void* data, uint32_t size, uint32_t offset = 0) override;
|
||||||
|
virtual void GetData(void* outData, uint32_t size, uint32_t offset = 0) const override;
|
||||||
|
virtual uint32_t GetRendererID() const override { return m_RendererID; }
|
||||||
|
virtual uint32_t GetSize() const override { return m_Size; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t m_RendererID = 0;
|
||||||
|
uint32_t m_Size = 0;
|
||||||
|
StorageBufferUsage m_Usage;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //PRISM_OPENGLSTORAGEBUFFER_H
|
||||||
@ -253,6 +253,22 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::DispatchCompute(int x, int y, int z)
|
||||||
|
{
|
||||||
|
Submit([x, y, z]()
|
||||||
|
{
|
||||||
|
RendererAPI::DispatchCompute(x, y, z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::MemoryBarrier(int barrier)
|
||||||
|
{
|
||||||
|
Submit([barrier]()
|
||||||
|
{
|
||||||
|
RendererAPI::MemoryBarrier(barrier);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color)
|
void Renderer::DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color)
|
||||||
{
|
{
|
||||||
glm::vec4 min = { aabb.Min.x, aabb.Min.y, aabb.Min.z, 1.0f };
|
glm::vec4 min = { aabb.Min.x, aabb.Min.y, aabb.Min.z, 1.0f };
|
||||||
|
|||||||
@ -59,6 +59,9 @@ namespace Prism
|
|||||||
|
|
||||||
static void DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color = glm::vec4(1.0f));
|
static void DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color = glm::vec4(1.0f));
|
||||||
static void DrawAABB(const Ref<Mesh>& mesh,const glm::mat4& transform, const glm::vec4& color = glm::vec4(1.0f));
|
static void DrawAABB(const Ref<Mesh>& mesh,const glm::mat4& transform, const glm::vec4& color = glm::vec4(1.0f));
|
||||||
|
static void DispatchCompute(int x, int y, int z);
|
||||||
|
static void MemoryBarrier(int barrier);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static RenderCommandQueue& GetRenderCommandQueue();
|
static RenderCommandQueue& GetRenderCommandQueue();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "Renderer2D.h"
|
#include "Renderer2D.h"
|
||||||
#include "SceneRenderer.h"
|
#include "SceneRenderer.h"
|
||||||
|
#include "StorageBuffer.h"
|
||||||
#include "Prism/Scene/Components.h"
|
#include "Prism/Scene/Components.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -39,18 +40,28 @@ namespace Prism
|
|||||||
Ref<RenderPass> BloomBlurPass[2];
|
Ref<RenderPass> BloomBlurPass[2];
|
||||||
Ref<RenderPass> BloomBlendPass;
|
Ref<RenderPass> BloomBlendPass;
|
||||||
|
|
||||||
// Auto exposure
|
|
||||||
struct AutoExposureData
|
struct AutoExposureData
|
||||||
{
|
{
|
||||||
Ref<RenderPass> LuminancePass;
|
Ref<RenderPass> LuminancePass;
|
||||||
|
|
||||||
float CurrentExposure = 1.0f;
|
|
||||||
bool EnableAutoExposure = true;
|
bool EnableAutoExposure = true;
|
||||||
float Key = 0.11f; // middle gray
|
float Key = 0.11f;
|
||||||
float AdaptationSpeed = 5.0f; // stops per second
|
|
||||||
|
|
||||||
Timer ExposureTimer;
|
Timer ExposureTimer;
|
||||||
float MaxExposure = 5.0f;
|
float MaxExposure = 5.0f;
|
||||||
|
float MinExposure = 0.01f;
|
||||||
|
|
||||||
|
// 直方图模式参数
|
||||||
|
float SpeedUp = 5.0f;
|
||||||
|
float SpeedDown = 2.0f;
|
||||||
|
float LowPercent = 70.0f;
|
||||||
|
float HighPercent = 95.0f;
|
||||||
|
float LogMin = -4.0f;
|
||||||
|
float LogMax = 4.0f;
|
||||||
|
|
||||||
|
Ref<StorageBuffer> HistogramSSBO;
|
||||||
|
Ref<StorageBuffer> ExposureSSBO;
|
||||||
|
Ref<Shader> HistogramCS;
|
||||||
|
Ref<Shader> ExposureCS;
|
||||||
} AutoExposureData;
|
} AutoExposureData;
|
||||||
|
|
||||||
Ref<Shader> ShadowMapShader, ShadowMapAnimShader;
|
Ref<Shader> ShadowMapShader, ShadowMapAnimShader;
|
||||||
@ -134,6 +145,8 @@ namespace Prism
|
|||||||
static Renderer3DStats s_Stats;
|
static Renderer3DStats s_Stats;
|
||||||
|
|
||||||
void Renderer3D::Init()
|
void Renderer3D::Init()
|
||||||
|
{
|
||||||
|
//////////////// GeoPass ////////////////
|
||||||
{
|
{
|
||||||
FramebufferSpecification geoFramebufferSpec;
|
FramebufferSpecification geoFramebufferSpec;
|
||||||
geoFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::DEPTH24STENCIL8 };
|
geoFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::DEPTH24STENCIL8 };
|
||||||
@ -143,17 +156,12 @@ namespace Prism
|
|||||||
RenderPassSpecification geoRenderPassSpec;
|
RenderPassSpecification geoRenderPassSpec;
|
||||||
geoRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(geoFramebufferSpec);
|
geoRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(geoFramebufferSpec);
|
||||||
s_Data.GeoPass = RenderPass::Create(geoRenderPassSpec);
|
s_Data.GeoPass = RenderPass::Create(geoRenderPassSpec);
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
/*
|
|
||||||
FramebufferSpecification compFramebufferSpec;
|
|
||||||
compFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA8 , FramebufferTextureFormat::RGBA8};
|
|
||||||
compFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
|
||||||
|
|
||||||
RenderPassSpecification compRenderPassSpec;
|
|
||||||
compRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(compFramebufferSpec);
|
|
||||||
s_Data.CompositePass = RenderPass::Create(compRenderPassSpec);
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
//////////////// BloomPass ////////////////
|
||||||
|
{
|
||||||
FramebufferSpecification bloomBlurFramebufferSpec;
|
FramebufferSpecification bloomBlurFramebufferSpec;
|
||||||
bloomBlurFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F , FramebufferTextureFormat::RGBA8};
|
bloomBlurFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F , FramebufferTextureFormat::RGBA8};
|
||||||
bloomBlurFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
bloomBlurFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||||
@ -172,11 +180,13 @@ namespace Prism
|
|||||||
bloomBlendRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(bloomBlendFramebufferSpec);
|
bloomBlendRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(bloomBlendFramebufferSpec);
|
||||||
s_Data.BloomBlendPass = RenderPass::Create(bloomBlendRenderPassSpec);
|
s_Data.BloomBlendPass = RenderPass::Create(bloomBlendRenderPassSpec);
|
||||||
|
|
||||||
s_Data.CompositeShader = Shader::Create("assets/shaders/SceneComposite.glsl");
|
|
||||||
s_Data.BloomBlurShader = Shader::Create("assets/shaders/BloomBlur.glsl");
|
s_Data.BloomBlurShader = Shader::Create("assets/shaders/BloomBlur.glsl");
|
||||||
s_Data.BloomBlendShader = Shader::Create("assets/shaders/BloomBlend.glsl");
|
s_Data.BloomBlendShader = Shader::Create("assets/shaders/BloomBlend.glsl");
|
||||||
s_Data.BRDFLUT = Texture2D::Create("assets/textures/BRDF_LUT.tga");
|
}
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
//////////////// AutoExposure ////////////////
|
||||||
|
{
|
||||||
// Luminance pass: used to compute average scene luminance (for auto exposure)
|
// Luminance pass: used to compute average scene luminance (for auto exposure)
|
||||||
FramebufferSpecification luminanceFramebufferSpec;
|
FramebufferSpecification luminanceFramebufferSpec;
|
||||||
luminanceFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F };
|
luminanceFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F };
|
||||||
@ -186,34 +196,19 @@ namespace Prism
|
|||||||
luminanceRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(luminanceFramebufferSpec);
|
luminanceRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(luminanceFramebufferSpec);
|
||||||
s_Data.AutoExposureData.LuminancePass = RenderPass::Create(luminanceRenderPassSpec);
|
s_Data.AutoExposureData.LuminancePass = RenderPass::Create(luminanceRenderPassSpec);
|
||||||
|
|
||||||
// Grid
|
constexpr uint32_t histogramSize = 64 * sizeof(uint32_t);
|
||||||
// const auto gridShader = Shader::Create("assets/shaders/Grid.glsl");
|
std::vector<uint32_t> zeros(64, 0);
|
||||||
const auto gridShader = Shader::Create("assets/shaders/InfiniteGrid.glsl");
|
s_Data.AutoExposureData.HistogramSSBO = StorageBuffer::Create(histogramSize, zeros.data());
|
||||||
s_Data.GridData.GridMaterial = MaterialInstance::Create(Material::Create(gridShader));
|
float initialExposure = 1.0f;
|
||||||
// constexpr float gridScale = 16.025f;
|
s_Data.AutoExposureData.ExposureSSBO = StorageBuffer::Create(sizeof(float), &initialExposure);
|
||||||
// constexpr float gridSize = 0.025f;
|
s_Data.AutoExposureData.HistogramCS = Shader::Create("assets/shaders/Histogram.glsl");
|
||||||
// s_Data.GridMaterial->Set("u_Scale", gridScale);
|
s_Data.AutoExposureData.ExposureCS = Shader::Create("assets/shaders/Exposure.glsl");
|
||||||
// s_Data.GridMaterial->Set("u_Res", gridSize);
|
}
|
||||||
s_Data.GridData.GridMaterial->SetFlag(MaterialFlag::TwoSided, true);
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
// outline
|
|
||||||
const auto outlineShader = Shader::Create("assets/shaders/Outline.glsl");
|
|
||||||
s_Data.OutlineMaterial = MaterialInstance::Create(Material::Create(outlineShader));
|
|
||||||
s_Data.OutlineMaterial->SetFlag(MaterialFlag::DepthTest, false);
|
|
||||||
|
|
||||||
// Collider
|
|
||||||
const auto colliderShader = Shader::Create("assets/shaders/Collider.glsl");
|
|
||||||
s_Data.ColliderMaterial = MaterialInstance::Create(Material::Create(colliderShader));
|
|
||||||
s_Data.ColliderMaterial->SetFlag(MaterialFlag::DepthTest, false);
|
|
||||||
|
|
||||||
auto outlineAnimShader = Shader::Create("assets/shaders/Outline_Anim.glsl");
|
|
||||||
s_Data.OutlineAnimMaterial = MaterialInstance::Create(Material::Create(outlineAnimShader));
|
|
||||||
s_Data.OutlineAnimMaterial->SetFlag(MaterialFlag::DepthTest, false);
|
|
||||||
|
|
||||||
// Shadow Map
|
|
||||||
s_Data.ShadowMapShader = Shader::Create("assets/shaders/ShadowMap.glsl");
|
|
||||||
s_Data.ShadowMapAnimShader = Shader::Create("assets/shaders/ShadowMap_Anim.glsl");
|
|
||||||
|
|
||||||
|
//////////////// ShadowMapPass ////////////////
|
||||||
|
{
|
||||||
FramebufferSpecification shadowMapFramebufferSpec;
|
FramebufferSpecification shadowMapFramebufferSpec;
|
||||||
shadowMapFramebufferSpec.Width = 4096;
|
shadowMapFramebufferSpec.Width = 4096;
|
||||||
shadowMapFramebufferSpec.Height = 4096;
|
shadowMapFramebufferSpec.Height = 4096;
|
||||||
@ -229,13 +224,41 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
glGenSamplers(1, &s_Data.ShadowMapSampler);
|
glGenSamplers(1, &s_Data.ShadowMapSampler);
|
||||||
|
|
||||||
// Setup the shadowmap depth sampler
|
// Setup the shadowMap depth sampler
|
||||||
glSamplerParameteri(s_Data.ShadowMapSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glSamplerParameteri(s_Data.ShadowMapSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glSamplerParameteri(s_Data.ShadowMapSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glSamplerParameteri(s_Data.ShadowMapSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glSamplerParameteri(s_Data.ShadowMapSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glSamplerParameteri(s_Data.ShadowMapSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glSamplerParameteri(s_Data.ShadowMapSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glSamplerParameteri(s_Data.ShadowMapSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
s_Data.CompositeShader = Shader::Create("assets/shaders/SceneComposite.glsl");
|
||||||
|
s_Data.BRDFLUT = Texture2D::Create("assets/textures/BRDF_LUT.tga");
|
||||||
|
|
||||||
|
// Grid
|
||||||
|
// const auto gridShader = Shader::Create("assets/shaders/Grid.glsl");
|
||||||
|
const auto gridShader = Shader::Create("assets/shaders/InfiniteGrid.glsl");
|
||||||
|
s_Data.GridData.GridMaterial = MaterialInstance::Create(Material::Create(gridShader));
|
||||||
|
s_Data.GridData.GridMaterial->SetFlag(MaterialFlag::TwoSided, true);
|
||||||
|
|
||||||
|
// outline
|
||||||
|
const auto outlineShader = Shader::Create("assets/shaders/Outline.glsl");
|
||||||
|
s_Data.OutlineMaterial = MaterialInstance::Create(Material::Create(outlineShader));
|
||||||
|
s_Data.OutlineMaterial->SetFlag(MaterialFlag::DepthTest, false);
|
||||||
|
|
||||||
|
// outlineAnim
|
||||||
|
auto outlineAnimShader = Shader::Create("assets/shaders/Outline_Anim.glsl");
|
||||||
|
s_Data.OutlineAnimMaterial = MaterialInstance::Create(Material::Create(outlineAnimShader));
|
||||||
|
s_Data.OutlineAnimMaterial->SetFlag(MaterialFlag::DepthTest, false);
|
||||||
|
|
||||||
|
// Collider
|
||||||
|
const auto colliderShader = Shader::Create("assets/shaders/Collider.glsl");
|
||||||
|
s_Data.ColliderMaterial = MaterialInstance::Create(Material::Create(colliderShader));
|
||||||
|
s_Data.ColliderMaterial->SetFlag(MaterialFlag::DepthTest, false);
|
||||||
|
|
||||||
|
s_Data.ShadowMapShader = Shader::Create("assets/shaders/ShadowMap.glsl");
|
||||||
|
s_Data.ShadowMapAnimShader = Shader::Create("assets/shaders/ShadowMap_Anim.glsl");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer3D::SetViewportSize(uint32_t width, uint32_t height)
|
void Renderer3D::SetViewportSize(uint32_t width, uint32_t height)
|
||||||
@ -429,7 +452,10 @@ namespace Prism
|
|||||||
Renderer::BeginRenderPass(outRenderPass);
|
Renderer::BeginRenderPass(outRenderPass);
|
||||||
|
|
||||||
s_Data.CompositeShader->Bind();
|
s_Data.CompositeShader->Bind();
|
||||||
s_Data.CompositeShader->SetFloat("u_Exposure", s_Data.AutoExposureData.EnableAutoExposure ? s_Data.AutoExposureData.CurrentExposure : s_Data.SceneData.SceneCamera.Camera.GetExposure());
|
|
||||||
|
s_Data.AutoExposureData.ExposureSSBO->BindBase(2);
|
||||||
|
s_Data.CompositeShader->SetBool("u_EnableAutoExposure",s_Data.AutoExposureData.EnableAutoExposure);
|
||||||
|
s_Data.CompositeShader->SetFloat("u_ManualExposure", s_Data.SceneData.SceneCamera.Camera.GetExposure());
|
||||||
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
|
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
|
||||||
s_Data.CompositeShader->SetFloat("u_EnableBloom", s_Data.EnableBloom);
|
s_Data.CompositeShader->SetFloat("u_EnableBloom", s_Data.EnableBloom);
|
||||||
|
|
||||||
@ -790,124 +816,71 @@ namespace Prism
|
|||||||
|
|
||||||
void Renderer3D::AutoExposurePass()
|
void Renderer3D::AutoExposurePass()
|
||||||
{
|
{
|
||||||
if (!s_Data.AutoExposureData.EnableAutoExposure)
|
auto& ae = s_Data.AutoExposureData;
|
||||||
|
if (!ae.EnableAutoExposure)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
||||||
auto dstFB = s_Data.AutoExposureData.LuminancePass->GetSpecification().TargetFramebuffer;
|
auto dstFB = ae.LuminancePass->GetSpecification().TargetFramebuffer;
|
||||||
if (!srcFB || !dstFB)
|
if (!srcFB || !dstFB) return;
|
||||||
return;
|
|
||||||
|
|
||||||
const uint32_t dstID = dstFB->GetColorAttachmentRendererID();
|
float dt = ae.ExposureTimer;
|
||||||
const uint32_t width = dstFB->GetWidth();
|
ae.ExposureTimer.Reset();
|
||||||
const uint32_t height = dstFB->GetHeight();
|
|
||||||
|
|
||||||
Renderer::Submit([dstID, width, height, srcFB]() mutable
|
Renderer::Submit([srcFB, dstFB, logMin = ae.LogMin, logMax = ae.LogMax, histCS = ae.HistogramCS, histSSBO = ae.HistogramSSBO]() {
|
||||||
{
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFB->GetRendererID());
|
||||||
// Use framebuffer blit to resolve multisampled source into non-multisampled luminance target.
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFB->GetRendererID());
|
||||||
const GLuint srcFBO = srcFB->GetRendererID();
|
|
||||||
const GLuint dstFBO = s_Data.AutoExposureData.LuminancePass->GetSpecification().TargetFramebuffer->GetRendererID();
|
|
||||||
|
|
||||||
// Bind read/draw FBOs and blit color attachment 0
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFBO);
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFBO);
|
|
||||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
|
glBlitFramebuffer(0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
|
||||||
// Source size — try to use srcFB dimensions if available
|
0, 0, dstFB->GetWidth(), dstFB->GetHeight(),
|
||||||
const int srcWidth = srcFB->GetWidth();
|
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
const int srcHeight = srcFB->GetHeight();
|
|
||||||
|
|
||||||
glBlitFramebuffer(0, 0, srcWidth, srcHeight, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
||||||
|
|
||||||
// Unbind
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
// Generate mipmaps so the smallest mip is the average color
|
const uint32_t zero = 0;
|
||||||
glGenerateTextureMipmap(dstID);
|
glClearNamedBufferData(histSSBO->GetRendererID(), GL_R32UI, GL_RED, GL_UNSIGNED_INT, &zero);
|
||||||
|
|
||||||
// Determine highest mip level
|
glUseProgram(histCS->GetRendererID());
|
||||||
int maxLevel = (int)std::floor(std::log2((float)std::max(width, height)));
|
glBindTextureUnit(0, dstFB->GetColorAttachmentRendererID());
|
||||||
if (maxLevel < 0) maxLevel = 0;
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, histSSBO->GetRendererID());
|
||||||
|
|
||||||
|
const GLint locLogMin = glGetUniformLocation(histCS->GetRendererID(), "u_LogMin");
|
||||||
|
const GLint locLogMax = glGetUniformLocation(histCS->GetRendererID(), "u_LogMax");
|
||||||
|
if (locLogMin != -1) glProgramUniform1f(histCS->GetRendererID(), locLogMin, logMin);
|
||||||
|
if (locLogMax != -1) glProgramUniform1f(histCS->GetRendererID(), locLogMax, logMax);
|
||||||
|
|
||||||
GLint levelWidth = 0, levelHeight = 0;
|
const uint32_t groupsX = (dstFB->GetWidth() + 15) / 16;
|
||||||
glGetTextureLevelParameteriv(dstID, maxLevel, GL_TEXTURE_WIDTH, &levelWidth);
|
const uint32_t groupsY = (dstFB->GetHeight() + 15) / 16;
|
||||||
glGetTextureLevelParameteriv(dstID, maxLevel, GL_TEXTURE_HEIGHT, &levelHeight);
|
glDispatchCompute(groupsX, groupsY, 1);
|
||||||
|
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||||
if (levelWidth == 0 || levelHeight == 0) return;
|
|
||||||
|
|
||||||
const int bufSize = levelWidth * levelHeight * 4 * sizeof(float);
|
|
||||||
std::vector<float> pixelData(bufSize / sizeof(float));
|
|
||||||
|
|
||||||
glGetTextureImage(dstID, maxLevel, GL_RGBA, GL_FLOAT, bufSize, pixelData.data());
|
|
||||||
|
|
||||||
// Sanitize pixel values (handle NaN/Inf or negative values coming from GPU)
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
{
|
|
||||||
if (!std::isfinite(pixelData[i]) || pixelData[i] < 0.0f)
|
|
||||||
pixelData[i] = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to luminance
|
|
||||||
float lum = 0.2126f * pixelData[0] + 0.7152f * pixelData[1] + 0.0722f * pixelData[2];
|
|
||||||
if (!std::isfinite(lum) || lum <= 0.0f)
|
|
||||||
lum = 1e-6f; // fallback minimum luminance
|
|
||||||
|
|
||||||
// Compute desired exposure (simple key/avg approach)
|
|
||||||
const float key = s_Data.AutoExposureData.Key;
|
|
||||||
constexpr float minLum = 1e-6f;
|
|
||||||
float desiredExposure = key / std::max(lum, minLum);
|
|
||||||
desiredExposure = std::clamp(desiredExposure, 0.0001f, s_Data.AutoExposureData.MaxExposure);
|
|
||||||
|
|
||||||
|
|
||||||
// Adapt exposure over time (exponential)
|
|
||||||
const float dt = s_Data.AutoExposureData.ExposureTimer.ElapsedMillis() / 1000.0f;
|
|
||||||
s_Data.AutoExposureData.ExposureTimer.Reset();
|
|
||||||
const float tau = s_Data.AutoExposureData.AdaptationSpeed;
|
|
||||||
const float adaptFactor = 1.0f - std::exp(-tau * dt);
|
|
||||||
s_Data.AutoExposureData.CurrentExposure = s_Data.AutoExposureData.CurrentExposure + (desiredExposure - s_Data.AutoExposureData.CurrentExposure) * adaptFactor;
|
|
||||||
s_Data.AutoExposureData.CurrentExposure = std::clamp(s_Data.AutoExposureData.CurrentExposure, 0.0001f, s_Data.AutoExposureData.MaxExposure);
|
|
||||||
|
|
||||||
// Write exposure directly into composite shader program uniform so the subsequent composite pass uses it
|
|
||||||
/*
|
|
||||||
if (const GLuint prog = s_Data.CompositeShader->GetRendererID())
|
|
||||||
{
|
|
||||||
const GLint loc = glGetUniformLocation(prog, "u_Exposure");
|
|
||||||
if (loc >= 0)
|
|
||||||
glProgramUniform1f(prog, loc, s_Data.CurrentExposure);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
Renderer::Submit([&ae, dt]() {
|
||||||
|
glUseProgram(ae.ExposureCS->GetRendererID());
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ae.HistogramSSBO->GetRendererID());
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ae.ExposureSSBO->GetRendererID());
|
||||||
|
|
||||||
/*
|
auto setUniform = [&](const char* name, const float value) {
|
||||||
void Renderer3D::CompositePass()
|
const GLint loc = glGetUniformLocation(ae.ExposureCS->GetRendererID(), name);
|
||||||
{
|
if (loc != -1) glProgramUniform1f(ae.ExposureCS->GetRendererID(), loc, value);
|
||||||
auto& compositeBuffer = s_Data.CompositePass->GetSpecification().TargetFramebuffer;
|
};
|
||||||
|
|
||||||
Renderer::BeginRenderPass(s_Data.CompositePass);
|
setUniform("u_SpeedUp", ae.SpeedUp);
|
||||||
s_Data.CompositeShader->Bind();
|
setUniform("u_SpeedDown", ae.SpeedDown);
|
||||||
s_Data.CompositeShader->SetFloat("u_Exposure", s_Data.AutoExposureData.EnableAutoExposure ? s_Data.AutoExposureData.CurrentExposure : s_Data.SceneData.SceneCamera.Camera.GetExposure());
|
setUniform("u_Key", ae.Key);
|
||||||
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
|
setUniform("u_LowPercent", ae.LowPercent);
|
||||||
// s_Data.CompositeShader->SetFloat2("u_ViewportSize", glm::vec2(compositeBuffer->GetWidth(), compositeBuffer->GetHeight()));
|
setUniform("u_HighPercent", ae.HighPercent);
|
||||||
// s_Data.CompositeShader->SetFloat2("u_FocusPoint", s_Data.FocusPoint);
|
setUniform("u_MinExposure", ae.MinExposure);
|
||||||
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
|
setUniform("u_MaxExposure", ae.MaxExposure);
|
||||||
// s_Data.CompositeShader->SetFloat("u_BloomThreshold", s_Data.BloomThreshold);
|
setUniform("u_DeltaTime", dt);
|
||||||
s_Data.CompositeShader->SetFloat("u_EnableBloom", s_Data.EnableBloom);
|
setUniform("u_LogMin", ae.LogMin);
|
||||||
|
setUniform("u_LogMax", ae.LogMax);
|
||||||
|
|
||||||
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
|
glDispatchCompute(1, 1, 1);
|
||||||
Renderer::Submit([]()
|
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||||
{
|
|
||||||
glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Renderer::SubmitFullscreenQuad(nullptr);
|
|
||||||
Renderer::EndRenderPass();
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void Renderer3D::BloomBlurPass()
|
void Renderer3D::BloomBlurPass()
|
||||||
@ -1111,7 +1084,7 @@ namespace Prism
|
|||||||
|
|
||||||
// TODO: this will not be hardcode
|
// TODO: this will not be hardcode
|
||||||
const glm::vec3 lightDir = glm::normalize(directionalLights[0].Direction); // 光线方向(从光源指向场景)
|
const glm::vec3 lightDir = glm::normalize(directionalLights[0].Direction); // 光线方向(从光源指向场景)
|
||||||
glm::vec3 lightPos = lightDir * 10.0f;
|
glm::vec3 lightPos = lightDir * 100.0f;
|
||||||
|
|
||||||
glm::mat4 lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
|
glm::mat4 lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
@ -1225,6 +1198,7 @@ namespace Prism
|
|||||||
UI::EndTreeNode();
|
UI::EndTreeNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if (UI::BeginTreeNode("Auto Exposure", false))
|
if (UI::BeginTreeNode("Auto Exposure", false))
|
||||||
{
|
{
|
||||||
UI::BeginPropertyGrid();
|
UI::BeginPropertyGrid();
|
||||||
@ -1236,6 +1210,36 @@ namespace Prism
|
|||||||
|
|
||||||
UI::EndTreeNode();
|
UI::EndTreeNode();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (UI::BeginTreeNode("Auto Exposure", false))
|
||||||
|
{
|
||||||
|
UI::BeginPropertyGrid();
|
||||||
|
UI::Property("Enable Auto Exposure", s_Data.AutoExposureData.EnableAutoExposure);
|
||||||
|
if (s_Data.AutoExposureData.EnableAutoExposure)
|
||||||
|
{
|
||||||
|
UI::Property("Key (middle gray)", s_Data.AutoExposureData.Key, 0.001f, 0.001f, 2.5f);
|
||||||
|
|
||||||
|
UI::Separator();
|
||||||
|
UI::Property("Speed Up (brighten)", s_Data.AutoExposureData.SpeedUp, 0.1f, 0.1f, 20.0f);
|
||||||
|
UI::Property("Speed Down (darken)", s_Data.AutoExposureData.SpeedDown, 0.1f, 0.1f, 20.0f);
|
||||||
|
|
||||||
|
UI::Separator();
|
||||||
|
UI::Property("Low Percent", s_Data.AutoExposureData.LowPercent, 1.0f, 0.0f, 100.0f);
|
||||||
|
UI::Property("High Percent", s_Data.AutoExposureData.HighPercent, 1.0f, 0.0f, 100.0f);
|
||||||
|
|
||||||
|
UI::Separator();
|
||||||
|
UI::Property("Min Exposure", s_Data.AutoExposureData.MinExposure, 0.01f, 0.0f, 10.0f);
|
||||||
|
UI::Property("Max Exposure", s_Data.AutoExposureData.MaxExposure, 0.1f, 0.0f, 20.0f);
|
||||||
|
|
||||||
|
UI::Separator();
|
||||||
|
UI::Property("Log Min", s_Data.AutoExposureData.LogMin, 0.1f, -10.0f, 10.0f);
|
||||||
|
UI::Property("Log Max", s_Data.AutoExposureData.LogMax, 0.1f, -10.0f, 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
UI::EndPropertyGrid();
|
||||||
|
UI::EndTreeNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|||||||
@ -52,6 +52,9 @@ namespace Prism
|
|||||||
return capabilities;
|
return capabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void DispatchCompute(int x, int y, int z);
|
||||||
|
static void MemoryBarrier(int barrier);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static RendererAPIType s_CurrentRendererAPI;
|
static RendererAPIType s_CurrentRendererAPI;
|
||||||
};
|
};
|
||||||
|
|||||||
25
Prism/src/Prism/Renderer/StorageBuffer.cpp
Normal file
25
Prism/src/Prism/Renderer/StorageBuffer.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/3/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "StorageBuffer.h"
|
||||||
|
|
||||||
|
#include "RendererAPI.h"
|
||||||
|
#include "Prism/Platform/OpenGL/OpenGLStorageBuffer.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
Ref<StorageBuffer> StorageBuffer::Create(uint32_t size, const void* data, StorageBufferUsage usage)
|
||||||
|
{
|
||||||
|
Ref<StorageBuffer> result = nullptr;
|
||||||
|
|
||||||
|
switch (RendererAPI::Current())
|
||||||
|
{
|
||||||
|
case RendererAPIType::None: return nullptr;
|
||||||
|
case RendererAPIType::OpenGL: result = Ref<OpenGLStorageBuffer>::Create(size, data, usage); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
42
Prism/src/Prism/Renderer/StorageBuffer.h
Normal file
42
Prism/src/Prism/Renderer/StorageBuffer.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/3/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef PRISM_STORAGEBUFFER_H
|
||||||
|
#define PRISM_STORAGEBUFFER_H
|
||||||
|
#include "Prism/Core/Ref.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
enum class StorageBufferUsage
|
||||||
|
{
|
||||||
|
Static = 0,
|
||||||
|
Dynamic,
|
||||||
|
Stream,
|
||||||
|
DynamicCopy
|
||||||
|
};
|
||||||
|
|
||||||
|
class StorageBuffer : public RefCounted
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~StorageBuffer() = default;
|
||||||
|
|
||||||
|
static Ref<StorageBuffer> Create(uint32_t size, const void* data = nullptr, StorageBufferUsage usage = StorageBufferUsage::Dynamic);
|
||||||
|
|
||||||
|
virtual void Bind() const = 0;
|
||||||
|
virtual void Unbind() const = 0;
|
||||||
|
|
||||||
|
virtual void BindBase(uint32_t index) const = 0;
|
||||||
|
|
||||||
|
virtual void SetData(const void* data, uint32_t size, uint32_t offset = 0) = 0;
|
||||||
|
virtual void GetData(void* outData, uint32_t size, uint32_t offset = 0) const = 0;
|
||||||
|
|
||||||
|
virtual uint32_t GetRendererID() const = 0;
|
||||||
|
virtual uint32_t GetSize() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StorageBuffer() = default;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //PRISM_STORAGEBUFFER_H
|
||||||
@ -95,8 +95,8 @@ ScriptComponent
|
|||||||
2. **配置依赖**
|
2. **配置依赖**
|
||||||
- PhysX SDK: Prism/CmakeLists.txt内记录了是用的PhysX的构建配置,建议手动按照配置构建SDK,构建好后无需移动文件,项目可以自动链接库
|
- PhysX SDK: Prism/CmakeLists.txt内记录了是用的PhysX的构建配置,建议手动按照配置构建SDK,构建好后无需移动文件,项目可以自动链接库
|
||||||
|
|
||||||
3. **编译**
|
3. **编译**:
|
||||||
**Cmake**:
|
- **Cmake**:
|
||||||
```bash
|
```bash
|
||||||
cd Prism
|
cd Prism
|
||||||
cmake -B build -G Ninja
|
cmake -B build -G Ninja
|
||||||
@ -104,10 +104,10 @@ cmake --build build --target PrismEditor --config Release -j10
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Visual Studio**:
|
**Visual Studio**:
|
||||||
visual Studio启用Cmake。 然后点击project下拉框,找到 PrismEditor,构建。
|
- visual Studio启用Cmake。 然后点击project下拉框,找到 PrismEditor,构建。
|
||||||
|
|
||||||
**JetBrain Clion**:
|
**JetBrain Clion**:
|
||||||
clion 会自动识别Cmake, 运行调试配置找到PrismEditor构建。
|
- clion 会自动识别Cmake, 运行调试配置找到PrismEditor构建。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user