121 lines
3.2 KiB
GLSL
121 lines
3.2 KiB
GLSL
#shader vertex
|
|
#version 460 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 460 core
|
|
|
|
in mat4 InvView;
|
|
in mat4 InvProjection;
|
|
|
|
uniform sampler2D u_Depth;
|
|
|
|
uniform vec3 u_CamPosition;
|
|
uniform int u_StepCount;
|
|
uniform float u_FogAmount;
|
|
|
|
const int MAX_LIGHT = 25;
|
|
uniform int u_LightCount;
|
|
struct Light {
|
|
mat4 transform;
|
|
vec3 color;
|
|
vec3 direction;
|
|
int shadowmap;
|
|
};
|
|
|
|
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 * u_FogAmount;
|
|
result /= (4.0f * PI * pow(1.0f + u_FogAmount * u_FogAmount - (2.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
|
|
|
|
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(lightShadowmap, projCoords.xy).r;
|
|
if (closestDepth > currentDepth)
|
|
accumFog += (ComputeScattering(dot(rayDirection, normalize(light.direction))).xxx * light.color);
|
|
|
|
currentPosition += step; //* ditherPattern[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4];
|
|
}
|
|
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]);
|
|
}
|
|
|
|
FragColor = vec4(mix(fog, ComputeVolumetric(globalFragmentPosition, u_Lights[0]), 0.9f), 1.0);
|
|
} |