Commit for 2021.04.20.7z
This commit is contained in:
parent
7794e730aa
commit
1fbf98155f
@ -2,8 +2,32 @@
|
||||
#extension GL_EXT_samplerless_texture_functions : require
|
||||
|
||||
#define MULTISAMPLING 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define RAY_MARCH_FOG 1
|
||||
#define UF_DEFERRED_SAMPLING 0
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const float EPSILON = 0.00001;
|
||||
|
||||
const float LIGHT_POWER_CUTOFF = 0.005;
|
||||
|
||||
const vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
vec2( -0.094184101, -0.92938870 ),
|
||||
vec2( 0.34495938, 0.29387760 ),
|
||||
vec2( -0.91588581, 0.45771432 ),
|
||||
vec2( -0.81544232, -0.87912464 ),
|
||||
vec2( -0.38277543, 0.27676845 ),
|
||||
vec2( 0.97484398, 0.75648379 ),
|
||||
vec2( 0.44323325, -0.97511554 ),
|
||||
vec2( 0.53742981, -0.47373420 ),
|
||||
vec2( -0.26496911, -0.41893023 ),
|
||||
vec2( 0.79197514, 0.19090188 ),
|
||||
vec2( -0.24188840, 0.99706507 ),
|
||||
vec2( -0.81409955, 0.91437590 ),
|
||||
vec2( 0.19984126, 0.78641367 ),
|
||||
vec2( 0.14383161, -0.14100790 )
|
||||
);
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 256;
|
||||
|
||||
@ -98,7 +122,7 @@ struct DrawCall {
|
||||
#if !MULTISAMPLING
|
||||
layout (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId;
|
||||
layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerUv;
|
||||
#else
|
||||
layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo;
|
||||
@ -107,7 +131,7 @@ struct DrawCall {
|
||||
#else
|
||||
layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId;
|
||||
layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerUv;
|
||||
#else
|
||||
layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo;
|
||||
@ -131,8 +155,8 @@ layout (binding = 4) uniform UBO {
|
||||
|
||||
uint msaa;
|
||||
uint poissonSamples;
|
||||
uint padding1;
|
||||
uint padding2;
|
||||
float gamma;
|
||||
float exposure;
|
||||
} ubo;
|
||||
|
||||
layout (std140, binding = 5) readonly buffer Lights {
|
||||
@ -158,321 +182,40 @@ layout (location = 1) in flat uint inPushConstantPass;
|
||||
|
||||
layout (location = 0) out vec4 outFragColor;
|
||||
|
||||
vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
vec2( -0.094184101, -0.92938870 ),
|
||||
vec2( 0.34495938, 0.29387760 ),
|
||||
vec2( -0.91588581, 0.45771432 ),
|
||||
vec2( -0.81544232, -0.87912464 ),
|
||||
vec2( -0.38277543, 0.27676845 ),
|
||||
vec2( 0.97484398, 0.75648379 ),
|
||||
vec2( 0.44323325, -0.97511554 ),
|
||||
vec2( 0.53742981, -0.47373420 ),
|
||||
vec2( -0.26496911, -0.41893023 ),
|
||||
vec2( 0.79197514, 0.19090188 ),
|
||||
vec2( -0.24188840, 0.99706507 ),
|
||||
vec2( -0.81409955, 0.91437590 ),
|
||||
vec2( 0.19984126, 0.78641367 ),
|
||||
vec2( 0.14383161, -0.14100790 )
|
||||
);
|
||||
|
||||
void phong( Light light, vec4 albedoSpecular, inout vec3 i ) {
|
||||
vec3 Ls = vec3(1.0, 1.0, 1.0); // light specular
|
||||
vec3 Ld = light.color; // light color
|
||||
vec3 La = vec3(1.0, 1.0, 1.0);
|
||||
|
||||
vec3 Ks = vec3(albedoSpecular.a); // material specular
|
||||
vec3 Kd = albedoSpecular.rgb; // material diffuse
|
||||
vec3 Ka = vec3(1.0, 1.0, 1.0);
|
||||
|
||||
float Kexp = ubo.kexp;
|
||||
|
||||
vec3 V = position.eye;
|
||||
vec3 N = normal.eye;
|
||||
vec3 L = light.position.xyz - V;
|
||||
float dist = length(L);
|
||||
// if ( light.radius > 0.001 && light.radius < dist ) return;
|
||||
|
||||
vec3 D = normalize(L);
|
||||
float d_dot = max(dot( D, N ), 0.0);
|
||||
|
||||
vec3 R = reflect( -D, N );
|
||||
vec3 S = normalize(-V);
|
||||
float s_factor = pow( max(dot( R, S ), 0.0), Kexp );
|
||||
if ( Kexp < 0.0001 ) s_factor = 0;
|
||||
|
||||
float radiance = light.power / (dist * dist);
|
||||
|
||||
vec3 Ia = La * Ka;
|
||||
vec3 Id = Ld * Kd * d_dot * radiance;
|
||||
vec3 Is = Ls * Ks * s_factor * radiance;
|
||||
|
||||
i += Id + Is;
|
||||
}
|
||||
void phongSpecular( Light light, vec4 albedoSpecular, inout vec3 i ) {
|
||||
vec3 Ls = vec3(1.0, 1.0, 1.0); // light specular
|
||||
vec3 Ld = light.color; // light color
|
||||
vec3 La = vec3(1.0, 1.0, 1.0);
|
||||
|
||||
vec3 Ks = vec3(albedoSpecular.a); // material specular
|
||||
vec3 Kd = albedoSpecular.rgb; // material diffuse
|
||||
vec3 Ka = vec3(1.0, 1.0, 1.0);
|
||||
|
||||
float Kexp = ubo.kexp;
|
||||
|
||||
vec3 V = position.eye;
|
||||
vec3 N = normal.eye;
|
||||
vec3 L = light.position.xyz - V;
|
||||
float dist = length(L);
|
||||
|
||||
vec3 D = normalize(L);
|
||||
vec3 R = reflect( -D, N );
|
||||
vec3 S = normalize(-V);
|
||||
float s_factor = pow( max(dot( R, S ), 0.0), Kexp );
|
||||
if ( Kexp < 0.0001 ) s_factor = 0;
|
||||
|
||||
float radiance = light.power / (dist * dist);
|
||||
|
||||
vec3 Ia = La * Ka;
|
||||
vec3 Is = Ls * Ks * s_factor * radiance;
|
||||
|
||||
i += Is;
|
||||
}
|
||||
const float PI = 3.14159265359;
|
||||
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 / denom;
|
||||
// GGX/Towbridge-Reitz normal distribution function.
|
||||
// Uses Disney's reparametrization of alpha = roughness^2.
|
||||
float ndfGGX(float cosLh, float roughness) {
|
||||
const float alpha = roughness * roughness;
|
||||
const float alphaSq = alpha * alpha;
|
||||
const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
return alphaSq / (PI * denom * denom);
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness) {
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r*r) / 8.0;
|
||||
// Single term for separable Schlick-GGX below.
|
||||
float gaSchlickG1(float cosTheta, float k) {
|
||||
return cosTheta / (cosTheta * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
float num = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
|
||||
return num / denom;
|
||||
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
|
||||
float gaSchlickGGX(float cosLi, float cosLo, float roughness) {
|
||||
const float r = roughness + 1.0;
|
||||
const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
|
||||
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
|
||||
}
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
|
||||
vec3 fresnelSchlick(vec3 F0, float cosTheta) {
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float random(vec3 seed, int i){
|
||||
vec4 seed4 = vec4(seed,i);
|
||||
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
|
||||
return fract(sin(dot_product) * 43758.5453);
|
||||
return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453);
|
||||
}
|
||||
|
||||
float shadowFactor( Light light, uint shadowMap, float def ) {
|
||||
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
|
||||
if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0;
|
||||
if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0;
|
||||
|
||||
float factor = 1.0;
|
||||
|
||||
// spot light
|
||||
if ( light.type == 1 || light.type == 2 ) {
|
||||
float dist = length( positionClip.xy );
|
||||
if ( dist > 0.5 ) return def; //0.0;
|
||||
|
||||
// spot light with attenuation
|
||||
if ( light.type == 2 ) {
|
||||
factor = 1.0 - (pow(dist * 2,2.0));
|
||||
}
|
||||
}
|
||||
|
||||
vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
float bias = light.depthBias;
|
||||
/*
|
||||
if ( true ) {
|
||||
float cosTheta = clamp(dot(normal.eye, normalize(light.position.xyz - position.eye)), 0, 1);
|
||||
bias = clamp(bias * tan(acos(cosTheta)), 0, 0.01);
|
||||
} else if ( true ) {
|
||||
bias = max(bias * 10 * (1.0 - dot(normal.eye, normalize(light.position.xyz - position.eye))), bias);
|
||||
}
|
||||
*/
|
||||
|
||||
float eyeDepth = positionClip.z;
|
||||
|
||||
int samples = int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) {
|
||||
return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor;
|
||||
}
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
// int index = i;
|
||||
// int index = int( float(samples) * random(gl_FragCoord.xyy, i) ) % samples;
|
||||
int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
|
||||
float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
return factor;
|
||||
// Returns a vector that is orthogonal to u.
|
||||
vec3 orthogonal(vec3 u){
|
||||
u = normalize(u);
|
||||
const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector.
|
||||
return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v);
|
||||
}
|
||||
vec3 hslToRgb(vec3 HSL) {
|
||||
vec3 RGB; {
|
||||
float H = HSL.x;
|
||||
float R = abs(H * 6 - 3) - 1;
|
||||
float G = 2 - abs(H * 6 - 2);
|
||||
float B = 2 - abs(H * 6 - 4);
|
||||
RGB = clamp(vec3(R,G,B), 0, 1);
|
||||
}
|
||||
float C = (1 - abs(2 * HSL.z - 1)) * HSL.y;
|
||||
return (RGB - 0.5) * C + HSL.z;
|
||||
}
|
||||
vec3 rgbToHsl(vec3 RGB) {
|
||||
float Epsilon = 1e-10;
|
||||
vec3 HCV; {
|
||||
vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0);
|
||||
vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx);
|
||||
float C = Q.x - min(Q.w, Q.y);
|
||||
float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z);
|
||||
HCV = vec3(H, C, Q.x);
|
||||
}
|
||||
float L = HCV.z - HCV.y * 0.5;
|
||||
float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon);
|
||||
return vec3(HCV.x, S, L);
|
||||
}
|
||||
|
||||
float hueDistance(float h1, float h2) {
|
||||
float diff = abs((h1 - h2));
|
||||
return min(abs((1.0 - diff)), diff);
|
||||
}
|
||||
const float lightnessSteps = 4.0;
|
||||
float lightnessStep(float l) {
|
||||
return floor((0.5 + l * lightnessSteps)) / lightnessSteps;
|
||||
}
|
||||
const int indexMatrix16x16[256] = int[](0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255,
|
||||
128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127,
|
||||
32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223,
|
||||
160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95,
|
||||
8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247,
|
||||
136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119,
|
||||
40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215,
|
||||
168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87,
|
||||
2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253,
|
||||
130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125,
|
||||
34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221,
|
||||
162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93,
|
||||
10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245,
|
||||
138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117,
|
||||
42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213,
|
||||
170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85);
|
||||
float indexValue16x16( float scale ) {
|
||||
int x = int(mod(gl_FragCoord.x * scale, 16));
|
||||
int y = int(mod(gl_FragCoord.y * scale, 16));
|
||||
return indexMatrix16x16[(x + y * 16)] / 256.0;
|
||||
}
|
||||
const int indexMatrix8x8[64] = int[](0, 32, 8, 40, 2, 34, 10, 42,
|
||||
48, 16, 56, 24, 50, 18, 58, 26,
|
||||
12, 44, 4, 36, 14, 46, 6, 38,
|
||||
60, 28, 52, 20, 62, 30, 54, 22,
|
||||
3, 35, 11, 43, 1, 33, 9, 41,
|
||||
51, 19, 59, 27, 49, 17, 57, 25,
|
||||
15, 47, 7, 39, 13, 45, 5, 37,
|
||||
63, 31, 55, 23, 61, 29, 53, 21);
|
||||
float indexValue8x8( float scale ) {
|
||||
int x = int(mod(gl_FragCoord.x * scale, 8));
|
||||
int y = int(mod(gl_FragCoord.y * scale, 8));
|
||||
return indexMatrix8x8[(x + y * 8)] / 64.0;
|
||||
}
|
||||
const int indexMatrix4x4[16] = int[](0, 8, 2, 10,
|
||||
12, 4, 14, 6,
|
||||
3, 11, 1, 9,
|
||||
15, 7, 13, 5);
|
||||
float indexValue4x4( float scale ) {
|
||||
int x = int(mod(gl_FragCoord.x * scale, 4));
|
||||
int y = int(mod(gl_FragCoord.y * scale, 4));
|
||||
return indexMatrix4x4[(x + y * 4)] / 16.0;
|
||||
}
|
||||
vec3[2] closestColors(float hue) {
|
||||
vec3 ret[2];
|
||||
vec3 closest = vec3(-2, 0, 0);
|
||||
vec3 secondClosest = vec3(-2, 0, 0);
|
||||
vec3 temp;
|
||||
/*
|
||||
for (int i = 0; i < palette.length(); ++i) {
|
||||
temp = rgbToHsl(palette[i].rgb);
|
||||
float tempDistance = hueDistance(temp.x, hue);
|
||||
if (tempDistance < hueDistance(closest.x, hue)) {
|
||||
secondClosest = closest;
|
||||
closest = temp;
|
||||
} else {
|
||||
if (tempDistance < hueDistance(secondClosest.x, hue)) {
|
||||
secondClosest = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
ret[0] = closest;
|
||||
ret[1] = secondClosest;
|
||||
return ret;
|
||||
}
|
||||
float dither(float color) {
|
||||
float closestColor = (color < 0.5) ? 0 : 1;
|
||||
float secondClosestColor = 1 - closestColor;
|
||||
float d = 1; // -0.5 - fract(ubo.mode.parameters.w / 8.0);
|
||||
if ( ubo.mode.scalar == 16 ) {
|
||||
d = indexValue16x16(1);
|
||||
} else if ( ubo.mode.scalar == 8 ) {
|
||||
d = indexValue8x8(1);
|
||||
} else if ( ubo.mode.scalar == 4 ) {
|
||||
d = indexValue4x4(1);
|
||||
}
|
||||
float distance = abs(closestColor - color);
|
||||
return (distance < d) ? closestColor : secondClosestColor;
|
||||
}
|
||||
void dither(inout vec3 color) {
|
||||
vec3 hsl = rgbToHsl(color);
|
||||
hsl.x = dither(hsl.x);
|
||||
color = hslToRgb(hsl);
|
||||
}
|
||||
void dither1(inout vec3 color) {
|
||||
vec3 hsl = rgbToHsl(color);
|
||||
|
||||
float d = 0;
|
||||
vec3 cs[2] = { hsl, hsl }; // closestColors(hsl.x);
|
||||
float scale = 1;
|
||||
if ( ubo.mode.scalar == 16 ) {
|
||||
d = indexValue16x16(scale);
|
||||
} else if ( ubo.mode.scalar == 8 ) {
|
||||
d = indexValue8x8(scale);
|
||||
} else if ( ubo.mode.scalar == 4 ) {
|
||||
d = indexValue4x4(scale);
|
||||
}
|
||||
float hueDiff = hueDistance(hsl.x, cs[0].x) / hueDistance(cs[1].x, cs[0].x);
|
||||
float l1 = lightnessStep(max((hsl.z - 0.125), 0.0));
|
||||
float l2 = lightnessStep(min((hsl.z + 0.124), 1.0));
|
||||
float lightnessDiff = (hsl.z - l1) / (l2 - l1);
|
||||
|
||||
vec3 resultColor = (hueDiff < d) ? cs[0] : cs[1];
|
||||
resultColor.z = (lightnessDiff < d) ? l1 : l2;
|
||||
color = hslToRgb(resultColor);
|
||||
}
|
||||
vec3 dither2() {
|
||||
vec3 vDither = dot( vec2( 171.0, 231.0 ), inUv.xy + ubo.mode.parameters.w ).xxx;
|
||||
vDither.rgb = fract( vDither.rgb / vec3( 103.0, 71.0, 97.0 ) ) - vec3( 0.5, 0.5, 0.5 );
|
||||
return ( vDither.rgb / 255.0 ) * 0.375;
|
||||
}
|
||||
|
||||
float rand2(vec2 co){
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453);
|
||||
}
|
||||
@ -480,95 +223,31 @@ float rand3(vec3 co){
|
||||
return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453);
|
||||
}
|
||||
void whitenoise(inout vec3 color) {
|
||||
float flicker = ubo.mode.parameters.x;
|
||||
float pieces = ubo.mode.parameters.y;
|
||||
float blend = ubo.mode.parameters.z;
|
||||
float time = ubo.mode.parameters.w;
|
||||
const float flicker = ubo.mode.parameters.x;
|
||||
const float pieces = ubo.mode.parameters.y;
|
||||
const float blend = ubo.mode.parameters.z;
|
||||
const float time = ubo.mode.parameters.w;
|
||||
if ( blend < 0.0001 ) return;
|
||||
float freq = sin(pow(mod(time, flicker) + flicker, 1.9));
|
||||
// float whiteNoise = rand3( floor(position.world / pieces) + floor(time * 2) );
|
||||
float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) );
|
||||
const float freq = sin(pow(mod(time, flicker) + flicker, 1.9));
|
||||
const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) );
|
||||
color = mix( color, vec3(whiteNoise), blend );
|
||||
}
|
||||
|
||||
void pbr( Light light, vec3 albedo, float metallic, float roughness, vec3 lightPositionWorld, inout vec3 i ) {
|
||||
vec3 F0 = vec3(0.04);
|
||||
F0 = mix(F0, albedo, metallic);
|
||||
|
||||
vec3 N = normalize(normal.eye);
|
||||
vec3 L = light.position.xyz - position.eye;
|
||||
float dist = length(L);
|
||||
|
||||
L = normalize(L);
|
||||
vec3 V = normalize(-position.eye);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float attenuation = light.power / (dist * dist);
|
||||
vec3 radiance = light.color.rgb * attenuation;
|
||||
|
||||
// cook-torrance brdf
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
|
||||
vec3 kD = vec3(1.0) - F;
|
||||
kD *= 1.0 - metallic;
|
||||
|
||||
vec3 numerator = NDF * G * F;
|
||||
float denominator = 4.0 * NdotV * NdotL;
|
||||
vec3 specular = numerator / max(denominator, 0.001);
|
||||
|
||||
// add to outgoing radiance Lo
|
||||
i += (kD * albedo / PI + specular) * radiance * NdotL;
|
||||
vec3 gamma( vec3 i ) {
|
||||
return pow(i.rgb, vec3(1.0 / 2.2));
|
||||
}
|
||||
void pbrSpecular( Light light, vec3 albedo, float metallic, float roughness, inout vec3 i ) {
|
||||
vec3 F0 = vec3(0.04);
|
||||
F0 = mix(F0, albedo, metallic);
|
||||
|
||||
vec3 N = normalize(normal.eye);
|
||||
vec3 L = light.position.xyz - position.eye;
|
||||
float dist = length(L);
|
||||
|
||||
L = normalize(L);
|
||||
vec3 V = normalize(-position.eye);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float attenuation = light.power / (dist * dist);
|
||||
vec3 radiance = light.color.rgb * attenuation;
|
||||
|
||||
// cook-torrance brdf
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
|
||||
vec3 kD = vec3(1.0) - F;
|
||||
kD *= 1.0 - metallic;
|
||||
|
||||
vec3 numerator = NDF * G * F;
|
||||
float denominator = 4.0 * NdotV * NdotL;
|
||||
vec3 specular = numerator / max(denominator, 0.001);
|
||||
|
||||
// add to outgoing radiance Lo
|
||||
i += specular * radiance * NdotL;
|
||||
}
|
||||
vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) {
|
||||
vec3 t0 = (boundsMin - rayO) / rayD;
|
||||
vec3 t1 = (boundsMax - rayO) / rayD;
|
||||
vec3 tmin = min(t0, t1);
|
||||
vec3 tmax = max(t0, t1);
|
||||
float dstA = max( max(tmin.x, tmin.y), tmin.z );
|
||||
float dstB = min( tmax.x, min(tmax.y, tmax.z) );
|
||||
float dstToBox = max(0, dstA);
|
||||
float dstInsideBox = max(0, dstB - dstToBox);
|
||||
return vec2(dstToBox, dstInsideBox);
|
||||
const vec3 t0 = (boundsMin - rayO) / rayD;
|
||||
const vec3 t1 = (boundsMax - rayO) / rayD;
|
||||
const vec3 tmin = min(t0, t1);
|
||||
const vec3 tmax = max(t0, t1);
|
||||
const float tStart = max(0, max( max(tmin.x, tmin.y), tmin.z ));
|
||||
const float tEnd = max(0, min( tmax.x, min(tmax.y, tmax.z) ) - tStart);
|
||||
return vec2(tStart, tEnd);
|
||||
}
|
||||
|
||||
float sampleDensity( vec3 position ) {
|
||||
vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01;
|
||||
const vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01;
|
||||
return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier;
|
||||
}
|
||||
|
||||
@ -577,15 +256,15 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return;
|
||||
|
||||
#if RAY_MARCH_FOG
|
||||
float range = ubo.fog.range.y;
|
||||
vec3 boundsMin = vec3(-range,-range,-range) + rayO;
|
||||
vec3 boundsMax = vec3(range,range,range) + rayO;
|
||||
int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale );
|
||||
const float range = ubo.fog.range.y;
|
||||
const vec3 boundsMin = vec3(-range,-range,-range) + rayO;
|
||||
const vec3 boundsMax = vec3(range,range,range) + rayO;
|
||||
const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale );
|
||||
|
||||
vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD );
|
||||
float dstToBox = rayBoxInfo.x;
|
||||
float dstInsideBox = rayBoxInfo.y;
|
||||
float depth = position.eye.z;
|
||||
const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD );
|
||||
const float dstToBox = rayBoxInfo.x;
|
||||
const float dstInsideBox = rayBoxInfo.y;
|
||||
const float depth = position.eye.z;
|
||||
|
||||
float lightEnergy = 0;
|
||||
// march
|
||||
@ -608,22 +287,20 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 color = ubo.fog.color.rgb;
|
||||
float inner = ubo.fog.range.x;
|
||||
float outer = ubo.fog.range.y * scale;
|
||||
float distance = length(-position.eye);
|
||||
float factor = (distance - inner) / (outer - inner);
|
||||
factor = clamp( factor, 0.0, 1.0 );
|
||||
const vec3 color = ubo.fog.color.rgb;
|
||||
const float inner = ubo.fog.range.x;
|
||||
const float outer = ubo.fog.range.y * scale;
|
||||
const float distance = length(-position.eye);
|
||||
const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 );
|
||||
|
||||
i.rgb = mix(i.rgb, color, factor);
|
||||
}
|
||||
|
||||
vec3 decodeNormals( vec2 enc ) {
|
||||
#define kPI 3.1415926536f
|
||||
vec2 ang = enc*2-1;
|
||||
vec2 scth = vec2( sin(ang.x * kPI), cos(ang.x * kPI) );
|
||||
vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
|
||||
return vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y);
|
||||
const vec2 ang = enc*2-1;
|
||||
const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) );
|
||||
const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
|
||||
return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) );
|
||||
/*
|
||||
vec2 fenc = enc*4-2;
|
||||
float f = dot(fenc,fenc);
|
||||
@ -638,15 +315,15 @@ vec2 wrap( vec2 uv ) {
|
||||
return vec2( wrap( uv.x ), wrap( uv.y ) );
|
||||
}
|
||||
float mipLevel( in vec2 uv ) {
|
||||
vec2 dx_vtc = dFdx(uv);
|
||||
vec2 dy_vtc = dFdy(uv);
|
||||
const vec2 dx_vtc = dFdx(uv);
|
||||
const vec2 dy_vtc = dFdy(uv);
|
||||
return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
|
||||
}
|
||||
bool validTextureIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex; // && textureIndex < ubo.textures;
|
||||
}
|
||||
vec4 resolve( subpassInputMS t ) {
|
||||
int samples = int(ubo.msaa);
|
||||
const int samples = int(ubo.msaa);
|
||||
vec4 resolved = vec4(0);
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
resolved += subpassLoad(t, i);
|
||||
@ -655,7 +332,7 @@ vec4 resolve( subpassInputMS t ) {
|
||||
return resolved;
|
||||
}
|
||||
uvec4 resolve( usubpassInputMS t ) {
|
||||
int samples = int(ubo.msaa);
|
||||
const int samples = int(ubo.msaa);
|
||||
uvec4 resolved = uvec4(0);
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
resolved += subpassLoad(t, i);
|
||||
@ -664,6 +341,42 @@ uvec4 resolve( usubpassInputMS t ) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
float shadowFactor( const Light light, float def ) {
|
||||
if ( !validTextureIndex(light.mapIndex) ) return 1.0;
|
||||
|
||||
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
|
||||
if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0;
|
||||
if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0;
|
||||
|
||||
float factor = 1.0;
|
||||
|
||||
// spot light
|
||||
if ( abs(light.type) == 2 || abs(light.type) == 3 ) {
|
||||
const float dist = length( positionClip.xy );
|
||||
if ( dist > 0.5 ) return def; //0.0;
|
||||
|
||||
// spot light with attenuation
|
||||
if ( abs(light.type) == 3 ) {
|
||||
factor = 1.0 - (pow(dist * 2,2.0));
|
||||
}
|
||||
}
|
||||
|
||||
const vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
const float bias = light.depthBias;
|
||||
const float eyeDepth = positionClip.z;
|
||||
const int samples = int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
|
||||
const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 rayO = vec3(0);
|
||||
vec3 rayD = vec3(0);
|
||||
@ -671,77 +384,72 @@ void main() {
|
||||
|
||||
{
|
||||
#if !MULTISAMPLING
|
||||
float depth = subpassLoad(samplerDepth).r;
|
||||
const float depth = subpassLoad(samplerDepth).r;
|
||||
#else
|
||||
float depth = resolve( samplerDepth ).r;
|
||||
const float depth = resolve( samplerDepth ).r;
|
||||
#endif
|
||||
|
||||
vec4 positionClip = vec4(inUv * 2.0 - 1.0, depth, 1.0);
|
||||
vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * positionClip;
|
||||
vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0);
|
||||
positionEye /= positionEye.w;
|
||||
position.eye = positionEye.xyz;
|
||||
|
||||
vec4 positionWorld = ubo.matrices.iView[inPushConstantPass] * positionEye;
|
||||
position.world = positionWorld.xyz;
|
||||
position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye );
|
||||
}
|
||||
{
|
||||
vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
vec3 near3 = near4.xyz / near4.w;
|
||||
vec3 far3 = far4.xyz / far4.w;
|
||||
const vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
rayO = near3;
|
||||
rayD = normalize( far3 - near3 );
|
||||
}
|
||||
{
|
||||
mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) );
|
||||
vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
vec3 near3 = near4.xyz / near4.w;
|
||||
vec3 far3 = far4.xyz / far4.w;
|
||||
// separate our ray direction due to floating point precision problems
|
||||
if ( false ) {
|
||||
const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) );
|
||||
const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
rayD = normalize( far3 - near3 );
|
||||
}
|
||||
#if !MULTISAMPLING
|
||||
normal.world = decodeNormals( subpassLoad(samplerNormal).xy );
|
||||
uvec2 ID = subpassLoad(samplerId).xy;
|
||||
const uvec2 ID = subpassLoad(samplerId).xy;
|
||||
#else
|
||||
normal.world = decodeNormals( resolve(samplerNormal).xy );
|
||||
uvec2 ID = resolve(samplerId).xy;
|
||||
const uvec2 ID = resolve(samplerId).xy;
|
||||
#endif
|
||||
normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) );
|
||||
|
||||
uint drawId = ID.x;
|
||||
uint materialId = ID.y;
|
||||
if ( drawId == 0 || materialId == 0 ) {
|
||||
if ( ID.x == 0 || ID.y == 0 ) {
|
||||
fragColor.rgb = texture( samplerSkybox, rayD ).rgb;
|
||||
fog(rayO, rayD, fragColor, 0.0);
|
||||
outFragColor = vec4(fragColor,1);
|
||||
return;
|
||||
}
|
||||
--drawId;
|
||||
--materialId;
|
||||
|
||||
DrawCall drawCall = drawCalls[drawId];
|
||||
materialId += drawCall.materialIndex;
|
||||
|
||||
Material material = materials[materialId];
|
||||
vec4 C = material.colorBase;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
const uint drawId = ID.x - 1;
|
||||
const DrawCall drawCall = drawCalls[drawId];
|
||||
const uint materialId = ID.y + drawCall.materialIndex - 1;
|
||||
const Material material = materials[materialId];
|
||||
vec4 A = material.colorBase;
|
||||
#if DEFERRED_SAMPLING
|
||||
#if !MULTISAMPLING
|
||||
vec2 uv = subpassLoad(samplerUv).xy;
|
||||
const vec2 uv = subpassLoad(samplerUv).xy;
|
||||
#else
|
||||
vec2 uv = resolve(samplerUv).xy;
|
||||
const vec2 uv = resolve(samplerUv).xy;
|
||||
#endif
|
||||
bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
const float mip = mipLevel(inUv.xy);
|
||||
const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas];
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) {
|
||||
Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
|
||||
C = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
}
|
||||
// OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
C.a = 1;
|
||||
A.a = 1;
|
||||
// BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
@ -751,78 +459,65 @@ void main() {
|
||||
}
|
||||
#else
|
||||
#if !MULTISAMPLING
|
||||
C = subpassLoad(samplerAlbedo);
|
||||
A = subpassLoad(samplerAlbedo);
|
||||
#else
|
||||
C = resolve(samplerAlbedo);
|
||||
A = resolve(samplerAlbedo);
|
||||
#endif
|
||||
#endif
|
||||
float M = material.factorMetallic;
|
||||
float R = material.factorRoughness * 4.0;
|
||||
float AO = material.factorOcclusion;
|
||||
const float M = material.factorMetallic;
|
||||
const float R = material.factorRoughness;
|
||||
const float AO = 1.0f - material.factorOcclusion;
|
||||
|
||||
bool usePbr = true;
|
||||
bool gammaCorrect = false;
|
||||
float litFactor = 1.0;
|
||||
bool useLightmap = 0 <= material.indexLightmap;
|
||||
if ( useLightmap ) {
|
||||
fragColor = C.rgb + ubo.ambient.rgb;
|
||||
for ( uint i = 0; i < ubo.lights; ++i ) {
|
||||
Light light = lights[i];
|
||||
|
||||
if ( light.power <= 0.001 ) continue;
|
||||
|
||||
light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1));
|
||||
if ( validTextureIndex(light.mapIndex) ) {
|
||||
float factor = shadowFactor( light, light.mapIndex, 0.0 );
|
||||
light.power *= factor;
|
||||
litFactor += light.power;
|
||||
}
|
||||
if ( light.power <= 0.0001 ) continue;
|
||||
if ( usePbr ) pbrSpecular( light, C.rgb, M, R, fragColor ); else phongSpecular( light, C, fragColor );
|
||||
}
|
||||
/*
|
||||
float totalShadows = 0.0;
|
||||
float totalLights = 0.0;
|
||||
if ( 0 <= material.indexLightmap ) {
|
||||
fragColor = A.rgb + ubo.ambient.rgb * (1 - AO);
|
||||
} else {
|
||||
fragColor = A.rgb * ubo.ambient.rgb * (1 - AO);
|
||||
}
|
||||
{
|
||||
const vec3 N = normal.eye;
|
||||
const vec3 F0 = mix(vec3(0.04), A.rgb, M);
|
||||
const vec3 Lo = normalize( -position.eye );
|
||||
const float cosLo = max(0.0, dot(N, Lo));
|
||||
|
||||
for ( uint i = 0; i < ubo.lights; ++i ) {
|
||||
Light light = lights[i];
|
||||
const Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
const vec3 Lp = light.position;
|
||||
const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - position.eye;
|
||||
const vec3 Li = normalize(Liu);
|
||||
const float Ls = shadowFactor( light, 0.0 );
|
||||
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
|
||||
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
|
||||
|
||||
const float cosLi = max(0.0, dot(N, Li));
|
||||
|
||||
const vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLh = max(0.0, dot(N, Lh));
|
||||
|
||||
if ( light.power <= 0.001 ) continue;
|
||||
|
||||
vec3 lightPositionWorld = light.position.xyz;
|
||||
light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1));
|
||||
++totalLights;
|
||||
if ( !validTextureIndex(light.mapIndex) ) continue;
|
||||
totalShadows += shadowFactor( light, light.mapIndex, 1.0 );
|
||||
}
|
||||
fragColor = vec3(totalShadows / totalLights);
|
||||
*/
|
||||
} else {
|
||||
fragColor = C.rgb * ubo.ambient.rgb * AO;
|
||||
for ( uint i = 0; i < ubo.lights; ++i ) {
|
||||
Light light = lights[i];
|
||||
|
||||
if ( light.power <= 0.001 ) continue;
|
||||
|
||||
vec3 lightPositionWorld = light.position.xyz;
|
||||
light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1));
|
||||
|
||||
if ( validTextureIndex(light.mapIndex) ) {
|
||||
float factor = shadowFactor( light, light.mapIndex, 0.0 );
|
||||
light.power *= factor;
|
||||
litFactor += light.power;
|
||||
}
|
||||
if ( light.power <= 0.0001 ) continue;
|
||||
if ( usePbr ) pbr( light, C.rgb, M, R, lightPositionWorld, fragColor ); else phong( light, C, fragColor );
|
||||
const vec3 Lr = light.color.rgb * light.power * La * Ls;
|
||||
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
const float D = ndfGGX( cosLh, R );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
const vec3 diffuseBRDF = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb;
|
||||
const vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specularBRDF) * Lr * cosLi;
|
||||
// else if ( light.type == 0 ) fragColor.rgb += (diffuseBRDF) * Lr * cosLi;
|
||||
else fragColor.rgb += (diffuseBRDF + specularBRDF) * Lr * cosLi;
|
||||
litFactor += light.power * La * Ls;
|
||||
}
|
||||
}
|
||||
if ( gammaCorrect ) {
|
||||
fragColor = fragColor / (fragColor + vec3(1.0));
|
||||
fragColor = pow(fragColor, vec3(1.0/2.2));
|
||||
}
|
||||
|
||||
fog(rayO, rayD, fragColor, litFactor);
|
||||
|
||||
#if TONE_MAP
|
||||
// fragColor = fragColor / (fragColor + 1.0f);
|
||||
fragColor = vec3(1.0) - exp(-fragColor * ubo.exposure);
|
||||
#endif
|
||||
#if GAMMA_CORRECT
|
||||
fragColor = pow(fragColor, vec3(1.0 / ubo.gama));
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
if ( (ubo.mode.type & (0x1 << 0)) == (0x1 << 0) ) {
|
||||
@ -833,5 +528,6 @@ void main() {
|
||||
if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) {
|
||||
whitenoise(fragColor);
|
||||
}
|
||||
|
||||
outFragColor = vec4(fragColor,1);
|
||||
}
|
||||
@ -3,7 +3,36 @@
|
||||
|
||||
#define MULTISAMPLING 1
|
||||
#define RAY_MARCH_FOG 1
|
||||
#define UF_DEFERRED_SAMPLING 0
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define SHADOW_CONE_TRACED 0
|
||||
#define VOXEL_TRACE_IN_NDC 0
|
||||
|
||||
#define GAMMA_CORRECT 1
|
||||
#define TONE_MAP 1
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const float EPSILON = 0.00001;
|
||||
|
||||
const float LIGHT_POWER_CUTOFF = 0.005;
|
||||
|
||||
const vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
vec2( -0.094184101, -0.92938870 ),
|
||||
vec2( 0.34495938, 0.29387760 ),
|
||||
vec2( -0.91588581, 0.45771432 ),
|
||||
vec2( -0.81544232, -0.87912464 ),
|
||||
vec2( -0.38277543, 0.27676845 ),
|
||||
vec2( 0.97484398, 0.75648379 ),
|
||||
vec2( 0.44323325, -0.97511554 ),
|
||||
vec2( 0.53742981, -0.47373420 ),
|
||||
vec2( -0.26496911, -0.41893023 ),
|
||||
vec2( 0.79197514, 0.19090188 ),
|
||||
vec2( -0.24188840, 0.99706507 ),
|
||||
vec2( -0.81409955, 0.91437590 ),
|
||||
vec2( 0.19984126, 0.78641367 ),
|
||||
vec2( 0.14383161, -0.14100790 )
|
||||
);
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 256;
|
||||
|
||||
@ -105,7 +134,7 @@ struct Voxel {
|
||||
#if !MULTISAMPLING
|
||||
layout (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId;
|
||||
layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerUv;
|
||||
#else
|
||||
layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo;
|
||||
@ -114,7 +143,7 @@ struct Voxel {
|
||||
#else
|
||||
layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId;
|
||||
layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerUv;
|
||||
#else
|
||||
layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo;
|
||||
@ -138,8 +167,8 @@ layout (binding = 4) uniform UBO {
|
||||
|
||||
uint msaa;
|
||||
uint poissonSamples;
|
||||
uint padding1;
|
||||
uint padding2;
|
||||
float gamma;
|
||||
float exposure;
|
||||
} ubo;
|
||||
|
||||
layout (std140, binding = 5) readonly buffer Lights {
|
||||
@ -170,35 +199,12 @@ layout (location = 1) in flat uint inPushConstantPass;
|
||||
layout (location = 0) out vec4 outFragColor;
|
||||
layout (location = 1) out vec4 outDebugValue;
|
||||
|
||||
vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
vec2( -0.094184101, -0.92938870 ),
|
||||
vec2( 0.34495938, 0.29387760 ),
|
||||
vec2( -0.91588581, 0.45771432 ),
|
||||
vec2( -0.81544232, -0.87912464 ),
|
||||
vec2( -0.38277543, 0.27676845 ),
|
||||
vec2( 0.97484398, 0.75648379 ),
|
||||
vec2( 0.44323325, -0.97511554 ),
|
||||
vec2( 0.53742981, -0.47373420 ),
|
||||
vec2( -0.26496911, -0.41893023 ),
|
||||
vec2( 0.79197514, 0.19090188 ),
|
||||
vec2( -0.24188840, 0.99706507 ),
|
||||
vec2( -0.81409955, 0.91437590 ),
|
||||
vec2( 0.19984126, 0.78641367 ),
|
||||
vec2( 0.14383161, -0.14100790 )
|
||||
);
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const float EPSILON = 0.00001;
|
||||
|
||||
// GGX/Towbridge-Reitz normal distribution function.
|
||||
// Uses Disney's reparametrization of alpha = roughness^2.
|
||||
float ndfGGX(float cosLh, float roughness) {
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSq = alpha * alpha;
|
||||
|
||||
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
const float alpha = roughness * roughness;
|
||||
const float alphaSq = alpha * alpha;
|
||||
const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
return alphaSq / (PI * denom * denom);
|
||||
}
|
||||
|
||||
@ -209,8 +215,8 @@ float gaSchlickG1(float cosTheta, float k) {
|
||||
|
||||
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
|
||||
float gaSchlickGGX(float cosLi, float cosLo, float roughness) {
|
||||
float r = roughness + 1.0;
|
||||
float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
|
||||
const float r = roughness + 1.0;
|
||||
const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
|
||||
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
|
||||
}
|
||||
vec3 fresnelSchlick(vec3 F0, float cosTheta) {
|
||||
@ -218,54 +224,13 @@ vec3 fresnelSchlick(vec3 F0, float cosTheta) {
|
||||
}
|
||||
|
||||
float random(vec3 seed, int i){
|
||||
vec4 seed4 = vec4(seed,i);
|
||||
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
|
||||
return fract(sin(dot_product) * 43758.5453);
|
||||
return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453);
|
||||
}
|
||||
|
||||
float shadowFactor( Light light, uint shadowMap, float def ) {
|
||||
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
|
||||
if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0;
|
||||
if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0;
|
||||
|
||||
float factor = 1.0;
|
||||
|
||||
// spot light
|
||||
if ( light.type == 1 || light.type == 2 ) {
|
||||
float dist = length( positionClip.xy );
|
||||
if ( dist > 0.5 ) return def; //0.0;
|
||||
|
||||
// spot light with attenuation
|
||||
if ( light.type == 2 ) {
|
||||
factor = 1.0 - (pow(dist * 2,2.0));
|
||||
}
|
||||
}
|
||||
|
||||
vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
float bias = light.depthBias;
|
||||
|
||||
float eyeDepth = positionClip.z;
|
||||
|
||||
int samples = int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) {
|
||||
return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor;
|
||||
}
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
// int index = i;
|
||||
// int index = int( float(samples) * random(gl_FragCoord.xyy, i) ) % samples;
|
||||
int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
|
||||
float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
// Returns a vector that is orthogonal to u.
|
||||
vec3 orthogonal(vec3 u){
|
||||
u = normalize(u);
|
||||
vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector.
|
||||
const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector.
|
||||
return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v);
|
||||
}
|
||||
float rand2(vec2 co){
|
||||
@ -275,14 +240,13 @@ float rand3(vec3 co){
|
||||
return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453);
|
||||
}
|
||||
void whitenoise(inout vec3 color) {
|
||||
float flicker = ubo.mode.parameters.x;
|
||||
float pieces = ubo.mode.parameters.y;
|
||||
float blend = ubo.mode.parameters.z;
|
||||
float time = ubo.mode.parameters.w;
|
||||
const float flicker = ubo.mode.parameters.x;
|
||||
const float pieces = ubo.mode.parameters.y;
|
||||
const float blend = ubo.mode.parameters.z;
|
||||
const float time = ubo.mode.parameters.w;
|
||||
if ( blend < 0.0001 ) return;
|
||||
float freq = sin(pow(mod(time, flicker) + flicker, 1.9));
|
||||
// float whiteNoise = rand3( floor(position.world / pieces) + floor(time * 2) );
|
||||
float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) );
|
||||
const float freq = sin(pow(mod(time, flicker) + flicker, 1.9));
|
||||
const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) );
|
||||
color = mix( color, vec3(whiteNoise), blend );
|
||||
}
|
||||
vec3 gamma( vec3 i ) {
|
||||
@ -290,19 +254,17 @@ vec3 gamma( vec3 i ) {
|
||||
}
|
||||
|
||||
vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) {
|
||||
vec3 t0 = (boundsMin - rayO) / rayD;
|
||||
vec3 t1 = (boundsMax - rayO) / rayD;
|
||||
vec3 tmin = min(t0, t1);
|
||||
vec3 tmax = max(t0, t1);
|
||||
float dstA = max( max(tmin.x, tmin.y), tmin.z );
|
||||
float dstB = min( tmax.x, min(tmax.y, tmax.z) );
|
||||
float tStart = max(0, dstA);
|
||||
float tEnd = max(0, dstB - tStart);
|
||||
const vec3 t0 = (boundsMin - rayO) / rayD;
|
||||
const vec3 t1 = (boundsMax - rayO) / rayD;
|
||||
const vec3 tmin = min(t0, t1);
|
||||
const vec3 tmax = max(t0, t1);
|
||||
const float tStart = max(0, max( max(tmin.x, tmin.y), tmin.z ));
|
||||
const float tEnd = max(0, min( tmax.x, min(tmax.y, tmax.z) ) - tStart);
|
||||
return vec2(tStart, tEnd);
|
||||
}
|
||||
|
||||
float sampleDensity( vec3 position ) {
|
||||
vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01;
|
||||
const vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01;
|
||||
return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier;
|
||||
}
|
||||
|
||||
@ -311,15 +273,15 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return;
|
||||
|
||||
#if RAY_MARCH_FOG
|
||||
float range = ubo.fog.range.y;
|
||||
vec3 boundsMin = vec3(-range,-range,-range) + rayO;
|
||||
vec3 boundsMax = vec3(range,range,range) + rayO;
|
||||
int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale );
|
||||
const float range = ubo.fog.range.y;
|
||||
const vec3 boundsMin = vec3(-range,-range,-range) + rayO;
|
||||
const vec3 boundsMax = vec3(range,range,range) + rayO;
|
||||
const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale );
|
||||
|
||||
vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD );
|
||||
float dstToBox = rayBoxInfo.x;
|
||||
float dstInsideBox = rayBoxInfo.y;
|
||||
float depth = position.eye.z;
|
||||
const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD );
|
||||
const float dstToBox = rayBoxInfo.x;
|
||||
const float dstInsideBox = rayBoxInfo.y;
|
||||
const float depth = position.eye.z;
|
||||
|
||||
float lightEnergy = 0;
|
||||
// march
|
||||
@ -342,21 +304,19 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 color = ubo.fog.color.rgb;
|
||||
float inner = ubo.fog.range.x;
|
||||
float outer = ubo.fog.range.y * scale;
|
||||
float distance = length(-position.eye);
|
||||
float factor = (distance - inner) / (outer - inner);
|
||||
factor = clamp( factor, 0.0, 1.0 );
|
||||
const vec3 color = ubo.fog.color.rgb;
|
||||
const float inner = ubo.fog.range.x;
|
||||
const float outer = ubo.fog.range.y * scale;
|
||||
const float distance = length(-position.eye);
|
||||
const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 );
|
||||
|
||||
i.rgb = mix(i.rgb, color, factor);
|
||||
}
|
||||
|
||||
vec3 decodeNormals( vec2 enc ) {
|
||||
#define kPI 3.1415926536f
|
||||
vec2 ang = enc*2-1;
|
||||
vec2 scth = vec2( sin(ang.x * kPI), cos(ang.x * kPI) );
|
||||
vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
|
||||
const vec2 ang = enc*2-1;
|
||||
const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) );
|
||||
const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
|
||||
return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) );
|
||||
/*
|
||||
vec2 fenc = enc*4-2;
|
||||
@ -372,15 +332,15 @@ vec2 wrap( vec2 uv ) {
|
||||
return vec2( wrap( uv.x ), wrap( uv.y ) );
|
||||
}
|
||||
float mipLevel( in vec2 uv ) {
|
||||
vec2 dx_vtc = dFdx(uv);
|
||||
vec2 dy_vtc = dFdy(uv);
|
||||
const vec2 dx_vtc = dFdx(uv);
|
||||
const vec2 dy_vtc = dFdy(uv);
|
||||
return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
|
||||
}
|
||||
bool validTextureIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex; // && textureIndex < ubo.textures;
|
||||
}
|
||||
vec4 resolve( subpassInputMS t ) {
|
||||
int samples = int(ubo.msaa);
|
||||
const int samples = int(ubo.msaa);
|
||||
vec4 resolved = vec4(0);
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
resolved += subpassLoad(t, i);
|
||||
@ -389,7 +349,7 @@ vec4 resolve( subpassInputMS t ) {
|
||||
return resolved;
|
||||
}
|
||||
uvec4 resolve( usubpassInputMS t ) {
|
||||
int samples = int(ubo.msaa);
|
||||
const int samples = int(ubo.msaa);
|
||||
uvec4 resolved = uvec4(0);
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
resolved += subpassLoad(t, i);
|
||||
@ -398,8 +358,44 @@ uvec4 resolve( usubpassInputMS t ) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
float shadowFactor( const Light light, float def ) {
|
||||
if ( !validTextureIndex(light.mapIndex) ) return 1.0;
|
||||
|
||||
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
|
||||
if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0;
|
||||
if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0;
|
||||
|
||||
float factor = 1.0;
|
||||
|
||||
// spot light
|
||||
if ( abs(light.type) == 2 || abs(light.type) == 3 ) {
|
||||
const float dist = length( positionClip.xy );
|
||||
if ( dist > 0.5 ) return def; //0.0;
|
||||
|
||||
// spot light with attenuation
|
||||
if ( abs(light.type) == 3 ) {
|
||||
factor = 1.0 - (pow(dist * 2,2.0));
|
||||
}
|
||||
}
|
||||
|
||||
const vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
const float bias = light.depthBias;
|
||||
const float eyeDepth = positionClip.z;
|
||||
const int samples = int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
|
||||
const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
|
||||
Voxel getVoxel( vec3 P ) {
|
||||
vec3 uvw = vec3( ubo.matrices.voxel * vec4( P, 1.0f ) ) * 0.5f + 0.5f;
|
||||
const vec3 uvw = vec3( ubo.matrices.voxel * vec4( P, 1.0f ) ) * 0.5f + 0.5f;
|
||||
|
||||
Voxel voxel;
|
||||
voxel.id = uvec2(texture(voxelId, uvw).xy);
|
||||
@ -411,64 +407,65 @@ Voxel getVoxel( vec3 P ) {
|
||||
return voxel;
|
||||
}
|
||||
|
||||
#define VOXEL_TRACE_IN_NDC 0
|
||||
vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture ) {
|
||||
// bounds
|
||||
float albedoSize = textureSize( voxelAlbedo, 0 ).x;
|
||||
float mipmapLevels = textureQueryLod( voxelAlbedo, vec3(0) ).x;
|
||||
struct VoxelInfo {
|
||||
vec3 min;
|
||||
vec3 max;
|
||||
|
||||
float mipmapLevels;
|
||||
float albedoSize;
|
||||
float voxelSize;
|
||||
};
|
||||
VoxelInfo voxelInfo;
|
||||
|
||||
vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture, float maxDistance ) {
|
||||
#if VOXEL_TRACE_IN_NDC
|
||||
rayO = vec3( ubo.matrices.voxel * vec4( rayO, 1.0 ) );
|
||||
rayD = vec3( ubo.matrices.voxel * vec4( rayD, 0.0 ) );
|
||||
|
||||
vec3 boundsMin = vec3( -1 );
|
||||
vec3 boundsMax = vec3( 1 );
|
||||
float voxelSize = 1.0 / albedoSize;
|
||||
#else
|
||||
mat4 inverseOrtho = inverse( ubo.matrices.voxel );
|
||||
vec3 boundsMin = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) );
|
||||
vec3 boundsMax = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) );
|
||||
float voxelSize = 1;
|
||||
#endif
|
||||
float granularity = 1.0 / 6.0; // (2.0 * sqrt(2.0) );
|
||||
const float granularity = 1.0 / 6.0; // (2.0 * sqrt(2.0) );
|
||||
// box
|
||||
vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD );
|
||||
float tStart = rayBoxInfo.x;
|
||||
float tEnd = rayBoxInfo.y;
|
||||
const vec2 rayBoxInfo = rayBoxDst( voxelInfo.min, voxelInfo.max, rayO, rayD );
|
||||
const float tStart = rayBoxInfo.x;
|
||||
const float tEnd = maxDistance > 0 ? min(maxDistance, rayBoxInfo.y) : rayBoxInfo.y;
|
||||
// steps
|
||||
float tDelta = voxelSize * granularity;
|
||||
uint maxSteps = uint(albedoSize / granularity);
|
||||
const float tDelta = voxelInfo.voxelSize * granularity;
|
||||
const uint maxSteps = uint(voxelInfo.albedoSize / granularity);
|
||||
// marcher
|
||||
float t = tStart + tDelta * 2.0;
|
||||
vec3 rayPos = vec3(0);
|
||||
vec4 radiance = vec4(0);
|
||||
vec3 uvw = vec3(0);
|
||||
// cone mipmap shit
|
||||
float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
||||
const float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
||||
float coneDiameter = coneCoefficient * t;
|
||||
float level = aperture > 0 ? log2( coneDiameter / albedoSize ) : 0;
|
||||
float level = aperture > 0 ? log2( coneDiameter / voxelInfo.albedoSize ) : 0;
|
||||
// results
|
||||
vec4 color = vec4(0);
|
||||
float occlusion = 0.0;
|
||||
// do
|
||||
uint stepCounter = 0;
|
||||
while ( t < tEnd && occlusion < 1.0 && stepCounter++ < maxSteps ) {
|
||||
t += tDelta;
|
||||
const float falloff = 256.0f;
|
||||
const vec3 voxelBoundsRecip = 1.0f / (voxelInfo.max - voxelInfo.min);
|
||||
while ( t < tEnd && color.a < 1.0 && occlusion < 1.0 && stepCounter++ < maxSteps ) {
|
||||
t += tDelta * pow(2, coneDiameter / voxelInfo.albedoSize);
|
||||
rayPos = rayO + rayD * t;
|
||||
#if VOXEL_TRACE_IN_NDC
|
||||
uvw = rayPos * 0.5 + 0.5;
|
||||
#else
|
||||
uvw = (rayPos - boundsMin) / (boundsMax - boundsMin); // vec3( ubo.matrices.voxel * vec4( rayPos, 1 ) ) * 0.5 + 0.5;
|
||||
uvw = (rayPos - voxelInfo.min) * voxelBoundsRecip;
|
||||
#endif
|
||||
if ( abs(uvw.x) > 1.0 || abs(uvw.y) > 1.0 || abs(uvw.z) > 1.0 ) break;
|
||||
coneDiameter = coneCoefficient * t;
|
||||
level = log2( coneDiameter / albedoSize );
|
||||
level = log2( coneDiameter / voxelInfo.albedoSize );
|
||||
radiance = texture(voxelAlbedo, uvw, level) * granularity;
|
||||
|
||||
occlusion += radiance.a;
|
||||
color.rgb += (1.0 - occlusion) * radiance.rgb;
|
||||
color += (1.0 - color.a) * radiance;
|
||||
occlusion += ((1.0f - occlusion) * radiance.a) / (1.0f + falloff * coneDiameter);
|
||||
}
|
||||
return vec4(color.rgb, occlusion);
|
||||
}
|
||||
vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture ) {
|
||||
return voxelConeTrace( rayO, rayD, aperture, 0 );
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 rayO = vec3(0);
|
||||
@ -477,77 +474,72 @@ void main() {
|
||||
|
||||
{
|
||||
#if !MULTISAMPLING
|
||||
float depth = subpassLoad(samplerDepth).r;
|
||||
const float depth = subpassLoad(samplerDepth).r;
|
||||
#else
|
||||
float depth = resolve( samplerDepth ).r;
|
||||
const float depth = resolve( samplerDepth ).r;
|
||||
#endif
|
||||
|
||||
vec4 positionClip = vec4(inUv * 2.0 - 1.0, depth, 1.0);
|
||||
vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * positionClip;
|
||||
vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0);
|
||||
positionEye /= positionEye.w;
|
||||
position.eye = positionEye.xyz;
|
||||
|
||||
vec4 positionWorld = ubo.matrices.iView[inPushConstantPass] * positionEye;
|
||||
position.world = positionWorld.xyz;
|
||||
position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye );
|
||||
}
|
||||
{
|
||||
vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
vec3 near3 = near4.xyz / near4.w;
|
||||
vec3 far3 = far4.xyz / far4.w;
|
||||
const vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
rayO = near3;
|
||||
rayD = normalize( far3 - near3 );
|
||||
}
|
||||
{
|
||||
mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) );
|
||||
vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
vec3 near3 = near4.xyz / near4.w;
|
||||
vec3 far3 = far4.xyz / far4.w;
|
||||
// separate our ray direction due to floating point precision problems
|
||||
if ( true ) {
|
||||
const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) );
|
||||
const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
rayD = normalize( far3 - near3 );
|
||||
}
|
||||
#if !MULTISAMPLING
|
||||
normal.world = decodeNormals( subpassLoad(samplerNormal).xy );
|
||||
uvec2 ID = subpassLoad(samplerId).xy;
|
||||
const uvec2 ID = subpassLoad(samplerId).xy;
|
||||
#else
|
||||
normal.world = decodeNormals( resolve(samplerNormal).xy );
|
||||
uvec2 ID = resolve(samplerId).xy;
|
||||
const uvec2 ID = resolve(samplerId).xy;
|
||||
#endif
|
||||
normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) );
|
||||
|
||||
uint drawId = ID.x;
|
||||
uint materialId = ID.y;
|
||||
if ( drawId == 0 || materialId == 0 ) {
|
||||
if ( ID.x == 0 || ID.y == 0 ) {
|
||||
fragColor.rgb = texture( samplerSkybox, rayD ).rgb;
|
||||
fog(rayO, rayD, fragColor, 0.0);
|
||||
fog(rayO, rayD, fragColor, 0.5);
|
||||
outFragColor = vec4(fragColor,1);
|
||||
return;
|
||||
}
|
||||
--drawId;
|
||||
--materialId;
|
||||
|
||||
DrawCall drawCall = drawCalls[drawId];
|
||||
materialId += drawCall.materialIndex;
|
||||
|
||||
Material material = materials[materialId];
|
||||
vec4 C = material.colorBase;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
const uint drawId = ID.x - 1;
|
||||
const DrawCall drawCall = drawCalls[drawId];
|
||||
const uint materialId = ID.y + drawCall.materialIndex - 1;
|
||||
const Material material = materials[materialId];
|
||||
vec4 A = material.colorBase;
|
||||
#if DEFERRED_SAMPLING
|
||||
#if !MULTISAMPLING
|
||||
vec2 uv = subpassLoad(samplerUv).xy;
|
||||
const vec2 uv = subpassLoad(samplerUv).xy;
|
||||
#else
|
||||
vec2 uv = resolve(samplerUv).xy;
|
||||
const vec2 uv = resolve(samplerUv).xy;
|
||||
#endif
|
||||
bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
const float mip = mipLevel(inUv.xy);
|
||||
const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas];
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) {
|
||||
Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
|
||||
C = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
}
|
||||
// OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
C.a = 1;
|
||||
A.a = 1;
|
||||
// BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
@ -557,131 +549,128 @@ void main() {
|
||||
}
|
||||
#else
|
||||
#if !MULTISAMPLING
|
||||
C = subpassLoad(samplerAlbedo);
|
||||
A = subpassLoad(samplerAlbedo);
|
||||
#else
|
||||
C = resolve(samplerAlbedo);
|
||||
A = resolve(samplerAlbedo);
|
||||
#endif
|
||||
#endif
|
||||
float M = material.factorMetallic;
|
||||
float R = material.factorRoughness;
|
||||
const float M = material.factorMetallic;
|
||||
const float R = material.factorRoughness;
|
||||
float AO = material.factorOcclusion;
|
||||
|
||||
vec4 indirectLighting = vec4(0);
|
||||
// GI
|
||||
{
|
||||
vec3 P = position.world;
|
||||
vec3 N = normal.world;
|
||||
|
||||
// outFragColor = voxelConeTrace(rayO, rayD, 0 );
|
||||
// return;
|
||||
|
||||
const float ROUGHNESS_SCALE = clamp(sqrt( 0.111111f / ( R * R + 0.111111f ) ), 0.0, 1.0);
|
||||
const float ANGLE_MIX = 0.5f;
|
||||
const float DIFFUSE_CONE_APERTURE = 0.325;
|
||||
const float DIFFUSE_INDIRECT_FACTOR = ROUGHNESS_SCALE; //0.11111f * 0.111111f;
|
||||
|
||||
const vec3 ortho = normalize(orthogonal(N));
|
||||
const vec3 ortho2 = normalize(cross(ortho, N));
|
||||
const vec3 corner = 0.5f * (ortho + ortho2);
|
||||
const vec3 corner2 = 0.5f * (ortho - ortho2);
|
||||
|
||||
const vec3 CONES[9] = {
|
||||
N,
|
||||
|
||||
mix(N, ortho, ANGLE_MIX),
|
||||
mix(N, -ortho, ANGLE_MIX),
|
||||
mix(N, ortho2, ANGLE_MIX),
|
||||
mix(N, -ortho2, ANGLE_MIX),
|
||||
|
||||
mix(N, corner, ANGLE_MIX),
|
||||
mix(N, -corner, ANGLE_MIX),
|
||||
mix(N, corner2, ANGLE_MIX),
|
||||
mix(N, -corner2, ANGLE_MIX),
|
||||
};
|
||||
|
||||
vec4 indirectDiffuse = vec4(0);
|
||||
vec4 indirectSpecular = vec4(0);
|
||||
|
||||
// indirectDiffuse += voxelConeTrace( P, N, 0.325 );
|
||||
for ( uint i = 0; i < 1; ++i ) {
|
||||
indirectDiffuse += voxelConeTrace(P, CONES[i], DIFFUSE_CONE_APERTURE );
|
||||
const vec3 P = position.world;
|
||||
const vec3 N = normal.world;
|
||||
|
||||
const float DIFFUSE_CONE_APERTURE = 0.57735f;
|
||||
const float DIFFUSE_INDIRECT_FACTOR = 1.0f;
|
||||
|
||||
const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * R), 0.0174533f, PI);
|
||||
const float SPECULAR_INDIRECT_FACTOR = 1.0f;
|
||||
|
||||
const vec4 CONES[] = {
|
||||
vec4(0.0f, 1.0f, 0.0f, PI / 4.0f),
|
||||
vec4(0.0f, 0.5f, 0.866025f, 3.0f * PI / 20.0f),
|
||||
vec4(0.823639f, 0.5f, 0.267617f, 3.0f * PI / 20.0f),
|
||||
vec4(0.509037f, 0.5f, -0.7006629f, 3.0f * PI / 20.0f),
|
||||
vec4(-0.50937f, 0.5f, -0.7006629f, 3.0f * PI / 20.0f),
|
||||
vec4(-0.823639f, 0.5f, 0.267617f, 3.0f * PI / 20.0f)
|
||||
};
|
||||
if ( DIFFUSE_INDIRECT_FACTOR > 0.0f ) {
|
||||
voxelInfo.albedoSize = textureSize( voxelAlbedo, 0 ).x;
|
||||
voxelInfo.mipmapLevels = textureQueryLod( voxelAlbedo, vec3(0) ).x;
|
||||
#if VOXEL_TRACE_IN_NDC
|
||||
voxelInfo.min = vec3( -1 );
|
||||
voxelInfo.max = vec3( 1 );
|
||||
voxelInfo.voxelSize = 1.0 / voxelInfo.albedoSize;
|
||||
#else
|
||||
const mat4 inverseOrtho = inverse( ubo.matrices.voxel );
|
||||
voxelInfo.min = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) );
|
||||
voxelInfo.max = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) );
|
||||
voxelInfo.voxelSize = 1;
|
||||
#endif
|
||||
}
|
||||
if ( SPECULAR_INDIRECT_FACTOR > 0.0f ) {
|
||||
vec3 guide = vec3(0.0f, 1.0f, 0.0f);
|
||||
if (abs(dot(N,guide)) == 1.0f) guide = vec3(0.0f, 0.0f, 1.0f);
|
||||
|
||||
const float SPECULAR_CONE_APERTURE = acos( ROUGHNESS_SCALE );
|
||||
const float SPECULAR_INDIRECT_FACTOR = ROUGHNESS_SCALE; // 0.1;
|
||||
|
||||
vec3 R = reflect( normalize(P - rayO), N );
|
||||
indirectSpecular = voxelConeTrace( P, R, SPECULAR_CONE_APERTURE );
|
||||
indirectLighting = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR;
|
||||
// AO = 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0);
|
||||
// outFragColor.rgb = vec3(AO);
|
||||
// return;
|
||||
|
||||
// outFragColor.rgb = indirectLighting.rgb;
|
||||
// outFragColor.rgb = indirectDiffuse.rgb;
|
||||
// outFragColor.rgb = indirectSpecular.rgb;
|
||||
// return;
|
||||
const vec3 right = normalize(guide - dot(N, guide) * N);
|
||||
const vec3 up = cross(right, N);
|
||||
for ( uint i = 0; i < 6; ++i ) {
|
||||
const vec3 coneDirection = normalize(N + CONES[i].x * right + CONES[i].z * up);
|
||||
indirectDiffuse += voxelConeTrace(P, coneDirection, DIFFUSE_CONE_APERTURE ) * CONES[i].w;
|
||||
}
|
||||
indirectDiffuse.rgb *= A.rgb;
|
||||
AO = indirectDiffuse.a;
|
||||
// outFragColor.rgb = indirectDiffuse.rgb; return;
|
||||
}
|
||||
{
|
||||
const vec3 R = reflect( normalize(P - rayO), N );
|
||||
indirectSpecular = voxelConeTrace( P, R, SPECULAR_CONE_APERTURE );
|
||||
indirectLighting = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR;
|
||||
// outFragColor.rgb = indirectSpecular.rgb; return;
|
||||
}
|
||||
// outFragColor.rgb = indirectLighting.rgb; return;
|
||||
}
|
||||
R *= 2.0f;
|
||||
|
||||
bool usePbr = true;
|
||||
bool gammaCorrect = false;
|
||||
float litFactor = 1.0;
|
||||
bool useLightmap = 0 <= material.indexLightmap;
|
||||
if ( useLightmap ) {
|
||||
fragColor = C.rgb + ubo.ambient.rgb + indirectLighting.rgb;
|
||||
if ( 0 <= material.indexLightmap ) {
|
||||
fragColor = A.rgb + ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb;
|
||||
} else {
|
||||
fragColor = C.rgb * ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb;
|
||||
fragColor = A.rgb * ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb;
|
||||
}
|
||||
{
|
||||
const float LIGHT_POWER_CUTOFF = 0.0001;
|
||||
vec3 N = normal.eye;
|
||||
vec3 F0 = mix(vec3(0.04), C.rgb, M);
|
||||
const vec3 N = normal.eye;
|
||||
const vec3 F0 = mix(vec3(0.04), A.rgb, M);
|
||||
const vec3 Lo = normalize( -position.eye );
|
||||
const float cosLo = max(0.0, dot(N, Lo));
|
||||
#if 0
|
||||
for ( uint i = 0; i < ubo.lights; ++i ) {
|
||||
Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
light.position = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1));
|
||||
if ( validTextureIndex(light.mapIndex) ) {
|
||||
float factor = shadowFactor( light, light.mapIndex, 0.0 );
|
||||
light.power *= factor;
|
||||
litFactor += light.power;
|
||||
}
|
||||
vec3 Li = light.position - position.eye;
|
||||
light.power *= 1.0 / (PI * pow(length(Li), 2.0));
|
||||
const Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
const vec3 Lp = light.position;
|
||||
const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - position.eye;
|
||||
const vec3 Li = normalize(Liu);
|
||||
const float Ls = shadowFactor( light, 0.0 );
|
||||
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
|
||||
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
|
||||
|
||||
Li = normalize(Li);
|
||||
vec3 Lo = normalize( -position.eye );
|
||||
vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLi = max(0.0, dot(N, Li));
|
||||
|
||||
const vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLh = max(0.0, dot(N, Lh));
|
||||
|
||||
vec3 Lradiance = light.color.rgb * light.power;
|
||||
vec3 albedo = C.rgb;
|
||||
|
||||
float cosLi = max(0.0, dot(N, Li));
|
||||
float cosLo = max(0.0, dot(N, Lo));
|
||||
float cosLh = max(0.0, dot(N, Lh));
|
||||
|
||||
vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
float D = ndfGGX( cosLh, R );
|
||||
float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
|
||||
vec3 Kd = mix( vec3(1.0) - F, vec3(0.0), M );
|
||||
vec3 diffuseBRDF = Kd * albedo;
|
||||
vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
if ( useLightmap ) {
|
||||
fragColor.rgb += (specularBRDF) * Lradiance * cosLi;
|
||||
} else {
|
||||
fragColor.rgb += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
||||
}
|
||||
const vec3 Lr = light.color.rgb * light.power * La * Ls;
|
||||
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
const float D = ndfGGX( cosLh, R );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
const vec3 diffuseBRDF = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb;
|
||||
const vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specularBRDF) * Lr * cosLi;
|
||||
// else if ( abs(light.type) == 1 ) fragColor.rgb += (diffuseBRDF) * Lr * cosLi;
|
||||
else fragColor.rgb += (diffuseBRDF + specularBRDF) * Lr * cosLi;
|
||||
litFactor += light.power * La * Ls;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if ( gammaCorrect ) fragColor = gamma( fragColor );
|
||||
|
||||
fog(rayO, rayD, fragColor, litFactor);
|
||||
fog(rayO, rayD, fragColor, 1.0 ); //litFactor);
|
||||
|
||||
#if TONE_MAP
|
||||
fragColor = vec3(1.0) - exp(-fragColor * ubo.exposure);
|
||||
#endif
|
||||
#if GAMMA_CORRECT
|
||||
fragColor = pow(fragColor, vec3(1.0 / ubo.gamma));
|
||||
#endif
|
||||
|
||||
if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) {
|
||||
whitenoise(fragColor);
|
||||
}
|
||||
outFragColor = vec4(fragColor,1);
|
||||
|
||||
outFragColor = vec4(fragColor,1);
|
||||
}
|
||||
@ -5,7 +5,31 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
|
||||
|
||||
#define MULTISAMPLING 1
|
||||
#define RAY_MARCH_FOG 1
|
||||
#define UF_DEFERRED_SAMPLING 0
|
||||
#define DEFERRED_SAMPLING 0
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const float EPSILON = 0.00001;
|
||||
|
||||
const float LIGHT_POWER_CUTOFF = 0.005;
|
||||
|
||||
const vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
vec2( -0.094184101, -0.92938870 ),
|
||||
vec2( 0.34495938, 0.29387760 ),
|
||||
vec2( -0.91588581, 0.45771432 ),
|
||||
vec2( -0.81544232, -0.87912464 ),
|
||||
vec2( -0.38277543, 0.27676845 ),
|
||||
vec2( 0.97484398, 0.75648379 ),
|
||||
vec2( 0.44323325, -0.97511554 ),
|
||||
vec2( 0.53742981, -0.47373420 ),
|
||||
vec2( -0.26496911, -0.41893023 ),
|
||||
vec2( 0.79197514, 0.19090188 ),
|
||||
vec2( -0.24188840, 0.99706507 ),
|
||||
vec2( -0.81409955, 0.91437590 ),
|
||||
vec2( 0.19984126, 0.78641367 ),
|
||||
vec2( 0.14383161, -0.14100790 )
|
||||
);
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 256;
|
||||
|
||||
@ -113,8 +137,8 @@ layout (binding = 4) uniform UBO {
|
||||
|
||||
uint msaa;
|
||||
uint poissonSamples;
|
||||
uint padding1;
|
||||
uint padding2;
|
||||
float gamma;
|
||||
float exposure;
|
||||
} ubo;
|
||||
|
||||
layout (std140, binding = 5) readonly buffer Lights {
|
||||
@ -139,16 +163,12 @@ layout (binding = 13) uniform sampler3D samplerNoise;
|
||||
layout (binding = 14) uniform samplerCube samplerSkybox;
|
||||
layout (binding = 15) uniform sampler2D samplerTextures[TEXTURES];
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const float EPSILON = 0.00001;
|
||||
|
||||
// GGX/Towbridge-Reitz normal distribution function.
|
||||
// Uses Disney's reparametrization of alpha = roughness^2.
|
||||
float ndfGGX(float cosLh, float roughness) {
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSq = alpha * alpha;
|
||||
|
||||
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
const float alpha = roughness * roughness;
|
||||
const float alphaSq = alpha * alpha;
|
||||
const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
return alphaSq / (PI * denom * denom);
|
||||
}
|
||||
|
||||
@ -159,8 +179,8 @@ float gaSchlickG1(float cosTheta, float k) {
|
||||
|
||||
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
|
||||
float gaSchlickGGX(float cosLi, float cosLo, float roughness) {
|
||||
float r = roughness + 1.0;
|
||||
float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
|
||||
const float r = roughness + 1.0;
|
||||
const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
|
||||
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
|
||||
}
|
||||
vec3 fresnelSchlick(vec3 F0, float cosTheta) {
|
||||
@ -168,31 +188,45 @@ vec3 fresnelSchlick(vec3 F0, float cosTheta) {
|
||||
}
|
||||
|
||||
float random(vec3 seed, int i){
|
||||
vec4 seed4 = vec4(seed,i);
|
||||
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
|
||||
return fract(sin(dot_product) * 43758.5453);
|
||||
return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453);
|
||||
}
|
||||
|
||||
vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
vec2( -0.094184101, -0.92938870 ),
|
||||
vec2( 0.34495938, 0.29387760 ),
|
||||
vec2( -0.91588581, 0.45771432 ),
|
||||
vec2( -0.81544232, -0.87912464 ),
|
||||
vec2( -0.38277543, 0.27676845 ),
|
||||
vec2( 0.97484398, 0.75648379 ),
|
||||
vec2( 0.44323325, -0.97511554 ),
|
||||
vec2( 0.53742981, -0.47373420 ),
|
||||
vec2( -0.26496911, -0.41893023 ),
|
||||
vec2( 0.79197514, 0.19090188 ),
|
||||
vec2( -0.24188840, 0.99706507 ),
|
||||
vec2( -0.81409955, 0.91437590 ),
|
||||
vec2( 0.19984126, 0.78641367 ),
|
||||
vec2( 0.14383161, -0.14100790 )
|
||||
);
|
||||
// Returns a vector that is orthogonal to u.
|
||||
vec3 orthogonal(vec3 u){
|
||||
u = normalize(u);
|
||||
const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector.
|
||||
return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v);
|
||||
}
|
||||
float rand2(vec2 co){
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453);
|
||||
}
|
||||
float rand3(vec3 co){
|
||||
return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453);
|
||||
}
|
||||
|
||||
vec3 gamma( vec3 i ) {
|
||||
return pow(i.rgb, vec3(1.0 / 2.2));
|
||||
}
|
||||
|
||||
vec3 decodeNormals( vec2 enc ) {
|
||||
const vec2 ang = enc*2-1;
|
||||
const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) );
|
||||
const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
|
||||
return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) );
|
||||
}
|
||||
float wrap( float i ) {
|
||||
return fract(i);
|
||||
}
|
||||
vec2 wrap( vec2 uv ) {
|
||||
return vec2( wrap( uv.x ), wrap( uv.y ) );
|
||||
}
|
||||
bool validTextureIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex; // && textureIndex < ubo.textures;
|
||||
}
|
||||
|
||||
float shadowFactor( const Light light, float def ) {
|
||||
if ( !validTextureIndex(light.mapIndex) ) return 1.0;
|
||||
|
||||
float shadowFactor( Light light, uint shadowMap, float def ) {
|
||||
vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
@ -203,107 +237,66 @@ float shadowFactor( Light light, uint shadowMap, float def ) {
|
||||
float factor = 1.0;
|
||||
|
||||
// spot light
|
||||
if ( light.type == 1 || light.type == 2 ) {
|
||||
float dist = length( positionClip.xy );
|
||||
if ( abs(light.type) == 2 || abs(light.type) == 3 ) {
|
||||
const float dist = length( positionClip.xy );
|
||||
if ( dist > 0.5 ) return def; //0.0;
|
||||
|
||||
// spot light with attenuation
|
||||
if ( light.type == 2 ) {
|
||||
if ( abs(light.type) == 3 ) {
|
||||
factor = 1.0 - (pow(dist * 2,2.0));
|
||||
}
|
||||
}
|
||||
|
||||
vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
float bias = light.depthBias;
|
||||
/*
|
||||
if ( true ) {
|
||||
float cosTheta = clamp(dot(normal.eye, normalize(light.position.xyz - position.eye)), 0, 1);
|
||||
bias = clamp(bias * tan(acos(cosTheta)), 0, 0.01);
|
||||
} else if ( true ) {
|
||||
bias = max(bias * 10 * (1.0 - dot(normal.eye, normalize(light.position.xyz - position.eye))), bias);
|
||||
}
|
||||
*/
|
||||
|
||||
float eyeDepth = positionClip.z;
|
||||
|
||||
int samples = int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) {
|
||||
return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor;
|
||||
}
|
||||
const vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
const float bias = light.depthBias;
|
||||
const float eyeDepth = positionClip.z;
|
||||
const int samples = int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
// int index = i;
|
||||
// int index = int( float(samples) * random(gl_FragCoord.xyy, i) ) % samples;
|
||||
int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
|
||||
float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r;
|
||||
const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples;
|
||||
const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
|
||||
vec3 decodeNormals( vec2 enc ) {
|
||||
#define kPI 3.1415926536f
|
||||
vec2 ang = enc*2-1;
|
||||
vec2 scth = vec2( sin(ang.x * kPI), cos(ang.x * kPI) );
|
||||
vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
|
||||
return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) );
|
||||
/*
|
||||
vec2 fenc = enc*4-2;
|
||||
float f = dot(fenc,fenc);
|
||||
float g = sqrt(1-f/4);
|
||||
return normalize( vec3(fenc * g, 1 - f / 2) );
|
||||
*/
|
||||
}
|
||||
float wrap( float i ) {
|
||||
return fract(i);
|
||||
}
|
||||
vec2 wrap( vec2 uv ) {
|
||||
return vec2( wrap( uv.x ), wrap( uv.y ) );
|
||||
}
|
||||
void main() {
|
||||
vec3 fragColor = vec3(0);
|
||||
|
||||
const vec3 tUvw = gl_GlobalInvocationID.xyz;
|
||||
{
|
||||
const vec2 N = vec2(imageLoad(voxelNormal, ivec3(tUvw) ).xy);
|
||||
normal.world = decodeNormals( N );
|
||||
normal.eye = vec3( ubo.matrices.voxel * vec4( normal.world, 0.0f ) );
|
||||
|
||||
position.eye = vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelAlbedo)) * 2.0f - 1.0f;
|
||||
position.world = vec3( inverse(ubo.matrices.voxel) * vec4( position.eye, 1.0f ) );
|
||||
}
|
||||
|
||||
bool validTextureIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex; // && textureIndex < ubo.textures;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 tUvw = gl_GlobalInvocationID.xyz;
|
||||
|
||||
uvec2 ID = uvec2(imageLoad(voxelID, ivec3(tUvw) ).xy);
|
||||
vec2 N = vec2(imageLoad(voxelNormal, ivec3(tUvw) ).xy);
|
||||
|
||||
normal.world = decodeNormals( N );
|
||||
normal.eye = vec3( ubo.matrices.voxel * vec4( normal.world, 0.0f ) );
|
||||
|
||||
position.eye = vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelAlbedo)) * 2.0f - 1.0f;
|
||||
position.world = vec3( inverse(ubo.matrices.voxel) * vec4( position.eye, 1.0f ) );
|
||||
|
||||
vec2 uv = imageLoad(voxelUv, ivec3(tUvw) ).xy;
|
||||
|
||||
uint drawId = ID.x;
|
||||
uint materialId = ID.y;
|
||||
if ( drawId == 0 || materialId == 0 ) {
|
||||
const uvec2 ID = uvec2(imageLoad(voxelID, ivec3(tUvw) ).xy);
|
||||
if ( ID.x == 0 || ID.y == 0 ) {
|
||||
imageStore(voxelAlbedo, ivec3(tUvw), vec4(0));
|
||||
return;
|
||||
}
|
||||
--drawId;
|
||||
--materialId;
|
||||
const uint drawId = ID.x - 1;
|
||||
const DrawCall drawCall = drawCalls[drawId];
|
||||
const uint materialId = ID.y + drawCall.materialIndex - 1;
|
||||
const Material material = materials[materialId];
|
||||
vec4 A = material.colorBase;
|
||||
|
||||
DrawCall drawCall = drawCalls[drawId];
|
||||
materialId += drawCall.materialIndex;
|
||||
|
||||
Material material = materials[materialId];
|
||||
vec4 C = material.colorBase;
|
||||
|
||||
bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
#if DEFERRED_SAMPLING
|
||||
const vec2 uv = imageLoad(voxelUv, ivec3(tUvw) ).xy;
|
||||
const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas];
|
||||
if ( validTextureIndex( drawCall.textureIndex + material.indexAtlas ) ) {
|
||||
Texture t = textures[drawCall.textureIndex + material.indexAlbedo];
|
||||
C = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv );
|
||||
A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv );
|
||||
}
|
||||
|
||||
// OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
C.a = 1;
|
||||
A.a = 1;
|
||||
// BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
@ -311,61 +304,52 @@ void main() {
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
|
||||
}
|
||||
#else
|
||||
A = imageLoad(voxelAlbedo, ivec3(tUvw) );
|
||||
#endif
|
||||
const float M = material.factorMetallic;
|
||||
const float R = material.factorRoughness;
|
||||
const float AO = material.factorOcclusion;
|
||||
|
||||
float M = material.factorMetallic;
|
||||
float R = material.factorRoughness * 4.0;
|
||||
float AO = material.factorOcclusion;
|
||||
|
||||
bool usePbr = true;
|
||||
bool gammaCorrect = false;
|
||||
float litFactor = 1.0;
|
||||
bool useLightmap = 0 <= material.indexLightmap;
|
||||
vec3 fragColor = vec3(0.0);
|
||||
if ( useLightmap ) {
|
||||
fragColor = C.rgb + ubo.ambient.rgb;
|
||||
if ( 0 <= material.indexLightmap ) {
|
||||
fragColor = A.rgb + ubo.ambient.rgb * (1 - AO);
|
||||
} else {
|
||||
fragColor = C.rgb * ubo.ambient.rgb * (1 - AO);
|
||||
fragColor = A.rgb * ubo.ambient.rgb * (1 - AO);
|
||||
}
|
||||
{
|
||||
const float LIGHT_POWER_CUTOFF = 0.005;
|
||||
vec3 N = normal.world;
|
||||
vec3 F0 = mix(vec3(0.04), C.rgb, M);
|
||||
const vec3 N = normal.world;
|
||||
const vec3 F0 = mix(vec3(0.04), A.rgb, M);
|
||||
const vec3 Lo = normalize( -position.world );
|
||||
const float cosLo = max(0.0, dot(N, Lo));
|
||||
|
||||
for ( uint i = 0; i < ubo.lights; ++i ) {
|
||||
Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
if ( validTextureIndex(light.mapIndex) ) {
|
||||
float factor = shadowFactor( light, light.mapIndex, 0.0 );
|
||||
light.power *= factor;
|
||||
litFactor += light.power;
|
||||
}
|
||||
vec3 Li = light.position - position.world;
|
||||
light.power *= 1.0 / (PI * pow(length(Li), 2.0));
|
||||
const Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
const vec3 Lp = light.position;
|
||||
const vec3 Liu = light.position - position.world;
|
||||
const vec3 Li = normalize(Liu);
|
||||
const float Ls = shadowFactor( light, 0.0 );
|
||||
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
|
||||
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
|
||||
|
||||
Li = normalize(Li);
|
||||
vec3 Lo = normalize( -position.world );
|
||||
vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLi = max(0.0, dot(N, Li));
|
||||
|
||||
const vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLh = max(0.0, dot(N, Lh));
|
||||
|
||||
vec3 Lradiance = light.color.rgb * light.power;
|
||||
vec3 albedo = C.rgb;
|
||||
|
||||
float cosLi = max(0.0, dot(N, Li));
|
||||
float cosLo = max(0.0, dot(N, Lo));
|
||||
float cosLh = max(0.0, dot(N, Lh));
|
||||
|
||||
vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
float D = ndfGGX( cosLh, R );
|
||||
float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
|
||||
vec3 Kd = mix( vec3(1.0) - F, vec3(0.0), M );
|
||||
vec3 diffuseBRDF = Kd * albedo;
|
||||
vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
if ( useLightmap ) {
|
||||
fragColor.rgb += (specularBRDF) * Lradiance * cosLi;
|
||||
} else {
|
||||
fragColor.rgb += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
||||
}
|
||||
const vec3 Lr = light.color.rgb * light.power * La * Ls;
|
||||
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
const float D = ndfGGX( cosLh, R );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
const vec3 diffuseBRDF = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb;
|
||||
const vec3 specularBRDF = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
|
||||
if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specularBRDF) * Lr * cosLi;
|
||||
// else if ( light.type == 0 ) fragColor.rgb += (diffuseBRDF) * Lr * cosLi;
|
||||
else fragColor.rgb += (diffuseBRDF + specularBRDF) * Lr * cosLi;
|
||||
litFactor += light.power * La * Ls;
|
||||
}
|
||||
}
|
||||
|
||||
imageStore(voxelAlbedo, ivec3(tUvw), vec4(fragColor.rgb, 1));
|
||||
}
|
||||
@ -3,6 +3,8 @@
|
||||
#define UF_DEFERRED_SAMPLING 0
|
||||
#define UF_CAN_DISCARD 1
|
||||
|
||||
#define PI 3.1415926536f
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 1;
|
||||
layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES];
|
||||
|
||||
@ -58,8 +60,7 @@ layout (location = 1) out vec2 outNormals;
|
||||
|
||||
vec2 encodeNormals( vec3 n ) {
|
||||
// return n.xy / sqrt(n.z*8+8) + 0.5;
|
||||
#define kPI 3.1415926536f
|
||||
return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5;
|
||||
return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5;
|
||||
}
|
||||
|
||||
float wrap( float i ) {
|
||||
@ -69,25 +70,25 @@ vec2 wrap( vec2 uv ) {
|
||||
return vec2( wrap( uv.x ), wrap( uv.y ) );
|
||||
}
|
||||
float mipLevel( in vec2 uv ) {
|
||||
vec2 dx_vtc = dFdx(uv);
|
||||
vec2 dy_vtc = dFdy(uv);
|
||||
const vec2 dx_vtc = dFdx(uv);
|
||||
const vec2 dy_vtc = dFdy(uv);
|
||||
return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
|
||||
}
|
||||
bool validTextureIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex && textureIndex < TEXTURES;
|
||||
}
|
||||
void main() {
|
||||
float mip = mipLevel(inUv.xy);
|
||||
vec2 uv = wrap(inUv.xy);
|
||||
vec4 C = vec4(0, 0, 0, 0);
|
||||
vec3 P = inPosition;
|
||||
vec3 N = inNormal;
|
||||
const float mip = mipLevel(inUv.xy);
|
||||
const vec2 uv = wrap(inUv.xy);
|
||||
vec4 A = vec4(0, 0, 0, 0);
|
||||
const vec3 P = inPosition;
|
||||
const vec3 N = inNormal;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
outUvs = wrap(inUv.xy);
|
||||
vec4 outAlbedo = vec4(0,0,0,0);
|
||||
const vec4 outAlbedo = vec4(0,0,0,0);
|
||||
#endif
|
||||
#if !UF_DEFERRED_SAMPLING
|
||||
C = textureLod( samplerTextures[0], inSt, mip );
|
||||
A = textureLod( samplerTextures[0], inSt, mip );
|
||||
#endif
|
||||
outNormals = encodeNormals( N );
|
||||
outId = ivec2(inId.w+1, inId.y+1);
|
||||
|
||||
@ -1,5 +1,29 @@
|
||||
#version 450
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const float EPSILON = 0.00001;
|
||||
|
||||
const float LIGHT_POWER_CUTOFF = 0.005;
|
||||
|
||||
const vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
vec2( -0.094184101, -0.92938870 ),
|
||||
vec2( 0.34495938, 0.29387760 ),
|
||||
vec2( -0.91588581, 0.45771432 ),
|
||||
vec2( -0.81544232, -0.87912464 ),
|
||||
vec2( -0.38277543, 0.27676845 ),
|
||||
vec2( 0.97484398, 0.75648379 ),
|
||||
vec2( 0.44323325, -0.97511554 ),
|
||||
vec2( 0.53742981, -0.47373420 ),
|
||||
vec2( -0.26496911, -0.41893023 ),
|
||||
vec2( 0.79197514, 0.19090188 ),
|
||||
vec2( -0.24188840, 0.99706507 ),
|
||||
vec2( -0.81409955, 0.91437590 ),
|
||||
vec2( 0.19984126, 0.78641367 ),
|
||||
vec2( 0.14383161, -0.14100790 )
|
||||
);
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 1;
|
||||
layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES];
|
||||
|
||||
@ -64,65 +88,58 @@ layout (location = 7) flat in ivec4 inId;
|
||||
|
||||
layout (location = 0) out vec4 outAlbedo;
|
||||
|
||||
vec2 poissonDisk[16] = vec2[](
|
||||
vec2( -0.94201624, -0.39906216 ),
|
||||
vec2( 0.94558609, -0.76890725 ),
|
||||
vec2( -0.094184101, -0.92938870 ),
|
||||
vec2( 0.34495938, 0.29387760 ),
|
||||
vec2( -0.91588581, 0.45771432 ),
|
||||
vec2( -0.81544232, -0.87912464 ),
|
||||
vec2( -0.38277543, 0.27676845 ),
|
||||
vec2( 0.97484398, 0.75648379 ),
|
||||
vec2( 0.44323325, -0.97511554 ),
|
||||
vec2( 0.53742981, -0.47373420 ),
|
||||
vec2( -0.26496911, -0.41893023 ),
|
||||
vec2( 0.79197514, 0.19090188 ),
|
||||
vec2( -0.24188840, 0.99706507 ),
|
||||
vec2( -0.81409955, 0.91437590 ),
|
||||
vec2( 0.19984126, 0.78641367 ),
|
||||
vec2( 0.14383161, -0.14100790 )
|
||||
);
|
||||
float random(vec3 seed, int i){
|
||||
vec4 seed4 = vec4(seed,i);
|
||||
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
|
||||
return fract(sin(dot_product) * 43758.5453);
|
||||
// GGX/Towbridge-Reitz normal distribution function.
|
||||
// Uses Disney's reparametrization of alpha = roughness^2.
|
||||
float ndfGGX(float cosLh, float roughness) {
|
||||
const float alpha = roughness * roughness;
|
||||
const float alphaSq = alpha * alpha;
|
||||
const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
return alphaSq / (PI * denom * denom);
|
||||
}
|
||||
float shadowFactor( vec3 position, Light light, uint shadowMap, float def ) {
|
||||
vec4 positionClip = light.projection * light.view * vec4(position, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def;
|
||||
if ( positionClip.y < -1 || positionClip.y >= 1 ) return def;
|
||||
if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def;
|
||||
// Single term for separable Schlick-GGX below.
|
||||
float gaSchlickG1(float cosTheta, float k) {
|
||||
return cosTheta / (cosTheta * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
float factor = 1.0;
|
||||
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
|
||||
float gaSchlickGGX(float cosLi, float cosLo, float roughness) {
|
||||
const float r = roughness + 1.0;
|
||||
const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
|
||||
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
|
||||
}
|
||||
vec3 fresnelSchlick(vec3 F0, float cosTheta) {
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
// spot light
|
||||
if ( light.type == 2 || light.type == 3 ) {
|
||||
float dist = length( positionClip.xy );
|
||||
if ( dist > 0.5 ) return def;
|
||||
|
||||
// spot light with attenuation
|
||||
if ( light.type == 3 ) {
|
||||
factor = 1.0 - (pow(dist * 2,2.0));
|
||||
}
|
||||
}
|
||||
|
||||
vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
float bias = light.depthBias;
|
||||
float random(vec3 seed, int i){
|
||||
return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453);
|
||||
}
|
||||
|
||||
float eyeDepth = positionClip.z;
|
||||
// Returns a vector that is orthogonal to u.
|
||||
vec3 orthogonal(vec3 u){
|
||||
u = normalize(u);
|
||||
const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector.
|
||||
return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v);
|
||||
}
|
||||
float rand2(vec2 co){
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453);
|
||||
}
|
||||
float rand3(vec3 co){
|
||||
return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453);
|
||||
}
|
||||
|
||||
int samples = 16;
|
||||
if ( samples <= 1 ) {
|
||||
return eyeDepth < texture(samplerTextures[shadowMap], uv).r - bias ? 0.0 : factor;
|
||||
}
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
int index = int( float(samples) * random(floor(position * 1000.0), i)) % samples;
|
||||
float lightDepth = texture(samplerTextures[shadowMap], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
return factor;
|
||||
vec3 decodeNormals( vec2 enc ) {
|
||||
const vec2 ang = enc*2-1;
|
||||
const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) );
|
||||
const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
|
||||
return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) );
|
||||
/*
|
||||
vec2 fenc = enc*4-2;
|
||||
float f = dot(fenc,fenc);
|
||||
float g = sqrt(1-f/4);
|
||||
return normalize( vec3(fenc * g, 1 - f / 2) );
|
||||
*/
|
||||
}
|
||||
float wrap( float i ) {
|
||||
return fract(i);
|
||||
@ -131,116 +148,83 @@ vec2 wrap( vec2 uv ) {
|
||||
return vec2( wrap( uv.x ), wrap( uv.y ) );
|
||||
}
|
||||
float mipLevel( in vec2 uv ) {
|
||||
vec2 dx_vtc = dFdx(uv);
|
||||
vec2 dy_vtc = dFdy(uv);
|
||||
const vec2 dx_vtc = dFdx(uv);
|
||||
const vec2 dy_vtc = dFdy(uv);
|
||||
return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
|
||||
}
|
||||
bool validTextureIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex && textureIndex < textures.length();
|
||||
return 0 <= textureIndex; // && textureIndex < ubo.textures;
|
||||
}
|
||||
const float PI = 3.14159265359;
|
||||
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 shadowFactor( const Light light, const vec3 P, float def ) {
|
||||
if ( !validTextureIndex(light.mapIndex) ) return 1.0;
|
||||
|
||||
vec4 positionClip = light.projection * light.view * vec4(P, 1.0);
|
||||
positionClip.xyz /= positionClip.w;
|
||||
|
||||
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
|
||||
if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0;
|
||||
if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0;
|
||||
|
||||
float factor = 1.0;
|
||||
|
||||
// spot light
|
||||
if ( abs(light.type) == 2 || abs(light.type) == 3 ) {
|
||||
const float dist = length( positionClip.xy );
|
||||
if ( dist > 0.5 ) return def; //0.0;
|
||||
|
||||
// spot light with attenuation
|
||||
if ( abs(light.type) == 3 ) {
|
||||
factor = 1.0 - (pow(dist * 2,2.0));
|
||||
}
|
||||
}
|
||||
|
||||
float num = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return num / denom;
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness) {
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r*r) / 8.0;
|
||||
|
||||
float num = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
|
||||
return num / denom;
|
||||
}
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
void pbr( Light light, vec3 albedo, float metallic, float roughness, vec3 normal, vec3 position, inout vec3 i ) {
|
||||
vec3 F0 = vec3(0.04);
|
||||
F0 = mix(F0, albedo, metallic);
|
||||
|
||||
vec3 N = normalize(normal);
|
||||
vec3 L = light.position.xyz - position;
|
||||
float dist = length(L);
|
||||
|
||||
L = normalize(L);
|
||||
vec3 V = normalize(-position);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float attenuation = light.power / (dist * dist);
|
||||
vec3 radiance = light.color.rgb * attenuation;
|
||||
|
||||
// cook-torrance brdf
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
|
||||
vec3 kD = vec3(1.0) - F;
|
||||
kD *= 1.0 - metallic;
|
||||
|
||||
vec3 numerator = NDF * G * F;
|
||||
float denominator = 4.0 * NdotV * NdotL;
|
||||
vec3 specular = numerator / max(denominator, 0.001);
|
||||
|
||||
// add to outgoing radiance Lo
|
||||
// ignore specular
|
||||
i += (kD * albedo / PI ) * radiance * NdotL;
|
||||
const vec2 uv = positionClip.xy * 0.5 + 0.5;
|
||||
const float bias = light.depthBias;
|
||||
const float eyeDepth = positionClip.z;
|
||||
const int samples = 16; //int(ubo.poissonSamples);
|
||||
if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor;
|
||||
for ( int i = 0; i < samples; ++i ) {
|
||||
const int index = int( float(samples) * random(floor(P * 1000.0), i)) % samples;
|
||||
const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r;
|
||||
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
|
||||
void main() {
|
||||
float mip = mipLevel(inUv.xy);
|
||||
vec2 uv = wrap(inUv.xy);
|
||||
vec4 C = vec4(1, 1, 1, 1);
|
||||
vec3 P = inPosition;
|
||||
vec4 A = vec4(1, 1, 1, 1);
|
||||
vec3 N = normalize( inNormal );
|
||||
|
||||
int materialId = int(inId.y);
|
||||
Material material = materials[materialId];
|
||||
const float mip = mipLevel(inUv.xy);
|
||||
const vec2 uv = wrap(inUv.xy);
|
||||
const vec3 P = inPosition;
|
||||
const int materialId = int(inId.y);
|
||||
const Material material = materials[materialId];
|
||||
|
||||
float M = material.factorMetallic;
|
||||
float R = material.factorRoughness;
|
||||
float AO = material.factorOcclusion;
|
||||
|
||||
const float M = material.factorMetallic;
|
||||
const float R = material.factorRoughness;
|
||||
const float AO = 1.0f - material.factorOcclusion;
|
||||
#if 0
|
||||
// sample albedo
|
||||
bool useAtlas = validTextureIndex( material.indexAtlas );
|
||||
const bool useAtlas = validTextureIndex( material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[material.indexAtlas];
|
||||
if ( !validTextureIndex( material.indexAlbedo ) ) discard;
|
||||
{
|
||||
Texture t = textures[material.indexAlbedo];
|
||||
C = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
A = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
// alpha mode OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
C.a = 1;
|
||||
A.a = 1;
|
||||
// alpha mode BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
// alpha mode MASK
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
if ( C.a < abs(material.factorAlphaCutoff) ) discard;
|
||||
C.a = 1;
|
||||
if ( A.a < abs(material.factorAlphaCutoff) ) discard;
|
||||
A.a = 1;
|
||||
}
|
||||
if ( C.a == 0 ) discard;
|
||||
if ( A.a == 0 ) discard;
|
||||
}
|
||||
|
||||
// sample normal
|
||||
@ -248,20 +232,40 @@ void main() {
|
||||
Texture t = textures[material.indexNormal];
|
||||
N = inTBN * normalize( textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ).xyz * 2.0 - vec3(1.0));
|
||||
}
|
||||
#else
|
||||
A = vec4(1);
|
||||
#endif
|
||||
|
||||
C = vec4(1);
|
||||
bool lit = false;
|
||||
float litFactor = 1.0;
|
||||
vec3 fragColor = vec3(0);
|
||||
for ( uint i = 0; i < lights.length(); ++i ) {
|
||||
Light light = lights[i];
|
||||
if ( light.power <= 0.001 ) continue;
|
||||
if ( 0 <= light.mapIndex ) {
|
||||
float factor = shadowFactor( P, light, light.mapIndex, 0.0 );
|
||||
light.power *= factor;
|
||||
{
|
||||
const vec3 F0 = mix(vec3(0.04), A.rgb, M);
|
||||
const vec3 Lo = normalize( -P );
|
||||
const float cosLo = max(0.0, dot(N, Lo));
|
||||
|
||||
for ( uint i = 0; i < lights.length(); ++i ) {
|
||||
const Light light = lights[i];
|
||||
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
|
||||
const vec3 Lp = light.position;
|
||||
const vec3 Liu = light.position - P;
|
||||
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
|
||||
const float Ls = shadowFactor( light, P, 0.0 );
|
||||
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
|
||||
|
||||
const vec3 Li = normalize(Liu);
|
||||
const vec3 Lh = normalize(Li + Lo);
|
||||
const float cosLi = max(0.0, dot(N, Li));
|
||||
const float cosLh = max(0.0, dot(N, Lh));
|
||||
|
||||
const vec3 Lr = light.color.rgb * light.power * La * Ls;
|
||||
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
|
||||
const float D = ndfGGX( cosLh, R );
|
||||
const float G = gaSchlickGGX(cosLi, cosLo, R);
|
||||
const vec3 diffuseBRDF = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb;
|
||||
fragColor.rgb += (diffuseBRDF) * Lr * cosLi;
|
||||
litFactor += light.power * La * Ls;
|
||||
}
|
||||
if ( light.power <= 0.0001 ) continue;
|
||||
pbr( light, C.rgb, M, R, N, P, fragColor );
|
||||
}
|
||||
|
||||
outAlbedo = vec4(fragColor, 1);
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
#version 450
|
||||
|
||||
#define UF_DEFERRED_SAMPLING 0
|
||||
#define UF_CAN_DISCARD 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define CAN_DISCARD 1
|
||||
#define USE_LIGHTMAP 1
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 1;
|
||||
layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES];
|
||||
@ -50,16 +51,17 @@ layout (location = 8) flat in ivec4 inId;
|
||||
|
||||
layout (location = 0) out uvec2 outId;
|
||||
layout (location = 1) out vec2 outNormals;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (location = 2) out vec2 outUvs;
|
||||
#else
|
||||
layout (location = 2) out vec4 outAlbedo;
|
||||
#endif
|
||||
|
||||
#define PI 3.1415926536f
|
||||
|
||||
vec2 encodeNormals( vec3 n ) {
|
||||
// return n.xy / sqrt(n.z*8+8) + 0.5;
|
||||
#define kPI 3.1415926536f
|
||||
return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5;
|
||||
return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5;
|
||||
}
|
||||
float wrap( float i ) {
|
||||
return fract(i);
|
||||
@ -68,24 +70,24 @@ vec2 wrap( vec2 uv ) {
|
||||
return vec2( wrap( uv.x ), wrap( uv.y ) );
|
||||
}
|
||||
float mipLevel( in vec2 uv ) {
|
||||
vec2 dx_vtc = dFdx(uv);
|
||||
vec2 dy_vtc = dFdy(uv);
|
||||
const vec2 dx_vtc = dFdx(uv);
|
||||
const vec2 dy_vtc = dFdy(uv);
|
||||
return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
|
||||
}
|
||||
bool validTextureIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex && textureIndex < textures.length();
|
||||
}
|
||||
void main() {
|
||||
float mip = mipLevel(inUv.xy);
|
||||
vec2 uv = wrap(inUv.xy);
|
||||
vec4 C = vec4(0, 0, 0, 0);
|
||||
vec3 P = inPosition;
|
||||
const float mip = mipLevel(inUv.xy);
|
||||
const vec2 uv = wrap(inUv.xy);
|
||||
const vec3 P = inPosition;
|
||||
vec3 N = inNormal;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
vec4 A = vec4(0, 0, 0, 0);
|
||||
#if DEFERRED_SAMPLING
|
||||
vec4 outAlbedo = vec4(0,0,0,0);
|
||||
#endif
|
||||
#if !UF_DEFERRED_SAMPLING || UF_CAN_DISCARD
|
||||
int materialId = int(inId.y);
|
||||
#if !DEFERRED_SAMPLING || CAN_DISCARD
|
||||
const int materialId = int(inId.y);
|
||||
Material material = materials[materialId];
|
||||
|
||||
float M = material.factorMetallic;
|
||||
@ -93,37 +95,39 @@ void main() {
|
||||
float AO = material.factorOcclusion;
|
||||
|
||||
// sample albedo
|
||||
bool useAtlas = validTextureIndex( material.indexAtlas );
|
||||
const bool useAtlas = validTextureIndex( material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[material.indexAtlas];
|
||||
if ( !validTextureIndex( material.indexAlbedo ) ) discard; {
|
||||
Texture t = textures[material.indexAlbedo];
|
||||
C = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
A = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
// alpha mode OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
C.a = 1;
|
||||
A.a = 1;
|
||||
// alpha mode BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
// alpha mode MASK
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
if ( C.a < abs(material.factorAlphaCutoff) ) discard;
|
||||
C.a = 1;
|
||||
if ( A.a < abs(material.factorAlphaCutoff) ) discard;
|
||||
A.a = 1;
|
||||
}
|
||||
if ( C.a == 0 ) discard;
|
||||
if ( A.a == 0 ) discard;
|
||||
}
|
||||
#if 1
|
||||
#if USE_LIGHTMAP
|
||||
if ( validTextureIndex( material.indexLightmap ) ) {
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
outUvs = inSt;
|
||||
#else
|
||||
Texture t = textures[material.indexLightmap];
|
||||
C *= textureLod( samplerTextures[t.index], inSt, mip );
|
||||
const float gamma = 1.6;
|
||||
const vec4 L = pow(textureLod( samplerTextures[t.index], inSt, mip ), vec4(1.0 / gamma));
|
||||
A *= L;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if !UF_DEFERRED_SAMPLING
|
||||
#if !DEFERRED_SAMPLING
|
||||
// sample normal
|
||||
if ( validTextureIndex( material.indexNormal ) ) {
|
||||
Texture t = textures[material.indexNormal];
|
||||
@ -131,9 +135,9 @@ void main() {
|
||||
}
|
||||
#if 0
|
||||
// sample metallic/roughness
|
||||
if ( validTextureIndex( material.indexNormal ) ) {
|
||||
Texture t = textures[material.indexNormal];
|
||||
vec4 sampled = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
if ( validTextureIndex( material.indexMetallicRoughness ) ) {
|
||||
Texture t = textures[material.indexMetallicRoughness];
|
||||
const vec4 sampled = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
M = sampled.b;
|
||||
R = sampled.g;
|
||||
}
|
||||
@ -144,7 +148,7 @@ void main() {
|
||||
AO = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv ).r;
|
||||
}
|
||||
#endif
|
||||
outAlbedo = C * inColor;
|
||||
outAlbedo = A * inColor;
|
||||
#else
|
||||
outUvs = wrap(inUv.xy);
|
||||
#endif
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
#version 450
|
||||
|
||||
#define UF_DEFERRED_SAMPLING 0
|
||||
#define UF_CAN_DISCARD 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
#define USE_LIGHTMAP 1
|
||||
|
||||
#define PI 3.1415926536f
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 1;
|
||||
|
||||
@ -56,7 +58,7 @@ layout (binding = 11, rgba8) uniform volatile coherent image3D voxelAlbedo;
|
||||
|
||||
layout (location = 0) out uvec2 outId;
|
||||
layout (location = 1) out vec2 outNormals;
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
#if DEFERRED_SAMPLING
|
||||
layout (location = 2) out vec2 outUvs;
|
||||
#else
|
||||
layout (location = 2) out vec4 outAlbedo;
|
||||
@ -64,8 +66,7 @@ layout (location = 1) out vec2 outNormals;
|
||||
|
||||
vec2 encodeNormals( vec3 n ) {
|
||||
// return n.xy / sqrt(n.z*8+8) + 0.5;
|
||||
#define kPI 3.1415926536f
|
||||
return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5;
|
||||
return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5;
|
||||
}
|
||||
float wrap( float i ) {
|
||||
return fract(i);
|
||||
@ -74,8 +75,8 @@ vec2 wrap( vec2 uv ) {
|
||||
return vec2( wrap( uv.x ), wrap( uv.y ) );
|
||||
}
|
||||
float mipLevel( in vec2 uv ) {
|
||||
vec2 dx_vtc = dFdx(uv);
|
||||
vec2 dy_vtc = dFdy(uv);
|
||||
const vec2 dx_vtc = dFdx(uv);
|
||||
const vec2 dy_vtc = dFdy(uv);
|
||||
return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
|
||||
}
|
||||
bool validTextureIndex( int textureIndex ) {
|
||||
@ -83,51 +84,57 @@ bool validTextureIndex( int textureIndex ) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 P = inPosition;
|
||||
const vec3 P = inPosition;
|
||||
if ( !(abs(P.x) < 1.0 && abs(P.y) < 1 && abs(P.z) < 1) ) discard;
|
||||
|
||||
vec4 C = vec4(0, 0, 0, 0);
|
||||
vec3 N = inNormal;
|
||||
vec2 uv = wrap(inUv.xy);
|
||||
float mip = mipLevel(inUv.xy);
|
||||
vec4 A = vec4(0, 0, 0, 0);
|
||||
const vec3 N = inNormal;
|
||||
const vec2 uv = wrap(inUv.xy);
|
||||
const float mip = mipLevel(inUv.xy);
|
||||
const int materialId = int(inId.y);
|
||||
const Material material = materials[materialId];
|
||||
|
||||
int materialId = int(inId.y);
|
||||
Material material = materials[materialId];
|
||||
|
||||
float M = material.factorMetallic;
|
||||
float R = material.factorRoughness;
|
||||
float AO = material.factorOcclusion;
|
||||
const float M = material.factorMetallic;
|
||||
const float R = material.factorRoughness;
|
||||
const float AO = material.factorOcclusion;
|
||||
|
||||
// sample albedo
|
||||
bool useAtlas = validTextureIndex( material.indexAtlas );
|
||||
const bool useAtlas = validTextureIndex( material.indexAtlas );
|
||||
Texture textureAtlas;
|
||||
if ( useAtlas ) textureAtlas = textures[material.indexAtlas];
|
||||
if ( !validTextureIndex( material.indexAlbedo ) ) discard; {
|
||||
Texture t = textures[material.indexAlbedo];
|
||||
C = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
A = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip );
|
||||
// alpha mode OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
C.a = 1;
|
||||
A.a = 1;
|
||||
// alpha mode BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
|
||||
// alpha mode MASK
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
if ( C.a < abs(material.factorAlphaCutoff) ) discard;
|
||||
C.a = 1;
|
||||
if ( A.a < abs(material.factorAlphaCutoff) ) discard;
|
||||
A.a = 1;
|
||||
}
|
||||
if ( C.a == 0 ) discard;
|
||||
if ( A.a == 0 ) discard;
|
||||
}
|
||||
#if USE_LIGHTMAP
|
||||
if ( validTextureIndex( material.indexLightmap ) ) {
|
||||
#if DEFERRED_SAMPLING
|
||||
outUvs = inSt;
|
||||
#else
|
||||
Texture t = textures[material.indexLightmap];
|
||||
const float gamma = 1.6;
|
||||
const vec4 L = pow(textureLod( samplerTextures[t.index], inSt, mip ), vec4(1.0 / gamma));
|
||||
A *= L;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UF_DEFERRED_SAMPLING
|
||||
vec4 outAlbedo;
|
||||
#else
|
||||
vec2 outUvs;
|
||||
#endif
|
||||
/*vec4*/ outAlbedo = C * inColor;
|
||||
/*uvec2*/ outId = uvec2(inId.w+1, inId.y+1);
|
||||
/*vec2*/ outNormals = encodeNormals( normalize( N ) );
|
||||
/*vec2*/ outUvs = wrap(inUv.xy);
|
||||
|
||||
const vec4 outAlbedo = A * inColor;
|
||||
const uvec2 outId = uvec2(inId.w+1, inId.y+1);
|
||||
const vec2 outNormals = encodeNormals( normalize( N ) );
|
||||
const vec2 outUvs = wrap(inUv.xy);
|
||||
|
||||
imageStore(voxelID, ivec3(P * imageSize(voxelID)), uvec4(outId, 0, 0));
|
||||
imageStore(voxelNormal, ivec3(P * imageSize(voxelNormal)), vec4(outNormals, 0, 0));
|
||||
|
||||
@ -22,7 +22,11 @@ namespace uf {
|
||||
ext::json::Value payload;
|
||||
double timeout;
|
||||
};
|
||||
|
||||
struct {
|
||||
size_t mtime = 0;
|
||||
bool enabled = false;
|
||||
std::string source = "";
|
||||
} hotReload;
|
||||
struct {
|
||||
std::unordered_map<std::string, std::vector<size_t>> bound;
|
||||
std::vector<Queued> queue;
|
||||
|
||||
@ -175,20 +175,19 @@ void uf::ObjectBehavior::destroy( uf::Object& self ) {
|
||||
void uf::ObjectBehavior::tick( uf::Object& self ) {
|
||||
// listen for metadata file changes
|
||||
#if UF_ENTITY_METADATA_USE_JSON
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
auto& metadataJson = this->getComponent<uf::Serializer>();
|
||||
#if !UF_ENV_DREAMCAST
|
||||
if ( metadata["system"]["hot reload"]["enabled"].as<bool>() ) {
|
||||
size_t mtime = uf::io::mtime( metadata["system"]["source"].as<std::string>() );
|
||||
if ( metadata["system"]["hot reload"]["mtime"].as<size_t>() < mtime ) {
|
||||
std::cout << "File reload detected: " << ": " << metadata["system"]["source"].as<std::string>() << ", " << metadata["system"]["hot reload"]["mtime"] << " -> " << mtime << std::endl;
|
||||
metadata["system"]["hot reload"]["mtime"] = mtime;
|
||||
if ( metadataJson["system"]["hot reload"]["enabled"].as<bool>() ) {
|
||||
size_t mtime = uf::io::mtime( metadataJson["system"]["source"].as<std::string>() );
|
||||
if ( metadataJson["system"]["hot reload"]["mtime"].as<size_t>() < mtime ) {
|
||||
metadataJson["system"]["hot reload"]["mtime"] = mtime;
|
||||
this->reload();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Call queued hooks
|
||||
{
|
||||
auto& queue = metadata["system"]["hooks"]["queue"];
|
||||
auto& queue = metadataJson["system"]["hooks"]["queue"];
|
||||
if ( !uf::Object::timer.running() ) uf::Object::timer.start();
|
||||
float curTime = uf::Object::timer.elapsed().asDouble();
|
||||
uf::Serializer newQueue = ext::json::array();
|
||||
@ -202,11 +201,18 @@ void uf::ObjectBehavior::tick( uf::Object& self ) {
|
||||
else newQueue.emplace_back(member);
|
||||
});
|
||||
}
|
||||
if ( ext::json::isObject( metadata ) ) queue = newQueue;
|
||||
if ( ext::json::isObject( metadataJson ) ) queue = newQueue;
|
||||
}
|
||||
#else
|
||||
|
||||
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
|
||||
if ( metadata.hotReload.enabled ) {
|
||||
size_t mtime = uf::io::mtime( metadata.hotReload.source );
|
||||
if ( metadata.hotReload.mtime < mtime ) {
|
||||
metadata.hotReload.mtime = mtime;
|
||||
this->reload();
|
||||
}
|
||||
}
|
||||
|
||||
auto& queue = metadata.hooks.queue;
|
||||
if ( !uf::Object::timer.running() ) uf::Object::timer.start();
|
||||
float curTime = uf::Object::timer.elapsed().asDouble();
|
||||
|
||||
@ -129,8 +129,8 @@ void uf::GltfBehavior::tick( uf::Object& self ) {
|
||||
auto& storageBuffer = *graphic.getStorageBuffer("Models");
|
||||
graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex /*storageBuffer*/ );
|
||||
}
|
||||
if ( graphic.material.hasShader("geometry", "svogi") ) {
|
||||
auto& shader = graphic.material.getShader("geometry", "svogi");
|
||||
if ( graphic.material.hasShader("geometry", "vxgi") ) {
|
||||
auto& shader = graphic.material.getShader("geometry", "vxgi");
|
||||
pod::Vector3f min = uf::vector::decode( graph.metadata["extents"]["min"], pod::Vector3f{} );
|
||||
pod::Vector3f max = uf::vector::decode( graph.metadata["extents"]["max"], pod::Vector3f{} );
|
||||
|
||||
|
||||
@ -93,7 +93,13 @@ bool uf::Object::load( const std::string& f, bool inheritRoot ) {
|
||||
|
||||
json["root"] = uf::io::directory(filename);
|
||||
json["source"] = filename;
|
||||
#if UF_ENTITY_METADATA_USE_JSON
|
||||
json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10;
|
||||
#else
|
||||
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
|
||||
metadata.hotReload.source = filename;
|
||||
metadata.hotReload.mtime = uf::io::mtime(filename) + 10;
|
||||
#endif
|
||||
return this->load(json);
|
||||
}
|
||||
|
||||
@ -118,7 +124,7 @@ bool uf::Object::reload( bool hard ) {
|
||||
transform.reference = reference;
|
||||
}
|
||||
payload["new"] = metadata;
|
||||
UF_DEBUG_MSG("Updated metadata for " << uf::string::toString( this ));
|
||||
// UF_DEBUG_MSG("Updated metadata for " << uf::string::toString( this ));
|
||||
this->queueHook("object:Reload.%UID%", payload);
|
||||
return true;
|
||||
}
|
||||
@ -160,7 +166,14 @@ bool uf::Object::load( const uf::Serializer& _json ) {
|
||||
if ( ext::json::isNull( json[key] ) )
|
||||
json[key] = value;
|
||||
});
|
||||
#if UF_ENTITY_METADATA_USE_JSON
|
||||
json["hot reload"]["enabled"] = json["system"]["hot reload"]["enabled"];
|
||||
#else
|
||||
{
|
||||
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
|
||||
metadata.hotReload.enabled = json["system"]["hot reload"]["enabled"].as<bool>();
|
||||
}
|
||||
#endif
|
||||
// Basic entity information
|
||||
// Set name
|
||||
this->m_name = json["name"].is<std::string>() ? json["name"].as<std::string>() : json["type"].as<std::string>();
|
||||
@ -325,7 +338,14 @@ bool uf::Object::load( const uf::Serializer& _json ) {
|
||||
|
||||
json["root"] = uf::io::directory(filename);
|
||||
json["source"] = filename;
|
||||
json["hot reload"]["mtime"] = uf::io::mtime( filename ) + 10;
|
||||
#if UF_ENTITY_METADATA_USE_JSON
|
||||
json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10;
|
||||
#else
|
||||
{
|
||||
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
|
||||
metadata.hotReload.mtime = uf::io::mtime(filename) + 10;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( this->loadChildUid(json) == -1 ) continue;
|
||||
}
|
||||
@ -363,7 +383,15 @@ uf::Object& uf::Object::loadChild( const std::string& f, bool initialize ) {
|
||||
|
||||
json["root"] = uf::io::directory(filename);
|
||||
json["source"] = filename;
|
||||
json["hot reload"]["mtime"] = uf::io::mtime( filename ) + 10;
|
||||
#if UF_ENTITY_METADATA_USE_JSON
|
||||
json["hot reload"]["mtime"] = uf::io::mtime(filename) + 10;
|
||||
#else
|
||||
{
|
||||
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
|
||||
metadata.hotReload.mtime = uf::io::mtime(filename) + 10;
|
||||
}
|
||||
#endif
|
||||
|
||||
return this->loadChild(json, initialize);
|
||||
}
|
||||
uf::Object& uf::Object::loadChild( const uf::Serializer& _json, bool initialize ) {
|
||||
|
||||
@ -54,7 +54,7 @@ uf::Scene& uf::scene::loadScene( const std::string& name, const std::string& fil
|
||||
*/
|
||||
target = uf::string::lowercase( target );
|
||||
scene->load(filename != "" ? filename : "./scenes/" + target + "/scene.json");
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) {
|
||||
uf::instantiator::bind( "VoxelizerBehavior", *scene );
|
||||
}
|
||||
scene->initialize();
|
||||
@ -64,7 +64,7 @@ uf::Scene& uf::scene::loadScene( const std::string& name, const uf::Serializer&
|
||||
uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene;
|
||||
uf::scene::scenes.emplace_back( scene );
|
||||
if ( data != "" ) scene->load(data);
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) {
|
||||
uf::instantiator::bind( "VoxelizerBehavior", *scene );
|
||||
}
|
||||
scene->initialize();
|
||||
|
||||
@ -68,8 +68,8 @@ namespace {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// svogi pipeline
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
|
||||
// vxgi pipeline
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) {
|
||||
std::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as<std::string>("/gltf/base.vert.spv");
|
||||
std::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as<std::string>("/gltf/voxelize.geom.spv");
|
||||
std::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as<std::string>("/gltf/voxelize.frag.spv");
|
||||
@ -79,21 +79,21 @@ namespace {
|
||||
vertexShaderFilename = graph.metadata["flags"]["SKINNED"].as<bool>() ? "/gltf/skinned.instanced.vert.spv" : "/gltf/instanced.vert.spv";
|
||||
} else if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) vertexShaderFilename = "/gltf/skinned.vert.spv";
|
||||
vertexShaderFilename = entity.grabURI( vertexShaderFilename, root );
|
||||
graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "svogi");
|
||||
graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "vxgi");
|
||||
}
|
||||
*/
|
||||
if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) {
|
||||
geometryShaderFilename = entity.grabURI( geometryShaderFilename, root );
|
||||
graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY, "svogi");
|
||||
graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY, "vxgi");
|
||||
}
|
||||
{
|
||||
fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root );
|
||||
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "svogi");
|
||||
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "vxgi");
|
||||
}
|
||||
#if UF_USE_VULKAN
|
||||
/*
|
||||
{
|
||||
auto& shader = graphic.material.getShader("vertex", "svogi");
|
||||
auto& shader = graphic.material.getShader("vertex", "vxgi");
|
||||
struct SpecializationConstant {
|
||||
uint32_t passes = 6;
|
||||
};
|
||||
@ -106,7 +106,7 @@ namespace {
|
||||
*/
|
||||
/*
|
||||
if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) {
|
||||
auto& shader = graphic.material.getShader("geometry", "svogi");
|
||||
auto& shader = graphic.material.getShader("geometry", "vxgi");
|
||||
pod::Vector3f min = uf::vector::decode( graph.metadata["extents"]["min"], pod::Vector3f{} );
|
||||
pod::Vector3f max = uf::vector::decode( graph.metadata["extents"]["max"], pod::Vector3f{} );
|
||||
|
||||
@ -121,7 +121,7 @@ namespace {
|
||||
}
|
||||
*/
|
||||
{
|
||||
auto& shader = graphic.material.getShader("fragment", "svogi");
|
||||
auto& shader = graphic.material.getShader("fragment", "vxgi");
|
||||
struct SpecializationConstant {
|
||||
uint32_t textures = 1;
|
||||
};
|
||||
@ -164,7 +164,7 @@ namespace {
|
||||
graphic.material.samplers.emplace_back( sampler );
|
||||
}
|
||||
// bind scene's voxel texture
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& sceneTextures = scene.getComponent<pod::SceneTextures>();
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id);
|
||||
|
||||
@ -198,10 +198,10 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
|
||||
blitter.initialize( this->getName() );
|
||||
blitter.initializeMesh( mesh );
|
||||
if ( ext::vulkan::settings::experimental::deferredMode == "svogi" ) {
|
||||
if ( ext::vulkan::settings::experimental::deferredMode == "vxgi" ) {
|
||||
blitter.material.initializeShaders({
|
||||
{uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
|
||||
{uf::io::root+"/shaders/display/subpass.svogi.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
|
||||
{uf::io::root+"/shaders/display/subpass.vxgi.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
|
||||
});
|
||||
} else {
|
||||
blitter.material.initializeShaders({
|
||||
|
||||
@ -37,10 +37,10 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD
|
||||
descriptor.parse(metadata["descriptor"]);
|
||||
std::string type = metadata["type"].as<std::string>();
|
||||
std::string target = metadata["target"].as<std::string>();
|
||||
if ( pass == 0 && type == "svogi" ) {
|
||||
if ( pass == 0 && type == "vxgi" ) {
|
||||
descriptor.cullMode = VK_CULL_MODE_NONE;
|
||||
descriptor.depth.test = false;
|
||||
descriptor.pipeline = "svogi";
|
||||
descriptor.pipeline = "vxgi";
|
||||
} else if ( type == "depth" ) {
|
||||
descriptor.cullMode = VK_CULL_MODE_NONE;
|
||||
}
|
||||
@ -63,7 +63,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
if ( subpasses == 0 ) subpasses = 1;
|
||||
renderTarget.device = &device;
|
||||
for ( size_t currentPass = 0; currentPass < subpasses; ++currentPass ) {
|
||||
if ( type == "depth" /*|| type == "svogi"*/ ) {
|
||||
if ( type == "depth" || type == "vxgi" ) {
|
||||
struct {
|
||||
size_t depth;
|
||||
} attachments;
|
||||
@ -341,7 +341,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
{uf::io::root+"/shaders/display/renderTarget.frag.spv", ext::vulkan::enums::Shader::FRAGMENT}
|
||||
});
|
||||
}
|
||||
if ( metadata["type"].as<std::string>() == "svogi" ) {
|
||||
if ( metadata["type"].as<std::string>() == "vxgi" ) {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
|
||||
auto& shader = blitter.material.getShader("compute");
|
||||
@ -409,7 +409,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
|
||||
void ext::vulkan::RenderTargetRenderMode::tick() {
|
||||
ext::vulkan::RenderMode::tick();
|
||||
if ( metadata["type"].as<std::string>() == "svogi" ) {
|
||||
if ( metadata["type"].as<std::string>() == "vxgi" ) {
|
||||
if ( ext::vulkan::states::resized ) {
|
||||
renderTarget.initialize( *renderTarget.device );
|
||||
if ( blitter.process ) blitter.getPipeline().update( blitter );
|
||||
|
||||
@ -154,9 +154,10 @@ void ext::LightBehavior::tick( uf::Object& self ) {
|
||||
metadata.type = metadataJson["light"]["type"].as<size_t>();
|
||||
} else if ( metadataJson["light"]["type"].is<std::string>() ) {
|
||||
std::string lightType = metadataJson["light"]["type"].as<std::string>();
|
||||
if ( lightType == "point" ) metadata.type = 0;
|
||||
else if ( lightType == "spot" ) metadata.type = 1;
|
||||
if ( lightType == "point" ) metadata.type = 1;
|
||||
else if ( lightType == "spot" ) metadata.type = 2;
|
||||
}
|
||||
if ( metadataJson["light"]["dynamic"].as<bool>() ) metadata.type = -metadata.type;
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
@ -223,7 +224,7 @@ void ext::LightBehavior::tick( uf::Object& self ) {
|
||||
if ( !metadata.renderer.external ) {
|
||||
auto& camera = this->getComponent<uf::Camera>();
|
||||
// omni light
|
||||
if ( metadata.shadows && metadata.type == 0 ) {
|
||||
if ( metadata.shadows && std::abs(metadata.type) == 1 ) {
|
||||
auto transform = camera.getTransform();
|
||||
std::vector<pod::Quaternion<>> rotations = {
|
||||
uf::quaternion::axisAngle( { 0, 1, 0 }, 0 * 1.57079633 ),
|
||||
|
||||
@ -19,7 +19,7 @@ namespace ext {
|
||||
float power = 0.0f;
|
||||
float bias = 0.0f;
|
||||
bool shadows = false;
|
||||
size_t type = 0;
|
||||
int32_t type = 1;
|
||||
struct {
|
||||
std::string mode = "in-range";
|
||||
float limiter = 0.0f;
|
||||
|
||||
@ -210,6 +210,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
|
||||
metadataJson["light"]["should"] = metadata.light.enabled;
|
||||
metadataJson["light"]["ambient"] = uf::vector::encode( metadata.light.ambient );
|
||||
metadataJson["light"]["specular"] = uf::vector::encode( metadata.light.specular );
|
||||
metadataJson["light"]["exposure"] = metadata.light.exposure;
|
||||
metadataJson["light"]["gamma"] = metadata.light.gamma;
|
||||
metadataJson["light"]["fog"]["color"] = uf::vector::encode( metadata.fog.color );
|
||||
metadataJson["light"]["fog"]["step scale"] = metadata.fog.stepScale;
|
||||
metadataJson["light"]["fog"]["absorbtion"] = metadata.fog.absorbtion;
|
||||
@ -229,6 +231,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
|
||||
metadata.light.updateThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["update threshold"].as<size_t>();
|
||||
metadata.light.ambient = uf::vector::decode( metadataJson["light"]["ambient"], pod::Vector4f{ 1, 1, 1, 1 } );
|
||||
metadata.light.specular = uf::vector::decode( metadataJson["light"]["specular"], pod::Vector4f{ 1, 1, 1, 1 } );
|
||||
metadata.light.exposure = metadataJson["light"]["exposure"].as<float>(1.0f);
|
||||
metadata.light.gamma = metadataJson["light"]["gamma"].as<float>(2.2f);
|
||||
metadata.fog.color = uf::vector::decode( metadataJson["light"]["fog"]["color"], pod::Vector3f{ 1, 1, 1 } );
|
||||
metadata.fog.stepScale = metadataJson["light"]["fog"]["step scale"].as<float>();
|
||||
metadata.fog.absorbtion = metadataJson["light"]["fog"]["absorbtion"].as<float>();
|
||||
@ -238,11 +242,14 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
|
||||
metadata.fog.density.threshold = metadataJson["light"]["fog"]["density"]["threshold"].as<float>();
|
||||
metadata.fog.density.multiplier = metadataJson["light"]["fog"]["density"]["multiplier"].as<float>();
|
||||
metadata.fog.density.scale = metadataJson["light"]["fog"]["density"]["scale"].as<float>();
|
||||
|
||||
UF_DEBUG_MSG( metadata.light.exposure << " | " << metadata.light.gamma );
|
||||
#if UF_USE_OPENGL_FIXED_FUNCTION
|
||||
uf::renderer::states::rebuild = true;
|
||||
#endif
|
||||
};
|
||||
this->addHook( "object:UpdateMetadata.%UID%", metadata.deserialize);
|
||||
this->addHook( "object:Reload.%UID%", metadata.deserialize);
|
||||
metadata.deserialize();
|
||||
}
|
||||
void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
@ -361,6 +368,8 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
if ( !metadata.light.shadowSamples ) metadata.light.shadowSamples = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow samples"].as<size_t>();
|
||||
if ( !metadata.light.shadowThreshold ) metadata.light.shadowThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow threshold"].as<size_t>();
|
||||
if ( !metadata.light.updateThreshold ) metadata.light.updateThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["update threshold"].as<size_t>();
|
||||
if ( !metadata.light.exposure ) metadata.light.exposure = metadataJson["light"]["exposure"].as<float>(1.0f);
|
||||
if ( !metadata.light.gamma ) metadata.light.gamma = metadataJson["light"]["gamma"].as<float>(2.2f);
|
||||
#endif
|
||||
/* Update lights */ if ( metadata.light.enabled ) {
|
||||
ext::ExtSceneBehavior::bindBuffers( *this );
|
||||
@ -477,8 +486,8 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
|
||||
alignas(4) uint32_t msaa;
|
||||
alignas(4) uint32_t poissonSamples;
|
||||
alignas(4) uint32_t padding1;
|
||||
alignas(4) uint32_t padding2;
|
||||
alignas(4) float gamma;
|
||||
alignas(4) float exposure;
|
||||
};
|
||||
struct SpecializationConstant {
|
||||
uint32_t maxTextures = 512;
|
||||
@ -493,7 +502,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
float distance = 0;
|
||||
float bias = 0;
|
||||
bool shadows = false;
|
||||
size_t type = 0;
|
||||
int32_t type = 0;
|
||||
};
|
||||
std::vector<LightInfo> entities;
|
||||
std::vector<pod::Graph*> graphs;
|
||||
@ -561,6 +570,8 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
uniforms->ambient = metadata.light.ambient;
|
||||
uniforms->msaa = ext::vulkan::settings::msaa;
|
||||
uniforms->poissonSamples = shadowSamples;
|
||||
uniforms->exposure = metadata.light.exposure;
|
||||
uniforms->gamma = metadata.light.gamma;
|
||||
|
||||
uniforms->fog.color = metadata.fog.color;
|
||||
uniforms->fog.color.w = metadata.fog.stepScale;
|
||||
@ -586,7 +597,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
for ( auto& texture : graphic.material.textures ) previousTextures.emplace_back(texture.image);
|
||||
|
||||
graphic.material.textures.clear();
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "svogi" ) {
|
||||
if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) {
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id); //this->getComponent<uf::renderer::Texture3D>());
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.normal); //this->getComponent<uf::renderer::Texture3D>());
|
||||
graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.uv); //this->getComponent<uf::renderer::Texture3D>());
|
||||
@ -647,13 +658,13 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re
|
||||
max.z = std::max( max.z, graphMax.z );
|
||||
}
|
||||
|
||||
min.x += floor(controllerTransform.position.x);
|
||||
min.y -= floor(controllerTransform.position.y);
|
||||
min.z -= floor(controllerTransform.position.z);
|
||||
min.x += floor(controllerTransform.position.x );
|
||||
min.y -= floor(controllerTransform.position.y );
|
||||
min.z -= floor(controllerTransform.position.z );
|
||||
|
||||
max.x += floor(controllerTransform.position.x);
|
||||
max.y -= floor(controllerTransform.position.y);
|
||||
max.z -= floor(controllerTransform.position.z);
|
||||
max.x += floor(controllerTransform.position.x );
|
||||
max.y -= floor(controllerTransform.position.y );
|
||||
max.z -= floor(controllerTransform.position.z );
|
||||
|
||||
uniforms->matrices.ortho = /*uf::matrix::translate( uf::matrix::identity(), controllerTransform.position ) **/ uf::matrix::ortho( min.x, max.x, min.y, max.y, min.z, max.z );
|
||||
|
||||
|
||||
@ -27,6 +27,8 @@ namespace ext {
|
||||
size_t updateThreshold = 4;
|
||||
pod::Vector4f ambient = {0,0,0,1};
|
||||
pod::Vector4f specular = {1,1,1,1};
|
||||
float exposure = 1.0f;
|
||||
float gamma = 1.0f;
|
||||
} light;
|
||||
struct {
|
||||
pod::Vector3f color = {1,1,1};
|
||||
|
||||
@ -20,12 +20,18 @@ UF_BEHAVIOR_REGISTER_CPP(ext::VoxelizerBehavior)
|
||||
void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
|
||||
#if UF_USE_VULKAN
|
||||
auto& metadata = this->getComponent<ext::VoxelizerBehavior::Metadata>();
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
|
||||
auto& sceneTextures = this->getComponent<pod::SceneTextures>();
|
||||
// initialize voxel map
|
||||
{
|
||||
if ( metadata.voxelSize.x == 0 ) metadata.voxelSize.x = 256;
|
||||
if ( metadata.voxelSize.y == 0 ) metadata.voxelSize.y = 256;
|
||||
if ( metadata.voxelSize.z == 0 ) metadata.voxelSize.z = 256;
|
||||
const uint32_t DEFAULT_VOXEL_SIZE = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["size"].as<uint32_t>();
|
||||
const float DEFAULT_VOXELIZE_LIMITER = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["limiter"].as<float>();
|
||||
|
||||
if ( metadata.voxelSize.x == 0 ) metadata.voxelSize.x = DEFAULT_VOXEL_SIZE;
|
||||
if ( metadata.voxelSize.y == 0 ) metadata.voxelSize.y = DEFAULT_VOXEL_SIZE;
|
||||
if ( metadata.voxelSize.z == 0 ) metadata.voxelSize.z = DEFAULT_VOXEL_SIZE;
|
||||
if ( metadata.renderer.limiter == 0 ) metadata.renderer.limiter = DEFAULT_VOXELIZE_LIMITER;
|
||||
|
||||
std::vector<uint8_t> empty(metadata.voxelSize.x * metadata.voxelSize.y * metadata.voxelSize.z * sizeof(uint8_t) * 4);
|
||||
|
||||
@ -43,16 +49,16 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) {
|
||||
// if ( metadata.fragmentSize.y == 0 ) metadata.fragmentSize.y = metadata.voxelSize.y * 2;
|
||||
|
||||
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
||||
metadata.renderModeName = "SVOGI:" + std::to_string((int) this->getUid());
|
||||
metadata.renderModeName = "VXGI:" + std::to_string((int) this->getUid());
|
||||
uf::renderer::addRenderMode( &renderMode, metadata.renderModeName );
|
||||
renderMode.metadata["type"] = "svogi";
|
||||
renderMode.metadata["type"] = "vxgi";
|
||||
renderMode.metadata["samples"] = 1;
|
||||
|
||||
renderMode.blitter.device = &ext::vulkan::device;
|
||||
renderMode.width = metadata.fragmentSize.x;
|
||||
renderMode.height = metadata.fragmentSize.y;
|
||||
#if COMP_SHADER_USED
|
||||
renderMode.metadata["shaders"]["compute"] = "/shaders/display/svogi.comp.spv";
|
||||
renderMode.metadata["shaders"]["compute"] = "/shaders/display/vxgi.comp.spv";
|
||||
renderMode.blitter.descriptor.renderMode = metadata.renderModeName;
|
||||
renderMode.blitter.descriptor.subpass = -1;
|
||||
renderMode.blitter.process = true;
|
||||
@ -126,9 +132,18 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) {
|
||||
auto& metadata = this->getComponent<ext::VoxelizerBehavior::Metadata>();
|
||||
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
||||
renderMode.setTarget("");
|
||||
if ( renderMode.executed && !metadata.initialized ) {
|
||||
// renderMode.execute = false;
|
||||
metadata.initialized = true;
|
||||
if ( renderMode.executed ) {
|
||||
if ( !metadata.initialized ) metadata.initialized = true;
|
||||
|
||||
if ( metadata.renderer.limiter > 0 ) {
|
||||
if ( metadata.renderer.timer > metadata.renderer.limiter ) {
|
||||
metadata.renderer.timer = 0;
|
||||
renderMode.execute = true;
|
||||
} else {
|
||||
metadata.renderer.timer = metadata.renderer.timer + uf::physics::time::delta;
|
||||
renderMode.execute = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if COMP_SHADER_USED
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
|
||||
@ -19,12 +19,16 @@ namespace ext {
|
||||
pod::Vector3ui fragmentSize = { 0, 0 };
|
||||
pod::Vector3ui voxelSize = { 256, 256, 256 };
|
||||
pod::Vector3ui dispatchSize = { 8, 8, 8 };
|
||||
std::string renderModeName = "SVOGI";
|
||||
std::string renderModeName = "VXGI";
|
||||
struct {
|
||||
pod::Vector3f min = {};
|
||||
pod::Vector3f max = {};
|
||||
pod::Matrix4f matrix = uf::matrix::identity();
|
||||
} extents;
|
||||
struct {
|
||||
float limiter = 0.0f;
|
||||
float timer = 0.0f;
|
||||
} renderer;
|
||||
bool initialized = false;
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user