Compare commits
1 Commits
forward-re
...
mono-PhysX
| Author | SHA1 | Date | |
|---|---|---|---|
| 57700da217 |
@ -1164,7 +1164,7 @@ namespace Prism
|
|||||||
UpdateWindowTitle("Untitled Scene");
|
UpdateWindowTitle("Untitled Scene");
|
||||||
m_SceneFilePath = std::string();
|
m_SceneFilePath = std::string();
|
||||||
|
|
||||||
m_EditorCamera = EditorCamera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 1000.0f));
|
m_EditorCamera = EditorCamera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 100.0f));
|
||||||
m_SelectionContext.clear();
|
m_SelectionContext.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,16 +24,16 @@ uniform sampler2D u_Texture;
|
|||||||
uniform bool u_Horizontal; // 未使用,可保留或移除
|
uniform bool u_Horizontal; // 未使用,可保留或移除
|
||||||
uniform bool u_FirstPass; // 是否进行阈值处理
|
uniform bool u_FirstPass; // 是否进行阈值处理
|
||||||
uniform float u_Threshold; // 亮度阈值
|
uniform float u_Threshold; // 亮度阈值
|
||||||
|
uniform int u_Quality;
|
||||||
|
uniform float u_Directions; // 模糊方向数
|
||||||
|
uniform float u_Size; // 模糊半径
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
float Pi = 6.28318530718; // 2*PI
|
float Pi = 6.28318530718; // 2*PI
|
||||||
|
|
||||||
float Directions = 32.0; // 模糊方向数
|
|
||||||
float Quality = 6.0; // 每个方向上的采样质量(采样次数)
|
|
||||||
float Size = 16.0; // 模糊半径
|
|
||||||
|
|
||||||
vec2 Radius = Size / textureSize(u_Texture, 0);
|
vec2 Radius = u_Size / textureSize(u_Texture, 0);
|
||||||
|
|
||||||
// 中心像素采样
|
// 中心像素采样
|
||||||
vec3 centerColor = texture(u_Texture, v_TexCoord).rgb;
|
vec3 centerColor = texture(u_Texture, v_TexCoord).rgb;
|
||||||
@ -50,9 +50,9 @@ void main()
|
|||||||
float totalSamples = 1.0; // 有效采样计数(中心像素已计入)
|
float totalSamples = 1.0; // 有效采样计数(中心像素已计入)
|
||||||
|
|
||||||
// 周围像素采样
|
// 周围像素采样
|
||||||
for (float d = 0.0; d < Pi; d += Pi / Directions)
|
for (float d = 0.0; d < Pi; d += Pi / u_Directions)
|
||||||
{
|
{
|
||||||
for (float i = 1.0 / Quality; i <= 1.0; i += 1.0 / Quality)
|
for (float i = 1.0 / u_Quality; i <= 1.0; i += 1.0 / u_Quality)
|
||||||
{
|
{
|
||||||
vec2 offset = vec2(cos(d), sin(d)) * Radius * i;
|
vec2 offset = vec2(cos(d), sin(d)) * Radius * i;
|
||||||
vec3 sampleColor = texture(u_Texture, v_TexCoord + offset).rgb;
|
vec3 sampleColor = texture(u_Texture, v_TexCoord + offset).rgb;
|
||||||
|
|||||||
348
Editor/assets/shaders/Lighting.glsl
Normal file
348
Editor/assets/shaders/Lighting.glsl
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
#type vertex
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 a_Position;
|
||||||
|
layout(location = 1) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
out vec2 v_TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
v_TexCoord = a_TexCoord;
|
||||||
|
gl_Position = vec4(a_Position.xy, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
// ==================== 输入 ====================
|
||||||
|
in vec2 v_TexCoord;
|
||||||
|
|
||||||
|
// G-buffer 纹理
|
||||||
|
uniform sampler2D u_AlbedoMetallic; // RGB: albedo, A: metallic
|
||||||
|
uniform sampler2D u_NormalRoughness; // RGB: normal (encoded), A: roughness
|
||||||
|
uniform sampler2D u_EmissiveAO; // RGB: emissive, A: AO
|
||||||
|
uniform sampler2D u_Depth; // depth
|
||||||
|
|
||||||
|
// 相机参数
|
||||||
|
uniform mat4 u_InvViewProj; // 逆视图投影矩阵,用于重建世界坐标
|
||||||
|
uniform vec3 u_CameraPosition;
|
||||||
|
|
||||||
|
// 光源结构体(与你的PBR着色器一致)
|
||||||
|
struct DirectionalLight {
|
||||||
|
vec3 Direction;
|
||||||
|
vec3 Radiance;
|
||||||
|
float Intensity;
|
||||||
|
bool CastShadows;
|
||||||
|
};
|
||||||
|
struct PointLight {
|
||||||
|
vec3 Position;
|
||||||
|
vec3 Radiance;
|
||||||
|
float Intensity;
|
||||||
|
float Range;
|
||||||
|
bool CastShadows;
|
||||||
|
};
|
||||||
|
struct SpotLight {
|
||||||
|
vec3 Position;
|
||||||
|
vec3 Direction;
|
||||||
|
vec3 Radiance;
|
||||||
|
float Intensity;
|
||||||
|
float Range;
|
||||||
|
float InnerConeCos;
|
||||||
|
float OuterConeCos;
|
||||||
|
bool CastShadows;
|
||||||
|
};
|
||||||
|
|
||||||
|
uniform DirectionalLight u_DirectionalLights; // 仅一个方向光
|
||||||
|
uniform int u_PointLightCount;
|
||||||
|
uniform PointLight u_PointLights[16]; // 假设最多16个点光源
|
||||||
|
uniform int u_SpotLightCount;
|
||||||
|
uniform SpotLight u_SpotLights[16]; // 最多16个聚光源
|
||||||
|
|
||||||
|
// IBL 相关
|
||||||
|
uniform samplerCube u_EnvRadianceTex;
|
||||||
|
uniform samplerCube u_EnvIrradianceTex;
|
||||||
|
uniform sampler2D u_BRDFLUTTexture;
|
||||||
|
uniform float u_IBLContribution;
|
||||||
|
uniform float u_EnvMapRotation;
|
||||||
|
|
||||||
|
// 阴影相关
|
||||||
|
uniform sampler2D u_ShadowMap;
|
||||||
|
uniform float u_ShadowBias;
|
||||||
|
uniform float u_ShadowSoftness;
|
||||||
|
uniform int u_ShadowEnabled;
|
||||||
|
uniform float u_ShadowIntensity; // 阴影强度(0-1)
|
||||||
|
uniform mat4 u_LightSpaceMatrix; // 方向光光源空间矩阵
|
||||||
|
|
||||||
|
// 天空盒(可选)
|
||||||
|
uniform samplerCube u_Skybox; // 如果深度为1.0则采样天空盒
|
||||||
|
uniform float u_SkyIntensity;
|
||||||
|
uniform float u_SkyTextureLod;
|
||||||
|
|
||||||
|
// 输出
|
||||||
|
layout(location = 0) out vec4 o_Color;
|
||||||
|
|
||||||
|
// ==================== 常量 ====================
|
||||||
|
const float PI = 3.14159265359;
|
||||||
|
const float Epsilon = 0.00001;
|
||||||
|
const vec3 Fdielectric = vec3(0.04);
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== 工具函数 ====================
|
||||||
|
// 从深度重建世界坐标
|
||||||
|
vec3 worldPosFromDepth(vec2 uv, float depth) {
|
||||||
|
vec4 clipPos = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||||
|
vec4 worldPos = u_InvViewProj * clipPos;
|
||||||
|
return worldPos.xyz / worldPos.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从深度重建世界空间方向(用于天空盒采样)
|
||||||
|
vec3 worldDirFromUV(vec2 uv) {
|
||||||
|
// 假设深度为1.0时,得到远平面方向
|
||||||
|
vec4 clipPos = vec4(uv * 2.0 - 1.0, 1.0, 1.0);
|
||||||
|
vec4 worldPos = u_InvViewProj * clipPos;
|
||||||
|
return normalize(worldPos.xyz / worldPos.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 旋转向量(绕Y轴)
|
||||||
|
vec3 RotateVectorAboutY(float angle, vec3 vec) {
|
||||||
|
angle = radians(angle);
|
||||||
|
mat3 rotationMatrix = mat3(
|
||||||
|
vec3(cos(angle), 0.0, sin(angle)),
|
||||||
|
vec3(0.0, 1.0, 0.0),
|
||||||
|
vec3(-sin(angle), 0.0, cos(angle))
|
||||||
|
);
|
||||||
|
return rotationMatrix * vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== PBR 函数(复用你的代码) ====================
|
||||||
|
float ndfGGX(float cosLh, float roughness) {
|
||||||
|
float alpha = roughness * roughness;
|
||||||
|
float alphaSq = alpha * alpha;
|
||||||
|
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||||
|
return alphaSq / (PI * denom * denom);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GeometrySchlickGGX(float NdotV, float roughness) {
|
||||||
|
float r = (roughness + 1.0);
|
||||||
|
float k = (r * r) / 8.0;
|
||||||
|
float nom = NdotV;
|
||||||
|
float denom = NdotV * (1.0 - k) + k;
|
||||||
|
return nom / denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
|
||||||
|
float NdotV = max(dot(N, V), 0.0);
|
||||||
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
|
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||||
|
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||||
|
return ggx1 * ggx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fresnelSchlick(vec3 F0, float cosTheta) {
|
||||||
|
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness) {
|
||||||
|
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 方向光 ----------
|
||||||
|
vec3 ComputeDirectionalLight(DirectionalLight light, vec3 F0, vec3 N, vec3 V, float NdotV, vec3 albedo, float roughness, float metallic) {
|
||||||
|
vec3 L = normalize(-light.Direction);
|
||||||
|
vec3 Lradiance = light.Radiance * light.Intensity;
|
||||||
|
|
||||||
|
vec3 Lh = normalize(L + V);
|
||||||
|
float cosLi = max(dot(N, L), 0.0);
|
||||||
|
float cosLh = max(dot(N, Lh), 0.0);
|
||||||
|
|
||||||
|
vec3 F = fresnelSchlick(F0, max(dot(Lh, V), 0.0));
|
||||||
|
float D = ndfGGX(cosLh, roughness);
|
||||||
|
float G = GeometrySmith(N, V, L, roughness);
|
||||||
|
|
||||||
|
vec3 kd = (1.0 - F) * (1.0 - metallic);
|
||||||
|
vec3 diffuseBRDF = kd * albedo;
|
||||||
|
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * NdotV);
|
||||||
|
|
||||||
|
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 点光源 ----------
|
||||||
|
vec3 ComputePointLight(PointLight light, vec3 F0, vec3 N, vec3 V, float NdotV, vec3 albedo, float roughness, float metallic, vec3 worldPos) {
|
||||||
|
vec3 lightVec = light.Position - worldPos;
|
||||||
|
float dist = length(lightVec);
|
||||||
|
if (dist > light.Range) return vec3(0.0);
|
||||||
|
|
||||||
|
vec3 L = lightVec / dist;
|
||||||
|
vec3 Lradiance = light.Radiance * light.Intensity;
|
||||||
|
|
||||||
|
float attenuation = 1.0 / (dist * dist + 0.0001);
|
||||||
|
float rangeFactor = clamp(1.0 - (dist / light.Range), 0.0, 1.0);
|
||||||
|
rangeFactor = rangeFactor * rangeFactor;
|
||||||
|
attenuation *= rangeFactor;
|
||||||
|
|
||||||
|
vec3 Lh = normalize(L + V);
|
||||||
|
float cosLi = max(dot(N, L), 0.0);
|
||||||
|
float cosLh = max(dot(N, Lh), 0.0);
|
||||||
|
|
||||||
|
vec3 F = fresnelSchlick(F0, max(dot(Lh, V), 0.0));
|
||||||
|
float D = ndfGGX(cosLh, roughness);
|
||||||
|
float G = GeometrySmith(N, V, L, roughness);
|
||||||
|
|
||||||
|
vec3 kd = (1.0 - F) * (1.0 - metallic);
|
||||||
|
vec3 diffuseBRDF = kd * albedo;
|
||||||
|
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * NdotV);
|
||||||
|
|
||||||
|
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 聚光源 ----------
|
||||||
|
vec3 ComputeSpotLight(SpotLight light, vec3 F0, vec3 N, vec3 V, float NdotV, vec3 albedo, float roughness, float metallic, vec3 worldPos) {
|
||||||
|
vec3 lightVec = light.Position - worldPos;
|
||||||
|
float dist = length(lightVec);
|
||||||
|
if (dist > light.Range) return vec3(0.0);
|
||||||
|
|
||||||
|
vec3 L = lightVec / dist;
|
||||||
|
vec3 Lradiance = light.Radiance * light.Intensity;
|
||||||
|
|
||||||
|
float attenuation = 1.0 / (dist * dist + 0.0001);
|
||||||
|
float rangeFactor = clamp(1.0 - (dist / light.Range), 0.0, 1.0);
|
||||||
|
rangeFactor = rangeFactor * rangeFactor;
|
||||||
|
attenuation *= rangeFactor;
|
||||||
|
|
||||||
|
float cosAngle = dot(-L, normalize(light.Direction));
|
||||||
|
if (cosAngle < light.OuterConeCos) return vec3(0.0);
|
||||||
|
float angleFalloff = (cosAngle - light.OuterConeCos) / (light.InnerConeCos - light.OuterConeCos);
|
||||||
|
angleFalloff = clamp(angleFalloff, 0.0, 1.0);
|
||||||
|
attenuation *= angleFalloff;
|
||||||
|
|
||||||
|
vec3 Lh = normalize(L + V);
|
||||||
|
float cosLi = max(dot(N, L), 0.0);
|
||||||
|
float cosLh = max(dot(N, Lh), 0.0);
|
||||||
|
|
||||||
|
vec3 F = fresnelSchlick(F0, max(dot(Lh, V), 0.0));
|
||||||
|
float D = ndfGGX(cosLh, roughness);
|
||||||
|
float G = GeometrySmith(N, V, L, roughness);
|
||||||
|
|
||||||
|
vec3 kd = (1.0 - F) * (1.0 - metallic);
|
||||||
|
vec3 diffuseBRDF = kd * albedo;
|
||||||
|
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * NdotV);
|
||||||
|
|
||||||
|
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- IBL ----------
|
||||||
|
vec3 IBL(vec3 F0, vec3 N, vec3 V, float NdotV, float roughness, float metallic, vec3 albedo) {
|
||||||
|
vec3 irradiance = texture(u_EnvIrradianceTex, N).rgb;
|
||||||
|
vec3 F = fresnelSchlickRoughness(F0, NdotV, roughness);
|
||||||
|
vec3 kd = (1.0 - F) * (1.0 - metallic);
|
||||||
|
vec3 diffuseIBL = albedo * irradiance;
|
||||||
|
|
||||||
|
vec3 R = 2.0 * NdotV * N - V; // 反射向量
|
||||||
|
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
||||||
|
vec3 specularIrradiance = textureLod(
|
||||||
|
u_EnvRadianceTex,
|
||||||
|
RotateVectorAboutY(u_EnvMapRotation, R),
|
||||||
|
roughness * u_EnvRadianceTexLevels
|
||||||
|
).rgb;
|
||||||
|
|
||||||
|
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(NdotV, 1.0 - roughness)).rg;
|
||||||
|
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
||||||
|
|
||||||
|
return kd * diffuseIBL + specularIBL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 阴影 ----------
|
||||||
|
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir) {
|
||||||
|
if (u_ShadowEnabled == 0) return 0.0;
|
||||||
|
|
||||||
|
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||||
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
|
||||||
|
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
||||||
|
float currentDepth = projCoords.z;
|
||||||
|
|
||||||
|
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||||
|
|
||||||
|
float shadow = 0.0;
|
||||||
|
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
|
||||||
|
int pcfRange = int(u_ShadowSoftness);
|
||||||
|
int sampleCount = 0;
|
||||||
|
|
||||||
|
for (int x = -pcfRange; x <= pcfRange; ++x) {
|
||||||
|
for (int y = -pcfRange; y <= pcfRange; ++y) {
|
||||||
|
float pcfDepth = texture(u_ShadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
|
||||||
|
shadow += (currentDepth - bias > pcfDepth) ? 1.0 : 0.0;
|
||||||
|
sampleCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadow /= float(sampleCount);
|
||||||
|
|
||||||
|
return shadow * u_ShadowIntensity; // 应用阴影强度
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 主函数 ====================
|
||||||
|
void main() {
|
||||||
|
vec2 uv = v_TexCoord;
|
||||||
|
float depth = texture(u_Depth, uv).r;
|
||||||
|
|
||||||
|
if (depth >= 1.0) {
|
||||||
|
vec3 dir = worldDirFromUV(uv);
|
||||||
|
vec3 skyColor = textureLod(u_Skybox, dir, u_SkyTextureLod).rgb * u_SkyIntensity;
|
||||||
|
o_Color = vec4(skyColor, 1.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 albedoMetal = texture(u_AlbedoMetallic, uv);
|
||||||
|
vec4 normalRough = texture(u_NormalRoughness, uv);
|
||||||
|
vec4 emissiveAO = texture(u_EmissiveAO, uv);
|
||||||
|
|
||||||
|
vec3 albedo = albedoMetal.rgb;
|
||||||
|
float metallic = albedoMetal.a;
|
||||||
|
vec3 normal = normalRough.rgb * 2.0 - 1.0;
|
||||||
|
float roughness = normalRough.a;
|
||||||
|
vec3 emissive = emissiveAO.rgb;
|
||||||
|
float ao = emissiveAO.a;
|
||||||
|
|
||||||
|
vec3 worldPos = worldPosFromDepth(uv, depth);
|
||||||
|
vec3 V = normalize(u_CameraPosition - worldPos);
|
||||||
|
float NdotV = clamp(dot(normal, V), 0.0, 1.0);
|
||||||
|
|
||||||
|
vec3 F0 = mix(Fdielectric, albedo, metallic);
|
||||||
|
|
||||||
|
vec3 Lo = vec3(0.0);
|
||||||
|
|
||||||
|
// Direction Light
|
||||||
|
if (u_DirectionalLights.Intensity > 0.0) {
|
||||||
|
Lo += ComputeDirectionalLight(u_DirectionalLights, F0, normal, V, NdotV, albedo, roughness, metallic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Point Light
|
||||||
|
for (int i = 0; i < u_PointLightCount; ++i) {
|
||||||
|
Lo += ComputePointLight(u_PointLights[i], F0, normal, V, NdotV, albedo, roughness, metallic, worldPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spot light
|
||||||
|
for (int i = 0; i < u_SpotLightCount; ++i) {
|
||||||
|
Lo += ComputeSpotLight(u_SpotLights[i], F0, normal, V, NdotV, albedo, roughness, metallic, worldPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
float shadowFactor = 1.0;
|
||||||
|
if (u_ShadowEnabled > 0 && u_DirectionalLights.CastShadows && u_DirectionalLights.Intensity > 0.0) {
|
||||||
|
vec4 fragPosLightSpace = u_LightSpaceMatrix * vec4(worldPos, 1.0);
|
||||||
|
float shadow = calculateShadow(fragPosLightSpace, normal, u_DirectionalLights.Direction);
|
||||||
|
shadowFactor = 1.0 - shadow;
|
||||||
|
}
|
||||||
|
Lo *= shadowFactor;
|
||||||
|
|
||||||
|
// 计算 IBL
|
||||||
|
vec3 ibl = IBL(F0, normal, V, NdotV, roughness, metallic, albedo) * u_IBLContribution;
|
||||||
|
|
||||||
|
vec3 finalColor = Lo + ibl + emissive;
|
||||||
|
|
||||||
|
o_Color = vec4(finalColor, 1.0);
|
||||||
|
}
|
||||||
@ -161,6 +161,13 @@ uniform float u_ShadowSoftness;
|
|||||||
uniform float u_ShadowIntensity;
|
uniform float u_ShadowIntensity;
|
||||||
uniform int u_ShadowEnabled;
|
uniform int u_ShadowEnabled;
|
||||||
|
|
||||||
|
// Emissive
|
||||||
|
uniform sampler2D u_EmissiveTexture;
|
||||||
|
uniform float u_EmissiveTexToggle;
|
||||||
|
uniform vec3 u_EmissiveColor;
|
||||||
|
uniform float u_EmissiveIntensity;
|
||||||
|
|
||||||
|
|
||||||
struct PBRParameters
|
struct PBRParameters
|
||||||
{
|
{
|
||||||
vec3 Albedo;
|
vec3 Albedo;
|
||||||
@ -425,7 +432,16 @@ float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord).rgb : u_AlbedoColor;
|
float alpha = 1.0;
|
||||||
|
if (u_AlbedoTexToggle > 0.5) {
|
||||||
|
vec4 albedoWithAlpha = texture(u_AlbedoTexture, vs_Input.TexCoord);
|
||||||
|
m_Params.Albedo = albedoWithAlpha.rgb;
|
||||||
|
alpha = albedoWithAlpha.a;
|
||||||
|
} else {
|
||||||
|
m_Params.Albedo = u_AlbedoColor;
|
||||||
|
alpha = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
m_Params.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
m_Params.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
||||||
m_Params.Roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
|
m_Params.Roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
|
||||||
m_Params.Roughness = max(m_Params.Roughness, 0.05);
|
m_Params.Roughness = max(m_Params.Roughness, 0.05);
|
||||||
@ -463,7 +479,16 @@ void main()
|
|||||||
|
|
||||||
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
|
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
|
||||||
|
|
||||||
color = vec4(lightContribution + iblContribution, 1.0);
|
vec3 emissive = u_EmissiveColor;
|
||||||
|
if (u_EmissiveTexToggle > 0.5) {
|
||||||
|
emissive = texture(u_EmissiveTexture, vs_Input.TexCoord).rgb;
|
||||||
|
}
|
||||||
|
emissive *= u_EmissiveIntensity;
|
||||||
|
|
||||||
|
vec3 finalRGB = lightContribution + iblContribution + emissive;
|
||||||
|
vec4 finalColor = vec4(finalRGB, alpha);
|
||||||
|
|
||||||
|
color = finalColor;
|
||||||
|
|
||||||
// Bloom
|
// Bloom
|
||||||
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||||||
|
|||||||
@ -55,6 +55,12 @@ void main()
|
|||||||
#type fragment
|
#type fragment
|
||||||
#version 430 core
|
#version 430 core
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outAlbedoMetal;
|
||||||
|
layout(location = 1) out vec4 outNormalRoughness;
|
||||||
|
layout(location = 2) out vec4 outEmissiveAO;
|
||||||
|
layout(location = 3) out vec4 outColor;
|
||||||
|
layout(location = 4) out vec4 outBloomColor;
|
||||||
|
|
||||||
const float PI = 3.141592;
|
const float PI = 3.141592;
|
||||||
const float Epsilon = 0.00001;
|
const float Epsilon = 0.00001;
|
||||||
|
|
||||||
@ -100,8 +106,8 @@ in VertexOutput
|
|||||||
vec4 FragPosLightSpace;
|
vec4 FragPosLightSpace;
|
||||||
} vs_Input;
|
} vs_Input;
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
|
||||||
layout(location = 1) out vec4 o_BloomColor;
|
uniform bool u_GBufferMode;
|
||||||
|
|
||||||
uniform DirectionalLight u_DirectionalLights;
|
uniform DirectionalLight u_DirectionalLights;
|
||||||
|
|
||||||
@ -149,6 +155,12 @@ uniform float u_ShadowSoftness;
|
|||||||
uniform float u_ShadowIntensity;
|
uniform float u_ShadowIntensity;
|
||||||
uniform int u_ShadowEnabled;
|
uniform int u_ShadowEnabled;
|
||||||
|
|
||||||
|
// Emissive
|
||||||
|
uniform sampler2D u_EmissiveTexture;
|
||||||
|
uniform float u_EmissiveTexToggle;
|
||||||
|
uniform vec3 u_EmissiveColor;
|
||||||
|
uniform float u_EmissiveIntensity;
|
||||||
|
|
||||||
struct PBRParameters
|
struct PBRParameters
|
||||||
{
|
{
|
||||||
vec3 Albedo;
|
vec3 Albedo;
|
||||||
@ -411,19 +423,44 @@ float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord).rgb : u_AlbedoColor;
|
// === 1. 采样基础属性(所有模式都需要) ===
|
||||||
m_Params.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
vec4 albedoWithAlpha = texture(u_AlbedoTexture, vs_Input.TexCoord);
|
||||||
m_Params.Roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
|
vec3 albedo = u_AlbedoTexToggle > 0.5 ? albedoWithAlpha.rgb : u_AlbedoColor;
|
||||||
m_Params.Roughness = max(m_Params.Roughness, 0.05);
|
float alpha = u_AlbedoTexToggle > 0.5 ? albedoWithAlpha.a : 1.0;
|
||||||
|
|
||||||
// normal
|
float metallic = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
||||||
m_Params.Normal = normalize(vs_Input.Normal);
|
float roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
|
||||||
|
roughness = max(roughness, 0.05);
|
||||||
|
|
||||||
|
// === 2. 法线计算(世界空间) ===
|
||||||
|
vec3 normal = normalize(vs_Input.Normal);
|
||||||
if (u_NormalTexToggle > 0.5)
|
if (u_NormalTexToggle > 0.5)
|
||||||
{
|
{
|
||||||
m_Params.Normal = normalize(2.0 * texture(u_NormalTexture, vs_Input.TexCoord).rgb - 1.0);
|
vec3 tangentNormal = texture(u_NormalTexture, vs_Input.TexCoord).rgb * 2.0 - 1.0;
|
||||||
m_Params.Normal = normalize(vs_Input.WorldNormals * m_Params.Normal);
|
normal = normalize(vs_Input.WorldNormals * tangentNormal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === 3. 自发光计算 ===
|
||||||
|
vec3 emissive = u_EmissiveColor;
|
||||||
|
if (u_EmissiveTexToggle > 0.5)
|
||||||
|
emissive = texture(u_EmissiveTexture, vs_Input.TexCoord).rgb;
|
||||||
|
emissive *= u_EmissiveIntensity;
|
||||||
|
|
||||||
|
// === 4. GBuffer 模式:直接输出到多个目标 ===
|
||||||
|
if (u_GBufferMode)
|
||||||
|
{
|
||||||
|
outAlbedoMetal = vec4(albedo, metallic);
|
||||||
|
outNormalRoughness = vec4(normal * 0.5 + 0.5, roughness);
|
||||||
|
outEmissiveAO = vec4(emissive, 1.0); // AO 暂设为 1.0
|
||||||
|
return; // 提前结束
|
||||||
|
}
|
||||||
|
|
||||||
|
// === 5. 非 GBuffer 模式:继续 PBR 光照计算 ===
|
||||||
|
// 填充 PBRParameters
|
||||||
|
m_Params.Albedo = albedo;
|
||||||
|
m_Params.Metalness = metallic;
|
||||||
|
m_Params.Roughness = roughness;
|
||||||
|
m_Params.Normal = normal;
|
||||||
m_Params.View = normalize(u_CameraPosition - vs_Input.WorldPosition);
|
m_Params.View = normalize(u_CameraPosition - vs_Input.WorldPosition);
|
||||||
m_Params.NdotV = max(dot(m_Params.Normal, m_Params.View), 0.0);
|
m_Params.NdotV = max(dot(m_Params.Normal, m_Params.View), 0.0);
|
||||||
|
|
||||||
@ -449,9 +486,12 @@ void main()
|
|||||||
|
|
||||||
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
|
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
|
||||||
|
|
||||||
color = vec4(lightContribution + iblContribution, 1.0);
|
vec3 finalRGB = lightContribution + iblContribution + emissive;
|
||||||
|
vec4 finalColor = vec4(finalRGB, alpha);
|
||||||
|
|
||||||
|
outColor = finalColor;
|
||||||
|
|
||||||
// Bloom
|
// Bloom
|
||||||
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
float brightness = dot(finalColor.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||||||
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
outBloomColor = brightness > u_BloomThreshold ? finalColor : vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,13 +17,11 @@ void main()
|
|||||||
#version 430
|
#version 430
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Color;
|
layout(location = 0) out vec4 o_Color;
|
||||||
layout(location = 1) out vec4 o_BloomTexture;
|
|
||||||
|
|
||||||
in vec2 v_TexCoord;
|
in vec2 v_TexCoord;
|
||||||
|
|
||||||
uniform sampler2DMS u_Texture;
|
uniform sampler2D u_HDRTexture; // 来自 LightingPass 的 HDR 颜色
|
||||||
uniform sampler2D u_BloomTexture;
|
uniform sampler2D u_BloomTexture; // 来自 BloomBlendPass 的 Bloom 纹理
|
||||||
|
|
||||||
|
|
||||||
uniform bool u_EnableAutoExposure;
|
uniform bool u_EnableAutoExposure;
|
||||||
uniform float u_ManualExposure;
|
uniform float u_ManualExposure;
|
||||||
@ -32,73 +30,36 @@ layout(std430, binding = 2) buffer Exposure
|
|||||||
float u_Exposure;
|
float u_Exposure;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform int u_TextureSamples;
|
|
||||||
|
|
||||||
uniform bool u_EnableBloom;
|
uniform bool u_EnableBloom;
|
||||||
uniform float u_BloomThreshold;
|
|
||||||
|
|
||||||
const float uFar = 1.0;
|
const float gamma = 2.2;
|
||||||
|
const float pureWhite = 1.0;
|
||||||
vec4 SampleTexture(sampler2D tex, vec2 texCoord)
|
|
||||||
{
|
|
||||||
return texture(tex, texCoord);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 MultiSampleTexture(sampler2DMS tex, vec2 tc)
|
|
||||||
{
|
|
||||||
ivec2 texSize = textureSize(tex);
|
|
||||||
ivec2 texCoord = ivec2(tc * texSize);
|
|
||||||
vec4 result = vec4(0.0);
|
|
||||||
for (int i = 0; i < u_TextureSamples; i++)
|
|
||||||
result += texelFetch(tex, texCoord, i);
|
|
||||||
|
|
||||||
result /= float(u_TextureSamples);
|
|
||||||
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;
|
// 采样 HDR 颜色(单样本)
|
||||||
const float pureWhite = 1.0;
|
vec3 color = texture(u_HDRTexture, v_TexCoord).rgb;
|
||||||
|
|
||||||
// Tonemapping
|
|
||||||
vec4 msColor = MultiSampleTexture(u_Texture, v_TexCoord);
|
|
||||||
vec3 color = msColor.rgb;
|
|
||||||
|
|
||||||
|
// 混合 Bloom(如果启用)
|
||||||
if (u_EnableBloom)
|
if (u_EnableBloom)
|
||||||
{
|
{
|
||||||
vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb;
|
vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb;
|
||||||
color += bloomColor;
|
color += bloomColor; // 在 HDR 空间混合
|
||||||
}
|
}
|
||||||
|
|
||||||
if(u_EnableAutoExposure)
|
// 应用曝光
|
||||||
|
if (u_EnableAutoExposure)
|
||||||
color *= u_Exposure;
|
color *= u_Exposure;
|
||||||
else
|
else
|
||||||
color *= u_ManualExposure;
|
color *= u_ManualExposure;
|
||||||
|
|
||||||
// Reinhard tonemapping operator.
|
// Reinhard 色调映射
|
||||||
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
|
|
||||||
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
|
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
|
||||||
float mappedLuminance = (luminance * (1.0 + luminance / (pureWhite * pureWhite))) / (1.0 + luminance);
|
float mappedLuminance = (luminance * (1.0 + luminance / (pureWhite * pureWhite))) / (1.0 + luminance);
|
||||||
|
|
||||||
// Scale color by ratio of average luminances.
|
// 按亮度比例缩放颜色
|
||||||
vec3 mappedColor = (mappedLuminance / luminance) * color;
|
vec3 mappedColor = (mappedLuminance / luminance) * color;
|
||||||
|
|
||||||
// Gamma correction.
|
// Gamma 校正
|
||||||
o_Color = vec4(pow(mappedColor, vec3(1.0 / gamma)), 1.0);
|
o_Color = vec4(pow(mappedColor, vec3(1.0 / gamma)), 1.0);
|
||||||
|
|
||||||
// Show over-exposed areas
|
|
||||||
// if (o_Color.r > 1.0 || o_Color.g > 1.0 || o_Color.b > 1.0)
|
|
||||||
// o_Color.rgb *= vec3(1.0, 0.25, 0.25);
|
|
||||||
}
|
}
|
||||||
@ -75,8 +75,8 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
glTexStorage2D(GL_TEXTURE_2D, 1, format, width, height);
|
glTexStorage2D(GL_TEXTURE_2D, 1, format, width, height);
|
||||||
|
|
||||||
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ namespace Prism
|
|||||||
virtual ~OpenGLRenderPass();
|
virtual ~OpenGLRenderPass();
|
||||||
|
|
||||||
virtual RenderPassSpecification& GetSpecification() override { return m_Spec; }
|
virtual RenderPassSpecification& GetSpecification() override { return m_Spec; }
|
||||||
virtual const RenderPassSpecification& GetSpecification() const { return m_Spec; }
|
virtual const RenderPassSpecification& GetSpecification() const override { return m_Spec; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RenderPassSpecification m_Spec;
|
RenderPassSpecification m_Spec;
|
||||||
|
|||||||
@ -20,6 +20,7 @@ namespace Prism
|
|||||||
virtual ~RenderPass() = default;
|
virtual ~RenderPass() = default;
|
||||||
|
|
||||||
virtual RenderPassSpecification& GetSpecification() = 0;
|
virtual RenderPassSpecification& GetSpecification() = 0;
|
||||||
|
virtual const RenderPassSpecification& GetSpecification() const = 0;
|
||||||
|
|
||||||
static Ref<RenderPass> Create(const RenderPassSpecification& spec);
|
static Ref<RenderPass> Create(const RenderPassSpecification& spec);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -25,20 +25,28 @@ namespace Prism
|
|||||||
LightEnvironment SceneLightEnvironment;
|
LightEnvironment SceneLightEnvironment;
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
Ref<MaterialInstance> SkyboxMaterial;
|
|
||||||
Ref<Environment> SceneEnvironment;
|
Ref<Environment> SceneEnvironment;
|
||||||
|
Ref<TextureCube> SkyboxTexture;
|
||||||
|
float SkyboxLoad;
|
||||||
} SceneData;
|
} SceneData;
|
||||||
|
|
||||||
Ref<Texture2D> BRDFLUT;
|
Ref<Texture2D> BRDFLUT;
|
||||||
Ref<Shader> CompositeShader;
|
Ref<Shader> CompositeShader;
|
||||||
Ref<Shader> BloomBlurShader;
|
Ref<Shader> BloomBlurShader;
|
||||||
Ref<Shader> BloomBlendShader;
|
// Ref<Shader> BloomBlendShader;
|
||||||
|
|
||||||
Ref<RenderPass> GeoPass;
|
Ref<RenderPass> GeoPass;
|
||||||
|
|
||||||
|
Ref<RenderPass> LightingPass;
|
||||||
|
Ref<Shader> LightingShader;
|
||||||
|
|
||||||
// Ref<RenderPass> CompositePass;
|
// Ref<RenderPass> CompositePass;
|
||||||
Ref<RenderPass> BloomBlurPass[2];
|
Ref<RenderPass> BloomBlurPass[2];
|
||||||
Ref<RenderPass> BloomBlendPass;
|
Ref<RenderPass> BloomBlendPass;
|
||||||
Ref<Texture2D> ResolvedHDRTexture; // 解析后的单样本 HDR 颜色
|
Ref<Texture2D> ResolvedHDRTexture; // 解析后的单样本 HDR 颜色
|
||||||
|
int Quality = 6;
|
||||||
|
float Directions = 32.0f;
|
||||||
|
float Size = 16.0f;
|
||||||
|
|
||||||
struct AutoExposureData
|
struct AutoExposureData
|
||||||
{
|
{
|
||||||
@ -95,7 +103,7 @@ namespace Prism
|
|||||||
bool ShadowEnabled = true;
|
bool ShadowEnabled = true;
|
||||||
float ShadowBias = 0.001f;
|
float ShadowBias = 0.001f;
|
||||||
float ShadowIntensity = 0.0f;
|
float ShadowIntensity = 0.0f;
|
||||||
int ShadowSoftness = 0;
|
float ShadowSoftness = 0.0f;
|
||||||
|
|
||||||
struct DrawCommand
|
struct DrawCommand
|
||||||
{
|
{
|
||||||
@ -134,11 +142,15 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
float ShadowPass = 0.0f;
|
float ShadowPass = 0.0f;
|
||||||
float GeometryPass = 0.0f;
|
float GeometryPass = 0.0f;
|
||||||
|
float LightingPass = 0.0f;
|
||||||
|
float BloomPass = 0.0f;
|
||||||
float CompositePass = 0.0f;
|
float CompositePass = 0.0f;
|
||||||
float AutoExposurePass = 0.0f;
|
float AutoExposurePass = 0.0f;
|
||||||
|
|
||||||
Timer ShadowPassTimer;
|
Timer ShadowPassTimer;
|
||||||
Timer GeometryPassTimer;
|
Timer GeometryPassTimer;
|
||||||
|
Timer LightingPassTimer;
|
||||||
|
Timer BloomPassTimer;
|
||||||
Timer CompositePassTimer;
|
Timer CompositePassTimer;
|
||||||
Timer AutoExposurePassTimer;
|
Timer AutoExposurePassTimer;
|
||||||
};
|
};
|
||||||
@ -153,9 +165,15 @@ namespace Prism
|
|||||||
//////////////// GeoPass ////////////////
|
//////////////// GeoPass ////////////////
|
||||||
{
|
{
|
||||||
FramebufferSpecification geoFramebufferSpec;
|
FramebufferSpecification geoFramebufferSpec;
|
||||||
geoFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::DEPTH24STENCIL8 };
|
geoFramebufferSpec.Attachments = {
|
||||||
geoFramebufferSpec.Samples = 8;
|
FramebufferTextureFormat::RGBA16F, // Albedo + Metallic
|
||||||
geoFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
FramebufferTextureFormat::RGBA16F, // Normal + Roughness
|
||||||
|
FramebufferTextureFormat::RGBA16F, // Emissive+AO
|
||||||
|
FramebufferTextureFormat::DEPTH24STENCIL8 // Depth
|
||||||
|
};
|
||||||
|
|
||||||
|
geoFramebufferSpec.Samples = 1;
|
||||||
|
geoFramebufferSpec.ClearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
RenderPassSpecification geoRenderPassSpec;
|
RenderPassSpecification geoRenderPassSpec;
|
||||||
geoRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(geoFramebufferSpec);
|
geoRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(geoFramebufferSpec);
|
||||||
@ -164,6 +182,18 @@ namespace Prism
|
|||||||
/////////////////////////////////////////////
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
//////////////// GeoPass ////////////////
|
||||||
|
FramebufferSpecification spec;
|
||||||
|
spec.Attachments = { FramebufferTextureFormat::RGBA16F }; // HDR 颜色输出
|
||||||
|
spec.Samples = 1;
|
||||||
|
spec.ClearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
RenderPassSpecification rpSpec;
|
||||||
|
rpSpec.TargetFramebuffer = FrameBuffer::Create(spec);
|
||||||
|
s_Data.LightingPass = RenderPass::Create(rpSpec);
|
||||||
|
s_Data.LightingShader = Shader::Create("assets/shaders/Lighting.glsl");
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
//////////////// BloomPass ////////////////
|
//////////////// BloomPass ////////////////
|
||||||
{
|
{
|
||||||
FramebufferSpecification bloomBlurFramebufferSpec;
|
FramebufferSpecification bloomBlurFramebufferSpec;
|
||||||
@ -185,7 +215,7 @@ namespace Prism
|
|||||||
s_Data.BloomBlendPass = RenderPass::Create(bloomBlendRenderPassSpec);
|
s_Data.BloomBlendPass = RenderPass::Create(bloomBlendRenderPassSpec);
|
||||||
|
|
||||||
s_Data.BloomBlurShader = Shader::Create("assets/shaders/BloomBlur.glsl");
|
s_Data.BloomBlurShader = Shader::Create("assets/shaders/BloomBlur.glsl");
|
||||||
s_Data.BloomBlendShader = Shader::Create("assets/shaders/BloomBlend.glsl");
|
// s_Data.BloomBlendShader = Shader::Create("assets/shaders/BloomBlend.glsl");
|
||||||
}
|
}
|
||||||
/////////////////////////////////////////////
|
/////////////////////////////////////////////
|
||||||
|
|
||||||
@ -284,7 +314,8 @@ namespace Prism
|
|||||||
void Renderer3D::BeginScene(const Scene* scene, const SceneRendererCamera& camera)
|
void Renderer3D::BeginScene(const Scene* scene, const SceneRendererCamera& camera)
|
||||||
{
|
{
|
||||||
s_Data.SceneData.SceneCamera = camera;
|
s_Data.SceneData.SceneCamera = camera;
|
||||||
s_Data.SceneData.SkyboxMaterial = scene->m_SkyboxMaterial;
|
s_Data.SceneData.SkyboxTexture = scene->m_SkyboxTexture;
|
||||||
|
s_Data.SceneData.SkyboxLoad = scene->m_SkyboxLod;
|
||||||
s_Data.SceneData.SceneEnvironment = scene->m_Environment;
|
s_Data.SceneData.SceneEnvironment = scene->m_Environment;
|
||||||
s_Data.SceneData.SceneEnvironmentIntensity = scene->m_EnvironmentIntensity;
|
s_Data.SceneData.SceneEnvironmentIntensity = scene->m_EnvironmentIntensity;
|
||||||
s_Data.SceneData.SceneLightEnvironment = scene->m_LightEnvironment;
|
s_Data.SceneData.SceneLightEnvironment = scene->m_LightEnvironment;
|
||||||
@ -468,7 +499,13 @@ namespace Prism
|
|||||||
Renderer::Submit([] { s_Stats.GeometryPass = s_Stats.GeometryPassTimer.ElapsedMillis(); });
|
Renderer::Submit([] { s_Stats.GeometryPass = s_Stats.GeometryPassTimer.ElapsedMillis(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolveMSAA();
|
{
|
||||||
|
Renderer::Submit([]() { s_Stats.LightingPassTimer.Reset(); });
|
||||||
|
LightingPass();
|
||||||
|
Renderer::Submit([] { s_Stats.LightingPass = s_Stats.LightingPassTimer.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)
|
||||||
{
|
{
|
||||||
@ -477,13 +514,17 @@ namespace Prism
|
|||||||
Renderer::Submit([] { s_Stats.AutoExposurePass = s_Stats.AutoExposurePassTimer.ElapsedMillis(); });
|
Renderer::Submit([] { s_Stats.AutoExposurePass = s_Stats.AutoExposurePassTimer.ElapsedMillis(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Renderer::Submit([]() { s_Stats.BloomPassTimer.Reset(); });
|
||||||
BloomBlurPass();
|
BloomBlurPass();
|
||||||
|
Renderer::Submit([] { s_Stats.BloomPass = s_Stats.BloomPassTimer.ElapsedMillis(); });
|
||||||
|
}
|
||||||
|
|
||||||
OverlayPass();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Renderer::Submit([]() { s_Stats.CompositePassTimer.Reset(); });
|
Renderer::Submit([]() { s_Stats.CompositePassTimer.Reset(); });
|
||||||
CompositePass(outRenderPass);
|
CompositePass(outRenderPass);
|
||||||
|
OverlayPass(outRenderPass);
|
||||||
Renderer::Submit([] { s_Stats.CompositePass = s_Stats.CompositePassTimer.ElapsedMillis(); });
|
Renderer::Submit([] { s_Stats.CompositePass = s_Stats.CompositePassTimer.ElapsedMillis(); });
|
||||||
// BloomBlurPass();
|
// BloomBlurPass();
|
||||||
}
|
}
|
||||||
@ -501,7 +542,8 @@ namespace Prism
|
|||||||
if (!ae.EnableAutoExposure)
|
if (!ae.EnableAutoExposure)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
auto srcFB = s_Data.LightingPass->GetSpecification().TargetFramebuffer;
|
||||||
|
// auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
||||||
auto dstFB = ae.LuminancePass->GetSpecification().TargetFramebuffer;
|
auto dstFB = ae.LuminancePass->GetSpecification().TargetFramebuffer;
|
||||||
if (!srcFB || !dstFB) return;
|
if (!srcFB || !dstFB) return;
|
||||||
|
|
||||||
@ -639,22 +681,23 @@ namespace Prism
|
|||||||
const glm::vec3 cameraPosition = glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix)[3]; // TODO: Negate instead
|
const glm::vec3 cameraPosition = glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix)[3]; // TODO: Negate instead
|
||||||
|
|
||||||
|
|
||||||
// Skybox
|
|
||||||
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);
|
|
||||||
Renderer::SubmitFullscreenQuad(s_Data.SceneData.SkyboxMaterial);
|
|
||||||
|
|
||||||
// const float aspectRatio = (float)s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetWidth() / (float)s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetHeight();
|
|
||||||
// float frustumSize = 2.0f * sceneCamera.Near * glm::tan(sceneCamera.FOV * 0.5f) * aspectRatio;
|
|
||||||
|
|
||||||
// Render entities
|
// Render entities
|
||||||
|
Renderer::Submit([]()
|
||||||
|
{
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
});
|
||||||
|
|
||||||
for (auto& dc : s_Data.DrawList)
|
for (auto& dc : s_Data.DrawList)
|
||||||
{
|
{
|
||||||
auto baseMaterial = dc.mesh->GetMaterial();
|
auto baseMaterial = dc.mesh->GetMaterial();
|
||||||
|
baseMaterial->Set("u_GBufferMode", true);
|
||||||
baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection);
|
baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection);
|
||||||
baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix);
|
baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix);
|
||||||
baseMaterial->Set("u_CameraPosition", cameraPosition);
|
baseMaterial->Set("u_CameraPosition", cameraPosition);
|
||||||
|
baseMaterial->Set("u_EmissiveColor", 1.0f);
|
||||||
|
baseMaterial->Set("u_EmissiveIntensity", 0.0f);
|
||||||
|
baseMaterial->Set("u_EmissiveTexToggle", 0.0f);
|
||||||
// baseMaterial->Set("u_LightMatrixCascade0", s_Data.LightMatrices[0]);
|
// baseMaterial->Set("u_LightMatrixCascade0", s_Data.LightMatrices[0]);
|
||||||
// baseMaterial->Set("u_LightMatrixCascade1", s_Data.LightMatrices[1]);
|
// baseMaterial->Set("u_LightMatrixCascade1", s_Data.LightMatrices[1]);
|
||||||
// baseMaterial->Set("u_LightMatrixCascade2", s_Data.LightMatrices[2]);
|
// baseMaterial->Set("u_LightMatrixCascade2", s_Data.LightMatrices[2]);
|
||||||
@ -752,6 +795,9 @@ namespace Prism
|
|||||||
baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection);
|
baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection);
|
||||||
baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix);
|
baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix);
|
||||||
baseMaterial->Set("u_CameraPosition", cameraPosition);
|
baseMaterial->Set("u_CameraPosition", cameraPosition);
|
||||||
|
baseMaterial->Set("u_EmissiveColor", 1.0f);
|
||||||
|
baseMaterial->Set("u_EmissiveIntensity", 0.0f);
|
||||||
|
baseMaterial->Set("u_EmissiveTexToggle", 0.0f);
|
||||||
// baseMaterial->Set("u_CascadeSplits", s_Data.CascadeSplits);
|
// baseMaterial->Set("u_CascadeSplits", s_Data.CascadeSplits);
|
||||||
// baseMaterial->Set("u_ShowCascades", s_Data.ShowCascades);
|
// baseMaterial->Set("u_ShowCascades", s_Data.ShowCascades);
|
||||||
// baseMaterial->Set("u_SoftShadows", s_Data.SoftShadows);
|
// baseMaterial->Set("u_SoftShadows", s_Data.SoftShadows);
|
||||||
@ -919,10 +965,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Grid
|
if (const auto option = GetOptions(); option.ShowBoundingBoxes)
|
||||||
const auto option = GetOptions();
|
|
||||||
|
|
||||||
if (option.ShowBoundingBoxes)
|
|
||||||
{
|
{
|
||||||
Renderer2D::BeginScene(cameraViewProjection);
|
Renderer2D::BeginScene(cameraViewProjection);
|
||||||
for (auto& dc : s_Data.DrawList)
|
for (auto& dc : s_Data.DrawList)
|
||||||
@ -933,6 +976,112 @@ namespace Prism
|
|||||||
Renderer::EndRenderPass();
|
Renderer::EndRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer3D::LightingPass()
|
||||||
|
{
|
||||||
|
Renderer::BeginRenderPass(s_Data.LightingPass);
|
||||||
|
s_Data.LightingShader->Bind();
|
||||||
|
|
||||||
|
// uniform
|
||||||
|
const glm::mat4 invViewProj = glm::inverse(s_Data.SceneData.SceneCamera.Camera.GetProjectionMatrix() * s_Data.SceneData.SceneCamera.ViewMatrix);
|
||||||
|
s_Data.LightingShader->SetMat4("u_InvViewProj", invViewProj);
|
||||||
|
const glm::vec3 cameraPosition = glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix)[3];
|
||||||
|
s_Data.LightingShader->SetFloat3("u_CameraPosition", cameraPosition);
|
||||||
|
|
||||||
|
|
||||||
|
// G-buffer
|
||||||
|
auto fb = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
||||||
|
Renderer::Submit([fb]() {
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, fb->GetColorAttachmentRendererID(0)); // AlbedoMetallic
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, fb->GetColorAttachmentRendererID(1)); // NormalRoughness
|
||||||
|
glActiveTexture(GL_TEXTURE2);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, fb->GetColorAttachmentRendererID(2)); // EmissiveAO
|
||||||
|
glActiveTexture(GL_TEXTURE3);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, fb->GetDepthAttachmentRendererID()); // Depth
|
||||||
|
});
|
||||||
|
s_Data.LightingShader->SetInt("u_AlbedoMetallic", 0);
|
||||||
|
s_Data.LightingShader->SetInt("u_NormalRoughness", 1);
|
||||||
|
s_Data.LightingShader->SetInt("u_EmissiveAO", 2);
|
||||||
|
s_Data.LightingShader->SetInt("u_Depth", 3);
|
||||||
|
|
||||||
|
|
||||||
|
// uniform
|
||||||
|
const auto& lights = s_Data.SceneData.SceneLightEnvironment;
|
||||||
|
// s_Data.LightingShader->SetStruct("u_DirectionalLights", lights.DirectionalLights[0]); // 需确保 SetStruct 支持
|
||||||
|
s_Data.LightingShader->SetFloat3("u_DirectionalLights.Direction", lights.DirectionalLights[0].Direction);
|
||||||
|
s_Data.LightingShader->SetFloat3("u_DirectionalLights.Radiance", lights.DirectionalLights[0].Radiance);
|
||||||
|
s_Data.LightingShader->SetFloat("u_DirectionalLights.Intensity", lights.DirectionalLights[0].Intensity);
|
||||||
|
s_Data.LightingShader->SetBool("u_DirectionalLights.CastShadows", lights.DirectionalLights[0].CastShadows);
|
||||||
|
|
||||||
|
s_Data.LightingShader->SetInt("u_PointLightCount", lights.PointLightCount);
|
||||||
|
// s_Data.LightingShader->SetStructArray("u_PointLights", lights.PointLights, lights.PointLightCount);
|
||||||
|
for (int i = 0; i < lights.PointLightCount; i++) {
|
||||||
|
std::string base = "u_PointLights[" + std::to_string(i) + "]";
|
||||||
|
s_Data.LightingShader->SetFloat3(base + ".Position", lights.PointLights[i].Position);
|
||||||
|
s_Data.LightingShader->SetFloat3(base + ".Radiance", lights.PointLights[i].Radiance);
|
||||||
|
s_Data.LightingShader->SetFloat(base + ".Intensity", lights.PointLights[i].Intensity);
|
||||||
|
s_Data.LightingShader->SetFloat(base + ".Range", lights.PointLights[i].Radius);
|
||||||
|
s_Data.LightingShader->SetBool(base + ".CastShadows", lights.PointLights[i].CastShadows);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Data.LightingShader->SetInt("u_SpotLightCount", lights.SpotLightCount);
|
||||||
|
for (int i = 0; i < lights.SpotLightCount; i++) {
|
||||||
|
std::string base = "u_SpotLights[" + std::to_string(i) + "]";
|
||||||
|
s_Data.LightingShader->SetFloat3(base + ".Position", lights.SpotLights[i].Position);
|
||||||
|
s_Data.LightingShader->SetFloat3(base + ".Direction", lights.SpotLights[i].Direction);
|
||||||
|
s_Data.LightingShader->SetFloat3(base + ".Radiance", lights.SpotLights[i].Radiance);
|
||||||
|
s_Data.LightingShader->SetFloat(base + ".Intensity", lights.SpotLights[i].Intensity);
|
||||||
|
s_Data.LightingShader->SetFloat(base + ".Range", lights.SpotLights[i].Range);
|
||||||
|
s_Data.LightingShader->SetFloat(base + ".InnerConeCos", lights.SpotLights[i].InnerConeCos);
|
||||||
|
s_Data.LightingShader->SetFloat(base + ".OuterConeCos", lights.SpotLights[i].OuterConeCos);
|
||||||
|
s_Data.LightingShader->SetBool(base + ".CastShadows", lights.SpotLights[i].CastShadows);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IBL
|
||||||
|
s_Data.LightingShader->SetInt("u_EnvRadianceTex", 4);
|
||||||
|
s_Data.LightingShader->SetInt("u_EnvIrradianceTex", 5);
|
||||||
|
s_Data.LightingShader->SetInt("u_BRDFLUTTexture", 6);
|
||||||
|
s_Data.LightingShader->SetFloat("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity);
|
||||||
|
s_Data.LightingShader->SetFloat("u_EnvMapRotation", 0.0f); // 若需要可调整
|
||||||
|
|
||||||
|
const auto& sceneEnvironment = s_Data.SceneData.SceneEnvironment;
|
||||||
|
const auto& BRDFLUT = s_Data.BRDFLUT;
|
||||||
|
Renderer::Submit([sceneEnvironment, BRDFLUT]() {
|
||||||
|
glActiveTexture(GL_TEXTURE4);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, sceneEnvironment->RadianceMap->GetRendererID());
|
||||||
|
glActiveTexture(GL_TEXTURE5);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, sceneEnvironment->IrradianceMap->GetRendererID());
|
||||||
|
glActiveTexture(GL_TEXTURE6);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, BRDFLUT->GetRendererID());
|
||||||
|
});
|
||||||
|
|
||||||
|
s_Data.LightingShader->SetMat4("u_LightSpaceMatrix", s_Data.LightMatrices);
|
||||||
|
s_Data.LightingShader->SetBool("u_ShadowEnabled", s_Data.ShadowEnabled);
|
||||||
|
s_Data.LightingShader->SetFloat("u_ShadowBias", s_Data.ShadowBias);
|
||||||
|
s_Data.LightingShader->SetFloat("u_ShadowIntensity", s_Data.ShadowIntensity);
|
||||||
|
s_Data.LightingShader->SetFloat("u_ShadowSoftness", s_Data.ShadowSoftness);
|
||||||
|
|
||||||
|
if (s_Data.ShadowEnabled) {
|
||||||
|
s_Data.LightingShader->SetInt("u_ShadowMap", 7);
|
||||||
|
Renderer::Submit([]() {
|
||||||
|
glActiveTexture(GL_TEXTURE7);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, s_Data.ShadowMapRenderPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID());
|
||||||
|
glBindSampler(7, s_Data.ShadowMapSampler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_Data.SceneData.SkyboxTexture) {
|
||||||
|
s_Data.LightingShader->SetFloat("u_SkyTextureLod", s_Data.SceneData.SkyboxLoad);
|
||||||
|
s_Data.SceneData.SkyboxTexture->Bind(8);
|
||||||
|
s_Data.LightingShader->SetInt("u_Skybox", 8); // 使用纹理单元 8(确保不与其他单元冲突)
|
||||||
|
s_Data.LightingShader->SetFloat("u_SkyIntensity", s_Data.SceneData.SceneEnvironmentIntensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer::SubmitFullscreenQuad(nullptr);
|
||||||
|
Renderer::EndRenderPass();
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer3D::BloomBlurPass()
|
void Renderer3D::BloomBlurPass()
|
||||||
{
|
{
|
||||||
if (!s_Data.EnableBloom)
|
if (!s_Data.EnableBloom)
|
||||||
@ -943,59 +1092,73 @@ namespace Prism
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t srcTex = s_Data.ResolvedHDRTexture->GetRendererID();
|
// uint32_t srcTex = s_Data.ResolvedHDRTexture->GetRendererID();
|
||||||
const int iterations = 5; // 模糊迭代次数,可调
|
uint32_t srcTex = s_Data.LightingPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
|
||||||
|
|
||||||
// 第一次:提取高光 + 水平模糊
|
// 第一次:提取高光 + 水平模糊
|
||||||
{
|
{
|
||||||
Renderer::BeginRenderPass(s_Data.BloomBlurPass[0]);
|
Renderer::BeginRenderPass(s_Data.BloomBlurPass[0]);
|
||||||
s_Data.BloomBlurShader->Bind();
|
s_Data.BloomBlurShader->Bind();
|
||||||
s_Data.BloomBlurShader->SetInt("u_Texture", 0);
|
s_Data.BloomBlurShader->SetInt("u_Texture", 0);
|
||||||
// s_Data.BloomBlurShader->SetBool("u_Horizontal", true);
|
|
||||||
s_Data.BloomBlurShader->SetBool("u_FirstPass", true);
|
s_Data.BloomBlurShader->SetBool("u_FirstPass", true);
|
||||||
s_Data.BloomBlurShader->SetFloat("u_Threshold", s_Data.BloomThreshold);
|
s_Data.BloomBlurShader->SetFloat("u_Threshold", s_Data.BloomThreshold);
|
||||||
|
s_Data.BloomBlurShader->SetInt("u_Quality", s_Data.Quality);
|
||||||
|
s_Data.BloomBlurShader->SetFloat("u_Directions", s_Data.Directions);
|
||||||
|
s_Data.BloomBlurShader->SetFloat("u_Size", s_Data.Size);
|
||||||
Renderer::Submit([srcTex]() { glBindTextureUnit(0, srcTex); });
|
Renderer::Submit([srcTex]() { glBindTextureUnit(0, srcTex); });
|
||||||
Renderer::SubmitFullscreenQuad(nullptr);
|
Renderer::SubmitFullscreenQuad(nullptr);
|
||||||
Renderer::EndRenderPass();
|
Renderer::EndRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 后续迭代
|
uint32_t finalBlurTex = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
|
||||||
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);
|
Renderer::BeginRenderPass(s_Data.BloomBlendPass);
|
||||||
s_Data.BloomBlurShader->Bind();
|
s_Data.BloomBlurShader->Bind();
|
||||||
s_Data.BloomBlurShader->SetInt("u_Texture", 0);
|
s_Data.BloomBlurShader->SetInt("u_Texture", 0);
|
||||||
// s_Data.BloomBlurShader->SetBool("u_Horizontal", false);
|
|
||||||
s_Data.BloomBlurShader->SetBool("u_FirstPass", false);
|
s_Data.BloomBlurShader->SetBool("u_FirstPass", false);
|
||||||
|
s_Data.BloomBlurShader->SetInt("u_Quality", s_Data.Quality);
|
||||||
|
s_Data.BloomBlurShader->SetFloat("u_Directions", s_Data.Directions);
|
||||||
|
s_Data.BloomBlurShader->SetFloat("u_Size", s_Data.Size);
|
||||||
Renderer::Submit([finalBlurTex]() { glBindTextureUnit(0, finalBlurTex); });
|
Renderer::Submit([finalBlurTex]() { glBindTextureUnit(0, finalBlurTex); });
|
||||||
Renderer::SubmitFullscreenQuad(nullptr);
|
Renderer::SubmitFullscreenQuad(nullptr);
|
||||||
Renderer::EndRenderPass();
|
Renderer::EndRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer3D::OverlayPass()
|
|
||||||
|
void Renderer3D::CompositePass(const Ref<RenderPass>& outRenderPass)
|
||||||
{
|
{
|
||||||
Renderer::BeginRenderPass(s_Data.GeoPass, false);
|
Renderer::BeginRenderPass(outRenderPass);
|
||||||
|
|
||||||
|
s_Data.CompositeShader->Bind();
|
||||||
|
|
||||||
|
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->SetBool("u_EnableBloom", s_Data.EnableBloom);
|
||||||
|
s_Data.LightingPass->GetSpecification().TargetFramebuffer->BindTexture(); // 通常绑定到单元0
|
||||||
|
Renderer::Submit([]() {
|
||||||
|
glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID());
|
||||||
|
});
|
||||||
|
|
||||||
|
if (s_Data.EnableBloom)
|
||||||
|
{
|
||||||
|
uint32_t bloomTex = s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
|
||||||
|
Renderer::Submit([bloomTex]() {
|
||||||
|
glBindTextureUnit(2, bloomTex);
|
||||||
|
});
|
||||||
|
s_Data.CompositeShader->SetInt("u_BloomTexture", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Data.AutoExposureData.ExposureSSBO->BindBase(2);
|
||||||
|
|
||||||
|
|
||||||
|
Renderer::SubmitFullscreenQuad(nullptr);
|
||||||
|
Renderer::EndRenderPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer3D::OverlayPass(const Ref<RenderPass>& outRenderPass)
|
||||||
|
{
|
||||||
|
Renderer::BeginRenderPass(outRenderPass, false);
|
||||||
|
|
||||||
if (const auto option = GetOptions(); option.ShowGrid)
|
if (const auto option = GetOptions(); option.ShowGrid)
|
||||||
{
|
{
|
||||||
@ -1023,216 +1186,7 @@ namespace Prism
|
|||||||
Renderer::EndRenderPass();
|
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
|
|
||||||
{
|
|
||||||
float r, l, b, t, f, n;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CascadeData
|
|
||||||
{
|
|
||||||
glm::mat4 ViewProj;
|
|
||||||
glm::mat4 View;
|
|
||||||
float SplitDepth;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void CalculateCascades(CascadeData* cascades, const glm::vec3& lightDirection)
|
|
||||||
{
|
|
||||||
// FrustumBounds frustumBounds[3];
|
|
||||||
|
|
||||||
auto& sceneCamera = s_Data.SceneData.SceneCamera;
|
|
||||||
auto viewProjection = sceneCamera.Camera.GetProjectionMatrix() * sceneCamera.ViewMatrix;
|
|
||||||
|
|
||||||
constexpr int SHADOW_MAP_CASCADE_COUNT = 4;
|
|
||||||
float cascadeSplits[SHADOW_MAP_CASCADE_COUNT];
|
|
||||||
|
|
||||||
// TODO: less hard-coding!
|
|
||||||
float nearClip = 0.1f;
|
|
||||||
float farClip = 1000.0f;
|
|
||||||
float clipRange = farClip - nearClip;
|
|
||||||
|
|
||||||
float minZ = nearClip;
|
|
||||||
float maxZ = nearClip + clipRange;
|
|
||||||
|
|
||||||
float range = maxZ - minZ;
|
|
||||||
float ratio = maxZ / minZ;
|
|
||||||
|
|
||||||
// Calculate split depths based on view camera frustum
|
|
||||||
// Based on method presented in https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch10.html
|
|
||||||
for (uint32_t i = 0; i < SHADOW_MAP_CASCADE_COUNT; i++)
|
|
||||||
{
|
|
||||||
float p = (i + 1) / static_cast<float>(SHADOW_MAP_CASCADE_COUNT);
|
|
||||||
float log = minZ * std::pow(ratio, p);
|
|
||||||
float uniform = minZ + range * p;
|
|
||||||
float d = s_Data.CascadeSplitLambda * (log - uniform) + uniform;
|
|
||||||
cascadeSplits[i] = (d - nearClip) / clipRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cascadeSplits[3] = 0.3f;
|
|
||||||
|
|
||||||
// Manually set cascades here
|
|
||||||
// cascadeSplits[0] = 0.05f;
|
|
||||||
// cascadeSplits[1] = 0.15f;
|
|
||||||
// cascadeSplits[2] = 0.3f;
|
|
||||||
// cascadeSplits[3] = 1.0f;
|
|
||||||
|
|
||||||
// Calculate orthographic projection matrix for each cascade
|
|
||||||
float lastSplitDist = 1.0;
|
|
||||||
for (uint32_t i = 0; i < SHADOW_MAP_CASCADE_COUNT; i++)
|
|
||||||
{
|
|
||||||
float splitDist = cascadeSplits[i];
|
|
||||||
|
|
||||||
glm::vec3 frustumCorners[8] =
|
|
||||||
{
|
|
||||||
glm::vec3(-1.0f, 1.0f, -1.0f),
|
|
||||||
glm::vec3( 1.0f, 1.0f, -1.0f),
|
|
||||||
glm::vec3( 1.0f, -1.0f, -1.0f),
|
|
||||||
glm::vec3(-1.0f, -1.0f, -1.0f),
|
|
||||||
glm::vec3(-1.0f, 1.0f, 1.0f),
|
|
||||||
glm::vec3( 1.0f, 1.0f, 1.0f),
|
|
||||||
glm::vec3( 1.0f, -1.0f, 1.0f),
|
|
||||||
glm::vec3(-1.0f, -1.0f, 1.0f),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Project frustum corners into world space
|
|
||||||
glm::mat4 invCam = glm::inverse(viewProjection);
|
|
||||||
for (uint32_t i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
glm::vec4 invCorner = invCam * glm::vec4(frustumCorners[i], 1.0f);
|
|
||||||
frustumCorners[i] = invCorner / invCorner.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
glm::vec3 dist = frustumCorners[i + 4] - frustumCorners[i];
|
|
||||||
frustumCorners[i + 4] = frustumCorners[i] + (dist * splitDist);
|
|
||||||
frustumCorners[i] = frustumCorners[i] + (dist * lastSplitDist);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get frustum center
|
|
||||||
glm::vec3 frustumCenter = glm::vec3(0.0f);
|
|
||||||
for (uint32_t i = 0; i < 8; i++)
|
|
||||||
frustumCenter += frustumCorners[i];
|
|
||||||
|
|
||||||
frustumCenter /= 8.0f;
|
|
||||||
|
|
||||||
//frustumCenter *= 0.01f;
|
|
||||||
|
|
||||||
float radius = 0.0f;
|
|
||||||
for (uint32_t i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
float distance = glm::length(frustumCorners[i] - frustumCenter);
|
|
||||||
radius = glm::max(radius, distance);
|
|
||||||
}
|
|
||||||
radius = std::ceil(radius * 16.0f) / 16.0f;
|
|
||||||
|
|
||||||
glm::vec3 maxExtents = glm::vec3(radius);
|
|
||||||
glm::vec3 minExtents = -maxExtents;
|
|
||||||
|
|
||||||
glm::vec3 lightDir = -lightDirection;
|
|
||||||
glm::mat4 lightViewMatrix = glm::lookAt(frustumCenter - lightDir * -minExtents.z, frustumCenter, glm::vec3(0.0f, 0.0f, 1.0f));
|
|
||||||
glm::mat4 lightOrthoMatrix = glm::ortho(minExtents.x, maxExtents.x, minExtents.y, maxExtents.y, 0.0f + s_Data.CascadeNearPlaneOffset, maxExtents.z - minExtents.z + s_Data.CascadeFarPlaneOffset);
|
|
||||||
|
|
||||||
// Offset to texel space to avoid shimmering (from https://stackoverflow.com/questions/33499053/cascaded-shadow-map-shimmering)
|
|
||||||
glm::mat4 shadowMatrix = lightOrthoMatrix * lightViewMatrix;
|
|
||||||
constexpr float ShadowMapResolution = 4096.0f;
|
|
||||||
glm::vec4 shadowOrigin = (shadowMatrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)) * ShadowMapResolution / 2.0f;
|
|
||||||
glm::vec4 roundedOrigin = glm::round(shadowOrigin);
|
|
||||||
glm::vec4 roundOffset = roundedOrigin - shadowOrigin;
|
|
||||||
roundOffset = roundOffset * 2.0f / ShadowMapResolution;
|
|
||||||
roundOffset.z = 0.0f;
|
|
||||||
roundOffset.w = 0.0f;
|
|
||||||
|
|
||||||
lightOrthoMatrix[3] += roundOffset;
|
|
||||||
|
|
||||||
// Store split distance and matrix in cascade
|
|
||||||
cascades[i].SplitDepth = (nearClip + splitDist * clipRange) * -1.0f;
|
|
||||||
cascades[i].ViewProj = lightOrthoMatrix * lightViewMatrix;
|
|
||||||
cascades[i].View = lightViewMatrix;
|
|
||||||
|
|
||||||
lastSplitDist = cascadeSplits[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::vector<glm::vec3> GetFrustumCornersWorldSpace(const SceneRendererCamera& sceneCamera)
|
std::vector<glm::vec3> GetFrustumCornersWorldSpace(const SceneRendererCamera& sceneCamera)
|
||||||
{
|
{
|
||||||
std::vector<glm::vec3> corners(8);
|
std::vector<glm::vec3> corners(8);
|
||||||
@ -1258,39 +1212,6 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Renderer3D::ResolveMSAA()
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
s_Data.ResolvedHDRTexture = Texture2D::Create(TextureFormat::RGBA16F, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFB->GetRendererID());
|
|
||||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SceneRenderer::OnImGuiRender()
|
void SceneRenderer::OnImGuiRender()
|
||||||
{
|
{
|
||||||
ImGui::Begin("Scene Renderer");
|
ImGui::Begin("Scene Renderer");
|
||||||
@ -1298,9 +1219,37 @@ namespace Prism
|
|||||||
|
|
||||||
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("Composite Pass time", s_Stats.CompositePass);
|
||||||
|
UI::Property("Bloom Pass time", s_Stats.BloomPass);
|
||||||
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);
|
||||||
|
|
||||||
|
if (UI::BeginTreeNode("Geometry", false))
|
||||||
|
{
|
||||||
|
const float size = ImGui::GetContentRegionAvail().x; // (float)fb->GetWidth() * 0.5f, (float)fb->GetHeight() * 0.5f
|
||||||
|
float w = size;
|
||||||
|
auto fb = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
||||||
|
auto image1 = fb->GetColorAttachmentRendererID(0);
|
||||||
|
auto image2 = fb->GetColorAttachmentRendererID(1);
|
||||||
|
auto image3 = fb->GetColorAttachmentRendererID(2);
|
||||||
|
float h = w / ((float)fb->GetWidth() / (float)fb->GetHeight());
|
||||||
|
ImGui::Image((ImTextureID)image1, { w, h }, { 0, 1 }, { 1, 0 });
|
||||||
|
ImGui::Image((ImTextureID)image2, { w, h }, { 0, 1 }, { 1, 0 });
|
||||||
|
ImGui::Image((ImTextureID)image3, { w, h }, { 0, 1 }, { 1, 0 });
|
||||||
|
|
||||||
|
auto lightFB = s_Data.LightingPass->GetSpecification().TargetFramebuffer;
|
||||||
|
auto lightImage = lightFB->GetColorAttachmentRendererID();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::Image((ImTextureID)lightImage, { w, h }, { 0, 1 }, { 1, 0 });
|
||||||
|
|
||||||
|
auto depthfb = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
|
||||||
|
uint32_t depthID = depthfb->GetDepthAttachmentRendererID();
|
||||||
|
ImGui::Image((ImTextureID)depthID, {w, h}, {0, 1}, {1, 0});
|
||||||
|
|
||||||
|
UI::EndTreeNode();
|
||||||
|
}
|
||||||
|
|
||||||
if (UI::BeginTreeNode("Grid Config", false))
|
if (UI::BeginTreeNode("Grid Config", false))
|
||||||
{
|
{
|
||||||
// Grid plane: 0 = XZ (Y up), 1 = XY (Z forward), 2 = YZ (X right)
|
// Grid plane: 0 = XZ (Y up), 1 = XY (Z forward), 2 = YZ (X right)
|
||||||
@ -1361,6 +1310,10 @@ namespace Prism
|
|||||||
UI::BeginPropertyGrid();
|
UI::BeginPropertyGrid();
|
||||||
UI::Property("Bloom", s_Data.EnableBloom);
|
UI::Property("Bloom", s_Data.EnableBloom);
|
||||||
UI::Property("Bloom threshold", s_Data.BloomThreshold, 0.05f);
|
UI::Property("Bloom threshold", s_Data.BloomThreshold, 0.05f);
|
||||||
|
UI::Property("Directions", s_Data.Directions);
|
||||||
|
UI::Property("Quality", s_Data.Quality);
|
||||||
|
UI::Property("Size", s_Data.Size);
|
||||||
|
|
||||||
UI::EndPropertyGrid();
|
UI::EndPropertyGrid();
|
||||||
|
|
||||||
auto fb = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer;
|
auto fb = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer;
|
||||||
@ -1374,24 +1327,9 @@ namespace Prism
|
|||||||
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)id2, { w, h }, { 0, 1 }, { 1, 0 });
|
||||||
ImGui::Image((ImTextureID)s_Data.ResolvedHDRTexture->GetRendererID(), { w, h }, { 0, 1 }, { 1, 0 });
|
|
||||||
UI::EndTreeNode();
|
UI::EndTreeNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if (UI::BeginTreeNode("Auto Exposure", false))
|
|
||||||
{
|
|
||||||
UI::BeginPropertyGrid();
|
|
||||||
UI::Property("Enable Auto Exposure", s_Data.AutoExposureData.EnableAutoExposure);
|
|
||||||
UI::Property("Key (middle gray)", s_Data.AutoExposureData.Key, 0.001f, 0.001f, 2.5f);
|
|
||||||
UI::Property("Adaptation Speed", s_Data.AutoExposureData.AdaptationSpeed, 0.01f, 0.001f, 5.0f);
|
|
||||||
UI::Property("Current Exposure", s_Data.AutoExposureData.CurrentExposure, 0.01f, 0.0f, 0.0f, true);
|
|
||||||
UI::EndPropertyGrid();
|
|
||||||
|
|
||||||
UI::EndTreeNode();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (UI::BeginTreeNode("Auto Exposure", false))
|
if (UI::BeginTreeNode("Auto Exposure", false))
|
||||||
{
|
{
|
||||||
UI::BeginPropertyGrid();
|
UI::BeginPropertyGrid();
|
||||||
|
|||||||
@ -61,13 +61,15 @@ namespace Prism
|
|||||||
static void AutoExposurePass();
|
static void AutoExposurePass();
|
||||||
static void ShadowMapPass();
|
static void ShadowMapPass();
|
||||||
static void GeometryPass();
|
static void GeometryPass();
|
||||||
|
static void LightingPass();
|
||||||
static void BloomBlurPass();
|
static void BloomBlurPass();
|
||||||
static void OverlayPass();
|
|
||||||
|
static void OverlayPass(const Ref<RenderPass>& outRenderPass);
|
||||||
|
|
||||||
static void CompositePass(const Ref<RenderPass>& outRenderPass);
|
static void CompositePass(const Ref<RenderPass>& outRenderPass);
|
||||||
|
|
||||||
|
|
||||||
static void ResolveMSAA();
|
// static void ResolveMSAA();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ namespace Prism
|
|||||||
void SceneRenderer::Init()
|
void SceneRenderer::Init()
|
||||||
{
|
{
|
||||||
FramebufferSpecification finalFramebufferSpec;
|
FramebufferSpecification finalFramebufferSpec;
|
||||||
finalFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::Depth};
|
finalFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::DEPTH24STENCIL8};
|
||||||
finalFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
finalFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||||
|
|
||||||
RenderPassSpecification finalRenderPassSpec;
|
RenderPassSpecification finalRenderPassSpec;
|
||||||
|
|||||||
@ -452,7 +452,7 @@ namespace Prism
|
|||||||
MeshComponent,
|
MeshComponent,
|
||||||
RigidBodyComponent, BoxColliderComponent, SphereColliderComponent, CapsuleColliderComponent, MeshColliderComponent,
|
RigidBodyComponent, BoxColliderComponent, SphereColliderComponent, CapsuleColliderComponent, MeshColliderComponent,
|
||||||
AnimationComponent,
|
AnimationComponent,
|
||||||
DirectionalLightComponent, SkyLightComponent,
|
DirectionalLightComponent, SkyLightComponent, PointLightComponent, SpotLightComponent,
|
||||||
ScriptComponent,
|
ScriptComponent,
|
||||||
CameraComponent
|
CameraComponent
|
||||||
>;
|
>;
|
||||||
|
|||||||
@ -70,9 +70,9 @@ namespace Prism
|
|||||||
|
|
||||||
void Scene::Init()
|
void Scene::Init()
|
||||||
{
|
{
|
||||||
const auto skyboxShader = Shader::Create("assets/shaders/Skybox.glsl");
|
// const auto skyboxShader = Shader::Create("assets/shaders/Skybox.glsl");
|
||||||
m_SkyboxMaterial = MaterialInstance::Create(Material::Create(skyboxShader));
|
// m_SkyboxMaterial = MaterialInstance::Create(Material::Create(skyboxShader));
|
||||||
m_SkyboxMaterial->SetFlag(MaterialFlag::DepthTest, false);
|
// m_SkyboxMaterial->SetFlag(MaterialFlag::DepthTest, false);
|
||||||
|
|
||||||
m_CameraIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/Camera.png");
|
m_CameraIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/Camera.png");
|
||||||
m_LightIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/light.png");
|
m_LightIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/light.png");
|
||||||
@ -171,7 +171,8 @@ namespace Prism
|
|||||||
|
|
||||||
// TODO: only one sky light at the moment!
|
// TODO: only one sky light at the moment!
|
||||||
{
|
{
|
||||||
m_Environment = Ref<Environment>::Create();
|
if (!m_Environment)
|
||||||
|
m_Environment = Ref<Environment>::Create(Renderer3D::GetBlackCubeTexture(), Renderer3D::GetBlackCubeTexture());
|
||||||
const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
|
const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
|
||||||
for (const auto entity : lights)
|
for (const auto entity : lights)
|
||||||
{
|
{
|
||||||
@ -184,7 +185,6 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
|
|
||||||
|
|
||||||
SceneRenderer::BeginScene(this, { static_cast<Camera>(camera), cameraViewMatrix }, false);
|
SceneRenderer::BeginScene(this, { static_cast<Camera>(camera), cameraViewMatrix }, false);
|
||||||
{
|
{
|
||||||
@ -236,7 +236,7 @@ namespace Prism
|
|||||||
// TODO: only one sky light at the moment!
|
// TODO: only one sky light at the moment!
|
||||||
{
|
{
|
||||||
const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
|
const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
|
||||||
if (lights.empty())
|
if (!m_Environment)
|
||||||
m_Environment = Ref<Environment>::Create(Renderer3D::GetBlackCubeTexture(), Renderer3D::GetBlackCubeTexture());
|
m_Environment = Ref<Environment>::Create(Renderer3D::GetBlackCubeTexture(), Renderer3D::GetBlackCubeTexture());
|
||||||
if (!lights.empty())
|
if (!lights.empty())
|
||||||
{
|
{
|
||||||
@ -251,13 +251,14 @@ namespace Prism
|
|||||||
|
|
||||||
m_Environment = skyLightComponent.SceneEnvironment;
|
m_Environment = skyLightComponent.SceneEnvironment;
|
||||||
m_EnvironmentIntensity = skyLightComponent.Intensity;
|
m_EnvironmentIntensity = skyLightComponent.Intensity;
|
||||||
|
|
||||||
|
break; //TODO: this only support one environment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_Environment)
|
if (m_Environment)
|
||||||
SetSkybox(m_Environment->RadianceMap);
|
SetSkybox(m_Environment->RadianceMap);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
|
|
||||||
|
|
||||||
// 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
|
||||||
@ -440,7 +441,6 @@ namespace Prism
|
|||||||
void Scene::SetSkybox(const Ref<TextureCube>& skybox)
|
void Scene::SetSkybox(const Ref<TextureCube>& skybox)
|
||||||
{
|
{
|
||||||
m_SkyboxTexture = skybox;
|
m_SkyboxTexture = skybox;
|
||||||
m_SkyboxMaterial->Set("u_Texture", skybox);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity Scene::GetMainCameraEntity()
|
Entity Scene::GetMainCameraEntity()
|
||||||
@ -579,8 +579,8 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
target->m_Environment = m_Environment;
|
target->m_Environment = m_Environment;
|
||||||
target->m_SkyboxTexture = m_SkyboxTexture;
|
target->m_SkyboxTexture = m_SkyboxTexture;
|
||||||
target->m_SkyboxMaterial = m_SkyboxMaterial;
|
|
||||||
target->m_SkyboxLod = m_SkyboxLod;
|
target->m_SkyboxLod = m_SkyboxLod;
|
||||||
|
target->m_EnvironmentIntensity = m_EnvironmentIntensity;
|
||||||
|
|
||||||
std::unordered_map<UUID, entt::entity> enttMap;
|
std::unordered_map<UUID, entt::entity> enttMap;
|
||||||
auto idComponents = m_Registry.view<IDComponent>();
|
auto idComponents = m_Registry.view<IDComponent>();
|
||||||
@ -646,35 +646,33 @@ namespace Prism
|
|||||||
// Point Light
|
// Point Light
|
||||||
{
|
{
|
||||||
const auto pointLights = m_Registry.group<PointLightComponent>(entt::get<TransformComponent>);
|
const auto pointLights = m_Registry.group<PointLightComponent>(entt::get<TransformComponent>);
|
||||||
uint32_t pointLightIndex = 0;
|
m_LightEnvironment.PointLightCount = 0;
|
||||||
for (const auto entity : pointLights)
|
for (const auto entity : pointLights)
|
||||||
{
|
{
|
||||||
if (pointLightIndex >= 8) break;
|
if (m_LightEnvironment.PointLightCount >= 16) break;
|
||||||
auto [transform, light] = pointLights.get<TransformComponent, PointLightComponent>(entity);
|
auto [transform, light] = pointLights.get<TransformComponent, PointLightComponent>(entity);
|
||||||
m_LightEnvironment.PointLights[pointLightIndex++] = {
|
m_LightEnvironment.PointLights[m_LightEnvironment.PointLightCount++] = {
|
||||||
transform.Translation,
|
transform.Translation,
|
||||||
light.Radiance,
|
light.Radiance,
|
||||||
light.Radius,
|
light.Radius,
|
||||||
light.Intensity,
|
light.Intensity,
|
||||||
light.CastShadows,
|
light.CastShadows,
|
||||||
};
|
};
|
||||||
|
|
||||||
m_LightEnvironment.PointLightCount ++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spot Light
|
// Spot Light
|
||||||
{
|
{
|
||||||
const auto spotLights = m_Registry.group<SpotLightComponent>(entt::get<TransformComponent>);
|
const auto spotLights = m_Registry.group<SpotLightComponent>(entt::get<TransformComponent>);
|
||||||
uint32_t pointLightIndex = 0;
|
m_LightEnvironment.SpotLightCount = 0;
|
||||||
for (const auto entity : spotLights)
|
for (const auto entity : spotLights)
|
||||||
{
|
{
|
||||||
if (pointLightIndex >= 8) break;
|
if (m_LightEnvironment.SpotLightCount >= 16) break;
|
||||||
auto [transform, light] = spotLights.get<TransformComponent, SpotLightComponent>(entity);
|
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 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 innerCos = glm::cos(glm::radians(light.InnerConeAngle));
|
||||||
const float outerCos = glm::cos(glm::radians(light.OuterConeAngle));
|
const float outerCos = glm::cos(glm::radians(light.OuterConeAngle));
|
||||||
m_LightEnvironment.SpotLights[pointLightIndex++] = {
|
m_LightEnvironment.SpotLights[m_LightEnvironment.SpotLightCount++] = {
|
||||||
transform.Translation,
|
transform.Translation,
|
||||||
direction,
|
direction,
|
||||||
light.Radiance,
|
light.Radiance,
|
||||||
@ -684,7 +682,6 @@ namespace Prism
|
|||||||
outerCos,
|
outerCos,
|
||||||
light.CastShadows,
|
light.CastShadows,
|
||||||
};
|
};
|
||||||
m_LightEnvironment.SpotLightCount ++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,10 +54,10 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
GPUDirectionalLight DirectionalLights[4];
|
GPUDirectionalLight DirectionalLights[4];
|
||||||
|
|
||||||
GPUPointLight PointLights[8]{};
|
GPUPointLight PointLights[16]{};
|
||||||
int PointLightCount = 0;
|
int PointLightCount = 0;
|
||||||
|
|
||||||
GPUSpotLight SpotLights[8]{};
|
GPUSpotLight SpotLights[16]{};
|
||||||
int SpotLightCount = 0;
|
int SpotLightCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,11 +164,10 @@ namespace Prism
|
|||||||
bool m_IsPlaying = false;
|
bool m_IsPlaying = false;
|
||||||
|
|
||||||
Ref<Environment> m_Environment;
|
Ref<Environment> m_Environment;
|
||||||
float m_EnvironmentIntensity = 1.0f;
|
|
||||||
Ref<TextureCube> m_SkyboxTexture;
|
Ref<TextureCube> m_SkyboxTexture;
|
||||||
Ref<MaterialInstance> m_SkyboxMaterial;
|
|
||||||
|
|
||||||
float m_SkyboxLod = 1.0f;
|
float m_SkyboxLod = 0.0f;
|
||||||
|
float m_EnvironmentIntensity = 1.0f;
|
||||||
|
|
||||||
|
|
||||||
Ref<Texture2D> m_CameraIcon;
|
Ref<Texture2D> m_CameraIcon;
|
||||||
|
|||||||
Reference in New Issue
Block a user