Merge branch 'main' into PlayerController

This commit is contained in:
Glence 2022-11-02 17:36:04 +08:00
commit 4f70b543b2
54 changed files with 1599 additions and 279 deletions

View File

@ -21,7 +21,8 @@ layout(set = 4, binding = 0, rgba32f) uniform image2D positions;
layout(set = 4, binding = 1, rgba32f) uniform image2D normals;
layout(set = 4, binding = 2, rgba8) uniform image2D albedo;
layout(set = 4, binding = 3, r32ui) uniform uimage2D lightLayerData;
layout(set = 4, binding = 4, rgba8) uniform image2D targetImage;
layout(set = 4, binding = 4, r8) uniform image2D ssaoBlurredImage;
layout(set = 4, binding = 5, rgba8) uniform image2D targetImage;
layout(set = 1, binding = 0) uniform LightCounts
{
@ -51,33 +52,46 @@ void main()
vec3 pixelDiffuse = imageLoad (albedo, globalThread).rgb;
// Get position of fragment in world space
vec3 positionWorld = imageLoad (positions, globalThread).rgb;
vec3 positionView = imageLoad (positions, globalThread).rgb;
// normal of fragment
vec3 normalWorld = imageLoad(normals, globalThread).rgb;
vec3 normalView = imageLoad(normals, globalThread).rgb;
// light layer index
uint lightLayer = imageLoad (lightLayerData, globalThread).r;
vec3 fragColor = vec3 (0.0f);
for (int i = 0; i < lightCounts.directionalLights; ++i)
{
// get normalized direction of light
vec3 dLightNormalized = normalize (DirLightData.dLightData[i].direction);
if ((lightLayer & DirLightData.dLightData[i].cullingMask) != 0)
{
// get normalized direction of light
vec3 dLightNormalized = normalize (DirLightData.dLightData[i].direction);
// Get diffuse strength
float diffuseStrength = max (0, dot (dLightNormalized, normalWorld));
// Get diffuse strength
float diffuseStrength = max (0, dot (dLightNormalized, normalView));
// Calculate the fragment color
fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse;
// Calculate the fragment color
fragColor += DirLightData.dLightData[i].diffuseColor.rgb * diffuseStrength.rrr * pixelDiffuse;
}
}
for (int i = 0; i < lightCounts.ambientLights; ++i)
{
// Just do some add
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f);
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0)
{
// Just do some add
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f);
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
}
}
float ssaoVal = imageLoad (ssaoBlurredImage, globalThread).r;
fragColor *= ssaoVal;
// store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor, 1.0f));
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f));
//imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(ssaoVal.rrr, 1.0f));
}

View File

@ -0,0 +1,58 @@
#version 450
#define BLUR_WIDTH 5
#define BLUR_HALF_WIDTH BLUR_WIDTH / 2
#define SHM_WIDTH BLUR_WIDTH + 16 - 1
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 4, binding = 0, r8) uniform image2D ssaoImage;
layout(set = 4, binding = 1, r8) uniform image2D ssaoBlurImage;
float GetSSAOValue(ivec2 uv, ivec2 imageSize)
{
if (uv.x >= 0 && uv.y >= 0 && uv.x < imageSize.x && uv.y < imageSize.y)
{
return imageLoad (ssaoImage, uv).r;
}
return 0.0f;
}
shared float sharedPixels[16 + BLUR_WIDTH - 1][16 + BLUR_WIDTH - 1];
void main()
{
ivec2 globalThread = ivec2 (gl_GlobalInvocationID.xy);
ivec2 localThread = ivec2 (gl_LocalInvocationID.xy);
ivec2 inputImageSize = imageSize(ssaoImage);
// Load color into shared memory
ivec2 start = ivec2 (gl_WorkGroupID) * ivec2 (gl_WorkGroupSize) - (BLUR_HALF_WIDTH);
for (int i = localThread.x; i < SHM_WIDTH; i += int (gl_WorkGroupSize.x))
{
for (int j = localThread.y; j < SHM_WIDTH; j += int (gl_WorkGroupSize.y))
{
float value = GetSSAOValue (start + ivec2 (i, j), inputImageSize);
sharedPixels[i][j] = value;
}
}
// wait for all shared memory to load
barrier();
ivec2 shmStart = ivec2 (localThread + (BLUR_HALF_WIDTH));
float sum = 0;
for (int i = -BLUR_HALF_WIDTH; i <= BLUR_HALF_WIDTH; ++i)
{
for (int j = -BLUR_HALF_WIDTH; j <= BLUR_HALF_WIDTH; ++j)
{
float sharedVal = sharedPixels[shmStart.x + i][shmStart.y + j];
sum += sharedVal;
}
}
sum /= (BLUR_WIDTH * BLUR_WIDTH);
imageStore(ssaoBlurImage, globalThread, vec4(sum.rrr, 1.0f));
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: SSAOBlur_CS
ID: 39760835
Type: 2

104
Assets/Shaders/SSAO_CS.glsl Normal file
View File

@ -0,0 +1,104 @@
#version 450
const uint NUM_SAMPLES = 64;
const uint NUM_ROTATIONS = 16;
const int ROTATION_KERNEL_W = 4;
const int ROTATION_KERNEL_H = 4;
// can perhaps pass in as push constant.
const float RADIUS = 0.5f;
const float BIAS = 0.025f;
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 4, binding = 0, rgba32f) uniform image2D positions;
layout(set = 4, binding = 1, rgba32f) uniform image2D normals;
layout(set = 4, binding = 2, rgba32f) uniform image2D outputImage;
// SSAO data
layout(std430, set = 5, binding = 0) buffer SSAOData
{
vec4 samples[NUM_SAMPLES];
} ssaoData;
layout (set = 5, binding = 1) uniform sampler2D noiseTexture;
layout(set = 2, binding = 0) uniform CameraData
{
vec4 position;
mat4 vpMat;
mat4 viewMat;
mat4 projMat;
} cameraData;
void main()
{
// image size of the SSAO image
ivec2 ssaoSize = imageSize (outputImage);
// global thread
ivec2 globalThread = ivec2 (gl_GlobalInvocationID.xy);
// load all the necessary variables
vec3 viewSpacePos = imageLoad (positions, globalThread).rgb;
vec3 viewSpaceNormal = normalize (imageLoad (normals, globalThread).rgb);
// Get the noise dimension. This should be 4x4
vec2 noiseDim = vec2 (textureSize(noiseTexture, 0));
// Get normlized thread UV coordinates
vec2 threadUV = (vec2(globalThread)) / vec2(ssaoSize);
vec2 noiseUVMult = vec2 (vec2(ssaoSize) / noiseDim);
noiseUVMult *= threadUV;
// sample from the noise
vec3 randomVec = texture(noiseTexture, noiseUVMult).rgb;
// Gram schmidt
vec3 tangent = normalize (randomVec - (viewSpaceNormal * dot(viewSpaceNormal, randomVec)));
vec3 bitangent = normalize (cross (tangent, viewSpaceNormal));
// matrix for tangent space to view space
mat3 TBN = mat3(tangent, bitangent, viewSpaceNormal);
float occlusion = 0.0f;
for (int i = 0; i < NUM_SAMPLES; ++i)
{
// We want to get a position at an offset from the view space position. Offset scaled by radius.
vec3 displacementVector = TBN * ssaoData.samples[i].rgb;
// Why are we adding positions?
displacementVector = viewSpacePos + displacementVector * RADIUS;
// Now we take that offset position and bring it to clip space
vec4 offsetPos = vec4 (displacementVector, 1.0f);
offsetPos = cameraData.projMat * offsetPos;
// then we do perspective division
offsetPos.xyz /= offsetPos.w;
// and bring it from [-1, 1] to screen coordinates
offsetPos.xyz = ((offsetPos.xyz * 0.5f) + 0.5f);
offsetPos.xy *= vec2(ssaoSize.xy);
// Now we attempt to get a position at that point.
float sampleDepth = imageLoad (positions, ivec2 (offsetPos.xy)).z;
// skip checks
if (sampleDepth == 0.0f)
continue;
// if sampled fragment is in front of current fragment, just occlude
float rangeCheck = smoothstep (0.0f, 1.0f, RADIUS / abs (viewSpacePos.z - sampleDepth));
occlusion += (sampleDepth <= displacementVector.z - BIAS ? 1.0f : 0.0f) * rangeCheck;
}
occlusion = 1.0f - (occlusion / float(NUM_SAMPLES));
// store result into result image
imageStore(outputImage, globalThread, occlusion.rrrr);
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: SSAO_CS
ID: 38430899
Type: 2

View File

@ -33,18 +33,31 @@ layout(set = 2, binding = 0) uniform CameraData
{
vec4 position;
mat4 vpMat;
mat4 viewMat;
mat4 projMat;
} cameraData;
void main()
{
Out2.materialIndex = gl_InstanceIndex;
Out2.eid = integerData[0];
Out2.lightLayerIndex = integerData[1];
Out.vertPos = worldTransform * vec4(aVertexPos, 1.0f);
// for transforming gBuffer position and normal data
mat4 modelViewMat = cameraData.viewMat * worldTransform;
// gBuffer position will be in view space
Out.vertPos = modelViewMat * vec4(aVertexPos, 1.0f);
// uvs for texturing in fragment shader
Out.uv = aUV;
Out.normal.rgb = mat3(transpose(inverse(worldTransform))) * aNormal.rgb;
mat3 transposeInv = mat3 (transpose(inverse(modelViewMat)));
// normals are also in view space
Out.normal.rgb = transposeInv * aNormal.rgb;
Out.normal.rgb = normalize (Out.normal.rgb);
// clip space for rendering
gl_Position = cameraData.vpMat * worldTransform * vec4 (aVertexPos, 1.0f);
}

Binary file not shown.

View File

@ -72,6 +72,9 @@ namespace Sandbox
SHSystemManager::CreateSystem<SHAudioSystem>();
SHSystemManager::CreateSystem<SHCameraSystem>();
SHSystemManager::CreateSystem<SHDebugDrawSystem>();
// Link up SHDebugDraw
SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>());
#ifdef SHEDITOR
SDL_Init(SDL_INIT_VIDEO);
@ -91,6 +94,7 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsDebugDraw>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHDebugDrawSystem, SHDebugDrawSystem::ProcessPointsRoutine>();
@ -148,6 +152,13 @@ namespace Sandbox
#endif
SHSystemManager::RunRoutines(editor->editorState != SHEditor::State::PLAY, 0.016f);
editor->PollPicking();
static bool drawColliders = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::SPACE))
{
drawColliders = !drawColliders;
SHSystemManager::GetSystem<SHPhysicsSystem>()->SetDrawColliders(drawColliders);
}
}
// Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution();

View File

