Improve shadows

This commit is contained in:
bailehuni 2024-03-30 23:49:29 +00:00
parent 28dcc9a3f7
commit 0603d77917
7 changed files with 109 additions and 81 deletions

View File

@ -6,21 +6,31 @@ a random game engine thing. Now finally with ECS!
# TO DO LIST # TO DO LIST
Add support for multiple lights. ## High priority (tomorrow)
Support dynamic shadow mapping (probably with cascades) - Support dynamic shadow mapping (at least for shadows cast from the scene's sun)
Support animations. - Sort out LOG_X calls and ensure DEBUG, TRACE, INFO, etc are being used appropriately
- skinned meshes / morph targets
At some point, add game controller support. Make sure it works well with the ## Medium priority (next week)
InputManager class.
(Was implemented in the past) - UI generator exposed at the Application level (Scene UI Systems could use this to draw menus every frame)
For font rendering, put all ASCII characters in one large texture and use
'instancing' (and uniform buffer objects?) to reduce draw calls.
Sort out LOG_X calls and ensure DEBUG, TRACE, INFO, etc are being used appropriately - Proper IBL with an irradiance map
- Multiple lights (dynamic and static; do not need to be shadow casting)
- More accurate raycast collision detection (Perhaps only sphere, capsule, OBB colliders. Mesh collision is probably unneccesary.)
## Low priority (next month)
- Explicit post processing pass exposed by the GFXDevice that can be used for bloom, AA, etc
- Audio!!
- Support animations (skinned meshes / morph targets)
- Game controller support (controller detection, input, feedback etc in window.cpp; integration with input_manager.cpp)
# DONE # DONE
@ -47,4 +57,4 @@ Added the BVH AABB tree made in Summer to start a much better Collision system.
The CameraControllerSystem now uses raycasting to enable FPS-style player movement. The CameraControllerSystem now uses raycasting to enable FPS-style player movement.
Added support for simple shadow mapping. Added static soft shadows.

View File

@ -10,14 +10,15 @@ layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler;
layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler; layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler;
layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionRoughnessMetallic; layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionRoughnessMetallic;
layout(location = 0) in vec2 fragUV; layout(location = 0) in vec2 fragUV; // for looking up textures
layout(location = 1) in vec3 fragPosTangentSpace; layout(location = 1) in vec3 fragPosTangentSpace; // finding view vector
layout(location = 2) in vec3 fragViewPosTangentSpace; layout(location = 2) in vec3 fragViewPosTangentSpace; // finding view vector
layout(location = 3) in vec3 fragLightPosTangentSpace; layout(location = 3) in vec3 fragLightDirTangentSpace; // directional light
layout(location = 4) in vec3 fragNormWorldSpace; layout(location = 4) in vec3 fragNormWorldSpace; // for skybox reflection lookup
layout(location = 5) in vec3 fragViewPosWorldSpace; layout(location = 5) in vec3 fragViewPosWorldSpace; // for skybox reflection lookup
layout(location = 6) in vec3 fragPosWorldSpace; layout(location = 6) in vec3 fragPosWorldSpace; // for skybox reflection lookup
layout(location = 7) in vec4 fragPosLightSpace; layout(location = 7) in vec4 fragPosLightSpace; // for shadow map lookup
layout(location = 8) in vec4 fragPosScreenSpace; // for shadow map randomness
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
@ -32,6 +33,19 @@ float GGXDist(float alpha_2, float N_dot_H) {
return num / den; return num / den;
} }
vec2 VogelDiskSample(int sampleIndex, int samplesCount, float phi) {
const float GoldenAngle = 2.4;
float r = sqrt(sampleIndex + 0.5) / sqrt(samplesCount);
float theta = sampleIndex * GoldenAngle + phi;
return vec2(r * cos(theta), r * sin(theta));
}
float InterleavedGradientNoise(vec2 position_screen)
{
const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
return magic.z * dot(position_screen, magic.xy);
}
void main() { void main() {
const vec4 albedo_alpha = texture(materialSetAlbedoSampler, fragUV); const vec4 albedo_alpha = texture(materialSetAlbedoSampler, fragUV);
@ -48,18 +62,14 @@ void main() {
const float roughness_2 = roughness * roughness; const float roughness_2 = roughness * roughness;
vec3 light_colour = vec3(1.0, 1.0, 1.0) * 2.4 * 4.0; vec3 light_colour = vec3(1.0, 1.0, 1.0) * 2.4 * 2.0;
float light_distance = length(fragLightPosTangentSpace - fragPosTangentSpace);
float attenuation = 1.0 / (1.0 + 0.09 * light_distance +
0.032 * (light_distance * light_distance));
//light_colour *= 5.0 * attenuation;
const vec3 emission = vec3(0.0, 0.0, 0.0); const vec3 emission = vec3(0.0, 0.0, 0.0);
const vec3 N = GetNormal(); const vec3 N = GetNormal();
const vec3 V = normalize(fragViewPosTangentSpace - fragPosTangentSpace); const vec3 V = normalize(fragViewPosTangentSpace - fragPosTangentSpace);
const vec3 L = normalize(fragLightPosTangentSpace /* - fragPosTangentSpace */ ); const vec3 L = normalize(fragLightDirTangentSpace);
//const vec3 L = normalize(vec3(5.0, 0.0, 3.0)); //const vec3 L = normalize(vec3(5.0, 0.0, 3.0));
const vec3 H = normalize(V + L); const vec3 H = normalize(V + L);
@ -92,27 +102,27 @@ void main() {
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords.x = projCoords.x * 0.5 + 0.5; projCoords.x = projCoords.x * 0.5 + 0.5;
projCoords.y = projCoords.y * 0.5 + 0.5; projCoords.y = projCoords.y * 0.5 + 0.5;
//float closestDepth = texture(globalSetShadowmap, projCoords.xy).r;
const float currentDepth = max(projCoords.z, 0.0); const float currentDepth = max(projCoords.z, 0.0);
//const float bias = max(0.01 * (1.0 - L_dot_N), 0.005);
float shadow = 0.0; float shadow = 0.0;
vec2 texelSize = 1.0 / textureSize(globalSetShadowmap, 0); vec2 texelSize = 2.0 / textureSize(globalSetShadowmap, 0);
for(int x = -2; x <= 2; ++x) const int samples = 16;
const float phi = InterleavedGradientNoise(fragPosScreenSpace.xy / fragPosScreenSpace.w) * 2.0 * PI;
//const float phi = 0.0;
for(int i = 0; i < samples; ++i)
{ {
for(int y = -2; y <= 2; ++y) float depth = texture(globalSetShadowmap, projCoords.xy + VogelDiskSample(i, samples, phi) * texelSize).r;
{ shadow += currentDepth > depth ? 1.0 : 0.0;
float pcfDepth = texture(globalSetShadowmap, projCoords.xy + vec2(x, y) * texelSize).r;
shadow += currentDepth > pcfDepth ? 1.0 : 0.0;
} }
} shadow /= float(samples);
shadow /= 25.0; //shadow = shadow < 0.25 ? 0.0 : shadow;
shadow = shadow < 0.25 ? 0.0 : shadow;
lighting *= (1.0 - shadow); lighting *= (1.0 - shadow);
const vec3 ambient_light = vec3(0.09082, 0.13281, 0.18164) * 2.4; const vec3 ambient_light = vec3(0.09082, 0.13281, 0.18164) * 2.4;
lighting += mix(ambient_light, texture(globalSetSkybox, R).rgb, metallic) * ao * diffuse_brdf; // this is NOT physically-based, it just looks cool lighting += mix(ambient_light, texture(globalSetSkybox, R).rgb, metallic) * ao * diffuse_brdf; // this is NOT physically-based, it just looks cool
outColor = vec4(min(emission + lighting, 1.0), 1.0); // tone mapping
//outColor = vec4(vec3(shadow), 1.0); const vec3 hdr_color = min(emission + lighting, 1.0);
outColor = vec4(hdr_color / (hdr_color + 1.0), 1.0);
//outColor = vec4(vec3(1.0 - shadow), 1.0);
} }

View File

@ -21,11 +21,12 @@ layout(location = 3) in vec2 inUV;
layout(location = 0) out vec2 fragUV; layout(location = 0) out vec2 fragUV;
layout(location = 1) out vec3 fragPosTangentSpace; layout(location = 1) out vec3 fragPosTangentSpace;
layout(location = 2) out vec3 fragViewPosTangentSpace; layout(location = 2) out vec3 fragViewPosTangentSpace;
layout(location = 3) out vec3 fragLightPosTangentSpace; layout(location = 3) out vec3 fragLightDirTangentSpace;
layout(location = 4) out vec3 fragNormWorldSpace; layout(location = 4) out vec3 fragNormWorldSpace;
layout(location = 5) out vec3 fragViewPosWorldSpace; layout(location = 5) out vec3 fragViewPosWorldSpace;
layout(location = 6) out vec3 fragPosWorldSpace; layout(location = 6) out vec3 fragPosWorldSpace;
layout(location = 7) out vec4 fragPosLightSpace; layout(location = 7) out vec4 fragPosLightSpace;
layout(location = 8) out vec4 fragPosScreenSpace;
void main() { void main() {
vec4 worldPosition = constants.model * vec4(inPosition, 1.0); vec4 worldPosition = constants.model * vec4(inPosition, 1.0);
@ -39,14 +40,14 @@ void main() {
fragUV = inUV; fragUV = inUV;
fragPosTangentSpace = worldToTangentSpace * vec3(worldPosition); fragPosTangentSpace = worldToTangentSpace * vec3(worldPosition);
fragViewPosTangentSpace = worldToTangentSpace * vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0)); fragViewPosTangentSpace = worldToTangentSpace * vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0));
fragLightPosTangentSpace = worldToTangentSpace * vec3(-0.4278,0.7923,0.43502); // directional light fragLightDirTangentSpace = worldToTangentSpace * vec3(-0.4278,0.7923,0.43502); // directional light
//fragLightPosTangentSpace = worldToTangentSpace * vec3(10.0, 0.0, 10.0);
fragNormWorldSpace = N; fragNormWorldSpace = N;
fragViewPosWorldSpace = vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0)); fragViewPosWorldSpace = vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0));
fragPosWorldSpace = worldPosition.xyz; fragPosWorldSpace = worldPosition.xyz;
fragPosLightSpace = globalSetUniformBuffer.lightSpaceMatrix * vec4(worldPosition.xyz, 1.0); fragPosLightSpace = globalSetUniformBuffer.lightSpaceMatrix * vec4(worldPosition.xyz, 1.0);
fragPosScreenSpace = gl_Position;
gl_Position.y *= -1.0; gl_Position.y *= -1.0;
} }

