Files
Nuake/Data/Shaders/volumetric.shader
2025-01-31 18:04:43 -05:00

141 lines
4.0 KiB
GLSL

#shader vertex
#version 440 core
layout(location = 0) in vec3 VertexPosition;
layout(location = 1) in vec2 UVPosition;
out flat vec2 UV;
out mat4 InvView;
out mat4 InvProjection;
uniform mat4 u_View;
uniform mat4 u_Projection;
void main()
{
UV = UVPosition;
InvView = inverse(u_View);
InvProjection = inverse(u_Projection);
gl_Position = vec4(VertexPosition, 1.0f);
}
#shader fragment
#version 440 core
float ditherPattern[4][4] = { { 0.0f, 0.5f, 0.125f, 0.625f},
{ 0.75f, 0.22f, 0.875f, 0.375f},
{ 0.1875f, 0.6875f, 0.0625f, 0.5625},
{ 0.9375f, 0.4375f, 0.8125f, 0.3125} };
in mat4 InvView;
in mat4 InvProjection;
uniform sampler2D u_Depth;
uniform vec3 u_CamPosition;
uniform int u_StepCount;
uniform float u_FogAmount;
uniform float u_Exponant;
const int MAX_LIGHT = 20;
uniform int u_LightCount;
struct Light {
mat4 transform;
vec3 color;
vec3 direction;
sampler2D shadowmap;
float strength;
};
uniform Light u_Lights[MAX_LIGHT];
uniform sampler2D lightShadowmap;
in vec2 UV;
out vec4 FragColor;
const float PI = 3.141592653589793f;
// Mie scaterring approximated with Henyey-Greenstein phase function.
float ComputeScattering(float lightDotView)
{
float result = 1.0f - u_FogAmount ;
result /= (4.0f * PI * pow(1.0f + u_FogAmount * u_FogAmount - (1.0f * u_FogAmount) * lightDotView, 1.5f));
return result;
}
vec3 ComputeVolumetric(vec3 FragPos, Light light)
{
vec3 startPosition = u_CamPosition; // Camera Position
vec3 rayVector = FragPos - startPosition; // Ray Direction
float rayLength = length(rayVector); // Length of the raymarched
if(rayLength > 1000.0)
return vec3(0.0);
float stepLength = rayLength / u_StepCount; // Step length
vec3 rayDirection = rayVector / rayLength;
vec3 step = rayDirection * stepLength; // Normalized to step length direction
vec3 accumFog = vec3(0.0f, 0.0f, 0.0f); // accumulative color
// Raymarching
vec3 currentPosition = startPosition;
for (int i = 0; i < u_StepCount; i++)
{
vec4 fragPosLightSpace = light.transform * vec4(currentPosition, 1.0f);
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
float currentDepth = projCoords.z;
float closestDepth = texture(light.shadowmap, projCoords.xy).r;
if (closestDepth > currentDepth && closestDepth < 999)
{
//accumFog = vec3(light.color);
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).xxx * light.color);
//accumFog = vec3(projCoords.x, projCoords.y, 1.0);
}
currentPosition += step * ditherPattern[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4];
//accumFog = vec3(projCoords);
}
accumFog /= u_StepCount;
return accumFog;
}
// Converts depth to World space coords.
vec3 WorldPosFromDepth(float depth) {
float z = depth * 2.0 - 1.0;
vec4 clipSpacePosition = vec4(UV * 2.0 - 1.0, z, 1.0);
vec4 viewSpacePosition = InvProjection * clipSpacePosition;
// Perspective division
viewSpacePosition /= viewSpacePosition.w;
vec4 worldSpacePosition = InvView * viewSpacePosition;
return worldSpacePosition.xyz;
}
void main()
{
float depth = texture(u_Depth, UV).r;
vec3 globalFragmentPosition = WorldPosFromDepth(depth);
vec3 fog = vec3(0, 0, 0);
for (int i = 0; i < u_LightCount; i++)
{
fog += ComputeVolumetric(globalFragmentPosition, u_Lights[i]) * u_Exponant;
}
FragColor = vec4(fog, 1.0);
//FragColor = vec4(mix(fog, ComputeVolumetric(globalFragmentPosition, u_Lights[0]), 0.9f), 0.01);
//FragColor = vec4(globalFragmentPosition * 10.0, 1.0f);
//FragColor = vec4(globalFragmentPosition.xyz * 100.0, 1.0f);
//FragColor = vec4(worldSpacePosition.x, worldSpacePosition.y, worldSpacePosition.z, 1);
//FragColor = vec4(ComputeVolumetric(globalFragmentPosition, u_Lights[0]), 1.0);
}