Skip to content

Commit

Permalink
Physics engine + more scene improvements (#44)
Browse files Browse the repository at this point in the history
* Started scene rework

* Refactored the new scene a bit

* More changes

* Attempt fix

* Subset on scene level with scene entity implemented

* Compilation works again

* Fixed a bunch of issues

* First iteration of physics integration

* Some fixes + some improvements

* Some more fixes

* Fixed a few things

* Box shape for rigid body supported + fixes

* Many improvements

* Scaled physics shapes work now + fixes

* Made ray tracing world optional in scene

* Terrain can be inserted into physics world + bug fixes
  • Loading branch information
tippesi committed Mar 24, 2024
1 parent fbf7676 commit 036bea8
Show file tree
Hide file tree
Showing 64 changed files with 1,706 additions and 299 deletions.
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ endif(COMMAND cmake_policy)

cmake_minimum_required(VERSION 3.24)

project(AtlasEngine VERSION 0.1.10)
project(AtlasEngine VERSION 0.2.0)

# Only 64 bit is supported
###################################################################
Expand Down Expand Up @@ -78,14 +78,15 @@ if (ANDROID)
add_subdirectory(${HIDAPI_LOCATION})
endif()

find_package(unofficial-spirv-reflect CONFIG REQUIRED)
find_package(Vulkan REQUIRED)
find_package(Threads REQUIRED)
find_package(volk CONFIG REQUIRED)
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
find_package(glslang CONFIG REQUIRED)
find_package(unofficial-spirv-reflect CONFIG REQUIRED)
find_package(SPIRV-Tools-opt CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(unofficial-joltphysics CONFIG REQUIRED)

if (ATLAS_TESTS)
find_package(GTest CONFIG REQUIRED)
Expand Down
2 changes: 1 addition & 1 deletion data/shader/impostor/impostorShadow.fsh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ layout(set = 3, binding = 0) uniform sampler2DArray baseColorMap;
layout(set = 3, binding = 1) uniform sampler2DArray depthMap;
#endif

layout(std430, set = 1, binding = 2) buffer Matrices {
layout(std430, set = 1, binding = 3) buffer Matrices {
mat4 matrices[];
};

Expand Down
2 changes: 1 addition & 1 deletion data/shader/impostor/impostorShadow.vsh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct ViewPlane {
vec4 up;
};

layout(std430, set = 1, binding = 2) buffer Matrices {
layout(std430, set = 1, binding = 3) buffer Matrices {
mat3x4 matrices[];
};

Expand Down
31 changes: 18 additions & 13 deletions data/shader/ssgi/temporal.csh
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ ivec2 FindNearest3x3(ivec2 pixel) {

}

void ComputeVarianceMinMax(out vec3 mean, out vec3 std) {
void ComputeVarianceMinMax(out vec4 mean, out vec4 std) {

vec3 m1 = vec3(0.0);
vec3 m2 = vec3(0.0);
vec4 m1 = vec4(0.0);
vec4 m2 = vec4(0.0);
// This could be varied using the temporal variance estimation
// By using a wide neighborhood for variance estimation (8x8) we introduce block artifacts
// These are similiar to video compression artifacts, the spatial filter mostly clears them up
Expand All @@ -144,13 +144,16 @@ void ComputeVarianceMinMax(out vec3 mean, out vec3 std) {
int sharedMemoryIdx = GetSharedMemoryIndex(ivec2(i, j));

vec3 sampleGi = FetchCurrentGi(sharedMemoryIdx);
float sampleAo = FetchCurrentAo(sharedMemoryIdx);

vec4 sampleAll = vec4(sampleGi, sampleAo);
float sampleLinearDepth = FetchDepth(sharedMemoryIdx);

float depthPhi = max(1.0, abs(0.025 * linearDepth));
float weight = min(1.0 , exp(-abs(linearDepth - sampleLinearDepth)));

m1 += sampleGi * weight;
m2 += sampleGi * sampleGi * weight;
m1 += sampleAll * weight;
m2 += sampleAll * sampleAll * weight;

totalWeight += weight;
}
Expand Down Expand Up @@ -245,16 +248,17 @@ void main() {
pixel.y > imageSize(resolveImage).y)
return;

vec3 mean, std;
vec4 mean, std;
ComputeVarianceMinMax(mean, std);

const float historyClipFactor = 1.0;
vec3 historyNeighbourhoodMin = mean - historyClipFactor * std;
vec3 historyNeighbourhoodMax = mean + historyClipFactor * std;
const float historyClipFactorGi = 1.0, historyClipFactorAo = 1.0;
vec4 historyClipFactor = vec4(vec3(historyClipFactorGi), historyClipFactorAo);
vec4 historyNeighbourhoodMin = mean - historyClipFactor * std;
vec4 historyNeighbourhoodMax = mean + historyClipFactor * std;

const float currentClipFactor = 4.0;
vec3 currentNeighbourhoodMin = mean - currentClipFactor * std;
vec3 currentNeighbourhoodMax = mean + currentClipFactor * std;
vec4 currentNeighbourhoodMin = mean - currentClipFactor * std;
vec4 currentNeighbourhoodMax = mean + currentClipFactor * std;

ivec2 velocityPixel = pixel;
vec2 velocity = texelFetch(velocityTexture, velocityPixel, 0).rg;
Expand All @@ -271,8 +275,9 @@ void main() {
vec4 currentValue = texelFetch(currentTexture, pixel, 0);

// In case of clipping we might also reject the sample. TODO: Investigate
currentValue.rgb = clamp(currentValue.rgb, currentNeighbourhoodMin, currentNeighbourhoodMax);
//historyValue = clamp(historyValue, historyNeighbourhoodMin, historyNeighbourhoodMax);
currentValue.rgb = clamp(currentValue.rgb, currentNeighbourhoodMin.rgb, currentNeighbourhoodMax.rgb);
// Only clamp AO for now, since this leaves visible streaks
// historyValue.a = clamp(historyValue.a, historyNeighbourhoodMin.a, historyNeighbourhoodMax.a);

float factor = 0.95;
factor = (uv.x < 0.0 || uv.y < 0.0 || uv.x > 1.0
Expand Down
124 changes: 107 additions & 17 deletions src/demo/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ void App::LoadContent() {
keyboardHandler.speed = cameraSpeed;
}
});

Atlas::Events::EventManager::MouseButtonEventDelegate.Subscribe(
[this](Atlas::Events::MouseButtonEvent event) {
if (event.button == AE_MOUSEBUTTON_RIGHT) {
shootSphere = event.down && shootSpheresEnabled;
}
});

Atlas::PipelineManager::EnableHotReload();

Expand Down Expand Up @@ -82,6 +89,9 @@ void App::LoadContent() {

scene->ssgi = Atlas::CreateRef<Atlas::Lighting::SSGI>();

scene->physicsWorld = Atlas::CreateRef<Atlas::Physics::PhysicsWorld>();
scene->rayTracingWorld = Atlas::CreateRef<Atlas::RayTracing::RayTracingWorld>();

LoadScene();

ImGui::CreateContext();
Expand Down Expand Up @@ -140,8 +150,12 @@ void App::Update(float deltaTime) {
if (sceneSelection == SPONZA) {
auto meshEntitySubset = scene->GetSubset<MeshComponent, TransformComponent>();

int idx = 0;
for (auto entity : meshEntitySubset) {

if (idx++ >= 3)
continue;

const auto& [meshComponent, transformComponent] = meshEntitySubset.Get(entity);

if (!meshComponent.mesh.IsLoaded())
Expand All @@ -163,6 +177,49 @@ void App::Update(float deltaTime) {
}
}

if (scene->IsFullyLoaded() && emitSpheresEnabled) {

static float lastSpawn = 0.0f;

if (Atlas::Clock::Get() - emitSpawnRate > lastSpawn) {
auto x = (2.0f * Atlas::Common::Random::SampleFastUniformFloat() - 1.0f) * 20.0f;
auto z = (2.0f * Atlas::Common::Random::SampleFastUniformFloat() - 1.0f) * 20.0f;

auto matrix = glm::translate(glm::mat4(1.0f), glm::vec3(x, 100.0f, z)) * glm::scale(glm::vec3(emitSphereScale));

auto entity = scene->CreatePrefab<MeshInstance>(meshes.back(), matrix, false);

auto shape = Atlas::Physics::ShapesManager::CreateShapeFromSphere(meshes.back()->data.radius);
entity.AddComponent<RigidBodyComponent>(shape, Atlas::Physics::Layers::MOVABLE);

entities.push_back(entity);
lastSpawn = Atlas::Clock::Get();
}

}

if (scene->IsFullyLoaded() && shootSphere) {

static float lastSpawn = 0.0f;


if (Atlas::Clock::Get() - shootSpawnRate > lastSpawn) {
auto shape = Atlas::Physics::ShapesManager::CreateShapeFromSphere(meshes.back()->data.radius,
glm::vec3(1.0f), shootDensity);

auto matrix = glm::translate(glm::mat4(1.0f), glm::vec3(camera.GetLocation() +
camera.direction * meshes.back()->data.radius * 2.0f));
auto entity = scene->CreatePrefab<MeshInstance>(meshes.back(), matrix, false);

auto& rigidBodyComponent = entity.AddComponent<RigidBodyComponent>(shape, Atlas::Physics::Layers::MOVABLE);
rigidBodyComponent.SetLinearVelocity(camera.direction * shootVelocity);

entities.push_back(entity);
lastSpawn = Atlas::Clock::Get();
}

}

scene->Update(deltaTime);
scene->UpdateCameraDependent(std::make_shared<Atlas::Camera>(camera), deltaTime);

Expand Down Expand Up @@ -295,6 +352,7 @@ void App::Render(float deltaTime) {
ImGui::Text("Camera location: %s", vecToString(camera.location).c_str());
ImGui::Text("Scene dimensions: %s to %s", vecToString(sceneAABB.min).c_str(),vecToString(sceneAABB.max).c_str());
ImGui::Text("Scene triangle count: %d", triangleCount);
ImGui::Text("Number of entities: %zu", entities.size());

{
const char* items[] = { "Cornell box", "Sponza", "San Miguel",
Expand Down Expand Up @@ -624,6 +682,18 @@ void App::Render(float deltaTime) {
ImGui::Checkbox("Enable##Film grain", &postProcessing.filmGrain.enable);
ImGui::SliderFloat("Strength##Film grain", &postProcessing.filmGrain.strength, 0.0f, 1.0f);
}
if (ImGui::CollapsingHeader("Physics")) {
ImGui::Text("Sphere emitter");
ImGui::Checkbox("Enable##PhysicsEmitter", &emitSpheresEnabled);
ImGui::SliderFloat("Spawn rate##PhysicsEmitter", &emitSpawnRate, 0.001f, 1.0f);
ImGui::SliderFloat("Sphere scale##PhysicsEmitter", &emitSphereScale, 1.0f, 10.0f);
ImGui::Separator();
ImGui::Text("Shoot spheres");
ImGui::Checkbox("Enable##PhysicsShoot", &shootSpheresEnabled);
ImGui::SliderFloat("Spawn rate##PhysicsShoot", &shootSpawnRate, 0.001f, 1.0f);
ImGui::SliderFloat("Velocity##PhysicsShoot", &shootVelocity, 0.0f, 100.0f);
ImGui::SliderFloat("Density##PhysicsShoot", &shootDensity, 0.0f, 100.0f);
}
if (ImGui::CollapsingHeader("Materials")) {
int32_t id = 0;
auto materials = scene->GetMaterials();
Expand Down Expand Up @@ -887,21 +957,13 @@ bool App::LoadScene() {
);
meshes.push_back(mesh);

transform = glm::scale(glm::mat4(1.0f), glm::vec3(1.f));
transform = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f));
mesh = Atlas::ResourceManager<Atlas::Mesh::Mesh>::GetOrLoadResourceWithLoaderAsync(
"metallicwall.gltf", ModelLoader::LoadMesh, Atlas::Mesh::MeshMobility::Movable,
false, transform, 2048
);
meshes.push_back(mesh);

transform = glm::scale(glm::mat4(1.0f), glm::vec3(1.f));
mesh = Atlas::ResourceManager<Atlas::Mesh::Mesh>::GetOrLoadResourceWithLoaderAsync(
"chromesphere.gltf", ModelLoader::LoadMesh, Atlas::Mesh::MeshMobility::Movable,
false, transform, 2048
);
meshes.push_back(mesh);


// Other scene related settings apart from the mesh
directionalLight->direction = glm::vec3(0.0f, -1.0f, 0.33f);
directionalLight->intensity = 100.0f;
Expand Down Expand Up @@ -1137,26 +1199,35 @@ bool App::LoadScene() {

// scene.sky.probe = std::make_shared<Atlas::Lighting::EnvironmentProbe>(sky);

// Load chrome sphere for every scene in order to test physics
auto transform = glm::scale(glm::mat4(1.0f), glm::vec3(1.f));
auto mesh = Atlas::ResourceManager<Atlas::Mesh::Mesh>::GetOrLoadResourceWithLoaderAsync(
"chromesphere.gltf", ModelLoader::LoadMesh, Atlas::Mesh::MeshMobility::Movable,
false, transform, 2048
);
meshes.push_back(mesh);

if (sceneSelection != FOREST && sceneSelection != EMERALDSQUARE) {
auto meshCount = 0;
for (auto &mesh: meshes) {
if (meshCount == 10) {
meshCount++;
// Only Sponza scene gets extra moving ball
if (mesh.GetID() == meshes.back().GetID() && sceneSelection != SPONZA)
continue;
}

auto entity = scene->CreatePrefab<MeshInstance>(mesh, glm::mat4(1.0f));
auto isStatic = meshCount == 0;
auto entity = scene->CreatePrefab<MeshInstance>(mesh, glm::mat4(1.0f), isStatic);
entities.push_back(entity);

/*
if (meshCount == 1) {
for (int32_t i = 0; i < 20000; i++) {
for (int32_t i = 0; i < 200000; i++) {
auto x = (2.0f * Atlas::Common::Random::SampleFastUniformFloat() - 1.0f) * 100.0f;
auto y = (2.0f * Atlas::Common::Random::SampleFastUniformFloat() - 1.0f) * 100.0f;
auto z = (2.0f * Atlas::Common::Random::SampleFastUniformFloat() - 1.0f) * 100.0f;
actors.push_back(Atlas::Actor::MovableMeshActor{mesh, glm::translate(glm::mat4(1.0f),
glm::vec3(x, y, z))});
auto entity = scene->CreatePrefab<MeshInstance>(mesh, glm::translate(glm::mat4(1.0f),
glm::vec3(x, y, z)));
entities.push_back(entity);
}
}
*/
Expand Down Expand Up @@ -1185,6 +1256,7 @@ void App::UnloadScene() {
}

meshes.clear();
entities.clear();

meshes.shrink_to_fit();

Expand Down Expand Up @@ -1246,6 +1318,7 @@ void App::CheckLoadScene() {
}

for (auto& mesh : meshes) {
if (!mesh.IsLoaded()) continue;
mesh->invertUVs = true;
mesh->cullBackFaces = true;
}
Expand Down Expand Up @@ -1318,6 +1391,22 @@ void App::CheckLoadScene() {

scene->irradianceVolume->useShadowMap = true;

// Add rigid body components to entities (we need to wait for loading to complete to get valid mesh bounds)
int32_t entityCount = 0;
for (auto& entity : entities) {
auto& meshComponent = entity.GetComponent<MeshComponent>();
if (entityCount++ == 0) {
auto shape = Atlas::Physics::ShapesManager::CreateShapeFromMesh(meshComponent.mesh.Get());
entity.AddComponent<RigidBodyComponent>(shape, Atlas::Physics::Layers::STATIC);
}
else {
auto shape = Atlas::Physics::ShapesManager::CreateShapeFromAABB(meshComponent.mesh->data.aabb);
entity.AddComponent<RigidBodyComponent>(shape, Atlas::Physics::Layers::STATIC);
}
}

scene->physicsWorld->OptimizeBroadphase();

Atlas::Clock::ResetAverage();

loadingComplete = true;
Expand All @@ -1333,7 +1422,8 @@ void App::SetResolution(int32_t width, int32_t height) {

void App::CopyActors(Atlas::Ref<Atlas::Scene::Scene> otherScene) {

scene->Merge<MeshComponent, TransformComponent>(otherScene);
// Can use entity map for user created components to merge them as well
scene->Merge(otherScene);

auto otherMeshes = otherScene->GetMeshes();

Expand Down
10 changes: 10 additions & 0 deletions src/demo/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ class App : public Atlas::EngineInstance {
bool loadingComplete = false;
bool sceneReload = false;

bool emitSpheresEnabled = false;
float emitSpawnRate = 0.1f;
float emitSphereScale = 1.0f;

bool shootSpheresEnabled = false;
bool shootSphere = false;
float shootSpawnRate = 0.1f;
float shootVelocity = 5.0f;
float shootDensity = 1.0f;

ImguiWrapper imguiWrapper;

};
6 changes: 3 additions & 3 deletions src/engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ if(WIN32)

set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SPIRV-Tools-opt
volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator
unofficial::spirv-reflect::spirv-reflect glslang::SPIRV)
unofficial::spirv-reflect::spirv-reflect glslang::SPIRV unofficial::joltphysics::Jolt)
endif()

if (MINGW)
Expand All @@ -54,7 +54,7 @@ if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_MACOS_MVK -DVK_EXAMPLE_XCODE_GENERATED")

set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static
volk::volk SPIRV-Tools-opt
volk::volk SPIRV-Tools-opt unofficial::joltphysics::Jolt
GPUOpen::VulkanMemoryAllocator Vulkan::Vulkan Vulkan::Headers
unofficial::spirv-reflect::spirv-reflect glslang::SPIRV)
endif()
Expand All @@ -78,7 +78,7 @@ if(UNIX AND NOT APPLE AND NOT ANDROID)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

set(ATLAS_ENGINE_LIBS assimp::assimp SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static
volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator
volk::volk volk::volk_headers GPUOpen::VulkanMemoryAllocator unofficial::joltphysics::Jolt
unofficial::spirv-reflect::spirv-reflect SPIRV-Tools-opt glslang::SPIRV)
endif()

Expand Down
Loading

0 comments on commit 036bea8

Please sign in to comment.