add bloom;some treaks

This commit is contained in:
2026-03-17 16:20:22 +08:00
parent 28d9a7dfb6
commit f1de5df4de
19 changed files with 678 additions and 421 deletions

View File

@ -21,59 +21,64 @@ layout(location = 0) out vec4 o_Color;
in vec2 v_TexCoord;
uniform sampler2D u_Texture;
uniform bool u_Horizontal;
uniform bool u_Horizontal; // 未使用,可保留或移除
uniform bool u_FirstPass; // 是否进行阈值处理
uniform float u_Threshold; // 亮度阈值
void main()
{
#if 1
// From learnopengl.com
float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
float Pi = 6.28318530718; // 2*PI
vec2 tex_offset = 1.0 / textureSize(u_Texture, 0); // gets size of single texel
vec3 result = texture(u_Texture, v_TexCoord).rgb * weight[0]; // current fragment's contribution
if (u_Horizontal)
float Directions = 32.0; // 模糊方向数
float Quality = 6.0; // 每个方向上的采样质量(采样次数)
float Size = 16.0; // 模糊半径
vec2 Radius = Size / textureSize(u_Texture, 0);
// 中心像素采样
vec3 centerColor = texture(u_Texture, v_TexCoord).rgb;
float centerLum = dot(centerColor, vec3(0.2126, 0.7152, 0.0722));
// 如果启用第一次处理且中心像素亮度低于阈值,则直接输出黑色(不进行模糊)
if (u_FirstPass && centerLum <= u_Threshold)
{
for(int i = 1; i < 5; ++i)
o_Color = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
vec3 result = centerColor; // 先累加中心像素
float totalSamples = 1.0; // 有效采样计数(中心像素已计入)
// 周围像素采样
for (float d = 0.0; d < Pi; d += Pi / Directions)
{
for (float i = 1.0 / Quality; i <= 1.0; i += 1.0 / Quality)
{
result += texture(u_Texture, v_TexCoord + vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
result += texture(u_Texture, v_TexCoord - vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
}
}
else
{
for(int i = 1; i < 5; ++i)
{
result += texture(u_Texture, v_TexCoord + vec2(0.0, tex_offset.y * i)).rgb * weight[i];
result += texture(u_Texture, v_TexCoord - vec2(0.0, tex_offset.y * i)).rgb * weight[i];
vec2 offset = vec2(cos(d), sin(d)) * Radius * i;
vec3 sampleColor = texture(u_Texture, v_TexCoord + offset).rgb;
if (u_FirstPass)
{
float lum = dot(sampleColor, vec3(0.2126, 0.7152, 0.0722));
if (lum <= u_Threshold)
{
// 低于阈值则贡献黑色,但采样点仍计入分母?这里选择不计入有效采样数
// 若希望保持模糊能量,可以 continue 跳过累加,但需调整分母
// 为简单起见,此处设为黑色并计入计数(分母不变),也可选择跳过
sampleColor = vec3(0.0);
// 如果希望忽略该采样点,可以 continue 并减少 totalSamples
// 但为了效果平滑,这里保留为黑色并计入计数
}
}
result += sampleColor;
totalSamples += 1.0;
}
}
// 归一化:除以总采样数(包括中心像素)
// 若之前选择忽略低于阈值的采样点continue则需相应调整 totalSamples
result /= totalSamples;
o_Color = vec4(result, 1.0);
#else
// From https://www.shadertoy.com/view/Xltfzj
float Pi = 6.28318530718; // Pi*2
// GAUSSIAN BLUR SETTINGS {{{
float Directions =32.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower)
float Quality = 6.0; // BLUR QUALITY (Default 4.0 - More is better but slower)
float Size = 16.0; // BLUR SIZE (Radius)
// GAUSSIAN BLUR SETTINGS }}}
vec2 Radius = Size/textureSize(u_Texture, 0);
vec3 result = texture(u_Texture, v_TexCoord).rgb;
vec2 uv = v_TexCoord;
// Blur calculations
for( float d=0.0; d<Pi; d+=Pi/Directions)
{
for(float i=1.0/Quality; i<=1.0; i+=1.0/Quality)
{
result += texture( u_Texture, uv+vec2(cos(d),sin(d))*Radius*i).rgb;
}
}
// Output to screen
result /= Quality * Directions - 15.0;
o_Color = vec4(result, 1.0);
#endif
}

View File

@ -7,6 +7,8 @@ layout(binding = 0, rgba32f) restrict writeonly uniform imageCube o_CubeMap;
uniform vec3 u_TurbidityAzimuthInclination;
#define PI 3.14159265359
vec3 GetCubeMapTexCoord()
{
vec2 st = gl_GlobalInvocationID.xy / vec2(imageSize(o_CubeMap));
@ -22,11 +24,10 @@ vec3 GetCubeMapTexCoord()
return normalize(ret);
}
#define PI 3.14159265359
float saturatedDot( in vec3 a, in vec3 b )
{
return max( dot( a, b ), 0.0 );
return clamp(dot(a, b), 0.0, 1.0);
}
vec3 YxyToXYZ( in vec3 Yxy )
@ -96,6 +97,7 @@ vec3 calculateZenithLuminanceYxy( in float t, in float thetaS )
vec3 calculatePerezLuminanceYxy( in float theta, in float gamma, in vec3 A, in vec3 B, in vec3 C, in vec3 D, in vec3 E )
{
float cosTheta = max(cos(theta), 1e-6);
return ( 1.0 + A * exp( B / cos( theta ) ) ) * ( 1.0 + C * exp( D * gamma ) + E * cos( gamma ) * cos( gamma ) );
}
@ -104,8 +106,8 @@ vec3 calculateSkyLuminanceRGB( in vec3 s, in vec3 e, in float t )
vec3 A, B, C, D, E;
calculatePerezDistribution( t, A, B, C, D, E );
float thetaS = acos( saturatedDot( s, vec3(0,1,0) ) );
float thetaE = acos( saturatedDot( e, vec3(0,1,0) ) );
float thetaS = acos(clamp(dot(s, vec3(0,1,0)), 0.0, 1.0));
float thetaE = acos(clamp(dot(e, vec3(0,1,0)), 0.0, 1.0));
float gammaE = acos( saturatedDot( s, e ) );
vec3 Yz = calculateZenithLuminanceYxy( t, thetaS );
@ -128,8 +130,30 @@ void main()
float inclination = u_TurbidityAzimuthInclination.z;
vec3 sunDir = normalize( vec3( sin(inclination) * cos(azimuth), cos(inclination), sin(inclination) * sin(azimuth) ) );
vec3 viewDir = cubeTC;
vec3 skyLuminance = calculateSkyLuminanceRGB( sunDir, viewDir, turbidity );
const float SUN_ANGULAR_RADIUS = 0.03465;
const float SUN_INTENSITY = 100.0;
vec3 skyLuminance;
if (viewDir.y < 0.0) {
skyLuminance = vec3(0.02);
} else {
skyLuminance = calculateSkyLuminanceRGB(sunDir, viewDir, turbidity);
}
float cosAngle = dot(viewDir, sunDir);
float angle = acos(cosAngle);
if (angle < SUN_ANGULAR_RADIUS) {
skyLuminance = vec3(SUN_INTENSITY);
} else {
float haloWidth = 0.1;
if (angle < SUN_ANGULAR_RADIUS + haloWidth) {
float t = (angle - SUN_ANGULAR_RADIUS) / haloWidth;
float haloFactor = 1.0 - smoothstep(0.0, 1.0, t);
skyLuminance += vec3(SUN_INTENSITY * 0.1 * haloFactor);
}
}
vec4 color = vec4(skyLuminance * 0.05, 1.0);
imageStore(o_CubeMap, ivec3(gl_GlobalInvocationID), color);
}
}

View File

