ADD: multi light system
This commit is contained in:
@@ -10,10 +10,10 @@ Current structure:
|
||||
- GLTF loading and rendering, primitive creation and rendering.
|
||||
- Supports texture compression(BCn, non glTF standard), LRU reload
|
||||
- Object clicking, generation.
|
||||
- Multi light system
|
||||
|
||||
Work-In-Progress
|
||||
- [ ] TAA
|
||||
- [ ] Multiple light
|
||||
- [ ] SSR
|
||||
- [ ] bloom
|
||||
- [ ] Planet Rendering
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#extension GL_EXT_ray_query : require
|
||||
#include "input_structures.glsl"
|
||||
#include "ibl_common.glsl"
|
||||
#include "lighting_common.glsl"
|
||||
|
||||
layout(location=0) in vec2 inUV;
|
||||
layout(location=0) out vec4 outColor;
|
||||
@@ -33,8 +34,6 @@ const float SHADOW_MIN_BIAS = 1e-5;
|
||||
const float SHADOW_RAY_TMIN = 0.02;// start a bit away from the surface
|
||||
const float SHADOW_RAY_ORIGIN_BIAS = 0.01;// world units
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
float hash12(vec2 p)
|
||||
{
|
||||
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
||||
@@ -263,41 +262,6 @@ float calcShadowVisibility(vec3 worldPos, vec3 N, vec3 L)
|
||||
return vis;
|
||||
}
|
||||
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
|
||||
float num = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return num / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
return NdotV / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float ggx2 = GeometrySchlickGGX(max(dot(N, V), 0.0), roughness);
|
||||
float ggx1 = GeometrySchlickGGX(max(dot(N, L), 0.0), roughness);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
void main(){
|
||||
vec4 posSample = texture(posTex, inUV);
|
||||
if (posSample.w == 0.0)
|
||||
@@ -317,28 +281,53 @@ void main(){
|
||||
|
||||
vec3 camPos = vec3(inverse(sceneData.view)[3]);
|
||||
vec3 V = normalize(camPos - pos);
|
||||
vec3 L = normalize(-sceneData.sunlightDirection.xyz);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
// Directional sun term using evaluate_brdf + cascaded shadowing
|
||||
vec3 Lsun = normalize(-sceneData.sunlightDirection.xyz);
|
||||
float sunVis = calcShadowVisibility(pos, N, Lsun);
|
||||
vec3 sunBRDF = evaluate_brdf(N, V, Lsun, albedo, roughness, metallic);
|
||||
vec3 direct = sunBRDF * sceneData.sunlightColor.rgb * sceneData.sunlightColor.a * sunVis;
|
||||
|
||||
vec3 numerator = NDF * G * F;
|
||||
float denom = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
|
||||
vec3 specular = numerator / max(denom, 0.001);
|
||||
// Punctual point lights
|
||||
uint pointCount = sceneData.lightCounts.x;
|
||||
for (uint i = 0u; i < pointCount; ++i)
|
||||
{
|
||||
vec3 contrib = eval_point_light(sceneData.punctualLights[i], pos, N, V, albedo, roughness, metallic);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = (1.0 - kS) * (1.0 - metallic);
|
||||
// Optional RT shadow for the first few point lights (hybrid mode)
|
||||
#ifdef GL_EXT_ray_query
|
||||
if (sceneData.rtOptions.x == 1u && i < 4u)
|
||||
{
|
||||
vec3 toL = sceneData.punctualLights[i].position_radius.xyz - pos;
|
||||
float maxT = length(toL);
|
||||
if (maxT > 0.01)
|
||||
{
|
||||
vec3 dir = toL / maxT;
|
||||
vec3 origin = pos + N * SHADOW_RAY_ORIGIN_BIAS;
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
// Shadowing (directional, forward-Z shadow map)
|
||||
float visibility = calcShadowVisibility(pos, N, L);
|
||||
rayQueryEXT rq;
|
||||
rayQueryInitializeEXT(
|
||||
rq,
|
||||
topLevelAS,
|
||||
gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT,
|
||||
0xFF,
|
||||
origin,
|
||||
SHADOW_RAY_TMIN,
|
||||
dir,
|
||||
maxT
|
||||
);
|
||||
while (rayQueryProceedEXT(rq)) { }
|
||||
bool hit = (rayQueryGetIntersectionTypeEXT(rq, true) != gl_RayQueryCommittedIntersectionNoneEXT);
|
||||
if (hit)
|
||||
{
|
||||
contrib = vec3(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 irradiance = sceneData.sunlightColor.rgb * sceneData.sunlightColor.a * NdotL * visibility;
|
||||
|
||||
vec3 color = (kD * albedo / PI + specular) * irradiance;
|
||||
direct += contrib;
|
||||
}
|
||||
|
||||
// Image-Based Lighting: split-sum approximation
|
||||
vec3 R = reflect(-V, N);
|
||||
@@ -347,9 +336,11 @@ void main(){
|
||||
vec2 uv = dir_to_equirect(R);
|
||||
vec3 prefiltered = textureLod(iblSpec2D, uv, lod).rgb;
|
||||
vec2 brdf = texture(iblBRDF, vec2(max(dot(N, V), 0.0), roughness)).rg;
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
vec3 specIBL = prefiltered * (F0 * brdf.x + brdf.y);
|
||||
vec3 diffIBL = (1.0 - metallic) * albedo * sh_eval_irradiance(N);
|
||||
color += diffIBL + specIBL;
|
||||
|
||||
vec3 color = direct + diffIBL + specIBL;
|
||||
|
||||
outColor = vec4(color, 1.0);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
#include "input_structures.glsl"
|
||||
#include "ibl_common.glsl"
|
||||
#include "lighting_common.glsl"
|
||||
|
||||
layout(location=0) in vec2 inUV;
|
||||
layout(location=0) out vec4 outColor;
|
||||
@@ -25,8 +26,6 @@ const float SHADOW_RPDB_SCALE = 1.0;
|
||||
// Minimum clamp to keep a tiny bias even on perpendicular receivers
|
||||
const float SHADOW_MIN_BIAS = 1e-5;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
float hash12(vec2 p)
|
||||
{
|
||||
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
||||
@@ -192,41 +191,6 @@ float calcShadowVisibility(vec3 worldPos, vec3 N, vec3 L)
|
||||
return mix(v0, v1, clamp(cm.w1, 0.0, 1.0));
|
||||
}
|
||||
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
|
||||
float num = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return num / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
return NdotV / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float ggx2 = GeometrySchlickGGX(max(dot(N, V), 0.0), roughness);
|
||||
float ggx1 = GeometrySchlickGGX(max(dot(N, L), 0.0), roughness);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
void main(){
|
||||
vec4 posSample = texture(posTex, inUV);
|
||||
if (posSample.w == 0.0)
|
||||
@@ -246,28 +210,19 @@ void main(){
|
||||
|
||||
vec3 camPos = vec3(inverse(sceneData.view)[3]);
|
||||
vec3 V = normalize(camPos - pos);
|
||||
vec3 L = normalize(-sceneData.sunlightDirection.xyz);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
// Directional sun term using evaluate_brdf + cascaded shadowing
|
||||
vec3 Lsun = normalize(-sceneData.sunlightDirection.xyz);
|
||||
float sunVis = calcShadowVisibility(pos, N, Lsun);
|
||||
vec3 sunBRDF = evaluate_brdf(N, V, Lsun, albedo, roughness, metallic);
|
||||
vec3 direct = sunBRDF * sceneData.sunlightColor.rgb * sceneData.sunlightColor.a * sunVis;
|
||||
|
||||
vec3 numerator = NDF * G * F;
|
||||
float denom = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
|
||||
vec3 specular = numerator / max(denom, 0.001);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = (1.0 - kS) * (1.0 - metallic);
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
// Shadowing (directional, forward-Z shadow map)
|
||||
float visibility = calcShadowVisibility(pos, N, L);
|
||||
|
||||
vec3 irradiance = sceneData.sunlightColor.rgb * sceneData.sunlightColor.a * NdotL * visibility;
|
||||
|
||||
vec3 color = (kD * albedo / PI + specular) * irradiance;
|
||||
// Punctual point lights
|
||||
uint pointCount = sceneData.lightCounts.x;
|
||||
for (uint i = 0u; i < pointCount; ++i)
|
||||
{
|
||||
direct += eval_point_light(sceneData.punctualLights[i], pos, N, V, albedo, roughness, metallic);
|
||||
}
|
||||
|
||||
// Image-Based Lighting: split-sum approximation
|
||||
vec3 R = reflect(-V, N);
|
||||
@@ -276,9 +231,11 @@ void main(){
|
||||
vec2 uv = dir_to_equirect(R);
|
||||
vec3 prefiltered = textureLod(iblSpec2D, uv, lod).rgb;
|
||||
vec2 brdf = texture(iblBRDF, vec2(max(dot(N, V), 0.0), roughness)).rg;
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
vec3 specIBL = prefiltered * (F0 * brdf.x + brdf.y);
|
||||
vec3 diffIBL = (1.0 - metallic) * albedo * sh_eval_irradiance(N);
|
||||
color += diffIBL + specIBL;
|
||||
|
||||
vec3 color = direct + diffIBL + specIBL;
|
||||
|
||||
outColor = vec4(color, 1.0);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
// Maximum number of shadow cascades supported in shaders
|
||||
#define MAX_CASCADES 4
|
||||
// Maximum number of punctual (point) lights
|
||||
#define MAX_PUNCTUAL_LIGHTS 64
|
||||
|
||||
struct GPUPunctualLight {
|
||||
vec4 position_radius;
|
||||
vec4 color_intensity;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 0) uniform SceneData{
|
||||
|
||||
@@ -22,6 +29,9 @@ layout(set = 0, binding = 0) uniform SceneData{
|
||||
uvec4 rtOptions;
|
||||
// rtParams.x = N·L threshold; others reserved
|
||||
vec4 rtParams;
|
||||
|
||||
GPUPunctualLight punctualLights[MAX_PUNCTUAL_LIGHTS];
|
||||
uvec4 lightCounts;
|
||||
} sceneData;
|
||||
|
||||
layout(set = 1, binding = 0) uniform GLTFMaterialData{
|
||||
|
||||
86
shaders/lighting_common.glsl
Normal file
86
shaders/lighting_common.glsl
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef LIGHTING_COMMON_GLSL
|
||||
#define LIGHTING_COMMON_GLSL
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
|
||||
float num = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return num / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
return NdotV / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float ggx2 = GeometrySchlickGGX(max(dot(N, V), 0.0), roughness);
|
||||
float ggx1 = GeometrySchlickGGX(max(dot(N, L), 0.0), roughness);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
vec3 evaluate_brdf(vec3 N, vec3 V, vec3 L, vec3 albedo, float roughness, float metallic)
|
||||
{
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
|
||||
vec3 numerator = NDF * G * F;
|
||||
float denom = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
|
||||
vec3 specular = numerator / max(denom, 0.001);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = (1.0 - kS) * (1.0 - metallic);
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
return (kD * albedo / PI + specular) * NdotL;
|
||||
}
|
||||
|
||||
vec3 eval_point_light(GPUPunctualLight light, vec3 pos, vec3 N, vec3 V, vec3 albedo, float roughness, float metallic)
|
||||
{
|
||||
vec3 lightPos = light.position_radius.xyz;
|
||||
float radius = max(light.position_radius.w, 0.0001);
|
||||
vec3 L = lightPos - pos;
|
||||
float dist = length(L);
|
||||
if (dist <= 0.0001)
|
||||
{
|
||||
return vec3(0.0);
|
||||
}
|
||||
L /= dist;
|
||||
|
||||
// Smooth falloff: inverse-square with soft clamp at radius
|
||||
float att = 1.0 / max(dist * dist, 0.0001);
|
||||
float x = clamp(dist / radius, 0.0, 1.0);
|
||||
float smth = (1.0 - x * x);
|
||||
smth *= smth;
|
||||
float falloff = att * smth;
|
||||
|
||||
vec3 brdf = evaluate_brdf(N, V, L, albedo, roughness, metallic);
|
||||
vec3 lightColor = light.color_intensity.rgb * light.color_intensity.a;
|
||||
return brdf * lightColor * falloff;
|
||||
}
|
||||
|
||||
#endif // LIGHTING_COMMON_GLSL
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
#include "input_structures.glsl"
|
||||
#include "ibl_common.glsl"
|
||||
#include "lighting_common.glsl"
|
||||
|
||||
layout (location = 0) in vec3 inNormal;
|
||||
layout (location = 1) in vec3 inColor;
|
||||
@@ -12,43 +13,6 @@ layout (location = 4) in vec4 inTangent;
|
||||
|
||||
layout (location = 0) out vec4 outFragColor;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
|
||||
float num = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return num / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
return NdotV / denom;
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float ggx2 = GeometrySchlickGGX(max(dot(N, V), 0.0), roughness);
|
||||
float ggx1 = GeometrySchlickGGX(max(dot(N, L), 0.0), roughness);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Base color with material factor and texture
|
||||
@@ -73,26 +37,18 @@ void main()
|
||||
vec3 N = normalize(T * Nm.x + B * Nm.y + Nn * Nm.z);
|
||||
vec3 camPos = vec3(inverse(sceneData.view)[3]);
|
||||
vec3 V = normalize(camPos - inWorldPos);
|
||||
vec3 L = normalize(-sceneData.sunlightDirection.xyz);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
// Directional sun term (no shadows in forward path)
|
||||
vec3 Lsun = normalize(-sceneData.sunlightDirection.xyz);
|
||||
vec3 sunBRDF = evaluate_brdf(N, V, Lsun, albedo, roughness, metallic);
|
||||
vec3 direct = sunBRDF * sceneData.sunlightColor.rgb * sceneData.sunlightColor.a;
|
||||
|
||||
vec3 numerator = NDF * G * F;
|
||||
float denom = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
|
||||
vec3 specular = numerator / max(denom, 0.001);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = vec3(1.0) - kS;
|
||||
kD *= 1.0 - metallic;
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
vec3 irradiance = sceneData.sunlightColor.rgb * sceneData.sunlightColor.a * NdotL;
|
||||
|
||||
vec3 color = (kD * albedo / PI + specular) * irradiance;
|
||||
// Punctual point lights
|
||||
uint pointCount = sceneData.lightCounts.x;
|
||||
for (uint i = 0u; i < pointCount; ++i)
|
||||
{
|
||||
direct += eval_point_light(sceneData.punctualLights[i], inWorldPos, N, V, albedo, roughness, metallic);
|
||||
}
|
||||
|
||||
// IBL: specular from equirect 2D mips; diffuse from SH
|
||||
vec3 R = reflect(-V, N);
|
||||
@@ -101,9 +57,11 @@ void main()
|
||||
vec2 uv = dir_to_equirect(R);
|
||||
vec3 prefiltered = textureLod(iblSpec2D, uv, lod).rgb;
|
||||
vec2 brdf = texture(iblBRDF, vec2(max(dot(N, V), 0.0), roughness)).rg;
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
vec3 specIBL = prefiltered * (F0 * brdf.x + brdf.y);
|
||||
vec3 diffIBL = (1.0 - metallic) * albedo * sh_eval_irradiance(N);
|
||||
color += diffIBL + specIBL;
|
||||
|
||||
vec3 color = direct + diffIBL + specIBL;
|
||||
|
||||
// Alpha from baseColor texture and factor (glTF spec)
|
||||
float alpha = clamp(baseTex.a * materialData.colorFactors.a, 0.0, 1.0);
|
||||
|
||||
@@ -70,6 +70,13 @@ struct AllocatedBuffer {
|
||||
VmaAllocationInfo info;
|
||||
};
|
||||
|
||||
struct GPUPunctualLight {
|
||||
glm::vec4 position_radius;
|
||||
glm::vec4 color_intensity;
|
||||
};
|
||||
|
||||
static constexpr uint32_t kMaxPunctualLights = 64;
|
||||
|
||||
struct GPUSceneData {
|
||||
glm::mat4 view;
|
||||
glm::mat4 proj;
|
||||
@@ -84,6 +91,9 @@ struct GPUSceneData {
|
||||
// Hybrid ray-query options (match shaders/input_structures.glsl)
|
||||
glm::uvec4 rtOptions; // x: enabled (1/0), y: cascade mask, z,w: reserved
|
||||
glm::vec4 rtParams; // x: N·L threshold, yzw: reserved
|
||||
|
||||
GPUPunctualLight punctualLights[kMaxPunctualLights];
|
||||
glm::uvec4 lightCounts;
|
||||
};
|
||||
|
||||
enum class MaterialPass :uint8_t {
|
||||
|
||||
@@ -27,6 +27,16 @@ SceneManager::~SceneManager()
|
||||
pendingGLTFRelease.size());
|
||||
}
|
||||
|
||||
void SceneManager::addPointLight(const PointLight &light)
|
||||
{
|
||||
pointLights.push_back(light);
|
||||
}
|
||||
|
||||
void SceneManager::clearPointLights()
|
||||
{
|
||||
pointLights.clear();
|
||||
}
|
||||
|
||||
void SceneManager::init(EngineContext *context)
|
||||
{
|
||||
_context = context;
|
||||
@@ -39,6 +49,21 @@ void SceneManager::init(EngineContext *context)
|
||||
sceneData.ambientColor = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
sceneData.sunlightDirection = glm::vec4(-0.2f, -1.0f, -0.3f, 1.0f);
|
||||
sceneData.sunlightColor = glm::vec4(1.0f, 1.0f, 1.0f, 3.0f);
|
||||
|
||||
// Seed a couple of default point lights for quick testing.
|
||||
PointLight warmKey{};
|
||||
warmKey.position = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
warmKey.radius = 25.0f;
|
||||
warmKey.color = glm::vec3(1.0f, 0.95f, 0.8f);
|
||||
warmKey.intensity = 15.0f;
|
||||
addPointLight(warmKey);
|
||||
|
||||
PointLight coolFill{};
|
||||
coolFill.position = glm::vec3(-10.0f, 4.0f, 10.0f);
|
||||
coolFill.radius = 20.0f;
|
||||
coolFill.color = glm::vec3(0.6f, 0.7f, 1.0f);
|
||||
coolFill.intensity = 10.0f;
|
||||
addPointLight(coolFill);
|
||||
}
|
||||
|
||||
void SceneManager::update_scene()
|
||||
@@ -290,6 +315,21 @@ void SceneManager::update_scene()
|
||||
sceneData.rtParams = glm::vec4(ss.hybridRayNoLThreshold, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
// Fill punctual lights into GPUSceneData
|
||||
const uint32_t lightCount = static_cast<uint32_t>(std::min(pointLights.size(), static_cast<size_t>(kMaxPunctualLights)));
|
||||
for (uint32_t i = 0; i < lightCount; ++i)
|
||||
{
|
||||
const PointLight &pl = pointLights[i];
|
||||
sceneData.punctualLights[i].position_radius = glm::vec4(pl.position, pl.radius);
|
||||
sceneData.punctualLights[i].color_intensity = glm::vec4(pl.color, pl.intensity);
|
||||
}
|
||||
for (uint32_t i = lightCount; i < kMaxPunctualLights; ++i)
|
||||
{
|
||||
sceneData.punctualLights[i].position_radius = glm::vec4(0.0f);
|
||||
sceneData.punctualLights[i].color_intensity = glm::vec4(0.0f);
|
||||
}
|
||||
sceneData.lightCounts = glm::uvec4(lightCount, 0u, 0u, 0u);
|
||||
|
||||
auto end = std::chrono::system_clock::now();
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
stats.scene_update_time = elapsed.count() / 1000.f;
|
||||
|
||||
@@ -126,6 +126,18 @@ public:
|
||||
bool setGLTFInstanceAnimation(const std::string &instanceName, const std::string &animationName, bool resetTime = true);
|
||||
bool setGLTFInstanceAnimationLoop(const std::string &instanceName, bool loop);
|
||||
|
||||
struct PointLight
|
||||
{
|
||||
glm::vec3 position;
|
||||
float radius;
|
||||
glm::vec3 color;
|
||||
float intensity;
|
||||
};
|
||||
|
||||
void addPointLight(const PointLight &light);
|
||||
void clearPointLights();
|
||||
const std::vector<PointLight> &getPointLights() const { return pointLights; }
|
||||
|
||||
struct SceneStats
|
||||
{
|
||||
float scene_update_time = 0.f;
|
||||
@@ -148,6 +160,7 @@ private:
|
||||
Camera mainCamera = {};
|
||||
GPUSceneData sceneData = {};
|
||||
DrawContext mainDrawContext;
|
||||
std::vector<PointLight> pointLights;
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<LoadedGLTF> > loadedScenes;
|
||||
std::unordered_map<std::string, std::shared_ptr<Node> > loadedNodes;
|
||||
|
||||
Reference in New Issue
Block a user