diff --git a/Editor/Editor/EditorLayer.cpp b/Editor/Editor/EditorLayer.cpp index 6de3011..ebe4144 100644 --- a/Editor/Editor/EditorLayer.cpp +++ b/Editor/Editor/EditorLayer.cpp @@ -1062,7 +1062,6 @@ namespace Prism for (const auto& selectedEntity : m_SelectionContext) { if (alreadySelectedEntityID == selectedEntity.Entity.GetUUID()) continue; - OnSelected(selectedEntity); return false; } } diff --git a/Editor/assets/shaders/PBRShader_Anim.glsl b/Editor/assets/shaders/PBRShader_Anim.glsl index a5dc7ec..c3e5611 100644 --- a/Editor/assets/shaders/PBRShader_Anim.glsl +++ b/Editor/assets/shaders/PBRShader_Anim.glsl @@ -75,11 +75,30 @@ const float Epsilon = 0.00001; const int LightCount = 1; const vec3 Fdielectric = vec3(0.04); -struct DirectionalLight -{ +struct DirectionalLight { vec3 Direction; vec3 Radiance; - float Multiplier; + 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; }; in VertexOutput @@ -100,6 +119,13 @@ layout(location = 1) out vec4 o_BloomColor; uniform DirectionalLight u_DirectionalLights; uniform vec3 u_CameraPosition; +uniform int u_PointLightCount; +uniform PointLight u_PointLights; + +uniform int u_SpotLightCount; +uniform SpotLight u_SpotLights; + + // PBR uniform sampler2D u_AlbedoTexture; uniform sampler2D u_NormalTexture; @@ -185,13 +211,104 @@ vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness) } // ---------- direction light ---------- +vec3 ComputeDirectionalLight(DirectionalLight light, vec3 F0, PBRParameters params) +{ + vec3 L = normalize(-light.Direction); + vec3 Lradiance = light.Radiance * light.Intensity; + + vec3 Lh = normalize(L + params.View); + float cosLi = max(0.0, dot(params.Normal, L)); + float cosLh = max(0.0, dot(params.Normal, Lh)); + + vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View))); + float D = ndfGGX(cosLh, params.Roughness); + float G = GeometrySmith(params.Normal, params.View, L, params.Roughness); + + vec3 kd = (1.0 - F) * (1.0 - params.Metalness); + vec3 diffuseBRDF = kd * params.Albedo; + vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV); + + return (diffuseBRDF + specularBRDF) * Lradiance * cosLi; +} + +vec3 ComputePointLight(PointLight light, vec3 F0, PBRParameters params, 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 + params.View); + float cosLi = max(0.0, dot(params.Normal, L)); + float cosLh = max(0.0, dot(params.Normal, Lh)); + + vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View))); + float D = ndfGGX(cosLh, params.Roughness); + float G = GeometrySmith(params.Normal, params.View, L, params.Roughness); + + vec3 kd = (1.0 - F) * (1.0 - params.Metalness); + vec3 diffuseBRDF = kd * params.Albedo; + vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV); + + return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation; +} + +vec3 ComputeSpotLight(SpotLight light, vec3 F0, PBRParameters params, 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)); // 光方向指向外,所以用 -L + 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 + params.View); + float cosLi = max(0.0, dot(params.Normal, L)); + float cosLh = max(0.0, dot(params.Normal, Lh)); + + vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View))); + float D = ndfGGX(cosLh, params.Roughness); + float G = GeometrySmith(params.Normal, params.View, L, params.Roughness); + + vec3 kd = (1.0 - F) * (1.0 - params.Metalness); + vec3 diffuseBRDF = kd * params.Albedo; + vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV); + + return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation; +} + + + vec3 Lighting(vec3 F0) { vec3 result = vec3(0.0); for(int i = 0; i < LightCount; i++) { vec3 Li = u_DirectionalLights.Direction; - vec3 Lradiance = u_DirectionalLights.Radiance * u_DirectionalLights.Multiplier; + vec3 Lradiance = u_DirectionalLights.Radiance * u_DirectionalLights.Intensity; vec3 Lh = normalize(Li + m_Params.View); float cosLi = max(0.0, dot(m_Params.Normal, Li)); @@ -216,9 +333,9 @@ 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)) + vec3(cos(angle), 0.0, sin(angle)), + vec3(0.0, 1.0, 0.0), + vec3(-sin(angle), 0.0, cos(angle)) ); return rotationMatrix * vec; } @@ -232,9 +349,9 @@ vec3 IBL(vec3 F0, vec3 Lr) int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex); vec3 specularIrradiance = textureLod( - u_EnvRadianceTex, - RotateVectorAboutY(u_EnvMapRotation, Lr), - m_Params.Roughness * u_EnvRadianceTexLevels + u_EnvRadianceTex, + RotateVectorAboutY(u_EnvMapRotation, Lr), + m_Params.Roughness * u_EnvRadianceTexLevels ).rgb; vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg; @@ -334,8 +451,15 @@ void main() shadowFactor = 1.0 - shadow; } - // directional light with shadow - vec3 lightContribution = u_DirectionalLights.Multiplier > 0.0 ? Lighting(F0) * shadowFactor : vec3(0.0); + + vec3 lightContribution = u_DirectionalLights.Intensity > 0.0 ? Lighting(F0) * shadowFactor : vec3(0.0); + + if(u_PointLightCount > 0) + lightContribution += ComputePointLight(u_PointLights, F0, m_Params, vs_Input.WorldPosition); + + if(u_SpotLightCount > 0) + lightContribution += ComputeSpotLight(u_SpotLights, F0, m_Params, vs_Input.WorldPosition); + vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution; diff --git a/Editor/assets/shaders/PBRShader_Static.glsl b/Editor/assets/shaders/PBRShader_Static.glsl index f1bde27..6aaed4c 100644 --- a/Editor/assets/shaders/PBRShader_Static.glsl +++ b/Editor/assets/shaders/PBRShader_Static.glsl @@ -61,13 +61,33 @@ const float Epsilon = 0.00001; const int LightCount = 1; const vec3 Fdielectric = vec3(0.04); -struct DirectionalLight -{ +struct DirectionalLight { vec3 Direction; vec3 Radiance; - float Multiplier; + 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; +}; + + in VertexOutput { vec3 WorldPosition; @@ -84,6 +104,14 @@ layout(location = 0) out vec4 color; layout(location = 1) out vec4 o_BloomColor; uniform DirectionalLight u_DirectionalLights; + +uniform int u_PointLightCount; +uniform PointLight u_PointLights; + +uniform int u_SpotLightCount; +uniform SpotLight u_SpotLights; + + uniform vec3 u_CameraPosition; // PBR @@ -171,13 +199,102 @@ vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness) } // ---------- direction light ---------- +vec3 ComputeDirectionalLight(DirectionalLight light, vec3 F0, PBRParameters params) +{ + vec3 L = normalize(-light.Direction); + vec3 Lradiance = light.Radiance * light.Intensity; + + vec3 Lh = normalize(L + params.View); + float cosLi = max(0.0, dot(params.Normal, L)); + float cosLh = max(0.0, dot(params.Normal, Lh)); + + vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View))); + float D = ndfGGX(cosLh, params.Roughness); + float G = GeometrySmith(params.Normal, params.View, L, params.Roughness); + + vec3 kd = (1.0 - F) * (1.0 - params.Metalness); + vec3 diffuseBRDF = kd * params.Albedo; + vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV); + + return (diffuseBRDF + specularBRDF) * Lradiance * cosLi; +} + +vec3 ComputePointLight(PointLight light, vec3 F0, PBRParameters params, 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 + params.View); + float cosLi = max(0.0, dot(params.Normal, L)); + float cosLh = max(0.0, dot(params.Normal, Lh)); + + vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View))); + float D = ndfGGX(cosLh, params.Roughness); + float G = GeometrySmith(params.Normal, params.View, L, params.Roughness); + + vec3 kd = (1.0 - F) * (1.0 - params.Metalness); + vec3 diffuseBRDF = kd * params.Albedo; + vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV); + + return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation; +} + +vec3 ComputeSpotLight(SpotLight light, vec3 F0, PBRParameters params, 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)); // 光方向指向外,所以用 -L + 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 + params.View); + float cosLi = max(0.0, dot(params.Normal, L)); + float cosLh = max(0.0, dot(params.Normal, Lh)); + + vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View))); + float D = ndfGGX(cosLh, params.Roughness); + float G = GeometrySmith(params.Normal, params.View, L, params.Roughness); + + vec3 kd = (1.0 - F) * (1.0 - params.Metalness); + vec3 diffuseBRDF = kd * params.Albedo; + vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV); + + return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation; +} + vec3 Lighting(vec3 F0) { vec3 result = vec3(0.0); for(int i = 0; i < LightCount; i++) { vec3 Li = u_DirectionalLights.Direction; - vec3 Lradiance = u_DirectionalLights.Radiance * u_DirectionalLights.Multiplier; + vec3 Lradiance = u_DirectionalLights.Radiance * u_DirectionalLights.Intensity; vec3 Lh = normalize(Li + m_Params.View); float cosLi = max(0.0, dot(m_Params.Normal, Li)); @@ -202,9 +319,9 @@ 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)) + vec3(cos(angle), 0.0, sin(angle)), + vec3(0.0, 1.0, 0.0), + vec3(-sin(angle), 0.0, cos(angle)) ); return rotationMatrix * vec; } @@ -218,9 +335,9 @@ vec3 IBL(vec3 F0, vec3 Lr) int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex); vec3 specularIrradiance = textureLod( - u_EnvRadianceTex, - RotateVectorAboutY(u_EnvMapRotation, Lr), - m_Params.Roughness * u_EnvRadianceTexLevels + u_EnvRadianceTex, + RotateVectorAboutY(u_EnvMapRotation, Lr), + m_Params.Roughness * u_EnvRadianceTexLevels ).rgb; vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg; @@ -314,6 +431,7 @@ void main() vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness); + // Shadow float shadowFactor = 1.0; if (u_ShadowEnabled > 0.5) { float shadow = calculateShadow(vs_Input.FragPosLightSpace, m_Params.Normal, u_DirectionalLights.Direction); @@ -321,7 +439,13 @@ void main() } // directional light with with shadow - vec3 lightContribution = u_DirectionalLights.Multiplier > 0.0 ? Lighting(F0) * shadowFactor : vec3(0.0); + vec3 lightContribution = u_DirectionalLights.Intensity > 0.0 ? Lighting(F0) * shadowFactor : vec3(0.0); + + if(u_PointLightCount > 0) + lightContribution += ComputePointLight(u_PointLights, F0, m_Params, vs_Input.WorldPosition); + + if(u_SpotLightCount > 0) + lightContribution += ComputeSpotLight(u_SpotLights, F0, m_Params, vs_Input.WorldPosition); vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution; diff --git a/Editor/assets/shaders/PreethamSky.glsl b/Editor/assets/shaders/PreethamSky.glsl new file mode 100644 index 0000000..88d637f --- /dev/null +++ b/Editor/assets/shaders/PreethamSky.glsl @@ -0,0 +1,135 @@ +#type compute +#version 450 core + +const float PI = 3.141592; + +layout(binding = 0, rgba32f) restrict writeonly uniform imageCube o_CubeMap; + +uniform vec3 u_TurbidityAzimuthInclination; + +vec3 GetCubeMapTexCoord() +{ + vec2 st = gl_GlobalInvocationID.xy / vec2(imageSize(o_CubeMap)); + vec2 uv = 2.0 * vec2(st.x, 1.0 - st.y) - vec2(1.0); + + vec3 ret; + if (gl_GlobalInvocationID.z == 0) ret = vec3( 1.0, uv.y, -uv.x); + else if (gl_GlobalInvocationID.z == 1) ret = vec3( -1.0, uv.y, uv.x); + else if (gl_GlobalInvocationID.z == 2) ret = vec3( uv.x, 1.0, -uv.y); + else if (gl_GlobalInvocationID.z == 3) ret = vec3( uv.x, -1.0, uv.y); + else if (gl_GlobalInvocationID.z == 4) ret = vec3( uv.x, uv.y, 1.0); + else if (gl_GlobalInvocationID.z == 5) ret = vec3(-uv.x, uv.y, -1.0); + return normalize(ret); +} + +#define PI 3.14159265359 + +float saturatedDot( in vec3 a, in vec3 b ) +{ + return max( dot( a, b ), 0.0 ); +} + +vec3 YxyToXYZ( in vec3 Yxy ) +{ + float Y = Yxy.r; + float x = Yxy.g; + float y = Yxy.b; + + float X = x * ( Y / y ); + float Z = ( 1.0 - x - y ) * ( Y / y ); + + return vec3(X,Y,Z); +} + +vec3 XYZToRGB( in vec3 XYZ ) +{ + // CIE/E + mat3 M = mat3 + ( + 2.3706743, -0.9000405, -0.4706338, + -0.5138850, 1.4253036, 0.0885814, + 0.0052982, -0.0146949, 1.0093968 + ); + + return XYZ * M; +} + + +vec3 YxyToRGB( in vec3 Yxy ) +{ + vec3 XYZ = YxyToXYZ( Yxy ); + vec3 RGB = XYZToRGB( XYZ ); + return RGB; +} + +void calculatePerezDistribution( in float t, out vec3 A, out vec3 B, out vec3 C, out vec3 D, out vec3 E ) +{ + A = vec3( 0.1787 * t - 1.4630, -0.0193 * t - 0.2592, -0.0167 * t - 0.2608 ); + B = vec3( -0.3554 * t + 0.4275, -0.0665 * t + 0.0008, -0.0950 * t + 0.0092 ); + C = vec3( -0.0227 * t + 5.3251, -0.0004 * t + 0.2125, -0.0079 * t + 0.2102 ); + D = vec3( 0.1206 * t - 2.5771, -0.0641 * t - 0.8989, -0.0441 * t - 1.6537 ); + E = vec3( -0.0670 * t + 0.3703, -0.0033 * t + 0.0452, -0.0109 * t + 0.0529 ); +} + +vec3 calculateZenithLuminanceYxy( in float t, in float thetaS ) +{ + float chi = ( 4.0 / 9.0 - t / 120.0 ) * ( PI - 2.0 * thetaS ); + float Yz = ( 4.0453 * t - 4.9710 ) * tan( chi ) - 0.2155 * t + 2.4192; + + float theta2 = thetaS * thetaS; + float theta3 = theta2 * thetaS; + float T = t; + float T2 = t * t; + + float xz = + ( 0.00165 * theta3 - 0.00375 * theta2 + 0.00209 * thetaS + 0.0) * T2 + + (-0.02903 * theta3 + 0.06377 * theta2 - 0.03202 * thetaS + 0.00394) * T + + ( 0.11693 * theta3 - 0.21196 * theta2 + 0.06052 * thetaS + 0.25886); + + float yz = + ( 0.00275 * theta3 - 0.00610 * theta2 + 0.00317 * thetaS + 0.0) * T2 + + (-0.04214 * theta3 + 0.08970 * theta2 - 0.04153 * thetaS + 0.00516) * T + + ( 0.15346 * theta3 - 0.26756 * theta2 + 0.06670 * thetaS + 0.26688); + + return vec3( Yz, xz, yz ); +} + +vec3 calculatePerezLuminanceYxy( in float theta, in float gamma, in vec3 A, in vec3 B, in vec3 C, in vec3 D, in vec3 E ) +{ + return ( 1.0 + A * exp( B / cos( theta ) ) ) * ( 1.0 + C * exp( D * gamma ) + E * cos( gamma ) * cos( gamma ) ); +} + +vec3 calculateSkyLuminanceRGB( in vec3 s, in vec3 e, in float t ) +{ + vec3 A, B, C, D, E; + calculatePerezDistribution( t, A, B, C, D, E ); + + float thetaS = acos( saturatedDot( s, vec3(0,1,0) ) ); + float thetaE = acos( saturatedDot( e, vec3(0,1,0) ) ); + float gammaE = acos( saturatedDot( s, e ) ); + + vec3 Yz = calculateZenithLuminanceYxy( t, thetaS ); + + vec3 fThetaGamma = calculatePerezLuminanceYxy( thetaE, gammaE, A, B, C, D, E ); + vec3 fZeroThetaS = calculatePerezLuminanceYxy( 0.0, thetaS, A, B, C, D, E ); + + vec3 Yp = Yz * ( fThetaGamma / fZeroThetaS ); + + return YxyToRGB( Yp ); +} + +layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in; +void main() +{ + vec3 cubeTC = GetCubeMapTexCoord(); + + float turbidity = u_TurbidityAzimuthInclination.x; + float azimuth = u_TurbidityAzimuthInclination.y;; + float inclination = u_TurbidityAzimuthInclination.z; + vec3 sunDir = normalize( vec3( sin(inclination) * cos(azimuth), cos(inclination), sin(inclination) * sin(azimuth) ) ); + vec3 viewDir = cubeTC; + vec3 skyLuminance = calculateSkyLuminanceRGB( sunDir, viewDir, turbidity ); + + vec4 color = vec4(skyLuminance * 0.05, 1.0); + imageStore(o_CubeMap, ivec3(gl_GlobalInvocationID), color); +} diff --git a/Editor/assets/shaders/ShadowMap.glsl b/Editor/assets/shaders/ShadowMap.glsl index 69352c4..b96ec41 100644 --- a/Editor/assets/shaders/ShadowMap.glsl +++ b/Editor/assets/shaders/ShadowMap.glsl @@ -5,12 +5,12 @@ layout(location = 0) in vec3 a_Position; -uniform mat4 u_ViewProjection; +uniform mat4 u_LightViewProjection; uniform mat4 u_Transform; void main() { - gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0); + gl_Position = u_LightViewProjection * u_Transform * vec4(a_Position, 1.0); } #type fragment diff --git a/Editor/assets/shaders/ShadowMap_Anim.glsl b/Editor/assets/shaders/ShadowMap_Anim.glsl index 0668c62..a190ac2 100644 --- a/Editor/assets/shaders/ShadowMap_Anim.glsl +++ b/Editor/assets/shaders/ShadowMap_Anim.glsl @@ -8,7 +8,7 @@ layout(location = 0) in vec3 a_Position; layout(location = 5) in ivec4 a_BoneIndices; layout(location = 6) in vec4 a_BoneWeights; -uniform mat4 u_ViewProjection; +uniform mat4 u_LightViewProjection; uniform mat4 u_Transform; const int MAX_BONES = 100; @@ -22,7 +22,7 @@ void main() boneTransform += u_BoneTransforms[a_BoneIndices[3]] * a_BoneWeights[3]; vec4 localPosition = boneTransform * vec4(a_Position, 1.0); - gl_Position = u_ViewProjection * u_Transform * localPosition; + gl_Position = u_LightViewProjection * u_Transform * localPosition; } #type fragment diff --git a/Prism/src/Prism/Core/Log.h b/Prism/src/Prism/Core/Log.h index 9e93014..5014805 100644 --- a/Prism/src/Prism/Core/Log.h +++ b/Prism/src/Prism/Core/Log.h @@ -5,6 +5,7 @@ #ifndef LOG_H #define LOG_H +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE #include diff --git a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp index 2569882..63a8eaa 100644 --- a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp +++ b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp @@ -19,6 +19,7 @@ #include "Prism/Physics/PhysicsLayer.h" #include "Prism/Physics/PhysicsWrappers.h" #include "Prism/Renderer/Meshfactory.h" +#include "Prism/Renderer/Renderer3D.h" #include "Prism/Script/ScriptEngine.h" namespace Prism @@ -330,9 +331,19 @@ namespace Prism isCreated = true; SetSelected(newEntity); } + if (ImGui::MenuItem("Point Light")) + { + auto newEntity = m_Context->CreateEntity("Point Light"); + newEntity.AddComponent(); + isCreated = true; + SetSelected(newEntity); + } if (ImGui::MenuItem("Spot Light")) { - PM_CORE_WARN("not impl"); + auto newEntity = m_Context->CreateEntity("Spot Light"); + newEntity.AddComponent(); + isCreated = true; + SetSelected(newEntity); } if (ImGui::MenuItem("Directional Light")) { @@ -671,6 +682,8 @@ namespace Prism ImGui::SeparatorText("Light Component"); AddComponentPopup("Directional Light"); AddComponentPopup("sky Light"); + AddComponentPopup("Point Light"); + AddComponentPopup("Spot Light"); ImGui::SeparatorText("Other Component"); AddComponentPopup("Camera"); @@ -991,12 +1004,51 @@ namespace Prism UI::EndPropertyGrid(); }); + DrawComponent("Point Light", entity, [](PointLightComponent& pc) + { + UI::BeginPropertyGrid(); + + UI::PropertyColor("Radiance", pc.Radiance); + UI::Property("Intensity", pc.Intensity); + UI::Property("Radius", pc.Radius); + + UI::EndPropertyGrid(); + }); + + DrawComponent("Spot Light", entity, [](SpotLightComponent& sc) + { + UI::BeginPropertyGrid(); + + UI::PropertyColor("Radiance", sc.Radiance); + UI::Property("Intensity", sc.Intensity); + UI::Property("Range", sc.Range); + UI::Property("InnerConeAngle", sc.InnerConeAngle); + UI::Property("OuterConeAngle", sc.OuterConeAngle); + + UI::EndPropertyGrid(); + }); + DrawComponent("Sky Light", entity, [](SkyLightComponent& slc) { UI::BeginPropertyGrid(); UI::PropertyAssetReference("Environment Map", slc.SceneEnvironment, AssetType::EnvMap); UI::Property("Intensity", slc.Intensity, 0.01f, 0.0f, 5.0f); + + ImGui::Separator(); + const bool isEnable = UI::Property("Dynamic Sky", slc.DynamicSky); + if (slc.DynamicSky) + { + bool changed = UI::Property("Turbidity", slc.TurbidityAzimuthInclination.x, 0.01f); + changed |= UI::Property("Azimuth", slc.TurbidityAzimuthInclination.y, 0.01f); + changed |= UI::Property("Inclination", slc.TurbidityAzimuthInclination.z, 0.01f); + if (changed || isEnable) + { + Ref preethamEnv = Renderer3D::CreatePreethamSky(slc.TurbidityAzimuthInclination.x, slc.TurbidityAzimuthInclination.y, slc.TurbidityAzimuthInclination.z); + slc.SceneEnvironment = Ref::Create(preethamEnv, preethamEnv); + } + } + UI::EndPropertyGrid(); }); diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp index b9051ac..4f8200e 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp @@ -22,6 +22,33 @@ namespace Prism return 0; } + static GLenum SizedInternalFormat(TextureFormat format) { + switch (format) { + case TextureFormat::RGB: return GL_RGB8; + case TextureFormat::RGBA: return GL_RGBA8; + case TextureFormat::Float16: return GL_RGBA16F; + default: return 0; + } + } + + static GLenum ImageFormat(TextureFormat format) { + switch (format) { + case TextureFormat::RGB: return GL_RGB; + case TextureFormat::RGBA: return GL_RGBA; + case TextureFormat::Float16: return GL_RGBA; // 根据实际情况调整 + default: return 0; + } + } + + static GLenum DataType(TextureFormat format) { + switch (format) { + case TextureFormat::RGB: + case TextureFormat::RGBA: return GL_UNSIGNED_BYTE; + case TextureFormat::Float16: return GL_HALF_FLOAT; + default: return 0; + } + } + // ****************************************** // Texture2D @@ -169,22 +196,41 @@ namespace Prism // TextureCube // ****************************************** - OpenGLTextureCube::OpenGLTextureCube(TextureFormat format, uint32_t width, uint32_t height) + OpenGLTextureCube::OpenGLTextureCube(TextureFormat format, uint32_t width, uint32_t height, const void* data) { m_Width = width; m_Height = height; m_Format = format; + if (data) + { + const uint32_t size = width * height * 4 * 6; // six layers + m_LocalStorage = Buffer::Copy(data, size); + } + const GLint levels = CalculateMipMapCount(width, height); Ref instance = this; Renderer::Submit([instance, levels]() mutable { glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &instance->m_RendererID); - glTextureStorage2D(instance->m_RendererID, levels, PrismToOpenGLTextureFormat(instance->m_Format), instance->m_Width, instance->m_Height); + glTextureStorage2D(instance->m_RendererID, levels, + SizedInternalFormat(instance->m_Format), + instance->m_Width, instance->m_Height); + + if (instance->m_LocalStorage.Data) + { + GLenum imgFormat = ImageFormat(instance->m_Format); + GLenum dataType = DataType(instance->m_Format); + glTextureSubImage3D(instance->m_RendererID, 0, + 0, 0, 0, + instance->m_Width, instance->m_Height, 6, + imgFormat, dataType, instance->m_LocalStorage.Data); + + } glTextureParameteri(instance->m_RendererID, GL_TEXTURE_MIN_FILTER, levels > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); glTextureParameteri(instance->m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_REPEAT); }); } diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h index 5187ec6..4ef9647 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h @@ -58,10 +58,13 @@ namespace Prism std::string m_FilePath; }; + + + class OpenGLTextureCube : public TextureCube { public: - OpenGLTextureCube(TextureFormat format, uint32_t width, uint32_t height); + OpenGLTextureCube(TextureFormat format, uint32_t width, uint32_t height, const void* data); OpenGLTextureCube(const std::string& path); virtual ~OpenGLTextureCube(); @@ -90,6 +93,7 @@ namespace Prism uint8_t* m_ImageData = nullptr; std::string m_FilePath; + Buffer m_LocalStorage; }; } diff --git a/Prism/src/Prism/Renderer/Renderer3D.cpp b/Prism/src/Prism/Renderer/Renderer3D.cpp index 35c9d6a..f233276 100644 --- a/Prism/src/Prism/Renderer/Renderer3D.cpp +++ b/Prism/src/Prism/Renderer/Renderer3D.cpp @@ -27,7 +27,6 @@ namespace Prism // Resources Ref SkyboxMaterial; Ref SceneEnvironment; - Light ActiveLight; } SceneData; Ref BRDFLUT; @@ -124,6 +123,8 @@ namespace Prism }GridData; SceneRendererOptions Options; + + Ref BlackCubeTexture; }; struct Renderer3DStats @@ -259,6 +260,10 @@ namespace Prism s_Data.ShadowMapShader = Shader::Create("assets/shaders/ShadowMap.glsl"); s_Data.ShadowMapAnimShader = Shader::Create("assets/shaders/ShadowMap_Anim.glsl"); + + + uint32_t blackTextureData[6] = { 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000 }; + s_Data.BlackCubeTexture = TextureCube::Create(TextureFormat::RGBA, 1, 1, &blackTextureData); } void Renderer3D::SetViewportSize(uint32_t width, uint32_t height) @@ -385,6 +390,34 @@ namespace Prism return { envFiltered, irradianceMap }; } + + static Ref preethamSkyShader; + + Ref Renderer3D::CreatePreethamSky(float turbidity, float azimuth, float inclination) + { + constexpr uint32_t cubemapSize = 2048; + + Ref environmentMap = TextureCube::Create(TextureFormat::Float16, cubemapSize, cubemapSize); + + if (!preethamSkyShader) + preethamSkyShader = Shader::Create("assets/shaders/PreethamSky.glsl"); + + preethamSkyShader->Bind(); + + const glm::vec3 TurbidityAzimuthInclination = { turbidity, azimuth, inclination}; + preethamSkyShader->SetFloat3("u_TurbidityAzimuthInclination", TurbidityAzimuthInclination); + + Renderer::Submit([environmentMap, cubemapSize]() + { + glBindImageTexture(0, environmentMap->GetRendererID(), 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA16F); + glDispatchCompute(cubemapSize / 32, cubemapSize / 32, 6); + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + glGenerateTextureMipmap(environmentMap->GetRendererID()); + }); + + return environmentMap; + } + /* Ref Renderer3D::GetFinalRenderPass() { @@ -420,6 +453,11 @@ namespace Prism return s_Data.Options; } + Ref Renderer3D::GetBlackCubeTexture() + { + return s_Data.BlackCubeTexture; + } + void Renderer3D::FlushDrawList(Ref& outRenderPass) { @@ -550,6 +588,11 @@ namespace Prism // Set lights (TODO: move to light environment and don't do per mesh) baseMaterial->Set("u_DirectionalLights", s_Data.SceneData.SceneLightEnvironment.DirectionalLights[0]); + baseMaterial->Set("u_PointLightCount", s_Data.SceneData.SceneLightEnvironment.PointLightCount); + baseMaterial->Set("u_PointLights", s_Data.SceneData.SceneLightEnvironment.PointLights[0]); + + baseMaterial->Set("u_SpotLightCount", s_Data.SceneData.SceneLightEnvironment.SpotLightCount); + baseMaterial->Set("u_SpotLights", s_Data.SceneData.SceneLightEnvironment.SpotLights[0]); // baseMaterial->Set("u_DirectionalLights", s_Data.SceneData.ActiveLight); // shadow @@ -642,6 +685,10 @@ namespace Prism // Set lights (TODO: move to light environment and don't do per mesh) baseMaterial->Set("u_DirectionalLights", s_Data.SceneData.SceneLightEnvironment.DirectionalLights[0]); + baseMaterial->Set("u_PointLightCount", s_Data.SceneData.SceneLightEnvironment.PointLightCount); + baseMaterial->Set("u_PointLights", s_Data.SceneData.SceneLightEnvironment.PointLights[0]); + baseMaterial->Set("u_SpotLightCount", s_Data.SceneData.SceneLightEnvironment.SpotLightCount); + baseMaterial->Set("u_SpotLights", s_Data.SceneData.SceneLightEnvironment.SpotLights[0]); // baseMaterial->Set("u_DirectionalLights", s_Data.SceneData.ActiveLight); @@ -881,59 +928,6 @@ namespace Prism }); } - /* - void Renderer3D::BloomBlurPass() - { - int amount = 10; - int index = 0; - - int horizontalCounter = 0, verticalCounter = 0; - for (int i = 0; i < amount; i++) - { - index = i % 2; - Renderer::BeginRenderPass(s_Data.BloomBlurPass[index]); - s_Data.BloomBlurShader->Bind(); - s_Data.BloomBlurShader->SetBool("u_Horizontal", index); - if (index) - horizontalCounter++; - else - verticalCounter++; - if (i > 0) - { - auto fb = s_Data.BloomBlurPass[1 - index]->GetSpecification().TargetFramebuffer; - fb->BindTexture(); - } - else - { - auto fb = s_Data.CompositePass->GetSpecification().TargetFramebuffer; - auto id = fb->GetColorAttachmentRendererID(1); - Renderer::Submit([id]() - { - glBindTextureUnit(0, id); - }); - } - Renderer::SubmitFullscreenQuad(nullptr); - Renderer::EndRenderPass(); - } - - // Composite bloom - { - Renderer::BeginRenderPass(s_Data.BloomBlendPass); - s_Data.BloomBlendShader->Bind(); - auto & adad =s_Data; - // s_Data.BloomBlendShader->SetFloat("u_Exposure", s_Data.SceneData.SceneCamera.Camera.GetExposure()); - s_Data.CompositeShader->SetFloat("u_Exposure", s_Data.AutoExposureData.EnableAutoExposure ? s_Data.AutoExposureData.CurrentExposure : s_Data.SceneData.SceneCamera.Camera.GetExposure()); - s_Data.BloomBlendShader->SetBool("u_EnableBloom", s_Data.EnableBloom); - - s_Data.CompositePass->GetSpecification().TargetFramebuffer->BindTexture(0); - s_Data.BloomBlurPass[index]->GetSpecification().TargetFramebuffer->BindTexture(1); - - Renderer::SubmitFullscreenQuad(nullptr); - Renderer::EndRenderPass(); - } - } - */ - /* struct FrustumBounds { @@ -1066,11 +1060,34 @@ namespace Prism } } */ + std::vector GetFrustumCornersWorldSpace(const SceneRendererCamera& sceneCamera) + { + std::vector corners(8); + const auto& proj = sceneCamera.Camera.GetProjectionMatrix(); + const auto& view = sceneCamera.ViewMatrix; + const glm::mat4 invViewProj = glm::inverse(proj * view); + + // 视锥体在 NDC 空间中的八个点 + const std::vector ndcCorners = { + glm::vec4(-1, -1, -1, 1), glm::vec4( 1, -1, -1, 1), + glm::vec4( 1, 1, -1, 1), glm::vec4(-1, 1, -1, 1), + glm::vec4(-1, -1, 1, 1), glm::vec4( 1, -1, 1, 1), + glm::vec4( 1, 1, 1, 1), glm::vec4(-1, 1, 1, 1) + }; + + for (size_t i = 0; i < 8; ++i) + { + glm::vec4 worldPos = invViewProj * ndcCorners[i]; + worldPos /= worldPos.w; + corners[i] = glm::vec3(worldPos); + } + return corners; + } void Renderer3D::ShadowMapPass() { const auto& directionalLights = s_Data.SceneData.SceneLightEnvironment.DirectionalLights; - if (directionalLights[0].Multiplier == 0.0f || !directionalLights[0].CastShadows) + if (directionalLights[0].Intensity == 0.0f || !directionalLights[0].CastShadows) { for (int i = 0; i < 4; i++) { @@ -1083,14 +1100,13 @@ namespace Prism // TODO: this will not be hardcode const glm::vec3 lightDir = glm::normalize(directionalLights[0].Direction); // 光线方向(从光源指向场景) - glm::vec3 lightPos = lightDir * 100.0f; + 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)); - glm::mat4 lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); - - float orthoSize = 100.0f; - float nearPlane = 0.01f, farPlane = 1000.0f; - glm::mat4 lightProjection = glm::ortho(-orthoSize, orthoSize, -orthoSize, orthoSize, nearPlane, farPlane); - glm::mat4 lightSpaceMatrix = lightProjection * lightView; + 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([]() { @@ -1108,7 +1124,7 @@ namespace Prism for (auto& dc : s_Data.ShadowPassDrawList) { Ref shader = dc.mesh->IsAnimated() ? s_Data.ShadowMapAnimShader : s_Data.ShadowMapShader; - shader->SetMat4("u_ViewProjection", lightSpaceMatrix); + shader->SetMat4("u_LightViewProjection", lightSpaceMatrix); Renderer::SubmitMeshWithShader(dc.mesh, dc.Transform, shader); } @@ -1120,6 +1136,7 @@ namespace Prism { ImGui::Begin("Scene Renderer"); + UI::Property("Composite Pass time", s_Stats.CompositePass); UI::Property("Geometry Pass time", s_Stats.GeometryPass); UI::Property("Shadow Pass time", s_Stats.ShadowPass); diff --git a/Prism/src/Prism/Renderer/Renderer3D.h b/Prism/src/Prism/Renderer/Renderer3D.h index df42859..42cf05f 100644 --- a/Prism/src/Prism/Renderer/Renderer3D.h +++ b/Prism/src/Prism/Renderer/Renderer3D.h @@ -41,6 +41,7 @@ namespace Prism static void SubmitColliderMesh(const CapsuleColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); static void SubmitColliderMesh(const MeshColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); static std::pair, Ref> CreateEnvironmentMap(const std::string& filepath); + static Ref CreatePreethamSky(float turbidity, float azimuth, float inclination); // static Ref GetFinalRenderPass(); static Ref GetGeoPass(); @@ -52,6 +53,7 @@ namespace Prism // static uint32_t GetFinalColorBufferRendererID(); static SceneRendererOptions& GetOptions(); + static Ref GetBlackCubeTexture(); private: static void FlushDrawList(Ref& outRenderPass); diff --git a/Prism/src/Prism/Renderer/Texture.cpp b/Prism/src/Prism/Renderer/Texture.cpp index 2c883e0..9affbae 100644 --- a/Prism/src/Prism/Renderer/Texture.cpp +++ b/Prism/src/Prism/Renderer/Texture.cpp @@ -49,12 +49,12 @@ namespace Prism return nullptr; } - Ref TextureCube::Create(TextureFormat format, uint32_t width, uint32_t height) + Ref TextureCube::Create(TextureFormat format, uint32_t width, uint32_t height, const void* data) { switch (RendererAPI::Current()) { case RendererAPIType::None: return nullptr; - case RendererAPIType::OpenGL: return Ref::Create(format, width, height); + case RendererAPIType::OpenGL: return Ref::Create(format, width, height, data); } return nullptr; } diff --git a/Prism/src/Prism/Renderer/Texture.h b/Prism/src/Prism/Renderer/Texture.h index 53a4293..1339e51 100644 --- a/Prism/src/Prism/Renderer/Texture.h +++ b/Prism/src/Prism/Renderer/Texture.h @@ -72,7 +72,7 @@ namespace Prism class PRISM_API TextureCube : public Texture { public: - static Ref Create(TextureFormat format, uint32_t width, uint32_t height); + static Ref Create(TextureFormat format, uint32_t width, uint32_t height, const void* data = nullptr); static Ref Create(const std::string& path); virtual const std::string& GetPath() const = 0; diff --git a/Prism/src/Prism/Scene/Components.h b/Prism/src/Prism/Scene/Components.h index 55a3cc6..df13f3b 100644 --- a/Prism/src/Prism/Scene/Components.h +++ b/Prism/src/Prism/Scene/Components.h @@ -366,13 +366,6 @@ namespace Prism }; // Lights - - // TODO: Move to renderer - enum class LightType - { - None = 0, Directional = 1, Point = 2, Spot = 3 - }; - struct DirectionalLightComponent { glm::vec3 Radiance = { 1.0f, 1.0f, 1.0f }; @@ -382,20 +375,45 @@ namespace Prism float LightSize = 0.5f; // For PCSS }; + struct PointLightComponent + { + glm::vec3 Radiance = {1.0f, 1.0f, 1.0f}; + float Radius = 10.0f; + float Intensity = 1.0f; + uint32_t CastShadows; + + PointLightComponent() = default; + PointLightComponent(const PointLightComponent& other) = default; + }; + + // 聚光灯光源组件 + struct SpotLightComponent + { + glm::vec3 Radiance = {1.0f, 1.0f, 1.0f}; + float Intensity = 1.0f; + float Range = 10.0f; + float InnerConeAngle = glm::radians(30.0f); // 内锥角(半角) + float OuterConeAngle = glm::radians(45.0f); // 外锥角(半角) + bool CastShadows = true; // 聚光通常需要阴影 + + SpotLightComponent() = default; + SpotLightComponent(const SpotLightComponent& other) = default; + }; + struct SkyLightComponent { Ref SceneEnvironment; float Intensity = 1.0f; float Angle = 0.0f; + bool DynamicSky = false; + glm::vec3 TurbidityAzimuthInclination = { 2.0, 0.0, 0.0 }; + SkyLightComponent(const Ref& environment) : SceneEnvironment(environment) { } - SkyLightComponent() - : SceneEnvironment(Ref::Create()) - { - } + SkyLightComponent() = default; }; template diff --git a/Prism/src/Prism/Scene/Scene.cpp b/Prism/src/Prism/Scene/Scene.cpp index 28a5590..1057960 100644 --- a/Prism/src/Prism/Scene/Scene.cpp +++ b/Prism/src/Prism/Scene/Scene.cpp @@ -23,6 +23,7 @@ #include "Prism/Core/Math/Math.h" #include "Prism/Physics/Physics2D.h" #include "Prism/Renderer/Renderer.h" +#include "Prism/Renderer/Renderer3D.h" namespace Prism { @@ -176,7 +177,7 @@ namespace Prism for (const auto entity : lights) { auto [transformComponent, lightComponent] = lights.get(entity); - const glm::vec3 direction = -glm::normalize(glm::mat3(transformComponent.GetTransform()) * glm::vec3(1.0f)); + const glm::vec3 direction = -glm::normalize(glm::mat3(transformComponent.GetTransform()) * glm::vec3(0.0f, 0.0f, -1.0f)); m_LightEnvironment.DirectionalLights[directionalLightIndex++] = { direction, @@ -253,13 +254,12 @@ namespace Prism // Process lights { - m_LightEnvironment = LightEnvironment(); const auto lights = m_Registry.group(entt::get); uint32_t directionalLightIndex = 0; for (const auto entity : lights) { auto [transformComponent, lightComponent] = lights.get(entity); - const glm::vec3 direction = -glm::normalize(glm::mat3(transformComponent.GetTransform()) * glm::vec3(1.0f)); + const glm::vec3 direction = glm::normalize(glm::mat3(transformComponent.GetTransform()) * glm::vec3(0.0f, 0.0f,1.0f)); m_LightEnvironment.DirectionalLights[directionalLightIndex++] = { direction, @@ -270,17 +270,69 @@ namespace Prism } } + { + const auto pointLights = m_Registry.group(entt::get); + uint32_t pointLightIndex = 0; + for (const auto entity : pointLights) + { + if (pointLightIndex >= 8) break; + auto [transform, light] = pointLights.get(entity); + m_LightEnvironment.PointLights[pointLightIndex++] = { + transform.Translation, + light.Radiance, + light.Radius, + light.Intensity, + light.CastShadows, + }; + + m_LightEnvironment.PointLightCount ++; + } + } + + { + const auto spotLights = m_Registry.group(entt::get); + uint32_t pointLightIndex = 0; + for (const auto entity : spotLights) + { + if (pointLightIndex >= 8) break; + auto [transform, light] = spotLights.get(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! { const auto lights = m_Registry.group(entt::get); + if (lights.empty()) + m_Environment = Ref::Create(Renderer3D::GetBlackCubeTexture(), Renderer3D::GetBlackCubeTexture()); if (!lights.empty()) { for (const auto entity : lights) { auto [transformComponent, skyLightComponent] = lights.get(entity); + if (!skyLightComponent.SceneEnvironment && skyLightComponent.DynamicSky) + { + Ref preethamEnv = Renderer3D::CreatePreethamSky(skyLightComponent.TurbidityAzimuthInclination.x, skyLightComponent.TurbidityAzimuthInclination.y, skyLightComponent.TurbidityAzimuthInclination.z); + skyLightComponent.SceneEnvironment = Ref::Create(preethamEnv, preethamEnv); + } + m_Environment = skyLightComponent.SceneEnvironment; m_EnvironmentIntensity = skyLightComponent.Intensity; - SetSkybox(m_Environment->RadianceMap); + if (m_Environment) + SetSkybox(m_Environment->RadianceMap); } } } diff --git a/Prism/src/Prism/Scene/Scene.h b/Prism/src/Prism/Scene/Scene.h index 8e642f3..1d068dd 100644 --- a/Prism/src/Prism/Scene/Scene.h +++ b/Prism/src/Prism/Scene/Scene.h @@ -18,27 +18,47 @@ namespace Prism { - struct Light - { - glm::vec3 Direction{-0.314f, -0.941f, -0.209f}; - glm::vec3 Radiance{ 0.0f, 0.0f, 0.0f}; - - float Multiplier = 1.0f; - }; - - struct DirectionalLight + struct GPUDirectionalLight { glm::vec3 Direction = { 0.0f, 0.0f, 0.0f }; glm::vec3 Radiance = { 0.0f, 0.0f, 0.0f }; - float Multiplier = 0.0f; + float Intensity = 0.0f; // C++ only bool CastShadows = true; }; + struct GPUPointLight + { + glm::vec3 Position; + glm::vec3 Radiance; + float Intensity; + float Radius; + uint32_t CastShadows; + }; + + struct GPUSpotLight { + glm::vec3 Position; + glm::vec3 Direction; + glm::vec3 Radiance; + float Intensity; + float Range; + float InnerConeCos; + float OuterConeCos; + bool CastShadows; + // mat4 LightSpaceMatrix; + // int ShadowMapIndex; + }; + struct LightEnvironment { - DirectionalLight DirectionalLights[4]; + GPUDirectionalLight DirectionalLights[4]; + + GPUPointLight PointLights[8]{}; + int PointLightCount = 0; + + GPUSpotLight SpotLights[8]{}; + int SpotLightCount = 0; }; @@ -136,7 +156,7 @@ namespace Prism Entity* m_Physics2DBodyEntityBuffer = nullptr; Entity* m_Physics3DBodyEntityBuffer = nullptr; - LightEnvironment m_LightEnvironment; + LightEnvironment m_LightEnvironment{}; bool m_IsPlaying = false; diff --git a/Prism/src/Prism/Scene/SceneCamera.h b/Prism/src/Prism/Scene/SceneCamera.h index 50e5a7b..9c79654 100644 --- a/Prism/src/Prism/Scene/SceneCamera.h +++ b/Prism/src/Prism/Scene/SceneCamera.h @@ -18,7 +18,7 @@ namespace Prism virtual ~SceneCamera(); - void SetPerspective(float verticalFOV, float nearClip = 0.01f, float farClip = 10000.0f); + void SetPerspective(float verticalFOV, float nearClip = 0.01f, float farClip = 1000.0f); void SetOrthographic(float size, float nearClip = -1.0f, float farClip = 1.0f); void SetViewportSize(uint32_t width, uint32_t height);