@ -269,14 +269,15 @@ namespace SHADE
{
const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
return sphere->GetRadius() / MAX_SCALE;
return (sphere->GetRadius() / MAX_SCALE) * 2.0f;
},
[collider](float const& value) { collider->SetBoundingSphere(value); });
[collider](float const& value) { collider->SetBoundingSphere(value); });
}
else if (collider->GetType() == SHCollider::Type::CAPSULE)
{
}
{
SHEditorWidgets::BeginPanel("Offsets",{ ImGui::GetContentRegionAvail().x, 30.0f });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); });
@ -301,6 +302,9 @@ namespace SHADE
});
SHEditorWidgets::EndPanel();
}
SHEditorWidgets::CheckBox("Is Trigger", [collider] { return collider->IsTrigger(); }, [collider](bool value) { collider->SetIsTrigger(value); });
if (ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data()))
{
colliderToDelete = i;

View File

@ -46,6 +46,7 @@
#include <backends/imgui_impl_vulkan.h>
#include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h"
#include "Tools/SHDebugDraw.h"
RTTR_REGISTRATION
{
@ -77,7 +78,6 @@ namespace SHADE
//#==============================================================#
void SHEditor::Init()
{
IMGUI_CHECKVERSION();
if(auto context = ImGui::CreateContext())
{
@ -120,6 +120,17 @@ namespace SHADE
window->Init();
}
/* Editor View Gridlines */
SetUpGridLines(true, true);
// Handle state changes so that we only show in edit mode
std::shared_ptr<SHEventReceiverSpec<SHEditor>> stateChangeEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHEditor>>(this, &SHEditor::onEditorStateChanged)
};
SHEventManager::SubscribeTo(SH_EDITOR_ON_PLAY_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(stateChangeEventReceiver));
SHEventManager::SubscribeTo(SH_EDITOR_ON_PAUSE_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(stateChangeEventReceiver));
SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(stateChangeEventReceiver));
SHLOG_INFO("Successfully initialised SHADE Engine Editor")
}
@ -180,6 +191,97 @@ namespace SHADE
io->Fonts->Build();
}
void SHEditor::SetUpGridLines(bool drawGrid, bool drawAxes)
{
// Clear existing lines
SHDebugDraw::ClearPersistentDraws();
static constexpr float DELTA = 1.0f;
static constexpr int EXTENT_COUNT = static_cast<int>(500.0f /* TODO: Remove hard code */ / DELTA);
static constexpr float LINE_HALF_LENGTH = (DELTA * static_cast<float>(EXTENT_COUNT)) * 0.5f;
// Render Grid
static const SHColour GRID_COL = { 0.2f, 0.2f, 0.2f, 1.0f };
if (drawGrid)
{
for (int i = 1; i < EXTENT_COUNT; ++i)
{
// X-Axis Lines
SHDebugDraw::PersistentLine
(
GRID_COL,
SHVec3 { -LINE_HALF_LENGTH, 0.0f, i * DELTA },
SHVec3 { LINE_HALF_LENGTH, 0.0f, i * DELTA }
);
SHDebugDraw::PersistentLine
(
GRID_COL,
SHVec3 { -LINE_HALF_LENGTH, 0.0f, i * -DELTA },
SHVec3 { LINE_HALF_LENGTH, 0.0f, i * -DELTA }
);
// Y-Axis Lines
SHDebugDraw::PersistentLine
(
GRID_COL,
SHVec3 { i * DELTA, 0.0f, -LINE_HALF_LENGTH },
SHVec3 { i * DELTA, 0.0f, LINE_HALF_LENGTH }
);
SHDebugDraw::PersistentLine
(
GRID_COL,
SHVec3 { -i * DELTA, 0.0f, -LINE_HALF_LENGTH },
SHVec3 { -i * DELTA, 0.0f, LINE_HALF_LENGTH }
);
}
}
// Render World Axes
if (drawAxes || drawGrid)
{
const SHColour X_AXIS_COL = drawAxes ? SHColour::RED : GRID_COL;
const SHColour Y_AXIS_COL = drawAxes ? SHColour::GREEN : GRID_COL;
const SHColour Z_AXIS_COL = drawAxes ? SHColour::BLUE : GRID_COL;
// X
SHDebugDraw::PersistentLine
(
X_AXIS_COL,
SHVec3 { -LINE_HALF_LENGTH, 0.0f, 0.0f },
SHVec3 { LINE_HALF_LENGTH, 0.0f, 0.0f }
);
// Y
SHDebugDraw::PersistentLine
(
Y_AXIS_COL,
SHVec3 { 0.0f, -LINE_HALF_LENGTH, 0.0f },
SHVec3 { 0.0f, LINE_HALF_LENGTH, 0.0f }
);
// Z
SHDebugDraw::PersistentLine
(
Z_AXIS_COL,
SHVec3 { 0.0f, 0.0f, -LINE_HALF_LENGTH },
SHVec3 { 0.0f, 0.0f, LINE_HALF_LENGTH }
);
}
}
SHEventHandle SHEditor::onEditorStateChanged(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHEditorStateChangeEvent>*>(eventPtr.get());
switch (editorState)
{
case State::PAUSE:
case State::STOP:
SetUpGridLines(true, true);
break;
case State::PLAY:
default:
SHDebugDraw::ClearPersistentDraws();
break;
}
return eventData->handle;
}
void SHEditor::Exit()
{
for (const auto& window : SHEditorWindowManager::editorWindows | std::views::values)

View File

@ -16,8 +16,9 @@
#include "Resource/SHHandle.h"
#include "EditorWindow/SHEditorWindow.h"
#include "Tools/SHLog.h"
#include "Gizmos/SHTransformGizmo.h"
#include "Gizmos/SHTransformGizmo.h"`
#include "Events/SHEventDefines.h"
#include "Events/SHEvent.h"
//#==============================================================#
//|| Library Includes ||
@ -194,6 +195,10 @@ namespace SHADE
void InitFonts() noexcept;
void SetUpGridLines(bool drawGrid, bool drawAxes);
SHEventHandle onEditorStateChanged(SHEventPtr eventPtr);
// Handle to command pool used for ImGui Vulkan Backend
Handle<SHVkCommandPool> imguiCommandPool;
// Handle to command buffer used for ImGui Vulkan Backend

View File

@ -157,7 +157,7 @@ namespace SHADE
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
return ImGui::Checkbox("#", &value);
return ImGui::Checkbox("##", &value);
}
bool SHEditorUI::InputInt(const std::string& label, int& value, bool* isHovered)
{
@ -165,7 +165,7 @@ namespace SHADE
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
return ImGui::InputInt("#", &value,
return ImGui::InputInt("##", &value,
1, 10,
ImGuiInputTextFlags_EnterReturnsTrue);
}
@ -176,7 +176,7 @@ namespace SHADE
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
const bool CHANGED = InputInt("#", signedVal);
const bool CHANGED = InputInt("##", signedVal);
if (CHANGED)
{
signedVal = std::clamp(signedVal, 0, std::numeric_limits<int>::max());
@ -190,7 +190,7 @@ namespace SHADE
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
return ImGui::InputFloat("#", &value,
return ImGui::InputFloat("##", &value,
0.1f, 1.0f, "%.3f",
ImGuiInputTextFlags_EnterReturnsTrue);
}
@ -200,7 +200,7 @@ namespace SHADE
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
return ImGui::InputDouble("#", &value,
return ImGui::InputDouble("##", &value,
0.1, 1.0, "%.3f",
ImGuiInputTextFlags_EnterReturnsTrue);
}
@ -210,7 +210,7 @@ namespace SHADE
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
return ImGui::InputDouble("#", &value,
return ImGui::InputDouble("##", &value,
1.0, 45.0, "%.3f",
ImGuiInputTextFlags_EnterReturnsTrue);
}
@ -280,7 +280,7 @@ namespace SHADE
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
const bool CHANGED = ImGui::InputText("#", &buffer[0], TEXT_FIELD_MAX_LENGTH);
const bool CHANGED = ImGui::InputText("##", &buffer[0], TEXT_FIELD_MAX_LENGTH);
if (CHANGED)
{
value = std::string(buffer.data(), buffer.data() + TEXT_FIELD_MAX_LENGTH);
@ -327,7 +327,7 @@ namespace SHADE
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
if (ImGui::BeginCombo("#", INITIAL_NAME.c_str(), ImGuiComboFlags_None))
if (ImGui::BeginCombo("##", INITIAL_NAME.c_str(), ImGuiComboFlags_None))
{
for (int i = 0; i < enumNames.size(); ++i)
{

View File

@ -64,6 +64,11 @@ namespace SHADE
return bufferUsageFlags;
}
uint32_t SHVkBuffer::GetSizeStored(void) const noexcept
{
return sizeStored;
}
/***************************************************************************/
/*!

View File

@ -102,8 +102,9 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
vk::Buffer GetVkBuffer (void) const noexcept;
vk::Buffer GetVkBuffer (void) const noexcept;
vk::BufferUsageFlags GetUsageBits(void) const noexcept;
uint32_t GetSizeStored (void) const noexcept;
template <typename T>
T GetDataFromMappedPointer(uint32_t index) const noexcept

View File

@ -119,6 +119,18 @@ namespace SHADE
return setIndex;
}
uint32_t SHVkDescriptorSetLayout::GetNumDynamicOffsetsRequired(void) const noexcept
{
uint32_t numDynamicBindings = 0;
for (auto& binding : layoutDesc)
{
if (binding.Type == vk::DescriptorType::eUniformBufferDynamic || binding.Type == vk::DescriptorType::eStorageBufferDynamic)
++numDynamicBindings;
}
return numDynamicBindings;
}
SHVkDescriptorSetLayout& SHVkDescriptorSetLayout::operator=(SHVkDescriptorSetLayout&& rhs) noexcept
{
if (&rhs == this)

View File

@ -99,6 +99,7 @@ namespace SHADE
inline const vk::DescriptorSetLayout& GetVkHandle() const { return setLayout; }
std::vector<Binding> const& GetBindings (void) const noexcept;
SetIndex GetSetIndex (void) const noexcept;
uint32_t GetNumDynamicOffsetsRequired (void) const noexcept;
private:
/*-----------------------------------------------------------------------------*/

View File

@ -79,7 +79,7 @@ namespace SHADE
SHVkDescriptorSetLayout::Binding cameraDataBinding
{
.Type = vk::DescriptorType::eUniformBufferDynamic,
.Stage = vk::ShaderStageFlagBits::eVertex,
.Stage = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eCompute,
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::CAMERA_DATA,
.DescriptorCount = 1,
};

View File

@ -43,20 +43,41 @@ namespace SHADE
return;
}
// Get the system
SHDebugDrawSystem* system = static_cast<SHDebugDrawSystem*>(GetSystem());
// Get current frame index
const uint32_t FRAME_IDX = gfxSys->GetCurrentFrameIndex();
// Create the buffer if it doesn't exist or just update it
SHDebugDrawSystem* system = static_cast<SHDebugDrawSystem*>(GetSystem());
/* Non-Persistent Buffer */
// Update the buffer
system->numPoints[FRAME_IDX] = system->points.size();
const uint32_t DATA_SIZE = sizeof(PointVertex) * system->points.size();
if (DATA_SIZE > 0)
{
system->vertexBuffers[FRAME_IDX]->WriteToMemory(system->points.data(), DATA_SIZE, 0, 0);
system->vertexBuffers[FRAME_IDX]->WriteToMemory(system->points.data(), DATA_SIZE, 0, 0);
}
// Reset for next frame
system->points.clear();
/* Persistent Buffer */
// Check if there are changes
if (system->persistentBuffersCleared[FRAME_IDX]
||
system->numPersistentPoints[FRAME_IDX] != system->persistentPoints.size())
{
// Update Buffer
system->numPersistentPoints[FRAME_IDX] = system->persistentPoints.size();
const uint32_t DATA_SIZE = sizeof(PointVertex) * system->persistentPoints.size();
if (DATA_SIZE > 0)
{
system->persistentVertexBuffers[FRAME_IDX]->WriteToMemory(system->persistentPoints.data(), DATA_SIZE, 0, 0);
}
// Reset Flag
system->persistentBuffersCleared[FRAME_IDX] = false;
}
}
/*---------------------------------------------------------------------------------*/
@ -75,31 +96,63 @@ namespace SHADE
const uint32_t FRAME_IDX = GFX_SYSTEM->GetCurrentFrameIndex();
// Don't draw if no points
if (numPoints[FRAME_IDX] <= 0)
return;
if (numPoints[FRAME_IDX] > 0)
{
cmdBuffer->BindPipeline(GFX_SYSTEM->GetDebugDrawPipeline());
cmdBuffer->SetLineWidth(LineWidth);
cmdBuffer->BindVertexBuffer(0, vertexBuffers[FRAME_IDX], 0);
cmdBuffer->DrawArrays(numPoints[FRAME_IDX], 1, 0, 0);
}
});
auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth");
subPassWithDepth->AddExteriorDrawCalls([this, GFX_SYSTEM](Handle<SHVkCommandBuffer>& cmdBuffer)
{
// Get Current frame index
const uint32_t FRAME_IDX = GFX_SYSTEM->GetCurrentFrameIndex();
cmdBuffer->BindPipeline(GFX_SYSTEM->GetDebugDrawPipeline());
cmdBuffer->SetLineWidth(LineWidth);
cmdBuffer->BindVertexBuffer(0, vertexBuffers[FRAME_IDX], 0);
cmdBuffer->DrawArrays(numPoints[FRAME_IDX], 1, 0, 0);
// Don't draw if no points
if (numPersistentPoints[FRAME_IDX] > 0)
{
cmdBuffer->BindPipeline(GFX_SYSTEM->GetDebugDrawDepthPipeline());
cmdBuffer->SetLineWidth(LineWidth);
cmdBuffer->BindVertexBuffer(0, persistentVertexBuffers[FRAME_IDX], 0);
cmdBuffer->DrawArrays(numPersistentPoints[FRAME_IDX], 1, 0, 0);
}
});
// Reset trackers
std::fill_n(numPoints.begin(), numPoints.size(), 0);
std::fill_n(numPersistentPoints.begin(), numPersistentPoints.size(), 0);
for (bool& cleared : persistentBuffersCleared)
cleared = true;
// Allocate buffers
// - Non-Persistent Draws
static constexpr uint32_t BUFFER_SIZE = MAX_POINTS * sizeof(PointVertex);
for (Handle<SHVkBuffer>& bufHandle : vertexBuffers)
{
bufHandle = GFX_SYSTEM->GetDevice()->CreateBuffer
(
BUFFER_SIZE,
nullptr,
0,
vk::BufferUsageFlagBits::eVertexBuffer,
VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO,
VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT
);
bufHandle = GFX_SYSTEM->GetDevice()->CreateBuffer
(
BUFFER_SIZE,
nullptr,
0,
vk::BufferUsageFlagBits::eVertexBuffer,
VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO,
VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT
);
}
// - Persistent Draws
for (Handle<SHVkBuffer>& bufHandle : persistentVertexBuffers)
{
bufHandle = GFX_SYSTEM->GetDevice()->CreateBuffer
(
BUFFER_SIZE,
nullptr,
0,
vk::BufferUsageFlagBits::eVertexBuffer,
VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO,
VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT
);
}
}
@ -110,6 +163,11 @@ namespace SHADE
if (vertexBuffer)
vertexBuffer.Free();
}
for (auto vertexBuffer : persistentVertexBuffers)
{
if (vertexBuffer)
vertexBuffer.Free();
}
}
/*---------------------------------------------------------------------------------*/
@ -117,54 +175,120 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
void SHDebugDrawSystem::DrawLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt)
{
if (points.size() > MAX_POINTS)
drawLine(points, color, startPt, endPt);
}
void SHDebugDrawSystem::DrawTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3)
{
drawPoly(points, color, { pt1, pt2, pt3 });
}
void SHDebugDrawSystem::DrawQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4)
{
drawPoly(points, color, { pt1, pt2, pt3, pt4 });
}
void SHDebugDrawSystem::DrawPoly(const SHVec4& color, std::initializer_list<SHVec3> pointList)
{
drawPoly(points, color, pointList.begin(), pointList.end());
}
void SHDebugDrawSystem::DrawCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size)
{
drawCube(points, color, pos, size);
}
void SHDebugDrawSystem::DrawSphere(const SHVec4& color, const SHVec3& pos, double radius)
{
drawSphere(points, color, pos, radius);
}
/*---------------------------------------------------------------------------------*/
/* Persistent Draw Functions */
/*---------------------------------------------------------------------------------*/
void SHDebugDrawSystem::DrawPersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt)
{
drawLine(persistentPoints, color, startPt, endPt);
}
void SHDebugDrawSystem::DrawPersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3)
{
drawPoly(persistentPoints, color, { pt1, pt2, pt3 });
}
void SHDebugDrawSystem::DrawPersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4)
{
drawPoly(persistentPoints, color, { pt1, pt2, pt3, pt4 });
}
void SHDebugDrawSystem::DrawPersistentPoly(const SHVec4& color, std::initializer_list<SHVec3> pointList)
{
drawPoly(persistentPoints, color, pointList.begin(), pointList.end());
}
void SHDebugDrawSystem::DrawPersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size)
{
drawCube(persistentPoints, color, pos, size);
}
void SHDebugDrawSystem::DrawPersistentSphere(const SHVec4& color, const SHVec3& pos, double radius)
{
drawSphere(persistentPoints, color, pos, radius);
}
void SHDebugDrawSystem::ClearPersistentDraws()
{
persistentPoints.clear();
for (bool& cleared : persistentBuffersCleared)
cleared = true;
}
void SHDebugDrawSystem::drawLine(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt)
{
if (storage.size() > MAX_POINTS)
{
SHLOG_WARNING("[DebugDraw] Exceeded maximum size of drawable debug elements.");
return;
}
points.emplace_back(PointVertex{ startPt, color });
points.emplace_back(PointVertex{ endPt, color });
storage.emplace_back(PointVertex{ startPt, color });
storage.emplace_back(PointVertex{ endPt, color });
}
void SHDebugDrawSystem::DrawTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3)
void SHDebugDrawSystem::drawLineSet(std::vector<PointVertex>& storage, const SHVec4& color, std::initializer_list<SHVec3> pointList)
{
DrawPoly(color, { pt1, pt2, pt3 });
drawLineSet(storage, color, pointList.begin(), pointList.end());
}
void SHDebugDrawSystem::DrawQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4)
void SHDebugDrawSystem::drawPoly(std::vector<PointVertex>& storage, const SHVec4& color, std::initializer_list<SHVec3> pointList)
{
DrawPoly(color, { pt1, pt2, pt3, pt4 });
drawPoly(storage, color, pointList.begin(), pointList.end());
}
void SHDebugDrawSystem::DrawPoly(const SHVec4& color, std::initializer_list<SHVec3> pointList)
void SHDebugDrawSystem::drawCube(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, const SHVec3& size)
{
DrawPoly(color, pointList.begin(), pointList.end());
}
static const SHVec3 EXTENTS = SHVec3{ 0.5f, 0.5f, 0.5f };
static const SHVec3 UNIT_BOT_LEFT_FRONT = SHVec3{ pos - EXTENTS };
static const SHVec3 UNIT_BOT_RIGHT_FRONT = SHVec3{ pos + SHVec3 { EXTENTS.x, -EXTENTS.y, -EXTENTS.z } };
static const SHVec3 UNIT_BOT_RIGHT_BACK = SHVec3{ pos + SHVec3 { EXTENTS.x, -EXTENTS.y, EXTENTS.z } };
static const SHVec3 UNIT_BOT_LEFT_BACK = SHVec3{ pos + SHVec3 { -EXTENTS.x, -EXTENTS.y, EXTENTS.z } };
static const SHVec3 UNIT_TOP_LEFT_BACK = SHVec3{ pos + SHVec3 { -EXTENTS.x, EXTENTS.y, EXTENTS.z } };
static const SHVec3 UNIT_TOP_RIGHT_FRONT = SHVec3{ pos + SHVec3 { EXTENTS.x, EXTENTS.y, -EXTENTS.z } };
static const SHVec3 UNIT_TOP_LEFT_FRONT = SHVec3{ pos + SHVec3 { -EXTENTS.x, EXTENTS.y, -EXTENTS.z } };
static const SHVec3 UNIT_TOP_RIGHT_BACK = SHVec3{ pos + EXTENTS };
void SHDebugDrawSystem::DrawCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size)
{
static const SHVec3 EXTENTS = SHVec3 { 0.5f, 0.5f, 0.5f };
static const SHVec3 UNIT_BOT_LEFT_FRONT = SHVec3 { pos - EXTENTS };
static const SHVec3 UNIT_BOT_RIGHT_FRONT = SHVec3 { pos + SHVec3 { EXTENTS.x, -EXTENTS.y, -EXTENTS.z } };
static const SHVec3 UNIT_BOT_RIGHT_BACK = SHVec3 { pos + SHVec3 { EXTENTS.x, -EXTENTS.y, EXTENTS.z } };
static const SHVec3 UNIT_BOT_LEFT_BACK = SHVec3 { pos + SHVec3 { -EXTENTS.x, -EXTENTS.y, EXTENTS.z } };
static const SHVec3 UNIT_TOP_LEFT_BACK = SHVec3 { pos + SHVec3 { -EXTENTS.x, EXTENTS.y, EXTENTS.z } };
static const SHVec3 UNIT_TOP_RIGHT_FRONT = SHVec3 { pos + SHVec3 { EXTENTS.x, EXTENTS.y, -EXTENTS.z } };
static const SHVec3 UNIT_TOP_LEFT_FRONT = SHVec3 { pos + SHVec3 { -EXTENTS.x, EXTENTS.y, -EXTENTS.z } };
static const SHVec3 UNIT_TOP_RIGHT_BACK = SHVec3 { pos + EXTENTS };
const SHVec3 BOT_LEFT_BACK = UNIT_BOT_LEFT_BACK * size;
const SHVec3 BOT_RIGHT_BACK = UNIT_BOT_RIGHT_BACK * size;
const SHVec3 BOT_LEFT_FRONT = UNIT_BOT_LEFT_FRONT * size;
const SHVec3 BOT_LEFT_BACK = UNIT_BOT_LEFT_BACK * size;
const SHVec3 BOT_RIGHT_BACK = UNIT_BOT_RIGHT_BACK * size;
const SHVec3 BOT_LEFT_FRONT = UNIT_BOT_LEFT_FRONT * size;
const SHVec3 BOT_RIGHT_FRONT = UNIT_BOT_RIGHT_FRONT * size;
const SHVec3 TOP_LEFT_BACK = UNIT_TOP_LEFT_BACK * size;
const SHVec3 TOP_RIGHT_BACK = UNIT_TOP_RIGHT_BACK * size;
const SHVec3 TOP_LEFT_FRONT = UNIT_TOP_LEFT_FRONT * size;
const SHVec3 TOP_LEFT_BACK = UNIT_TOP_LEFT_BACK * size;
const SHVec3 TOP_RIGHT_BACK = UNIT_TOP_RIGHT_BACK * size;
const SHVec3 TOP_LEFT_FRONT = UNIT_TOP_LEFT_FRONT * size;
const SHVec3 TOP_RIGHT_FRONT = UNIT_TOP_RIGHT_FRONT * size;
DrawPoly
drawLineSet
(
storage,
color,
{
// Bottom Square
@ -186,7 +310,7 @@ namespace SHADE
);
}
void SHDebugDrawSystem::DrawSphere(const SHVec4& color, const SHVec3& pos, double radius)
void SHDebugDrawSystem::drawSphere(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, double radius)
{
if (spherePoints.empty())
{
@ -197,6 +321,6 @@ namespace SHADE
spherePoints.emplace_back(SPHERE.VertexPositions[idx]);
}
}
DrawPoly(color, spherePoints.begin(), spherePoints.end());
drawLineSet(storage, color, spherePoints.begin(), spherePoints.end());
}
}

