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
|
||||
|
||||
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.
|
||||
- skinned meshes / morph targets
|
||||
- Sort out LOG_X calls and ensure DEBUG, TRACE, INFO, etc are being used appropriately
|
||||
|
||||
At some point, add game controller support. Make sure it works well with the
|
||||
InputManager class.
|
||||
## Medium priority (next week)
|
||||
|
||||
(Was implemented in the past)
|
||||
For font rendering, put all ASCII characters in one large texture and use
|
||||
'instancing' (and uniform buffer objects?) to reduce draw calls.
|
||||
- UI generator exposed at the Application level (Scene UI Systems could use this to draw menus every frame)
|
||||
|
||||
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
|
||||
|
||||
@ -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.
|
||||
|
||||
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 = 2) uniform sampler2D materialSetOcclusionRoughnessMetallic;
|
||||
|
||||
layout(location = 0) in vec2 fragUV;
|
||||
layout(location = 1) in vec3 fragPosTangentSpace;
|
||||
layout(location = 2) in vec3 fragViewPosTangentSpace;
|
||||
layout(location = 3) in vec3 fragLightPosTangentSpace;
|
||||
layout(location = 4) in vec3 fragNormWorldSpace;
|
||||
layout(location = 5) in vec3 fragViewPosWorldSpace;
|
||||
layout(location = 6) in vec3 fragPosWorldSpace;
|
||||
layout(location = 7) in vec4 fragPosLightSpace;
|
||||
layout(location = 0) in vec2 fragUV; // for looking up textures
|
||||
layout(location = 1) in vec3 fragPosTangentSpace; // finding view vector
|
||||
layout(location = 2) in vec3 fragViewPosTangentSpace; // finding view vector
|
||||
layout(location = 3) in vec3 fragLightDirTangentSpace; // directional light
|
||||
layout(location = 4) in vec3 fragNormWorldSpace; // for skybox reflection lookup
|
||||
layout(location = 5) in vec3 fragViewPosWorldSpace; // for skybox reflection lookup
|
||||
layout(location = 6) in vec3 fragPosWorldSpace; // for skybox reflection lookup
|
||||
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;
|
||||
|
||||
@ -32,6 +33,19 @@ float GGXDist(float alpha_2, float N_dot_H) {
|
||||
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() {
|
||||
|
||||
const vec4 albedo_alpha = texture(materialSetAlbedoSampler, fragUV);
|
||||
@ -48,18 +62,14 @@ void main() {
|
||||
|
||||
const float roughness_2 = roughness * roughness;
|
||||
|
||||
vec3 light_colour = vec3(1.0, 1.0, 1.0) * 2.4 * 4.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;
|
||||
vec3 light_colour = vec3(1.0, 1.0, 1.0) * 2.4 * 2.0;
|
||||
|
||||
const vec3 emission = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
const vec3 N = GetNormal();
|
||||
|
||||
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 H = normalize(V + L);
|
||||
|
||||
@ -92,27 +102,27 @@ void main() {
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
projCoords.x = projCoords.x * 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 bias = max(0.01 * (1.0 - L_dot_N), 0.005);
|
||||
float shadow = 0.0;
|
||||
vec2 texelSize = 1.0 / textureSize(globalSetShadowmap, 0);
|
||||
for(int x = -2; x <= 2; ++x)
|
||||
vec2 texelSize = 2.0 / textureSize(globalSetShadowmap, 0);
|
||||
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 pcfDepth = texture(globalSetShadowmap, projCoords.xy + vec2(x, y) * texelSize).r;
|
||||
shadow += currentDepth > pcfDepth ? 1.0 : 0.0;
|
||||
float depth = texture(globalSetShadowmap, projCoords.xy + VogelDiskSample(i, samples, phi) * texelSize).r;
|
||||
shadow += currentDepth > depth ? 1.0 : 0.0;
|
||||
}
|
||||
}
|
||||
shadow /= 25.0;
|
||||
shadow = shadow < 0.25 ? 0.0 : shadow;
|
||||
shadow /= float(samples);
|
||||
//shadow = shadow < 0.25 ? 0.0 : shadow;
|
||||
|
||||
lighting *= (1.0 - shadow);
|
||||
|
||||
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
|
||||
|
||||
outColor = vec4(min(emission + lighting, 1.0), 1.0);
|
||||
//outColor = vec4(vec3(shadow), 1.0);
|
||||
// tone mapping
|
||||
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 = 1) out vec3 fragPosTangentSpace;
|
||||
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 = 5) out vec3 fragViewPosWorldSpace;
|
||||
layout(location = 6) out vec3 fragPosWorldSpace;
|
||||
layout(location = 7) out vec4 fragPosLightSpace;
|
||||
layout(location = 8) out vec4 fragPosScreenSpace;
|
||||
|
||||
void main() {
|
||||
vec4 worldPosition = constants.model * vec4(inPosition, 1.0);
|
||||
@ -39,14 +40,14 @@ void main() {
|
||||
fragUV = inUV;
|
||||
fragPosTangentSpace = worldToTangentSpace * vec3(worldPosition);
|
||||
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
|
||||
//fragLightPosTangentSpace = worldToTangentSpace * vec3(10.0, 0.0, 10.0);
|
||||
fragLightDirTangentSpace = worldToTangentSpace * vec3(-0.4278,0.7923,0.43502); // directional light
|
||||
|
||||
fragNormWorldSpace = N;
|
||||
fragViewPosWorldSpace = vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0));
|
||||
fragPosWorldSpace = worldPosition.xyz;
|
||||
|
||||
fragPosLightSpace = globalSetUniformBuffer.lightSpaceMatrix * vec4(worldPosition.xyz, 1.0);
|
||||
fragPosScreenSpace = gl_Position;
|
||||
|
||||
gl_Position.y *= -1.0;
|
||||
}
|
||||
|
@ -1351,9 +1351,9 @@ gfx::Pipeline* GFXDevice::CreatePipeline(const gfx::PipelineInfo& info)
|
||||
if (info.depth_attachment_only) {
|
||||
// use depth bias if only rendering to a depth attachment
|
||||
rasterizer.depthBiasEnable = VK_TRUE;
|
||||
rasterizer.depthBiasConstantFactor = 1.25f;
|
||||
rasterizer.depthBiasConstantFactor = 2.0f;//1.25f;
|
||||
rasterizer.depthBiasClamp = 0.0f;
|
||||
rasterizer.depthBiasSlopeFactor = 1.75f;
|
||||
rasterizer.depthBiasSlopeFactor = 3.5f;//1.75f;
|
||||
}
|
||||
else {
|
||||
rasterizer.depthBiasEnable = VK_FALSE;
|
||||
|
@ -63,14 +63,14 @@ void CameraControllerSystem::OnUpdate(float ts)
|
||||
c->vel.z += CameraControllerComponent::kGravAccel * dt;
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// update position with velocity:
|
||||
|
||||
// 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{};
|
||||
engine::Raycast* chosen_cast = nullptr; // nullptr means no hit at all
|
||||
@ -113,11 +113,12 @@ void CameraControllerSystem::OnUpdate(float ts)
|
||||
}
|
||||
|
||||
// check falling collisions
|
||||
if (!c->noclip) {
|
||||
if (c->vel.z < 0.0f) { // if falling
|
||||
engine::Ray fall_ray{};
|
||||
fall_ray.origin = t->position;
|
||||
fall_ray.origin.z += CameraControllerComponent::kMaxStairHeight - CameraControllerComponent::kPlayerHeight;
|
||||
fall_ray.direction = {0.0f, 0.0f, -1.0f}; // down
|
||||
fall_ray.direction = { 0.0f, 0.0f, -1.0f }; // down
|
||||
const engine::Raycast fall_raycast = scene_->GetSystem<engine::CollisionSystem>()->GetRaycast(fall_ray);
|
||||
if (fall_raycast.hit) { // there is ground below player
|
||||
// find how far the player will move (downwards) if velocity is applied without collision
|
||||
@ -155,6 +156,7 @@ void CameraControllerSystem::OnUpdate(float ts)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t->position += c->vel * dt;
|
||||
|
||||
|
@ -28,6 +28,8 @@ struct CameraControllerComponent {
|
||||
static constexpr float kGravAccel = -9.81f;
|
||||
static constexpr float kMaxDistanceFromOrigin = 1000.0f;
|
||||
|
||||
bool noclip = false;
|
||||
|
||||
float yaw = 0.0f;
|
||||
float pitch = glm::half_pi<float>();
|
||||
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
|
||||
* 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->RegisterSystem<CameraControllerSystem>();
|
||||
start_scene->AddComponent<CameraControllerComponent>(camera);
|
||||
start_scene->AddComponent<CameraControllerComponent>(camera)->noclip = true;
|
||||
}
|
||||
|
||||
engine::Scene* main_scene = app.scene_manager()->CreateEmptyScene();
|
||||
|
Loading…
Reference in New Issue
Block a user