mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Improve shadows
This commit is contained in:
parent
28dcc9a3f7
commit
0603d77917
32
README.md
32
README.md
@ -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.
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user