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; in vec2 v_TexCoord;
uniform sampler2D u_Texture; uniform sampler2D u_Texture;
uniform bool u_Horizontal; uniform bool u_Horizontal; // 未使用,可保留或移除
uniform bool u_FirstPass; // 是否进行阈值处理
uniform float u_Threshold; // 亮度阈值
void main() void main()
{ {
#if 1 float Pi = 6.28318530718; // 2*PI
// From learnopengl.com
float weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
vec2 tex_offset = 1.0 / textureSize(u_Texture, 0); // gets size of single texel float Directions = 32.0; // 模糊方向数
vec3 result = texture(u_Texture, v_TexCoord).rgb * weight[0]; // current fragment's contribution float Quality = 6.0; // 每个方向上的采样质量(采样次数)
if (u_Horizontal) float Size = 16.0; // 模糊半径
{
for(int i = 1; i < 5; ++i)
{
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];
}
}
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); vec2 Radius = Size / textureSize(u_Texture, 0);
vec3 result = texture(u_Texture, v_TexCoord).rgb; // 中心像素采样
vec2 uv = v_TexCoord; vec3 centerColor = texture(u_Texture, v_TexCoord).rgb;
// Blur calculations float centerLum = dot(centerColor, vec3(0.2126, 0.7152, 0.0722));
// 如果启用第一次处理且中心像素亮度低于阈值,则直接输出黑色(不进行模糊)
if (u_FirstPass && centerLum <= u_Threshold)
{
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 d = 0.0; d < Pi; d += Pi / Directions)
{ {
for (float i = 1.0 / Quality; i <= 1.0; i += 1.0 / Quality) 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; 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
// 但为了效果平滑,这里保留为黑色并计入计数
} }
} }
// Output to screen result += sampleColor;
result /= Quality * Directions - 15.0; totalSamples += 1.0;
o_Color = vec4(result, 1.0); }
#endif }
// 归一化:除以总采样数(包括中心像素)
// 若之前选择忽略低于阈值的采样点continue则需相应调整 totalSamples
result /= totalSamples;
o_Color = vec4(result, 1.0);
} }

View File

@ -7,6 +7,8 @@ layout(binding = 0, rgba32f) restrict writeonly uniform imageCube o_CubeMap;
uniform vec3 u_TurbidityAzimuthInclination; uniform vec3 u_TurbidityAzimuthInclination;
#define PI 3.14159265359
vec3 GetCubeMapTexCoord() vec3 GetCubeMapTexCoord()
{ {
vec2 st = gl_GlobalInvocationID.xy / vec2(imageSize(o_CubeMap)); vec2 st = gl_GlobalInvocationID.xy / vec2(imageSize(o_CubeMap));
@ -22,11 +24,10 @@ vec3 GetCubeMapTexCoord()
return normalize(ret); return normalize(ret);
} }
#define PI 3.14159265359
float saturatedDot( in vec3 a, in vec3 b ) 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 ) 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 ) 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 ) ); 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; vec3 A, B, C, D, E;
calculatePerezDistribution( t, A, B, C, D, E ); calculatePerezDistribution( t, A, B, C, D, E );
float thetaS = acos( saturatedDot( s, vec3(0,1,0) ) ); float thetaS = acos(clamp(dot(s, vec3(0,1,0)), 0.0, 1.0));
float thetaE = acos( saturatedDot( e, vec3(0,1,0) ) ); float thetaE = acos(clamp(dot(e, vec3(0,1,0)), 0.0, 1.0));
float gammaE = acos( saturatedDot( s, e ) ); float gammaE = acos( saturatedDot( s, e ) );
vec3 Yz = calculateZenithLuminanceYxy( t, thetaS ); vec3 Yz = calculateZenithLuminanceYxy( t, thetaS );
@ -128,7 +130,29 @@ void main()
float inclination = u_TurbidityAzimuthInclination.z; float inclination = u_TurbidityAzimuthInclination.z;
vec3 sunDir = normalize( vec3( sin(inclination) * cos(azimuth), cos(inclination), sin(inclination) * sin(azimuth) ) ); vec3 sunDir = normalize( vec3( sin(inclination) * cos(azimuth), cos(inclination), sin(inclination) * sin(azimuth) ) );
vec3 viewDir = cubeTC; 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); vec4 color = vec4(skyLuminance * 0.05, 1.0);
imageStore(o_CubeMap, ivec3(gl_GlobalInvocationID), color); imageStore(o_CubeMap, ivec3(gl_GlobalInvocationID), color);

View File

