Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
97 lines
3.3 KiB
Plaintext
97 lines
3.3 KiB
Plaintext
#version 450 core
|
|
|
|
/**
|
|
Maximum number of lights per cluster
|
|
*/
|
|
#define MAX_LIGHTS_PER_CLUSTER 100
|
|
|
|
/**
|
|
Bind points for different SSBOs
|
|
*/
|
|
#define CLUSTER_SSBO_BIND_POINT 1
|
|
#define POINT_LIGHT_SSBO_BIND_POINT 2
|
|
#define DIRECT_LIGHT_SSBO_BIND_POINT 3
|
|
|
|
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
|
|
|
struct Cluster {
|
|
vec4 minPoint;
|
|
vec4 maxPoint;
|
|
uint count;
|
|
uint lightIndices[MAX_LIGHTS_PER_CLUSTER];
|
|
};
|
|
|
|
layout(std430, binding = CLUSTER_SSBO_BIND_POINT) restrict buffer clusterSSBO {
|
|
Cluster clusters[];
|
|
};
|
|
|
|
uniform float zNear;
|
|
uniform float zFar;
|
|
|
|
uniform mat4 inverseProjection;
|
|
uniform uvec3 gridSize;
|
|
uniform uvec2 screenDimensions;
|
|
|
|
vec3 screenToView(vec2 screenCoord);
|
|
vec3 lineIntersectionWithZPlane(vec3 startPoint, vec3 endPoint, float zDistance);
|
|
|
|
/*
|
|
context: glViewport is referred to as the "screen"
|
|
clusters are built based on a 2d screen-space grid and depth slices.
|
|
Later when shading, it is easy to figure what cluster a fragment is in based on
|
|
gl_FragCoord.xy and the fragment's z depth from camera
|
|
*/
|
|
void main() {
|
|
uint tileIndex = gl_WorkGroupID.x + (gl_WorkGroupID.y * gridSize.x) +
|
|
(gl_WorkGroupID.z * gridSize.x * gridSize.y);
|
|
vec2 tileSize = screenDimensions / gridSize.xy;
|
|
|
|
// tile in screen-space
|
|
vec2 minTile_screenspace = gl_WorkGroupID.xy * tileSize;
|
|
vec2 maxTile_screenspace = (gl_WorkGroupID.xy + 1) * tileSize;
|
|
|
|
// convert tile to view space sitting on the near plane
|
|
vec3 minTile = screenToView(minTile_screenspace);
|
|
vec3 maxTile = screenToView(maxTile_screenspace);
|
|
|
|
float planeNear =
|
|
zNear * pow(zFar / zNear, gl_WorkGroupID.z / float(gridSize.z));
|
|
float planeFar =
|
|
zNear * pow(zFar / zNear, (gl_WorkGroupID.z + 1) / float(gridSize.z));
|
|
|
|
// the line goes from the eye position in view space (0, 0, 0)
|
|
// through the min/max points of a tile to intersect with a given cluster's near-far planes
|
|
vec3 minPointNear =
|
|
lineIntersectionWithZPlane(vec3(0, 0, 0), minTile, planeNear);
|
|
vec3 minPointFar =
|
|
lineIntersectionWithZPlane(vec3(0, 0, 0), minTile, planeFar);
|
|
vec3 maxPointNear =
|
|
lineIntersectionWithZPlane(vec3(0, 0, 0), maxTile, planeNear);
|
|
vec3 maxPointFar =
|
|
lineIntersectionWithZPlane(vec3(0, 0, 0), maxTile, planeFar);
|
|
|
|
clusters[tileIndex].minPoint = vec4(min(minPointNear, minPointFar), 0.0);
|
|
clusters[tileIndex].maxPoint = vec4(max(maxPointNear, maxPointFar), 0.0);
|
|
}
|
|
|
|
// Returns the intersection point of an infinite line and a
|
|
// plane perpendicular to the Z-axis
|
|
vec3 lineIntersectionWithZPlane(vec3 startPoint, vec3 endPoint, float zDistance) {
|
|
vec3 direction = endPoint - startPoint;
|
|
vec3 normal = vec3(0.0, 0.0, -1.0); // plane normal
|
|
|
|
// skip check if the line is parallel to the plane.
|
|
|
|
float t = (zDistance - dot(normal, startPoint)) / dot(normal, direction);
|
|
return startPoint + t * direction; // the parametric form of the line equation
|
|
}
|
|
vec3 screenToView(vec2 screenCoord) {
|
|
// normalize screenCoord to [-1, 1] and
|
|
// set the NDC depth of the coordinate to be on the near plane. This is -1 by
|
|
// default in OpenGL
|
|
vec4 ndc = vec4(screenCoord / screenDimensions * 2.0 - 1.0, -1.0, 1.0);
|
|
|
|
vec4 viewCoord = inverseProjection * ndc;
|
|
viewCoord /= viewCoord.w;
|
|
return viewCoord.xyz;
|
|
} |