View File

@ -126,6 +126,82 @@ namespace SHADE
/// <param name="size">Size of the rendered sphere.</param>
void DrawSphere(const SHVec4& color, const SHVec3& pos, double radius);
/*---------------------------------------------------------------------------------*/
/* Persistent Draw Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Renders a line between two points in world space that will persist until
/// ClearPersistentDraws() is called. These lines are depth tested.
/// </summary>
/// <param name="color">Colour of the line.</param>
/// <param name="startPt">First point of the line.</param>
/// <param name="endPt">Second point of the line.</param>
void DrawPersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt);
/// <summary>
/// Renders a triangle indicated by three points in world space that will persist
/// until ClearPersistentDraws() is called. These lines are depth tested.
/// </summary>
/// <param name="color">Colour of the triangle.</param>
/// <param name="pt1">First point of the triangle.</param>
/// <param name="pt2">Second point of the triangle.</param>
/// <param name="pt3">Third point of the triangle.</param>
void DrawPersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3);
/// <summary>
/// Renders a quadrilateral indicated by four points in world space that will persist
/// until ClearPersistentDraws() is called. These lines are depth tested.
/// </summary>
/// <param name="color">Colour of the quadrilateral.</param>
/// <param name="pt1">First point of the triangle.</param>
/// <param name="pt2">Second point of the quadrilateral.</param>
/// <param name="pt3">Third point of the quadrilateral.</param>
/// <param name="pt4">Third point of the quadrilateral.</param>
void DrawPersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4);
/// <summary>
/// Renders a polygon indicated by the specified set of points in world space that
/// will persist until ClearPersistentDraws() is called. These lines are depth
/// tested.
/// </summary>
/// <param name="color">Colour of the polygon.</param>
/// <param name="pointList">List of points for the polygon.</param>
void DrawPersistentPoly(const SHVec4& color, std::initializer_list<SHVec3> pointList);
/// <summary>
/// Renders a polygon indicated by the specified set of points in world space that
/// will persist until ClearPersistentDraws() is called. These lines are depth
/// tested.
/// </summary>
/// <typeparam name="IterType">Iterator for a STL-like container.</typeparam>
/// <param name="color">Colour of the polygon.</param>
/// <param name="pointListBegin">
/// Iterator to the first point of the point container.
/// </param>
/// <param name="pointListEnd">
/// One past last iterator of the point container.
/// </param>
template<typename IterType>
void DrawPersistentPoly(const SHVec4& color, IterType pointListBegin, IterType pointListEnd);
/// <summary>
/// Renders a wireframe cube centered around the position specified in world space
/// that will persist until ClearPersistentDraws() is called. These lines are depth
/// tested.
/// </summary>
/// <param name="color">Colour of the cube.</param>
/// <param name="pos">Position where the cube wil be centered at.</param>
/// <param name="size">Size of the rendered cube.</param>
void DrawPersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size);
/// <summary>
/// Renders a wireframe sphere centered around the position specified in world space
/// that will persist until ClearPersistentDraws() is called. These lines are depth
/// tested.
/// </summary>
/// <param name="color">Colour of the sphere.</param>
/// <param name="pos">Position where the sphere wil be centered at.</param>
/// <param name="size">Size of the rendered sphere.</param>
void DrawPersistentSphere(const SHVec4& color, const SHVec3& pos, double radius);
/// <summary>
/// Clears any persistent drawn debug primitives.
/// </summary>
void ClearPersistentDraws();
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
@ -136,7 +212,8 @@ namespace SHADE
SHVec4 Color;
};
using TripleBuffer = std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleUInt = std::array<uint32_t, SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleUInt = std::array<uint32_t , SHGraphicsConstants::NUM_FRAME_BUFFERS>;
using TripleBool = std::array<bool , SHGraphicsConstants::NUM_FRAME_BUFFERS>;
/*---------------------------------------------------------------------------------*/
/* Constants */
@ -148,11 +225,28 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
// CPU Buffers
std::vector<PointVertex> points;
std::vector<PointVertex> persistentPoints;
// GPU Buffers
TripleBuffer vertexBuffers;
TripleUInt numPoints;
TripleBuffer persistentVertexBuffers;
TripleUInt numPersistentPoints;
TripleBool persistentBuffersCleared;
// Cached Points for polygon drawing
std::vector<SHVec3> spherePoints;
/*---------------------------------------------------------------------------------*/
/* Helper Draw Functions */
/*---------------------------------------------------------------------------------*/
void drawLine(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt);
void drawLineSet(std::vector<PointVertex>& storage, const SHVec4& color, std::initializer_list<SHVec3> pointList);
template<typename IterType>
void drawLineSet(std::vector<PointVertex>& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd);
void drawPoly(std::vector<PointVertex>& storage, const SHVec4& color, std::initializer_list<SHVec3> pointList);
template<typename IterType>
void drawPoly(std::vector<PointVertex>& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd);
void drawCube(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, const SHVec3& size);
void drawSphere(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, double radius);
};
}

View File

