From dc52e375e30128d0980b1d8878b276cb518c62ea Mon Sep 17 00:00:00 2001 From: austin Date: Thu, 19 Sep 2024 11:29:04 -0400 Subject: [PATCH] clustered lighting implementation --- assets/Shaders/FragmentShader.fs | 204 ++++--- assets/Shaders/VertexShader.vs | 2 + assets/Shaders/core/light/cluster.comp | 97 +++ assets/Shaders/core/light/cull.comp | 87 +++ .../core/oit/general/FragmentShader.fs | 160 +++-- .../Shaders/core/oit/general/VertexShader.vs | 2 + assets/Shaders/entities/foliage/foliage.fs | 182 +++--- assets/Shaders/entities/foliage/foliage.vs | 2 + assets/Shaders/entities/terrain2/terrain2.fs | 163 +++-- assets/Shaders/entities/terrain2/terrain2.vs | 2 + buildNumber.properties | 4 +- .../chemisty/chemistrydesign.md | 11 +- docs/src/progress/currenttarget.md | 2 + docs/src/progress/renderertodo.md | 9 + .../entity/camera/CameraEntityUtils.java | 18 + .../java/electrosphere/engine/Globals.java | 5 + .../engine/assetmanager/AssetDataStrings.java | 6 + .../engine/assetmanager/AssetManager.java | 56 ++ .../electrosphere/renderer/OpenGLState.java | 11 +- .../renderer/RenderingEngine.java | 7 +- .../actor/instance/StridedInstanceData.java | 2 +- .../renderer/buffer/ShaderStorageBuffer.java | 28 +- .../renderer/light/DirectionalLight.java | 46 +- .../renderer/light/LightManager.java | 573 ++++++++++-------- .../renderer/light/PointLight.java | 55 +- .../electrosphere/renderer/model/Mesh.java | 12 +- .../renderer/shader/ComputeShader.java | 52 +- .../renderer/shader/MemoryBarrier.java | 7 +- .../renderer/shader/ShaderProgram.java | 36 ++ .../buffer/ShaderStorageBufferTests.java | 2 +- 30 files changed, 1211 insertions(+), 632 deletions(-) create mode 100644 assets/Shaders/core/light/cluster.comp create mode 100644 assets/Shaders/core/light/cull.comp diff --git a/assets/Shaders/FragmentShader.fs b/assets/Shaders/FragmentShader.fs index 6a777ed6..73c132a7 100644 --- a/assets/Shaders/FragmentShader.fs +++ b/assets/Shaders/FragmentShader.fs @@ -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){ diff --git a/assets/Shaders/VertexShader.vs b/assets/Shaders/VertexShader.vs index c724ed51..555eec66 100644 --- a/assets/Shaders/VertexShader.vs +++ b/assets/Shaders/VertexShader.vs @@ -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; diff --git a/assets/Shaders/core/light/cluster.comp b/assets/Shaders/core/light/cluster.comp new file mode 100644 index 00000000..8c000370 --- /dev/null +++ b/assets/Shaders/core/light/cluster.comp @@ -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; +} \ No newline at end of file diff --git a/assets/Shaders/core/light/cull.comp b/assets/Shaders/core/light/cull.comp new file mode 100644 index 00000000..8851ce09 --- /dev/null +++ b/assets/Shaders/core/light/cull.comp @@ -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); +} \ No newline at end of file diff --git a/assets/Shaders/core/oit/general/FragmentShader.fs b/assets/Shaders/core/oit/general/FragmentShader.fs index 6075b610..a04684f5 100644 --- a/assets/Shaders/core/oit/general/FragmentShader.fs +++ b/assets/Shaders/core/oit/general/FragmentShader.fs @@ -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); +} + diff --git a/assets/Shaders/core/oit/general/VertexShader.vs b/assets/Shaders/core/oit/general/VertexShader.vs index 3ca84862..78e31d64 100644 --- a/assets/Shaders/core/oit/general/VertexShader.vs +++ b/assets/Shaders/core/oit/general/VertexShader.vs @@ -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; diff --git a/assets/Shaders/entities/foliage/foliage.fs b/assets/Shaders/entities/foliage/foliage.fs index 78ec6de5..53696d64 100644 --- a/assets/Shaders/entities/foliage/foliage.fs +++ b/assets/Shaders/entities/foliage/foliage.fs @@ -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){ diff --git a/assets/Shaders/entities/foliage/foliage.vs b/assets/Shaders/entities/foliage/foliage.vs index eec50fca..962df24a 100644 --- a/assets/Shaders/entities/foliage/foliage.vs +++ b/assets/Shaders/entities/foliage/foliage.vs @@ -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; diff --git a/assets/Shaders/entities/terrain2/terrain2.fs b/assets/Shaders/entities/terrain2/terrain2.fs index 985d42ff..fc499180 100644 --- a/assets/Shaders/entities/terrain2/terrain2.fs +++ b/assets/Shaders/entities/terrain2/terrain2.fs @@ -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){ diff --git a/assets/Shaders/entities/terrain2/terrain2.vs b/assets/Shaders/entities/terrain2/terrain2.vs index 977c90c8..a28caeb3 100644 --- a/assets/Shaders/entities/terrain2/terrain2.vs +++ b/assets/Shaders/entities/terrain2/terrain2.vs @@ -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/ diff --git a/buildNumber.properties b/buildNumber.properties index 97453e56..87898e04 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -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 diff --git a/docs/src/highlevel-design/chemisty/chemistrydesign.md b/docs/src/highlevel-design/chemisty/chemistrydesign.md index c6167de7..c3b7d25c 100644 --- a/docs/src/highlevel-design/chemisty/chemistrydesign.md +++ b/docs/src/highlevel-design/chemisty/chemistrydesign.md @@ -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 \ No newline at end of file diff --git a/docs/src/progress/currenttarget.md b/docs/src/progress/currenttarget.md index 8aa558de..515d3cd3 100644 --- a/docs/src/progress/currenttarget.md +++ b/docs/src/progress/currenttarget.md @@ -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 diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index ad784682..86fe8f73 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -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 diff --git a/src/main/java/electrosphere/client/entity/camera/CameraEntityUtils.java b/src/main/java/electrosphere/client/entity/camera/CameraEntityUtils.java index f2579391..40f2dcd5 100644 --- a/src/main/java/electrosphere/client/entity/camera/CameraEntityUtils.java +++ b/src/main/java/electrosphere/client/entity/camera/CameraEntityUtils.java @@ -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 diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index 259e656a..64ab1769 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -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(); diff --git a/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java b/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java index d2c102a6..0c21beb3 100644 --- a/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java +++ b/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java @@ -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"; + } diff --git a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java index b07ffd06..c244432b 100644 --- a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java +++ b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java @@ -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 shadersLoadedIntoMemory = new ConcurrentHashMap(); List shadersInQueue = new CopyOnWriteArrayList(); + // + //Compute shader related + // + Map computeShadersLoadedIntoMemory = new ConcurrentHashMap(); + List computeShadersInQueue = new CopyOnWriteArrayList(); + Map physicsMeshesLoadedIntoMemory = new ConcurrentHashMap(); List physicsMeshesToLoad = new CopyOnWriteArrayList(); @@ -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; + } diff --git a/src/main/java/electrosphere/renderer/OpenGLState.java b/src/main/java/electrosphere/renderer/OpenGLState.java index e66837fc..cbb05113 100644 --- a/src/main/java/electrosphere/renderer/OpenGLState.java +++ b/src/main/java/electrosphere/renderer/OpenGLState.java @@ -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(); } } diff --git a/src/main/java/electrosphere/renderer/RenderingEngine.java b/src/main/java/electrosphere/renderer/RenderingEngine.java index c4e14c6a..5e39aab2 100644 --- a/src/main/java/electrosphere/renderer/RenderingEngine.java +++ b/src/main/java/electrosphere/renderer/RenderingEngine.java @@ -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(); diff --git a/src/main/java/electrosphere/renderer/actor/instance/StridedInstanceData.java b/src/main/java/electrosphere/renderer/actor/instance/StridedInstanceData.java index d5839270..75277f25 100644 --- a/src/main/java/electrosphere/renderer/actor/instance/StridedInstanceData.java +++ b/src/main/java/electrosphere/renderer/actor/instance/StridedInstanceData.java @@ -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); } diff --git a/src/main/java/electrosphere/renderer/buffer/ShaderStorageBuffer.java b/src/main/java/electrosphere/renderer/buffer/ShaderStorageBuffer.java index e37db9ab..cb4b7680 100644 --- a/src/main/java/electrosphere/renderer/buffer/ShaderStorageBuffer.java +++ b/src/main/java/electrosphere/renderer/buffer/ShaderStorageBuffer.java @@ -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(); + } } /** diff --git a/src/main/java/electrosphere/renderer/light/DirectionalLight.java b/src/main/java/electrosphere/renderer/light/DirectionalLight.java index 430ab9b4..1b1863df 100644 --- a/src/main/java/electrosphere/renderer/light/DirectionalLight.java +++ b/src/main/java/electrosphere/renderer/light/DirectionalLight.java @@ -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(); } } \ No newline at end of file diff --git a/src/main/java/electrosphere/renderer/light/LightManager.java b/src/main/java/electrosphere/renderer/light/LightManager.java index aab9efed..90e8b895 100644 --- a/src/main/java/electrosphere/renderer/light/LightManager.java +++ b/src/main/java/electrosphere/renderer/light/LightManager.java @@ -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 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, , 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(); + 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); - - } - } \ No newline at end of file diff --git a/src/main/java/electrosphere/renderer/light/PointLight.java b/src/main/java/electrosphere/renderer/light/PointLight.java index c21c56d9..beeddbf6 100644 --- a/src/main/java/electrosphere/renderer/light/PointLight.java +++ b/src/main/java/electrosphere/renderer/light/PointLight.java @@ -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; } } \ No newline at end of file diff --git a/src/main/java/electrosphere/renderer/model/Mesh.java b/src/main/java/electrosphere/renderer/model/Mesh.java index 3fbb6f30..a57d46eb 100644 --- a/src/main/java/electrosphere/renderer/model/Mesh.java +++ b/src/main/java/electrosphere/renderer/model/Mesh.java @@ -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(); } diff --git a/src/main/java/electrosphere/renderer/shader/ComputeShader.java b/src/main/java/electrosphere/renderer/shader/ComputeShader.java index 431fa261..50365dc2 100644 --- a/src/main/java/electrosphere/renderer/shader/ComputeShader.java +++ b/src/main/java/electrosphere/renderer/shader/ComputeShader.java @@ -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 diff --git a/src/main/java/electrosphere/renderer/shader/MemoryBarrier.java b/src/main/java/electrosphere/renderer/shader/MemoryBarrier.java index 730f2cc1..0cc25280 100644 --- a/src/main/java/electrosphere/renderer/shader/MemoryBarrier.java +++ b/src/main/java/electrosphere/renderer/shader/MemoryBarrier.java @@ -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(); } } diff --git a/src/main/java/electrosphere/renderer/shader/ShaderProgram.java b/src/main/java/electrosphere/renderer/shader/ShaderProgram.java index 85ff2c2b..64bcb73d 100644 --- a/src/main/java/electrosphere/renderer/shader/ShaderProgram.java +++ b/src/main/java/electrosphere/renderer/shader/ShaderProgram.java @@ -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){ diff --git a/src/test/java/electrosphere/renderer/buffer/ShaderStorageBufferTests.java b/src/test/java/electrosphere/renderer/buffer/ShaderStorageBufferTests.java index b5c22f7f..4d1227df 100644 --- a/src/test/java/electrosphere/renderer/buffer/ShaderStorageBufferTests.java +++ b/src/test/java/electrosphere/renderer/buffer/ShaderStorageBufferTests.java @@ -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()); }); }