View File

@ -1351,9 +1351,9 @@ gfx::Pipeline* GFXDevice::CreatePipeline(const gfx::PipelineInfo& info)
if (info.depth_attachment_only) { if (info.depth_attachment_only) {
// use depth bias if only rendering to a depth attachment // use depth bias if only rendering to a depth attachment
rasterizer.depthBiasEnable = VK_TRUE; rasterizer.depthBiasEnable = VK_TRUE;
rasterizer.depthBiasConstantFactor = 1.25f; rasterizer.depthBiasConstantFactor = 2.0f;//1.25f;
rasterizer.depthBiasClamp = 0.0f; rasterizer.depthBiasClamp = 0.0f;
rasterizer.depthBiasSlopeFactor = 1.75f; rasterizer.depthBiasSlopeFactor = 3.5f;//1.75f;
} }
else { else {
rasterizer.depthBiasEnable = VK_FALSE; rasterizer.depthBiasEnable = VK_FALSE;

View File

@ -63,14 +63,14 @@ void CameraControllerSystem::OnUpdate(float ts)
c->vel.z += CameraControllerComponent::kGravAccel * dt; c->vel.z += CameraControllerComponent::kGravAccel * dt;
// jumping // jumping
if (scene_->app()->input_manager()->GetButtonPress("jump") && c->grounded) { if (scene_->app()->input_manager()->GetButtonPress("jump") && (c->grounded || c->noclip)) {
c->vel.z += CameraControllerComponent::kJumpHeight; // m/s c->vel.z += CameraControllerComponent::kJumpHeight; // m/s
} }
// update position with velocity: // update position with velocity:
// check horizontal collisions first as otherwise the player may be teleported above a wall instead of colliding against it // check horizontal collisions first as otherwise the player may be teleported above a wall instead of colliding against it
if (c->vel.x != 0.0f || c->vel.y != 0.0f) { // just in case, to avoid a ray with direction = (0,0,0) if ((c->vel.x != 0.0f || c->vel.y != 0.0f) && !c->noclip) { // just in case, to avoid a ray with direction = (0,0,0)
std::array<engine::Raycast, CameraControllerComponent::kNumHorizontalRays> raycasts{}; std::array<engine::Raycast, CameraControllerComponent::kNumHorizontalRays> raycasts{};
engine::Raycast* chosen_cast = nullptr; // nullptr means no hit at all engine::Raycast* chosen_cast = nullptr; // nullptr means no hit at all
@ -113,6 +113,7 @@ void CameraControllerSystem::OnUpdate(float ts)
} }
// check falling collisions // check falling collisions
if (!c->noclip) {
if (c->vel.z < 0.0f) { // if falling if (c->vel.z < 0.0f) { // if falling
engine::Ray fall_ray{}; engine::Ray fall_ray{};
fall_ray.origin = t->position; fall_ray.origin = t->position;
@ -155,6 +156,7 @@ void CameraControllerSystem::OnUpdate(float ts)
} }
} }
} }
}
t->position += c->vel * dt; t->position += c->vel * dt;