@ -20,12 +20,21 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
template<typename IterType>
void SHDebugDrawSystem::DrawPoly(const SHVec4& color, IterType pointListBegin, IterType pointListEnd)
{
drawPoly(points, color, pointListBegin, pointListEnd);
}
/*-----------------------------------------------------------------------------------*/
/* Helper Draw Functions */
/*-----------------------------------------------------------------------------------*/
template<typename IterType>
void SHDebugDrawSystem::drawLineSet(std::vector<PointVertex>& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd)
{
// Ensure dereferenced type is SHVec3
static_assert(std::is_same_v<SHVec3, std::remove_cvref_t<decltype(*pointListBegin)>>, "Parameters to DrawPoly must be SHVec3.");
// Check if points exceeded max
if (points.size() > MAX_POINTS)
if (storage.size() > MAX_POINTS)
{
SHLOG_WARNING("[DebugDraw] Exceeded maximum size of drawable debug elements.");
return;
@ -42,7 +51,39 @@ namespace SHADE
const size_t POINTS_ROUNDED_COUNT = POINTS_COUNT / 2 * 2;
for (auto pointIter = pointListBegin; pointIter != (pointListBegin + POINTS_ROUNDED_COUNT); ++pointIter)
{
points.emplace_back(PointVertex{ *pointIter, color });
storage.emplace_back(PointVertex{ *pointIter, color });
}
}
template<typename IterType>
void SHDebugDrawSystem::drawPoly(std::vector<PointVertex>& storage, const SHVec4& color, IterType pointListBegin, IterType pointListEnd)
{
// Ensure dereferenced type is SHVec3
static_assert(std::is_same_v<SHVec3, std::remove_cvref_t<decltype(*pointListBegin)>>, "Parameters to DrawPoly must be SHVec3.");
// Check if points exceeded max
if (storage.size() > MAX_POINTS)
{
SHLOG_WARNING("[DebugDraw] Exceeded maximum size of drawable debug elements.");
return;
}
const size_t POINTS_COUNT = pointListEnd - pointListBegin;
// Invalid polygon
if (POINTS_COUNT < 2)
{
SHLOG_WARNING("[SHDebugDraw] Invalid polygon provided to DrawPoly().");
return;
}
// Trace the polygon
for (auto pointIter = pointListBegin + 1; pointIter != pointListEnd; ++pointIter)
{
storage.emplace_back(PointVertex{ *(pointIter - 1), color });
storage.emplace_back(PointVertex{ *pointIter , color });
}
// Close the line loop
storage.emplace_back(PointVertex{ *(pointListEnd - 1), color });
storage.emplace_back(PointVertex{ *pointListBegin , color });
}
}

View File

@ -70,7 +70,17 @@ namespace SHADE
*/
/***************************************************************************/
static constexpr uint32_t RENDERGRAPH_RESOURCE = 4;
/***************************************************************************/
/*!
\brief
DescriptorSet Index for render graph node compute resources. For data
that we wish to pass to compute shaders in the render graph, this is
the set to use. Unlike the sets from 1 to 3, this set index does not have
hard coded bindings and is NOT part of the layouts included in the global
data.
*/
/***************************************************************************/
static constexpr uint32_t RENDERGRAPH_NODE_COMPUTE_RESOURCE = 5;
};
@ -119,6 +129,7 @@ namespace SHADE
*/
/***************************************************************************/
static constexpr uint32_t BATCHED_PER_INST_DATA = 0;
};
struct VertexBufferBindings

View File

@ -40,6 +40,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Assets/SHAssetManager.h"
#include "Resource/SHResourceManager.h"
#include "Graphics/SHVkUtil.h"
#include "Graphics/RenderGraph/SHRenderGraphNodeCompute.h"
namespace SHADE
{
@ -115,6 +116,8 @@ namespace SHADE
static constexpr AssetID VS_DEBUG = 48002439; debugVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEBUG);
static constexpr AssetID FS_DEBUG = 36671027; debugFragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(FS_DEBUG);
static constexpr AssetID CS_COMPOSITE = 45072428; deferredCompositeShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(CS_COMPOSITE);
static constexpr AssetID SSAO = 38430899; ssaoShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(SSAO);
static constexpr AssetID SSAO_BLUR = 39760835; ssaoBlurShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(SSAO_BLUR);
}
void SHGraphicsSystem::InitSceneRenderGraph(void) noexcept
@ -153,52 +156,109 @@ namespace SHADE
renderContextCmdPools[i] = renderContext.GetFrameData(i).cmdPoolHdls[0];
}
/*-----------------------------------------------------------------------*/
/* SCENE RENDER GRAPH RESOURCES */
/*-----------------------------------------------------------------------*/
// Initialize world render graph
worldRenderGraph->Init(device, swapchain);
worldRenderGraph->AddResource("Position", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
worldRenderGraph->AddResource("Normals", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
//worldRenderGraph->AddResource("Tangents", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32G32B32A32Sfloat);
worldRenderGraph->AddResource("Albedo", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("Depth Buffer", { SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL }, windowDims.first, windowDims.second, vk::Format::eD32SfloatS8Uint);
worldRenderGraph->AddResource("Entity ID", { SH_ATT_DESC_TYPE_FLAGS::COLOR }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Light Layer Indices", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR32Uint, 1, vk::ImageUsageFlagBits::eTransferSrc);
worldRenderGraph->AddResource("Scene", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second);
worldRenderGraph->AddResource("SSAO", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
worldRenderGraph->AddResource("SSAO Blur", { SH_ATT_DESC_TYPE_FLAGS::COLOR, SH_ATT_DESC_TYPE_FLAGS::INPUT, SH_ATT_DESC_TYPE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
/*-----------------------------------------------------------------------*/
/* MAIN NODE */
/*-----------------------------------------------------------------------*/
auto gBufferNode = worldRenderGraph->AddNode("G-Buffer",
{
"Position",
"Entity ID",
"Light Layer Indices",
"Normals",
//"Tangents",
"Albedo",
"Depth Buffer",
"Scene"
"Scene",
"SSAO",
"SSAO Blur"
},
{}); // no predecessors
/*-----------------------------------------------------------------------*/
/* G-BUFFER SUBPASS INIT */
/*-----------------------------------------------------------------------*/
auto gBufferSubpass = gBufferNode->AddSubpass("G-Buffer Write");
gBufferSubpass->AddColorOutput("Position");
gBufferSubpass->AddColorOutput("Entity ID");
gBufferSubpass->AddColorOutput("Light Layer Indices");
gBufferSubpass->AddColorOutput("Normals");
//gBufferSubpass->AddColorOutput("Tangents");
gBufferSubpass->AddColorOutput("Albedo");
gBufferSubpass->AddDepthOutput("Depth Buffer", SH_ATT_DESC_TYPE_FLAGS::DEPTH_STENCIL);
// deferred composite
gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "Scene" });
/*-----------------------------------------------------------------------*/
/* SSAO PASS AND DATA INIT */
/*-----------------------------------------------------------------------*/
ssaoStorage = resourceManager.Create<SHSSAO>();
// Set up Debug Draw Pass
auto debugDrawNode = worldRenderGraph->AddNode("Debug Draw", { "Scene" }, {"G-Buffer"});
ssaoTransferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
ssaoTransferCmdBuffer->BeginRecording();
ssaoStorage->Init(device, ssaoTransferCmdBuffer);
ssaoTransferCmdBuffer->EndRecording();
graphicsQueue->SubmitCommandBuffer({ ssaoTransferCmdBuffer });
// Set up Debug Draw Passes
// - Depth Tested
auto debugDrawNodeDepth = worldRenderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer"});
auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth");
debugDrawDepthSubpass->AddColorOutput("Scene");
debugDrawDepthSubpass->AddDepthOutput("Depth Buffer");
// - No Depth Test
auto debugDrawNode = worldRenderGraph->AddNode("Debug Draw", { "Scene" }, { "Debug Draw with Depth" });
auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw");
debugDrawSubpass->AddColorOutput("Scene");
graphicsQueue->WaitIdle();
ssaoStorage->PrepareRotationVectorsVkData(device);
Handle<SHRenderGraphNodeCompute> ssaoPass = gBufferNode->AddNodeCompute(ssaoShader, {"Position", "Normals", "SSAO"});
auto ssaoDataBuffer = ssaoStorage->GetBuffer();
ssaoPass->ModifyWriteDescBufferComputeResource(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE, SHSSAO::DESC_SET_BUFFER_BINDING, { &ssaoDataBuffer, 1 }, 0, ssaoStorage->GetBuffer()->GetSizeStored());
auto viewSamplerLayout = ssaoStorage->GetViewSamplerLayout();
ssaoPass->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE, SHSSAO::DESC_SET_IMAGE_BINDING, {&viewSamplerLayout, 1});
Handle<SHRenderGraphNodeCompute> ssaoBlurPass = gBufferNode->AddNodeCompute(ssaoBlurShader, { "SSAO", "SSAO Blur"});
/*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE SUBPASS INIT */
/*-----------------------------------------------------------------------*/
gBufferNode->AddNodeCompute(deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" });
// Dummy Node
auto dummyNode = worldRenderGraph->AddNode("Dummy Pass", { "Scene" }, { "Debug Draw" }); // no predecessors
auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass");
dummySubpass->AddInput("Scene");
/*-----------------------------------------------------------------------*/
/* GENERATE RENDER GRAPH */
/*-----------------------------------------------------------------------*/
// Generate world render graph
worldRenderGraph->Generate();
/*-----------------------------------------------------------------------*/
/* BIND RENDER GRAPH TO RENDERER */
/*-----------------------------------------------------------------------*/
// Add world renderer to default viewport
worldRenderer = worldViewport->AddRenderer(resourceManager, swapchain->GetNumImages(), renderContextCmdPools, descPool, SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS], worldRenderGraph);
worldRenderer->SetCamera(worldCamera);
@ -209,53 +269,8 @@ namespace SHADE
defaultMaterial = AddMaterial(defaultVertShader, defaultFragShader, gBufferSubpass);
// Create debug draw pipeline
auto debugDrawPipelineLayout = resourceManager.Create<SHVkPipelineLayout>
(
device, SHPipelineLayoutParams
{
.shaderModules = { debugVertShader, debugFragShader },
.globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts()
}
);
debugDrawPipeline = resourceManager.Create<SHVkPipeline>(device, debugDrawPipelineLayout, nullptr, debugDrawNode->GetRenderpass(), debugDrawSubpass);
debugDrawPipeline->GetPipelineState().SetRasterizationState(SHRasterizationState
{
.polygonMode = vk::PolygonMode::eLine,
.cull_mode = vk::CullModeFlagBits::eNone
});
debugDrawPipeline->GetPipelineState().SetInputAssemblyState(SHInputAssemblyState
{
.topology = vk::PrimitiveTopology::eLineList
});
SHVertexInputState debugDrawVertexInputState;
debugDrawVertexInputState.AddBinding(false, true, { SHVertexAttribute(SHAttribFormat::FLOAT_4D), SHVertexAttribute(SHAttribFormat::FLOAT_4D) });
debugDrawPipeline->GetPipelineState().SetVertexInputState(debugDrawVertexInputState);
SHColorBlendState colorBlendState{};
colorBlendState.logic_op_enable = VK_FALSE;
colorBlendState.logic_op = vk::LogicOp::eCopy;
auto const& subpassColorReferences = debugDrawSubpass->GetColorAttachmentReferences();
colorBlendState.attachments.reserve(subpassColorReferences.size());
for (auto& att : subpassColorReferences)
{
colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState
{
.blendEnable = SHVkUtil::IsBlendCompatible(debugDrawSubpass->GetFormatFromAttachmentReference(att.attachment)),
.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha,
.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
.colorBlendOp = vk::BlendOp::eAdd,
.srcAlphaBlendFactor = vk::BlendFactor::eOne,
.dstAlphaBlendFactor = vk::BlendFactor::eZero,
.alphaBlendOp = vk::BlendOp::eAdd,
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
}
);
}
debugDrawPipeline->GetPipelineState().SetColorBlenState(colorBlendState);
debugDrawPipeline->ConstructPipeline();
debugDrawPipeline = createDebugDrawPipeline(debugDrawNode->GetRenderpass(), debugDrawSubpass);
debugDrawDepthPipeline = createDebugDrawPipeline(debugDrawNodeDepth->GetRenderpass(), debugDrawDepthSubpass);
}
void SHGraphicsSystem::InitMiddleEnd(void) noexcept
@ -294,6 +309,7 @@ namespace SHADE
lightingSubSystem = resourceManager.Create<SHLightingSubSystem>();
lightingSubSystem->Init(device, descPool);
}
#ifdef SHEDITOR
@ -399,6 +415,17 @@ namespace SHADE
auto cameraSystem = SHSystemManager::GetSystem<SHCameraSystem>();
{
#ifdef SHEDITOR
auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
if (editorSystem->editorState != SHEditor::State::PLAY)
lightingSubSystem->Run(cameraSystem->GetEditorCamera()->GetViewMatrix(), frameIndex);
else
lightingSubSystem->Run(worldRenderer->GetCameraDirector()->GetViewMatrix(), frameIndex);
#else
lightingSubSystem->Run(worldRenderer->GetCameraDirector()->GetViewMatrix(), frameIndex);
#endif
}
// For every viewport
for (int vpIndex = 0; vpIndex < static_cast<int>(viewports.size()); ++vpIndex)
@ -435,8 +462,7 @@ namespace SHADE
currentCmdBuffer->BindIndexBuffer(buffer, 0);
}
// Bind the descriptor set for lights
lightingSubSystem->Run(currentCmdBuffer, frameIndex);
lightingSubSystem->BindDescSet(currentCmdBuffer, frameIndex);
// Bind textures
auto textureDescSet = texLibrary.GetTextureDescriptorSetGroup();
@ -460,7 +486,7 @@ namespace SHADE
{
auto editorSystem = SHSystemManager::GetSystem<SHEditor>();
if (editorSystem->editorState != SHEditor::State::PLAY)
worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, SHMatrix::Transpose(cameraSystem->GetEditorCamera()->GetProjMatrix() * cameraSystem->GetEditorCamera()->GetViewMatrix()));
worldRenderer->UpdateDataAndBind(currentCmdBuffer, frameIndex, cameraSystem->GetEditorCamera()->GetViewMatrix(), cameraSystem->GetEditorCamera()->GetProjMatrix());
else
renderers[renIndex]->UpdateDataAndBind(currentCmdBuffer, frameIndex);
}
@ -867,5 +893,57 @@ namespace SHADE
return worldRenderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data());
}
Handle<SHVkPipeline> SHGraphicsSystem::createDebugDrawPipeline(Handle<SHVkRenderpass> renderPass, Handle<SHSubpass> subpass)
{
auto pipelineLayout = resourceManager.Create<SHVkPipelineLayout>
(
device, SHPipelineLayoutParams
{
.shaderModules = { debugVertShader, debugFragShader },
.globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts()
}
);
auto pipeline = resourceManager.Create<SHVkPipeline>(device, pipelineLayout, nullptr, renderPass, subpass);
pipeline->GetPipelineState().SetRasterizationState(SHRasterizationState
{
.polygonMode = vk::PolygonMode::eLine,
.cull_mode = vk::CullModeFlagBits::eNone
});
pipeline->GetPipelineState().SetInputAssemblyState(SHInputAssemblyState
{
.topology = vk::PrimitiveTopology::eLineList
});
SHVertexInputState debugDrawVertexInputState;
debugDrawVertexInputState.AddBinding(false, true, { SHVertexAttribute(SHAttribFormat::FLOAT_4D), SHVertexAttribute(SHAttribFormat::FLOAT_4D) });
pipeline->GetPipelineState().SetVertexInputState(debugDrawVertexInputState);
SHColorBlendState colorBlendState{};
colorBlendState.logic_op_enable = VK_FALSE;
colorBlendState.logic_op = vk::LogicOp::eCopy;
auto const& subpassColorReferences = subpass->GetColorAttachmentReferences();
colorBlendState.attachments.reserve(subpassColorReferences.size());
for (auto& att : subpassColorReferences)
{
colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState
{
.blendEnable = SHVkUtil::IsBlendCompatible(subpass->GetFormatFromAttachmentReference(att.attachment)),
.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha,
.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
.colorBlendOp = vk::BlendOp::eAdd,
.srcAlphaBlendFactor = vk::BlendFactor::eOne,
.dstAlphaBlendFactor = vk::BlendFactor::eZero,
.alphaBlendOp = vk::BlendOp::eAdd,
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
});
}
pipeline->GetPipelineState().SetColorBlenState(colorBlendState);
pipeline->ConstructPipeline();
return pipeline;
}
#pragma endregion MISC
}

