clustered lighting implementation
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2024-09-19 11:29:04 -04:00
parent 5eeb281e0b
commit dc52e375e3
30 changed files with 1211 additions and 632 deletions

View File

@ -1,37 +1,66 @@
#version 330 core
#version 450 core
//FragmentShader.fs
#define NR_POINT_LIGHTS 10
/**
Maximum number of point lights
*/
#define MAX_POINT_LIGHTS 512
/**
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
/**
The direct global light
*/
struct DirectLight {
vec3 direction;
vec3 color;
};
/**
A point light
*/
struct PointLight {
vec4 position;
vec4 color;
float constant;
float linear;
float quadratic;
float radius;
};
/**
A light cluster
*/
struct Cluster {
vec4 minPoint;
vec4 maxPoint;
uint count;
uint lightIndices[MAX_LIGHTS_PER_CLUSTER];
};
out vec4 FragColor;
layout(std430, binding = CLUSTER_SSBO_BIND_POINT) restrict buffer clusterGridSSBO {
Cluster clusters[];
};
layout (std140) uniform Lights {
// this is how many because we have to align
// bytes it SHOULD in multiples of 16, this
// take it where it ACTUALLY is
//
//refer: https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
//
// base alignment aligned offset
//direct light
vec3 dLDirection; // 16 0
vec3 dLAmbient; // 16 16
vec3 dLDiffuse; // 16 32
vec3 dLSpecular; // 16 48
//point light
vec3 pLposition[NR_POINT_LIGHTS]; // 16*10 64
float pLconstant[NR_POINT_LIGHTS]; // 16*10 224
float pLlinear[NR_POINT_LIGHTS]; // 16*10 384
float pLquadratic[NR_POINT_LIGHTS]; // 16*10 544
vec3 pLambient[NR_POINT_LIGHTS]; // 16*10 704
vec3 pLdiffuse[NR_POINT_LIGHTS]; // 16*10 864
vec3 pLspecular[NR_POINT_LIGHTS]; // 16*10 1024
//for a total size of 1184
layout(std430, binding = POINT_LIGHT_SSBO_BIND_POINT) restrict buffer pointLightSSBO {
PointLight pointLight[];
};
layout(std430, binding = DIRECT_LIGHT_SSBO_BIND_POINT) restrict buffer dirLightSSBO {
DirectLight directLight;
};
struct Material {
@ -41,6 +70,7 @@ struct Material {
};
in vec3 FragPos;
in vec3 ViewFragPos;
in vec3 Normal;
in vec2 TexCoord;
in vec4 FragPosLightSpace;
@ -60,11 +90,18 @@ uniform int hasTransparency;
//light depth map
uniform sampler2D shadowMap;
/**
Used for light cluster calculation
*/
uniform float zNear;
uniform float zFar;
uniform uvec3 gridSize;
uniform uvec2 screenDimensions;
// function prototypes
// vec3 CalcDirLight(vec3 normal, vec3 viewDir);
// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir);
// vec3 CalcSpotLight(vec3 normal, vec3 fragPos, vec3 viewDir);
uint findCluster(vec3 viewspaceFragPos, float zNear, float zFar);
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir);
float calcLightIntensityTotal(vec3 normal);
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal);
@ -76,54 +113,47 @@ void main(){
vec3 viewDir = normalize(viewPos - FragPos);
//grab light intensity
float lightIntensity = calcLightIntensityTotal(norm);
vec3 lightIntensity = vec3(calcLightIntensityTotal(norm));
//get color of base texture
vec3 textureColor = texture(material.diffuse, TexCoord).rgb;
//shadow
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm);
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), norm);
//
//point light calculations
vec3 lightAmount = vec3(0);
uint clusterIndex = findCluster(ViewFragPos, zNear, zFar);
uint pointLightCount = clusters[clusterIndex].count;
for(int i = 0; i < pointLightCount; i++){
uint pointLightIndex = clusters[clusterIndex].lightIndices[i];
PointLight pointLight = pointLight[pointLightIndex];
lightIntensity = lightIntensity + CalcPointLight(pointLight, norm, FragPos, viewDir);
}
//error checking on light clusters
if(pointLightCount > MAX_LIGHTS_PER_CLUSTER){
FragColor = vec4(1.0f,0,0,1.0f);
return;
}
//calculate final color
vec3 finalColor = textureColor * lightIntensity * max(shadow,0.4);
// vec3 lightAmount = CalcDirLight(norm, viewDir);
// for(int i = 0; i < NR_POINT_LIGHTS; i++){
// lightAmount += CalcPointLight(i, norm, FragPos, viewDir);
// }
//this final calculation is for transparency
FragColor = vec4(finalColor, texture(material.diffuse, TexCoord).a);//texture(ourTexture, TexCoord);//vec4(result, 1.0);
}
// calculates the color when using a directional light.
// vec3 CalcDirLight(vec3 normal, vec3 viewDir){
// vec3 lightDir = normalize(-dLDirection);
// // diffuse shading
// float diff = max(dot(normal, lightDir), 0.0);
// // specular shading
// // vec3 reflectDir = reflect(-lightDir, normal);
// // float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// // combine results
// vec3 texColor = texture(material.diffuse, TexCoord).rgb;
// vec3 diffuse = dLDiffuse * diff;
// //vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoord).rgb);
// float shadow = ShadowCalculation(FragPosLightSpace, lightDir, normal);
// return ( dLAmbient + (1.0-shadow) * diffuse ) * texColor;// + specular);
// }
//
float calcLightIntensityAmbient(){
//calculate average of ambient light
float avg = (dLAmbient.x + dLAmbient.y + dLAmbient.z)/3.0;
float avg = (directLight.color.x + directLight.color.y + directLight.color.z)/3.0;
return avg;
}
//
float calcLightIntensityDir(vec3 normal){
vec3 lightDir = normalize(-dLDirection);
vec3 lightDir = normalize(-directLight.direction);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
@ -146,63 +176,53 @@ float calcLightIntensityTotal(vec3 normal){
//
vec3 getTotalLightColor(vec3 normal){
//get the direct light color adjusted for intensity
vec3 diffuseLightColor = dLDiffuse * calcLightIntensityDir(normal);
vec3 diffuseLightColor = directLight.color * calcLightIntensityDir(normal);
//sum light colors
vec3 totalLightColor = diffuseLightColor;
return totalLightColor;
}
vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){
vec3 lightDir = normalize(pLposition[i] - fragPos);
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir){
vec3 lightDir = normalize(pointLight.position.xyz - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
// vec3 reflectDir = reflect(-lightDir, normal);
// float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(pLposition[i] - fragPos);
float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance));
float distance = length(pointLight.position.xyz - fragPos);
float attenuation = 1.0 / (pointLight.constant + pointLight.linear * distance + pointLight.quadratic * (distance * distance));
if(distance > pointLight.radius){
attenuation = 0;
}
// combine results
vec3 ambient = pLambient[i];// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 diffuse = pLdiffuse[i] * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 ambient = pointLight.color.xyz;// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 diffuse = pointLight.color.xyz * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
// vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz;
ambient *= attenuation;
diffuse *= attenuation;
ambient = ambient * attenuation;
diffuse = diffuse * attenuation;
// specular *= attenuation;
vec3 specular = vec3(0,0,0);
vec3 finalValue = (ambient + diffuse + specular);
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
vec3 finalValue = vec3(0);
if(distance < pointLight.radius){
finalValue = (ambient + diffuse + specular);
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
}
return finalValue;
}
// // calculates the color when using a point light.
// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){
// vec3 lightDir = normalize(pLposition[i] - fragPos);
// // diffuse shading
// float diff = max(dot(normal, lightDir), 0.0);
// // specular shading
// // vec3 reflectDir = reflect(-lightDir, normal);
// // float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// // attenuation
// float distance = length(pLposition[i] - fragPos);
// float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance));
// // combine results
// vec3 ambient = pLambient[i];// * vec4(texture(material.diffuse, TexCoord)).xyz;
// vec3 diffuse = pLdiffuse[i] * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
// // vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz;
// ambient *= attenuation;
// diffuse *= attenuation;
// // specular *= attenuation;
// vec3 specular = vec3(0,0,0);
// vec3 finalValue = (ambient + diffuse + specular);
// finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
// return finalValue;
// }
/**
Finds the light cluster this fragment belongs to
*/
uint findCluster(vec3 viewspaceFragPos, float zNear, float zFar){
uint zTile = uint((log(abs(viewspaceFragPos.z) / zNear) * gridSize.z) / log(zFar / zNear));
vec2 tileSize = screenDimensions / gridSize.xy;
uvec3 tile = uvec3(gl_FragCoord.xy / tileSize, zTile);
return tile.x + (tile.y * gridSize.x) + (tile.z * gridSize.x * gridSize.y);
}
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){

View File

@ -30,6 +30,7 @@ uniform int numBones;
//output buffers
out vec3 Normal;
out vec3 FragPos;
out vec3 ViewFragPos;
out vec2 TexCoord;
out vec4 FragPosLightSpace;
@ -59,6 +60,7 @@ void main() {
//push frag, normal, and texture positions to fragment shader
FragPos = vec3(model * FinalVertex);
ViewFragPos = vec3(view * model * FinalVertex);
Normal = mat3(transpose(inverse(model))) * FinalNormal.xyz;
TexCoord = aTex;

View File

@ -0,0 +1,97 @@
#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;
}

View File

@ -0,0 +1,87 @@
#version 450 core
/**
Maximum number of lights per cluster
*/
#define MAX_LIGHTS_PER_CLUSTER 100
/**
The number of "threads" to run
*/
#define CULL_LOCAL_SIZE 128
/**
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 = CULL_LOCAL_SIZE, local_size_y = 1, local_size_z = 1) in;
struct PointLight {
vec4 position;
vec4 color;
float constant;
float linear;
float quadratic;
float radius;
};
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[];
};
layout(std430, binding = POINT_LIGHT_SSBO_BIND_POINT) restrict buffer lightSSBO {
PointLight pointLight[];
};
uniform mat4 viewMatrix;
bool testSphereAABB(uint i, Cluster c);
// each invocation of main() is a thread processing a cluster
void main() {
uint lightCount = pointLight.length();
uint index = gl_WorkGroupID.x * CULL_LOCAL_SIZE + gl_LocalInvocationID.x;
Cluster cluster = clusters[index];
// we need to reset count because culling runs every frame.
// otherwise it would accumulate.
cluster.count = 0;
for (uint i = 0; i < lightCount; ++i){
if (testSphereAABB(i, cluster) && cluster.count < 100){
cluster.lightIndices[cluster.count] = i;
cluster.count++;
}
}
clusters[index] = cluster;
}
bool sphereAABBIntersection(vec3 center, float radius, vec3 aabbMin, vec3 aabbMax) {
// closest point on the AABB to the sphere center
vec3 closestPoint = clamp(center, aabbMin, aabbMax);
// squared distance between the sphere center and closest point
float distanceSquared = dot(closestPoint - center, closestPoint - center);
return distanceSquared <= radius * radius;
}
// this just unpacks data for sphereAABBIntersection
bool testSphereAABB(uint i, Cluster cluster) {
vec3 center = vec3(viewMatrix * pointLight[i].position);
float radius = pointLight[i].radius;
vec3 aabbMin = cluster.minPoint.xyz;
vec3 aabbMax = cluster.maxPoint.xyz;
return sphereAABBIntersection(center, radius, aabbMin, aabbMax);
}

View File

@ -1,36 +1,67 @@
#version 400 core
#version 450 core
/**
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
/**
Maximum number of point lights
*/
#define MAX_POINT_LIGHTS 512
/**
Maximum number of lights per cluster
*/
#define MAX_LIGHTS_PER_CLUSTER 100
/**
The direct global light
*/
struct DirectLight {
vec3 direction;
vec3 color;
};
/**
A point light
*/
struct PointLight {
vec4 position;
vec4 color;
float constant;
float linear;
float quadratic;
float radius;
};
/**
A light cluster
*/
struct Cluster {
vec4 minPoint;
vec4 maxPoint;
uint count;
uint lightIndices[MAX_LIGHTS_PER_CLUSTER];
};
#define NR_POINT_LIGHTS 10
layout (location = 0) out vec4 accum;
layout (location = 1) out float reveal;
layout(std430, binding = CLUSTER_SSBO_BIND_POINT) restrict buffer clusterGridSSBO {
Cluster clusters[];
};
layout (std140) uniform Lights {
// this is how many because we have to align
// bytes it SHOULD in multiples of 16, this
// take it where it ACTUALLY is
//
//refer: https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
//
// base alignment aligned offset
//direct light
vec3 dLDirection; // 16 0
vec3 dLAmbient; // 16 16
vec3 dLDiffuse; // 16 32
vec3 dLSpecular; // 16 48
//point light
vec3 pLposition[NR_POINT_LIGHTS]; // 16*10 64
float pLconstant[NR_POINT_LIGHTS]; // 16*10 224
float pLlinear[NR_POINT_LIGHTS]; // 16*10 384
float pLquadratic[NR_POINT_LIGHTS]; // 16*10 544
vec3 pLambient[NR_POINT_LIGHTS]; // 16*10 704
vec3 pLdiffuse[NR_POINT_LIGHTS]; // 16*10 864
vec3 pLspecular[NR_POINT_LIGHTS]; // 16*10 1024
//for a total size of 1184
layout(std430, binding = POINT_LIGHT_SSBO_BIND_POINT) restrict buffer pointLightSSBO {
PointLight pointLight[];
};
layout(std430, binding = DIRECT_LIGHT_SSBO_BIND_POINT) restrict buffer dirLightSSBO {
DirectLight directLight;
};
struct Material {
@ -42,6 +73,7 @@ struct Material {
//inputs
in vec3 FragPos;
in vec3 ViewFragPos;
in vec3 Normal;
in vec2 TexCoord;
in vec4 FragPosLightSpace;
@ -58,9 +90,20 @@ uniform Material material;
//light depth map
uniform sampler2D shadowMap;
/**
Used for light cluster calculation
*/
uniform float zNear;
uniform float zFar;
uniform uvec3 gridSize;
uniform uvec2 screenDimensions;
uniform mat4 view;
//function prototypes
float calcLightIntensityTotal(vec3 normal);
uint findCluster(vec3 FragPos, float zNear, float zFar);
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir);
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal);
float linearizeDepth(float d,float zNear,float zFar);
float weightCalcOrigin(float finalAlpha, float zLoc, float linearizedLoc);
@ -74,17 +117,33 @@ void main(){
vec3 viewDir = normalize(viewPos - FragPos);
//grab light intensity
float lightIntensity = calcLightIntensityTotal(norm);
vec3 lightIntensity = vec3(calcLightIntensityTotal(norm));
//get color of base texture
vec4 textureColor = texture(material.diffuse, TexCoord);
vec3 textureRGB = textureColor.rgb;
//shadow
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm);
vec3 shadowModifiedColor = textureRGB * lightIntensity * max(shadow, 0.4);
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), norm);
//
//point light calculations
uint clusterIndex = findCluster(ViewFragPos, zNear, zFar);
uint pointLightCount = clusters[clusterIndex].count;
for(int i = 0; i < pointLightCount; i++){
uint pointLightIndex = clusters[clusterIndex].lightIndices[i];
PointLight pointLight = pointLight[pointLightIndex];
lightIntensity = lightIntensity + CalcPointLight(pointLight, norm, FragPos, viewDir);
}
//error checking on light clusters
if(pointLightCount > MAX_LIGHTS_PER_CLUSTER){
accum = vec4(1.0f,0.0f,0.0f,1);
reveal = textureColor.a;
return;
}
//calculate final color
vec3 shadowModifiedColor = textureRGB * lightIntensity * max(shadow, 0.4);
vec4 finalColor = vec4(shadowModifiedColor,textureColor.a);
//calculate weight function
@ -127,13 +186,13 @@ float linearizeDepth(float d,float zNear,float zFar){
float calcLightIntensityAmbient(){
//calculate average of ambient light
float avg = (dLAmbient.x + dLAmbient.y + dLAmbient.z)/3.0;
float avg = (directLight.color.x + directLight.color.y + directLight.color.z)/3.0;
return avg;
}
//
float calcLightIntensityDir(vec3 normal){
vec3 lightDir = normalize(-dLDirection);
vec3 lightDir = normalize(-directLight.direction);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
@ -156,38 +215,55 @@ float calcLightIntensityTotal(vec3 normal){
//
vec3 getTotalLightColor(vec3 normal){
//get the direct light color adjusted for intensity
vec3 diffuseLightColor = dLDiffuse * calcLightIntensityDir(normal);
vec3 diffuseLightColor = directLight.color * calcLightIntensityDir(normal);
//sum light colors
vec3 totalLightColor = diffuseLightColor;
return totalLightColor;
}
vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){
vec3 lightDir = normalize(pLposition[i] - fragPos);
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir){
vec3 lightDir = normalize(pointLight.position.xyz - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
// vec3 reflectDir = reflect(-lightDir, normal);
// float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(pLposition[i] - fragPos);
float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance));
float distance = length(pointLight.position.xyz - fragPos);
float attenuation = 1.0 / (pointLight.constant + pointLight.linear * distance + pointLight.quadratic * (distance * distance));
if(distance > pointLight.radius){
attenuation = 0;
}
// combine results
vec3 ambient = pLambient[i];// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 diffuse = pLdiffuse[i] * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 ambient = pointLight.color.xyz;// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 diffuse = pointLight.color.xyz * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
// vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz;
ambient *= attenuation;
diffuse *= attenuation;
ambient = ambient * attenuation;
diffuse = diffuse * attenuation;
// specular *= attenuation;
vec3 specular = vec3(0,0,0);
vec3 finalValue = (ambient + diffuse + specular);
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
vec3 finalValue = vec3(0);
if(distance < pointLight.radius){
finalValue = (ambient + diffuse + specular);
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
}
return finalValue;
}
/**
Finds the light cluster this fragment belongs to
*/
uint findCluster(vec3 viewspaceFragPos, float zNear, float zFar){
uint zTile = uint((log(abs(viewspaceFragPos.z) / zNear) * gridSize.z) / log(zFar / zNear));
vec2 tileSize = screenDimensions / gridSize.xy;
uvec3 tile = uvec3(gl_FragCoord.xy / tileSize, zTile);
return tile.x + (tile.y * gridSize.x) + (tile.z * gridSize.x * gridSize.y);
}

View File

@ -30,6 +30,7 @@ uniform int numBones;
//output buffers
out vec3 Normal;
out vec3 FragPos;
out vec3 ViewFragPos;
out vec2 TexCoord;
out vec4 FragPosLightSpace;
@ -59,6 +60,7 @@ void main() {
//push frag, normal, and texture positions to fragment shader
FragPos = vec3(model * FinalVertex);
ViewFragPos = vec3(view * model * FinalVertex);
Normal = mat3(transpose(inverse(model))) * FinalNormal.xyz;
TexCoord = aTex;

View File

@ -1,37 +1,68 @@
#version 330 core
#version 450 core
//foliage.fs
#define NR_POINT_LIGHTS 10
/**
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
/**
Maximum number of point lights
*/
#define MAX_POINT_LIGHTS 512
/**
Maximum number of lights per cluster
*/
#define MAX_LIGHTS_PER_CLUSTER 100
/**
The direct global light
*/
struct DirectLight {
vec3 direction;
vec3 color;
};
/**
A point light
*/
struct PointLight {
vec4 position;
vec4 color;
float constant;
float linear;
float quadratic;
float radius;
};
/**
A light cluster
*/
struct Cluster {
vec4 minPoint;
vec4 maxPoint;
uint count;
uint lightIndices[MAX_LIGHTS_PER_CLUSTER];
};
out vec4 FragColor;
layout (std140) uniform Lights {
// this is how many because we have to align
// bytes it SHOULD in multiples of 16, this
// take it where it ACTUALLY is
//
//refer: https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
//
// base alignment aligned offset
//direct light
vec3 dLDirection; // 16 0
vec3 dLAmbient; // 16 16
vec3 dLDiffuse; // 16 32
vec3 dLSpecular; // 16 48
layout(std430, binding = CLUSTER_SSBO_BIND_POINT) restrict buffer clusterGridSSBO {
Cluster clusters[];
};
//point light
vec3 pLposition[NR_POINT_LIGHTS]; // 16*10 64
float pLconstant[NR_POINT_LIGHTS]; // 16*10 224
float pLlinear[NR_POINT_LIGHTS]; // 16*10 384
float pLquadratic[NR_POINT_LIGHTS]; // 16*10 544
vec3 pLambient[NR_POINT_LIGHTS]; // 16*10 704
vec3 pLdiffuse[NR_POINT_LIGHTS]; // 16*10 864
vec3 pLspecular[NR_POINT_LIGHTS]; // 16*10 1024
//for a total size of 1184
layout(std430, binding = POINT_LIGHT_SSBO_BIND_POINT) restrict buffer pointLightSSBO {
PointLight pointLight[];
};
layout(std430, binding = DIRECT_LIGHT_SSBO_BIND_POINT) restrict buffer dirLightSSBO {
DirectLight directLight;
};
struct Material {
@ -41,6 +72,7 @@ struct Material {
};
in vec3 FragPos;
in vec3 ViewFragPos;
in vec3 Normal;
in vec2 TexCoord;
in vec4 FragPosLightSpace;
@ -62,11 +94,19 @@ uniform int hasTransparency;
//light depth map
uniform sampler2D shadowMap;
/**
Used for light cluster calculation
*/
uniform float zNear;
uniform float zFar;
uniform uvec3 gridSize;
uniform uvec2 screenDimensions;
uniform mat4 view;
// function prototypes
// vec3 CalcDirLight(vec3 normal, vec3 viewDir);
// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir);
// vec3 CalcSpotLight(vec3 normal, vec3 fragPos, vec3 viewDir);
uint findCluster(vec3 FragPos, float zNear, float zFar);
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir);
float calcLightIntensityTotal(vec3 normal);
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal);
float easeIn(float interpolator);
@ -90,7 +130,7 @@ void main(){
vec3 viewDir = normalize(viewPos - FragPos);
//grab light intensity
float lightIntensity = calcLightIntensityTotal(norm);
vec3 lightIntensity = vec3(calcLightIntensityTotal(norm));
//get color of base texture
// vec3 textureColor = vec3((norm.x + 1) / 2.0, norm.y, 1.0 - (norm.x + 1) / 2.0);
@ -98,7 +138,22 @@ void main(){
// vec3 textureColor = vec3(0.17647,0.4,0.09411);//texture(material.diffuse, TexCoord).rgb;
//shadow
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm);
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), norm);
//
//point light calculations
uint clusterIndex = findCluster(ViewFragPos, zNear, zFar);
uint pointLightCount = clusters[clusterIndex].count;
for(int i = 0; i < pointLightCount; i++){
uint pointLightIndex = clusters[clusterIndex].lightIndices[i];
PointLight pointLight = pointLight[pointLightIndex];
lightIntensity = lightIntensity + CalcPointLight(pointLight, norm, FragPos, viewDir);
}
//error checking on light clusters
if(pointLightCount > MAX_LIGHTS_PER_CLUSTER){
FragColor = vec4(1.0f,0.0f,0.0f,1);
return;
}
//calculate final color
vec3 finalColor = textureColor * lightIntensity;// * max(shadow,0.4);
@ -133,13 +188,13 @@ void main(){
//
float calcLightIntensityAmbient(){
//calculate average of ambient light
float avg = (dLAmbient.x + dLAmbient.y + dLAmbient.z)/3.0;
float avg = (directLight.color.x + directLight.color.y + directLight.color.z)/3.0;
return avg;
}
//
float calcLightIntensityDir(vec3 normal){
vec3 lightDir = normalize(-dLDirection);
vec3 lightDir = normalize(-directLight.direction);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
@ -162,64 +217,53 @@ float calcLightIntensityTotal(vec3 normal){
//
vec3 getTotalLightColor(vec3 normal){
//get the direct light color adjusted for intensity
vec3 diffuseLightColor = dLDiffuse * calcLightIntensityDir(normal);
vec3 diffuseLightColor = directLight.color * calcLightIntensityDir(normal);
//sum light colors
vec3 totalLightColor = diffuseLightColor;
return totalLightColor;
}
vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){
vec3 lightDir = normalize(pLposition[i] - fragPos);
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir){
vec3 lightDir = normalize(pointLight.position.xyz - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
// vec3 reflectDir = reflect(-lightDir, normal);
// float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(pLposition[i] - fragPos);
float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance));
float distance = length(pointLight.position.xyz - fragPos);
float attenuation = 1.0 / (pointLight.constant + pointLight.linear * distance + pointLight.quadratic * (distance * distance));
if(distance > pointLight.radius){
attenuation = 0;
}
// combine results
vec3 ambient = pLambient[i];// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 diffuse = pLdiffuse[i] * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 ambient = pointLight.color.xyz;// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 diffuse = pointLight.color.xyz * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
// vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz;
ambient *= attenuation;
diffuse *= attenuation;
ambient = ambient * attenuation;
diffuse = diffuse * attenuation;
// specular *= attenuation;
vec3 specular = vec3(0,0,0);
vec3 finalValue = (ambient + diffuse + specular);
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
vec3 finalValue = vec3(0);
if(distance < pointLight.radius){
finalValue = (ambient + diffuse + specular);
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
}
return finalValue;
}
// // calculates the color when using a point light.
// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){
// vec3 lightDir = normalize(pLposition[i] - fragPos);
// // diffuse shading
// float diff = max(dot(normal, lightDir), 0.0);
// // specular shading
// // vec3 reflectDir = reflect(-lightDir, normal);
// // float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// // attenuation
// float distance = length(pLposition[i] - fragPos);
// float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance));
// // combine results
// vec3 ambient = pLambient[i];// * vec4(texture(material.diffuse, TexCoord)).xyz;
// vec3 diffuse = pLdiffuse[i] * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
// // vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz;
// ambient *= attenuation;
// diffuse *= attenuation;
// // specular *= attenuation;
// vec3 specular = vec3(0,0,0);
// vec3 finalValue = (ambient + diffuse + specular);
// finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
// return finalValue;
// }
/**
Finds the light cluster this fragment belongs to
*/
uint findCluster(vec3 viewspaceFragPos, float zNear, float zFar){
uint zTile = uint((log(abs(viewspaceFragPos.z) / zNear) * gridSize.z) / log(zFar / zNear));
vec2 tileSize = screenDimensions / gridSize.xy;
uvec3 tile = uvec3(gl_FragCoord.xy / tileSize, zTile);
return tile.x + (tile.y * gridSize.x) + (tile.z * gridSize.x * gridSize.y);
}
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){

View File

@ -40,6 +40,7 @@ uniform float time;
//output buffers
out vec3 Normal;
out vec3 FragPos;
out vec3 ViewFragPos;
out vec2 TexCoord;
out vec4 FragPosLightSpace;
out vec3 normalRot1;
@ -156,6 +157,7 @@ void main() {
//push frag, normal, and texture positions to fragment shader
//
FragPos = vec3(FinalVertex);
ViewFragPos = vec3(view * model * FinalVertex);
Normal = vec3(FinalNormal);
TexCoord = aTex;

View File

@ -1,4 +1,4 @@
#version 330 core
#version 450 core
//texture defines
#define ATLAS_ELEMENT_DIM 256.0
@ -8,37 +8,67 @@
#define ATLAS_NORMALIZED_ELEMENT_WIDTH_FULL 0.03125 //used to properly shift from texture to texture in the atlas
#define NR_POINT_LIGHTS 10
/**
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
/**
Maximum number of point lights
*/
#define MAX_POINT_LIGHTS 512
/**
Maximum number of lights per cluster
*/
#define MAX_LIGHTS_PER_CLUSTER 100
/**
The direct global light
*/
struct DirectLight {
vec3 direction;
vec3 color;
};
/**
A point light
*/
struct PointLight {
vec4 position;
vec4 color;
float constant;
float linear;
float quadratic;
float radius;
};
/**
A light cluster
*/
struct Cluster {
vec4 minPoint;
vec4 maxPoint;
uint count;
uint lightIndices[MAX_LIGHTS_PER_CLUSTER];
};
out vec4 FragColor;
layout(std430, binding = CLUSTER_SSBO_BIND_POINT) restrict buffer clusterGridSSBO {
Cluster clusters[];
};
layout (std140) uniform Lights {
// this is how many because we have to align
// bytes it SHOULD in multiples of 16, this
// take it where it ACTUALLY is
//
//refer: https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
//
// base alignment aligned offset
//direct light
vec3 dLDirection; // 16 0
vec3 dLAmbient; // 16 16
vec3 dLDiffuse; // 16 32
vec3 dLSpecular; // 16 48
//point light
vec3 pLposition[NR_POINT_LIGHTS]; // 16*10 64
float pLconstant[NR_POINT_LIGHTS]; // 16*10 224
float pLlinear[NR_POINT_LIGHTS]; // 16*10 384
float pLquadratic[NR_POINT_LIGHTS]; // 16*10 544
vec3 pLambient[NR_POINT_LIGHTS]; // 16*10 704
vec3 pLdiffuse[NR_POINT_LIGHTS]; // 16*10 864
vec3 pLspecular[NR_POINT_LIGHTS]; // 16*10 1024
//for a total size of 1184
layout(std430, binding = POINT_LIGHT_SSBO_BIND_POINT) restrict buffer pointLightSSBO {
PointLight pointLight[];
};
layout(std430, binding = DIRECT_LIGHT_SSBO_BIND_POINT) restrict buffer dirLightSSBO {
DirectLight directLight;
};
struct Material {
@ -48,6 +78,7 @@ struct Material {
};
in vec3 FragPos;
in vec3 ViewFragPos;
in vec3 Normal;
in vec2 texPlane1;
in vec2 texPlane2;
@ -71,11 +102,19 @@ uniform int hasTransparency;
//light depth map
uniform sampler2D shadowMap;
/**
Used for light cluster calculation
*/
uniform float zNear;
uniform float zFar;
uniform uvec3 gridSize;
uniform uvec2 screenDimensions;
uniform mat4 view;
// function prototypes
// vec3 CalcDirLight(vec3 normal, vec3 viewDir);
// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir);
// vec3 CalcSpotLight(vec3 normal, vec3 fragPos, vec3 viewDir);
uint findCluster(vec3 FragPos, float zNear, float zFar);
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir);
float calcLightIntensityTotal(vec3 normal);
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal);
vec3 getColor(vec2 texPlane1, vec2 texPlane2, vec2 texPlane3, vec3 normal, vec3 samplerIndexVec, vec3 samplerRatioVec, Material material);
@ -85,20 +124,31 @@ void main(){
vec3 viewDir = normalize(viewPos - FragPos);
//grab light intensity
float lightIntensity = calcLightIntensityTotal(norm);
vec3 lightIntensity = vec3(calcLightIntensityTotal(norm));
//get color of base texture
vec3 textureColor = getColor(texPlane1, texPlane2, texPlane3, norm, samplerIndexVec, samplerRatioVec, material);
//shadow
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm);
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), norm);
//
//point light calculations
uint clusterIndex = findCluster(ViewFragPos, zNear, zFar);
uint pointLightCount = clusters[clusterIndex].count;
for(int i = 0; i < pointLightCount; i++){
uint pointLightIndex = clusters[clusterIndex].lightIndices[i];
PointLight pointLight = pointLight[pointLightIndex];
lightIntensity = lightIntensity + CalcPointLight(pointLight, norm, FragPos, viewDir);
}
//error checking on light clusters
if(pointLightCount > MAX_LIGHTS_PER_CLUSTER){
FragColor = vec4(1.0f,0.0f,0.0f,1);
return;
}
//calculate final color
vec3 finalColor = textureColor * lightIntensity * max(shadow,0.4);
// vec3 lightAmount = CalcDirLight(norm, viewDir);
// for(int i = 0; i < NR_POINT_LIGHTS; i++){
// lightAmount += CalcPointLight(i, norm, FragPos, viewDir);
// }
//this final calculation is for transparency
FragColor = vec4(finalColor, 1);
@ -188,13 +238,13 @@ vec3 getColor(vec2 texPlane1, vec2 texPlane2, vec2 texPlane3, vec3 normal, vec3
//
float calcLightIntensityAmbient(){
//calculate average of ambient light
float avg = (dLAmbient.x + dLAmbient.y + dLAmbient.z)/3.0;
float avg = (directLight.color.x + directLight.color.y + directLight.color.z)/3.0;
return avg;
}
//
float calcLightIntensityDir(vec3 normal){
vec3 lightDir = normalize(-dLDirection);
vec3 lightDir = normalize(-directLight.direction);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
@ -217,37 +267,54 @@ float calcLightIntensityTotal(vec3 normal){
//
vec3 getTotalLightColor(vec3 normal){
//get the direct light color adjusted for intensity
vec3 diffuseLightColor = dLDiffuse * calcLightIntensityDir(normal);
vec3 diffuseLightColor = directLight.color * calcLightIntensityDir(normal);
//sum light colors
vec3 totalLightColor = diffuseLightColor;
return totalLightColor;
}
vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){
vec3 lightDir = normalize(pLposition[i] - fragPos);
vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir){
vec3 lightDir = normalize(pointLight.position.xyz - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
// vec3 reflectDir = reflect(-lightDir, normal);
// float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(pLposition[i] - fragPos);
float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance));
float distance = length(pointLight.position.xyz - fragPos);
float attenuation = 1.0 / (pointLight.constant + pointLight.linear * distance + pointLight.quadratic * (distance * distance));
if(distance > pointLight.radius){
attenuation = 0;
}
// combine results
vec3 ambient = pLambient[i];
vec3 diffuse = pLdiffuse[i] * diff;
ambient *= attenuation;
diffuse *= attenuation;
vec3 ambient = pointLight.color.xyz;// * vec4(texture(material.diffuse, TexCoord)).xyz;
vec3 diffuse = pointLight.color.xyz * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz;
// vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz;
ambient = ambient * attenuation;
diffuse = diffuse * attenuation;
// specular *= attenuation;
vec3 specular = vec3(0,0,0);
vec3 finalValue = (ambient + diffuse + specular);
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
vec3 finalValue = vec3(0);
if(distance < pointLight.radius){
finalValue = (ambient + diffuse + specular);
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
}
return finalValue;
}
/**
Finds the light cluster this fragment belongs to
*/
uint findCluster(vec3 viewspaceFragPos, float zNear, float zFar){
uint zTile = uint((log(abs(viewspaceFragPos.z) / zNear) * gridSize.z) / log(zFar / zNear));
vec2 tileSize = screenDimensions / gridSize.xy;
uvec3 tile = uvec3(gl_FragCoord.xy / tileSize, zTile);
return tile.x + (tile.y * gridSize.x) + (tile.z * gridSize.x * gridSize.y);
}
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){

View File

@ -26,6 +26,7 @@ uniform mat4 lightSpaceMatrix;
//output buffers
out vec3 Normal;
out vec3 FragPos;
out vec3 ViewFragPos;
out vec2 texPlane1;
out vec2 texPlane2;
out vec2 texPlane3;
@ -44,6 +45,7 @@ void main() {
//push frag, normal, and texture positions to fragment shader
FragPos = vec3(model * FinalVertex);
ViewFragPos = vec3(view * model * FinalVertex);
Normal = mat3(transpose(inverse(model))) * aNormal;
//reference https://catlikecoding.com/unity/tutorials/advanced-rendering/triplanar-mapping/

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file
#Mon Sep 16 19:58:57 EDT 2024
buildNumber=333
#Wed Sep 18 20:37:06 EDT 2024
buildNumber=338

View File

@ -5,13 +5,21 @@ Design notes for the chemistry system
Ideas for the chemistry system:
- fire
- Torch
- Fire Arrow
- water
- bucket
- electricity
- lightning arrow
- ice
- ice chunk/block
- light
- Glittering chunk
- Wind/fans
- Placeable fan
- gravity
- stabilization
- metal parts / conductivity
- light
- mirrors
- plants burning
- plants growing really fast
@ -20,6 +28,5 @@ Ideas for the chemistry system:
- spinning mechanisms and gears
- weighing things down and measuring scales w/ weight
- trampolines
- Wind/fans
- Weight
- Music

View File

@ -37,6 +37,8 @@
- Spawn player in a town with a quest to complete a nearby dungeon
+ bug fixes
Fix light cluster mapping for foliage shader
Fix ui elements not storing default discrete world size on level editor menu
Fix skeleton right strafe
Fix block tree preventing initiating an attack
Fix return to title menu synchronization bug

View File

@ -801,6 +801,11 @@ Migrate documentation
Netcode generator qol fixes
Combat Stances Component
Remove geometry shader support
Work on clustered lighting
(09/19/2024)
Cluster lighting completed
# TODO
@ -836,11 +841,15 @@ Code Generation
Rearchitecting
- Main render is a ui element (that we can have multiple of)
- Shader handling updates to allow for library based shader compilation
- Also allow injecting consts from the engine itself (ie max lights is dynamically injected, that way never have to worry about .glsl and .java not aligning)
Code cleanup
- Rename "BehaviorTree" to be "Component" (what it actually is)
- Refactor ground movement components
- Refactor menu clases to be under electrosphere.client package
- Rename "ShaderProgram" to "VisualShader"
- Have ComputeShader and VisualShader use same static method for uploading uniforms
Goof off today requirements:
Transvoxel implementation

View File

@ -232,6 +232,24 @@ public class CameraEntityUtils {
return rVal;
}
/**
* Gets the near clip of the camera
* @param camera The camera
* @return The near clip
*/
public static float getNearClip(Entity camera){
return Globals.nearClip;
}
/**
* Gets the far clip of the camera
* @param camera The camera
* @return The far clip
*/
public static float getFarClip(Entity camera){
return Globals.userSettings.getGraphicsViewDistance();
}
/**
* Gets the rotation quaternion from a camera entity
* @param entity The entity

View File

@ -250,6 +250,7 @@ public class Globals {
public static float verticalFOV = 90;
public static float aspectRatio = 2.0f;
public static float nearClip = 0.001f;
//matrices for drawing models
public static Matrix4f viewMatrix = new Matrix4f();
@ -651,6 +652,10 @@ public class Globals {
assetManager.addShaderToQueue("Shaders/ui/debug/windowBorder/windowBound.vs", "Shaders/ui/debug/windowBorder/windowBound.fs");
assetManager.addShaderToQueue("Shaders/ui/debug/windowContentBorder/windowContentBound.vs", "Shaders/ui/debug/windowContentBorder/windowContentBound.fs");
//compute shaders
assetManager.addComputeShaderToQueue(AssetDataStrings.COMPUTE_LIGHT_CLUSTER);
assetManager.addComputeShaderToQueue(AssetDataStrings.COMPUTE_LIGHT_CULL);
//as these assets are required for the renderer to work, we go ahead and
//load them into memory now. The loading time penalty is worth it I think.
Globals.assetManager.loadAssetsInQueue();

View File

@ -45,4 +45,10 @@ public class AssetDataStrings {
public static final String UI_SFX_ITEM_GRAB = "Audio/ui/items/inventoryGrabItem.ogg";
public static final String UI_SFX_ITEM_RELEASE = "Audio/ui/items/inventorySlotItem.ogg";
/**
* Compute shaders
*/
public static final String COMPUTE_LIGHT_CLUSTER = "Shaders/core/light/cluster.comp";
public static final String COMPUTE_LIGHT_CULL = "Shaders/core/light/cull.comp";
}

View File

@ -13,6 +13,7 @@ import electrosphere.renderer.buffer.HomogenousUniformBuffer;
import electrosphere.renderer.loading.ModelLoader;
import electrosphere.renderer.model.Mesh;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.shader.ComputeShader;
import electrosphere.renderer.shader.ShaderProgram;
import electrosphere.renderer.texture.Texture;
import electrosphere.renderer.texture.TextureMap;
@ -20,6 +21,7 @@ import electrosphere.server.poseactor.PoseModel;
import electrosphere.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
@ -51,6 +53,12 @@ public class AssetManager {
Map<String,ShaderProgram> shadersLoadedIntoMemory = new ConcurrentHashMap<String,ShaderProgram>();
List<ActorShaderMask> shadersInQueue = new CopyOnWriteArrayList<ActorShaderMask>();
//
//Compute shader related
//
Map<String,ComputeShader> computeShadersLoadedIntoMemory = new ConcurrentHashMap<String,ComputeShader>();
List<String> computeShadersInQueue = new CopyOnWriteArrayList<String>();
Map<String,DBody> physicsMeshesLoadedIntoMemory = new ConcurrentHashMap<String,DBody>();
List<PhysicsMeshQueueItem> physicsMeshesToLoad = new CopyOnWriteArrayList<PhysicsMeshQueueItem>();
@ -126,6 +134,20 @@ public class AssetManager {
ShaderProgram.loadSpecificShader(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath())
);
}
//compute shaders
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load compute shaders");
for(String computePath : computeShadersInQueue){
computeShadersInQueue.remove(computePath);
String key = getComputeShaderKey(computePath);
try {
computeShadersLoadedIntoMemory.put(
key,
ComputeShader.create(FileUtils.getAssetFileAsString(computePath))
);
} catch (IOException e) {
e.printStackTrace();
}
}
//pose models
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load pose models");
for(String currentPath: poseModelsInQueue){
@ -415,6 +437,40 @@ public class AssetManager {
}
shadersLoadedIntoMemory.clear();
}
//
//SHADERS
//
/**
* Adds a compute shader to the queue to be loaded
* @param computePath The path to the source code for the shader
*/
public void addComputeShaderToQueue(String computePath){
computeShadersInQueue.add(getComputeShaderKey(computePath));
}
/**
* Gets a compute shader
* @param computePath The path to the source code for the compute shader
* @return The compute shader if it exists, null otherwise
*/
public ComputeShader fetchComputeShader(String computePath){
String key = getComputeShaderKey(computePath);
ComputeShader rVal = null;
if(computeShadersLoadedIntoMemory.containsKey(key)){
rVal = computeShadersLoadedIntoMemory.get(key);
}
return rVal;
}
/**
* Gets the key for a compute shader
* @param computePath The path to the shader source
* @return The key
*/
static String getComputeShaderKey(String computePath){
return computePath;
}

View File

@ -9,6 +9,7 @@ import org.lwjgl.opengl.GL45;
import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.buffer.OpenGLBuffer;
import electrosphere.renderer.buffer.UniformBlockBinding;
import electrosphere.renderer.shader.Shader;
import electrosphere.renderer.shader.ShaderProgram;
@ -122,7 +123,7 @@ public class OpenGLState {
* @return The viewport's dimensions
*/
public Vector2i getViewport(){
return viewport;
return new Vector2i(viewport);
}
/**
@ -333,13 +334,13 @@ public class OpenGLState {
if(currentBuffer == null || currentBuffer != buffer){
//does not already contain index, should bind
this.indexBlockMap.put(index,buffer);
GL45.glBindBufferBase(index, index, buffer.getId());
GL45.glBindBufferBase(OpenGLBuffer.getTypeInt(buffer), index, buffer.getId());
Globals.renderingEngine.checkError();
}
} else {
//does not already contain index, should bind
this.indexBlockMap.put(index,buffer);
GL45.glBindBufferBase(index, index, buffer.getId());
GL45.glBindBufferBase(OpenGLBuffer.getTypeInt(buffer), index, buffer.getId());
Globals.renderingEngine.checkError();
}
}
@ -348,10 +349,10 @@ public class OpenGLState {
* Unbinds a buffer from a given uniform buffer block index
* @param index the index
*/
public void glUnbindBufferBase(int index){
public void glUnbindBufferBase(int index, UniformBlockBinding buffer){
if(this.indexBlockMap.containsKey(index)){
this.indexBlockMap.remove(index);
GL45.glBindBufferBase(index, index, UniformBlockBinding.UNBIND_ADDRESS);
GL45.glBindBufferBase(OpenGLBuffer.getTypeInt(buffer), index, UniformBlockBinding.UNBIND_ADDRESS);
Globals.renderingEngine.checkError();
}
}

View File

@ -415,7 +415,7 @@ public class RenderingEngine {
//instantiate light manager
lightManager = new LightManager();
lightManager = LightManager.create();
//
//Fog
@ -452,8 +452,7 @@ public class RenderingEngine {
verticalFOV = (float)(Globals.verticalFOV * Math.PI /180.0f);
//set local aspect ratio and global aspect ratio at the same time
aspectRatio = Globals.aspectRatio = Globals.WINDOW_WIDTH / (float)Globals.WINDOW_HEIGHT;
float nearClip = 0.001f;
Globals.projectionMatrix.setPerspective(verticalFOV, Globals.aspectRatio, nearClip, Globals.userSettings.getGraphicsViewDistance());
Globals.projectionMatrix.setPerspective(verticalFOV, Globals.aspectRatio, Globals.nearClip, Globals.userSettings.getGraphicsViewDistance());
Globals.viewMatrix.translation(new Vector3f(0.0f,0.0f,-3.0f));
/**
@ -489,7 +488,7 @@ public class RenderingEngine {
}
//Update light buffer
lightManager.updateData();
lightManager.update(renderPipelineState,openGLState,Globals.playerCamera);
checkError();

View File

@ -223,7 +223,7 @@ public class StridedInstanceData implements InstanceData {
@Override
public void upload(OpenGLState openGLState, RenderPipelineState renderPipelineState){
this.buffer.upload();
this.buffer.upload(openGLState);
openGLState.glBindBufferBase(0, buffer);
}

View File

@ -4,9 +4,9 @@ import java.nio.ByteBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL45;
import org.lwjgl.system.MemoryUtil;
import electrosphere.engine.Globals;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.buffer.BufferEnums.BufferAccess;
import electrosphere.renderer.buffer.BufferEnums.BufferUsage;
@ -40,7 +40,7 @@ public class ShaderStorageBuffer implements UniformBlockBinding {
Globals.renderingEngine.checkError();
GL45.glBindBuffer(GL45.GL_SHADER_STORAGE_BUFFER, id);
Globals.renderingEngine.checkError();
GL45.glBufferData(GL45.GL_SHADER_STORAGE_BUFFER, MemoryUtil.NULL, BufferEnums.getBufferUsage(usage, access));
GL45.glBufferData(GL45.GL_SHADER_STORAGE_BUFFER, buffer, BufferEnums.getBufferUsage(usage, access));
Globals.renderingEngine.checkError();
GL45.glBindBuffer(GL45.GL_SHADER_STORAGE_BUFFER,id);
Globals.renderingEngine.checkError();
@ -51,19 +51,21 @@ public class ShaderStorageBuffer implements UniformBlockBinding {
/**
* Uploads the java side buffer to opengl
*/
public void upload(){
public void upload(OpenGLState openGLState){
long offset = 0;
//bind
GL45.glBindBuffer(GL45.GL_SHADER_STORAGE_BUFFER,id);
Globals.renderingEngine.checkError();
if(buffer.limit() > buffer.position()){
//bind
openGLState.glBindBufferBase(0, this);
Globals.renderingEngine.checkError();
//upload
GL45.glBufferSubData(GL45.GL_SHADER_STORAGE_BUFFER, offset, buffer);
Globals.renderingEngine.checkError();
//unbind
GL45.glBindBuffer(GL45.GL_SHADER_STORAGE_BUFFER,UNBIND_ADDRESS);
Globals.renderingEngine.checkError();
//upload
GL45.glBufferSubData(OpenGLBuffer.getTypeInt(this), offset, buffer);
Globals.renderingEngine.checkError();
//unbind
openGLState.glUnbindBufferBase(0, this);
Globals.renderingEngine.checkError();
}
}
/**

View File

@ -10,64 +10,34 @@ public class DirectionalLight {
//the direction of the light as a uniform vector
Vector3f direction;
//the ambient color
Vector3f ambient;
//the diffuse color
Vector3f diffuse;
//the specular color
Vector3f specular;
//the color
Vector3f color;
public void setDirection(Vector3f direction) {
this.direction = direction;
}
public void setAmbient(Vector3f ambient) {
this.ambient = ambient;
}
public void setDiffuse(Vector3f diffuse) {
this.diffuse = diffuse;
}
public void setSpecular(Vector3f specular) {
this.specular = specular;
public void setColor(Vector3f color) {
this.color = color;
}
public Vector3f getDirection() {
return direction;
}
public Vector3f getAmbient() {
return ambient;
}
public Vector3f getDiffuse() {
return diffuse;
}
public Vector3f getSpecular() {
return specular;
public Vector3f getColor() {
return color;
}
public DirectionalLight(Vector3f direction){
this.direction = direction;
ambient = new Vector3f(0.05f, 0.05f, 0.05f);
diffuse = new Vector3f(0.4f, 0.4f, 0.4f);
specular = new Vector3f(0.5f, 0.5f, 0.5f);
color = new Vector3f(1.0f);
this.direction.normalize();
ambient.normalize();
diffuse.normalize();
specular.normalize();
}
public DirectionalLight(Vector3f direction, Vector3f color){
this.direction = direction;
ambient = new Vector3f( color.x * 0.05f, color.y * 0.05f, color.z * 0.05f);
diffuse = new Vector3f( color.x * 0.4f, color.y * 0.4f, color.z * 0.4f);
specular = new Vector3f(color.x * 0.5f, color.y * 0.5f, color.z * 0.5f);
this.color = new Vector3f(color);
this.direction.normalize();
ambient.normalize();
diffuse.normalize();
specular.normalize();
}
}

View File

@ -1,300 +1,339 @@
package electrosphere.renderer.light;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.joml.Matrix4d;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL31;
import org.joml.Vector3i;
import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderingEngine;
import electrosphere.renderer.shader.ShaderProgram;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.buffer.ShaderStorageBuffer;
import electrosphere.renderer.buffer.BufferEnums.BufferAccess;
import electrosphere.renderer.buffer.BufferEnums.BufferUsage;
import electrosphere.renderer.shader.ComputeShader;
import electrosphere.renderer.shader.MemoryBarrier;
import electrosphere.renderer.shader.MemoryBarrier.Barrier;
/**
* Manages the light sources in the engine
*/
public class LightManager {
/**
* Maximum number of lights per cluster
*/
static final int MAX_LIGHTS_PER_CLUSTER = 100;
/**
* Size of the light cluster structure
*/
static final int CLUSTER_STRUCT_SIZE = 16 + 16 + 4 + (4 * MAX_LIGHTS_PER_CLUSTER);
/**
* The width of the light cluster grid's x dimension
*/
public static final int LIGHT_CLUSTER_WIDTH_X = 12;
/**
* The width of the light cluster grid's y dimension
*/
public static final int LIGHT_CLUSTER_WIDTH_Y = 12;
/**
* The width of the light cluster grid's z dimension
*/
public static final int LIGHT_CLUSTER_WIDTH_Z = 24;
/**
* The size of a single point light struct
*/
static final int POINT_LIGHT_STRUCT_SIZE = 16 + 16 + 4 + 4 + 4 + 4;
/**
* The maximum number of point lights
*/
static final int MAX_POINT_LIGHTS = 2048;
/**
* The size of the point light buffer
*/
static final int POINT_LIGHT_BUFFER_SIZE = POINT_LIGHT_STRUCT_SIZE * MAX_POINT_LIGHTS;
/**
* The number of "threads" to run for light culling
*/
static final int CULL_LOCAL_SIZE = 128;
/**
* The number of work groups to dispatch for the light culling phase
* !!note!! DISPATCH_LOCAL_COUNT * CULL_LOCAL_SIZE must equal (LIGHT_CLUSTER_WIDTH_X * LIGHT_CLUSTER_WIDTH_Y * LIGHT_CLUSTER_WIDTH_Z)
*/
static final int DISPATCH_LOCAL_COUNT = 27;
/**
* Size of the direct light buffer
*/
static final int DIRECT_LIGHT_BUFFER_SIZE = 12 + 12;
/**
* Bind point for the cluster ssbo
*/
public static final int CLUSTER_SSBO_BIND_POINT = 1;
/**
* Bind point for the point light ssbo
*/
public static final int POINT_LIGHT_SSBO_BIND_POINT = 2;
/**
* Bind point for the direct light ssbo
*/
public static final int DIRECT_LIGHT_SSBO_BIND_POINT = 3;
/**
* The cluster grid ssbo
Light cluster struct:
{
vec4 minPoint; //16 bytes
vec4 maxPoint; //16 bytes
unsigned int count; //4 bytes
unsigned int lightIndices[MAX_LIGHTS_PER_CLUSTER]; //assuming MAX_LIGHTS_PER_CLUSTER is 100, 400 bytes
}
Totals to 436 bytes
*/
ShaderStorageBuffer clusterGridSSBO;
/**
* The map of all entities to point lights
*/
Map<Entity,PointLight> entityPointLightMap;
/**
* The buffer of all point light data
final static int BIND_POINT = 1;
final static int POINT_LIGHT_COUNT = 10;
final static int BUFFER_SIZE = 1184;
int uboIndex;
ByteBuffer dataBuffer;
//sun position (For shadow maps)
Vector3f sunPosition = new Vector3f(0.2f,-1.0f,0.3f);
//lights
DirectionalLight directionalLight;
PointLight[] pointLights;
public LightManager(){
//create data buffer
dataBuffer = BufferUtils.createByteBuffer(BUFFER_SIZE);
uboIndex = glGenBuffers();
glBindBuffer(GL_UNIFORM_BUFFER, uboIndex);
glBufferData(GL_UNIFORM_BUFFER, BUFFER_SIZE, GL_DYNAMIC_DRAW); // allocate 152 bytes of memory
//set range to full size
int offset = 0;
GL30.glBindBufferRange(GL_UNIFORM_BUFFER, BIND_POINT, uboIndex, offset, BUFFER_SIZE);
//unbind
glBindBuffer(GL_UNIFORM_BUFFER, 0);
//create directional light
directionalLight = new DirectionalLight(new Vector3f(1,-1,0).normalize());
directionalLight.setAmbient(new Vector3f(0.6f,0.6f,0.6f));
directionalLight.setDiffuse(new Vector3f(0.3f,0.3f,0.3f));
directionalLight.setDirection(sunPosition);
directionalLight.setSpecular(new Vector3f(0.0f,0.0f,0.0f));
pointLights = new PointLight[POINT_LIGHT_COUNT];
for(int i = 0; i < POINT_LIGHT_COUNT; i++){
pointLights[i] = new PointLight(new Vector3f(0,0,0),new Vector3f(0,0,0));
Point light struct:
{
vec4 position; //16 bytes
vec4 color; //16 bytes
float constant; //4 bytes
float linear; // 4 bytes
float quadratic; // 4 bytes
float radius; //4 bytes
}
pointLights[0].setAmbient(new Vector3f(0.924500f, 0.369800f, 0.092450f));
pointLights[0].setConstant(1.0f);
pointLights[0].setDiffuse(new Vector3f(0.924500f, 0.369800f, 0.092450f));
pointLights[0].setLinear(0.7f);
pointLights[0].setPosition(new Vector3f(1.0f,0.05f,1.0f));
pointLights[0].setQuadratic(1.8f);
pointLights[0].setSpecular(new Vector3f(0.0f,0.0f,0.0f));
// pointLights[0].setAmbient(new Vector3f(0.924500f, 0.369800f, 0.092450f));
// pointLights[0].setConstant(1.0f);
// pointLights[0].setDiffuse(new Vector3f(0.924500f, 0.369800f, 0.092450f));
// pointLights[0].setLinear(0.09f);
// pointLights[0].setPosition(new Vector3f(1.0f,0.05f,1.0f));
// pointLights[0].setQuadratic(0.032f);
// pointLights[0].setSpecular(new Vector3f(0.0f,0.0f,0.0f));
*/
ShaderStorageBuffer pointLightSSBO;
/**
* The direct light ssbo
*
struct DirectLight {
vec3 direction; //12 bytes
vec3 color; //12 bytes
};
*/
ShaderStorageBuffer dirLightSSBO;
/**
* The directional light
*/
DirectionalLight directionalLight;
/*
Vector3f lightLoc = new Vector3f(0.2f,-1.0f,0.3f);
float temp[] = new float[3];
temp[0] = lightLoc.x;
temp[1] = lightLoc.y;
temp[2] = lightLoc.z;
glUniform3fv(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "dirLight.direction"), temp);
temp[0] = 0.4f;
temp[1] = 0.4f;
temp[2] = 0.4f;
glUniform3fv(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "dirLight.ambient"), temp);
temp[0] = 0.3f;
temp[1] = 0.3f;
temp[2] = 0.3f;
glUniform3fv(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "dirLight.diffuse"), temp);
temp[0] = 0.1f;
temp[1] = 0.1f;
temp[2] = 0.1f;
glUniform3fv(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "dirLight.specular"), temp);
temp[0] = 32f;
*/
//glBufferData(GL_UNIFORM_BUFFER, <my_data>, GL_STATIC_DRAW);
}
//
//
// HIGHER ORDER OBJECT MANIPULATION
//
//
public void setPointLight(PointLight light, int index){
pointLights[index] = light;
/**
* Constructor
*/
private LightManager(){
}
/**
* Gets the directional light for this light manager
* @return the directional light
* Creates a light manager
* @return The light manager
*/
public static LightManager create(){
LightManager rVal = new LightManager();
//
//create the cluster ssbo
rVal.clusterGridSSBO = new ShaderStorageBuffer(
CLUSTER_STRUCT_SIZE * LIGHT_CLUSTER_WIDTH_X * LIGHT_CLUSTER_WIDTH_Y * LIGHT_CLUSTER_WIDTH_Z,
BufferUsage.STATIC,
BufferAccess.COPY
);
//
//create pointlight structures
rVal.entityPointLightMap = new HashMap<Entity,PointLight>();
rVal.pointLightSSBO = new ShaderStorageBuffer(POINT_LIGHT_BUFFER_SIZE, BufferUsage.DYNAMIC, BufferAccess.DRAW);
//create a shit ton of point lights
Random rand = new Random(0);
for(int i = 0; i < 500; i++){
PointLight newLight = new PointLight(new Vector3f(rand.nextFloat(32),rand.nextFloat(),rand.nextFloat(32)));
newLight.setRadius(1);
newLight.setColor(new Vector3f(rand.nextFloat(),rand.nextFloat(),rand.nextFloat()).normalize());
rVal.entityPointLightMap.put(EntityCreationUtils.createClientSpatialEntity(),newLight);
}
//
//create direct light ssbo
rVal.dirLightSSBO = new ShaderStorageBuffer(DIRECT_LIGHT_BUFFER_SIZE, BufferUsage.DYNAMIC, BufferAccess.DRAW);
rVal.directionalLight = new DirectionalLight(new Vector3f(0,-1,0));
rVal.directionalLight.setColor(new Vector3f(0.5f));
return rVal;
}
/**
* Computes the light culling clusters based on a camera
* @param renderPipelineState The render pipeline state
* @param openGLState The opengl state
* @param camera The camera
*/
private void computeLightCulling(RenderPipelineState renderPipelineState, OpenGLState openGLState, Entity camera){
openGLState.glViewport(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
//
//Build AABBs
ComputeShader clusterComp = Globals.assetManager.fetchComputeShader(AssetDataStrings.COMPUTE_LIGHT_CLUSTER);
if(clusterComp != null){
openGLState.setActiveShader(renderPipelineState, clusterComp);
clusterComp.setUniform(openGLState, "zNear", CameraEntityUtils.getNearClip(camera));
clusterComp.setUniform(openGLState, "zFar", CameraEntityUtils.getFarClip(camera));
clusterComp.setUniform(openGLState, "inverseProjection", new Matrix4d(Globals.projectionMatrix).invert());
clusterComp.setUniform(openGLState, "gridSize", new Vector3i(LIGHT_CLUSTER_WIDTH_X,LIGHT_CLUSTER_WIDTH_Y,LIGHT_CLUSTER_WIDTH_Z));
clusterComp.setUniform(openGLState, "screenDimensions", openGLState.getViewport());
clusterComp.dispatch(LIGHT_CLUSTER_WIDTH_X,LIGHT_CLUSTER_WIDTH_Y,LIGHT_CLUSTER_WIDTH_Z);
MemoryBarrier.glMemoryBarrier(Barrier.GL_SHADER_STORAGE_BARRIER_BIT);
}
//
//cull lights
ComputeShader lightCull = Globals.assetManager.fetchComputeShader(AssetDataStrings.COMPUTE_LIGHT_CULL);
openGLState.setActiveShader(renderPipelineState, lightCull);
lightCull.setUniform(openGLState, "viewMatrix", Globals.viewMatrix);
int dispatchLocal = (LIGHT_CLUSTER_WIDTH_X * LIGHT_CLUSTER_WIDTH_Y * LIGHT_CLUSTER_WIDTH_Z) / CULL_LOCAL_SIZE;
lightCull.dispatch(dispatchLocal, ComputeShader.DEFAULT_LOCAL_SIZE, ComputeShader.DEFAULT_LOCAL_SIZE);
MemoryBarrier.glMemoryBarrier(Barrier.GL_SHADER_STORAGE_BARRIER_BIT);
}
/**
* Pushes latest data to buffers
*/
private void pushToBuffers(RenderPipelineState renderPipelineState, OpenGLState openGLState, Entity camera){
int i = 0;
//
//push point lights
ByteBuffer pointLightBuffer = pointLightSSBO.getBuffer();
for(PointLight light : this.entityPointLightMap.values()){
if(i >= MAX_POINT_LIGHTS){
LoggerInterface.loggerRenderer.WARNING("CLOSE TO MAXIMUM NUMBER OF POINT LIGHTS!");
break;
}
//
//position
Vector3f modifiedCameraPos = new Vector3f(light.getPosition()).sub(CameraEntityUtils.getCameraCenter(camera));
pointLightBuffer.putFloat(modifiedCameraPos.x);
pointLightBuffer.putFloat(modifiedCameraPos.y);
pointLightBuffer.putFloat(modifiedCameraPos.z);
pointLightBuffer.putFloat(1);
//
//color
pointLightBuffer.putFloat(light.getColor().x);
pointLightBuffer.putFloat(light.getColor().y);
pointLightBuffer.putFloat(light.getColor().z);
pointLightBuffer.putFloat(1);
//
//const
pointLightBuffer.putFloat(light.getConstant());
pointLightBuffer.putFloat(light.getLinear());
pointLightBuffer.putFloat(light.getQuadratic());
pointLightBuffer.putFloat(light.getRadius());
}
pointLightBuffer.flip();
pointLightSSBO.upload(openGLState);
//
//push direct light
ByteBuffer directLightBuffer = dirLightSSBO.getBuffer();
{
//
//direction
directLightBuffer.putFloat(directionalLight.getDirection().x);
directLightBuffer.putFloat(directionalLight.getDirection().y);
directLightBuffer.putFloat(directionalLight.getDirection().z);
//
//color
directLightBuffer.putFloat(directionalLight.getColor().x);
directLightBuffer.putFloat(directionalLight.getColor().y);
directLightBuffer.putFloat(directionalLight.getColor().z);
}
directLightBuffer.flip();
dirLightSSBO.upload(openGLState);
}
/**
* Updates the light manager
* @param renderPipelineState The rendering state
* @param openGLState The opengl state
* @param camera The camera
*/
public void update(RenderPipelineState renderPipelineState, OpenGLState openGLState, Entity camera){
if(camera != null){
this.pushToBuffers(renderPipelineState, openGLState, camera);
this.computeLightCulling(renderPipelineState, openGLState, camera);
}
}
/**
* Gets the cluster grid ssbo
* @return The cluster grid ssbo
*/
public ShaderStorageBuffer getClusterGridSSBO(){
return this.clusterGridSSBO;
}
/**
* Gets the point light ssbo
* @return The point light ssbo
*/
public ShaderStorageBuffer getPointLightSSBO(){
return this.pointLightSSBO;
}
/**
* Gets the direct light ssbo
* @return The direct light ssbo
*/
public ShaderStorageBuffer getDirectLightSSBO(){
return this.dirLightSSBO;
}
/**
* Gets the directional light
* @return The directional light
*/
public DirectionalLight getDirectionalLight(){
return this.directionalLight;
return directionalLight;
}
//
//
// BUFFER MANAGEMENT
//
//
/**
* Call in each mesh / per each shader
* @param shaderIndex
*/
public void bindBuffer(OpenGLState openGLState){
//get position of lights object in shader
int bufferIndex = GL31.glGetUniformBlockIndex(openGLState.getActiveShader().getId(), "Lights");
int glErrorCode = Globals.renderingEngine.getError();
if(glErrorCode != 0){
LoggerInterface.loggerRenderer.DEBUG_LOOP(RenderingEngine.getErrorInEnglish(glErrorCode));
}
if(bufferIndex == ShaderProgram.INVALID_UNIFORM_NAME){
LoggerInterface.loggerRenderer.INFO("Tried to buffer light manager to shader that does not have it active.");
} else {
//bind that position to the slot '2'
GL31.glUniformBlockBinding(openGLState.getActiveShader().getId(), bufferIndex, BIND_POINT);
Globals.renderingEngine.checkError();
//bind our buffer to slot '2' as well
GL31.glBindBufferBase(GL_UNIFORM_BUFFER, BIND_POINT, uboIndex);
Globals.renderingEngine.checkError();
}
//alternatively if want to use range, do glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);
// Globals.renderingEngine.checkError();
}
/**
* Call once per render loop to set buffer values
*/
public void updateData(){
putDataInBuffer();
bufferData();
}
void bufferData(){
glBindBuffer(GL_UNIFORM_BUFFER, uboIndex);
// int offset = 0;
glBufferData(GL_UNIFORM_BUFFER, dataBuffer, GL_DYNAMIC_DRAW);
// glBufferSubData(GL_UNIFORM_BUFFER, offset, dataBuffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
void putDataInBuffer(){
//implicitly flips
dataBuffer.clear();
//direct light
//vec3 dirLightDirection
dataBuffer.putFloat(directionalLight.direction.x);
dataBuffer.putFloat(directionalLight.direction.y);
dataBuffer.putFloat(directionalLight.direction.z);
dataBuffer.putFloat(0);
//vec3 dirLightAmbient
dataBuffer.putFloat(directionalLight.ambient.x);
dataBuffer.putFloat(directionalLight.ambient.y);
dataBuffer.putFloat(directionalLight.ambient.z);
dataBuffer.putFloat(0);
//vec3 dirLightDiffuse
dataBuffer.putFloat(directionalLight.diffuse.x);
dataBuffer.putFloat(directionalLight.diffuse.y);
dataBuffer.putFloat(directionalLight.diffuse.z);
dataBuffer.putFloat(0);
//vec3 dirLightSpecular
dataBuffer.putFloat(directionalLight.specular.x);
dataBuffer.putFloat(directionalLight.specular.y);
dataBuffer.putFloat(directionalLight.specular.z);
dataBuffer.putFloat(0);
//point light
//vec3 position[10]
//dont sub cam
// for(int i = 0; i < POINT_LIGHT_COUNT; i++){
// PointLight light = pointLights[i];
// dataBuffer.putFloat(light.position.x);
// dataBuffer.putFloat(light.position.y);
// dataBuffer.putFloat(light.position.z);
// dataBuffer.putFloat(0);
// }
//do sub cam
if(Globals.playerCamera != null){
Vector3f cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera);
for(int i = 0; i < POINT_LIGHT_COUNT; i++){
PointLight light = pointLights[i];
dataBuffer.putFloat(light.position.x - cameraPos.x);
dataBuffer.putFloat(light.position.y - cameraPos.y);
dataBuffer.putFloat(light.position.z - cameraPos.z);
dataBuffer.putFloat(0);
}
}
//float constant[10]
for(int i = 0; i < POINT_LIGHT_COUNT; i++){
PointLight light = pointLights[i];
dataBuffer.putFloat(light.constant);
dataBuffer.putFloat(0);
dataBuffer.putFloat(0);
dataBuffer.putFloat(0);
}
//float linear[10]
for(int i = 0; i < POINT_LIGHT_COUNT; i++){
PointLight light = pointLights[i];
dataBuffer.putFloat(light.linear);
dataBuffer.putFloat(0);
dataBuffer.putFloat(0);
dataBuffer.putFloat(0);
}
//float quadratic[10]
for(int i = 0; i < POINT_LIGHT_COUNT; i++){
PointLight light = pointLights[i];
dataBuffer.putFloat(light.quadratic);
dataBuffer.putFloat(0);
dataBuffer.putFloat(0);
dataBuffer.putFloat(0);
}
//vec3 ambient[10]
for(int i = 0; i < POINT_LIGHT_COUNT; i++){
PointLight light = pointLights[i];
dataBuffer.putFloat(light.ambient.x);
dataBuffer.putFloat(light.ambient.y);
dataBuffer.putFloat(light.ambient.z);
dataBuffer.putFloat(0);
}
//vec3 diffuse[10]
for(int i = 0; i < POINT_LIGHT_COUNT; i++){
PointLight light = pointLights[i];
dataBuffer.putFloat(light.diffuse.x);
dataBuffer.putFloat(light.diffuse.y);
dataBuffer.putFloat(light.diffuse.z);
dataBuffer.putFloat(0);
}
//vec3 specular[10]
for(int i = 0; i < POINT_LIGHT_COUNT; i++){
PointLight light = pointLights[i];
dataBuffer.putFloat(light.specular.x);
dataBuffer.putFloat(light.specular.y);
dataBuffer.putFloat(light.specular.z);
dataBuffer.putFloat(0);
}
if(dataBuffer.position() > 0){
dataBuffer.flip();
}
// dataBuffer.position(0);
}
}

View File

@ -10,9 +10,8 @@ public class PointLight {
float constant;
float linear;
float quadratic;
Vector3f ambient;
Vector3f diffuse;
Vector3f specular;
float radius;
Vector3f color;
public void setPosition(Vector3f position) {
this.position = position;
@ -30,16 +29,12 @@ public class PointLight {
this.quadratic = quadratic;
}
public void setAmbient(Vector3f ambient) {
this.ambient = ambient;
public void setRadius(float radius){
this.radius = radius;
}
public void setDiffuse(Vector3f diffuse) {
this.diffuse = diffuse;
}
public void setSpecular(Vector3f specular) {
this.specular = specular;
public void setColor(Vector3f color){
this.color = color;
}
public Vector3f getPosition() {
@ -58,43 +53,29 @@ public class PointLight {
return quadratic;
}
public Vector3f getAmbient() {
return ambient;
public Vector3f getColor(){
return color;
}
public Vector3f getDiffuse() {
return diffuse;
}
public Vector3f getSpecular() {
return specular;
public float getRadius(){
return radius;
}
public PointLight(Vector3f position){
this.position = position;
radius = 1;
constant = 1.0f;
linear = 0.01f;
quadratic = 0.01f;
ambient = new Vector3f(0.05f, 0.05f, 0.05f);
diffuse = new Vector3f(0.8f, 0.8f, 0.8f);
specular = new Vector3f(1.0f, 1.0f, 1.0f);
this.position.normalize();
ambient.normalize();
diffuse.normalize();
specular.normalize();
linear = 0.7f;
quadratic = 1.8f;
color = new Vector3f(1.0f);
}
public PointLight(Vector3f position, Vector3f color){
this.position = position;
radius = 1;
constant = 1.0f;
linear = 0.01f;
quadratic = 0.01f;
ambient = new Vector3f(color.x * 0.05f, color.y * 0.05f, color.z * 0.05f);
diffuse = new Vector3f(color.x * 0.8f, color.y * 0.8f, color.z * 0.8f);
specular = new Vector3f(color.x, color.y, color.z);
this.position.normalize();
ambient.normalize();
diffuse.normalize();
specular.normalize();
linear = 0.7f;
quadratic = 1.8f;
this.color = color;
}
}

View File

@ -21,6 +21,7 @@ import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Sphered;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
@ -354,7 +355,16 @@ public class Mesh {
//don't buffer as the light manager hasn't initialized
} else {
LightManager lightManager = Globals.renderingEngine.getLightManager();
lightManager.bindBuffer(openGLState);
openGLState.glBindBufferBase(LightManager.CLUSTER_SSBO_BIND_POINT, lightManager.getClusterGridSSBO());
openGLState.glBindBufferBase(LightManager.POINT_LIGHT_SSBO_BIND_POINT, lightManager.getPointLightSSBO());
openGLState.glBindBufferBase(LightManager.DIRECT_LIGHT_SSBO_BIND_POINT, lightManager.getDirectLightSSBO());
//set uniforms required
openGLState.getActiveShader().setUniform(openGLState, "zNear", CameraEntityUtils.getNearClip(Globals.playerCamera));
openGLState.getActiveShader().setUniform(openGLState, "zFar", CameraEntityUtils.getFarClip(Globals.playerCamera));
openGLState.getActiveShader().setUniform(openGLState, "gridSize", new Vector3i(LightManager.LIGHT_CLUSTER_WIDTH_X,LightManager.LIGHT_CLUSTER_WIDTH_Y,LightManager.LIGHT_CLUSTER_WIDTH_Z));
openGLState.getActiveShader().setUniform(openGLState, "screenDimensions", openGLState.getViewport());
}
Globals.renderingEngine.checkError();
}

View File

@ -5,7 +5,11 @@ import java.util.Map;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Vector2d;
import org.joml.Vector2i;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL40;
import org.lwjgl.opengl.GL45;
@ -20,6 +24,11 @@ import electrosphere.renderer.RenderingEngine;
* A compute shader program (leaving object called "ComputeShader" because that's how most people refer to them)
*/
public class ComputeShader implements Shader {
/**
* The default local size
*/
public static final int DEFAULT_LOCAL_SIZE = 1;
/**
* The id for the shader
@ -86,14 +95,7 @@ public class ComputeShader implements Shader {
*/
public void dispatch(int x, int y, int z){
GL45.glDispatchCompute(x, y, z);
}
/**
* Sets the memory barrier value
* @param value The value
*/
public void memoryBarier(int value){
GL45.glMemoryBarrier(value);
Globals.renderingEngine.checkError();
}
/**
@ -164,7 +166,39 @@ public class ComputeShader implements Shader {
Vector3f currentUniform = (Vector3f)value;
GL40.glUniform3fv(uniformLocation, currentUniform.get(BufferUtils.createFloatBuffer(3)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector3f(currentUniform)); //create new matrix4f to break pointer-matching with equals on cache check
uniformMap.put(uniformLocation,new Vector3f(currentUniform)); //create new vector3f to break pointer-matching with equals on cache check
//
//vector3d
} else if(value instanceof Vector3d){
Vector3d currentUniform = (Vector3d)value;
GL40.glUniform3dv(uniformLocation, currentUniform.get(BufferUtils.createDoubleBuffer(3)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector3d(currentUniform)); //create new vector3d to break pointer-matching with equals on cache check
//
//vector2d
} else if(value instanceof Vector2d){
Vector2d currentUniform = (Vector2d)value;
GL40.glUniform2dv(uniformLocation, currentUniform.get(BufferUtils.createDoubleBuffer(2)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector2d(currentUniform)); //create new vector2d to break pointer-matching with equals on cache check
//
//Vector3i
} else if(value instanceof Vector3i){
Vector3i currentUniform = (Vector3i)value;
GL40.glUniform3uiv(uniformLocation, currentUniform.get(BufferUtils.createIntBuffer(3)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector3i(currentUniform)); //create new vector2d to break pointer-matching with equals on cache check
//
//Vector2i
} else if(value instanceof Vector2i){
Vector2i currentUniform = (Vector2i)value;
GL40.glUniform2uiv(uniformLocation, currentUniform.get(BufferUtils.createIntBuffer(2)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector2i(currentUniform)); //create new vector2d to break pointer-matching with equals on cache check
//
//integer

View File

@ -2,6 +2,8 @@ package electrosphere.renderer.shader;
import org.lwjgl.opengl.GL45;
import electrosphere.engine.Globals;
/**
* Memory barrier operations
*/
@ -152,7 +154,9 @@ public class MemoryBarrier {
}
/**
* Sets the memory barrier
* Sets the memory barrier.
* Essentially halts CPU execution until the given barrier is cleared.
* IE, if GL_SHADER_STORAGE_BARRIER_BIT is passed, the CPU will wait until the SSBO values are fully set before continuing execution.
* @param barrier The barrier to set
*/
public static void glMemoryBarrier(Barrier barrier){
@ -205,6 +209,7 @@ public class MemoryBarrier {
} break;
}
GL45.glMemoryBarrier(barrierVal);
Globals.renderingEngine.checkError();
}
}

View File

@ -29,7 +29,11 @@ import javax.management.RuntimeErrorException;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Vector2d;
import org.joml.Vector2i;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL40;
@ -704,6 +708,38 @@ public class ShaderProgram implements Shader {
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector3f(currentUniform)); //create new matrix4f to break pointer-matching with equals on cache check
//
//vector3d
} else if(value instanceof Vector3d){
Vector3d currentUniform = (Vector3d)value;
GL40.glUniform3dv(uniformLocation, currentUniform.get(BufferUtils.createDoubleBuffer(3)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector3d(currentUniform)); //create new vector3d to break pointer-matching with equals on cache check
//
//vector2d
} else if(value instanceof Vector2d){
Vector2d currentUniform = (Vector2d)value;
GL40.glUniform2dv(uniformLocation, currentUniform.get(BufferUtils.createDoubleBuffer(2)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector2d(currentUniform)); //create new vector2d to break pointer-matching with equals on cache check
//
//Vector3i
} else if(value instanceof Vector3i){
Vector3i currentUniform = (Vector3i)value;
GL40.glUniform3uiv(uniformLocation, currentUniform.get(BufferUtils.createIntBuffer(3)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector3i(currentUniform)); //create new vector2d to break pointer-matching with equals on cache check
//
//Vector2i
} else if(value instanceof Vector2i){
Vector2i currentUniform = (Vector2i)value;
GL40.glUniform2uiv(uniformLocation, currentUniform.get(BufferUtils.createIntBuffer(2)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector2i(currentUniform)); //create new vector2d to break pointer-matching with equals on cache check
//
//integer
} else if(value instanceof Integer){

View File

@ -48,7 +48,7 @@ public class ShaderStorageBufferTests extends RenderingTestTemplate {
public void test_upload_NoThrow(){
assertDoesNotThrow(() -> {
ShaderStorageBuffer buffer = new ShaderStorageBuffer(10, BufferUsage.STATIC, BufferAccess.READ);
buffer.upload();
buffer.upload(Globals.renderingEngine.getOpenGLState());
});
}