diff --git a/bin/data/shaders/display/rendertarget.frag.glsl b/bin/data/shaders/display/rendertarget.frag.glsl index c46eec2a..9a63e7b4 100644 --- a/bin/data/shaders/display/rendertarget.frag.glsl +++ b/bin/data/shaders/display/rendertarget.frag.glsl @@ -2,25 +2,25 @@ #extension GL_EXT_samplerless_texture_functions : require #define MULTISAMPLING 1 -#define UF_DEFERRED_SAMPLING 0 -#define UF_CAN_DISCARD 1 +#define DEFERRED_SAMPLING 0 +#define CAN_DISCARD 1 #if !MULTISAMPLING layout (binding = 1) uniform usampler2D textureId; layout (binding = 2) uniform sampler2D textureNormals; - #if UF_DEFERRED_SAMPLING + #if DEFERRED_SAMPLING layout (binding = 3) uniform sampler2D textureUvs; #else - layout (binding = 3) uniform sampler2D textureAlbedo; - #endif + layout (binding = 3) uniform sampler2D textureAlbedo; + #endif #else layout (binding = 1) uniform usampler2DMS textureId; layout (binding = 2) uniform sampler2DMS textureNormals; - #if UF_DEFERRED_SAMPLING + #if DEFERRED_SAMPLING layout (binding = 3) uniform sampler2DMS textureUvs; #else - layout (binding = 3) uniform sampler2DMS textureAlbedo; - #endif + layout (binding = 3) uniform sampler2DMS textureAlbedo; + #endif #endif struct Cursor { @@ -44,6 +44,7 @@ layout (location = 1) in float inAlpha; layout (location = 2) in Cursor inCursor; layout (location = 0) out vec4 outAlbedo; + void main() { #if !MULTISAMPLING ivec2 screenSize = textureSize(textureId, 0); @@ -53,7 +54,7 @@ void main() { ivec2 uv = ivec2(inUv * screenSize); if ( inCursor.radius.x <= 0 || inCursor.radius.y <= 0 ) { #if !MULTISAMPLING - outAlbedo = texture(textureAlbedo, uv).rgba; + outAlbedo = texture( textureAlbedo, uv ).rgba; #else outAlbedo = resolve( textureAlbedo, uv ); #endif @@ -62,7 +63,7 @@ void main() { float dist = pow(inUv.x - inCursor.position.x, 2) / pow(inCursor.radius.x, 2) + pow(inUv.y - inCursor.position.y, 2) / pow(inCursor.radius.y, 2); #if !MULTISAMPLING - outAlbedo = texture(textureAlbedo, inUv); + outAlbedo = texture( textureAlbedo, inUv ); #else outAlbedo = resolve( textureAlbedo, uv ); #endif diff --git a/bin/data/shaders/display/subpass.frag.glsl b/bin/data/shaders/display/subpass.frag.glsl index 7ab8c66e..6ca182ee 100644 --- a/bin/data/shaders/display/subpass.frag.glsl +++ b/bin/data/shaders/display/subpass.frag.glsl @@ -2,14 +2,25 @@ #extension GL_EXT_samplerless_texture_functions : require #define MULTISAMPLING 1 -#define DEFERRED_SAMPLING 0 -#define RAY_MARCH_FOG 1 +#define DEFERRED_SAMPLING 1 + +#define VXGI_NDC 1 +#define VXGI_SHADOWS 0 +#define VXGI_CASCADES 1 + +#define FOG 1 +#define FOG_RAY_MARCH 1 + +#define WHITENOISE 1 +#define GAMMA_CORRECT 1 +#define TONE_MAP 1 #define LAMBERT 0 #define PBR 1 const float PI = 3.14159265359; const float EPSILON = 0.00001; +const float SQRT2 = 1.41421356237; const float LIGHT_POWER_CUTOFF = 0.005; @@ -40,13 +51,20 @@ struct Matrices { mat4 iView[2]; mat4 iProjection[2]; mat4 iProjectionView[2]; - mat4 ortho; + vec4 eyePos[2]; + mat4 vxgi; +}; + +struct Ray { + vec3 origin; + vec3 direction; + float distance; }; struct Space { vec3 eye; vec3 world; -} position, normal, view; +}; struct Fog { vec3 color; @@ -107,6 +125,7 @@ struct Material { int indexLightmap; int modeAlpha; }; + struct Texture { int index; int samp; @@ -115,6 +134,7 @@ struct Texture { vec4 lerp; }; + struct DrawCall { int materialIndex; uint materials; @@ -122,6 +142,29 @@ struct DrawCall { uint textures; }; +struct SurfaceMaterial { + uint id; + + vec4 albedo; + vec4 indirect; + + float metallic; + float roughness; + float occlusion; +}; + +struct Surface { + vec2 uv; + Space position; + Space normal; + + Ray ray; + + SurfaceMaterial material; + + vec4 fragment; +} surface; + #if !MULTISAMPLING layout (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId; layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal; @@ -144,7 +187,7 @@ struct DrawCall { layout (binding = 4) uniform UBO { Matrices matrices; - + Mode mode; Fog fog; @@ -154,12 +197,12 @@ layout (binding = 4) uniform UBO { uint drawCalls; vec3 ambient; - float kexp; - - uint msaa; - uint poissonSamples; float gamma; + float exposure; + uint msaa; + uint shadowSamples; + uint padding1; } ubo; layout (std140, binding = 5) readonly buffer Lights { @@ -179,7 +222,6 @@ layout (binding = 9) uniform sampler3D samplerNoise; layout (binding = 10) uniform samplerCube samplerSkybox; layout (binding = 11) uniform sampler2D samplerTextures[TEXTURES]; - layout (location = 0) in vec2 inUv; layout (location = 1) in flat uint inPushConstantPass; @@ -239,9 +281,9 @@ vec3 gamma( vec3 i ) { return pow(i.rgb, vec3(1.0 / 2.2)); } -vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) { - const vec3 t0 = (boundsMin - rayO) / rayD; - const vec3 t1 = (boundsMax - rayO) / rayD; +vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) { + const vec3 t0 = (boundsMin - ray.origin) / ray.direction; + const vec3 t1 = (boundsMax - ray.origin) / ray.direction; 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 )); @@ -254,20 +296,20 @@ float sampleDensity( vec3 position ) { return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier; } -void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { +void fog( in Ray ray, inout vec3 i, float scale ) { if ( ubo.fog.stepScale <= 0 ) return; if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return; -#if RAY_MARCH_FOG +#if FOG_RAY_MARCH const float range = ubo.fog.range.y; - const vec3 boundsMin = vec3(-range,-range,-range) + rayO; - const vec3 boundsMax = vec3(range,range,range) + rayO; + const vec3 boundsMin = vec3(-range,-range,-range) + ray.origin; + const vec3 boundsMax = vec3(range,range,range) + ray.origin; const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); - const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD ); + const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, ray ); const float dstToBox = rayBoxInfo.x; const float dstInsideBox = rayBoxInfo.y; - const float depth = position.eye.z; + const float depth = surface.position.eye.z; float lightEnergy = 0; // march @@ -278,7 +320,7 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { float totalDensity = 0; float transmittance = 1; while ( dstTravelled < dstLimit ) { - vec3 rayPos = rayO + rayD * (dstToBox + dstTravelled); + vec3 rayPos = ray.origin + ray.direction * (dstToBox + dstTravelled); float density = sampleDensity(rayPos); if ( density > 0 ) { transmittance *= exp(-density * stepSize * ubo.fog.absorbtion); @@ -293,7 +335,7 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { 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 distance = length(-surface.position.eye); const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 ); i.rgb = mix(i.rgb, color, factor); @@ -304,12 +346,6 @@ vec3 decodeNormals( vec2 enc ) { 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); @@ -347,7 +383,7 @@ uvec4 resolve( usubpassInputMS t ) { 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); + vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); positionClip.xyz /= positionClip.w; if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; @@ -370,21 +406,34 @@ float shadowFactor( const Light light, float def ) { 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; + const int samples = int(ubo.shadowSamples); + 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 int index = int( float(samples) * random(floor(surface.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); - vec3 fragColor = vec3(0); +vec4 postProcess() { +#if FOG + fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); +#endif +#if TONE_MAP + surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * ubo.exposure); +#endif +#if GAMMA_CORRECT + surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / ubo.gamma)); +#endif +#if WHITENOISE + if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) whitenoise(surface.fragment.rgb); +#endif + return vec4(surface.fragment.rgb,1); +} + +void main() { { #if !MULTISAMPLING const float depth = subpassLoad(samplerDepth).r; @@ -394,65 +443,79 @@ void main() { vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0); positionEye /= positionEye.w; - position.eye = positionEye.xyz; - position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye ); + surface.position.eye = positionEye.xyz; + surface.position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye ); } +#if 0 { 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 ); + surface.ray.origin = near3; + surface.ray.direction = normalize( far3 - near3 ); } // 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 ); + surface.ray.direction = normalize( far3 - near3 ); } +#else + { + 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; + + surface.ray.direction = normalize( far3 - near3 ); + surface.ray.origin = ubo.matrices.eyePos[inPushConstantPass].xyz; + } +#endif #if !MULTISAMPLING - normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); + surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); const uvec2 ID = subpassLoad(samplerId).xy; #else - normal.world = decodeNormals( resolve(samplerNormal).xy ); + surface.normal.world = decodeNormals( resolve(samplerNormal).xy ); const uvec2 ID = resolve(samplerId).xy; #endif - normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) ); + surface.normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(surface.normal.world, 0.0) ); if ( ID.x == 0 || ID.y == 0 ) { - fragColor.rgb = texture( samplerSkybox, rayD ).rgb; - fog(rayO, rayD, fragColor, 0.0); - outFragColor = vec4(fragColor,1); + surface.fragment.rgb = texture( samplerSkybox, surface.ray.direction ).rgb; + surface.fragment.a = 0.0; + outFragColor = postProcess(); return; } 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; + surface.material.id = ID.y + drawCall.materialIndex - 1; + const Material material = materials[surface.material.id]; + surface.material.albedo = material.colorBase; + surface.fragment = material.colorEmissive; #if DEFERRED_SAMPLING #if !MULTISAMPLING - const vec2 uv = subpassLoad(samplerUv).xy; + surface.uv = subpassLoad(samplerUv).xy; #else - const vec2 uv = resolve(samplerUv).xy; + surface.uv = resolve(samplerUv).xy; #endif 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]; - A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + if ( validTextureIndex( drawCall.textureIndex + material.indexAlbedo ) ) { + const Texture t = textures[drawCall.textureIndex + material.indexAlbedo]; + surface.material.albedo = textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); } // OPAQUE if ( material.modeAlpha == 0 ) { - A.a = 1; + surface.material.albedo.a = 1; // BLEND } else if ( material.modeAlpha == 1 ) { @@ -460,83 +523,72 @@ void main() { } else if ( material.modeAlpha == 2 ) { } + // Emissive textures + if ( validTextureIndex( drawCall.textureIndex + material.indexEmissive ) ) { + const Texture t = textures[drawCall.textureIndex + material.indexEmissive]; + surface.fragment += textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); + } #else #if !MULTISAMPLING - A = subpassLoad(samplerAlbedo); + surface.material.albedo = subpassLoad(samplerAlbedo); #else - A = resolve(samplerAlbedo); + surface.material.albedo = resolve(samplerAlbedo); #endif #endif - const float M = material.factorMetallic; - const float R = material.factorRoughness; - const float AO = 1.0f - material.factorOcclusion; + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; - float litFactor = 1.0; if ( 0 <= material.indexLightmap ) { - fragColor = A.rgb + ubo.ambient.rgb * (1 - AO); + surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion; } else { - fragColor = A.rgb * ubo.ambient.rgb * (1 - AO); + surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion; } - { - 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)); + // corrections + surface.material.roughness *= 4.0; + { + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize( -surface.position.eye ); + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); + for ( uint i = 0; i < ubo.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 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - surface.position.eye; const vec3 Li = normalize(Liu); + #if VXGI_SHADOWS + const float Ls = i < ubo.shadowSamples ? shadowFactor( light, 0.0 ) : 1.0; + #else const float Ls = shadowFactor( light, 0.0 ); + #endif 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 float cosLi = max(0.0, dot(surface.normal.eye, Li)); const vec3 Lr = light.color.rgb * light.power * La * Ls; #if LAMBERT - const vec3 diffuse = A.rgb; + const vec3 diffuse = surface.material.albedo.rgb; const vec3 specular = vec3(0); #elif PBR const vec3 Lh = normalize(Li + Lo); - const float cosLh = max(0.0, dot(N, Lh)); + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); 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 diffuse = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb; + const float D = ndfGGX( cosLh, surface.material.roughness ); + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); + const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); #endif // lightmapped, compute only specular - if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specular) * Lr * cosLi; + if ( light.type >= 0 && 0 <= material.indexLightmap ) surface.fragment.rgb += (specular) * Lr * cosLi; // point light, compute only diffuse - // else if ( abs(light.type) == 1 ) fragColor.rgb += (diffuse) * Lr * cosLi; - else fragColor.rgb += (diffuse + specular) * Lr * cosLi; - litFactor += light.power * La * Ls; + // else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi; + else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; + surface.fragment.a += light.power * La * Ls; } } - 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) ) { - //dither1(fragColor); - fragColor += dither2(); - } -*/ - if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) { - whitenoise(fragColor); - } - - outFragColor = vec4(fragColor,1); + outFragColor = postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.vxgi.frag.glsl b/bin/data/shaders/display/subpass.vxgi.frag.glsl index b724877f..2f70696b 100644 --- a/bin/data/shaders/display/subpass.vxgi.frag.glsl +++ b/bin/data/shaders/display/subpass.vxgi.frag.glsl @@ -2,13 +2,15 @@ #extension GL_EXT_samplerless_texture_functions : require #define MULTISAMPLING 1 -#define FOG 1 -#define RAY_MARCH_FOG 1 -#define WHITENOISE 1 -#define DEFERRED_SAMPLING 0 -#define SHADOW_CONE_TRACED 0 -#define VOXEL_TRACE_IN_NDC 1 +#define DEFERRED_SAMPLING 1 +#define VXGI_NDC 0 +#define VXGI_SHADOWS 1 + +#define FOG 1 +#define FOG_RAY_MARCH 1 + +#define WHITENOISE 1 #define GAMMA_CORRECT 1 #define TONE_MAP 1 @@ -41,6 +43,7 @@ const vec2 poissonDisk[16] = vec2[]( ); layout (constant_id = 0) const uint TEXTURES = 256; +layout (constant_id = 1) const uint CASCADES = 1; struct Matrices { mat4 view[2]; @@ -48,13 +51,22 @@ struct Matrices { mat4 iView[2]; mat4 iProjection[2]; mat4 iProjectionView[2]; - mat4 voxel; + vec4 eyePos[2]; + mat4 vxgi; +}; + +struct Ray { + vec3 origin; + vec3 direction; + + vec3 position; + float distance; }; struct Space { vec3 eye; vec3 world; -} position, normal, view; +}; struct Fog { vec3 color; @@ -115,6 +127,7 @@ struct Material { int indexLightmap; int modeAlpha; }; + struct Texture { int index; int samp; @@ -123,12 +136,37 @@ struct Texture { vec4 lerp; }; + struct DrawCall { int materialIndex; uint materials; int textureIndex; uint textures; }; + +struct SurfaceMaterial { + uint id; + + vec4 albedo; + vec4 indirect; + + float metallic; + float roughness; + float occlusion; +}; + +struct Surface { + vec2 uv; + Space position; + Space normal; + + Ray ray; + + SurfaceMaterial material; + + vec4 fragment; +} surface; + struct Voxel { uvec2 id; vec3 position; @@ -169,12 +207,12 @@ layout (binding = 4) uniform UBO { uint drawCalls; vec3 ambient; - float kexp; - - uint msaa; - uint poissonSamples; float gamma; + float exposure; + uint msaa; + uint shadowSamples; + uint padding1; } ubo; layout (std140, binding = 5) readonly buffer Lights { @@ -190,10 +228,10 @@ layout (std140, binding = 8) readonly buffer DrawCalls { DrawCall drawCalls[]; }; -layout (binding = 9) uniform usampler3D voxelId; -layout (binding = 10) uniform sampler3D voxelNormal; -layout (binding = 11) uniform sampler3D voxelUv; -layout (binding = 12) uniform sampler3D voxelAlbedo; +layout (binding = 9) uniform usampler3D voxelId[CASCADES]; +layout (binding = 10) uniform sampler3D voxelUv[CASCADES]; +layout (binding = 11) uniform sampler3D voxelNormal[CASCADES]; +layout (binding = 12) uniform sampler3D voxelRadiance[CASCADES]; layout (binding = 13) uniform sampler3D samplerNoise; layout (binding = 14) uniform samplerCube samplerSkybox; @@ -258,9 +296,9 @@ vec3 gamma( vec3 i ) { return pow(i.rgb, vec3(1.0 / 2.2)); } -vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayO, vec3 rayD ) { - const vec3 t0 = (boundsMin - rayO) / rayD; - const vec3 t1 = (boundsMax - rayO) / rayD; +vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) { + const vec3 t0 = (boundsMin - ray.origin) / ray.direction; + const vec3 t1 = (boundsMax - ray.origin) / ray.direction; 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 )); @@ -273,20 +311,20 @@ float sampleDensity( vec3 position ) { return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier; } -void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { +void fog( in Ray ray, inout vec3 i, float scale ) { if ( ubo.fog.stepScale <= 0 ) return; if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return; -#if RAY_MARCH_FOG +#if FOG_RAY_MARCH const float range = ubo.fog.range.y; - const vec3 boundsMin = vec3(-range,-range,-range) + rayO; - const vec3 boundsMax = vec3(range,range,range) + rayO; + const vec3 boundsMin = vec3(-range,-range,-range) + ray.origin; + const vec3 boundsMax = vec3(range,range,range) + ray.origin; const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); - const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayO, rayD ); + const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, ray ); const float dstToBox = rayBoxInfo.x; const float dstInsideBox = rayBoxInfo.y; - const float depth = position.eye.z; + const float depth = surface.position.eye.z; float lightEnergy = 0; // march @@ -297,7 +335,7 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { float totalDensity = 0; float transmittance = 1; while ( dstTravelled < dstLimit ) { - vec3 rayPos = rayO + rayD * (dstToBox + dstTravelled); + vec3 rayPos = ray.origin + ray.direction * (dstToBox + dstTravelled); float density = sampleDensity(rayPos); if ( density > 0 ) { transmittance *= exp(-density * stepSize * ubo.fog.absorbtion); @@ -312,7 +350,7 @@ void fog( vec3 rayO, vec3 rayD, inout vec3 i, float scale ) { 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 distance = length(-surface.position.eye); const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 ); i.rgb = mix(i.rgb, color, factor); @@ -323,12 +361,6 @@ vec3 decodeNormals( vec2 enc ) { 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); @@ -363,10 +395,11 @@ uvec4 resolve( usubpassInputMS t ) { return resolved; } +#if !VXGI_SHADOWS 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); + vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); positionClip.xyz /= positionClip.w; if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; @@ -389,25 +422,43 @@ float shadowFactor( const Light light, float def ) { 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; + const int samples = int(ubo.shadowSamples); + 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 int index = int( float(samples) * random(floor(surface.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; } +#endif + +vec4 postProcess() { +#if FOG + fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); +#endif +#if TONE_MAP + surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * ubo.exposure); +#endif +#if GAMMA_CORRECT + surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / ubo.gamma)); +#endif +#if WHITENOISE + if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) whitenoise(surface.fragment.rgb); +#endif + + return vec4(surface.fragment.rgb,1); +} Voxel getVoxel( vec3 P ) { - const vec3 uvw = vec3( ubo.matrices.voxel * vec4( P, 1.0f ) ) * 0.5f + 0.5f; + const vec3 uvw = vec3( ubo.matrices.vxgi * vec4( P, 1.0f ) ) * 0.5f + 0.5f; Voxel voxel; - voxel.id = uvec2(texture(voxelId, uvw).xy); + voxel.id = uvec2(texture(voxelId[0], uvw).xy); voxel.position = P; - voxel.normal = decodeNormals( texture(voxelNormal, uvw).xy ); - voxel.uv = texture(voxelUv, uvw).xy; - voxel.color = texture(voxelAlbedo, uvw).rgba; + voxel.normal = decodeNormals( texture(voxelNormal[0], uvw).xy ); + voxel.uv = texture(voxelUv[0], uvw).xy; + voxel.color = texture(voxelRadiance[0], uvw).rgba; return voxel; } @@ -417,76 +468,88 @@ struct VoxelInfo { vec3 max; float mipmapLevels; - float albedoSize; + float radianceSize; float voxelSize; - float albedoSizeRecip; + float radianceSizeRecip; float voxelSizeRecip; -}; -VoxelInfo 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 ) ); - const float granularity = 1.0f / 8.0f; - const uint maxSteps = uint(voxelInfo.albedoSize * 2); +vec4 voxelTrace( inout Ray ray, float aperture, float maxDistance ) { +#if VXGI_NDC + ray.origin = vec3( ubo.matrices.vxgi * vec4( ray.origin, 1.0 ) ); + ray.direction = vec3( ubo.matrices.vxgi * vec4( ray.direction, 0.0 ) ); + const float granularity = 1.0f / 16.0f; + const uint maxSteps = uint(voxelInfo.radianceSize * 2); #else - const float granularity = 8.0f; - const uint maxSteps = uint(voxelInfo.albedoSize * granularity); + const float granularity = 10.0f; + const uint maxSteps = uint(voxelInfo.radianceSize * granularity); #endif const float granularityRecip = 1.0f / granularity; // box - const vec2 rayBoxInfo = rayBoxDst( voxelInfo.min, voxelInfo.max, rayO, rayD ); + const vec2 rayBoxInfo = rayBoxDst( voxelInfo.min, voxelInfo.max, ray ); const float tStart = rayBoxInfo.x; const float tEnd = maxDistance > 0 ? min(maxDistance, rayBoxInfo.y) : rayBoxInfo.y; // steps const float tDelta = voxelInfo.voxelSize * granularityRecip; // marcher - float t = tStart + 2.0 * SQRT2; - vec3 rayPos = vec3(0); + ray.distance = tStart + tDelta * granularity; + ray.position = vec3(0); vec4 radiance = vec4(0); vec3 uvw = vec3(0); // cone mipmap shit const float coneCoefficient = 2.0 * tan(aperture * 0.5); - float coneDiameter = coneCoefficient * t; + float coneDiameter = coneCoefficient * ray.distance; float level = aperture > 0 ? log2( coneDiameter ) : 0; // results vec4 color = vec4(0); float occlusion = 0.0; uint stepCounter = 0; - float tD; - const float falloff = 256.0f; + const float falloff = 32.0f; // maxDistance > 0.0 ? 0.0f : 256.0f; const vec3 voxelBoundsRecip = 1.0f / (voxelInfo.max - voxelInfo.min); -// while ( t < tEnd && color.a < 1.0 && occlusion < 1.0 && stepCounter++ < maxSteps ) { - while ( t < tEnd && color.a < 1.0 && occlusion < 1.0 ) { - t += tDelta * (aperture > 0 ? coneDiameter : 1); - rayPos = rayO + rayD * t; - #if VOXEL_TRACE_IN_NDC - uvw = rayPos * 0.5 + 0.5; +// while ( ray.distance < tEnd && color.a < 1.0 && occlusion < 1.0 && stepCounter++ < maxSteps ) { + while ( ray.distance < tEnd && color.a < 1.0 && occlusion < 1.0 ) { + ray.distance += tDelta * (aperture > 0 ? coneDiameter : 1); + ray.position = ray.origin + ray.direction * ray.distance; + #if VXGI_NDC + uvw = ray.position * 0.5 + 0.5; #else - uvw = (rayPos - voxelInfo.min) * voxelBoundsRecip; + uvw = (ray.position - voxelInfo.min) * voxelBoundsRecip; #endif if ( abs(uvw.x) > 1.0 || abs(uvw.y) > 1.0 || abs(uvw.z) > 1.0 ) break; - coneDiameter = coneCoefficient * t; + coneDiameter = coneCoefficient * ray.distance; level = log2( coneDiameter ); if ( level >= voxelInfo.mipmapLevels ) break; - radiance = texture(voxelAlbedo, uvw, level); + radiance = textureLod(voxelRadiance[0], uvw.xzy, level); color += (1.0 - color.a) * radiance; occlusion += ((1.0f - occlusion) * radiance.a) / (1.0f + falloff * coneDiameter); } - return vec4(color.rgb, occlusion); + return maxDistance > 0 ? color : vec4(color.rgb, occlusion); +// return vec4(color.rgb, occlusion); } -vec4 voxelConeTrace( vec3 rayO, vec3 rayD, float aperture ) { - return voxelConeTrace( rayO, rayD, aperture, 0 ); +vec4 voxelConeTrace( inout Ray ray, float aperture ) { + return voxelTrace( ray, aperture, 0 ); } +vec4 voxelTrace( inout Ray ray, float maxDistance ) { + return voxelTrace( ray, 0, maxDistance ); +} + +#if VXGI_SHADOWS +float shadowFactor( const Light light, float def ) { + const float SHADOW_APERTURE = 0.2; + const float DEPTH_BIAS = 0.0; + + Ray ray; + ray.origin = surface.position.world; + ray.direction = normalize( light.position - surface.position.world ); + ray.origin -= ray.direction * 0.5; + float z = distance( surface.position.world, light.position ) - DEPTH_BIAS; + return 1.0 - voxelTrace( ray, SHADOW_APERTURE, z ).a; +} +#endif void main() { - vec3 rayO = vec3(0); - vec3 rayD = vec3(0); - vec3 fragColor = vec3(0); - { #if !MULTISAMPLING const float depth = subpassLoad(samplerDepth).r; @@ -496,65 +559,79 @@ void main() { vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0); positionEye /= positionEye.w; - position.eye = positionEye.xyz; - position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye ); + surface.position.eye = positionEye.xyz; + surface.position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye ); } +#if 0 { 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 ); + surface.ray.origin = near3; + surface.ray.direction = normalize( far3 - near3 ); } // 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 ); + surface.ray.direction = normalize( far3 - near3 ); } +#else + { + 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; + + surface.ray.direction = normalize( far3 - near3 ); + surface.ray.origin = ubo.matrices.eyePos[inPushConstantPass].xyz; + } +#endif #if !MULTISAMPLING - normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); + surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); const uvec2 ID = subpassLoad(samplerId).xy; #else - normal.world = decodeNormals( resolve(samplerNormal).xy ); + surface.normal.world = decodeNormals( resolve(samplerNormal).xy ); const uvec2 ID = resolve(samplerId).xy; #endif - normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(normal.world, 0.0) ); + surface.normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(surface.normal.world, 0.0) ); if ( ID.x == 0 || ID.y == 0 ) { - fragColor.rgb = texture( samplerSkybox, rayD ).rgb; - fog(rayO, rayD, fragColor, 0.5); - outFragColor = vec4(fragColor,1); + surface.fragment.rgb = texture( samplerSkybox, surface.ray.direction ).rgb; + surface.fragment.a = 0.0; + outFragColor = postProcess(); return; } 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; + surface.material.id = ID.y + drawCall.materialIndex - 1; + const Material material = materials[surface.material.id]; + surface.material.albedo = material.colorBase; + surface.fragment = material.colorEmissive; #if DEFERRED_SAMPLING #if !MULTISAMPLING - const vec2 uv = subpassLoad(samplerUv).xy; + surface.uv = subpassLoad(samplerUv).xy; #else - const vec2 uv = resolve(samplerUv).xy; + surface.uv = resolve(samplerUv).xy; #endif 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]; - A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + if ( validTextureIndex( drawCall.textureIndex + material.indexAlbedo ) ) { + const Texture t = textures[drawCall.textureIndex + material.indexAlbedo]; + surface.material.albedo = textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); } // OPAQUE if ( material.modeAlpha == 0 ) { - A.a = 1; + surface.material.albedo.a = 1; // BLEND } else if ( material.modeAlpha == 1 ) { @@ -562,142 +639,177 @@ void main() { } else if ( material.modeAlpha == 2 ) { } + // Emissive textures + if ( validTextureIndex( drawCall.textureIndex + material.indexEmissive ) ) { + const Texture t = textures[drawCall.textureIndex + material.indexEmissive]; + surface.fragment += textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); + } #else #if !MULTISAMPLING - A = subpassLoad(samplerAlbedo); + surface.material.albedo = subpassLoad(samplerAlbedo); #else - A = resolve(samplerAlbedo); + surface.material.albedo = resolve(samplerAlbedo); #endif #endif - const float M = material.factorMetallic; - const float R = material.factorRoughness; - float AO = material.factorOcclusion; - - vec4 indirectLighting = vec4(0); + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; // GI { + const vec3 P = surface.position.world; + const vec3 N = surface.normal.world; + + #if 1 + const vec3 right = normalize(orthogonal(N)); + const vec3 up = normalize(cross(right, N)); + + const uint CONES_COUNT = 6; + const vec3 CONES[] = { + N, + normalize(N + 0.0f * right + 0.866025f * up), + normalize(N + 0.823639f * right + 0.267617f * up), + normalize(N + 0.509037f * right + -0.7006629f * up), + normalize(N + -0.50937f * right + -0.7006629f * up), + normalize(N + -0.823639f * right + 0.267617f * up), + }; + #else + 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 uint CONES_COUNT = 9; + const vec3 CONES[] = { + N, + normalize(mix(N, ortho, 0.5)), + normalize(mix(N, -ortho, 0.5)), + normalize(mix(N, ortho2, 0.5)), + normalize(mix(N, -ortho2, 0.5)), + normalize(mix(N, corner, 0.5)), + normalize(mix(N, -corner, 0.5)), + normalize(mix(N, corner2, 0.5)), + normalize(mix(N, -corner2, 0.5)), + }; + #endif + + const float DIFFUSE_CONE_APERTURE = 0.57735f; + const float DIFFUSE_INDIRECT_FACTOR = 1.0f / float(CONES_COUNT); + + const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * surface.material.roughness), 0.0174533f, PI); // tan( R * PI * 0.5f * 0.1f ); + const float SPECULAR_INDIRECT_FACTOR = (1.0 - surface.material.metallic) * 0.5; // 1.0f; + vec4 indirectDiffuse = vec4(0); vec4 indirectSpecular = vec4(0); - const vec3 P = position.world; - const vec3 N = normal.world; - - const float DIFFUSE_CONE_APERTURE = 0.57735f; - const float DIFFUSE_INDIRECT_FACTOR = 1.0f / 6.0f; // 1.0f; - - const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * R), 0.0174533f, PI); // tan( R * PI * 0.5f * 0.1f ); - const float SPECULAR_INDIRECT_FACTOR = (1.0 - M) * 0.5; // 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) - }; { - voxelInfo.albedoSize = textureSize( voxelAlbedo, 0 ).x; - voxelInfo.albedoSizeRecip = 1.0 / voxelInfo.albedoSize; - voxelInfo.mipmapLevels = log2(voxelInfo.albedoSize) + 1; //textureQueryLod( voxelAlbedo, vec3(0) ).x; - #if VOXEL_TRACE_IN_NDC + voxelInfo.radianceSize = textureSize( voxelRadiance[0], 0 ).x; + voxelInfo.radianceSizeRecip = 1.0 / voxelInfo.radianceSize; + voxelInfo.mipmapLevels = log2(voxelInfo.radianceSize) + 1; + #if VXGI_NDC voxelInfo.min = vec3( -1 ); voxelInfo.max = vec3( 1 ); - voxelInfo.voxelSize = voxelInfo.albedoSizeRecip; + voxelInfo.voxelSize = voxelInfo.radianceSizeRecip; #else - const mat4 inverseOrtho = inverse( ubo.matrices.voxel ); + const mat4 inverseOrtho = inverse( ubo.matrices.vxgi ); voxelInfo.min = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) ); voxelInfo.max = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) ); voxelInfo.voxelSize = 1; #endif voxelInfo.voxelSizeRecip = 1.0 / voxelInfo.voxelSize; } - - // outFragColor.rgb = voxelConeTrace( rayO, rayD, 0 ).rgb; return; + // outFragColor.rgb = voxelConeTrace( surface.ray, 0 ).rgb; return; + Ray ray; if ( DIFFUSE_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 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 * ( dot(coneDirection, N) < 0 ? -1 : 1 ), DIFFUSE_CONE_APERTURE ) * CONES[i].w; + for ( uint i = 0; i < CONES_COUNT; ++i ) { + float weight = i == 0 ? PI * 0.25f : PI * 0.15f; + ray.origin = P; + ray.direction = CONES[i].xyz; + indirectDiffuse += voxelConeTrace( ray, DIFFUSE_CONE_APERTURE ) * weight; } - // indirectDiffuse.rgb *= A.rgb; - // outFragColor.rgb = indirectDiffuse.rgb; return; - AO = indirectDiffuse.a; + surface.material.occlusion = 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0); + // outFragColor.rgb = indirectDiffuse.rgb; return; + // outFragColor.rgb = vec3(surface.material.occlusion); return; } if ( SPECULAR_INDIRECT_FACTOR > 0.0f ) { - // const vec3 R = reflect( normalize(P - rayO), N ); - const vec3 R = reflect( normalize(P - rayO), N ); - indirectSpecular = voxelConeTrace( P, R, SPECULAR_CONE_APERTURE ); - // outFragColor.rgb = indirectSpecular.rgb; return; + ray.origin = P; + ray.direction = reflect( normalize(P - surface.ray.origin), N ); + indirectSpecular = voxelConeTrace( ray, SPECULAR_CONE_APERTURE ); + // outFragColor.rgb = indirectSpecular.rgb; return; + /* + if ( indirectSpecular.a < 1.0 ) { + vec4 radiance = texture( samplerSkybox, ray.direction ) * 0.25; + indirectSpecular += (1.0 - indirectSpecular.a) * radiance; + } + */ } - indirectLighting = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR; - // outFragColor.rgb = indirectLighting.rgb; return; + surface.material.indirect = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR; + // outFragColor.rgb = surface.material.indirect.rgb; return; } - float litFactor = 1.0; if ( 0 <= material.indexLightmap ) { - fragColor = A.rgb + ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb; + surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; } else { - fragColor = A.rgb * ubo.ambient.rgb * (1 - AO) + indirectLighting.rgb; + surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; } +#if DEFERRED_SAMPLING + // deferred sampling doesn't have a blended albedo buffer + // in place we'll just cone trace behind the window + if ( surface.material.albedo.a < 1.0 ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = surface.ray.direction; + vec4 radiance = voxelConeTrace( ray, surface.material.albedo.a ); + surface.fragment.rgb += (1.0 - surface.material.albedo.a) * radiance.rgb; + } +#endif + + // corrections + surface.material.roughness *= 4.0; + { - const float R = material.factorRoughness * 2.0f; - 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)); + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize( -surface.position.eye ); + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); for ( uint i = 0; i < ubo.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 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - surface.position.eye; const vec3 Li = normalize(Liu); + #if VXGI_SHADOWS + const float Ls = i < ubo.shadowSamples ? shadowFactor( light, 0.0 ) : 1.0; + #else const float Ls = shadowFactor( light, 0.0 ); + #endif 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 float cosLi = max(0.0, dot(surface.normal.eye, Li)); const vec3 Lr = light.color.rgb * light.power * La * Ls; #if LAMBERT - const vec3 diffuse = A.rgb; + const vec3 diffuse = surface.material.albedo.rgb; const vec3 specular = vec3(0); #elif PBR const vec3 Lh = normalize(Li + Lo); - const float cosLh = max(0.0, dot(N, Lh)); + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); 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 diffuse = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb; + const float D = ndfGGX( cosLh, surface.material.roughness ); + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); + const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); #endif // lightmapped, compute only specular - if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specular) * Lr * cosLi; + if ( light.type >= 0 && 0 <= material.indexLightmap ) surface.fragment.rgb += (specular) * Lr * cosLi; // point light, compute only diffuse - // else if ( abs(light.type) == 1 ) fragColor.rgb += (diffuse) * Lr * cosLi; - else fragColor.rgb += (diffuse + specular) * Lr * cosLi; - litFactor += light.power * La * Ls; + // else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi; + else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; + surface.fragment.a += light.power * La * Ls; } } -#if FOG - fog(rayO, rayD, fragColor, 1.0 ); //litFactor); -#endif -#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 WHITENOISE - if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) whitenoise(fragColor); -#endif - - outFragColor = vec4(fragColor,1); + outFragColor = postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/vxgi.comp.glsl b/bin/data/shaders/display/vxgi.comp.glsl index 82432064..ee023243 100644 --- a/bin/data/shaders/display/vxgi.comp.glsl +++ b/bin/data/shaders/display/vxgi.comp.glsl @@ -4,8 +4,7 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; #define MULTISAMPLING 1 -#define RAY_MARCH_FOG 1 -#define DEFERRED_SAMPLING 0 +#define DEFERRED_SAMPLING 1 #define LAMBERT 1 #define PBR 0 @@ -15,26 +14,8 @@ 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; +layout (constant_id = 1) const uint CASCADES = 1; struct Matrices { mat4 view[2]; @@ -42,13 +23,22 @@ struct Matrices { mat4 iView[2]; mat4 iProjection[2]; mat4 iProjectionView[2]; - mat4 voxel; + vec4 eyePos[2]; + mat4 vxgi; }; struct Space { vec3 eye; vec3 world; -} position, normal, view; +}; + +struct Ray { + vec3 origin; + vec3 direction; + + vec3 position; + float distance; +}; struct Fog { vec3 color; @@ -109,6 +99,7 @@ struct Material { int indexLightmap; int modeAlpha; }; + struct Texture { int index; int samp; @@ -117,6 +108,7 @@ struct Texture { vec4 lerp; }; + struct DrawCall { int materialIndex; uint materials; @@ -124,6 +116,29 @@ struct DrawCall { uint textures; }; +struct SurfaceMaterial { + uint id; + + vec4 albedo; + vec4 indirect; + + float metallic; + float roughness; + float occlusion; +}; + +struct Surface { + vec2 uv; + Space position; + Space normal; + + Ray ray; + + SurfaceMaterial material; + + vec4 fragment; +} surface; + layout (binding = 4) uniform UBO { Matrices matrices; @@ -136,12 +151,12 @@ layout (binding = 4) uniform UBO { uint drawCalls; vec3 ambient; - float kexp; - - uint msaa; - uint poissonSamples; float gamma; + float exposure; + uint msaa; + uint shadowSamples; + uint padding1; } ubo; layout (std140, binding = 5) readonly buffer Lights { @@ -157,10 +172,10 @@ layout (std140, binding = 8) readonly buffer DrawCalls { DrawCall drawCalls[]; }; -layout (binding = 9, rg16ui) uniform volatile coherent uimage3D voxelID; -layout (binding = 10, rg16f) uniform volatile coherent image3D voxelNormal; -layout (binding = 11, rg16f) uniform volatile coherent image3D voxelUv; -layout (binding = 12, rgba8) uniform volatile coherent image3D voxelAlbedo; +layout (binding = 9, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; +layout (binding = 10, rg16f) uniform volatile coherent image3D voxelUv[CASCADES]; +layout (binding = 11, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; +layout (binding = 12, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; layout (binding = 13) uniform sampler3D samplerNoise; layout (binding = 14) uniform samplerCube samplerSkybox; @@ -230,7 +245,7 @@ bool validTextureIndex( int textureIndex ) { 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); + vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); positionClip.xyz /= positionClip.w; if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; @@ -253,11 +268,11 @@ float shadowFactor( const Light light, float def ) { 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); + const int samples = int(ubo.shadowSamples); return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor; #if 0 for ( int i = 0; i < samples; ++i ) { - const int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples; + const int index = int( float(samples) * random(floor(surface.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; } @@ -266,121 +281,105 @@ float shadowFactor( const Light light, float def ) { } void main() { - vec3 fragColor = vec3(0); + const vec3 tUvw = gl_GlobalInvocationID.xzy; + for ( uint CASCADE = 0; CASCADE < CASCADES; ++CASCADE ) { + surface.normal.world = decodeNormals( vec2(imageLoad(voxelNormal[CASCADE], ivec3(tUvw) ).xy) ); + surface.normal.eye = vec3( ubo.matrices.vxgi * vec4( surface.normal.world, 0.0f ) ); - 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 ) ); - } - - const uvec2 ID = uvec2(imageLoad(voxelID, ivec3(tUvw) ).xy); - if ( ID.x == 0 || ID.y == 0 ) { - imageStore(voxelAlbedo, ivec3(tUvw), vec4(0)); - return; - } -#if 0 - { - const uvec3 dim = imageSize(voxelAlbedo); - float sdf = max(dim.x, max(dim.y, dim.z)) * 2.82842712; - - uvec2 ID; - ivec3 coord; - for ( uint z = 0; z < dim.z; ++z ) { - for ( uint y = 0; y < dim.y; ++y ) { - for ( uint x = 0; x < dim.x; ++x ) { - coord = ivec3(x,y,z); - ID = imageLoad( voxelID, coord ).xy; - if ( ID.x == 0 || ID.y == 0 ) continue; - sdf = min(distance(tUvw, coord), sdf); + surface.position.eye = vec3(gl_GlobalInvocationID.xyz) / (vec3(imageSize(voxelRadiance[CASCADE])) / (CASCADE + 1)) * 2.0f - 1.0f; + surface.position.world = vec3( inverse(ubo.matrices.vxgi) * vec4( surface.position.eye, 1.0f ) ); + + const uvec2 ID = uvec2(imageLoad(voxelId[CASCADE], ivec3(tUvw) ).xy); + if ( ID.x == 0 || ID.y == 0 ) { + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(0)); + continue; } + const uint drawId = ID.x - 1; + const DrawCall drawCall = drawCalls[drawId]; + surface.material.id = ID.y + drawCall.materialIndex - 1; + const Material material = materials[surface.material.id]; + surface.material.albedo = material.colorBase; + surface.fragment = material.colorEmissive; + + #if DEFERRED_SAMPLING + surface.uv = imageLoad(voxelUv[CASCADE], 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.indexAlbedo ) ) { + const Texture t = textures[drawCall.textureIndex + material.indexAlbedo]; + surface.material.albedo = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv ); } + + // OPAQUE + if ( material.modeAlpha == 0 ) { + surface.material.albedo.a = 1; + // BLEND + } else if ( material.modeAlpha == 1 ) { + + // MASK + } else if ( material.modeAlpha == 2 ) { + } - } -#endif - 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 - 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]; - A = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv ); - } - - // OPAQUE - if ( material.modeAlpha == 0 ) { - A.a = 1; - // BLEND - } else if ( material.modeAlpha == 1 ) { - - // MASK - } 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 litFactor = 1.0; - if ( 0 <= material.indexLightmap ) { - fragColor = A.rgb + ubo.ambient.rgb * (1 - AO); - } else { - fragColor = A.rgb * ubo.ambient.rgb * (1 - AO); - } - { - const float R = material.factorRoughness * 2.0f; - 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 ) { - const Light light = lights[i]; - if ( light.power <= LIGHT_POWER_CUTOFF ) continue; - if ( light.type >= 0 && 0 <= material.indexLightmap ) 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; - - const float cosLi = max(0.0, dot(N, Li)); - const vec3 Lr = light.color.rgb * light.power * La * Ls; - #if LAMBERT - const vec3 diffuse = A.rgb; - const vec3 specular = vec3(0); - #elif PBR - const vec3 Lh = normalize(Li + Lo); - const float cosLh = max(0.0, dot(N, Lh)); - - 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 diffuse = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb; - const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); - #endif - // lightmapped, compute only specular - if ( light.type >= 0 && 0 <= material.indexLightmap ) fragColor.rgb += (specular) * Lr * cosLi; - // point light, compute only diffuse - // else if ( abs(light.type) == 1 ) fragColor.rgb += (diffuse) * Lr * cosLi; - else fragColor.rgb += (diffuse + specular) * Lr * cosLi; - litFactor += light.power * La * Ls; + // Emissive textures + if ( validTextureIndex( drawCall.textureIndex + material.indexEmissive ) ) { + const Texture t = textures[drawCall.textureIndex + material.indexEmissive]; + surface.fragment += texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv ); } - } + #else + surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) ); + #endif + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; - imageStore(voxelAlbedo, ivec3(tUvw), vec4(fragColor.rgb, 1)); + float litFactor = 1.0; + if ( 0 <= material.indexLightmap ) { + surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion; + } else { + surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion; + } + // corrections + surface.material.roughness *= 4.0; + { + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize( surface.position.world ); + const float cosLo = max(0.0, dot(surface.normal.world, Lo)); + for ( uint i = 0; i < ubo.lights; ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + if ( light.type >= 0 && 0 <= material.indexLightmap ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - surface.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; + + const float cosLi = max(0.0, dot(surface.normal.world, Li)); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + #if LAMBERT + const vec3 diffuse = surface.material.albedo.rgb; + const vec3 specular = vec3(0); + #elif PBR + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.world, Lh)); + + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, surface.material.roughness ); + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); + const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; + const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + #endif + // lightmapped, compute only specular + if ( light.type >= 0 && 0 <= material.indexLightmap ) surface.fragment.rgb += (specular) * Lr * cosLi; + // point light, compute only diffuse + // else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi; + else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; + surface.fragment.a += light.power * La * Ls; + } + } + + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, 1)); + } } \ No newline at end of file diff --git a/bin/data/shaders/gltf/baking/bake.frag.glsl b/bin/data/shaders/gltf/baking/bake.frag.glsl index 89f30220..ca6001b7 100644 --- a/bin/data/shaders/gltf/baking/bake.frag.glsl +++ b/bin/data/shaders/gltf/baking/bake.frag.glsl @@ -50,6 +50,7 @@ struct Material { int indexLightmap; int modeAlpha; }; + struct Texture { int index; int samp; @@ -58,6 +59,7 @@ struct Texture { vec4 lerp; }; + struct Light { vec3 position; float radius; @@ -73,6 +75,43 @@ struct Light { mat4 view; mat4 projection; }; + +struct Ray { + vec3 origin; + vec3 direction; + + vec3 position; + float distance; +}; + +struct Space { + vec3 eye; + vec3 world; +}; + +struct SurfaceMaterial { + uint id; + + vec4 albedo; + vec4 indirect; + + float metallic; + float roughness; + float occlusion; +}; + +struct Surface { + vec2 uv; + Space position; + Space normal; + + Ray ray; + + SurfaceMaterial material; + + vec4 fragment; +} surface; + layout (std140, binding = 3) readonly buffer Materials { Material materials[]; }; @@ -160,10 +199,10 @@ bool validTextureIndex( int textureIndex ) { return 0 <= textureIndex; // && textureIndex < ubo.textures; } -float shadowFactor( const Light light, const vec3 P, float def ) { +float shadowFactor( const Light light, float def ) { if ( !validTextureIndex(light.mapIndex) ) return 1.0; - vec4 positionClip = light.projection * light.view * vec4(P, 1.0); + vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); positionClip.xyz /= positionClip.w; if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; @@ -189,7 +228,7 @@ float shadowFactor( const Light light, const vec3 P, float def ) { 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 int index = int( float(samples) * random(floor(surface.position.world * 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; } @@ -198,16 +237,18 @@ float shadowFactor( const Light light, const vec3 P, float def ) { void main() { vec4 A = vec4(1, 1, 1, 1); - vec3 N = normalize( inNormal ); + surface.normal.world = normalize( inNormal ); 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]; + surface.uv = wrap(inUv.xy); + surface.position.world = inPosition; + surface.material.id = int(inId.y); + const Material material = materials[surface.material.id]; - const float M = material.factorMetallic; - const float R = material.factorRoughness; - const float AO = 1.0f - material.factorOcclusion; + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = 1.0f - material.factorOcclusion; + + surface.fragment = material.colorEmissive; #if 0 // sample albedo const bool useAtlas = validTextureIndex( material.indexAtlas ); @@ -215,66 +256,70 @@ void main() { if ( useAtlas ) textureAtlas = textures[material.indexAtlas]; if ( !validTextureIndex( material.indexAlbedo ) ) discard; { - Texture t = textures[material.indexAlbedo]; - A = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + const Texture t = textures[material.indexAlbedo]; + surface.material.albedo = 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 ) { - A.a = 1; + surface.material.albedo.a = 1; // alpha mode BLEND } else if ( material.modeAlpha == 1 ) { // alpha mode MASK } else if ( material.modeAlpha == 2 ) { - if ( A.a < abs(material.factorAlphaCutoff) ) discard; - A.a = 1; + if ( surface.material.albedo.a < abs(material.factorAlphaCutoff) ) discard; + surface.material.albedo.a = 1; } - if ( A.a == 0 ) discard; + if ( surface.material.albedo.a == 0 ) discard; } // sample normal if ( validTextureIndex( material.indexNormal ) ) { - 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)); + const Texture t = textures[material.indexNormal]; + surfacem.normal.world = 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)); + } + + // sample emissive + if ( validTextureIndex( material.indexEmissive ) ) { + const Texture t = textures[material.indexEmissive]; + surface.fragment = textureLod( samplerTextures[(useAtlas) ? textureAtlas.index : t.index], (useAtlas) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); } #else - A = vec4(1); + surface.material.albedo = vec4(1); #endif - float litFactor = 1.0; - vec3 fragColor = vec3(0); { - const vec3 F0 = mix(vec3(0.04), A.rgb, M); - const vec3 Lo = normalize( -P ); - const float cosLo = max(0.0, dot(N, Lo)); + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize( -surface.position.world ); + const float cosLo = max(0.0, dot(surface.normal.world, 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 vec3 Liu = light.position - surface.position.world; const float La = 1.0 / (PI * pow(length(Liu), 2.0)); - const float Ls = shadowFactor( light, P, 0.0 ); + const float Ls = shadowFactor( light, 0.0 ); if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; const vec3 Li = normalize(Liu); const vec3 Lr = light.color.rgb * light.power * La * Ls; - const float cosLi = abs(dot(N, Li));// max(0.0, dot(N, Li)); + const float cosLi = abs(dot(surface.normal.world, Li));// max(0.0, dot(N, Li)); #if LAMBERT - const vec3 diffuse = A.rgb; + const vec3 diffuse = surface.material.albedo.rgb; const vec3 specular = vec3(0); #elif PBR const vec3 Lh = normalize(Li + Lo); const float cosLh = max(0.0, dot(N, Lh)); 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 diffuse = mix( vec3(1.0) - F, vec3(0.0), M ) * A.rgb; + const float D = ndfGGX( cosLh, surface.material.roughness ); + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); + const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); #endif - fragColor.rgb += (diffuse + specular) * Lr * cosLi; - litFactor += light.power * La * Ls; + surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; + surface.fragment.a += light.power * La * Ls; } } - outAlbedo = vec4(fragColor, 1); + outAlbedo = vec4(surface.fragment.rgb, 1); } \ No newline at end of file diff --git a/bin/data/shaders/gltf/base.frag.glsl b/bin/data/shaders/gltf/base.frag.glsl index 77a214e0..d01abd00 100644 --- a/bin/data/shaders/gltf/base.frag.glsl +++ b/bin/data/shaders/gltf/base.frag.glsl @@ -1,6 +1,6 @@ #version 450 -#define DEFERRED_SAMPLING 0 +#define DEFERRED_SAMPLING 1 #define CAN_DISCARD 1 #define USE_LIGHTMAP 1 @@ -137,7 +137,7 @@ void main() { // sample metallic/roughness 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 ); + const vec4 sampled = textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); M = sampled.b; R = sampled.g; } @@ -145,7 +145,7 @@ void main() { AO = material.factorOcclusion; if ( validTextureIndex( material.indexOcclusion ) ) { Texture t = textures[material.indexOcclusion]; - AO = texture( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv ).r; + AO = textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv ).r; } #endif outAlbedo = A * inColor; diff --git a/bin/data/shaders/gltf/voxelize.frag.glsl b/bin/data/shaders/gltf/voxelize.frag.glsl index 1d135f36..cbec2c91 100644 --- a/bin/data/shaders/gltf/voxelize.frag.glsl +++ b/bin/data/shaders/gltf/voxelize.frag.glsl @@ -1,11 +1,12 @@ #version 450 -#define DEFERRED_SAMPLING 0 +#define DEFERRED_SAMPLING 1 #define USE_LIGHTMAP 1 #define PI 3.1415926536f layout (constant_id = 0) const uint TEXTURES = 1; +layout (constant_id = 1) const uint CASCADES = 1; struct Material { vec4 colorBase; @@ -51,10 +52,11 @@ layout (location = 7) in vec3 inPosition; layout (location = 8) flat in ivec4 inId; layout (binding = 7) uniform sampler2D samplerTextures[TEXTURES]; -layout (binding = 8, rg16ui) uniform volatile coherent uimage3D voxelID; -layout (binding = 9, rg16f) uniform volatile coherent image3D voxelNormal; -layout (binding = 10, rg16f) uniform volatile coherent image3D voxelUv; -layout (binding = 11, rgba8) uniform volatile coherent image3D voxelAlbedo; + +layout (binding = 8, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; +layout (binding = 9, rg16f) uniform volatile coherent image3D voxelUv[CASCADES]; +layout (binding = 10, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; +layout (binding = 11, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; layout (location = 0) out uvec2 outId; layout (location = 1) out vec2 outNormals; @@ -84,8 +86,9 @@ bool validTextureIndex( int textureIndex ) { } void main() { - const vec3 P = inPosition; - if ( !(abs(P.x) < 1.0 && abs(P.y) < 1 && abs(P.z) < 1) ) discard; + const vec3 P = inPosition.xzy; + const uint CASCADE = uint(max( abs(floor(P.x)), max( abs(floor(P.y)), abs(floor(P.z)) ) )); + if ( CASCADES <= CASCADE ) discard; vec4 A = vec4(0, 0, 0, 0); const vec3 N = inNormal; @@ -136,8 +139,8 @@ void main() { 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)); - imageStore(voxelUv, ivec3(P * imageSize(voxelUv)), vec4(outUvs, 0, 0)); - imageStore(voxelAlbedo, ivec3(P * imageSize(voxelAlbedo)), outAlbedo); + imageStore(voxelId[CASCADE], ivec3(P * (1 + CASCADE) * imageSize(voxelId[CASCADE])), uvec4(outId, 0, 0)); + imageStore(voxelNormal[CASCADE], ivec3(P * (1 + CASCADE) * imageSize(voxelNormal[CASCADE])), vec4(outNormals, 0, 0)); + imageStore(voxelUv[CASCADE], ivec3(P * (1 + CASCADE) * imageSize(voxelUv[CASCADE])), vec4(outUvs, 0, 0)); + imageStore(voxelRadiance[CASCADE], ivec3(P * (1 + CASCADE) * imageSize(voxelRadiance[CASCADE])), outAlbedo); } \ No newline at end of file diff --git a/bin/data/shaders/gltf/voxelize.geom.glsl b/bin/data/shaders/gltf/voxelize.geom.glsl index 1e51b564..e72b6496 100644 --- a/bin/data/shaders/gltf/voxelize.geom.glsl +++ b/bin/data/shaders/gltf/voxelize.geom.glsl @@ -24,39 +24,42 @@ layout (binding = 6) uniform UBO { } ubo; void main(){ - vec3 norm = abs(inNormal[0] + inNormal[1] + inNormal[2]); - uint axis = norm.y > norm.x ? 1 : 0; - axis = norm.z > norm[axis] ? 2 : axis; + const float RENDER_RESOLUTION = 256.0; + const float PIXEL_SCALE = 2.0; + const float HALF_PIXEL = 1.0 / (RENDER_RESOLUTION * PIXEL_SCALE); + const vec3 C = ( inPosition[0] + inPosition[1] + inPosition[2] ) / 3.0; - mat4 invOrtho = inverse( ubo.voxel ); - vec3 extentMin = vec3( invOrtho * vec4(-1, -1, -1, 1 ) ); - vec3 extentMid = vec3( invOrtho * vec4( 0, 0, 0, 1 ) ); - vec3 extentMax = vec3( invOrtho * vec4( 1, 1, 1, 1 ) ); - vec3 extentSize = extentMax - extentMin; - - for( uint i = 0; i < 3; ++i ){ +#if USE_CROSS + const vec3 N = abs(cross(inPosition[2] - inPosition[0], inPosition[1] - inPosition[0])); +#else + const vec3 N = abs(inNormal[0] + inNormal[1] + inNormal[2]); + uint A = N.y > N.x ? 1 : 0; + A = N.z > N[A] ? 2 : A; +#endif + for(uint i = 0; i < 3; ++i){ outUv = inUv[i]; outSt = inSt[i]; outColor = inColor[i]; outNormal = inNormal[i]; outTBN = inTBN[i]; - outPosition = inPosition[i]; + outPosition = vec3( ubo.voxel * vec4( inPosition[i], 1 ) ) + normalize( inPosition[i] - C ) * HALF_PIXEL; outId = inId[i]; - outPosition = vec3( ubo.voxel * vec4( outPosition, 1 ) ); - - gl_Position = vec4( outPosition.xyz, 1 ); - if ( axis == 0 ) gl_Position.xyz = gl_Position.zyx; - else if ( axis == 1 ) gl_Position.xyz = gl_Position.xzy; - - // outPosition = (inPosition[i] - extentMin) / extentSize; - // outPosition = fract(outPosition * 0.5 + 0.5); + const vec3 P = fract(outPosition); + // const vec3 P = fract(outPosition + normalize( inPosition[i] - C ) * HALF_PIXEL); + #if USE_CROSS + if ( N.z > N.x && N.z > N.y ) gl_Position = vec4(P.x, P.y, 0, 1); + else if ( N.x > N.y && N.x > N.z ) gl_Position = vec4(P.y, P.z, 0, 1); + else gl_Position = vec4(P.x, P.z, 0, 1); + #else + if ( A == 0 ) gl_Position = vec4(P.zy, 1, 1 ); + else if ( A == 1 ) gl_Position = vec4(P.xz, 1, 1 ); + else if ( A == 2 ) gl_Position = vec4(P.xy, 1, 1 ); + #endif outPosition = outPosition * 0.5 + 0.5; - // gl_Position.xy = fract( gl_Position.xy * 0.5 + 0.5 ) * 2.0 - 1.0; - // gl_Position.xy = fract( gl_Position.xy * 0.5 + 0.5 ) * 2.0 - 1.0; - gl_Position.z = 1; - + + EmitVertex(); } EndPrimitive(); diff --git a/bin/data/shaders/gui/base.frag.glsl b/bin/data/shaders/gui/base.frag.glsl index 1dc5485a..1119afa1 100644 --- a/bin/data/shaders/gui/base.frag.glsl +++ b/bin/data/shaders/gui/base.frag.glsl @@ -1,7 +1,7 @@ #version 450 -#define UF_DEFERRED_SAMPLING 0 -#define UF_CAN_DISCARD 1 +#define DEFERRED_SAMPLING 0 +#define CAN_DISCARD 1 layout (binding = 1) uniform sampler2D samplerTexture; @@ -18,12 +18,18 @@ layout (location = 1) in flat Gui inGui; 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 +float wrap( float i ) { + return fract(i); +} +vec2 wrap( vec2 uv ) { + return vec2( wrap( uv.x ), wrap( uv.y ) ); +} vec2 encodeNormals( vec3 n ) { float p = sqrt(n.z*8+8); return n.xy/p + 0.5; @@ -44,14 +50,14 @@ void main() { vec2 uv = inUv.xy; vec4 C = vec4(1, 1, 1, 1); //vec3 N = inNormal; -#if UF_DEFERRED_SAMPLING +#if DEFERRED_SAMPLING outUvs = wrap(inUv.xy); vec4 outAlbedo = vec4(0,0,0,0); #endif -#if !UF_DEFERRED_SAMPLING || UF_CAN_DISCARD +#if !DEFERRED_SAMPLING || CAN_DISCARD C = textureLod( samplerTexture, uv, mip ); #endif -#if !UF_DEFERRED_SAMPLING +#if !DEFERRED_SAMPLING if ( inGui.mode == 1 ) { C = inGui.color; } else { diff --git a/bin/data/shaders/gui/text.frag.glsl b/bin/data/shaders/gui/text.frag.glsl index 520220cd..ad40d261 100644 --- a/bin/data/shaders/gui/text.frag.glsl +++ b/bin/data/shaders/gui/text.frag.glsl @@ -1,7 +1,7 @@ #version 450 -#define UF_DEFERRED_SAMPLING 0 -#define UF_CAN_DISCARD 1 +#define DEFERRED_SAMPLING 0 +#define CAN_DISCARD 1 layout (binding = 1) uniform sampler2D samplerTexture; @@ -24,7 +24,7 @@ layout (location = 1) in flat Gui inGui; 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; @@ -36,7 +36,7 @@ void main() { if ( inUv.x > inGui.offset.z ) discard; if ( inUv.y > inGui.offset.w ) discard; -#if UF_DEFERRED_SAMPLING +#if DEFERRED_SAMPLING vec4 outAlbedo = vec4(0,0,0,0); #endif diff --git a/engine/inc/uf/ext/gltf/pod.h b/engine/inc/uf/ext/gltf/pod.h index d84ce14b..c6a20da9 100644 --- a/engine/inc/uf/ext/gltf/pod.h +++ b/engine/inc/uf/ext/gltf/pod.h @@ -10,10 +10,10 @@ namespace pod { uf::renderer::Texture3D noise; uf::renderer::TextureCube skybox; struct { - uf::renderer::Texture3D id; - uf::renderer::Texture3D normal; - uf::renderer::Texture3D albedo; - uf::renderer::Texture3D uv; + std::vector id; + std::vector uv; + std::vector normal; + std::vector radiance; pod::Matrix4f matrix; } voxels; }; diff --git a/engine/inc/uf/utils/camera/camera.h b/engine/inc/uf/utils/camera/camera.h index 06557a95..bdb0fdf6 100644 --- a/engine/inc/uf/utils/camera/camera.h +++ b/engine/inc/uf/utils/camera/camera.h @@ -39,11 +39,7 @@ namespace uf { static bool USE_REVERSE_INFINITE_PROJECTION; Camera(); -/* - Camera( const pod::Math::num_t& fov, const pod::Vector2& size, const pod::Vector2& bounds, const pod::Vector3& offset = {0, 0, 0}, const pod::Vector2& tops = {0, 0} ); - Camera( Camera&& move ); - Camera( const Camera& copy ); -*/ + bool modified() const; void setStereoscopic( bool ); pod::Transform<>& getTransform(); @@ -55,8 +51,7 @@ namespace uf { pod::Matrix4& getProjection( size_t = 0 ); const pod::Matrix4& getProjection( size_t = 0 ) const; - // pod::Matrix4& getModel(); - // const pod::Matrix4& getModel() const; + pod::Vector3f getEye( size_t = 0 ) const; pod::Math::num_t& getFov(); pod::Math::num_t getFov() const; diff --git a/engine/inc/uf/utils/octree/octree.h b/engine/inc/uf/utils/octree/octree.h new file mode 100644 index 00000000..7b9637ef --- /dev/null +++ b/engine/inc/uf/utils/octree/octree.h @@ -0,0 +1 @@ +#pragma once \ No newline at end of file diff --git a/engine/src/engine/object/behaviors/gltf.cpp b/engine/src/engine/object/behaviors/gltf.cpp index 818cb885..cd84ddd3 100644 --- a/engine/src/engine/object/behaviors/gltf.cpp +++ b/engine/src/engine/object/behaviors/gltf.cpp @@ -38,6 +38,7 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { assetLoader.remove(filename); bool shouldUpdate = false; + auto& sceneMetadataJson = scene.getComponent(); if ( !ext::json::isNull(graph.metadata["ambient"]) ) { sceneMetadataJson["light"]["ambient"] = graph.metadata["ambient"]; @@ -48,6 +49,7 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { shouldUpdate = true; } if ( shouldUpdate ) scene.callHook("object:UpdateMetadata.%UID%"); + // deferred shader loading auto& transform = this->getComponent>(); graph.root.entity->getComponent>().reference = &transform; @@ -75,23 +77,25 @@ void uf::GltfBehavior::destroy( uf::Object& self ) { uf::graph::destroy( graph ); } } + +#define UNIFORMS_UPDATE_IN_TICK 1 void uf::GltfBehavior::tick( uf::Object& self ) { - /* Animation change test */ /* Update animations */ if ( this->hasComponent() ) { auto& graph = this->getComponent(); if ( graph.metadata["flags"]["SKINNED"].as() ) uf::graph::update( graph ); } - /* Update uniforms */ + if ( !this->hasComponent() ) return; + auto& scene = uf::scene::getCurrentScene(); auto& metadata = this->getComponent(); auto& graphic = this->getComponent(); auto& controller = scene.getController(); - auto& controllerTransform = controller.getComponent>(); auto& camera = controller.getComponent(); + auto& transform = this->getComponent>(); if ( !graphic.initialized ) return; - + auto* objectWithGraph = this; while ( objectWithGraph != &scene ) { if ( objectWithGraph->hasComponent() ) break; @@ -100,6 +104,7 @@ void uf::GltfBehavior::tick( uf::Object& self ) { if ( !objectWithGraph->hasComponent() ) return; auto& graph = objectWithGraph->getComponent(); +#if UNIFORMS_UPDATE_IN_TICK #if UF_USE_OPENGL if ( graphic.material.hasShader("vertex") ) { auto& shader = graphic.material.getShader("vertex"); @@ -119,7 +124,7 @@ void uf::GltfBehavior::tick( uf::Object& self ) { } } #elif UF_USE_VULKAN - if ( graphic.material.hasShader("fragment") && !(graph.metadata["flags"]["SEPARATE"].as()) ) { + if ( graphic.material.hasShader("vertex") && !(graph.metadata["flags"]["SEPARATE"].as()) ) { auto& shader = graphic.material.getShader("vertex"); std::vector instances( graph.nodes.size() ); for ( size_t i = 0; i < graph.nodes.size(); ++i ) { @@ -129,31 +134,7 @@ 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", "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{} ); - - 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); - // uniforms.matrix = uf::matrix::translate( uf::matrix::identity(), -controllerTransform.position ) - uniforms.matrix = uf::matrix::ortho( min.x, max.x, min.y, max.y, min.z, max.z ); - */ - auto& sceneTextures = scene.getComponent(); - struct UniformDescriptor { - alignas(16) pod::Matrix4f matrix; - }; - auto& uniform = shader.getUniform("UBO"); - auto& uniforms = uniform.get(); - uniforms.matrix = sceneTextures.voxels.matrix; - shader.updateUniform( "UBO", uniform ); - } +#endif #endif } @@ -202,24 +183,15 @@ void uf::GltfBehavior::render( uf::Object& self ) { if ( graphic.material.hasShader("vertex") ) { auto& shader = graphic.material.getShader("vertex"); auto& uniform = shader.getUniform("UBO"); + #if UF_UNIFORMS_UPDATE_WITH_JSON if ( !(graph.metadata["flags"]["SEPARATE"].as()) ) { - #if UF_UNIFORMS_UPDATE_WITH_JSON ext::json::Value uniforms; for ( std::size_t i = 0; i < uf::renderer::settings::maxViews; ++i ) { uniforms["view"][i] = uf::matrix::encode( camera.getView( i ) ); uniforms["projection"][i] = uf::matrix::encode( camera.getProjection( i ) ); } shader.updateUniform("UBO", uniforms ); - #else - auto& uniforms = uniform.get>(); - for ( std::size_t i = 0; i < uf::renderer::settings::maxViews; ++i ) { - uniforms.view[i] = camera.getView( i ); - uniforms.projection[i] = camera.getProjection( i ); - } - shader.updateUniform( "UBO", uniform ); - #endif } else { - #if UF_UNIFORMS_UPDATE_WITH_JSON // auto uniforms = shader.getUniformJson("UBO"); ext::json::Value uniforms; uniforms["matrices"]["model"] = uf::matrix::encode( uf::transform::model( transform ) ); @@ -239,24 +211,61 @@ void uf::GltfBehavior::render( uf::Object& self ) { uniforms["color"][3] = 1.0f; } shader.updateUniform("UBO", uniforms ); - #else + } + #else + if ( !(graph.metadata["flags"]["SEPARATE"].as()) ) { + auto& uniforms = uniform.get>(); + for ( std::size_t i = 0; i < uf::renderer::settings::maxViews; ++i ) { + uniforms.view[i] = camera.getView( i ); + uniforms.projection[i] = camera.getProjection( i ); + } + shader.updateUniform( "UBO", uniform ); + } else { auto& uniforms = uniform.get>(); uniforms.matrices.model = uf::transform::model( transform ); for ( std::size_t i = 0; i < uf::renderer::settings::maxViews; ++i ) { uniforms.matrices.view[i] = camera.getView( i ); uniforms.matrices.projection[i] = camera.getProjection( i ); } - if ( ext::json::isArray(metadata["color"]) ) { - uniforms.color[0] = metadata["color"][0].as(); - uniforms.color[1] = metadata["color"][1].as(); - uniforms.color[2] = metadata["color"][2].as(); - uniforms.color[3] = metadata["color"][3].as(); - } else { - uniforms.color = { 1, 1, 1, 1 }; - } + uniforms.color = uf::vector::decode( metadata["color"], pod::Vector4f{1,1,1,1} ); shader.updateUniform( "UBO", uniform ); - #endif } + #endif + } +#endif + +#if !UNIFORMS_UPDATE_IN_TICK + if ( uf::renderer::currentRenderMode == uf::renderer::renderModes.front() ) { + #if UF_USE_OPENGL + if ( graphic.material.hasShader("vertex") ) { + auto& shader = graphic.material.getShader("vertex"); + auto& mesh = this->getComponent(); + + if ( !(graph.metadata["flags"]["SEPARATE"].as()) ) { + std::vector instances( graph.nodes.size() ); + for ( size_t i = 0; i < graph.nodes.size(); ++i ) { + auto& node = graph.nodes[i]; + instances[i] = node.entity ? uf::transform::model( node.entity->getComponent>() ) : uf::transform::model( node.transform ); + } + + graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex ); + shader.execute( graphic, &mesh.vertices[0] ); + } else if ( graph.metadata["flags"]["SKINNED"].as() ) { + shader.execute( graphic, &mesh.vertices[0] ); + } + } + #elif UF_USE_VULKAN + if ( graphic.material.hasShader("vertex") && !(graph.metadata["flags"]["SEPARATE"].as()) ) { + auto& shader = graphic.material.getShader("vertex"); + std::vector instances( graph.nodes.size() ); + for ( size_t i = 0; i < graph.nodes.size(); ++i ) { + auto& node = graph.nodes[i]; + instances[i] = node.entity ? uf::transform::model( node.entity->getComponent>() ) : uf::transform::model( node.transform ); + } + auto& storageBuffer = *graphic.getStorageBuffer("Models"); + graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex /*storageBuffer*/ ); + } + #endif } #endif } diff --git a/engine/src/ext/gltf/graph.cpp b/engine/src/ext/gltf/graph.cpp index 02df78ca..4d2e0b00 100644 --- a/engine/src/ext/gltf/graph.cpp +++ b/engine/src/ext/gltf/graph.cpp @@ -16,8 +16,10 @@ namespace { auto& graphic = entity.getComponent(); std::string root = uf::io::directory( graph.name ); size_t texture2Ds = 0; + size_t texture3Ds = 0; for ( auto& texture : graphic.material.textures ) { if ( texture.width > 1 && texture.height > 1 && texture.depth == 1 && texture.layers == 1 ) ++texture2Ds; + else if ( texture.width > 1 && texture.height > 1 && texture.depth > 1 && texture.layers == 1 ) ++texture3Ds; } // standard pipeline @@ -62,9 +64,14 @@ namespace { ext::json::forEach( shader.metadata["specializationConstants"], [&]( ext::json::Value& sc ){ if ( sc["name"].as() == "TEXTURES" ) sc["value"] = specializationConstants.textures; }); - for ( auto& binding : shader.descriptorSetLayoutBindings ) { - if ( binding.descriptorCount > 1 ) binding.descriptorCount = specializationConstants.textures; - } + + ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){ + if ( t["name"].as() != "samplerTextures" ) return; + size_t binding = t["binding"].as(); + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding == binding ) layout.descriptorCount = specializationConstants.textures; + } + }); } #endif } @@ -73,15 +80,7 @@ namespace { std::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/gltf/base.vert.spv"); std::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as("/gltf/voxelize.geom.spv"); std::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/gltf/voxelize.frag.spv"); - /* - { - if ( !graph.metadata["flags"]["SEPARATE"].as() ) { - vertexShaderFilename = graph.metadata["flags"]["SKINNED"].as() ? "/gltf/skinned.instanced.vert.spv" : "/gltf/instanced.vert.spv"; - } else if ( graph.metadata["flags"]["SKINNED"].as() ) vertexShaderFilename = "/gltf/skinned.vert.spv"; - vertexShaderFilename = entity.grabURI( vertexShaderFilename, root ); - 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, "vxgi"); @@ -91,48 +90,32 @@ namespace { graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "vxgi"); } #if UF_USE_VULKAN - /* - { - auto& shader = graphic.material.getShader("vertex", "vxgi"); - struct SpecializationConstant { - uint32_t passes = 6; - }; - auto& specializationConstants = shader.specializationConstants.get(); - specializationConstants.passes = uf::renderer::settings::maxViews; - ext::json::forEach( shader.metadata["specializationConstants"], [&]( ext::json::Value& sc ){ - if ( sc["name"].as() == "PASSES" ) sc["value"] = specializationConstants.passes; - }); - } - */ - /* - if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) { - 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{} ); - - struct UniformDescriptor { - alignas(16) pod::Matrix4f matrix; - }; - - auto& uniform = shader.getUniform("UBO"); - auto& uniforms = uniform.get(); - uniforms.matrix = uf::matrix::ortho( min.x, max.x, min.y, max.y, max.z, min.z ); - shader.updateUniform( "UBO", uniform ); - } - */ { auto& shader = graphic.material.getShader("fragment", "vxgi"); struct SpecializationConstant { - uint32_t textures = 1; + uint32_t textures = 256; + uint32_t cascades = 2; }; auto& specializationConstants = shader.specializationConstants.get(); specializationConstants.textures = texture2Ds; + specializationConstants.cascades = texture3Ds / 4; ext::json::forEach( shader.metadata["specializationConstants"], [&]( ext::json::Value& sc ){ - if ( sc["name"].as() == "TEXTURES" ) sc["value"] = specializationConstants.textures; + std::string name = sc["name"].as(); + if ( name == "TEXTURES" ) sc["value"] = specializationConstants.textures; + else if ( name == "CASCADES" ) sc["value"] = specializationConstants.cascades; + }); + ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){ + size_t binding = t["binding"].as(); + std::string name = t["name"].as(); + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding != binding ) continue; + if ( name == "samplerTextures" ) layout.descriptorCount = specializationConstants.textures; + else if ( name == "voxelId" ) layout.descriptorCount = specializationConstants.cascades; + else if ( name == "voxelUv" ) layout.descriptorCount = specializationConstants.cascades; + else if ( name == "voxelNormal" ) layout.descriptorCount = specializationConstants.cascades; + else if ( name == "voxelRadiance" ) layout.descriptorCount = specializationConstants.cascades; + } }); - for ( auto& binding : shader.descriptorSetLayoutBindings ) { - if ( binding.descriptorCount > 1 ) binding.descriptorCount = specializationConstants.textures; - } } #endif } @@ -167,10 +150,10 @@ namespace { if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { auto& scene = uf::scene::getCurrentScene(); auto& sceneTextures = scene.getComponent(); - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id); - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.normal); - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.uv); - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.albedo); + for ( auto& t : sceneTextures.voxels.id ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.uv ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.normal ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.radiance ) graphic.material.textures.emplace_back().aliasTexture(t); } } if ( graph.metadata["flags"]["LOAD"].as() ) { @@ -340,12 +323,14 @@ void uf::graph::process( pod::Graph& graph ) { break; } } + // Failsafe + if ( graph.materials.empty() ) graph.materials.emplace_back(); + if ( graph.textures.empty() ) graph.textures.emplace_back(); + // Materials storage buffer std::vector materials( graph.materials.size() ); for ( size_t i = 0; i < graph.materials.size(); ++i ) { materials[i] = graph.materials[i].storage; - if ( graph.metadata["alpha cutoff"].is() ) - materials[i].factorAlphaCutoff = graph.metadata["alpha cutoff"].as(); } graph.root.materialBufferIndex = graphic.initializeBuffer( (void*) materials.data(), @@ -1434,7 +1419,7 @@ void uf::graph::save( const pod::Graph& graph, const std::string& filename ) { if ( saveSeparately ) { for ( size_t i = 0; i < graph.images.size(); ++i ) { std::string f = "image."+std::to_string(i)+(compression?".jpg":".png"); - graph.images[i].save(directory + "/" + f, true); + graph.images[i].save(directory + "/" + f); serializer["images"].emplace_back(f); } } else { @@ -1523,7 +1508,7 @@ void uf::graph::save( const pod::Graph& graph, const std::string& filename ) { if ( saveSeparately ) { for ( size_t i = 0; i < graph.images.size(); ++i ) { std::string f = "image."+std::to_string(i)+(compression?".jpg":".png"); - graph.images[i].save(directory + "/" + f, true); + graph.images[i].save(directory + "/" + f); serializer["images"].emplace_back(f); } } else { diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 34df59bb..ba4c577a 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -62,7 +62,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.blend = */false, /*.samples = */msaa, }); - if ( ext::vulkan::settings::experimental::deferredMode == "deferredSampling" ) { + if ( ext::vulkan::settings::experimental::deferredMode != "" ) { attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ /*.format = */VK_FORMAT_R16G16_UNORM, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, @@ -131,7 +131,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.samples = */1, }); - if ( ext::vulkan::settings::experimental::deferredMode == "deferredSampling" ) { + if ( ext::vulkan::settings::experimental::deferredMode != "" ) { // First pass: fill the G-Buffer { renderTarget.addPass( @@ -213,23 +213,56 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { auto& scene = uf::scene::getCurrentScene(); auto& shader = blitter.material.shaders.back(); - struct SpecializationConstant { - uint32_t maxTextures = 512; - }; - auto& specializationConstants = shader.specializationConstants.get(); + size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(256); + size_t maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(256); - auto& metadata = scene.getComponent(); - size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(); - specializationConstants.maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(); - for ( auto& binding : shader.descriptorSetLayoutBindings ) { - if ( binding.descriptorCount > 1 ) - binding.descriptorCount = specializationConstants.maxTextures; + UF_DEBUG_MSG( maxLights << "\t" << maxTextures ); + + if ( ext::vulkan::settings::experimental::deferredMode == "vxgi" ) { + struct SpecializationConstant { + uint32_t maxTextures = 256; + uint32_t maxCascades = 2; + }; + auto& specializationConstants = shader.specializationConstants.get(); + + auto& metadata = scene.getComponent(); + specializationConstants.maxTextures = maxTextures; + specializationConstants.maxCascades = metadata["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as(2); + + ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){ + size_t binding = t["binding"].as(); + std::string name = t["name"].as(); + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding != binding ) continue; + if ( name == "samplerTextures" ) layout.descriptorCount = specializationConstants.maxTextures; + else if ( name == "voxelId" ) layout.descriptorCount = specializationConstants.maxCascades; + else if ( name == "voxelUv" ) layout.descriptorCount = specializationConstants.maxCascades; + else if ( name == "voxelNormal" ) layout.descriptorCount = specializationConstants.maxCascades; + else if ( name == "voxelRadiance" ) layout.descriptorCount = specializationConstants.maxCascades; + } + }); + } else { + struct SpecializationConstant { + uint32_t maxTextures = 256; + }; + auto& specializationConstants = shader.specializationConstants.get(); + + auto& metadata = scene.getComponent(); + specializationConstants.maxTextures = maxTextures; + + ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){ + if ( t["name"].as() != "samplerTextures" ) return; + size_t binding = t["binding"].as(); + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding == binding ) layout.descriptorCount = specializationConstants.maxTextures; + } + }); } std::vector lights(maxLights); - std::vector materials(specializationConstants.maxTextures); - std::vector textures(specializationConstants.maxTextures); - std::vector drawCalls(specializationConstants.maxTextures); + std::vector materials(maxTextures); + std::vector textures(maxTextures); + std::vector drawCalls(maxTextures); for ( auto& material : materials ) material.colorBase = {0,0,0,0}; diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 3821e54b..0d1de059 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -40,9 +40,10 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD if ( pass == 0 && type == "vxgi" ) { descriptor.cullMode = VK_CULL_MODE_NONE; descriptor.depth.test = false; + descriptor.depth.write = false; descriptor.pipeline = "vxgi"; } else if ( type == "depth" ) { - descriptor.cullMode = VK_CULL_MODE_NONE; + // descriptor.cullMode = VK_CULL_MODE_NONE; } // invalidate if ( target != "" && descriptor.renderMode != this->getName() && descriptor.renderMode != target ) { @@ -185,7 +186,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { /*.blend = */false, /*.samples = */msaa, }); - if ( ext::vulkan::settings::experimental::deferredMode == "deferredSampling" ) { + if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) { attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ /*.format = */VK_FORMAT_R16G16_UNORM, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, @@ -216,7 +217,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { /*.blend =*/ true, /*.samples =*/ 1, }); - if ( ext::vulkan::settings::experimental::deferredMode == "deferredSampling" ) { + if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) { // First pass: fill the G-Buffer { renderTarget.addPass( @@ -347,16 +348,28 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { auto& shader = blitter.material.getShader("compute"); struct SpecializationConstant { uint32_t maxTextures = 512; + uint32_t maxCascades = 1; }; auto& specializationConstants = shader.specializationConstants.get(); auto& metadata = scene.getComponent(); - size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(); - specializationConstants.maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(); - for ( auto& binding : shader.descriptorSetLayoutBindings ) { - if ( binding.descriptorCount > 1 ) - binding.descriptorCount = specializationConstants.maxTextures; - } + size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(256); + specializationConstants.maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(256); + specializationConstants.maxCascades = metadata["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as(2); + + + ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){ + size_t binding = t["binding"].as(); + std::string name = t["name"].as(); + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding != binding ) continue; + if ( name == "samplerTextures" ) layout.descriptorCount = specializationConstants.maxTextures; + else if ( name == "voxelId" ) layout.descriptorCount = specializationConstants.maxCascades; + else if ( name == "voxelUv" ) layout.descriptorCount = specializationConstants.maxCascades; + else if ( name == "voxelNormal" ) layout.descriptorCount = specializationConstants.maxCascades; + else if ( name == "voxelRadiance" ) layout.descriptorCount = specializationConstants.maxCascades; + } + }); std::vector lights(maxLights); std::vector materials(specializationConstants.maxTextures); diff --git a/engine/src/ext/vulkan/texture.cpp b/engine/src/ext/vulkan/texture.cpp index 49e3537f..3e898d66 100644 --- a/engine/src/ext/vulkan/texture.cpp +++ b/engine/src/ext/vulkan/texture.cpp @@ -530,12 +530,14 @@ void ext::vulkan::Texture::aliasTexture( const Texture& texture ) { view = texture.view; imageLayout = texture.imageLayout; deviceMemory = texture.deviceMemory; - sampler = texture.sampler; width = texture.width; height = texture.height; depth = texture.depth; layers = texture.layers; + sampler = texture.sampler; + sampler.device = NULL; + this->updateDescriptors(); } void ext::vulkan::Texture::aliasAttachment( const RenderTarget::Attachment& attachment, bool createSampler ) { diff --git a/engine/src/utils/camera/camera.cpp b/engine/src/utils/camera/camera.cpp index 47bc4589..120016ea 100644 --- a/engine/src/utils/camera/camera.cpp +++ b/engine/src/utils/camera/camera.cpp @@ -16,9 +16,6 @@ uf::Camera::Camera() : m_modified(false) { this->m_settings.offset = {0, 0, 0}; this->m_settings.mode = 1; -// this->setModel(uf::matrix::identity()); -// this->setView(uf::matrix::identity()); -// this->setProjection(uf::matrix::identity()); this->m_matrices.views.resize(6, uf::matrix::identity()); this->m_matrices.projections.resize(6, uf::matrix::identity()); @@ -39,89 +36,30 @@ const pod::Transform<>& uf::Camera::getTransform() const { pod::Matrix4& uf::Camera::getView( size_t eye ) { if ( eye >= this->m_matrices.views.size() ) eye = 0; return this->m_matrices.views[eye]; -// if ( eye >= this->m_matrices.views.size() ) return uf::matrix::identity(); -// if ( eye >= this->m_matrices.views.size() ) this->m_matrices.views.resize( uf::matrix::identity() ); -/* - switch ( eye ) { - case 0: - return this->m_matrices.left.view; - break; - case 1: - return this->m_matrices.right.view; - break; - default: - return this->m_matrices.left.view; - break; - } -*/ } pod::Matrix4& uf::Camera::getProjection( size_t eye ) { if ( eye >= this->m_matrices.projections.size() ) eye = 0; return this->m_matrices.projections[eye]; -// if ( eye >= this->m_matrices.projections.size() ) return uf::matrix::identity(); -// if ( eye >= this->m_matrices.projections.size() ) this->m_matrices.projections.resize( eye, uf::matrix::identity() ); -/* - switch ( eye ) { - case 0: - return this->m_matrices.left.projection; - break; - case 1: - return this->m_matrices.right.projection; - break; - default: - return this->m_matrices.left.projection; - break; - } -*/ } -/* -pod::Matrix4& uf::Camera::getModel() { - return this->m_matrices.model; -} -*/ const pod::Matrix4& uf::Camera::getView( size_t eye ) const { if ( eye >= this->m_matrices.views.size() ) eye = 0; return this->m_matrices.views[eye]; -// if ( eye >= this->m_matrices.views.size() ) return uf::matrix::identity(); -// if ( eye >= this->m_matrices.views.size() ) this->m_matrices.views.resize( eye, uf::matrix::identity() ); -/* - switch ( eye ) { - case 0: - return this->m_matrices.left.view; - break; - case 1: - return this->m_matrices.right.view; - break; - default: - return this->m_matrices.left.view; - break; - } -*/ } const pod::Matrix4& uf::Camera::getProjection( size_t eye ) const { if ( eye >= this->m_matrices.projections.size() ) eye = 0; return this->m_matrices.projections[eye]; -// if ( eye >= this->m_matrices.projections.size() ) return uf::matrix::identity(); -// if ( eye >= this->m_matrices.projections.size() ) this->m_matrices.projections.resize( eye, uf::matrix::identity() ); -/* - switch ( eye ) { - case 0: - return this->m_matrices.left.projection; - break; - case 1: - return this->m_matrices.right.projection; - break; - default: - return this->m_matrices.left.projection; - break; +} + +pod::Vector3f uf::Camera::getEye( size_t eye ) const { + pod::Vector3f position = uf::transform::flatten( this->m_transform ).position; +#if UF_USE_OPENVR + if ( this->m_settings.stereoscopic && ext::openvr::context ) { + position += ext::openvr::hmdPosition( eye == 0 ? vr::Eye_Left : vr::Eye_Right ); } -*/ +#endif + return position; } -/* -const pod::Matrix4& uf::Camera::getModel() const { - return this->m_matrices.model; -} -*/ + pod::Math::num_t& uf::Camera::getFov() { return this->m_settings.perspective.fov; } @@ -162,20 +100,6 @@ void uf::Camera::setView( const pod::Matrix4& mat, size_t i ) { } if ( i >= this->m_matrices.views.size() ) this->m_matrices.views.resize( i, uf::matrix::identity() ); this->m_matrices.views[i] = mat; -/* - switch ( i ) { - case 0: - this->m_matrices.left.view = mat; - break; - case 1: - this->m_matrices.right.view = mat; - break; - default: - this->setView( mat, 0 ); - this->setView( mat, 1 ); - break; - } -*/ } void uf::Camera::setProjection( const pod::Matrix4& mat, size_t i ) { if ( i >= uf::renderer::settings::maxViews ) { @@ -185,26 +109,7 @@ void uf::Camera::setProjection( const pod::Matrix4& mat, size_t i ) { } if ( i >= this->m_matrices.projections.size() ) this->m_matrices.projections.resize( i, uf::matrix::identity() ); this->m_matrices.projections[i] = mat; -/* - switch ( i ) { - case 0: - this->m_matrices.left.projection = mat; - break; - case 1: - this->m_matrices.right.projection = mat; - break; - default: - this->setProjection( mat, 0 ); - this->setProjection( mat, 1 ); - break; - } -*/ } -/* -void uf::Camera::setModel( const pod::Matrix4& mat ) { - this->m_matrices.model = mat; -} -*/ void uf::Camera::setFov( pod::Math::num_t fov ) { this->m_settings.mode = 1; this->m_settings.perspective.fov = fov; diff --git a/engine/src/utils/octree/octree.cpp b/engine/src/utils/octree/octree.cpp new file mode 100644 index 00000000..85c650a7 --- /dev/null +++ b/engine/src/utils/octree/octree.cpp @@ -0,0 +1,2 @@ +#include + diff --git a/ext/behaviors/player/model/behavior.cpp b/ext/behaviors/player/model/behavior.cpp index 9b7b4deb..13f65d06 100644 --- a/ext/behaviors/player/model/behavior.cpp +++ b/ext/behaviors/player/model/behavior.cpp @@ -71,8 +71,9 @@ void ext::PlayerModelBehavior::render( uf::Object& self ){ auto& transform = this->getComponent>(); // auto& renderMode = *uf::renderer::currentRenderMode; -// if ( renderMode.getType() == "Deferred" ) { - if ( player.getUid() == controller.getUid() && uf::renderer::currentRenderMode->getName() != "RenderTarget" ) { +// UF_DEBUG_MSG( uf::renderer::currentRenderMode->getName() << ": " << uf::renderer::currentRenderMode->getType() ); + if ( uf::renderer::currentRenderMode->getName() == "Gui" ) { +// if ( player.getUid() == controller.getUid() && uf::renderer::currentRenderMode->getName() != "RenderTarget" ) { transform.scale = { 0, 0, 0 }; } else { transform.scale = metadata.scale; diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index e5db43ed..06953732 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -210,10 +210,12 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); metadata.serialize = [&]() { 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; @@ -227,14 +229,17 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { metadata.deserialize = [&](){ metadata.max.textures = ext::config["engine"]["scenes"]["textures"]["max"].as(); metadata.max.lights = ext::config["engine"]["scenes"]["lights"]["max"].as(); + metadata.light.enabled = ext::config["engine"]["scenes"]["lights"]["enabled"].as() && metadataJson["light"]["should"].as(); metadata.light.shadowSamples = ext::config["engine"]["scenes"]["lights"]["shadow samples"].as(); metadata.light.shadowThreshold = ext::config["engine"]["scenes"]["lights"]["shadow threshold"].as(); metadata.light.updateThreshold = ext::config["engine"]["scenes"]["lights"]["update threshold"].as(); + 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(1.0f); metadata.light.gamma = metadataJson["light"]["gamma"].as(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(); metadata.fog.absorbtion = metadataJson["light"]["fog"]["absorbtion"].as(); @@ -244,6 +249,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { metadata.fog.density.threshold = metadataJson["light"]["fog"]["density"]["threshold"].as(); metadata.fog.density.multiplier = metadataJson["light"]["fog"]["density"]["multiplier"].as(); metadata.fog.density.scale = metadataJson["light"]["fog"]["density"]["scale"].as(); + #if UF_USE_OPENGL_FIXED_FUNCTION uf::renderer::states::rebuild = true; #endif @@ -364,6 +370,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { #else if ( !metadata.max.textures ) metadata.max.textures = ext::config["engine"]["scenes"]["textures"]["max"].as(); if ( !metadata.max.lights ) metadata.max.lights = ext::config["engine"]["scenes"]["lights"]["max"].as(); + if ( !metadata.light.enabled ) metadata.light.enabled = ext::config["engine"]["scenes"]["lights"]["enabled"].as() && metadataJson["light"]["should"].as(); if ( !metadata.light.shadowSamples ) metadata.light.shadowSamples = ext::config["engine"]["scenes"]["lights"]["shadow samples"].as(); if ( !metadata.light.shadowThreshold ) metadata.light.shadowThreshold = ext::config["engine"]["scenes"]["lights"]["shadow threshold"].as(); @@ -371,7 +378,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { if ( !metadata.light.exposure ) metadata.light.exposure = metadataJson["light"]["exposure"].as(1.0f); if ( !metadata.light.gamma ) metadata.light.gamma = metadataJson["light"]["gamma"].as(2.2f); #endif - /* Update lights */ if ( metadata.light.enabled ) { + /* Update lights */ if ( uf::renderer::settings::experimental::deferredMode != "vxgi" ) { ext::ExtSceneBehavior::bindBuffers( *this ); } @@ -456,7 +463,8 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re alignas(16) pod::Matrix4f iView[2]; alignas(16) pod::Matrix4f iProjection[2]; alignas(16) pod::Matrix4f iProjectionView[2]; - alignas(16) pod::Matrix4f ortho; + alignas(16) pod::Vector4f eyePos[2]; + alignas(16) pod::Matrix4f vxgi; } matrices; struct Mode { alignas(8) pod::Vector2ui type; @@ -482,12 +490,14 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re alignas(4) uint32_t textures = 0; alignas(4) uint32_t drawCalls = 0; } lengths; - alignas(16) pod::Vector4f ambient; - - alignas(4) uint32_t msaa; - alignas(4) uint32_t poissonSamples; + // alignas(16) pod::Vector4f ambient; + pod::Vector3f ambient; alignas(4) float gamma; + alignas(4) float exposure; + alignas(4) uint32_t msaa; + alignas(4) uint32_t shadowSamples; + alignas(4) uint32_t padding1; }; struct SpecializationConstant { uint32_t maxTextures = 512; @@ -536,7 +546,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re int shadowSamples = metadata.light.shadowSamples; int shadowThreshold = metadata.light.shadowThreshold; - if ( shadowSamples <= 0 ) shadowSamples = 16; + if ( shadowSamples < 0 ) shadowSamples = 0; if ( shadowThreshold <= 0 ) shadowThreshold = std::numeric_limits::max(); { std::vector scratch; @@ -565,14 +575,16 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re uniforms->matrices.iView[i] = uf::matrix::inverse( uniforms->matrices.view[i] ); uniforms->matrices.iProjection[i] = uf::matrix::inverse( uniforms->matrices.projection[i] ); uniforms->matrices.iProjectionView[i] = uf::matrix::inverse( uniforms->matrices.projection[i] * uniforms->matrices.view[i] ); + + uniforms->matrices.eyePos[i] = camera.getEye( i ); } uniforms->ambient = metadata.light.ambient; uniforms->msaa = ext::vulkan::settings::msaa; - uniforms->poissonSamples = shadowSamples; + uniforms->shadowSamples = shadowSamples; uniforms->exposure = metadata.light.exposure; uniforms->gamma = metadata.light.gamma; - + uniforms->fog.color = metadata.fog.color; uniforms->fog.color.w = metadata.fog.stepScale; @@ -598,10 +610,10 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re graphic.material.textures.clear(); if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id); //this->getComponent()); - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.normal); //this->getComponent()); - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.uv); //this->getComponent()); - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.albedo); //this->getComponent()); + for ( auto& t : sceneTextures.voxels.id ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.uv ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.normal ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.radiance ) graphic.material.textures.emplace_back().aliasTexture(t); } graphic.material.textures.emplace_back().aliasTexture(sceneTextures.noise); //this->getComponent()); @@ -645,33 +657,8 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re graphic.material.textures.emplace_back().aliasTexture(texture.texture); ++textureSlot; } - #if 1 } - uniforms->matrices.ortho = sceneTextures.voxels.matrix; - #else - // calculate extents - pod::Vector3f graphMin = uf::vector::decode( graph.metadata["extents"]["min"], pod::Vector3f{} ); - pod::Vector3f graphMax = uf::vector::decode( graph.metadata["extents"]["max"], pod::Vector3f{} ); - - min.x = std::min( min.x, graphMin.x ); - min.y = std::min( min.y, graphMin.y ); - min.z = std::min( min.z, graphMin.z ); - - max.x = std::max( max.x, graphMax.x ); - max.y = std::max( max.y, graphMax.y ); - 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 ); - - 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 ); - #endif + uniforms->matrices.vxgi = sceneTextures.voxels.matrix; uniforms->lengths.materials = std::min( materials.size(), maxTextures ); uniforms->lengths.textures = std::min( textures.size(), maxTextures ); uniforms->lengths.drawCalls = std::min( drawCalls.size(), maxTextures ); @@ -740,6 +727,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re graphic.updatePipelines(); } + shader.updateUniform( "UBO", uniform ); } } diff --git a/ext/behaviors/voxelizer/behavior.cpp b/ext/behaviors/voxelizer/behavior.cpp index 47dc7b45..6fecf387 100644 --- a/ext/behaviors/voxelizer/behavior.cpp +++ b/ext/behaviors/voxelizer/behavior.cpp @@ -28,7 +28,8 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { { const uint32_t DEFAULT_VOXEL_SIZE = ext::config["engine"]["scenes"]["vxgi"]["size"].as(256); const float DEFAULT_VOXELIZE_LIMITER = ext::config["engine"]["scenes"]["vxgi"]["limiter"].as(0); - const uint32_t DEFAULT_DISPATCH_LIMITER = ext::config["engine"]["scenes"]["vxgi"]["dispatch"].as(8); + const uint32_t DEFAULT_DISPATCH_SIZE = ext::config["engine"]["scenes"]["vxgi"]["dispatch"].as(8); + const uint32_t DEFAULT_CASCADES = ext::config["engine"]["scenes"]["vxgi"]["cascades"].as(8); if ( metadata.voxelSize.x == 0 ) metadata.voxelSize.x = DEFAULT_VOXEL_SIZE; if ( metadata.voxelSize.y == 0 ) metadata.voxelSize.y = DEFAULT_VOXEL_SIZE; @@ -36,33 +37,42 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { if ( metadata.renderer.limiter == 0 ) metadata.renderer.limiter = DEFAULT_VOXELIZE_LIMITER; - if ( metadata.dispatchSize.x == 0 ) metadata.dispatchSize.x = DEFAULT_DISPATCH_LIMITER; - if ( metadata.dispatchSize.y == 0 ) metadata.dispatchSize.y = DEFAULT_DISPATCH_LIMITER; - if ( metadata.dispatchSize.z == 0 ) metadata.dispatchSize.z = DEFAULT_DISPATCH_LIMITER; - + if ( metadata.dispatchSize.x == 0 ) metadata.dispatchSize.x = DEFAULT_DISPATCH_SIZE; + if ( metadata.dispatchSize.y == 0 ) metadata.dispatchSize.y = DEFAULT_DISPATCH_SIZE; + if ( metadata.dispatchSize.z == 0 ) metadata.dispatchSize.z = DEFAULT_DISPATCH_SIZE; + + if ( metadata.cascades == 0 ) metadata.cascades = DEFAULT_CASCADES; + metadata.extents.min = uf::vector::decode( ext::config["engine"]["scenes"]["vxgi"]["extents"]["min"], pod::Vector3f{-32, -32, -32} ); metadata.extents.max = uf::vector::decode( ext::config["engine"]["scenes"]["vxgi"]["extents"]["max"], pod::Vector3f{ 32, 32, 32} ); std::vector empty(metadata.voxelSize.x * metadata.voxelSize.y * metadata.voxelSize.z * sizeof(uint8_t) * 4); - sceneTextures.voxels.id.sampler.descriptor.filter.min = VK_FILTER_NEAREST; - sceneTextures.voxels.id.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; + for ( size_t i = 0; i < metadata.cascades; ++i ) { + auto& id = sceneTextures.voxels.id.emplace_back(); + auto& uv = sceneTextures.voxels.uv.emplace_back(); + auto& normal = sceneTextures.voxels.normal.emplace_back(); + auto& radiance = sceneTextures.voxels.radiance.emplace_back(); - sceneTextures.voxels.id.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_UINT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); - sceneTextures.voxels.normal.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); - sceneTextures.voxels.uv.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); - sceneTextures.voxels.albedo.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); + id.sampler.descriptor.filter.min = VK_FILTER_NEAREST; + id.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; + + id.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_UINT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); + uv.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); + normal.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); + radiance.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); + } } // initialize render mode { - // if ( metadata.fragmentSize.x == 0 ) metadata.fragmentSize.x = metadata.voxelSize.x * 2; - // if ( metadata.fragmentSize.y == 0 ) metadata.fragmentSize.y = metadata.voxelSize.y * 2; + if ( metadata.fragmentSize.x == 0 ) metadata.fragmentSize.x = metadata.voxelSize.x; + if ( metadata.fragmentSize.y == 0 ) metadata.fragmentSize.y = metadata.voxelSize.y; auto& renderMode = this->getComponent(); metadata.renderModeName = "VXGI:" + std::to_string((int) this->getUid()); uf::renderer::addRenderMode( &renderMode, metadata.renderModeName ); renderMode.metadata["type"] = "vxgi"; - renderMode.metadata["samples"] = 1; + renderMode.metadata["samples"] = 2; renderMode.blitter.device = &ext::vulkan::device; renderMode.width = metadata.fragmentSize.x; @@ -77,12 +87,13 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { renderMode.blitter.process = false; #endif - renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.id); //this->getComponent()); - renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.normal); //this->getComponent()); - renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.uv); //this->getComponent()); - renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.voxels.albedo); //this->getComponent()); - renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.noise); //this->getComponent()); - renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.skybox); //this->getComponent()); + for ( auto& t : sceneTextures.voxels.id ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.uv ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.normal ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.radiance ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t); + + renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.noise); + renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.skybox); renderMode.bindCallback( renderMode.CALLBACK_BEGIN, [&]( VkCommandBuffer commandBuffer ){ // clear textures @@ -94,10 +105,10 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { subresourceRange.layerCount = 1; VkClearColorValue clearColor = { 0.0, 0.0, 0.0, 0.0 }; - vkCmdClearColorImage( commandBuffer, sceneTextures.voxels.id.image, sceneTextures.voxels.id.imageLayout, &clearColor, 1, &subresourceRange ); - vkCmdClearColorImage( commandBuffer, sceneTextures.voxels.normal.image, sceneTextures.voxels.normal.imageLayout, &clearColor, 1, &subresourceRange ); - vkCmdClearColorImage( commandBuffer, sceneTextures.voxels.uv.image, sceneTextures.voxels.uv.imageLayout, &clearColor, 1, &subresourceRange ); - vkCmdClearColorImage( commandBuffer, sceneTextures.voxels.albedo.image, sceneTextures.voxels.albedo.imageLayout, &clearColor, 1, &subresourceRange ); + for ( auto& t : sceneTextures.voxels.id ) vkCmdClearColorImage( commandBuffer, t.image, t.imageLayout, &clearColor, 1, &subresourceRange ); + for ( auto& t : sceneTextures.voxels.normal ) vkCmdClearColorImage( commandBuffer, t.image, t.imageLayout, &clearColor, 1, &subresourceRange ); + for ( auto& t : sceneTextures.voxels.uv ) vkCmdClearColorImage( commandBuffer, t.image, t.imageLayout, &clearColor, 1, &subresourceRange ); + for ( auto& t : sceneTextures.voxels.radiance ) vkCmdClearColorImage( commandBuffer, t.image, t.imageLayout, &clearColor, 1, &subresourceRange ); }); renderMode.bindCallback( renderMode.CALLBACK_END, [&]( VkCommandBuffer commandBuffer ){ // parse voxel lighting @@ -113,24 +124,25 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.baseMipLevel = 0; subresourceRange.baseArrayLayer = 0; - subresourceRange.levelCount = sceneTextures.voxels.albedo.mips; subresourceRange.layerCount = 1; - - sceneTextures.voxels.albedo.setImageLayout( - commandBuffer, - sceneTextures.voxels.albedo.image, - sceneTextures.voxels.albedo.imageLayout, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - subresourceRange - ); - sceneTextures.voxels.albedo.generateMipmaps( commandBuffer, 0 ); - sceneTextures.voxels.albedo.setImageLayout( - commandBuffer, - sceneTextures.voxels.albedo.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - sceneTextures.voxels.albedo.imageLayout, - subresourceRange - ); + for ( auto& t : sceneTextures.voxels.radiance ) { + subresourceRange.levelCount = t.mips; + t.setImageLayout( + commandBuffer, + t.image, + t.imageLayout, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + subresourceRange + ); + t.generateMipmaps( commandBuffer, 0 ); + t.setImageLayout( + commandBuffer, + t.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + t.imageLayout, + subresourceRange + ); + } }); } #endif @@ -145,9 +157,10 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) { auto& scene = uf::scene::getCurrentScene(); auto& sceneTextures = scene.getComponent(); auto& controller = scene.getController(); - auto& controllerTransform = controller.getComponent>(); + auto controllerTransform = uf::transform::flatten( controller.getComponent().getTransform() ); renderMode.setTarget(""); - if ( renderMode.executed ) { + + if ( renderMode.executed ) { if ( !metadata.initialized ) metadata.initialized = true; if ( metadata.renderer.limiter > 0 ) { @@ -159,50 +172,42 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) { renderMode.execute = false; } } - #if 0 if ( renderMode.execute ) { - pod::Vector3f min = metadata.extents.min; - pod::Vector3f max = metadata.extents.max; + pod::Vector3f controllerPosition = controllerTransform.position; + controllerPosition.x = floor(controllerPosition.x); + controllerPosition.y = floor(controllerPosition.y); + controllerPosition.z = -floor(controllerPosition.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); + pod::Vector3f min = metadata.extents.min + controllerPosition; + pod::Vector3f max = metadata.extents.max + controllerPosition; sceneTextures.voxels.matrix = uf::matrix::ortho( min.x, max.x, min.y, max.y, min.z, max.z ); + + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; + auto& graphic = entity->getComponent(); + if ( graphic.material.hasShader("geometry", "vxgi") ) { + auto& shader = graphic.material.getShader("geometry", "vxgi"); + + auto& sceneTextures = scene.getComponent(); + struct UniformDescriptor { + alignas(16) pod::Matrix4f matrix; + }; + auto& uniform = shader.getUniform("UBO"); + auto& uniforms = uniform.get(); + uniforms.matrix = sceneTextures.voxels.matrix; + shader.updateUniform( "UBO", uniform ); + } + } } - #endif } #if COMP_SHADER_USED ext::ExtSceneBehavior::bindBuffers( scene, metadata.renderModeName, true ); + ext::ExtSceneBehavior::bindBuffers( scene ); #endif #endif } -void ext::VoxelizerBehavior::render( uf::Object& self ){ - auto& metadata = this->getComponent(); - auto& renderMode = this->getComponent(); - - auto& scene = uf::scene::getCurrentScene(); - auto& sceneTextures = scene.getComponent(); - auto& controller = scene.getController(); - auto& controllerTransform = controller.getComponent>(); - - if ( uf::renderer::currentRenderMode->getName() != "RenderTarget" && renderMode.execute ) { - pod::Vector3f min = metadata.extents.min; - pod::Vector3f max = metadata.extents.max; - - 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); - sceneTextures.voxels.matrix = uf::matrix::ortho( min.x, max.x, min.y, max.y, min.z, max.z ); - } -} +void ext::VoxelizerBehavior::render( uf::Object& self ){} void ext::VoxelizerBehavior::destroy( uf::Object& self ){ #if UF_USE_VULKAN if ( this->hasComponent() ) { diff --git a/ext/behaviors/voxelizer/behavior.h b/ext/behaviors/voxelizer/behavior.h index 1083ef8a..36a26303 100644 --- a/ext/behaviors/voxelizer/behavior.h +++ b/ext/behaviors/voxelizer/behavior.h @@ -20,6 +20,7 @@ namespace ext { pod::Vector3ui voxelSize = { 0, 0, 0 }; pod::Vector3ui dispatchSize = { 0, 0, 0 }; std::string renderModeName = "VXGI"; + size_t cascades = 0; struct { pod::Vector3f min = {}; pod::Vector3f max = {};