View File

@ -31,6 +31,7 @@ of DigiPen Institute of Technology is prohibited.
#include "../Textures/SHVkSamplerCache.h"
#include "Graphics/MiddleEnd/Interface/SHPostOffscreenRenderSystem.h"
#include "Graphics/MiddleEnd/Lights/SHLightingSubSystem.h"
#include "Graphics/MiddleEnd/PostProcessing/SHSSAO.h"
namespace SHADE
{
@ -289,6 +290,7 @@ namespace SHADE
Handle<SHPostOffscreenRenderSystem> GetPostOffscreenRenderSystem(void) const noexcept {return postOffscreenRender;};
Handle<SHRenderGraphNode> GetPrimaryRenderpass() const noexcept;
Handle<SHVkPipeline> GetDebugDrawPipeline(void) const noexcept { return debugDrawPipeline; }
Handle<SHVkPipeline> GetDebugDrawDepthPipeline(void) const noexcept { return debugDrawDepthPipeline; }
uint32_t GetCurrentFrameIndex(void) const noexcept { return renderContext.GetCurrentFrame(); }
/*-----------------------------------------------------------------------------*/
@ -315,6 +317,7 @@ namespace SHADE
Handle<SHVkDescriptorPool> descPool;
Handle<SHVkCommandPool> graphicsCmdPool;
Handle<SHVkCommandBuffer> transferCmdBuffer;
Handle<SHVkCommandBuffer> ssaoTransferCmdBuffer;
Handle<SHVkCommandBuffer> graphicsTexCmdBuffer;
SHRenderContext renderContext;
std::array<Handle<SHVkSemaphore>, 2> graphSemaphores;
@ -351,10 +354,14 @@ namespace SHADE
Handle<SHVkShaderModule> debugVertShader;
Handle<SHVkShaderModule> debugFragShader;
Handle<SHVkShaderModule> deferredCompositeShader;
Handle<SHVkShaderModule> ssaoShader;
Handle<SHVkShaderModule> ssaoBlurShader;
// Built-In Materials
Handle<SHMaterial> defaultMaterial;
Handle<SHVkPipeline> debugDrawPipeline;
Handle<SHVkPipeline> debugDrawDepthPipeline;
Handle<SHRenderGraph> worldRenderGraph;
@ -362,10 +369,15 @@ namespace SHADE
Handle<SHMousePickSystem> mousePickSystem;
Handle<SHPostOffscreenRenderSystem> postOffscreenRender;
Handle<SHLightingSubSystem> lightingSubSystem;
Handle<SHSSAO> ssaoStorage;
uint32_t resizeWidth;
uint32_t resizeHeight;
bool restoredFromMinimize = false;
uint32_t resizeWidth = 1;
uint32_t resizeHeight = 1;
bool restoredFromMinimize = false;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
Handle<SHVkPipeline> createDebugDrawPipeline(Handle<SHVkRenderpass> renderPass, Handle<SHSubpass> subpass);
};
}

View File

@ -83,13 +83,14 @@ namespace SHADE
{
if (camera && cameraDirector)
{
UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix()));
//UpdateDataAndBind(cmdBuffer, frameIndex, SHMatrix::Transpose(cameraDirector->GetVPMatrix()));
UpdateDataAndBind(cmdBuffer, frameIndex, cameraDirector->GetViewMatrix(), cameraDirector->GetProjMatrix());
}
}
void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept
void SHRenderer::UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept
{
SetViewProjectionMatrix(exteriorMatrix);
SetViewProjectionMatrix(viewMatrix, projMatrix);
//cpuCameraData.viewProjectionMatrix = camera->GetViewProjectionMatrix();
cameraBuffer->WriteToMemory(&cpuCameraData, sizeof(SHShaderCameraData), 0, cameraDataAlignedSize * frameIndex);
@ -97,16 +98,19 @@ namespace SHADE
std::array<uint32_t, 1> dynamicOffsets{ frameIndex * cameraDataAlignedSize };
cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
cmdBuffer->BindDescriptorSet(cameraDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::HIGH_FREQUENCY_GLOBALS, std::span{ dynamicOffsets.data(), 1 });
}
void SHRenderer::UpdateCameraDataToBuffer(void) noexcept
{
}
void SHRenderer::SetViewProjectionMatrix(SHMatrix const& vpMatrix) noexcept
void SHRenderer::SetViewProjectionMatrix(SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept
{
//cpuCameraData.viewProjectionMatrix = camera->GetViewMatrix() * camera->GetProjectionMatrix();
cpuCameraData.viewProjectionMatrix = vpMatrix;
cpuCameraData.viewProjectionMatrix = SHMatrix::Transpose(projMatrix * viewMatrix);
cpuCameraData.viewMatrix = SHMatrix::Transpose(viewMatrix);
cpuCameraData.projectionMatrix = SHMatrix::Transpose(projMatrix);
}
Handle<SHRenderGraph> SHRenderer::GetRenderGraph(void) const noexcept
@ -119,4 +123,9 @@ namespace SHADE
return commandBuffers[frameIndex];
}
Handle<SHCameraDirector> SHRenderer::GetCameraDirector(void) const noexcept
{
return cameraDirector;
}
}

View File

