Skip to content

Commit

Permalink
feat: add spotlights back
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Pollind <[email protected]>
  • Loading branch information
pollend committed Nov 26, 2023
1 parent ad1a82a commit 1652608
Show file tree
Hide file tree
Showing 17 changed files with 449 additions and 40 deletions.
41 changes: 41 additions & 0 deletions HPL2/include/graphics/ImageBindlessPool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include "graphics/ForgeHandles.h"
#include "graphics/ForgeRenderer.h"
#include "graphics/IndexPool.h"

#include <cstdint>
#include <vector>

namespace hpl {
class Image;
class TextureDescriptorPool;
class ImageBindlessPool {
public:
static uint32_t constexpr MinimumFrameCount = ForgeRenderer::SwapChainLength * 4;

struct ImageReserveEntry {
uint16_t m_prev = UINT16_MAX;
uint16_t m_next = UINT16_MAX;
uint32_t m_handle = IndexPool::InvalidHandle;
uint32_t m_frameCount = 0;
Image* m_image = nullptr;
};
ImageBindlessPool();
ImageBindlessPool(TextureDescriptorPool* pool, uint32_t reserveSize);
~ImageBindlessPool();
void reset(const ForgeRenderer::Frame& frame); // reset and prepare for the next frame
uint32_t request(Image* image);

private:

TextureDescriptorPool* m_texturePool = nullptr;
std::vector<ImageReserveEntry> m_pool;
uint32_t m_allocSize = 0;

uint16_t m_headIndex = UINT16_MAX;
uint16_t m_tailIndex = UINT16_MAX;

uint32_t m_currentFrame = 0;
};
} // namespace hpl
1 change: 1 addition & 0 deletions HPL2/include/graphics/IndexPool.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace hpl {
public:
explicit IndexPool(uint32_t reserve);
IndexPool();
static constexpr uint32_t InvalidHandle = UINT32_MAX;

uint32_t requestId();
inline uint32_t reserve() {return m_reserve;}
Expand Down
8 changes: 8 additions & 0 deletions HPL2/include/graphics/RendererDeferred2.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "engine/RTTI.h"

#include "graphics/CommandBufferPool.h"
#include "graphics/ImageBindlessPool.h"
#include "graphics/SceneResource.h"
#include "graphics/ShadowCache.h"
#include "graphics/TextureDescriptorPool.h"
Expand Down Expand Up @@ -82,6 +83,7 @@ namespace hpl {
static constexpr uint32_t MaxIndirectDrawArgs = 4096;

static constexpr uint32_t PointLightCount = 256;
static constexpr uint32_t SpotLightCount = 256;
static constexpr float ShadowDistanceMedium = 10;
static constexpr float ShadowDistanceLow = 20;
static constexpr float ShadowDistanceNone = 40;
Expand All @@ -91,6 +93,8 @@ namespace hpl {
static constexpr uint32_t LightClusterWidth = 16;
static constexpr uint32_t LightClusterHeight = 16;
static constexpr uint32_t LightClusterLightCount = 128;
static constexpr uint32_t TransientImagePoolCount = 256;


struct ViewportData {
public:
Expand Down Expand Up @@ -176,15 +180,19 @@ namespace hpl {
cRenderList m_rendererList;

// Lights
ImageBindlessPool m_transientImagePool;
SharedRootSignature m_lightClusterRootSignature;
std::array<SharedDescriptorSet, ForgeRenderer::SwapChainLength> m_lightDescriptorPerFrameSet;
SharedShader m_lightClusterShader;
SharedShader m_lightClusterSpotlightShader;
SharedShader m_clearLightClusterShader;
SharedPipeline m_pointLightClusterPipeline;
SharedPipeline m_spotLightClusterPipeline;
SharedPipeline m_clearClusterPipeline;
std::array<SharedBuffer, ForgeRenderer::SwapChainLength> m_lightClustersBuffer;
std::array<SharedBuffer, ForgeRenderer::SwapChainLength> m_lightClusterCountBuffer;
std::array<SharedBuffer, ForgeRenderer::SwapChainLength> m_pointLightBuffer;
std::array<SharedBuffer, ForgeRenderer::SwapChainLength> m_spotlightBuffer;
};
}; // namespace hpl

19 changes: 17 additions & 2 deletions HPL2/include/graphics/SceneResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,26 @@ namespace hpl::resource {
};

struct ScenePointLight {
mat4 m_mvp;
float3 m_lightPos;
float3 m_worldPos;
uint32_t m_config;
float4 m_lightColor;
float m_radius;
uint32_t m_pad0;
uint32_t m_pad1;
uint32_t m_pad2;
};

struct SceneSpotLight {
mat4 m_viewProjection;
float3 m_worldPos;
uint m_config;
float3 m_direction;
float m_angle;
float4 m_lightColor;
float m_radius;
uint32_t m_pad0;
uint32_t m_pad1;
uint32_t m_pad2;
};

struct DiffuseMaterial {
Expand Down
3 changes: 0 additions & 3 deletions HPL2/include/scene/LightSpot.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ namespace hpl {

class cLightSpot : public iLight
{
#ifdef __GNUC__
typedef iLight __super;
#endif
public:
cLightSpot(tString asName, cResources *apResources);
~cLightSpot();
Expand Down
4 changes: 4 additions & 0 deletions HPL2/resource/ShaderList.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@
#include "scene_light_cluster.comp.fsl"
#end

#comp scene_light_cluster_spotlight.comp
#include "scene_light_cluster_spotlight.comp.fsl"
#end

#comp scene_light_cluster_clear.comp
#include "scene_light_cluster_clear.comp.fsl"
#end
Expand Down
2 changes: 1 addition & 1 deletion HPL2/resource/deferred_light_spotlight.frag.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ float4 PS_MAIN(PsIn In)
float3 diffuseColor = color.xyz * Get(lightObjectBuffer)[Get(lightId)].lightColor.xyz * fLDotN;
float t = 0;
if(HasShadowMap(Get(lightObjectBuffer)[Get(lightId)].config)) {
const float depthBias = 0.0005;
const float depthBias = 0.0005;

#ifdef SHADOW_JITTER_SIZE
float2 shadowTexelSize = 1.0/ GetDimensions(Get(shadowMap), NO_SAMPLER).xy;
Expand Down
18 changes: 18 additions & 0 deletions HPL2/resource/math_utils.h.fsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef _MATH_UTILITIES_H_
#define _MATH_UTILITIES_H_

#define PI 3.141592654f

INLINE float3x3 ToNormalMat(float4x4 invModel, float4x4 invView) {
return transpose(mul(float3x3(invModel[0].xyz, invModel[1].xyz, invModel[2].xyz), float3x3(invView[0].xyz, invView[1].xyz, invView[2].xyz)));
}
Expand All @@ -20,4 +22,20 @@ float3 WorldSpaceToTangent(float3 dir, float3 normal, float3 tangent, float3 bit
return float3(a,b,c);
}

float4 boundingSphereForSpotlight(in float3 origin, in float3 forward, in float size, in float angle)
{
float4 boundingSphere;
if(angle > PI/4.0f)
{
boundingSphere.xyz = origin + cos(angle) * size * forward;
boundingSphere.w = sin(angle) * size;
}
else
{
boundingSphere.xyz = origin + size / (2.0f * cos(angle)) * forward;
boundingSphere.w = size / (2.0f * cos(angle));
}

return boundingSphere;
}
#endif
29 changes: 28 additions & 1 deletion HPL2/resource/scene_defs.h.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,39 @@ STRUCT(UniformObject)
#define MATERIAL_INDEX(id) ((MATERIAL_INDEX_MASK & (id)) >> MATERIAL_INDEX_BIT)

STRUCT(PointLight) {
DATA(float4x4, mvp, None);
DATA(float3, lightPos, none);
DATA(uint, config, none);
DATA(float4, lightColor, none);
DATA(float, lightRadius, none);
DATA(uint, __pad0, NONE);
DATA(uint, __pad1, NONE);
DATA(uint, __pad2, NONE);
};

STRUCT(SpotLight) {
DATA(mat4, viewProjection, none);
DATA(float3, lightPos, none);
DATA(uint, config, none);
DATA(float3, direction, none);
DATA(float, angle, none);
DATA(float4, lightColor, none);
DATA(float, radius, none);
DATA(uint, __pad0, NONE);
DATA(uint, __pad1, NONE);
DATA(uint, __pad2, NONE);
};
#define LIGHT_TYPE_POINT_LIGHT 1
#define LIGHT_TYPE_SPOT_LIGHT 2

#define LIGHT_ID_BIT 0
#define LIGHT_INDEX_BIT 8

#define LIGHT_ID_MASK 0xff // 0000 0000 0000 0000 0000 0000 1111 1111
#define LIGHT_INDEX_MASK 0xffff00 // 0000 0000 1111 1111 1111 1111 0000 0000

#define LIGHT_ID(id) ((LIGHT_ID_MASK & (id)) >> LIGHT_ID_BIT)
#define LIGHT_INDEX(id) ((LIGHT_INDEX_MASK & (id)) >> LIGHT_INDEX_BIT)
#define LIGHT_ENCODE(id, index) (((id << LIGHT_ID_BIT) & LIGHT_ID_MASK) | ((index << LIGHT_INDEX_BIT) & LIGHT_INDEX_MASK))

STRUCT(WorldInfo) {
DATA(float, worldFogStart, None);
Expand Down
2 changes: 1 addition & 1 deletion HPL2/resource/scene_light_cluster.comp.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void CS_MAIN(SV_GroupThreadID(uint3) threadInGroupId, SV_GroupID(uint3) groupId)
AtomicAdd(Get(lightClustersCount)[LIGHT_CLUSTER_COUNT_POS(threadInGroupId.x, threadInGroupId.y)], 1, lightArrayPos);

// Add light id to cluster
AtomicExchange(Get(lightClusters)[LIGHT_CLUSTER_DATA_POS(lightArrayPos, threadInGroupId.x, threadInGroupId.y)], groupId.x, lightArrayPos);
AtomicExchange(Get(lightClusters)[LIGHT_CLUSTER_DATA_POS(lightArrayPos, threadInGroupId.x, threadInGroupId.y)], LIGHT_ENCODE(LIGHT_TYPE_POINT_LIGHT, groupId.x), lightArrayPos);
}
}

7 changes: 4 additions & 3 deletions HPL2/resource/scene_light_cluster_resource.h.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ CBUFFER(sceneInfo, UPDATE_FREQ_PER_FRAME, b0, binding = 0) {
DATA(ViewportInfo, viewports[64], None);
};

RES(Buffer(PointLight), pointLights, UPDATE_FREQ_PER_FRAME, t0, binding = 1);
RES(RWBuffer(atomic_uint), lightClustersCount, UPDATE_FREQ_PER_FRAME, u0, binding = 2);
RES(RWBuffer(atomic_uint), lightClusters, UPDATE_FREQ_PER_FRAME, u1, binding = 3);
RES(Buffer(SpotLight), spotLights, UPDATE_FREQ_PER_FRAME, t0, binding = 1);
RES(Buffer(PointLight), pointLights, UPDATE_FREQ_PER_FRAME, t0, binding = 2);
RES(RWBuffer(atomic_uint), lightClustersCount, UPDATE_FREQ_PER_FRAME, u0, binding = 3);
RES(RWBuffer(atomic_uint), lightClusters, UPDATE_FREQ_PER_FRAME, u1, binding = 4);



70 changes: 70 additions & 0 deletions HPL2/resource/scene_light_cluster_spotlight.comp.fsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "scene_light_cluster_resource.h.fsl"
#include "math_utils.h.fsl"


NUM_THREADS(LIGHT_CLUSTER_WIDTH, LIGHT_CLUSTER_HEIGHT, 1)
void CS_MAIN(SV_GroupThreadID(uint3) threadInGroupId, SV_GroupID(uint3) groupId)
{
INIT_MAIN;
const float invClusterWidth = 1.0f / float(LIGHT_CLUSTER_WIDTH);
const float invClusterHeight = 1.0f / float(LIGHT_CLUSTER_HEIGHT);
ViewportInfo viewInfo = Get(viewports)[PRIMARY_VIEWPORT_INDEX];
float2 size = viewInfo.rect.zw;
float4x4 viewProjMat = mul(viewInfo.projMat, viewInfo.viewMat);

// aspect ratio is hard coded to 4/3
const float aspectRatio = 4.0/3.0;
SpotLight lightData = Get(spotLights)[groupId.x];

float4 sphere = boundingSphereForSpotlight(lightData.lightPos, lightData.direction, lightData.radius, lightData.angle);

float4 lightPosWorldSpace = float4(sphere.xyz, 1.0f);
float4 lightPosClipSpace = mul(viewProjMat, lightPosWorldSpace);
float invLightPosW = 1.0f / lightPosClipSpace.w;
float3 lightPos = lightPosClipSpace.xyz * invLightPosW;

float fov = 2.0 * atan((2.0 * viewInfo.zNear)/viewInfo.projMat[1][1]);
float projRadius = 2.0f * sphere.w * (1 / tan(fov * 0.5f)) * invLightPosW;
projRadius *= size.x > size.y ? aspectRatio : 1 / aspectRatio;

// Early exit light if it's behind the camera
if (lightPosClipSpace.w < 0.0f && -lightPosClipSpace.w > sphere.w) {
RETURN();
}

lightPos.x *= aspectRatio;

// Cluster coordinates in post perspective clip space
float clusterLeft = float(threadInGroupId.x) * invClusterWidth;
float clusterTop = float(threadInGroupId.y) * invClusterHeight;
float clusterRight = clusterLeft + invClusterWidth;
float clusterBottom = clusterTop + invClusterHeight;

// Transform coordinates from range [0..1] to range [-1..1]
clusterLeft = clusterLeft * 2.0f - 1.0f;
clusterTop = clusterTop * 2.0f - 1.0f;
clusterRight = clusterRight * 2.0f - 1.0f;
clusterBottom = clusterBottom * 2.0f - 1.0f;

clusterLeft *= aspectRatio;
clusterRight *= aspectRatio;

float clusterCenterX = (clusterLeft + clusterRight) * 0.5f;
float clusterCenterY = (clusterTop + clusterBottom) * 0.5f;
float clusterRadius = distance(float2(clusterLeft, clusterTop), float2(clusterRight, clusterBottom)) * 0.5f;

// Check if the light projection overlaps the cluster: add the light bit to this cluster coords
float distanceToCenter = distance(float2(clusterCenterX, clusterCenterY), lightPos.xy);

if (distanceToCenter - clusterRadius < abs(projRadius))
{
// Increase light count on this cluster
uint lightArrayPos = 0;
AtomicAdd(Get(lightClustersCount)[LIGHT_CLUSTER_COUNT_POS(threadInGroupId.x, threadInGroupId.y)], 1, lightArrayPos);

// Add light id to cluster
AtomicExchange(Get(lightClusters)[LIGHT_CLUSTER_DATA_POS(lightArrayPos, threadInGroupId.x, threadInGroupId.y)], LIGHT_ENCODE(LIGHT_TYPE_SPOT_LIGHT, groupId.x), lightArrayPos);
}
}


7 changes: 4 additions & 3 deletions HPL2/resource/scene_resource.h.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ RES(SamplerState, nearPointWrapSampler, UPDATE_FREQ_NONE, s1, binding = 11);
RES(Tex2D(float4), visibilityTexture, UPDATE_FREQ_PER_FRAME, t0, binding = 12);
RES(Tex2D(float4), dissolveTexture, UPDATE_FREQ_NONE, t0, binding = 13);

RES(Buffer(PointLight), pointLights, UPDATE_FREQ_PER_FRAME, t0, binding = 14);
RES(RWBuffer(atomic_uint), lightClustersCount, UPDATE_FREQ_PER_FRAME, u0, binding = 15);
RES(RWBuffer(atomic_uint), lightClusters, UPDATE_FREQ_PER_FRAME, u1, binding = 16);
RES(Buffer(SpotLight), spotLights, UPDATE_FREQ_PER_FRAME, t0, binding = 14);
RES(Buffer(PointLight), pointLights, UPDATE_FREQ_PER_FRAME, t0, binding = 15);
RES(RWBuffer(atomic_uint), lightClustersCount, UPDATE_FREQ_PER_FRAME, u0, binding = 16);
RES(RWBuffer(atomic_uint), lightClusters, UPDATE_FREQ_PER_FRAME, u1, binding = 17);

RES(SamplerState, sceneFilters[SCENE_MAX_FILTER_COUNT], UPDATE_FREQ_NONE, s1, binding = 20);
RES(Tex2D(float4), sceneTextures[SCENE_MAX_TEXTURE_COUNT], UPDATE_FREQ_PER_FRAME, t5, binding = 20 + SCENE_MAX_FILTER_COUNT);
Expand Down
Loading

0 comments on commit 1652608

Please sign in to comment.