initial commit-moved from vulkan_guide
This commit is contained in:
164
shaders/deferred_lighting.frag
Normal file
164
shaders/deferred_lighting.frag
Normal file
@@ -0,0 +1,164 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
#include "input_structures.glsl"
|
||||
|
||||
layout(location=0) in vec2 inUV;
|
||||
layout(location=0) out vec4 outColor;
|
||||
|
||||
layout(set=1, binding=0) uniform sampler2D posTex;
|
||||
layout(set=1, binding=1) uniform sampler2D normalTex;
|
||||
layout(set=1, binding=2) uniform sampler2D albedoTex;
|
||||
layout(set=2, binding=0) uniform sampler2D shadowTex;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
float hash12(vec2 p)
|
||||
{
|
||||
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
||||
p3 += dot(p3, p3.yzx + 33.33); return fract((p3.x + p3.y) * p3.z);
|
||||
}
|
||||
|
||||
const vec2 POISSON_16[16] = vec2[16](
|
||||
vec2(0.2852, -0.1883), vec2(-0.1464, 0.2591),
|
||||
vec2(-0.3651, -0.0974), vec2(0.0901, 0.3807),
|
||||
vec2(0.4740, 0.0679), vec2(-0.0512, -0.4466),
|
||||
vec2(-0.4497, 0.1673), vec2(0.3347, 0.3211),
|
||||
vec2(0.1948, -0.4196), vec2(-0.2919, -0.3291),
|
||||
vec2(-0.0763, 0.4661), vec2(0.4421, -0.2217),
|
||||
vec2(0.0281, -0.2468), vec2(-0.2104, 0.0573),
|
||||
vec2(0.1197, 0.0779), vec2(-0.0905, -0.1203)
|
||||
);
|
||||
|
||||
float calcShadowVisibility(vec3 worldPos, vec3 N, vec3 L)
|
||||
{
|
||||
vec4 lclip = sceneData.lightViewProj * vec4(worldPos, 1.0);
|
||||
vec3 ndc = lclip.xyz / lclip.w;
|
||||
vec2 suv = ndc.xy * 0.5 + 0.5;
|
||||
|
||||
if (any(lessThan(suv, vec2(0.0))) || any(greaterThan(suv, vec2(1.0))))
|
||||
return 1.0;
|
||||
|
||||
float current = clamp(ndc.z, 0.0, 1.0);
|
||||
|
||||
float NoL = max(dot(N, L), 0.0);
|
||||
float slopeBias = max(0.0006 * (1.0 - NoL), 0.0001);
|
||||
|
||||
float dzdx = dFdx(current);
|
||||
float dzdy = dFdy(current);
|
||||
float ddz = max(abs(dzdx), abs(dzdy));
|
||||
float bias = slopeBias + ddz * 0.75;
|
||||
|
||||
ivec2 dim = textureSize(shadowTex, 0);
|
||||
vec2 texelSize = 1.0 / vec2(dim);
|
||||
|
||||
float baseRadius = 1.25;
|
||||
float radius = mix(baseRadius, baseRadius * 4.0, current);
|
||||
|
||||
float ang = hash12(suv * 4096.0) * 6.2831853;
|
||||
vec2 r = vec2(cos(ang), sin(ang));
|
||||
mat2 rot = mat2(r.x, -r.y, r.y, r.x);
|
||||
|
||||
const int TAP_COUNT = 16;
|
||||
float occluded = 0.0;
|
||||
float wsum = 0.0;
|
||||
|
||||
for (int i = 0; i < TAP_COUNT; ++i)
|
||||
{
|
||||
vec2 pu = rot * POISSON_16[i];
|
||||
vec2 off = pu * radius * texelSize;
|
||||
|
||||
float pr = length(pu);
|
||||
float w = 1.0 - smoothstep(0.0, 0.65, pr);
|
||||
|
||||
float mapD = texture(shadowTex, suv + off).r;
|
||||
|
||||
float occ = step(current + bias, mapD);
|
||||
|
||||
occluded += occ * w;
|
||||
wsum += w;
|
||||
}
|
||||
|
||||
float shadow = (wsum > 0.0) ? (occluded / wsum) : 0.0;
|
||||
return 1.0 - shadow;
|
||||
}
|
||||
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
|
||||
float num = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return num / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
return NdotV / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float ggx2 = GeometrySchlickGGX(max(dot(N, V), 0.0), roughness);
|
||||
float ggx1 = GeometrySchlickGGX(max(dot(N, L), 0.0), roughness);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
void main(){
|
||||
vec4 posSample = texture(posTex, inUV);
|
||||
if (posSample.w == 0.0)
|
||||
{
|
||||
outColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 pos = posSample.xyz;
|
||||
vec4 normalSample = texture(normalTex, inUV);
|
||||
vec3 N = normalize(normalSample.xyz);
|
||||
float roughness = clamp(normalSample.w, 0.04, 1.0);
|
||||
|
||||
vec4 albedoSample = texture(albedoTex, inUV);
|
||||
vec3 albedo = albedoSample.rgb;
|
||||
float metallic = clamp(albedoSample.a, 0.0, 1.0);
|
||||
|
||||
vec3 camPos = vec3(inverse(sceneData.view)[3]);
|
||||
vec3 V = normalize(camPos - pos);
|
||||
vec3 L = normalize(-sceneData.sunlightDirection.xyz);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
|
||||
vec3 numerator = NDF * G * F;
|
||||
float denom = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
|
||||
vec3 specular = numerator / max(denom, 0.001);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = (1.0 - kS) * (1.0 - metallic);
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
// Shadowing (directional, reversed-Z shadow map)
|
||||
float visibility = calcShadowVisibility(pos, N, L);
|
||||
|
||||
vec3 irradiance = sceneData.sunlightColor.rgb * sceneData.sunlightColor.a * NdotL * visibility;
|
||||
|
||||
vec3 color = (kD * albedo / PI + specular) * irradiance;
|
||||
color += albedo * sceneData.ambientColor.rgb;
|
||||
|
||||
outColor = vec4(color, 1.0);
|
||||
}
|
||||
10
shaders/fullscreen.vert
Normal file
10
shaders/fullscreen.vert
Normal file
@@ -0,0 +1,10 @@
|
||||
#version 450
|
||||
|
||||
layout(location=0) out vec2 outUV;
|
||||
|
||||
void main() {
|
||||
vec2 positions[3] = vec2[3](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));
|
||||
vec2 uvs[3] = vec2[3](vec2(0.0, 0.0), vec2(2.0, 0.0), vec2(0.0, 2.0));
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
outUV = uvs[gl_VertexIndex];
|
||||
}
|
||||
26
shaders/gbuffer.frag
Normal file
26
shaders/gbuffer.frag
Normal file
@@ -0,0 +1,26 @@
|
||||
#version 450
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
#include "input_structures.glsl"
|
||||
|
||||
layout(location = 0) in vec3 inNormal;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
layout(location = 2) in vec2 inUV;
|
||||
layout(location = 3) in vec3 inWorldPos;
|
||||
|
||||
layout(location = 0) out vec4 outPos;
|
||||
layout(location = 1) out vec4 outNorm;
|
||||
layout(location = 2) out vec4 outAlbedo;
|
||||
|
||||
void main() {
|
||||
// Apply baseColor texture and baseColorFactor once
|
||||
vec3 albedo = inColor * texture(colorTex, inUV).rgb * materialData.colorFactors.rgb;
|
||||
|
||||
// glTF metallic-roughness in G (roughness) and B (metallic)
|
||||
vec2 mrTex = texture(metalRoughTex, inUV).gb;
|
||||
float roughness = clamp(mrTex.x * materialData.metal_rough_factors.y, 0.04, 1.0);
|
||||
float metallic = clamp(mrTex.y * materialData.metal_rough_factors.x, 0.0, 1.0);
|
||||
|
||||
outPos = vec4(inWorldPos, 1.0);
|
||||
outNorm = vec4(normalize(inNormal), roughness);
|
||||
outAlbedo = vec4(albedo, metallic);
|
||||
}
|
||||
32
shaders/gradient_color.comp
Normal file
32
shaders/gradient_color.comp
Normal file
@@ -0,0 +1,32 @@
|
||||
#version 460
|
||||
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
|
||||
layout(rgba16f,set = 0, binding = 0) uniform image2D image;
|
||||
|
||||
//push constants block
|
||||
layout( push_constant ) uniform constants
|
||||
{
|
||||
vec4 data1;
|
||||
vec4 data2;
|
||||
vec4 data3;
|
||||
vec4 data4;
|
||||
} PushConstants;
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texelCoord = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
ivec2 size = imageSize(image);
|
||||
|
||||
vec4 topColor = PushConstants.data1;
|
||||
vec4 bottomColor = PushConstants.data2;
|
||||
|
||||
if(texelCoord.x < size.x && texelCoord.y < size.y)
|
||||
{
|
||||
float blend = float(texelCoord.y)/(size.y);
|
||||
|
||||
imageStore(image, texelCoord, mix(topColor,bottomColor, blend));
|
||||
}
|
||||
}
|
||||
|
||||
20
shaders/input_structures.glsl
Normal file
20
shaders/input_structures.glsl
Normal file
@@ -0,0 +1,20 @@
|
||||
layout(set = 0, binding = 0) uniform SceneData{
|
||||
|
||||
mat4 view;
|
||||
mat4 proj;
|
||||
mat4 viewproj;
|
||||
mat4 lightViewProj;
|
||||
vec4 ambientColor;
|
||||
vec4 sunlightDirection; //w for sun power
|
||||
vec4 sunlightColor;
|
||||
} sceneData;
|
||||
|
||||
layout(set = 1, binding = 0) uniform GLTFMaterialData{
|
||||
|
||||
vec4 colorFactors;
|
||||
vec4 metal_rough_factors;
|
||||
|
||||
} materialData;
|
||||
|
||||
layout(set = 1, binding = 1) uniform sampler2D colorTex;
|
||||
layout(set = 1, binding = 2) uniform sampler2D metalRoughTex;
|
||||
88
shaders/mesh.frag
Normal file
88
shaders/mesh.frag
Normal file
@@ -0,0 +1,88 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
#include "input_structures.glsl"
|
||||
|
||||
layout (location = 0) in vec3 inNormal;
|
||||
layout (location = 1) in vec3 inColor;
|
||||
layout (location = 2) in vec2 inUV;
|
||||
layout (location = 3) in vec3 inWorldPos;
|
||||
|
||||
layout (location = 0) out vec4 outFragColor;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
|
||||
float num = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return num / max(denom, 0.001);
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
return NdotV / denom;
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||
{
|
||||
float ggx2 = GeometrySchlickGGX(max(dot(N, V), 0.0), roughness);
|
||||
float ggx1 = GeometrySchlickGGX(max(dot(N, L), 0.0), roughness);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Base color with material factor and texture
|
||||
vec4 baseTex = texture(colorTex, inUV);
|
||||
vec3 albedo = inColor * baseTex.rgb * materialData.colorFactors.rgb;
|
||||
// glTF: metallicRoughnessTexture uses G=roughness, B=metallic
|
||||
vec2 mrTex = texture(metalRoughTex, inUV).gb;
|
||||
float roughness = clamp(mrTex.x * materialData.metal_rough_factors.y, 0.04, 1.0);
|
||||
float metallic = clamp(mrTex.y * materialData.metal_rough_factors.x, 0.0, 1.0);
|
||||
|
||||
vec3 N = normalize(inNormal);
|
||||
vec3 camPos = vec3(inverse(sceneData.view)[3]);
|
||||
vec3 V = normalize(camPos - inWorldPos);
|
||||
vec3 L = normalize(-sceneData.sunlightDirection.xyz);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), albedo, metallic);
|
||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
|
||||
vec3 numerator = NDF * G * F;
|
||||
float denom = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
|
||||
vec3 specular = numerator / max(denom, 0.001);
|
||||
|
||||
vec3 kS = F;
|
||||
vec3 kD = vec3(1.0) - kS;
|
||||
kD *= 1.0 - metallic;
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
vec3 irradiance = sceneData.sunlightColor.rgb * sceneData.sunlightColor.a * NdotL;
|
||||
|
||||
vec3 color = (kD * albedo / PI + specular) * irradiance;
|
||||
color += albedo * sceneData.ambientColor.rgb;
|
||||
|
||||
// Alpha from baseColor texture and factor (glTF spec)
|
||||
float alpha = clamp(baseTex.a * materialData.colorFactors.a, 0.0, 1.0);
|
||||
outFragColor = vec4(color, alpha);
|
||||
}
|
||||
46
shaders/mesh.vert
Normal file
46
shaders/mesh.vert
Normal file
@@ -0,0 +1,46 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
#extension GL_EXT_buffer_reference : require
|
||||
|
||||
#include "input_structures.glsl"
|
||||
|
||||
layout (location = 0) out vec3 outNormal;
|
||||
layout (location = 1) out vec3 outColor;
|
||||
layout (location = 2) out vec2 outUV;
|
||||
layout (location = 3) out vec3 outWorldPos;
|
||||
|
||||
struct Vertex {
|
||||
|
||||
vec3 position;
|
||||
float uv_x;
|
||||
vec3 normal;
|
||||
float uv_y;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
layout(buffer_reference, std430) readonly buffer VertexBuffer{
|
||||
Vertex vertices[];
|
||||
};
|
||||
|
||||
//push constants block
|
||||
layout( push_constant ) uniform constants
|
||||
{
|
||||
mat4 render_matrix;
|
||||
VertexBuffer vertexBuffer;
|
||||
} PushConstants;
|
||||
|
||||
void main()
|
||||
{
|
||||
Vertex v = PushConstants.vertexBuffer.vertices[gl_VertexIndex];
|
||||
|
||||
vec4 worldPos = PushConstants.render_matrix * vec4(v.position, 1.0f);
|
||||
gl_Position = sceneData.viewproj * worldPos;
|
||||
|
||||
outNormal = (PushConstants.render_matrix * vec4(v.normal, 0.f)).xyz;
|
||||
// Pass pure vertex color; apply baseColorFactor only in fragment
|
||||
outColor = v.color.xyz;
|
||||
outUV.x = v.uv_x;
|
||||
outUV.y = v.uv_y;
|
||||
outWorldPos = worldPos.xyz;
|
||||
}
|
||||
4
shaders/shadow.frag
Normal file
4
shaders/shadow.frag
Normal file
@@ -0,0 +1,4 @@
|
||||
#version 450
|
||||
|
||||
void main() {}
|
||||
|
||||
29
shaders/shadow.vert
Normal file
29
shaders/shadow.vert
Normal file
@@ -0,0 +1,29 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
#extension GL_EXT_buffer_reference : require
|
||||
|
||||
#include "input_structures.glsl"
|
||||
|
||||
struct Vertex {
|
||||
vec3 position; float uv_x;
|
||||
vec3 normal; float uv_y;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
layout(buffer_reference, std430) readonly buffer VertexBuffer{
|
||||
Vertex vertices[];
|
||||
};
|
||||
|
||||
layout(push_constant) uniform PushConsts {
|
||||
mat4 render_matrix;
|
||||
VertexBuffer vertexBuffer;
|
||||
} PC;
|
||||
|
||||
void main()
|
||||
{
|
||||
Vertex v = PC.vertexBuffer.vertices[gl_VertexIndex];
|
||||
vec4 worldPos = PC.render_matrix * vec4(v.position, 1.0);
|
||||
gl_Position = sceneData.lightViewProj * worldPos;
|
||||
}
|
||||
|
||||
83
shaders/sky.comp
Normal file
83
shaders/sky.comp
Normal file
@@ -0,0 +1,83 @@
|
||||
#version 450
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
layout(rgba8,set = 0, binding = 0) uniform image2D image;
|
||||
|
||||
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||
|
||||
// Return random noise in the range [0.0, 1.0], as a function of x.
|
||||
float Noise2d( in vec2 x )
|
||||
{
|
||||
float xhash = cos( x.x * 37.0 );
|
||||
float yhash = cos( x.y * 57.0 );
|
||||
return fract( 415.92653 * ( xhash + yhash ) );
|
||||
}
|
||||
|
||||
// Convert Noise2d() into a "star field" by stomping everthing below fThreshhold to zero.
|
||||
float NoisyStarField( in vec2 vSamplePos, float fThreshhold )
|
||||
{
|
||||
float StarVal = Noise2d( vSamplePos );
|
||||
if ( StarVal >= fThreshhold )
|
||||
StarVal = pow( (StarVal - fThreshhold)/(1.0 - fThreshhold), 6.0 );
|
||||
else
|
||||
StarVal = 0.0;
|
||||
return StarVal;
|
||||
}
|
||||
|
||||
// Stabilize NoisyStarField() by only sampling at integer values.
|
||||
float StableStarField( in vec2 vSamplePos, float fThreshhold )
|
||||
{
|
||||
// Linear interpolation between four samples.
|
||||
// Note: This approach has some visual artifacts.
|
||||
// There must be a better way to "anti alias" the star field.
|
||||
float fractX = fract( vSamplePos.x );
|
||||
float fractY = fract( vSamplePos.y );
|
||||
vec2 floorSample = floor( vSamplePos );
|
||||
float v1 = NoisyStarField( floorSample, fThreshhold );
|
||||
float v2 = NoisyStarField( floorSample + vec2( 0.0, 1.0 ), fThreshhold );
|
||||
float v3 = NoisyStarField( floorSample + vec2( 1.0, 0.0 ), fThreshhold );
|
||||
float v4 = NoisyStarField( floorSample + vec2( 1.0, 1.0 ), fThreshhold );
|
||||
|
||||
float StarVal = v1 * ( 1.0 - fractX ) * ( 1.0 - fractY )
|
||||
+ v2 * ( 1.0 - fractX ) * fractY
|
||||
+ v3 * fractX * ( 1.0 - fractY )
|
||||
+ v4 * fractX * fractY;
|
||||
return StarVal;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 iResolution = imageSize(image);
|
||||
// Sky Background Color
|
||||
vec3 vColor = vec3( 0.1, 0.2, 0.4 ) * fragCoord.y / iResolution.y;
|
||||
|
||||
// Note: Choose fThreshhold in the range [0.99, 0.9999].
|
||||
// Higher values (i.e., closer to one) yield a sparser starfield.
|
||||
float StarFieldThreshhold = 0.97;
|
||||
|
||||
// Stars with a slow crawl.
|
||||
float xRate = 0.2;
|
||||
float yRate = -0.06;
|
||||
vec2 vSamplePos = fragCoord.xy + vec2( xRate * float( 1 ), yRate * float( 1 ) );
|
||||
float StarVal = StableStarField( vSamplePos, StarFieldThreshhold );
|
||||
vColor += vec3( StarVal );
|
||||
|
||||
fragColor = vec4(vColor, 1.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 value = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
ivec2 texelCoord = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 size = imageSize(image);
|
||||
if(texelCoord.x < size.x && texelCoord.y < size.y)
|
||||
{
|
||||
vec4 color;
|
||||
mainImage(color,texelCoord);
|
||||
|
||||
|
||||
imageStore(image, texelCoord, color);
|
||||
}
|
||||
}
|
||||
|
||||
49
shaders/tonemap.frag
Normal file
49
shaders/tonemap.frag
Normal file
@@ -0,0 +1,49 @@
|
||||
#version 450
|
||||
|
||||
layout(location=0) in vec2 inUV;
|
||||
layout(location=0) out vec4 outColor;
|
||||
|
||||
layout(set=0, binding=0) uniform sampler2D uHdr;
|
||||
|
||||
layout(push_constant) uniform Push
|
||||
{
|
||||
float exposure;
|
||||
int mode;
|
||||
} pc;
|
||||
|
||||
vec3 reinhard(vec3 x)
|
||||
{
|
||||
return x / (1.0 + x);
|
||||
}
|
||||
|
||||
// Narkowicz ACES approximation
|
||||
vec3 aces_tonemap(vec3 x)
|
||||
{
|
||||
// https://64.github.io/tonemapping/
|
||||
const float a = 2.51;
|
||||
const float b = 0.03;
|
||||
const float c = 2.43;
|
||||
const float d = 0.59;
|
||||
const float e = 0.14;
|
||||
return clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 hdr = texture(uHdr, inUV).rgb;
|
||||
|
||||
// Simple exposure
|
||||
float exposure = max(pc.exposure, 0.0001);
|
||||
vec3 mapped = hdr * exposure;
|
||||
|
||||
if (pc.mode == 1)
|
||||
mapped = aces_tonemap(mapped);
|
||||
else
|
||||
mapped = reinhard(mapped);
|
||||
|
||||
const float gamma = 2.2;
|
||||
mapped = pow(mapped, vec3(1.0 / gamma));
|
||||
|
||||
outColor = vec4(mapped, 1.0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user