@ -46,6 +46,8 @@ namespace SHADE
{
SHVec4 cameraPosition;
SHMatrix viewProjectionMatrix;
SHMatrix viewMatrix;
SHMatrix projectionMatrix;
};
/*---------------------------------------------------------------------------------*/
@ -79,15 +81,16 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
void Draw(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix exteriorMatrix) noexcept;
void UpdateDataAndBind(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept;
void UpdateCameraDataToBuffer (void) noexcept;
void SetViewProjectionMatrix (SHMatrix const& vpMatrix) noexcept;
void SetViewProjectionMatrix (SHMatrix const& viewMatrix, SHMatrix const& projMatrix) noexcept;
/*-----------------------------------------------------------------------------*/
/* Setters and Getters */
/*-----------------------------------------------------------------------------*/
Handle<SHRenderGraph> GetRenderGraph (void) const noexcept;
Handle<SHRenderGraph> GetRenderGraph (void) const noexcept;
Handle<SHVkCommandBuffer> GetCommandBuffer(uint32_t frameIndex) const noexcept;
Handle<SHCameraDirector> GetCameraDirector (void) const noexcept;
private:
/*-----------------------------------------------------------------------------*/

View File

@ -9,9 +9,9 @@ namespace SHADE
{
lightData.Reset();
SetType(SH_LIGHT_TYPE::DIRECTIONAL);
indexInBuffer = std::numeric_limits<uint32_t>::max();
//indexInBuffer = std::numeric_limits<uint32_t>::max();
isActive = true;
Unbind();
//Unbind();
}
@ -23,28 +23,28 @@ namespace SHADE
void SHLightComponent::SetPosition(SHVec3 const& position) noexcept
{
lightData.position = position;
MakeDirty();
//MakeDirty();
}
void SHLightComponent::SetType(SH_LIGHT_TYPE type) noexcept
{
lightData.type = type;
MakeDirty();
//MakeDirty();
}
void SHLightComponent::SetDirection(SHVec3 const& direction) noexcept
{
lightData.direction = direction;
MakeDirty();
//MakeDirty();
}
void SHLightComponent::SetColor(SHVec4 const& color) noexcept
{
lightData.color = color;
MakeDirty();
//MakeDirty();
}
void SHLightComponent::ModifyCullingMask(uint8_t layerIndex, bool value) noexcept
@ -54,7 +54,7 @@ namespace SHADE
else
lightData.cullingMask &= ~(1u << layerIndex);
MakeDirty();
//MakeDirty();
}
void SHLightComponent::SetCullingMask(uint32_t const& value) noexcept
@ -65,43 +65,43 @@ namespace SHADE
void SHLightComponent::SetAllLayers(void) noexcept
{
lightData.cullingMask = std::numeric_limits<uint32_t>::max();
MakeDirty();
//MakeDirty();
}
void SHLightComponent::ClearAllLayers(void) noexcept
{
lightData.cullingMask = 0;
MakeDirty();
//MakeDirty();
}
void SHLightComponent::MakeDirty(void) noexcept
{
dirty = true;
}
//void SHLightComponent::MakeDirty(void) noexcept
//{
// dirty = true;
//}
void SHLightComponent::ClearDirtyFlag(void) noexcept
{
dirty = false;
}
//void SHLightComponent::ClearDirtyFlag(void) noexcept
//{
// dirty = false;
//}
void SHLightComponent::Unbind(void) noexcept
{
bound = false;
MakeDirty();
}
void SHLightComponent::SetBound(uint32_t inIndexInBuffer) noexcept
{
bound = true;
indexInBuffer = inIndexInBuffer;
}
// void SHLightComponent::Unbind(void) noexcept
// {
// bound = false;
// MakeDirty();
// }
//
// void SHLightComponent::SetBound(uint32_t inIndexInBuffer) noexcept
//{
// bound = true;
// indexInBuffer = inIndexInBuffer;
// }
void SHLightComponent::SetStrength(float value) noexcept
{
lightData.strength = value;
MakeDirty();
//MakeDirty();
}
SHLightData const& SHLightComponent::GetLightData(void) const noexcept
@ -135,20 +135,20 @@ namespace SHADE
}
bool SHLightComponent::IsDirty(void) const noexcept
{
return dirty;
}
//bool SHLightComponent::IsDirty(void) const noexcept
//{
// return dirty;
//}
bool SHLightComponent::GetBound(void) const noexcept
{
return bound;
}
//bool SHLightComponent::GetBound(void) const noexcept
//{
// return bound;
//}
uint32_t SHLightComponent::GetIndexInBuffer(void) const noexcept
{
return indexInBuffer;
}
//uint32_t SHLightComponent::GetIndexInBuffer(void) const noexcept
//{
// return indexInBuffer;
//}
float SHLightComponent::GetStrength(void) const noexcept
{

View File

@ -17,13 +17,13 @@ namespace SHADE
//! Since the lighting system is gonna be self contained and light weight, we store this
//! so that we only write this to the CPU buffer when this light component change, we don't
//! rewrite everything. However we still write to the GPU buffer when everything changes.
uint32_t indexInBuffer;
//uint32_t indexInBuffer;
//! If the light component changed some value we mark this true.
bool dirty;
////! If the light component changed some value we mark this true.
//bool dirty;
//! If the light's data is already in the buffers, this will be set to true.
bool bound;
////! If the light's data is already in the buffers, this will be set to true.
//bool bound;
public:
@ -44,10 +44,10 @@ namespace SHADE
void SetCullingMask (uint32_t const& value) noexcept;
void SetAllLayers (void) noexcept; // serialized
void ClearAllLayers (void) noexcept; // serialized
void MakeDirty (void) noexcept;
void ClearDirtyFlag (void) noexcept;
void Unbind (void) noexcept;
void SetBound (uint32_t inIndexInBuffer) noexcept;
//void MakeDirty (void) noexcept;
//void ClearDirtyFlag (void) noexcept;
//void Unbind (void) noexcept;
//void SetBound (uint32_t inIndexInBuffer) noexcept;
void SetStrength (float value) noexcept; // serialized
@ -57,8 +57,8 @@ namespace SHADE
SHVec3 const& GetDirection (void) const noexcept; // serialized
SHVec4 const& GetColor (void) const noexcept; // serialized
uint32_t const& GetCullingMask (void) const noexcept; // serialized
bool IsDirty (void) const noexcept;
bool GetBound (void) const noexcept;
//bool IsDirty (void) const noexcept;
//bool GetBound (void) const noexcept;
uint32_t GetIndexInBuffer (void) const noexcept;
float GetStrength (void) const noexcept;
RTTR_ENABLE()

View File

@ -8,6 +8,8 @@
#include "SHLightComponent.h"
#include "ECS_Base/Managers/SHComponentManager.h"
#include "SHLightComponent.h"
#include "Math/Vector/SHVec4.h"
#include "Math/SHMatrix.h"
namespace SHADE
{
@ -31,7 +33,7 @@ namespace SHADE
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::WriteLightToAddress(void* address, SHLightComponent* lightComp) noexcept
void SHLightingSubSystem::PerTypeData::WriteLightToAddress(void* address, SHMatrix const& viewMat, SHLightComponent* lightComp) noexcept
{
auto const& lightData = lightComp->GetLightData();
switch (lightData.type)
@ -40,8 +42,12 @@ namespace SHADE
{
SHDirectionalLightData* lightPtr = reinterpret_cast<SHDirectionalLightData*>(address);
// #NoteToSelf: NEED TO TRANSPOSE HERE BECAUSE MULTIPLICATION IS ROW MAJOR.
SHVec4 transformedDir = SHMatrix::Transpose(viewMat) * SHVec4(lightData.direction[0], lightData.direction[1], lightData.direction[2], 0.0f);
lightPtr->cullingMask = lightData.cullingMask;
lightPtr->direction = lightData.direction;
lightPtr->direction = SHVec3 (transformedDir.x, transformedDir.y, transformedDir.z);
//lightPtr->direction = lightData.direction;
lightPtr->diffuseColor = lightData.color;
lightPtr->active = lightComp->isActive;
break;
@ -240,7 +246,7 @@ namespace SHADE
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::AddLight(Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept
void SHLightingSubSystem::PerTypeData::AddLight(Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, SHMatrix const& viewMat, bool& expanded) noexcept
{
if (unboundLight)
{
@ -259,10 +265,10 @@ namespace SHADE
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignedSize * numLights);
// Write the light data to address
WriteLightToAddress(writeLocation, unboundLight);
WriteLightToAddress(writeLocation, viewMat, unboundLight);
// Set the light component to be bound to that location
unboundLight->SetBound(numLights);
//unboundLight->SetBound(numLights);
// Increase light count
++numLights;
@ -280,11 +286,11 @@ namespace SHADE
*/
/***************************************************************************/
void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept
{
void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignedSize * lightComp->GetIndexInBuffer());
WriteLightToAddress(writeLocation, lightComp);
}
//void SHLightingSubSystem::PerTypeData::ModifyLight(SHLightComponent* lightComp) noexcept
//{
// void* writeLocation = reinterpret_cast<uint8_t*>(intermediateData.get()) + (lightDataAlignedSize * lightComp->GetIndexInBuffer());
// WriteLightToAddress(writeLocation, lightComp);
//}
void SHLightingSubSystem::PerTypeData::WriteToGPU(uint32_t frameIndex) noexcept
{
@ -406,7 +412,7 @@ namespace SHADE
dynamicOffsets[i].resize(NUM_LIGHT_TYPES + 1); // +1 for the count
}
numLightComponents = 0;
//numLightComponents = 0;
}
/***************************************************************************/
@ -419,21 +425,25 @@ namespace SHADE
*/
/***************************************************************************/
void SHLightingSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
void SHLightingSubSystem::Run(SHMatrix const& viewMat, uint32_t frameIndex) noexcept
{
static uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES);
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
bool expanded = false;
bool rewrite = false;
if (numLightComponents > lightComps.size())
{
rewrite = true;
ResetNumLights();
}
// First we reset the number of lights. We do this every frame so that we can count how many lights we have
ResetNumLights();
numLightComponents = lightComps.size();
//bool rewrite = false;
//if (numLightComponents > lightComps.size())
//{
// rewrite = true;
// ResetNumLights();
//}
//numLightComponents = lightComps.size();
for (auto& light : lightComps)
{
@ -441,22 +451,22 @@ namespace SHADE
// First we want to make sure the light is already bound to the system. if it
// isn't, we write it to the correct buffer.
if (!light.GetBound() || rewrite)
//if (!light.GetBound() || rewrite)
{
perTypeData[enumValue].AddLight(logicalDevice, &light, expanded);
perTypeData[enumValue].AddLight(logicalDevice, &light, viewMat, expanded);
//// add to light count
// add to light count
//++lightCountsData[enumValue];
}
// if there was modification to the light data
if (light.IsDirty())
//if (light.IsDirty())
{
// Write the data to the CPU
perTypeData[enumValue].ModifyLight(&light);
//perTypeData[enumValue].ModifyLight(&light);
// Light is now updated in the container
light.ClearDirtyFlag();
//light.ClearDirtyFlag();
}
}
@ -488,8 +498,6 @@ namespace SHADE
// so we do it anyway. #NoteToSelf: if at any point it affects performance, do a check before computing.
ComputeDynamicOffsets();
// Bind descriptor set (We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data).
cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, {dynamicOffsets[frameIndex]});
}
@ -505,4 +513,12 @@ namespace SHADE
{
}
void SHLightingSubSystem::BindDescSet(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{
//Bind descriptor set(We bind at an offset because the buffer holds NUM_FRAME_BUFFERS sets of data).
cmdBuffer->BindDescriptorSet(lightingDataDescSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::DYNAMIC_GLOBALS, { dynamicOffsets[frameIndex] });
}
}

View File

@ -95,15 +95,15 @@ namespace SHADE
//! to the GPU that stores NUM_FRAME_BUFFERS copies.
std::unique_ptr<uint8_t[]> intermediateData;
void WriteLightToAddress (void* address, SHLightComponent* lightComp) noexcept;
void WriteLightToAddress (void* address, SHMatrix const& viewMat, SHLightComponent* lightComp) noexcept;
public:
/*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void InitializeData (Handle<SHVkLogicalDevice> logicalDevice, SH_LIGHT_TYPE type) noexcept;
void Expand (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
void AddLight (Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, bool expanded) noexcept;
void ModifyLight (SHLightComponent* lightComp) noexcept;
void AddLight (Handle<SHVkLogicalDevice> logicalDevice, SHLightComponent* unboundLight, SHMatrix const& viewMat, bool& expanded) noexcept;
//void ModifyLight (SHLightComponent* lightComp) noexcept;
void WriteToGPU (uint32_t frameIndex) noexcept;
void ResetNumLights (void) noexcept;
@ -144,7 +144,7 @@ namespace SHADE
//! Number of SHLightComponents recorded. If at the beginning of the run function the size returned by the dense
//! set is less than the size recorded, rewrite all light components into the its respective buffers. If its more,
//! don't do anything.
uint32_t numLightComponents;
//uint32_t numLightComponents;
/*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */
@ -159,8 +159,10 @@ namespace SHADE
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
void Init (Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> descPool) noexcept;
void Run (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void Run (SHMatrix const& viewMat, uint32_t frameIndex) noexcept;
void Exit (void) noexcept;
void BindDescSet (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
};
}

View File

@ -0,0 +1,138 @@
#include "SHpch.h"
#include "SHSSAO.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/Buffers/SHVkBuffer.h"
#include "Graphics/Images/SHVkImage.h"
#include "Graphics/Images/SHVkSampler.h"
#include <random>
namespace SHADE
{
void SHSSAO::Init(Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkCommandBuffer> cmdBuffer) noexcept
{
// Initialize a distribution to get values from 0 to 1
std::uniform_real_distribution<float> distrib{0.0f, 1.0f};
// generator for random number
std::default_random_engine generator;
// generate samples
for (uint32_t i = 0; i < NUM_SAMPLES; ++i)
{
//SHVec3 temp
//{
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
// distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
//};
//temp = SHVec3::Normalise(temp);
//temp *= distrib(generator);
//// This makes sure that most points are closer to fragment's position
//float scale = 1.0f / static_cast<float>(NUM_SAMPLES);
//scale = std::lerp(0.1f, 1.0f, scale * scale);
//temp *= scale;
//samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f);
samples[i] = SHVec4
{
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
0.0f
};
// This makes sure that most points are closer to fragment's position
float scale = 1.0f / static_cast<float>(NUM_SAMPLES);
scale = std::lerp(0.1f, 1.0f, scale * scale);
samples[i] *= scale;
}
// generate rotation vector
for (uint32_t i = 0; i < NUM_ROTATION_VECTORS; ++i)
{
rotationVectors[i] = SHVec4
{
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
0.0f, // we want to rotate about the z axis in tangent space
0.0f
};
}
SHImageCreateParams imageDetails =
{
.imageType = vk::ImageType::e2D,
.width = NUM_ROTATION_VECTORS_W,
.height = NUM_ROTATION_VECTORS_H,
.depth = 1,
.levels = 1,
.arrayLayers = 1,
.imageFormat = vk::Format::eR32G32B32A32Sfloat,
.usageFlags = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst,
.createFlags = {}
};
uint32_t mipOffset = 0;
rotationVectorsImage = logicalDevice->CreateImage(imageDetails, reinterpret_cast<unsigned char*>( rotationVectors.data()), static_cast<uint32_t>(sizeof(rotationVectors)), {&mipOffset, 1}, VMA_MEMORY_USAGE_AUTO, {});
vk::ImageMemoryBarrier transferBarrier{};
rotationVectorsImage->PrepareImageTransitionInfo(vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, transferBarrier);
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, {transferBarrier});
rotationVectorsImage->TransferToDeviceResource(cmdBuffer);
vk::ImageMemoryBarrier shaderReadBarrier{};
rotationVectorsImage->PrepareImageTransitionInfo(vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, shaderReadBarrier);
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eComputeShader, {}, {}, {}, { shaderReadBarrier });
// Get aligned size for buffer
uint32_t alignedSize = logicalDevice->PadSSBOSize(sizeof (samples));
// Create buffer
ssaoDataBuffer = logicalDevice->CreateBuffer(alignedSize, samples.data(), alignedSize, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst, VMA_MEMORY_USAGE_AUTO, {});
ssaoDataBuffer->TransferToDeviceResource(cmdBuffer);
}
void SHSSAO::PrepareRotationVectorsVkData(Handle<SHVkLogicalDevice> logicalDevice) noexcept
{
SHImageViewDetails DETAILS =
{
.viewType = vk::ImageViewType::e2D,
.format = vk::Format::eR32G32B32A32Sfloat,
.imageAspectFlags = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.mipLevelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1
};
rotationVectorsImageView = rotationVectorsImage->CreateImageView(logicalDevice, rotationVectorsImage, DETAILS);
SHVkSamplerParams samplerParams
{
.minFilter = vk::Filter::eNearest,
.magFilter = vk::Filter::eNearest,
.addressMode = vk::SamplerAddressMode::eRepeat,
.mipmapMode = vk::SamplerMipmapMode::eNearest,
.maxLod = 1u
};
rotationVectorsSampler = logicalDevice->CreateSampler(samplerParams);
}
SHVkDescriptorSetGroup::viewSamplerLayout SHSSAO::GetViewSamplerLayout(void) const noexcept
{
return std::make_tuple(rotationVectorsImageView, rotationVectorsSampler, vk::ImageLayout::eShaderReadOnlyOptimal);
}
Handle<SHVkBuffer> SHSSAO::GetBuffer(void) const noexcept
{
return ssaoDataBuffer;
}
}

View File

@ -0,0 +1,49 @@
#pragma once
#include "Resource/SHHandle.h"
#include "Graphics/SHVulkanIncludes.h"
#include "Math/Vector/SHVec4.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
namespace SHADE
{
class SHVkBuffer;
class SHVkLogicalDevice;
class SHVkCommandBuffer;
class SHVkImage;
class SHVkImageView;
class SHVkSampler;
class SHSSAO
{
public:
static constexpr uint32_t DESC_SET_BUFFER_BINDING = 0;
static constexpr uint32_t DESC_SET_IMAGE_BINDING = 1;
private:
static constexpr uint32_t NUM_SAMPLES = 64;
static constexpr uint32_t NUM_ROTATION_VECTORS_W = 4;
static constexpr uint32_t NUM_ROTATION_VECTORS_H = 4;
static constexpr uint32_t NUM_ROTATION_VECTORS = NUM_ROTATION_VECTORS_W * NUM_ROTATION_VECTORS_H;
private:
//! distances from a pixel we want to sample
std::array<SHVec4, NUM_SAMPLES> samples;
//! For passing SSAO samples and kernel to GPU
Handle<SHVkBuffer> ssaoDataBuffer;
std::array<SHVec4, NUM_ROTATION_VECTORS> rotationVectors;
Handle<SHVkImage> rotationVectorsImage;
Handle<SHVkImageView> rotationVectorsImageView;
Handle<SHVkSampler> rotationVectorsSampler;
public:
void Init (Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkCommandBuffer> cmdBuffer) noexcept;
void PrepareRotationVectorsVkData (Handle<SHVkLogicalDevice> logicalDevice) noexcept;
SHVkDescriptorSetGroup::viewSamplerLayout GetViewSamplerLayout (void) const noexcept;
Handle<SHVkBuffer> GetBuffer (void) const noexcept;
};
}