@ -22,6 +22,7 @@ layout(location = 1) out vec4 o_BloomTexture;
in vec2 v_TexCoord;
uniform sampler2DMS u_Texture;
uniform sampler2D u_BloomTexture;
uniform bool u_EnableAutoExposure;
@ -55,6 +56,17 @@ vec4 MultiSampleTexture(sampler2DMS tex, vec2 tc)
return result;
}
float MultiSampleDepth(sampler2DMS tex, vec2 tc)
{
ivec2 texSize = textureSize(tex);
ivec2 texCoord = ivec2(tc * texSize);
float result = 0.0;
for (int i = 0; i < u_TextureSamples; i++)
result += texelFetch(tex, texCoord, i).r;
result /= float(u_TextureSamples);
return result;
}
void main()
{
const float gamma = 2.2;
@ -62,12 +74,11 @@ void main()
// Tonemapping
vec4 msColor = MultiSampleTexture(u_Texture, v_TexCoord);
vec3 color = msColor.rgb;
if (u_EnableBloom)
{
vec3 bloomColor = MultiSampleTexture(u_Texture, v_TexCoord).rgb;
vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb;
color += bloomColor;
}

View File

@ -327,7 +327,12 @@ namespace Prism
if (ImGui::MenuItem("Sky Light"))
{
auto newEntity = m_Context->CreateEntity("Sky Light");
newEntity.AddComponent<SkyLightComponent>();
auto& slc = newEntity.AddComponent<SkyLightComponent>();
slc.DynamicSky = true;
Ref<TextureCube> preethamEnv = Renderer3D::CreatePreethamSky(slc.TurbidityAzimuthInclination);
slc.SceneEnvironment = Ref<Environment>::Create(preethamEnv, preethamEnv);
isCreated = true;
SetSelected(newEntity);
}
@ -681,7 +686,12 @@ namespace Prism
ImGui::SeparatorText("Light Component");
AddComponentPopup<DirectionalLightComponent>("Directional Light");
AddComponentPopup<SkyLightComponent>("sky Light");
AddComponentPopup<SkyLightComponent>("Sky Light", [&]( SkyLightComponent& slc)
{
slc.DynamicSky = true;
Ref<TextureCube> preethamEnv = Renderer3D::CreatePreethamSky(slc.TurbidityAzimuthInclination);
slc.SceneEnvironment = Ref<Environment>::Create(preethamEnv, preethamEnv);
});
AddComponentPopup<PointLightComponent>("Point Light");
AddComponentPopup<SpotLightComponent>("Spot Light");
@ -939,6 +949,10 @@ namespace Prism
});
DrawComponent<CameraComponent>("Camera", entity, [](CameraComponent& cameraComponent) {
UI::Property("ShowIcon", cameraComponent.ShowIcon);
UI::Separator();
// Projection Type
const char* projTypeStrings[] = { "Perspective", "Orthographic" };
const char* currentProj = projTypeStrings[(int)cameraComponent.Camera.GetProjectionType()];
@ -996,6 +1010,8 @@ namespace Prism
DrawComponent<DirectionalLightComponent>("Directional Light", entity, [](DirectionalLightComponent& dlc)
{
UI::BeginPropertyGrid();
UI::Property("ShowIcon", dlc.ShowIcon);
UI::Separator();
UI::PropertyColor("Radiance", dlc.Radiance);
UI::Property("Intensity", dlc.Intensity);
UI::Property("Cast Shadows", dlc.CastShadows);
@ -1007,6 +1023,8 @@ namespace Prism
DrawComponent<PointLightComponent>("Point Light", entity, [](PointLightComponent& pc)
{
UI::BeginPropertyGrid();
UI::Property("ShowIcon", pc.ShowIcon);
UI::Separator();
UI::PropertyColor("Radiance", pc.Radiance);
UI::Property("Intensity", pc.Intensity);
@ -1018,6 +1036,8 @@ namespace Prism
DrawComponent<SpotLightComponent>("Spot Light", entity, [](SpotLightComponent& sc)
{
UI::BeginPropertyGrid();
UI::Property("ShowIcon", sc.ShowIcon);
UI::Separator();
UI::PropertyColor("Radiance", sc.Radiance);
UI::Property("Intensity", sc.Intensity);
@ -1032,9 +1052,17 @@ namespace Prism
{
UI::BeginPropertyGrid();
UI::PropertyAssetReference("Environment Map", slc.SceneEnvironment, AssetType::EnvMap);
UI::Property("ShowIcon", slc.ShowIcon);
UI::Separator();
if (UI::PropertyAssetReference("Environment Map", slc.SceneEnvironment, AssetType::EnvMap))
{
if (slc.DynamicSky) slc.DynamicSky = false;
}
UI::Property("Intensity", slc.Intensity, 0.01f, 0.0f, 5.0f);
ImGui::Separator();
const bool isEnable = UI::Property("Dynamic Sky", slc.DynamicSky);
if (slc.DynamicSky)
@ -1044,7 +1072,7 @@ namespace Prism
changed |= UI::Property("Inclination", slc.TurbidityAzimuthInclination.z, 0.01f);
if (changed || isEnable)
{
Ref<TextureCube> preethamEnv = Renderer3D::CreatePreethamSky(slc.TurbidityAzimuthInclination.x, slc.TurbidityAzimuthInclination.y, slc.TurbidityAzimuthInclination.z);
Ref<TextureCube> preethamEnv = Renderer3D::CreatePreethamSky(slc.TurbidityAzimuthInclination);
slc.SceneEnvironment = Ref<Environment>::Create(preethamEnv, preethamEnv);
}
}

View File

@ -98,7 +98,7 @@ namespace Prism
}
OpenGLFrameBuffer::OpenGLFrameBuffer(const FramebufferSpecification& spec)
: m_Specification(spec), m_Width(spec.Width), m_Height(spec.Height)
: m_Specification(spec)
{
for (auto format : m_Specification.Attachments.Attachments)
{
@ -124,7 +124,7 @@ namespace Prism
Ref<const OpenGLFrameBuffer> instance = this;
Renderer::Submit([instance]() {
glBindFramebuffer(GL_FRAMEBUFFER, instance->m_RendererID);
glViewport(0, 0, instance->m_Width, instance->m_Height);
glViewport(0, 0, instance->m_Specification.Width, instance->m_Specification.Height);
});
}
@ -137,11 +137,11 @@ namespace Prism
void OpenGLFrameBuffer::Resize(const uint32_t width, const uint32_t height, const bool forceReCreate)
{
if (!forceReCreate && (m_Width == width && m_Height == height))
if (!forceReCreate && (m_Specification.Width == width && m_Specification.Height == height))
return;
m_Width = width;
m_Height = height;
m_Specification.Width = width;
m_Specification.Height = height;
Ref<OpenGLFrameBuffer> instance = this;
Renderer::Submit([instance]() mutable
@ -173,16 +173,16 @@ namespace Prism
switch (instance->m_ColorAttachmentFormats[i])
{
case FramebufferTextureFormat::RGBA8:
Utils::AttachColorTexture(instance->m_ColorAttachments[i], instance->m_Specification.Samples, GL_RGBA8, instance->m_Width, instance->m_Height, i);
Utils::AttachColorTexture(instance->m_ColorAttachments[i], instance->m_Specification.Samples, GL_RGBA8, instance->m_Specification.Width, instance->m_Specification.Height, i);
break;
case FramebufferTextureFormat::RGBA16F:
Utils::AttachColorTexture(instance->m_ColorAttachments[i], instance->m_Specification.Samples, GL_RGBA16F, instance->m_Width, instance->m_Height, i);
Utils::AttachColorTexture(instance->m_ColorAttachments[i], instance->m_Specification.Samples, GL_RGBA16F, instance->m_Specification.Width, instance->m_Specification.Height, i);
break;
case FramebufferTextureFormat::RGBA32F:
Utils::AttachColorTexture(instance->m_ColorAttachments[i], instance->m_Specification.Samples, GL_RGBA32F, instance->m_Width, instance->m_Height, i);
Utils::AttachColorTexture(instance->m_ColorAttachments[i], instance->m_Specification.Samples, GL_RGBA32F, instance->m_Specification.Width, instance->m_Specification.Height, i);
break;
case FramebufferTextureFormat::RG32F:
Utils::AttachColorTexture(instance->m_ColorAttachments[i], instance->m_Specification.Samples, GL_RG32F, instance->m_Width, instance->m_Height, i);
Utils::AttachColorTexture(instance->m_ColorAttachments[i], instance->m_Specification.Samples, GL_RG32F, instance->m_Specification.Width, instance->m_Specification.Height, i);
break;
}
@ -196,10 +196,10 @@ namespace Prism
switch (instance->m_DepthAttachmentFormat)
{
case FramebufferTextureFormat::DEPTH24STENCIL8:
Utils::AttachDepthTexture(instance->m_DepthAttachment, instance->m_Specification.Samples, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL_ATTACHMENT, instance->m_Width, instance->m_Height);
Utils::AttachDepthTexture(instance->m_DepthAttachment, instance->m_Specification.Samples, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL_ATTACHMENT, instance->m_Specification.Width, instance->m_Specification.Height);
break;
case FramebufferTextureFormat::DEPTH32F:
Utils::AttachDepthTexture(instance->m_DepthAttachment, instance->m_Specification.Samples, GL_DEPTH_COMPONENT32F, GL_DEPTH_ATTACHMENT, instance->m_Width, instance->m_Height);
Utils::AttachDepthTexture(instance->m_DepthAttachment, instance->m_Specification.Samples, GL_DEPTH_COMPONENT32F, GL_DEPTH_ATTACHMENT, instance->m_Specification.Width, instance->m_Specification.Height);
break;
}

View File

@ -40,8 +40,6 @@ namespace Prism
std::vector<FramebufferTextureFormat> m_ColorAttachmentFormats;
FramebufferTextureFormat m_DepthAttachmentFormat = FramebufferTextureFormat::None;
uint32_t m_Width = 0, m_Height = 0;
};
}

View File

@ -67,7 +67,10 @@ namespace Prism {
void OpenGLStorageBuffer::GetData(void* outData, const uint32_t size, const uint32_t offset) const
{
glGetNamedBufferSubData(m_RendererID, offset, size, outData);
Renderer::Submit([this, outData, size, offset]()
{
glGetNamedBufferSubData(m_RendererID, offset, size, outData);
});
}
}

View File

@ -17,7 +17,7 @@ namespace Prism
{
case TextureFormat::RGB: return GL_RGB;
case TextureFormat::RGBA: return GL_RGBA;
case TextureFormat::Float16: return GL_RGBA16F;
case TextureFormat::RGBA16F: return GL_RGBA16F;
}
return 0;
}
@ -26,7 +26,7 @@ namespace Prism
switch (format) {
case TextureFormat::RGB: return GL_RGB8;
case TextureFormat::RGBA: return GL_RGBA8;
case TextureFormat::Float16: return GL_RGBA16F;
case TextureFormat::RGBA16F: return GL_RGBA16F;
default: return 0;
}
}
@ -35,7 +35,7 @@ namespace Prism
switch (format) {
case TextureFormat::RGB: return GL_RGB;
case TextureFormat::RGBA: return GL_RGBA;
case TextureFormat::Float16: return GL_RGBA; // 根据实际情况调整
case TextureFormat::RGBA16F: return GL_RGBA; // 根据实际情况调整
default: return 0;
}
}
@ -44,7 +44,7 @@ namespace Prism
switch (format) {
case TextureFormat::RGB:
case TextureFormat::RGBA: return GL_UNSIGNED_BYTE;
case TextureFormat::Float16: return GL_HALF_FLOAT;
case TextureFormat::RGBA16F: return GL_HALF_FLOAT;
default: return 0;
}
}
@ -69,7 +69,12 @@ namespace Prism
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
glTextureParameterf(instance->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(instance->m_Format), (GLint)instance->m_Width, (GLint)instance->m_Height, 0, Prism::PrismToOpenGLTextureFormat(instance->m_Format), GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(GL_TEXTURE_2D, 0,
SizedInternalFormat(instance->m_Format), // 内部格式
(GLint)instance->m_Width, (GLint)instance->m_Height, 0,
ImageFormat(instance->m_Format), // 像素格式
DataType(instance->m_Format), // 数据类型
nullptr);
// glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
@ -88,7 +93,7 @@ namespace Prism
PM_CORE_INFO("Loading HDR texture {0}, srgb={1}", path, srgb);
m_ImageData.Data = (byte*)stbi_loadf(path.c_str(), &width, &height, &channels, 0);
m_IsHDR = true;
m_Format = TextureFormat::Float16;
m_Format = TextureFormat::RGBA16F;
}
else
{
@ -126,9 +131,12 @@ namespace Prism
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
const GLint wrap = instance->m_Wrap == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, wrap);
GLenum internalFormat = PrismToOpenGLTextureFormat(instance->m_Format);
GLenum format = srgb ? GL_SRGB8 : (instance->m_IsHDR ? GL_RGB : PrismToOpenGLTextureFormat(instance->m_Format)); // HDR = GL_RGB for now
@ -178,6 +186,27 @@ namespace Prism
});
}
void OpenGLTexture2D::SetData(const void* data, int count)
{
Lock();
PM_CORE_ASSERT(count <= m_ImageData.Size * 4);
// Convert RGBA32F color to RGBA8
auto pixels = m_ImageData.Data;
const auto* pixelData = static_cast<const glm::vec4*>(data);
for (uint32_t i = 0; i < m_Width * m_Height; i++)
{
const glm::vec4& value = pixelData[i];
*pixels++ = static_cast<uint32_t>(value.x * 255.0f);
*pixels++ = static_cast<uint32_t>(value.y * 255.0f);
*pixels++ = static_cast<uint32_t>(value.z * 255.0f);
*pixels++ = static_cast<uint32_t>(value.w * 255.0f);
}
Unlock();
}
void OpenGLTexture2D::Resize(uint32_t width, uint32_t height)
{
PM_CORE_ASSERT(m_Locked, "Texture must be locked!");

View File

@ -30,6 +30,8 @@ namespace Prism
virtual void Lock() override;
virtual void Unlock() override;
virtual void SetData(const void* data, int count) override;
virtual void Resize(uint32_t width, uint32_t height) override;
virtual Buffer GetWriteableBuffer() override;
@ -47,7 +49,7 @@ namespace Prism
RendererID m_RendererID = 0;
TextureFormat m_Format;
unsigned int m_Width, m_Height;
TextureWrap m_Wrap = TextureWrap::Clamp;
TextureWrap m_Wrap = TextureWrap::Repeat;
bool m_IsHDR = false;
bool m_Loaded = false;

View File

@ -119,6 +119,8 @@ namespace Prism
static Ref<MaterialInstance> Create(const Ref<Material>& material);
static Ref<MaterialInstance> Copy(Ref<MaterialInstance> other);
template<typename T>
T& Get(const std::string& name)
{

View File

@ -38,13 +38,16 @@ namespace Prism
// Ref<RenderPass> CompositePass;
Ref<RenderPass> BloomBlurPass[2];
Ref<RenderPass> BloomBlendPass;
Ref<Texture2D> ResolvedHDRTexture; // 解析后的单样本 HDR 颜色
struct AutoExposureData
{
Ref<RenderPass> LuminancePass;
float Exposure = 1.0f;
bool EnableAutoExposure = true;
float Key = 0.11f;
float Key = 0.3f;
Timer ExposureTimer;
float MaxExposure = 5.0f;
float MinExposure = 0.01f;
@ -266,12 +269,16 @@ namespace Prism
s_Data.BlackCubeTexture = TextureCube::Create(TextureFormat::RGBA, 1, 1, &blackTextureData);
}
void Renderer3D::SetViewportSize(uint32_t width, uint32_t height)
void Renderer3D::SetViewportSize(const uint32_t width, const uint32_t height)
{
s_Data.GeoPass->GetSpecification().TargetFramebuffer->Resize(width, height);
// s_Data.CompositePass->GetSpecification().TargetFramebuffer->Resize(width, height);
if (s_Data.AutoExposureData.LuminancePass)
s_Data.AutoExposureData.LuminancePass->GetSpecification().TargetFramebuffer->Resize(width, height);
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->Resize(width, height);
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->Resize(width, height);
s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->Resize(width, height);
}
void Renderer3D::BeginScene(const Scene* scene, const SceneRendererCamera& camera)
@ -331,11 +338,11 @@ namespace Prism
constexpr uint32_t cubemapSize = 2048;
constexpr uint32_t irradianceMapSize = 32;
Ref<TextureCube> envUnfiltered = TextureCube::Create(TextureFormat::Float16, cubemapSize, cubemapSize);
Ref<TextureCube> envUnfiltered = TextureCube::Create(TextureFormat::RGBA16F, cubemapSize, cubemapSize);
if (!equirectangularConversionShader)
equirectangularConversionShader = Shader::Create("assets/shaders/EquirectangularToCubeMap.glsl");
Ref<Texture2D> envEquirect = Texture2D::Create(filepath);
if (envEquirect->GetFormat() != TextureFormat::Float16)
if (envEquirect->GetFormat() != TextureFormat::RGBA16F)
PM_CORE_WARN("Texture is not HDR!");
equirectangularConversionShader->Bind();
@ -351,7 +358,7 @@ namespace Prism
if (!envFilteringShader)
envFilteringShader = Shader::Create("assets/shaders/EnvironmentMipFilter.glsl");
Ref<TextureCube> envFiltered = TextureCube::Create(TextureFormat::Float16, cubemapSize, cubemapSize);
Ref<TextureCube> envFiltered = TextureCube::Create(TextureFormat::RGBA16F, cubemapSize, cubemapSize);
Renderer::Submit([envUnfiltered, envFiltered]()
{
@ -377,7 +384,7 @@ namespace Prism
if (!envIrradianceShader)
envIrradianceShader = Shader::Create("assets/shaders/EnvironmentIrradiance.glsl");
Ref<TextureCube> irradianceMap = TextureCube::Create(TextureFormat::Float16, irradianceMapSize, irradianceMapSize);
Ref<TextureCube> irradianceMap = TextureCube::Create(TextureFormat::RGBA16F, irradianceMapSize, irradianceMapSize);
envIrradianceShader->Bind();
envFiltered->Bind();
Renderer::Submit([irradianceMap]()
@ -393,19 +400,18 @@ namespace Prism
static Ref<Shader> preethamSkyShader;
Ref<TextureCube> Renderer3D::CreatePreethamSky(float turbidity, float azimuth, float inclination)
Ref<TextureCube> Renderer3D::CreatePreethamSky(const glm::vec3& turbidityAzimuthInclination)
{
constexpr uint32_t cubemapSize = 2048;
Ref<TextureCube> environmentMap = TextureCube::Create(TextureFormat::Float16, cubemapSize, cubemapSize);
Ref<TextureCube> environmentMap = TextureCube::Create(TextureFormat::RGBA16F, cubemapSize, cubemapSize);
if (!preethamSkyShader)
preethamSkyShader = Shader::Create("assets/shaders/PreethamSky.glsl");
preethamSkyShader->Bind();
const glm::vec3 TurbidityAzimuthInclination = { turbidity, azimuth, inclination};
preethamSkyShader->SetFloat3("u_TurbidityAzimuthInclination", TurbidityAzimuthInclination);
preethamSkyShader->SetFloat3("u_TurbidityAzimuthInclination", turbidityAzimuthInclination);
Renderer::Submit([environmentMap, cubemapSize]()
{
@ -418,13 +424,6 @@ namespace Prism
return environmentMap;
}
/*
Ref<RenderPass> Renderer3D::GetFinalRenderPass()
{
return s_Data.CompositePass;
}
*/
Ref<RenderPass> Renderer3D::GetGeoPass()
{
return s_Data.GeoPass;
@ -441,12 +440,6 @@ namespace Prism
s_Data.FocusPoint = point;
}
/*
uint32_t Renderer3D::GetFinalColorBufferRendererID()
{
return s_Data.CompositePass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
}
*/
SceneRendererOptions& Renderer3D::GetOptions()
{
@ -475,6 +468,8 @@ namespace Prism
Renderer::Submit([] { s_Stats.GeometryPass = s_Stats.GeometryPassTimer.ElapsedMillis(); });
}
ResolveMSAA();
// Compute average luminance and update exposure (GPU-copy + mipmap -> read 1 texel)
{
Renderer::Submit([]() { s_Stats.AutoExposurePassTimer.Reset(); });
@ -482,30 +477,13 @@ namespace Prism
Renderer::Submit([] { s_Stats.AutoExposurePass = s_Stats.AutoExposurePassTimer.ElapsedMillis(); });
}
BloomBlurPass();
OverlayPass();
{
Renderer::Submit([]() { s_Stats.CompositePassTimer.Reset(); });
// CompositePass();
{
Renderer::BeginRenderPass(outRenderPass);
s_Data.CompositeShader->Bind();
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->SetFloat("u_EnableBloom", s_Data.EnableBloom);
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
Renderer::Submit([]()
{
glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID());
});
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
CompositePass(outRenderPass);
Renderer::Submit([] { s_Stats.CompositePass = s_Stats.CompositePassTimer.ElapsedMillis(); });
// BloomBlurPass();
}
@ -517,6 +495,119 @@ namespace Prism
s_Data.SceneData = {};
}
void Renderer3D::AutoExposurePass()
{
auto& ae = s_Data.AutoExposureData;
if (!ae.EnableAutoExposure)
return;
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
auto dstFB = ae.LuminancePass->GetSpecification().TargetFramebuffer;
if (!srcFB || !dstFB) return;
float dt = ae.ExposureTimer;
ae.ExposureTimer.Reset();
Renderer::Submit([srcFB, dstFB, logMin = ae.LogMin, logMax = ae.LogMax, histCS = ae.HistogramCS, histSSBO = ae.HistogramSSBO]() {
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFB->GetRendererID());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFB->GetRendererID());
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
0, 0, dstFB->GetWidth(), dstFB->GetHeight(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
const uint32_t zero = 0;
glClearNamedBufferData(histSSBO->GetRendererID(), GL_R32UI, GL_RED, GL_UNSIGNED_INT, &zero);
glUseProgram(histCS->GetRendererID());
glBindTextureUnit(0, dstFB->GetColorAttachmentRendererID());
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);
const uint32_t groupsX = (dstFB->GetWidth() + 15) / 16;
const uint32_t groupsY = (dstFB->GetHeight() + 15) / 16;
glDispatchCompute(groupsX, groupsY, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
});
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) {
const GLint loc = glGetUniformLocation(ae.ExposureCS->GetRendererID(), name);
if (loc != -1) glProgramUniform1f(ae.ExposureCS->GetRendererID(), loc, value);
};
setUniform("u_SpeedUp", ae.SpeedUp);
setUniform("u_SpeedDown", ae.SpeedDown);
setUniform("u_Key", ae.Key);
setUniform("u_LowPercent", ae.LowPercent);
setUniform("u_HighPercent", ae.HighPercent);
setUniform("u_MinExposure", ae.MinExposure);
setUniform("u_MaxExposure", ae.MaxExposure);
setUniform("u_DeltaTime", dt);
setUniform("u_LogMin", ae.LogMin);
setUniform("u_LogMax", ae.LogMax);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
});
}
void Renderer3D::ShadowMapPass()
{
const auto& directionalLights = s_Data.SceneData.SceneLightEnvironment.DirectionalLights;
if (!s_Data.ShadowEnabled || directionalLights[0].Intensity == 0.0f || !directionalLights[0].CastShadows)
{
// Clear shadow maps
Renderer::BeginRenderPass(s_Data.ShadowMapRenderPass);
Renderer::EndRenderPass();
return;
}
// TODO: this will not be hardcode
const glm::vec3 lightDir = glm::normalize(directionalLights[0].Direction); // 光线方向(从光源指向场景)
const glm::vec3 lightPos = lightDir * 100.0f;
const glm::mat4 lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
const float orthoSize = 100.0f;
const float nearPlane = 0.01f, farPlane = 1000.0f;
const glm::mat4 lightProjection = glm::ortho(-orthoSize, orthoSize, -orthoSize, orthoSize, nearPlane, farPlane);
const glm::mat4 lightSpaceMatrix = lightProjection * lightView;
Renderer::Submit([]()
{
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
});
{
Renderer::BeginRenderPass(s_Data.ShadowMapRenderPass);
s_Data.LightMatrices = lightSpaceMatrix;
// Render entities
for (auto& dc : s_Data.ShadowPassDrawList)
{
Ref<Shader> shader = dc.mesh->IsAnimated() ? s_Data.ShadowMapAnimShader : s_Data.ShadowMapShader;
shader->SetMat4("u_LightViewProjection", lightSpaceMatrix);
Renderer::SubmitMeshWithShader(dc.mesh, dc.Transform, shader);
}
Renderer::EndRenderPass();
}
}
void Renderer3D::GeometryPass()
{
const bool outline = !s_Data.SelectedMeshDrawList.empty();
@ -549,7 +640,6 @@ namespace Prism
// Skybox
auto skyboxShader = s_Data.SceneData.SkyboxMaterial->GetShader();
s_Data.SceneData.SkyboxMaterial->Set("u_InverseVP", glm::inverse(cameraViewProjection));
s_Data.SceneData.SkyboxMaterial->Set("u_SkyIntensity", s_Data.SceneData.SceneEnvironmentIntensity);
// s_Data.SceneInfo.EnvironmentIrradianceMap->Bind(0);
@ -830,24 +920,7 @@ namespace Prism
// Grid
const auto option = GetOptions();
if (option.ShowGrid)
{
s_Data.GridData.GridMaterial->Set("u_View", sceneCamera.ViewMatrix);
s_Data.GridData.GridMaterial->Set("u_Projection", cameraProjection);
s_Data.GridData.GridMaterial->Set("u_CameraPosition", cameraPosition);
// grid config
s_Data.GridData.GridMaterial->Set("u_GridPlane", s_Data.GridData.GridPlane);
s_Data.GridData.GridMaterial->Set("u_GridScale", s_Data.GridData.GridScale);
s_Data.GridData.GridMaterial->Set("u_GridColorThin", s_Data.GridData.GridColorThin);
s_Data.GridData.GridMaterial->Set("u_GridColorThick", s_Data.GridData.GridColorThick);
s_Data.GridData.GridMaterial->Set("u_AxisColorX", s_Data.GridData.AxisColorX);
s_Data.GridData.GridMaterial->Set("u_AxisColorZ", s_Data.GridData.AxisColorZ);
s_Data.GridData.GridMaterial->Set("u_FadeDistance", s_Data.GridData.FadeDistance);
Renderer::SubmitFullscreenQuad(s_Data.GridData.GridMaterial);
}
const auto option = GetOptions();
if (option.ShowBoundingBoxes)
{
@ -860,74 +933,174 @@ namespace Prism
Renderer::EndRenderPass();
}
void Renderer3D::AutoExposurePass()
void Renderer3D::BloomBlurPass()
{
auto& ae = s_Data.AutoExposureData;
if (!ae.EnableAutoExposure)
if (!s_Data.EnableBloom)
{
// 如果关闭 Bloom可以清除 BloomBlendPass避免使用旧数据
Renderer::BeginRenderPass(s_Data.BloomBlendPass);
Renderer::EndRenderPass();
return;
}
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
auto dstFB = ae.LuminancePass->GetSpecification().TargetFramebuffer;
if (!srcFB || !dstFB) return;
uint32_t srcTex = s_Data.ResolvedHDRTexture->GetRendererID();
const int iterations = 5; // 模糊迭代次数,可调
float dt = ae.ExposureTimer;
ae.ExposureTimer.Reset();
// 第一次:提取高光 + 水平模糊
{
Renderer::BeginRenderPass(s_Data.BloomBlurPass[0]);
s_Data.BloomBlurShader->Bind();
s_Data.BloomBlurShader->SetInt("u_Texture", 0);
// s_Data.BloomBlurShader->SetBool("u_Horizontal", true);
s_Data.BloomBlurShader->SetBool("u_FirstPass", true);
s_Data.BloomBlurShader->SetFloat("u_Threshold", s_Data.BloomThreshold);
Renderer::Submit([srcTex]() { glBindTextureUnit(0, srcTex); });
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
Renderer::Submit([srcFB, dstFB, logMin = ae.LogMin, logMax = ae.LogMax, histCS = ae.HistogramCS, histSSBO = ae.HistogramSSBO]() {
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFB->GetRendererID());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFB->GetRendererID());
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
0, 0, dstFB->GetWidth(), dstFB->GetHeight(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// 后续迭代
for (int i = 1; i < iterations; ++i)
{
bool horizontal = (i % 2 == 1); // 第二次垂直,第三次水平...
uint32_t inputTex = (i % 2 == 1) ?
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID() :
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
auto outputPass = (i % 2 == 1) ? s_Data.BloomBlurPass[1] : s_Data.BloomBlurPass[0];
const uint32_t zero = 0;
glClearNamedBufferData(histSSBO->GetRendererID(), GL_R32UI, GL_RED, GL_UNSIGNED_INT, &zero);
Renderer::BeginRenderPass(outputPass);
s_Data.BloomBlurShader->Bind();
s_Data.BloomBlurShader->SetInt("u_Texture", 0);
// s_Data.BloomBlurShader->SetBool("u_Horizontal", horizontal);
s_Data.BloomBlurShader->SetBool("u_FirstPass", false);
Renderer::Submit([inputTex]() { glBindTextureUnit(0, inputTex); });
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
glUseProgram(histCS->GetRendererID());
glBindTextureUnit(0, dstFB->GetColorAttachmentRendererID());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, histSSBO->GetRendererID());
// 将最终模糊结果拷贝到 BloomBlendPass供合成使用
uint32_t finalBlurTex = (iterations % 2 == 0) ?
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID() :
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
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);
const uint32_t groupsX = (dstFB->GetWidth() + 15) / 16;
const uint32_t groupsY = (dstFB->GetHeight() + 15) / 16;
glDispatchCompute(groupsX, groupsY, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
});
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) {
const GLint loc = glGetUniformLocation(ae.ExposureCS->GetRendererID(), name);
if (loc != -1) glProgramUniform1f(ae.ExposureCS->GetRendererID(), loc, value);
};
setUniform("u_SpeedUp", ae.SpeedUp);
setUniform("u_SpeedDown", ae.SpeedDown);
setUniform("u_Key", ae.Key);
setUniform("u_LowPercent", ae.LowPercent);
setUniform("u_HighPercent", ae.HighPercent);
setUniform("u_MinExposure", ae.MinExposure);
setUniform("u_MaxExposure", ae.MaxExposure);
setUniform("u_DeltaTime", dt);
setUniform("u_LogMin", ae.LogMin);
setUniform("u_LogMax", ae.LogMax);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
});
Renderer::BeginRenderPass(s_Data.BloomBlendPass);
s_Data.BloomBlurShader->Bind();
s_Data.BloomBlurShader->SetInt("u_Texture", 0);
// s_Data.BloomBlurShader->SetBool("u_Horizontal", false);
s_Data.BloomBlurShader->SetBool("u_FirstPass", false);
Renderer::Submit([finalBlurTex]() { glBindTextureUnit(0, finalBlurTex); });
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
void Renderer3D::OverlayPass()
{
Renderer::BeginRenderPass(s_Data.GeoPass, false);
if (const auto option = GetOptions(); option.ShowGrid)
{
const auto& sceneCamera = s_Data.SceneData.SceneCamera;
const auto cameraProjection = sceneCamera.Camera.GetProjectionMatrix();
const glm::vec3 cameraPosition = glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix)[3]; // TODO: Negate instead
s_Data.GridData.GridMaterial->Set("u_View", sceneCamera.ViewMatrix);
s_Data.GridData.GridMaterial->Set("u_Projection", cameraProjection);
s_Data.GridData.GridMaterial->Set("u_CameraPosition", cameraPosition);
// grid config
s_Data.GridData.GridMaterial->Set("u_GridPlane", s_Data.GridData.GridPlane);
s_Data.GridData.GridMaterial->Set("u_GridScale", s_Data.GridData.GridScale);
s_Data.GridData.GridMaterial->Set("u_GridColorThin", s_Data.GridData.GridColorThin);
s_Data.GridData.GridMaterial->Set("u_GridColorThick", s_Data.GridData.GridColorThick);
s_Data.GridData.GridMaterial->Set("u_AxisColorX", s_Data.GridData.AxisColorX);
s_Data.GridData.GridMaterial->Set("u_AxisColorZ", s_Data.GridData.AxisColorZ);
s_Data.GridData.GridMaterial->Set("u_FadeDistance", s_Data.GridData.FadeDistance);
Renderer::SubmitFullscreenQuad(s_Data.GridData.GridMaterial);
}
Renderer::EndRenderPass();
}
void Renderer3D::CompositePass(const Ref<RenderPass>& outRenderPass)
{
Renderer::BeginRenderPass(outRenderPass);
s_Data.CompositeShader->Bind();
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->SetBool("u_EnableBloom", s_Data.EnableBloom);
// 绑定几何阶段颜色纹理(多重采样)
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture(0); // 通常绑定到单元0
Renderer::Submit([]() {
glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID());
});
// 新增:绑定 Bloom 纹理(如果启用)
if (s_Data.EnableBloom)
{
uint32_t bloomTex = s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
Renderer::Submit([bloomTex]() {
glBindTextureUnit(2, bloomTex); // 绑定到单元2
});
s_Data.CompositeShader->SetInt("u_BloomTexture", 2); // 告诉着色器使用单元2
}
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
/*
void Renderer3D::CompositePass(const Ref<RenderPass>& outRenderPass)
{
Renderer::BeginRenderPass(outRenderPass);
s_Data.CompositeShader->Bind();
s_Data.BloomBlendShader->Bind();
s_Data.BloomBlendShader->SetBool("u_EnableBloom", s_Data.EnableBloom);
s_Data.AutoExposureData.ExposureSSBO->BindBase(2);
Renderer::Submit([]() {
glBindTextureUnit(0, s_Data.ResolvedHDRTexture->GetRendererID());
});
s_Data.BloomBlendShader->SetInt("u_SceneTexture", 0);
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->SetFloat("u_EnableBloom", s_Data.EnableBloom);
if (s_Data.EnableBloom)
{
uint32_t bloomTex = s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
Renderer::Submit([bloomTex]() {
glBindTextureUnit(1, bloomTex);
});
s_Data.BloomBlendShader->SetInt("u_BloomTexture", 1);
}
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
Renderer::Submit([]()
{
glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID());
});
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
*/
/*
struct FrustumBounds
{
@ -1084,61 +1257,47 @@ namespace Prism
return corners;
}
void Renderer3D::ShadowMapPass()
void Renderer3D::ResolveMSAA()
{
const auto& directionalLights = s_Data.SceneData.SceneLightEnvironment.DirectionalLights;
if (directionalLights[0].Intensity == 0.0f || !directionalLights[0].CastShadows)
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
const uint32_t width = srcFB->GetWidth();
const uint32_t height = srcFB->GetHeight();
if (!s_Data.ResolvedHDRTexture ||
s_Data.ResolvedHDRTexture->GetWidth() != width ||
s_Data.ResolvedHDRTexture->GetHeight() != height)
{
for (int i = 0; i < 4; i++)
{
// Clear shadow maps
Renderer::BeginRenderPass(s_Data.ShadowMapRenderPass);
Renderer::EndRenderPass();
}
return;
s_Data.ResolvedHDRTexture = Texture2D::Create(TextureFormat::RGBA16F, width, height);
}
// TODO: this will not be hardcode
const glm::vec3 lightDir = glm::normalize(directionalLights[0].Direction); // 光线方向(从光源指向场景)
const glm::vec3 lightPos = lightDir * 100.0f;
const glm::mat4 lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
Renderer::Submit([srcFB, resolvedTex = s_Data.ResolvedHDRTexture]() {
GLuint resolveFBO;
glGenFramebuffers(1, &resolveFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolvedTex->GetRendererID(), 0);
const float orthoSize = 100.0f;
const float nearPlane = 0.01f, farPlane = 1000.0f;
const glm::mat4 lightProjection = glm::ortho(-orthoSize, orthoSize, -orthoSize, orthoSize, nearPlane, farPlane);
const glm::mat4 lightSpaceMatrix = lightProjection * lightView;
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFB->GetRendererID());
glReadBuffer(GL_COLOR_ATTACHMENT0);
Renderer::Submit([]()
{
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glBlitFramebuffer(0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glDeleteFramebuffers(1, &resolveFBO);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
});
{
Renderer::BeginRenderPass(s_Data.ShadowMapRenderPass);
s_Data.LightMatrices = lightSpaceMatrix;
// Render entities
for (auto& dc : s_Data.ShadowPassDrawList)
{
Ref<Shader> shader = dc.mesh->IsAnimated() ? s_Data.ShadowMapAnimShader : s_Data.ShadowMapShader;
shader->SetMat4("u_LightViewProjection", lightSpaceMatrix);
Renderer::SubmitMeshWithShader(dc.mesh, dc.Transform, shader);
}
Renderer::EndRenderPass();
}
}
void SceneRenderer::OnImGuiRender()
{
ImGui::Begin("Scene Renderer");
UI::Property("Composite Pass time", s_Stats.CompositePass);
UI::Property("Geometry Pass time", s_Stats.GeometryPass);
UI::Property("Composite Pass time", s_Stats.CompositePass);
UI::Property("Shadow Pass time", s_Stats.ShadowPass);
UI::Property("AutoExposure Pass time", s_Stats.AutoExposurePass);
@ -1207,10 +1366,15 @@ namespace Prism
auto fb = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer;
const auto id = fb->GetColorAttachmentRendererID();
auto fb2 = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer;
const auto id2 = fb2->GetColorAttachmentRendererID();
const float size = ImGui::GetContentRegionAvail().x; // (float)fb->GetWidth() * 0.5f, (float)fb->GetHeight() * 0.5f
float w = size;
float h = w / ((float)fb->GetWidth() / (float)fb->GetHeight());
ImGui::Image((ImTextureID)id, { w, h }, { 0, 1 }, { 1, 0 });
ImGui::Image((ImTextureID)id2, { w, h }, { 0, 1 }, { 1, 0 });
ImGui::Image((ImTextureID)s_Data.ResolvedHDRTexture->GetRendererID(), { w, h }, { 0, 1 }, { 1, 0 });
UI::EndTreeNode();
}

View File

@ -41,7 +41,7 @@ namespace Prism
static void SubmitColliderMesh(const CapsuleColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
static void SubmitColliderMesh(const MeshColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
static std::pair<Ref<TextureCube>, Ref<TextureCube>> CreateEnvironmentMap(const std::string& filepath);
static Ref<TextureCube> CreatePreethamSky(float turbidity, float azimuth, float inclination);
static Ref<TextureCube> CreatePreethamSky(const glm::vec3& turbidityAzimuthInclination);
// static Ref<RenderPass> GetFinalRenderPass();
static Ref<RenderPass> GetGeoPass();
@ -59,10 +59,15 @@ namespace Prism
static void FlushDrawList(Ref<RenderPass>& outRenderPass);
static void AutoExposurePass();
static void GeometryPass();
// static void CompositePass();
// static void BloomBlurPass();
static void ShadowMapPass();
static void GeometryPass();
static void BloomBlurPass();
static void OverlayPass();
static void CompositePass(const Ref<RenderPass>& outRenderPass);
static void ResolveMSAA();
};
}

View File

@ -23,9 +23,6 @@ namespace Prism
{
Prism::Camera Camera;
glm::mat4 ViewMatrix;
float Near, Far;
float FOV;
};
class PRISM_API SceneRenderer

View File

@ -18,7 +18,7 @@ namespace Prism
None = 0,
RGB = 1,
RGBA = 2,
Float16 = 3,
RGBA16F = 3,
};
enum class TextureWrap
@ -62,6 +62,7 @@ namespace Prism
virtual void Lock() = 0;
virtual void Unlock() = 0;
virtual void SetData(const void* data, int count) = 0;
virtual void Resize(uint32_t width, uint32_t height) = 0;
virtual Buffer GetWriteableBuffer() = 0;

View File

@ -91,13 +91,32 @@ namespace Prism
struct MeshComponent
{
Ref<Mesh> Mesh;
// std::vector<Ref<MaterialInstance>> Materials;
MeshComponent() = default;
MeshComponent(const MeshComponent& other) = default;
MeshComponent(const Ref<Prism::Mesh>& mesh)
: Mesh(mesh) {}
: Mesh(mesh) {}
operator Ref<Prism::Mesh> () { return Mesh; }
/*
MeshComponent(Ref<Prism::Mesh> mesh)
: Mesh(mesh)
{
// 复制 Mesh 的材质实例,每个实体拥有独立副本
if (mesh)
{
const auto& srcMaterials = mesh->GetMaterials();
Materials.reserve(srcMaterials.size());
for (auto& srcMat : srcMaterials)
{
auto newMat = MaterialInstance::Copy(srcMat);
Materials.push_back(newMat);
}
}
}
*/
};
struct AnimationComponent
@ -126,6 +145,7 @@ namespace Prism
{
SceneCamera Camera;
bool Primary = true;
bool ShowIcon = true;
CameraComponent() = default;
CameraComponent(const CameraComponent& other) = default;
@ -373,6 +393,7 @@ namespace Prism
bool CastShadows = true;
bool SoftShadows = true;
float LightSize = 0.5f; // For PCSS
bool ShowIcon = true;
};
struct PointLightComponent
@ -381,6 +402,7 @@ namespace Prism
float Radius = 10.0f;
float Intensity = 1.0f;
uint32_t CastShadows;
bool ShowIcon = true;
PointLightComponent() = default;
PointLightComponent(const PointLightComponent& other) = default;
@ -395,6 +417,7 @@ namespace Prism
float InnerConeAngle = glm::radians(30.0f); // 内锥角(半角)
float OuterConeAngle = glm::radians(45.0f); // 外锥角(半角)
bool CastShadows = true; // 聚光通常需要阴影
bool ShowIcon = true;
SpotLightComponent() = default;
SpotLightComponent(const SpotLightComponent& other) = default;
@ -405,6 +428,7 @@ namespace Prism
Ref<Environment> SceneEnvironment;
float Intensity = 1.0f;
float Angle = 0.0f;
bool ShowIcon = false;
bool DynamicSky = false;
glm::vec3 TurbidityAzimuthInclination = { 2.0, 0.0, 0.0 };