@ -22,6 +22,7 @@ layout(location = 1) out vec4 o_BloomTexture;
in vec2 v_TexCoord; in vec2 v_TexCoord;
uniform sampler2DMS u_Texture; uniform sampler2DMS u_Texture;
uniform sampler2D u_BloomTexture;
uniform bool u_EnableAutoExposure; uniform bool u_EnableAutoExposure;
@ -55,6 +56,17 @@ vec4 MultiSampleTexture(sampler2DMS tex, vec2 tc)
return result; 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() void main()
{ {
const float gamma = 2.2; const float gamma = 2.2;
@ -62,12 +74,11 @@ void main()
// Tonemapping // Tonemapping
vec4 msColor = MultiSampleTexture(u_Texture, v_TexCoord); vec4 msColor = MultiSampleTexture(u_Texture, v_TexCoord);
vec3 color = msColor.rgb; vec3 color = msColor.rgb;
if (u_EnableBloom) if (u_EnableBloom)
{ {
vec3 bloomColor = MultiSampleTexture(u_Texture, v_TexCoord).rgb; vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb;
color += bloomColor; color += bloomColor;
} }

View File

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

View File

@ -98,7 +98,7 @@ namespace Prism
} }
OpenGLFrameBuffer::OpenGLFrameBuffer(const FramebufferSpecification& spec) 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) for (auto format : m_Specification.Attachments.Attachments)
{ {
@ -124,7 +124,7 @@ namespace Prism
Ref<const OpenGLFrameBuffer> instance = this; Ref<const OpenGLFrameBuffer> instance = this;
Renderer::Submit([instance]() { Renderer::Submit([instance]() {
glBindFramebuffer(GL_FRAMEBUFFER, instance->m_RendererID); 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) 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; return;
m_Width = width; m_Specification.Width = width;
m_Height = height; m_Specification.Height = height;
Ref<OpenGLFrameBuffer> instance = this; Ref<OpenGLFrameBuffer> instance = this;
Renderer::Submit([instance]() mutable Renderer::Submit([instance]() mutable
@ -173,16 +173,16 @@ namespace Prism
switch (instance->m_ColorAttachmentFormats[i]) switch (instance->m_ColorAttachmentFormats[i])
{ {
case FramebufferTextureFormat::RGBA8: 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; break;
case FramebufferTextureFormat::RGBA16F: 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; break;
case FramebufferTextureFormat::RGBA32F: 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; break;
case FramebufferTextureFormat::RG32F: 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; break;
} }
@ -196,10 +196,10 @@ namespace Prism
switch (instance->m_DepthAttachmentFormat) switch (instance->m_DepthAttachmentFormat)
{ {
case FramebufferTextureFormat::DEPTH24STENCIL8: 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; break;
case FramebufferTextureFormat::DEPTH32F: 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; break;
} }

View File

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

View File

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

View File

@ -17,7 +17,7 @@ namespace Prism
{ {
case TextureFormat::RGB: return GL_RGB; case TextureFormat::RGB: return GL_RGB;
case TextureFormat::RGBA: return GL_RGBA; case TextureFormat::RGBA: return GL_RGBA;
case TextureFormat::Float16: return GL_RGBA16F; case TextureFormat::RGBA16F: return GL_RGBA16F;
} }
return 0; return 0;
} }
@ -26,7 +26,7 @@ namespace Prism
switch (format) { switch (format) {
case TextureFormat::RGB: return GL_RGB8; case TextureFormat::RGB: return GL_RGB8;
case TextureFormat::RGBA: return GL_RGBA8; case TextureFormat::RGBA: return GL_RGBA8;
case TextureFormat::Float16: return GL_RGBA16F; case TextureFormat::RGBA16F: return GL_RGBA16F;
default: return 0; default: return 0;
} }
} }
@ -35,7 +35,7 @@ namespace Prism
switch (format) { switch (format) {
case TextureFormat::RGB: return GL_RGB; case TextureFormat::RGB: return GL_RGB;
case TextureFormat::RGBA: return GL_RGBA; case TextureFormat::RGBA: return GL_RGBA;
case TextureFormat::Float16: return GL_RGBA; // 根据实际情况调整 case TextureFormat::RGBA16F: return GL_RGBA; // 根据实际情况调整
default: return 0; default: return 0;
} }
} }
@ -44,7 +44,7 @@ namespace Prism
switch (format) { switch (format) {
case TextureFormat::RGB: case TextureFormat::RGB:
case TextureFormat::RGBA: return GL_UNSIGNED_BYTE; case TextureFormat::RGBA: return GL_UNSIGNED_BYTE;
case TextureFormat::Float16: return GL_HALF_FLOAT; case TextureFormat::RGBA16F: return GL_HALF_FLOAT;
default: return 0; default: return 0;
} }
} }
@ -69,7 +69,12 @@ namespace Prism
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
glTextureParameterf(instance->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy); 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); // glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
@ -88,7 +93,7 @@ namespace Prism
PM_CORE_INFO("Loading HDR texture {0}, srgb={1}", path, srgb); 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_ImageData.Data = (byte*)stbi_loadf(path.c_str(), &width, &height, &channels, 0);
m_IsHDR = true; m_IsHDR = true;
m_Format = TextureFormat::Float16; m_Format = TextureFormat::RGBA16F;
} }
else 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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_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); const GLint wrap = instance->m_Wrap == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
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 internalFormat = PrismToOpenGLTextureFormat(instance->m_Format);
GLenum format = srgb ? GL_SRGB8 : (instance->m_IsHDR ? GL_RGB : PrismToOpenGLTextureFormat(instance->m_Format)); // HDR = GL_RGB for now 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) void OpenGLTexture2D::Resize(uint32_t width, uint32_t height)
{ {
PM_CORE_ASSERT(m_Locked, "Texture must be locked!"); PM_CORE_ASSERT(m_Locked, "Texture must be locked!");

View File

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

View File

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

View File

@ -38,13 +38,16 @@ namespace Prism
// Ref<RenderPass> CompositePass; // Ref<RenderPass> CompositePass;
Ref<RenderPass> BloomBlurPass[2]; Ref<RenderPass> BloomBlurPass[2];
Ref<RenderPass> BloomBlendPass; Ref<RenderPass> BloomBlendPass;
Ref<Texture2D> ResolvedHDRTexture; // 解析后的单样本 HDR 颜色
struct AutoExposureData struct AutoExposureData
{ {
Ref<RenderPass> LuminancePass; Ref<RenderPass> LuminancePass;
float Exposure = 1.0f;
bool EnableAutoExposure = true; bool EnableAutoExposure = true;
float Key = 0.11f; float Key = 0.3f;
Timer ExposureTimer; Timer ExposureTimer;
float MaxExposure = 5.0f; float MaxExposure = 5.0f;
float MinExposure = 0.01f; float MinExposure = 0.01f;
@ -266,12 +269,16 @@ namespace Prism
s_Data.BlackCubeTexture = TextureCube::Create(TextureFormat::RGBA, 1, 1, &blackTextureData); 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.GeoPass->GetSpecification().TargetFramebuffer->Resize(width, height);
// s_Data.CompositePass->GetSpecification().TargetFramebuffer->Resize(width, height); // s_Data.CompositePass->GetSpecification().TargetFramebuffer->Resize(width, height);
if (s_Data.AutoExposureData.LuminancePass) if (s_Data.AutoExposureData.LuminancePass)
s_Data.AutoExposureData.LuminancePass->GetSpecification().TargetFramebuffer->Resize(width, height); 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) void Renderer3D::BeginScene(const Scene* scene, const SceneRendererCamera& camera)
@ -331,11 +338,11 @@ namespace Prism
constexpr uint32_t cubemapSize = 2048; constexpr uint32_t cubemapSize = 2048;
constexpr uint32_t irradianceMapSize = 32; 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) if (!equirectangularConversionShader)
equirectangularConversionShader = Shader::Create("assets/shaders/EquirectangularToCubeMap.glsl"); equirectangularConversionShader = Shader::Create("assets/shaders/EquirectangularToCubeMap.glsl");
Ref<Texture2D> envEquirect = Texture2D::Create(filepath); Ref<Texture2D> envEquirect = Texture2D::Create(filepath);
if (envEquirect->GetFormat() != TextureFormat::Float16) if (envEquirect->GetFormat() != TextureFormat::RGBA16F)
PM_CORE_WARN("Texture is not HDR!"); PM_CORE_WARN("Texture is not HDR!");
equirectangularConversionShader->Bind(); equirectangularConversionShader->Bind();
@ -351,7 +358,7 @@ namespace Prism
if (!envFilteringShader) if (!envFilteringShader)
envFilteringShader = Shader::Create("assets/shaders/EnvironmentMipFilter.glsl"); 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]() Renderer::Submit([envUnfiltered, envFiltered]()
{ {
@ -377,7 +384,7 @@ namespace Prism
if (!envIrradianceShader) if (!envIrradianceShader)
envIrradianceShader = Shader::Create("assets/shaders/EnvironmentIrradiance.glsl"); 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(); envIrradianceShader->Bind();
envFiltered->Bind(); envFiltered->Bind();
Renderer::Submit([irradianceMap]() Renderer::Submit([irradianceMap]()
@ -393,19 +400,18 @@ namespace Prism
static Ref<Shader> preethamSkyShader; 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; 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) if (!preethamSkyShader)
preethamSkyShader = Shader::Create("assets/shaders/PreethamSky.glsl"); preethamSkyShader = Shader::Create("assets/shaders/PreethamSky.glsl");
preethamSkyShader->Bind(); preethamSkyShader->Bind();
const glm::vec3 TurbidityAzimuthInclination = { turbidity, azimuth, inclination}; preethamSkyShader->SetFloat3("u_TurbidityAzimuthInclination", turbidityAzimuthInclination);
preethamSkyShader->SetFloat3("u_TurbidityAzimuthInclination", TurbidityAzimuthInclination);
Renderer::Submit([environmentMap, cubemapSize]() Renderer::Submit([environmentMap, cubemapSize]()
{ {
@ -418,13 +424,6 @@ namespace Prism
return environmentMap; return environmentMap;
} }
/*
Ref<RenderPass> Renderer3D::GetFinalRenderPass()
{
return s_Data.CompositePass;
}
*/
Ref<RenderPass> Renderer3D::GetGeoPass() Ref<RenderPass> Renderer3D::GetGeoPass()
{ {
return s_Data.GeoPass; return s_Data.GeoPass;
@ -441,12 +440,6 @@ namespace Prism
s_Data.FocusPoint = point; s_Data.FocusPoint = point;
} }
/*
uint32_t Renderer3D::GetFinalColorBufferRendererID()
{
return s_Data.CompositePass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
}
*/
SceneRendererOptions& Renderer3D::GetOptions() SceneRendererOptions& Renderer3D::GetOptions()
{ {
@ -475,6 +468,8 @@ namespace Prism
Renderer::Submit([] { s_Stats.GeometryPass = s_Stats.GeometryPassTimer.ElapsedMillis(); }); Renderer::Submit([] { s_Stats.GeometryPass = s_Stats.GeometryPassTimer.ElapsedMillis(); });
} }
ResolveMSAA();
// Compute average luminance and update exposure (GPU-copy + mipmap -> read 1 texel) // Compute average luminance and update exposure (GPU-copy + mipmap -> read 1 texel)
{ {
Renderer::Submit([]() { s_Stats.AutoExposurePassTimer.Reset(); }); Renderer::Submit([]() { s_Stats.AutoExposurePassTimer.Reset(); });
@ -482,30 +477,13 @@ namespace Prism
Renderer::Submit([] { s_Stats.AutoExposurePass = s_Stats.AutoExposurePassTimer.ElapsedMillis(); }); Renderer::Submit([] { s_Stats.AutoExposurePass = s_Stats.AutoExposurePassTimer.ElapsedMillis(); });
} }
BloomBlurPass();
OverlayPass();
{ {
Renderer::Submit([]() { s_Stats.CompositePassTimer.Reset(); }); Renderer::Submit([]() { s_Stats.CompositePassTimer.Reset(); });
// CompositePass(); CompositePass(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->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();
}
Renderer::Submit([] { s_Stats.CompositePass = s_Stats.CompositePassTimer.ElapsedMillis(); }); Renderer::Submit([] { s_Stats.CompositePass = s_Stats.CompositePassTimer.ElapsedMillis(); });
// BloomBlurPass(); // BloomBlurPass();
} }
@ -517,6 +495,119 @@ namespace Prism
s_Data.SceneData = {}; 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() void Renderer3D::GeometryPass()
{ {
const bool outline = !s_Data.SelectedMeshDrawList.empty(); const bool outline = !s_Data.SelectedMeshDrawList.empty();
@ -549,7 +640,6 @@ namespace Prism
// Skybox // Skybox
auto skyboxShader = s_Data.SceneData.SkyboxMaterial->GetShader();
s_Data.SceneData.SkyboxMaterial->Set("u_InverseVP", glm::inverse(cameraViewProjection)); s_Data.SceneData.SkyboxMaterial->Set("u_InverseVP", glm::inverse(cameraViewProjection));
s_Data.SceneData.SkyboxMaterial->Set("u_SkyIntensity", s_Data.SceneData.SceneEnvironmentIntensity); s_Data.SceneData.SkyboxMaterial->Set("u_SkyIntensity", s_Data.SceneData.SceneEnvironmentIntensity);
// s_Data.SceneInfo.EnvironmentIrradianceMap->Bind(0); // s_Data.SceneInfo.EnvironmentIrradianceMap->Bind(0);
@ -831,8 +921,89 @@ namespace Prism
// Grid // Grid
const auto option = GetOptions(); const auto option = GetOptions();
if (option.ShowGrid)
if (option.ShowBoundingBoxes)
{ {
Renderer2D::BeginScene(cameraViewProjection);
for (auto& dc : s_Data.DrawList)
Renderer::DrawAABB(dc.mesh, dc.Transform);
Renderer2D::EndScene();
}
Renderer::EndRenderPass();
}
void Renderer3D::BloomBlurPass()
{
if (!s_Data.EnableBloom)
{
// 如果关闭 Bloom可以清除 BloomBlendPass避免使用旧数据
Renderer::BeginRenderPass(s_Data.BloomBlendPass);
Renderer::EndRenderPass();
return;
}
uint32_t srcTex = s_Data.ResolvedHDRTexture->GetRendererID();
const int iterations = 5; // 模糊迭代次数,可调
// 第一次:提取高光 + 水平模糊
{
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();
}
// 后续迭代
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];
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();
}
// 将最终模糊结果拷贝到 BloomBlendPass供合成使用
uint32_t finalBlurTex = (iterations % 2 == 0) ?
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID() :
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
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_View", sceneCamera.ViewMatrix);
s_Data.GridData.GridMaterial->Set("u_Projection", cameraProjection); s_Data.GridData.GridMaterial->Set("u_Projection", cameraProjection);
s_Data.GridData.GridMaterial->Set("u_CameraPosition", cameraPosition); s_Data.GridData.GridMaterial->Set("u_CameraPosition", cameraPosition);
@ -849,85 +1020,87 @@ namespace Prism
Renderer::SubmitFullscreenQuad(s_Data.GridData.GridMaterial); Renderer::SubmitFullscreenQuad(s_Data.GridData.GridMaterial);
} }
if (option.ShowBoundingBoxes) Renderer::EndRenderPass();
{
Renderer2D::BeginScene(cameraViewProjection);
for (auto& dc : s_Data.DrawList)
Renderer::DrawAABB(dc.mesh, dc.Transform);
Renderer2D::EndScene();
} }
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(); Renderer::EndRenderPass();
} }
void Renderer3D::AutoExposurePass()
/*
void Renderer3D::CompositePass(const Ref<RenderPass>& outRenderPass)
{ {
auto& ae = s_Data.AutoExposureData; Renderer::BeginRenderPass(outRenderPass);
if (!ae.EnableAutoExposure)
return;
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer; s_Data.CompositeShader->Bind();
auto dstFB = ae.LuminancePass->GetSpecification().TargetFramebuffer;
if (!srcFB || !dstFB) return;
float dt = ae.ExposureTimer; s_Data.BloomBlendShader->Bind();
ae.ExposureTimer.Reset(); s_Data.BloomBlendShader->SetBool("u_EnableBloom", s_Data.EnableBloom);
Renderer::Submit([srcFB, dstFB, logMin = ae.LogMin, logMax = ae.LogMax, histCS = ae.HistogramCS, histSSBO = ae.HistogramSSBO]() { s_Data.AutoExposureData.ExposureSSBO->BindBase(2);
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; Renderer::Submit([]() {
glClearNamedBufferData(histSSBO->GetRendererID(), GL_R32UI, GL_RED, GL_UNSIGNED_INT, &zero); glBindTextureUnit(0, s_Data.ResolvedHDRTexture->GetRendererID());
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);
}); });
s_Data.BloomBlendShader->SetInt("u_SceneTexture", 0);
Renderer::Submit([&ae, dt]() { s_Data.CompositeShader->SetBool("u_EnableAutoExposure",s_Data.AutoExposureData.EnableAutoExposure);
glUseProgram(ae.ExposureCS->GetRendererID()); s_Data.CompositeShader->SetFloat("u_ManualExposure", s_Data.SceneData.SceneCamera.Camera.GetExposure());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ae.HistogramSSBO->GetRendererID()); s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ae.ExposureSSBO->GetRendererID()); s_Data.CompositeShader->SetFloat("u_EnableBloom", s_Data.EnableBloom);
auto setUniform = [&](const char* name, const float value) { if (s_Data.EnableBloom)
const GLint loc = glGetUniformLocation(ae.ExposureCS->GetRendererID(), name); {
if (loc != -1) glProgramUniform1f(ae.ExposureCS->GetRendererID(), loc, value); uint32_t bloomTex = s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
}; Renderer::Submit([bloomTex]() {
glBindTextureUnit(1, bloomTex);
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);
}); });
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 struct FrustumBounds
{ {
@ -1084,61 +1257,47 @@ namespace Prism
return corners; return corners;
} }
void Renderer3D::ShadowMapPass()
void Renderer3D::ResolveMSAA()
{ {
const auto& directionalLights = s_Data.SceneData.SceneLightEnvironment.DirectionalLights; auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
if (directionalLights[0].Intensity == 0.0f || !directionalLights[0].CastShadows) 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++) s_Data.ResolvedHDRTexture = Texture2D::Create(TextureFormat::RGBA16F, width, height);
{
// Clear shadow maps
Renderer::BeginRenderPass(s_Data.ShadowMapRenderPass);
Renderer::EndRenderPass();
}
return;
} }
// TODO: this will not be hardcode Renderer::Submit([srcFB, resolvedTex = s_Data.ResolvedHDRTexture]() {
const glm::vec3 lightDir = glm::normalize(directionalLights[0].Direction); // 光线方向(从光源指向场景) GLuint resolveFBO;
const glm::vec3 lightPos = lightDir * 100.0f; glGenFramebuffers(1, &resolveFBO);
const glm::mat4 lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolvedTex->GetRendererID(), 0);
const float orthoSize = 100.0f; glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFB->GetRendererID());
const float nearPlane = 0.01f, farPlane = 1000.0f; glReadBuffer(GL_COLOR_ATTACHMENT0);
const glm::mat4 lightProjection = glm::ortho(-orthoSize, orthoSize, -orthoSize, orthoSize, nearPlane, farPlane);
const glm::mat4 lightSpaceMatrix = lightProjection * lightView;
Renderer::Submit([]() glBlitFramebuffer(0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
{ 0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
glEnable(GL_CULL_FACE); GL_COLOR_BUFFER_BIT, GL_LINEAR);
glCullFace(GL_BACK);
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() void SceneRenderer::OnImGuiRender()
{ {
ImGui::Begin("Scene Renderer"); ImGui::Begin("Scene Renderer");
UI::Property("Composite Pass time", s_Stats.CompositePass);
UI::Property("Geometry Pass time", s_Stats.GeometryPass); 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("Shadow Pass time", s_Stats.ShadowPass);
UI::Property("AutoExposure Pass time", s_Stats.AutoExposurePass); UI::Property("AutoExposure Pass time", s_Stats.AutoExposurePass);
@ -1207,10 +1366,15 @@ namespace Prism
auto fb = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer; auto fb = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer;
const auto id = fb->GetColorAttachmentRendererID(); 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 const float size = ImGui::GetContentRegionAvail().x; // (float)fb->GetWidth() * 0.5f, (float)fb->GetHeight() * 0.5f
float w = size; float w = size;
float h = w / ((float)fb->GetWidth() / (float)fb->GetHeight()); float h = w / ((float)fb->GetWidth() / (float)fb->GetHeight());
ImGui::Image((ImTextureID)id, { w, h }, { 0, 1 }, { 1, 0 }); 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(); 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 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 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 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> GetFinalRenderPass();
static Ref<RenderPass> GetGeoPass(); static Ref<RenderPass> GetGeoPass();
@ -59,10 +59,15 @@ namespace Prism
static void FlushDrawList(Ref<RenderPass>& outRenderPass); static void FlushDrawList(Ref<RenderPass>& outRenderPass);
static void AutoExposurePass(); static void AutoExposurePass();
static void GeometryPass();
// static void CompositePass();
// static void BloomBlurPass();
static void ShadowMapPass(); 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; Prism::Camera Camera;
glm::mat4 ViewMatrix; glm::mat4 ViewMatrix;
float Near, Far;
float FOV;
}; };
class PRISM_API SceneRenderer class PRISM_API SceneRenderer

View File

@ -18,7 +18,7 @@ namespace Prism
None = 0, None = 0,
RGB = 1, RGB = 1,
RGBA = 2, RGBA = 2,
Float16 = 3, RGBA16F = 3,
}; };
enum class TextureWrap enum class TextureWrap
@ -62,6 +62,7 @@ namespace Prism
virtual void Lock() = 0; virtual void Lock() = 0;
virtual void Unlock() = 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 void Resize(uint32_t width, uint32_t height) = 0;
virtual Buffer GetWriteableBuffer() = 0; virtual Buffer GetWriteableBuffer() = 0;

View File

@ -91,6 +91,7 @@ namespace Prism
struct MeshComponent struct MeshComponent
{ {
Ref<Mesh> Mesh; Ref<Mesh> Mesh;
// std::vector<Ref<MaterialInstance>> Materials;
MeshComponent() = default; MeshComponent() = default;
MeshComponent(const MeshComponent& other) = default; MeshComponent(const MeshComponent& other) = default;
@ -98,6 +99,24 @@ namespace Prism
: Mesh(mesh) {} : Mesh(mesh) {}
operator Ref<Prism::Mesh> () { return 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 struct AnimationComponent
@ -126,6 +145,7 @@ namespace Prism
{ {
SceneCamera Camera; SceneCamera Camera;
bool Primary = true; bool Primary = true;
bool ShowIcon = true;
CameraComponent() = default; CameraComponent() = default;
CameraComponent(const CameraComponent& other) = default; CameraComponent(const CameraComponent& other) = default;
@ -373,6 +393,7 @@ namespace Prism
bool CastShadows = true; bool CastShadows = true;
bool SoftShadows = true; bool SoftShadows = true;
float LightSize = 0.5f; // For PCSS float LightSize = 0.5f; // For PCSS
bool ShowIcon = true;
}; };
struct PointLightComponent struct PointLightComponent
@ -381,6 +402,7 @@ namespace Prism
float Radius = 10.0f; float Radius = 10.0f;
float Intensity = 1.0f; float Intensity = 1.0f;
uint32_t CastShadows; uint32_t CastShadows;
bool ShowIcon = true;
PointLightComponent() = default; PointLightComponent() = default;
PointLightComponent(const PointLightComponent& other) = default; PointLightComponent(const PointLightComponent& other) = default;
@ -395,6 +417,7 @@ namespace Prism
float InnerConeAngle = glm::radians(30.0f); // 内锥角(半角) float InnerConeAngle = glm::radians(30.0f); // 内锥角(半角)
float OuterConeAngle = glm::radians(45.0f); // 外锥角(半角) float OuterConeAngle = glm::radians(45.0f); // 外锥角(半角)
bool CastShadows = true; // 聚光通常需要阴影 bool CastShadows = true; // 聚光通常需要阴影
bool ShowIcon = true;
SpotLightComponent() = default; SpotLightComponent() = default;
SpotLightComponent(const SpotLightComponent& other) = default; SpotLightComponent(const SpotLightComponent& other) = default;
@ -405,6 +428,7 @@ namespace Prism
Ref<Environment> SceneEnvironment; Ref<Environment> SceneEnvironment;
float Intensity = 1.0f; float Intensity = 1.0f;
float Angle = 0.0f; float Angle = 0.0f;
bool ShowIcon = false;
bool DynamicSky = false; bool DynamicSky = false;
glm::vec3 TurbidityAzimuthInclination = { 2.0, 0.0, 0.0 }; glm::vec3 TurbidityAzimuthInclination = { 2.0, 0.0, 0.0 };

View File

@ -159,34 +159,15 @@ namespace Prism
return; return;
const glm::mat4 cameraViewMatrix = glm::inverse(GetTransformRelativeToParent(cameraEntity)); const glm::mat4 cameraViewMatrix = glm::inverse(GetTransformRelativeToParent(cameraEntity));
PM_CORE_ASSERT(cameraEntity, "Scene does not contain any cameras!");
SceneCamera& camera = cameraEntity.GetComponent<CameraComponent>(); SceneCamera& camera = cameraEntity.GetComponent<CameraComponent>();
camera.SetViewportSize(m_ViewportWidth, m_ViewportHeight); camera.SetViewportSize(m_ViewportWidth, m_ViewportHeight);
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// RENDER 3D SCENE // // RENDER 3D SCENE //
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// Process lights // Process lights
{ UpdateLights();
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
};
}
}
// TODO: only one sky light at the moment! // TODO: only one sky light at the moment!
{ {
@ -248,70 +229,9 @@ namespace Prism
void Scene::OnRenderEditor(const TimeStep ts, const EditorCamera& editorCamera) void Scene::OnRenderEditor(const TimeStep ts, const EditorCamera& editorCamera)
{ {
/////////////////////////////////////////////////////////////////////
// RENDER 3D SCENE //
/////////////////////////////////////////////////////////////////////
// Process lights // Process lights Direction, Point, Spot
{ UpdateLights();
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 ++;
}
}
// TODO: only one sky light at the moment! // TODO: only one sky light at the moment!
{ {
@ -325,7 +245,7 @@ namespace Prism
auto [transformComponent, skyLightComponent] = lights.get<TransformComponent, SkyLightComponent>(entity); auto [transformComponent, skyLightComponent] = lights.get<TransformComponent, SkyLightComponent>(entity);
if (!skyLightComponent.SceneEnvironment && skyLightComponent.DynamicSky) 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); skyLightComponent.SceneEnvironment = Ref<Environment>::Create(preethamEnv, preethamEnv);
} }
@ -341,8 +261,13 @@ namespace Prism
// TODO: this value should be storage and can modify // TODO: this value should be storage and can modify
// TODO: Renderer2D cannot blend with Renderer3D // 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>); const auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
{ {
for (const auto [entity, meshComponent, transformComponent]: group.each()) for (const auto [entity, meshComponent, transformComponent]: group.each())
@ -400,23 +325,57 @@ namespace Prism
// render camera icon // render camera icon
{ {
const auto editorCameraPosition = editorCamera.GetPosition();
const auto editorCameraUpDirection = editorCamera.GetUpDirection();
const auto cameras = m_Registry.view<CameraComponent>(); const auto cameras = m_Registry.view<CameraComponent>();
if (!cameras.empty()) if (!cameras.empty())
{ {
for (auto& entity : cameras) for (auto& entity : cameras)
{ {
Entity e = { entity, this }; 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 (const auto skyLights = m_Registry.view<SkyLightComponent>(); !skyLights.empty())
if (!lights.empty())
{ {
for (auto& entity : lights) for (auto& entity : skyLights)
{ {
Entity e = { entity, this }; 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 // Box2D physics
Physics2D::CreateBody(this); Physics2D::CreateBody(this);
// PhyX
{ {
auto view = m_Registry.view<RigidBodyComponent>(); auto view = m_Registry.view<RigidBodyComponent>();
// Physics3D::ExpandEntityBuffer(static_cast<uint32_t>(view.size())); // Physics3D::ExpandEntityBuffer(static_cast<uint32_t>(view.size()));
@ -485,11 +445,10 @@ namespace Prism
Entity Scene::GetMainCameraEntity() Entity Scene::GetMainCameraEntity()
{ {
auto view = m_Registry.view<CameraComponent>(); const auto view = m_Registry.view<CameraComponent>();
for (auto entity : view) for (auto entity : view)
{ {
auto& comp = view.get<CameraComponent>(entity); if (const auto& comp = view.get<CameraComponent>(entity); comp.Primary)
if (comp.Primary)
return { entity, this }; return { entity, this };
} }
return {}; return {};
@ -577,33 +536,6 @@ namespace Prism
newEntity = CreateEntity(); newEntity = CreateEntity();
CopyComponentIfExists(AllComponent{},newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); 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) { Entity Scene::FindEntityByTag(const std::string &tag) {
@ -613,7 +545,7 @@ namespace Prism
{ {
const auto& canditate = view.get<TagComponent>(entity).Tag; const auto& canditate = view.get<TagComponent>(entity).Tag;
if (canditate == tag) if (canditate == tag)
return Entity(entity, this); return {entity, this};
} }
return Entity{}; return Entity{};
@ -625,8 +557,7 @@ namespace Prism
auto view = m_Registry.view<IDComponent>(); auto view = m_Registry.view<IDComponent>();
for (auto entity : view) for (auto entity : view)
{ {
auto& idComponent = m_Registry.get<IDComponent>(entity); if (auto& idComponent = m_Registry.get<IDComponent>(entity); idComponent.ID == uuid)
if (idComponent.ID == uuid)
return {entity, this}; return {entity, this};
} }
@ -660,32 +591,7 @@ namespace Prism
enttMap[uuid] = e.m_EntityHandle; enttMap[uuid] = e.m_EntityHandle;
} }
CopyComponent(AllComponent{},target->m_Registry, m_Registry, enttMap); 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(); const auto& entityInstanceMap = ScriptEngine::GetEntityInstanceMap();
if (entityInstanceMap.find(target->GetUUID()) != entityInstanceMap.end()) 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}); 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) void Scene::DestroyEntity(Entity entity)
{ {

View File

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

View File

@ -291,6 +291,9 @@ namespace Prism
out << YAML::Key << "Intensity" << YAML::Value << skyLightComponent.Intensity; out << YAML::Key << "Intensity" << YAML::Value << skyLightComponent.Intensity;
out << YAML::Key << "Angle" << YAML::Value << skyLightComponent.Angle; 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 out << YAML::EndMap; // SkyLightComponent
} }
@ -855,7 +858,7 @@ namespace Prism
AssetHandle assetHandle; AssetHandle assetHandle;
if (skyLightComponent["EnvironmentAssetPath"]) if (skyLightComponent["EnvironmentAssetPath"])
{ {
const std::string filePath = skyLightComponent["EnvironmentAssetPath"].as<std::string>(); const auto filePath = skyLightComponent["EnvironmentAssetPath"].as<std::string>();
assetHandle = AssetsManager::GetAssetHandleFromFilePath(filepath); assetHandle = AssetsManager::GetAssetHandleFromFilePath(filepath);
} }
else else
@ -870,6 +873,10 @@ namespace Prism
component.Intensity = skyLightComponent["Intensity"].as<float>(); component.Intensity = skyLightComponent["Intensity"].as<float>();
component.Angle = skyLightComponent["Angle"].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"]) 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) void Prism_Texture2D_SetData(Ref<Texture2D>* _this, MonoArray* inData, int32_t count)
{ {
Ref<Texture2D>& instance = *_this; Ref<Texture2D>& instance = *_this;
instance->SetData(inData, count);
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();
} }
void Prism_Material_Destructor(const Ref<Material>* _this) void Prism_Material_Destructor(const Ref<Material>* _this)