View File

@ -2,8 +2,10 @@
#define SH_PIPELINE_LAYOUT_PARAMS_H
#include "Graphics/SHVulkanIncludes.h"
#include "Graphics/SHVulkanDefines.h"
#include "Resource/SHHandle.h"
#include "Graphics/Descriptors/SHVkDescriptorSetLayout.h"
#include <unordered_set>
namespace SHADE
{
@ -24,6 +26,12 @@ namespace SHADE
//! want to use the layout to initialize the pipeline layout but we do not
//! want to use it for allocating descriptor sets.
std::vector<Handle<SHVkDescriptorSetLayout>> const& globalDescSetLayouts = {};
//! Since both SPIRV-Reflect and GLSL don't provide ways to describe UBOs or
//! SSBOs as dynamic, we need to do it ourselves. This will store bindings
//! which we will use when parsing for descriptor set layouts. If a parsed
//! binding is in this container, we make that binding's descriptor dynamic.
std::unordered_set<BindingAndSetHash> dynamicBufferBindings;
};
struct SHPipelineLayoutParamsDummy

View File

@ -165,6 +165,28 @@ namespace SHADE
newBinding.Stage = shaderModule->GetShaderStageFlagBits();
newBinding.Type = descBindingInfo.ConvertFromReflectDescType(reflectedBinding->descriptor_type);
// Here we want to check if a binding is supposed to be dynamic. If it is, make it dynamic.
if (newBinding.Type == vk::DescriptorType::eUniformBuffer || newBinding.Type == vk::DescriptorType::eStorageBuffer)
{
for (auto& bsHash : dynamicBufferBindings)
{
uint32_t set = static_cast<uint32_t>(bsHash >> 32);
uint32_t binding = static_cast<uint32_t>(bsHash & 0xFFFFFFFF);
if (set == CURRENT_SET && binding == newBinding.BindPoint)
{
switch (newBinding.Type)
{
case vk::DescriptorType::eUniformBuffer:
newBinding.Type = vk::DescriptorType::eUniformBufferDynamic;
break;
case vk::DescriptorType::eStorageBuffer:
newBinding.Type = vk::DescriptorType::eStorageBufferDynamic;
break;
}
}
}
}
// In reality, the check for variable descriptor sets do not exists in spirv-reflect. Fortunately, when a shader
// defines a boundless descriptor binding in the shader, the information reflected makes the array dimensions
// contain a 1 element of value 1. Knowing that having an array [1] doesn't make sense, we can use this to
@ -300,6 +322,7 @@ namespace SHADE
, vkDescriptorSetLayoutsAllocate{}
, descriptorSetLayoutsPipeline{}
, vkDescriptorSetLayoutsPipeline{}
, dynamicBufferBindings{std::move (pipelineLayoutParams.dynamicBufferBindings)}
{
for (auto& mod : shaderModules)
{

View File

@ -29,6 +29,9 @@ namespace SHADE
//! Push constant interface
SHPushConstantInterface pushConstantInterface;
//! See SHPipelineLayoutParams for details
std::unordered_set<BindingAndSetHash> dynamicBufferBindings;
//! Push constant ranges
std::vector<vk::PushConstantRange> vkPcRanges;

View File

@ -129,4 +129,9 @@ namespace SHADE
return vkQueue;
}
void SHVkQueue::WaitIdle(void) const noexcept
{
vkQueue.waitIdle();
}
}

View File

@ -50,6 +50,8 @@ namespace SHADE
void SubmitCommandBuffer (std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems = {}, std::initializer_list<Handle<SHVkSemaphore>> waitSems = {}, vk::PipelineStageFlags waitDstStageMask = {}, Handle<SHVkFence> const& fence = {}) noexcept;
vk::Result Present (Handle<SHVkSwapchain> const& swapchain, std::initializer_list<Handle<SHVkSemaphore>> waitSems, uint32_t frameIndex) noexcept;
vk::Queue GetVkQueue() noexcept;
void WaitIdle (void) const noexcept;
};
}

View File

@ -263,7 +263,7 @@ namespace SHADE
return subpass;
}
Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale/* = 1.0f*/) noexcept
Handle<SHRenderGraphNodeCompute> SHRenderGraphNode::AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, float numWorkGroupScale/* = 1.0f*/) noexcept
{
// Look for the required resources in the graph
std::vector<Handle<SHRenderGraphResource>> nodeComputeResources{};
@ -276,7 +276,7 @@ namespace SHADE
}
// Create the subpass compute with the resources
auto nodeCompute = graphStorage->resourceManager->Create<SHRenderGraphNodeCompute>(graphStorage, computeShaderModule, std::move(nodeComputeResources), nodeComputes.empty());
auto nodeCompute = graphStorage->resourceManager->Create<SHRenderGraphNodeCompute>(graphStorage, computeShaderModule, std::move(nodeComputeResources), std::move (dynamicBufferBindings), nodeComputes.empty());
nodeComputes.push_back(nodeCompute);
return nodeCompute;

View File

@ -100,7 +100,7 @@ namespace SHADE
/* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/
Handle<SHSubpass> AddSubpass(std::string subpassName) noexcept;
Handle<SHRenderGraphNodeCompute> AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, float numWorkGroupScale = 1.0f) noexcept;
Handle<SHRenderGraphNodeCompute> AddNodeCompute(Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept;
void AddDummySubpassIfNeeded (void) noexcept;
// TODO: RemoveSubpass()

View File

@ -13,7 +13,7 @@
namespace SHADE
{
SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept
SHRenderGraphNodeCompute::SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale/* = 1.0f*/) noexcept
: computePipeline{}
, pipelineLayout{}
, resources{}
@ -21,11 +21,13 @@ namespace SHADE
, groupSizeY{0}
, followingEndRenderpass {followingEndRP}
, numWorkGroupScale {std::clamp(inNumWorkGroupScale, 0.0f, 1.0f)}
, computeResource{}
{
SHPipelineLayoutParams pipelineLayoutParams
{
.shaderModules = {computeShaderModule},
.globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts()
.globalDescSetLayouts = SHGraphicsGlobalData::GetDescSetLayouts(),
.dynamicBufferBindings = std::move(dynamicBufferBindings),
};
// Create pipeline layout from parameters
@ -42,16 +44,31 @@ namespace SHADE
//Get the descriptor set layouts required to allocate. We only want the ones for allocate because
//global descriptors are already bound in the main system.
auto const& layouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate();
//Variable counts for the descriptor sets (all should be 1).
std::vector<uint32_t> variableCounts{ static_cast<uint32_t>(layouts.size()) };
std::fill(variableCounts.begin(), variableCounts.end(), 0);
auto const& graphResourceLayout = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline()[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE];
// Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE)
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
descSetGroups[i] = graphStorage->descriptorPool->Allocate(layouts, variableCounts);
graphResourceDescSets[i] = graphStorage->descriptorPool->Allocate({graphResourceLayout}, { 1 });
}
auto const& layouts = computePipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline();
if (layouts.size() == SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE + 1)
{
// create compute resources
computeResource = graphStorage->resourceManager->Create<ComputeResource>();
auto computeResourceLayout = layouts[SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE];
computeResource->descSet = graphStorage->descriptorPool->Allocate({ computeResourceLayout }, { 1 });
// Allocate for descriptor offsets
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
computeResource->dynamicOffsets[i].resize(computeResourceLayout->GetNumDynamicOffsetsRequired());
// 1st set all start at 0
for (auto& index : computeResource->dynamicOffsets[0])
index = 0;
}
HandleResize();
@ -63,7 +80,12 @@ namespace SHADE
cmdBuffer->BindPipeline(computePipeline);
// bind descriptor sets
cmdBuffer->BindDescriptorSet(descSetGroups[frameIndex], SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, {});
cmdBuffer->BindDescriptorSet(graphResourceDescSets[frameIndex], SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, {});
if (computeResource)
{
cmdBuffer->BindDescriptorSet(computeResource->descSet, SH_PIPELINE_TYPE::COMPUTE, SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE, computeResource->dynamicOffsets[frameIndex]);
}
// dispatch compute
cmdBuffer->ComputeDispatch(groupSizeX, groupSizeY, 1);
@ -89,8 +111,8 @@ namespace SHADE
uint32_t imageIndex = (resources[i]->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)) ? frameIndex : 0;
SHVkDescriptorSetGroup::viewSamplerLayout vsl = std::make_tuple(resources[i]->GetImageView(imageIndex), Handle<SHVkSampler>{}, vk::ImageLayout::eGeneral);
descSetGroups[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 });
descSetGroups[frameIndex]->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint);
graphResourceDescSets[frameIndex]->ModifyWriteDescImage(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint, { &vsl, 1 });
graphResourceDescSets[frameIndex]->UpdateDescriptorSetImages(SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_RESOURCE, binding.BindPoint);
++i;
}
}
@ -137,4 +159,27 @@ namespace SHADE
}
}
void SHRenderGraphNodeCompute::SetDynamicOffsets(std::span<uint32_t> perFrameSizes) noexcept
{
for (uint32_t i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
{
auto dynamicOffsets = computeResource->dynamicOffsets[i];
for (uint32_t j = 0; j < perFrameSizes.size(); ++j)
dynamicOffsets[j] = perFrameSizes[j] * i;
}
}
void SHRenderGraphNodeCompute::ModifyWriteDescBufferComputeResource(uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept
{
computeResource->descSet->ModifyWriteDescBuffer(set, binding, buffers, offset, range);
computeResource->descSet->UpdateDescriptorSetBuffer(set, binding);
}
void SHRenderGraphNodeCompute::ModifyWriteDescImageComputeResource(uint32_t set, uint32_t binding, std::span<SHVkDescriptorSetGroup::viewSamplerLayout> const& viewSamplerLayouts) noexcept
{
computeResource->descSet->ModifyWriteDescImage(set, binding, viewSamplerLayouts);
computeResource->descSet->UpdateDescriptorSetImages(set, binding);
}
}

View File

@ -2,6 +2,7 @@
#include "Resource/SHHandle.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h"
#include "Graphics/SHVulkanIncludes.h"
#include <initializer_list>
#include <string>
@ -10,7 +11,6 @@
namespace SHADE
{
class SHVkPipeline;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
class SHVkLogicalDevice;
class SHVkPipelineLayout;
@ -18,9 +18,22 @@ namespace SHADE
class SHRenderGraphResource;
class SHVkShaderModule;
class SHVkCommandBuffer;
class SHVkBuffer;
class SHRenderGraphNodeCompute
{
private:
// Binding of set SHGraphicsConstants::DescriptorSetIndex::RENDERGRAPH_NODE_COMPUTE_RESOURCE
struct ComputeResource
{
//! Descriptor set (initialized by parent class)
Handle<SHVkDescriptorSetGroup> descSet {};
//! Dynamic offsets into these resources (initialized from the outside).
std::array<std::vector<uint32_t>, SHGraphicsConstants::NUM_FRAME_BUFFERS> dynamicOffsets {};
};
private:
static constexpr uint32_t workGroupSizeX = 16;
static constexpr uint32_t workGroupSizeY = 16;
@ -32,7 +45,10 @@ namespace SHADE
Handle<SHVkPipelineLayout> pipelineLayout;
//! Descriptor set group to hold the images for reading (STORAGE_IMAGE)
std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS> descSetGroups;
std::array<Handle<SHVkDescriptorSetGroup>, SHGraphicsConstants::NUM_FRAME_BUFFERS> graphResourceDescSets;
//! Compute resources
Handle<ComputeResource> computeResource;
//! vector of resources needed by the subpass compute
std::vector<Handle<SHRenderGraphResource>> resources;
@ -50,11 +66,17 @@ namespace SHADE
std::array<std::vector<vk::ImageMemoryBarrier>, SHGraphicsConstants::NUM_FRAME_BUFFERS> memoryBarriers;
public:
SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept;
SHRenderGraphNodeCompute(Handle<SHRenderGraphStorage> graphStorage, Handle<SHVkShaderModule> computeShaderModule, std::vector<Handle<SHRenderGraphResource>>&& subpassComputeResources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings, bool followingEndRP, float inNumWorkGroupScale = 1.0f) noexcept;
void Execute (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept;
void SetDynamicOffsets (std::span<uint32_t> perFrameSizes) noexcept;
void ModifyWriteDescBufferComputeResource (uint32_t set, uint32_t binding, std::span<Handle<SHVkBuffer>> const& buffers, uint32_t offset, uint32_t range) noexcept;
void ModifyWriteDescImageComputeResource(uint32_t set, uint32_t binding, std::span<SHVkDescriptorSetGroup::viewSamplerLayout> const& viewSamplerLayouts) noexcept;
friend class SHRenderGraph;
friend class SHRenderGraphNode;
};

View File

@ -142,6 +142,16 @@ namespace SHADE
case SpvOp::SpvOpTypeRuntimeArray:
recurseForInfo(&member, interfaceHdl, member.offset, biggestAlignment, parentVarName + std::string(member.name) + ".");
break;
case SpvOp::SpvOpTypeArray:
interfaceHdl->AddVariable(parentVarName + std::string (member.name),
SHShaderBlockInterface::Variable
(
parentOffset + member.offset,
SHShaderBlockInterface::Variable::Type::OTHER
)
);
biggestAlignment = std::max(biggestAlignment, member.size);
break;
}
}
};