View File

@ -159,34 +159,15 @@ namespace Prism
return;
const glm::mat4 cameraViewMatrix = glm::inverse(GetTransformRelativeToParent(cameraEntity));
PM_CORE_ASSERT(cameraEntity, "Scene does not contain any cameras!");
SceneCamera& camera = cameraEntity.GetComponent<CameraComponent>();
camera.SetViewportSize(m_ViewportWidth, m_ViewportHeight);
/////////////////////////////////////////////////////////////////////
// RENDER 3D SCENE //
/////////////////////////////////////////////////////////////////////
// Process lights
{
m_LightEnvironment = LightEnvironment();
const auto lights = m_Registry.group<DirectionalLightComponent>(entt::get<TransformComponent>);
uint32_t directionalLightIndex = 0;
for (const auto entity : lights)
{
auto [transformComponent, lightComponent] = lights.get<TransformComponent, DirectionalLightComponent>(entity);
const glm::vec3 direction = -glm::normalize(glm::mat3(transformComponent.GetTransform()) * glm::vec3(0.0f, 0.0f, -1.0f));
m_LightEnvironment.DirectionalLights[directionalLightIndex++] =
{
direction,
lightComponent.Radiance,
lightComponent.Intensity,
lightComponent.CastShadows
};
}
}
UpdateLights();
// TODO: only one sky light at the moment!
{
@ -248,70 +229,9 @@ namespace Prism
void Scene::OnRenderEditor(const TimeStep ts, const EditorCamera& editorCamera)
{
/////////////////////////////////////////////////////////////////////
// RENDER 3D SCENE //
/////////////////////////////////////////////////////////////////////
// Process lights
{
const auto lights = m_Registry.group<DirectionalLightComponent>(entt::get<TransformComponent>);
uint32_t directionalLightIndex = 0;
for (const auto entity : lights)
{
auto [transformComponent, lightComponent] = lights.get<TransformComponent, DirectionalLightComponent>(entity);
const glm::vec3 direction = glm::normalize(glm::mat3(transformComponent.GetTransform()) * glm::vec3(0.0f, 0.0f,1.0f));
m_LightEnvironment.DirectionalLights[directionalLightIndex++] =
{
direction,
lightComponent.Radiance,
lightComponent.Intensity,
lightComponent.CastShadows
};
}
}
{
const auto pointLights = m_Registry.group<PointLightComponent>(entt::get<TransformComponent>);
uint32_t pointLightIndex = 0;
for (const auto entity : pointLights)
{
if (pointLightIndex >= 8) break;
auto [transform, light] = pointLights.get<TransformComponent, PointLightComponent>(entity);
m_LightEnvironment.PointLights[pointLightIndex++] = {
transform.Translation,
light.Radiance,
light.Radius,
light.Intensity,
light.CastShadows,
};
m_LightEnvironment.PointLightCount ++;
}
}
{
const auto spotLights = m_Registry.group<SpotLightComponent>(entt::get<TransformComponent>);
uint32_t pointLightIndex = 0;
for (const auto entity : spotLights)
{
if (pointLightIndex >= 8) break;
auto [transform, light] = spotLights.get<TransformComponent, SpotLightComponent>(entity);
const glm::vec3 direction = glm::normalize(glm::mat3(transform.GetTransform()) * glm::vec3(0.0f, 0.0f, 1.0f));
const float innerCos = glm::cos(glm::radians(light.InnerConeAngle));
const float outerCos = glm::cos(glm::radians(light.OuterConeAngle));
m_LightEnvironment.SpotLights[pointLightIndex++] = {
transform.Translation,
direction,
light.Radiance,
light.Intensity,
light.Range,
innerCos,
outerCos,
light.CastShadows,
};
m_LightEnvironment.SpotLightCount ++;
}
}
// Process lights Direction, Point, Spot
UpdateLights();
// TODO: only one sky light at the moment!
{
@ -325,7 +245,7 @@ namespace Prism
auto [transformComponent, skyLightComponent] = lights.get<TransformComponent, SkyLightComponent>(entity);
if (!skyLightComponent.SceneEnvironment && skyLightComponent.DynamicSky)
{
Ref<TextureCube> preethamEnv = Renderer3D::CreatePreethamSky(skyLightComponent.TurbidityAzimuthInclination.x, skyLightComponent.TurbidityAzimuthInclination.y, skyLightComponent.TurbidityAzimuthInclination.z);
Ref<TextureCube> preethamEnv = Renderer3D::CreatePreethamSky(skyLightComponent.TurbidityAzimuthInclination);
skyLightComponent.SceneEnvironment = Ref<Environment>::Create(preethamEnv, preethamEnv);
}
@ -341,8 +261,13 @@ namespace Prism
// TODO: this value should be storage and can modify
// TODO: Renderer2D cannot blend with Renderer3D
SceneRenderer::BeginScene(this, { static_cast<Camera>(editorCamera), editorCamera.GetViewMatrix(), 0.1f, 1000.0f, 45.0f}, false);
SceneRenderer::BeginScene(this, { static_cast<Camera>(editorCamera), editorCamera.GetViewMatrix()}, false);
{
/////////////////////////////////////////////////////////////////////
// RENDER 3D SCENE //
/////////////////////////////////////////////////////////////////////
const auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
{
for (const auto [entity, meshComponent, transformComponent]: group.each())
@ -400,23 +325,57 @@ namespace Prism
// render camera icon
{
const auto editorCameraPosition = editorCamera.GetPosition();
const auto editorCameraUpDirection = editorCamera.GetUpDirection();
const auto cameras = m_Registry.view<CameraComponent>();
if (!cameras.empty())
{
for (auto& entity : cameras)
{
Entity e = { entity, this };
SceneRenderer::SubmitBillBoardQuad(e.Transform().Translation, m_CameraIcon, editorCamera.GetPosition(), editorCamera.GetUpDirection());
if (!e.GetComponent<CameraComponent>().ShowIcon) continue;
SceneRenderer::SubmitBillBoardQuad(e.Transform().Translation, m_CameraIcon, editorCameraPosition, editorCameraUpDirection);
}
}
const auto lights = m_Registry.view<SkyLightComponent>();
if (!lights.empty())
if (const auto skyLights = m_Registry.view<SkyLightComponent>(); !skyLights.empty())
{
for (auto& entity : lights)
for (auto& entity : skyLights)
{
Entity e = { entity, this };
SceneRenderer::SubmitBillBoardQuad(e.Transform().Translation, m_LightIcon, editorCamera.GetPosition(), editorCamera.GetUpDirection());
if (!e.GetComponent<SkyLightComponent>().ShowIcon) continue;
SceneRenderer::SubmitBillBoardQuad(e.Transform().Translation, m_LightIcon, editorCameraPosition, editorCameraUpDirection);
}
}
if (const auto directionLight = m_Registry.view<DirectionalLightComponent>(); !directionLight.empty())
{
for (auto& entity : directionLight)
{
Entity e = { entity, this };
if (!e.GetComponent<DirectionalLightComponent>().ShowIcon) continue;
SceneRenderer::SubmitBillBoardQuad(e.Transform().Translation, m_LightIcon, editorCameraPosition, editorCameraUpDirection);
}
}
if (const auto pointLight = m_Registry.view<PointLightComponent>(); !pointLight.empty())
{
for (auto& entity : pointLight )
{
Entity e = { entity, this };
if (!e.GetComponent<PointLightComponent>().ShowIcon) continue;
SceneRenderer::SubmitBillBoardQuad(e.Transform().Translation, m_LightIcon, editorCameraPosition, editorCameraUpDirection);
}
}
if (const auto spotLight = m_Registry.view<SpotLightComponent>(); !spotLight.empty())
{
for (auto& entity : spotLight )
{
Entity e = { entity, this };
if (!e.GetComponent<SpotLightComponent>().ShowIcon) continue;
SceneRenderer::SubmitBillBoardQuad(e.Transform().Translation, m_LightIcon, editorCameraPosition, editorCameraUpDirection);
}
}
}
@ -446,6 +405,7 @@ namespace Prism
// Box2D physics
Physics2D::CreateBody(this);
// PhyX
{
auto view = m_Registry.view<RigidBodyComponent>();
// Physics3D::ExpandEntityBuffer(static_cast<uint32_t>(view.size()));
@ -485,11 +445,10 @@ namespace Prism
Entity Scene::GetMainCameraEntity()
{
auto view = m_Registry.view<CameraComponent>();
const auto view = m_Registry.view<CameraComponent>();
for (auto entity : view)
{
auto& comp = view.get<CameraComponent>(entity);
if (comp.Primary)
if (const auto& comp = view.get<CameraComponent>(entity); comp.Primary)
return { entity, this };
}
return {};
@ -577,33 +536,6 @@ namespace Prism
newEntity = CreateEntity();
CopyComponentIfExists(AllComponent{},newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
/*
CopyComponentIfExists<TransformComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<RelationshipComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<MeshComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<DirectionalLightComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<SkyLightComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<ScriptComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<CameraComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<SpriteRendererComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<RigidBody2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<BoxCollider2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<CircleCollider2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<RigidBodyComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<BoxColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<SphereColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<CapsuleColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<MeshColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<AnimationComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<DistanceJoint2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<RevoluteJoint2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<PrismaticJoint2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<WeldJoint2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
*/
}
Entity Scene::FindEntityByTag(const std::string &tag) {
@ -613,7 +545,7 @@ namespace Prism
{
const auto& canditate = view.get<TagComponent>(entity).Tag;
if (canditate == tag)
return Entity(entity, this);
return {entity, this};
}
return Entity{};
@ -625,8 +557,7 @@ namespace Prism
auto view = m_Registry.view<IDComponent>();
for (auto entity : view)
{
auto& idComponent = m_Registry.get<IDComponent>(entity);
if (idComponent.ID == uuid)
if (auto& idComponent = m_Registry.get<IDComponent>(entity); idComponent.ID == uuid)
return {entity, this};
}
@ -660,32 +591,7 @@ namespace Prism
enttMap[uuid] = e.m_EntityHandle;
}
CopyComponent(AllComponent{},target->m_Registry, m_Registry, enttMap);
/*
CopyComponent<TagComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<TransformComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<RelationshipComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<MeshComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<DirectionalLightComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<SkyLightComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<ScriptComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<CameraComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<SpriteRendererComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<RigidBody2DComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<BoxCollider2DComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<CircleCollider2DComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<RigidBodyComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<BoxColliderComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<SphereColliderComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<CapsuleColliderComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<MeshColliderComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<AnimationComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<DistanceJoint2DComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<RevoluteJoint2DComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<PrismaticJoint2DComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<WeldJoint2DComponent>(target->m_Registry, m_Registry, enttMap);
*/
const auto& entityInstanceMap = ScriptEngine::GetEntityInstanceMap();
if (entityInstanceMap.find(target->GetUUID()) != entityInstanceMap.end())
@ -717,6 +623,72 @@ namespace Prism
b2World_SetGravity(m_Registry.get<Box2DWorldComponent>(m_SceneEntity).World, {0.0f, gravity});
}
void Scene::UpdateLights()
{
// direction Light
{
const auto lights = m_Registry.group<DirectionalLightComponent>(entt::get<TransformComponent>);
uint32_t directionalLightIndex = 0;
for (const auto entity : lights)
{
auto [transformComponent, lightComponent] = lights.get<TransformComponent, DirectionalLightComponent>(entity);
const glm::vec3 direction = glm::normalize(glm::mat3(transformComponent.GetTransform()) * glm::vec3(0.0f, 0.0f,1.0f));
m_LightEnvironment.DirectionalLights[directionalLightIndex++] =
{
direction,
lightComponent.Radiance,
lightComponent.Intensity,
lightComponent.CastShadows
};
}
}
// Point Light
{
const auto pointLights = m_Registry.group<PointLightComponent>(entt::get<TransformComponent>);
uint32_t pointLightIndex = 0;
for (const auto entity : pointLights)
{
if (pointLightIndex >= 8) break;
auto [transform, light] = pointLights.get<TransformComponent, PointLightComponent>(entity);
m_LightEnvironment.PointLights[pointLightIndex++] = {
transform.Translation,
light.Radiance,
light.Radius,
light.Intensity,
light.CastShadows,
};
m_LightEnvironment.PointLightCount ++;
}
}
// Spot Light
{
const auto spotLights = m_Registry.group<SpotLightComponent>(entt::get<TransformComponent>);
uint32_t pointLightIndex = 0;
for (const auto entity : spotLights)
{
if (pointLightIndex >= 8) break;
auto [transform, light] = spotLights.get<TransformComponent, SpotLightComponent>(entity);
const glm::vec3 direction = glm::normalize(glm::mat3(transform.GetTransform()) * glm::vec3(0.0f, 0.0f, 1.0f));
const float innerCos = glm::cos(glm::radians(light.InnerConeAngle));
const float outerCos = glm::cos(glm::radians(light.OuterConeAngle));
m_LightEnvironment.SpotLights[pointLightIndex++] = {
transform.Translation,
direction,
light.Radiance,
light.Intensity,
light.Range,
innerCos,
outerCos,
light.CastShadows,
};
m_LightEnvironment.SpotLightCount ++;
}
}
}
void Scene::DestroyEntity(Entity entity)
{

View File

@ -139,6 +139,9 @@ namespace Prism
// Editor-specific
void SetSelectedEntity(const entt::entity entity) { m_SelectedEntity = entity; }
private:
void UpdateLights();
private:
UUID m_SceneID;
entt::entity m_SceneEntity;

View File

@ -291,6 +291,9 @@ namespace Prism
out << YAML::Key << "Intensity" << YAML::Value << skyLightComponent.Intensity;
out << YAML::Key << "Angle" << YAML::Value << skyLightComponent.Angle;
out << YAML::Key << "DynamicSky" << YAML::Value << skyLightComponent.DynamicSky;
out << YAML::Key << "TurbidityAzimuthInclination" << YAML::Value << skyLightComponent.TurbidityAzimuthInclination;
out << YAML::EndMap; // SkyLightComponent
}
@ -855,7 +858,7 @@ namespace Prism
AssetHandle assetHandle;
if (skyLightComponent["EnvironmentAssetPath"])
{
const std::string filePath = skyLightComponent["EnvironmentAssetPath"].as<std::string>();
const auto filePath = skyLightComponent["EnvironmentAssetPath"].as<std::string>();
assetHandle = AssetsManager::GetAssetHandleFromFilePath(filepath);
}
else
@ -870,6 +873,10 @@ namespace Prism
component.Intensity = skyLightComponent["Intensity"].as<float>();
component.Angle = skyLightComponent["Angle"].as<float>();
component.DynamicSky = skyLightComponent["DynamicSky"].as<bool>();
component.TurbidityAzimuthInclination = skyLightComponent["TurbidityAzimuthInclination"].as<glm::vec3>();
}
if (auto cameraComponent = entity["CameraComponent"])

View File

@ -781,25 +781,7 @@ namespace Prism { namespace Script {
void Prism_Texture2D_SetData(Ref<Texture2D>* _this, MonoArray* inData, int32_t count)
{
Ref<Texture2D>& instance = *_this;
const uint32_t dataSize = count * sizeof(glm::vec4) / 4;
instance->Lock();
const Buffer buffer = instance->GetWriteableBuffer();
PM_CORE_ASSERT(dataSize <= buffer.Size);
// Convert RGBA32F color to RGBA8
auto pixels = static_cast<uint8_t*>(buffer.Data);
for (uint32_t i = 0; i < instance->GetWidth() * instance->GetHeight(); i++)
{
const glm::vec4& value = mono_array_get(inData, glm::vec4, i);
*pixels++ = static_cast<uint32_t>(value.x * 255.0f);
*pixels++ = static_cast<uint32_t>(value.y * 255.0f);
*pixels++ = static_cast<uint32_t>(value.z * 255.0f);
*pixels++ = static_cast<uint32_t>(value.w * 255.0f);
}
instance->Unlock();
instance->SetData(inData, count);
}
void Prism_Material_Destructor(const Ref<Material>* _this)