View File

@ -28,6 +28,8 @@ struct CameraControllerComponent {
static constexpr float kGravAccel = -9.81f; static constexpr float kGravAccel = -9.81f;
static constexpr float kMaxDistanceFromOrigin = 1000.0f; static constexpr float kMaxDistanceFromOrigin = 1000.0f;
bool noclip = false;
float yaw = 0.0f; float yaw = 0.0f;
float pitch = glm::half_pi<float>(); float pitch = glm::half_pi<float>();
glm::vec3 vel{0.0f, 0.0f, 0.0f}; glm::vec3 vel{0.0f, 0.0f, 0.0f};

View File

@ -67,9 +67,12 @@ void PlayGame(GameSettings settings)
/* as of right now, the entity with tag 'camera' is used to build the view /* as of right now, the entity with tag 'camera' is used to build the view
* matrix */ * matrix */
engine::Entity sponza = engine::util::LoadGLTF(*start_scene, app.GetResourcePath("models/tree.glb"), true);
start_scene->GetPosition(sponza).z += 90.0f;
start_scene->RegisterComponent<CameraControllerComponent>(); start_scene->RegisterComponent<CameraControllerComponent>();
start_scene->RegisterSystem<CameraControllerSystem>(); start_scene->RegisterSystem<CameraControllerSystem>();
start_scene->AddComponent<CameraControllerComponent>(camera); start_scene->AddComponent<CameraControllerComponent>(camera)->noclip = true;
} }
engine::Scene* main_scene = app.scene_manager()->CreateEmptyScene(); engine::Scene* main_scene = app.scene_manager()->CreateEmptyScene();