View File

@ -118,6 +118,17 @@ namespace SHADE
}
{}
SHColour::SHColour(uint32_t rgba) noexcept
: XMFLOAT4 { 0.0f, 0.0f, 0.0f, 1.0f }
{
const SHColour32 TMP { ._32bitValue = rgba };
x = static_cast<float>(TMP._8bitValues[0]) / 255.0f;
y = static_cast<float>(TMP._8bitValues[1]) / 255.0f;
z = static_cast<float>(TMP._8bitValues[2]) / 255.0f;
w = static_cast<float>(TMP._8bitValues[3]) / 255.0f;
}
SHColour::SHColour(const SHVec3& rgb) noexcept
: XMFLOAT4 { rgb.x, rgb.y, rgb.z, 1.0f }
{}

View File

@ -34,6 +34,12 @@ namespace SHADE
float v = 0.0f;
};
union SH_API SHColour32
{
uint32_t _32bitValue;
uint8_t _8bitValues[4];
};
class SH_API SHColour : public DirectX::XMFLOAT4
{
public:
@ -46,6 +52,7 @@ namespace SHADE
SHColour (float r, float g, float b, float a) noexcept;
SHColour (uint8_t r, uint8_t g, uint8_t b) noexcept;
SHColour (uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept;
SHColour (uint32_t rgba) noexcept;
SHColour (const SHVec3& rgb) noexcept;
SHColour (const SHVec4& rgba) noexcept;

View File

@ -212,7 +212,7 @@ namespace SHADE
const SHVec3 TF_WORLD_SCALE = transformComponent->GetWorldScale();
const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z });
worldRadius *= MAX_SCALE;
worldRadius *= MAX_SCALE * 0.5f;
}
if (type == Type::SPHERE)

View File

@ -17,10 +17,12 @@
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Math/SHMathHelpers.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneManager.h"
#include "Scripting/SHScriptEngine.h"
#include "Tools/SHUtilities.h"
namespace SHADE
{
@ -30,6 +32,7 @@ namespace SHADE
SHPhysicsSystem::SHPhysicsSystem()
: worldUpdated { false }
, debugDrawFlags { 0 }
, interpolationFactor { 0.0 }
, fixedDT { 60.0 }
, world { nullptr }
@ -47,6 +50,11 @@ namespace SHADE
: SHSystemRoutine { "Physics PostUpdate", false }
{}
SHPhysicsSystem::PhysicsDebugDraw::PhysicsDebugDraw()
: SHSystemRoutine { "Physics DebugDraw", true }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
@ -99,6 +107,31 @@ namespace SHADE
return 0;
}
bool SHPhysicsSystem::GetDrawColliders() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER);
}
bool SHPhysicsSystem::GetDrawColliderAABBs() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB);
}
bool SHPhysicsSystem::GetDrawBroadPhase() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB);
}
bool SHPhysicsSystem::GetDrawContactPoints() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS);
}
bool SHPhysicsSystem::GetDrawContactNormals() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS);
}
const SHPhysicsSystem::CollisionEvents& SHPhysicsSystem::GetCollisionInfo() const noexcept
{
return collisionInfo;
@ -181,6 +214,96 @@ namespace SHADE
}
}
void SHPhysicsSystem::SetDrawColliders(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::COLLISION_SHAPE,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawColliderAABBs(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::COLLIDER_AABB,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawBroadPhase(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::COLLIDER_BROADPHASE_AABB,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawContactPoints(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::CONTACT_POINT,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawContactNormals(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL,
shouldDraw
);
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
@ -198,6 +321,7 @@ namespace SHADE
world = factory.createPhysicsWorld(settings);
world->setEventListener(this);
world->setIsDebugRenderingEnabled(true);
// Set up solvers
world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES);
@ -323,7 +447,7 @@ namespace SHADE
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_WARNING("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
}
fixedTimeStep = 1.0 / physicsSystem->fixedDT;
@ -353,7 +477,7 @@ namespace SHADE
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_WARNING("Unable to invoke collision and trigger script events due to missing SHScriptEngine!");
SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!");
}
// Interpolate transforms for rendering
@ -369,6 +493,40 @@ namespace SHADE
}
}
void SHPhysicsSystem::PhysicsDebugDraw::Execute(double) noexcept
{
const auto* PHYSICS_SYSTEM = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
if (PHYSICS_SYSTEM->debugDrawFlags == 0)
return;
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
if (debugDrawSystem == nullptr)
{
SHLOGV_ERROR("Unable to debug draw physics objects due to missing SHDebugDrawSystem!");
return;
}
const auto& RP3D_DEBUG_RENDERER = PHYSICS_SYSTEM->world->getDebugRenderer();
const auto& LINES = RP3D_DEBUG_RENDERER.getLines();
const auto& TRIANGLES = RP3D_DEBUG_RENDERER.getTriangles();
// Draw all lines
for (uint32_t i = 0; i < RP3D_DEBUG_RENDERER.getNbLines(); ++i)
{
const auto& LINE = LINES[i];
debugDrawSystem->DrawLine(SHColour{ LINE.color1 }, LINE.point1, LINE.point2);
}
for (uint32_t i = 0; i < RP3D_DEBUG_RENDERER.getNbTriangles(); ++i)
{
const auto& TRIANGLE = TRIANGLES[i];
SHColour triColour{ TRIANGLE.color1 };
triColour.a() = 1.0f;
debugDrawSystem->DrawTri(triColour, TRIANGLE.point1, TRIANGLE.point2, TRIANGLE.point3);
}
}
void SHPhysicsSystem::onContact(const CallbackData& callbackData)
{
for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i)

View File

@ -51,6 +51,15 @@ namespace SHADE
using CollisionEvents = std::vector<SHCollisionEvent>;
enum class DebugDrawFlags : uint8_t
{
COLLIDER = 1
, COLLIDER_AABB = 2
, BROAD_PHASE_AABB = 4
, CONTACT_POINTS = 8
, CONTACT_NORMALS = 16
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
@ -69,6 +78,12 @@ namespace SHADE
[[nodiscard]] uint16_t GetNumberVelocityIterations () const noexcept;
[[nodiscard]] uint16_t GetNumberPositionIterations () const noexcept;
[[nodiscard]] bool GetDrawColliders () const noexcept;
[[nodiscard]] bool GetDrawColliderAABBs () const noexcept;
[[nodiscard]] bool GetDrawBroadPhase () const noexcept;
[[nodiscard]] bool GetDrawContactPoints () const noexcept;
[[nodiscard]] bool GetDrawContactNormals () const noexcept;
[[nodiscard]] const CollisionEvents& GetCollisionInfo () const noexcept;
[[nodiscard]] const CollisionEvents& GetTriggerInfo () const noexcept;
@ -85,6 +100,13 @@ namespace SHADE
void SetWorldSettings (const WorldSettings& settings) const noexcept;
// TODO(Diren): Can the debug draw flags be done through an enum?
void SetDrawColliders (bool shouldDraw) noexcept;
void SetDrawColliderAABBs (bool shouldDraw) noexcept;
void SetDrawBroadPhase (bool shouldDraw) noexcept;
void SetDrawContactPoints (bool shouldDraw) noexcept;
void SetDrawContactNormals (bool shouldDraw) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
@ -105,48 +127,31 @@ namespace SHADE
class SH_API PhysicsPreUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsPreUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override;
};
class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsFixedUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute (double dt) noexcept override;
};
class SH_API PhysicsPostUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsPostUpdate();
void Execute(double dt) noexcept override;
};
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
class SH_API PhysicsDebugDraw final : public SHSystemRoutine
{
public:
PhysicsDebugDraw();
void Execute(double dt) noexcept override;
};
@ -162,6 +167,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
bool worldUpdated;
uint8_t debugDrawFlags;
double interpolationFactor;
double fixedDT;

View File

@ -25,7 +25,7 @@ namespace SHADE
/* Static Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHDebugDrawSystem* SHDebugDraw::dbgDrawSys = nullptr;
/*-----------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*-----------------------------------------------------------------------------------*/
@ -70,4 +70,40 @@ namespace SHADE
{
dbgDrawSys->DrawSphere(color, pos, radius);
}
void SHDebugDraw::PersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt)
{
dbgDrawSys->DrawPersistentLine(color, startPt, endPt);
}
void SHDebugDraw::PersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3)
{
dbgDrawSys->DrawPersistentTri(color, pt1, pt2, pt3);
}
void SHDebugDraw::PersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4)
{
dbgDrawSys->DrawPersistentQuad(color, pt1, pt2, pt3, pt4);
}
void SHDebugDraw::PersistentPoly(const SHVec4& color, std::initializer_list<SHVec3> pointList)
{
dbgDrawSys->DrawPersistentPoly(color, pointList);
}
void SHDebugDraw::PersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size)
{
dbgDrawSys->DrawPersistentCube(color, pos, size);
}
void SHDebugDraw::PersistentSphere(const SHVec4& color, const SHVec3& pos, double radius)
{
dbgDrawSys->DrawPersistentSphere(color, pos, radius);
}
void SHDebugDraw::ClearPersistentDraws()
{
dbgDrawSys->ClearPersistentDraws();
}
}

View File

@ -92,6 +92,64 @@ namespace SHADE
/// <param name="size">Size of the rendered sphere.</param>
static void Sphere(const SHVec4& color, const SHVec3& pos, double radius);
/*---------------------------------------------------------------------------------*/
/* Persistent Draw Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Renders a line between two points in world space that will persist until
/// ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the line.</param>
/// <param name="startPt">First point of the line.</param>
/// <param name="endPt">Second point of the line.</param>
static void PersistentLine(const SHVec4& color, const SHVec3& startPt, const SHVec3& endPt);
/// <summary>
/// Renders a triangle indicated by three points in world space that will persist
/// until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the triangle.</param>
/// <param name="pt1">First point of the triangle.</param>
/// <param name="pt2">Second point of the triangle.</param>
/// <param name="pt3">Third point of the triangle.</param>
static void PersistentTri(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3);
/// <summary>
/// Renders a quadrilateral indicated by four points in world space that will persist
/// until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the quadrilateral.</param>
/// <param name="pt1">First point of the triangle.</param>
/// <param name="pt2">Second point of the quadrilateral.</param>
/// <param name="pt3">Third point of the quadrilateral.</param>
/// <param name="pt4">Third point of the quadrilateral.</param>
static void PersistentQuad(const SHVec4& color, const SHVec3& pt1, const SHVec3& pt2, const SHVec3& pt3, const SHVec3& pt4);
/// <summary>
/// Renders a polygon indicated by the specified set of points in world space that
/// will persist until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the polygon.</param>
/// <param name="pointList">List of points for the polygon.</param>
static void PersistentPoly(const SHVec4& color, std::initializer_list<SHVec3> pointList);
/// <summary>
/// Renders a wireframe cube centered around the position specified in world space
/// that will persist until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the cube.</param>
/// <param name="pos">Position where the cube wil be centered at.</param>
/// <param name="size">Size of the rendered cube.</param>
static void PersistentCube(const SHVec4& color, const SHVec3& pos, const SHVec3& size);
/// <summary>
/// Renders a wireframe sphere centered around the position specified in world space
/// that will persist until ClearPersistentDraws() is called.
/// </summary>
/// <param name="color">Colour of the sphere.</param>
/// <param name="pos">Position where the sphere wil be centered at.</param>
/// <param name="size">Size of the rendered sphere.</param>
static void PersistentSphere(const SHVec4& color, const SHVec3& pos, double radius);
/// <summary>
/// Clears any persistent drawn debug primitives.
/// </summary>
static void ClearPersistentDraws();
private:
/*---------------------------------------------------------------------------------*/
/* Static Data Members */

View File

@ -39,7 +39,7 @@ namespace SHADE
* @param[in] enumClassMember A member of the specified enum class.
* @returns The value of the enum class member in the output type.
*/
template <IsEnum InputType, IsIntegral OutputType = int>
template <IsEnum InputType, IsIntegral OutputType = std::underlying_type_t<InputType>>
static constexpr OutputType ConvertEnum(InputType enumClassMember) noexcept;
/**

View File

@ -148,6 +148,14 @@ namespace SHADE
{
return Convert::ToCLI(GetNativeComponent()->GetTorque());
}
bool RigidBody::Interpolating::get()
{
return GetNativeComponent()->IsInterpolating();
}
void RigidBody::Interpolating::set(bool value)
{
GetNativeComponent()->SetInterpolate(value);
}
/*---------------------------------------------------------------------------------*/
/* Force Functions */

View File

@ -129,6 +129,11 @@ namespace SHADE
{
Vector3 get();
}
property bool Interpolating
{
bool get();
void set(bool value);
}
/*-----------------------------------------------------------------------------*/
/* Force Functions */