diff --git a/bin/data/shaders/display/subpass.frag.glsl b/bin/data/shaders/display/subpass.frag.glsl index 6ca182ee..face4f81 100644 --- a/bin/data/shaders/display/subpass.frag.glsl +++ b/bin/data/shaders/display/subpass.frag.glsl @@ -4,10 +4,6 @@ #define MULTISAMPLING 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 @@ -58,6 +54,8 @@ struct Matrices { struct Ray { vec3 origin; vec3 direction; + + vec3 position; float distance; }; @@ -165,6 +163,14 @@ struct Surface { vec4 fragment; } surface; +struct Voxel { + uvec2 id; + vec3 position; + vec3 normal; + vec2 uv; + vec4 color; +}; + #if !MULTISAMPLING layout (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId; layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal; @@ -331,7 +337,7 @@ void fog( in Ray ray, inout vec3 i, float scale ) { i.rgb = mix(ubo.fog.color.rgb, i.rgb, transmittance); } #endif - +#if 0 const vec3 color = ubo.fog.color.rgb; const float inner = ubo.fog.range.x; const float outer = ubo.fog.range.y * scale; @@ -339,6 +345,7 @@ void fog( in Ray ray, inout vec3 i, float scale ) { const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 ); i.rgb = mix(i.rgb, color, factor); +#endif } vec3 decodeNormals( vec2 enc ) { @@ -544,6 +551,7 @@ void main() { } else { surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion; } + // corrections surface.material.roughness *= 4.0; diff --git a/bin/data/shaders/display/subpass.vxgi.frag.glsl b/bin/data/shaders/display/subpass.vxgi.frag.glsl index 2f70696b..e8edc0e2 100644 --- a/bin/data/shaders/display/subpass.vxgi.frag.glsl +++ b/bin/data/shaders/display/subpass.vxgi.frag.glsl @@ -4,7 +4,7 @@ #define MULTISAMPLING 1 #define DEFERRED_SAMPLING 1 -#define VXGI_NDC 0 +#define VXGI_NDC 1 #define VXGI_SHADOWS 1 #define FOG 1 @@ -42,8 +42,9 @@ const vec2 poissonDisk[16] = vec2[]( vec2( 0.14383161, -0.14100790 ) ); -layout (constant_id = 0) const uint TEXTURES = 256; -layout (constant_id = 1) const uint CASCADES = 1; +#define MAX_CASCADES 4 +layout (constant_id = 0) const uint CASCADES = MAX_CASCADES; +layout (constant_id = 1) const uint TEXTURES = 256; struct Matrices { mat4 view[2]; @@ -346,7 +347,7 @@ void fog( in Ray ray, inout vec3 i, float scale ) { i.rgb = mix(ubo.fog.color.rgb, i.rgb, transmittance); } #endif - +#if 0 const vec3 color = ubo.fog.color.rgb; const float inner = ubo.fog.range.x; const float outer = ubo.fog.range.y * scale; @@ -354,6 +355,7 @@ void fog( in Ray ray, inout vec3 i, float scale ) { const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 ); i.rgb = mix(i.rgb, color, factor); +#endif } vec3 decodeNormals( vec2 enc ) { @@ -450,17 +452,12 @@ vec4 postProcess() { return vec4(surface.fragment.rgb,1); } -Voxel getVoxel( vec3 P ) { - const vec3 uvw = vec3( ubo.matrices.vxgi * vec4( P, 1.0f ) ) * 0.5f + 0.5f; - - Voxel voxel; - voxel.id = uvec2(texture(voxelId[0], uvw).xy); - voxel.position = P; - voxel.normal = decodeNormals( texture(voxelNormal[0], uvw).xy ); - voxel.uv = texture(voxelUv[0], uvw).xy; - voxel.color = texture(voxelRadiance[0], uvw).rgba; - - return voxel; +uint BIASED_ROUND( float x ) { + return uint( x < 255.0 / 256.0 ? floor(x) : ceil(x)); +} +#define CASCADE_POWER 2 +uint SCALE_CASCADE( uint x ) { + return uint(pow(1 + x, CASCADE_POWER)); } struct VoxelInfo { @@ -476,24 +473,36 @@ struct VoxelInfo { } voxelInfo; vec4 voxelTrace( inout Ray ray, float aperture, float maxDistance ) { + uint CASCADE = 1; #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); + const float granularity = 1.0f / 32.0f; + const uint maxSteps = uint(voxelInfo.radianceSize * 2 * CASCADES); + + CASCADE = BIASED_ROUND(clamp( max( max( abs(ray.origin.x), abs(ray.origin.y) ), abs(ray.origin.z) ), 0, CASCADES - 1 )); #else - const float granularity = 10.0f; - const uint maxSteps = uint(voxelInfo.radianceSize * granularity); + const float granularity = 16.0f; + const uint maxSteps = uint(voxelInfo.radianceSize * granularity * CASCADES); + { + vec3 uvw = vec3( ubo.matrices.vxgi * vec4( ray.origin, 1.0 ) ); + CASCADE = BIASED_ROUND(clamp( max( max( abs(uvw.x), abs(uvw.y) ), abs(uvw.z) ), 0, CASCADES - 1 )); + } #endif const float granularityRecip = 1.0f / granularity; // box - 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; + const vec2 rayBoxInfoA = rayBoxDst( voxelInfo.min * SCALE_CASCADE(CASCADE), voxelInfo.max * SCALE_CASCADE(CASCADE), ray ); + const vec2 rayBoxInfoB = rayBoxDst( voxelInfo.min * SCALE_CASCADE(CASCADES), voxelInfo.max * SCALE_CASCADE(CASCADES), ray ); + const float tStart = rayBoxInfoA.x; + const float tEnd = maxDistance > 0 ? min(maxDistance, rayBoxInfoB.y * SCALE_CASCADE(CASCADES)) : rayBoxInfoB.y * SCALE_CASCADE(CASCADES); // steps const float tDelta = voxelInfo.voxelSize * granularityRecip; // marcher +#if VXGI_NDC + ray.distance = tStart + tDelta * granularityRecip * 0.25; +#else ray.distance = tStart + tDelta * granularity; +#endif ray.position = vec3(0); vec4 radiance = vec4(0); vec3 uvw = vec3(0); @@ -505,22 +514,76 @@ vec4 voxelTrace( inout Ray ray, float aperture, float maxDistance ) { vec4 color = vec4(0); float occlusion = 0.0; uint stepCounter = 0; - const float falloff = 32.0f; // maxDistance > 0.0 ? 0.0f : 256.0f; - const vec3 voxelBoundsRecip = 1.0f / (voxelInfo.max - voxelInfo.min); -// while ( ray.distance < tEnd && color.a < 1.0 && occlusion < 1.0 && stepCounter++ < maxSteps ) { - while ( ray.distance < tEnd && color.a < 1.0 && occlusion < 1.0 ) { + const float falloff = 128.0f; // maxDistance > 0.0 ? 0.0f : 256.0f; + const vec3 voxelBounds = voxelInfo.max - voxelInfo.min; + const vec3 voxelBoundsRecip = 1.0f / voxelBounds; +#if VXGI_NDC + while ( ray.distance < tEnd && color.a < 1.0 && occlusion < 1.0 && stepCounter++ < maxSteps ) { +#else + while ( color.a < 1.0 && stepCounter++ < maxSteps ) { +#endif 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; + uvw = ray.position; #else - uvw = (ray.position - voxelInfo.min) * voxelBoundsRecip; + uvw = vec3( ubo.matrices.vxgi * vec4( ray.position, 1.0 ) ); #endif - if ( abs(uvw.x) > 1.0 || abs(uvw.y) > 1.0 || abs(uvw.z) > 1.0 ) break; + CASCADE = BIASED_ROUND(clamp( max( max( abs(uvw.x), abs(uvw.y) ), abs(uvw.z) ), 0, CASCADES - 1 )); + + uvw = (uvw / SCALE_CASCADE(CASCADE)) * 0.5 + 0.5; + + if ( CASCADE >= CASCADES || uvw.x < 0.0 || uvw.y < 0.0 || uvw.z < 0.0 || uvw.x >= 1.0 || uvw.y >= 1.0 || uvw.z >= 1.0 ) break; + coneDiameter = coneCoefficient * ray.distance; - level = log2( coneDiameter ); + level = aperture > 0 ? log2( coneDiameter ) : 0; + if ( level >= voxelInfo.mipmapLevels ) break; - radiance = textureLod(voxelRadiance[0], uvw.xzy, level); + + // radiance = textureLod(voxelRadiance[CASCADE], uvw.xzy, level); + #define C 0 + #if C < MAX_CASCADES + if ( CASCADE == C && C < CASCADES ) radiance = textureLod(voxelRadiance[C], uvw.xzy, level); + #endif + #undef C + #define C 1 + #if C < MAX_CASCADES + if ( CASCADE == C && C < CASCADES ) radiance = textureLod(voxelRadiance[C], uvw.xzy, level); + #endif + #undef C + #define C 2 + #if C < MAX_CASCADES + if ( CASCADE == C && C < CASCADES ) radiance = textureLod(voxelRadiance[C], uvw.xzy, level); + #endif + #undef C + #define C 3 + #if C < MAX_CASCADES + if ( CASCADE == C && C < CASCADES ) radiance = textureLod(voxelRadiance[C], uvw.xzy, level); + #endif + #undef C + #define C 4 + #if C < MAX_CASCADES + if ( CASCADE == C && C < CASCADES ) radiance = textureLod(voxelRadiance[C], uvw.xzy, level); + #endif + #undef C + #define C 5 + #if C < MAX_CASCADES + if ( CASCADE == C && C < CASCADES ) radiance = textureLod(voxelRadiance[C], uvw.xzy, level); + #endif + #undef C + #define C 6 + #if C < MAX_CASCADES + if ( CASCADE == C && C < CASCADES ) radiance = textureLod(voxelRadiance[C], uvw.xzy, level); + #endif + #undef C + #define C 7 + #if C < MAX_CASCADES + if ( CASCADE == C && C < CASCADES ) radiance = textureLod(voxelRadiance[C], uvw.xzy, level); + #endif + #undef C + + // else radiance = textureLod(voxelRadiance[CASCADE], uvw.xzy, level); color += (1.0 - color.a) * radiance; occlusion += ((1.0f - occlusion) * radiance.a) / (1.0f + falloff * coneDiameter); @@ -543,7 +606,11 @@ float shadowFactor( const Light light, float def ) { Ray ray; ray.origin = surface.position.world; ray.direction = normalize( light.position - surface.position.world ); +#if VXGI_NDC +// ray.origin -= ray.direction * 0.125; +#else ray.origin -= ray.direction * 0.5; +#endif float z = distance( surface.position.world, light.position ) - DEPTH_BIAS; return 1.0 - voxelTrace( ray, SHADOW_APERTURE, z ).a; } @@ -562,7 +629,7 @@ void main() { surface.position.eye = positionEye.xyz; surface.position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye ); } -#if 0 +#if 1 { 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)); @@ -720,12 +787,12 @@ void main() { } // outFragColor.rgb = voxelConeTrace( surface.ray, 0 ).rgb; return; - Ray ray; if ( DIFFUSE_INDIRECT_FACTOR > 0.0f ) { for ( uint i = 0; i < CONES_COUNT; ++i ) { float weight = i == 0 ? PI * 0.25f : PI * 0.15f; - ray.origin = P; + Ray ray; ray.direction = CONES[i].xyz; + ray.origin = P; // + ray.direction; indirectDiffuse += voxelConeTrace( ray, DIFFUSE_CONE_APERTURE ) * weight; } surface.material.occlusion = 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0); @@ -733,16 +800,11 @@ void main() { // outFragColor.rgb = vec3(surface.material.occlusion); return; } if ( SPECULAR_INDIRECT_FACTOR > 0.0f ) { - ray.origin = P; + Ray ray; ray.direction = reflect( normalize(P - surface.ray.origin), N ); + ray.origin = P; // + ray.direction; 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; - } - */ } surface.material.indirect = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR; // outFragColor.rgb = surface.material.indirect.rgb; return; diff --git a/bin/data/shaders/display/vxgi.comp.glsl b/bin/data/shaders/display/vxgi.comp.glsl index ee023243..92433a41 100644 --- a/bin/data/shaders/display/vxgi.comp.glsl +++ b/bin/data/shaders/display/vxgi.comp.glsl @@ -14,8 +14,8 @@ const float EPSILON = 0.00001; const float LIGHT_POWER_CUTOFF = 0.005; -layout (constant_id = 0) const uint TEXTURES = 256; -layout (constant_id = 1) const uint CASCADES = 1; +layout (constant_id = 0) const uint CASCADES = 4; +layout (constant_id = 1) const uint TEXTURES = 256; struct Matrices { mat4 view[2]; @@ -280,13 +280,18 @@ float shadowFactor( const Light light, float def ) { #endif } +#define CASCADE_POWER 2 +uint SCALE_CASCADE( uint x ) { + return uint(pow(1 + x, CASCADE_POWER)); +} + void main() { 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 ) ); - surface.position.eye = vec3(gl_GlobalInvocationID.xyz) / (vec3(imageSize(voxelRadiance[CASCADE])) / (CASCADE + 1)) * 2.0f - 1.0f; + surface.position.eye = (vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelRadiance[CASCADE])) * 2.0f - 1.0f) * SCALE_CASCADE(CASCADE); surface.position.world = vec3( inverse(ubo.matrices.vxgi) * vec4( surface.position.eye, 1.0f ) ); const uvec2 ID = uvec2(imageLoad(voxelId[CASCADE], ivec3(tUvw) ).xy); diff --git a/bin/data/shaders/gltf/voxelize.frag.glsl b/bin/data/shaders/gltf/voxelize.frag.glsl index cbec2c91..bd357dd6 100644 --- a/bin/data/shaders/gltf/voxelize.frag.glsl +++ b/bin/data/shaders/gltf/voxelize.frag.glsl @@ -5,8 +5,8 @@ #define PI 3.1415926536f -layout (constant_id = 0) const uint TEXTURES = 1; -layout (constant_id = 1) const uint CASCADES = 1; +layout (constant_id = 0) const uint CASCADES = 4; +layout (constant_id = 1) const uint TEXTURES = 256; struct Material { vec4 colorBase; @@ -86,9 +86,10 @@ bool validTextureIndex( int textureIndex ) { } void main() { - const vec3 P = inPosition.xzy; - const uint CASCADE = uint(max( abs(floor(P.x)), max( abs(floor(P.y)), abs(floor(P.z)) ) )); + const uint CASCADE = inId.z; if ( CASCADES <= CASCADE ) discard; + const vec3 P = inPosition.xzy * 0.5 + 0.5; + if ( abs(P.x) > 1 || abs(P.y) > 1 || abs(P.z) > 1 ) discard; vec4 A = vec4(0, 0, 0, 0); const vec3 N = inNormal; @@ -139,8 +140,8 @@ void main() { const vec2 outNormals = encodeNormals( normalize( N ) ); const vec2 outUvs = wrap(inUv.xy); - 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); + imageStore(voxelId[CASCADE], ivec3(P * imageSize(voxelId[CASCADE])), uvec4(outId, 0, 0)); + imageStore(voxelNormal[CASCADE], ivec3(P * imageSize(voxelNormal[CASCADE])), vec4(outNormals, 0, 0)); + imageStore(voxelUv[CASCADE], ivec3(P * imageSize(voxelUv[CASCADE])), vec4(outUvs, 0, 0)); + imageStore(voxelRadiance[CASCADE], ivec3(P * 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 e72b6496..870a8069 100644 --- a/bin/data/shaders/gltf/voxelize.geom.glsl +++ b/bin/data/shaders/gltf/voxelize.geom.glsl @@ -23,6 +23,11 @@ layout (binding = 6) uniform UBO { mat4 voxel; } ubo; +#define CASCADE_POWER 2 +uint SCALE_CASCADE( uint x ) { + return uint(pow(1 + x, CASCADE_POWER)); +} + void main(){ const float RENDER_RESOLUTION = 256.0; const float PIXEL_SCALE = 2.0; @@ -36,17 +41,27 @@ void main(){ uint A = N.y > N.x ? 1 : 0; A = N.z > N[A] ? 2 : A; #endif - for(uint i = 0; i < 3; ++i){ + + const uint CASCADE = inId[0].z; + vec3 P[3] = { + vec3( ubo.voxel * vec4( inPosition[0], 1 ) ) / SCALE_CASCADE(CASCADE), + vec3( ubo.voxel * vec4( inPosition[1], 1 ) ) / SCALE_CASCADE(CASCADE), + vec3( ubo.voxel * vec4( inPosition[2], 1 ) ) / SCALE_CASCADE(CASCADE), + }; + + + for( uint i = 0; i < 3; ++i ){ + const vec3 D = normalize( inPosition[i] - C ) * HALF_PIXEL; + outUv = inUv[i]; outSt = inSt[i]; outColor = inColor[i]; outNormal = inNormal[i]; outTBN = inTBN[i]; - outPosition = vec3( ubo.voxel * vec4( inPosition[i], 1 ) ) + normalize( inPosition[i] - C ) * HALF_PIXEL; + outPosition = P[i]; // + D; outId = inId[i]; - const vec3 P = fract(outPosition); - // const vec3 P = fract(outPosition + normalize( inPosition[i] - C ) * HALF_PIXEL); + const vec3 P = outPosition + D; #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); @@ -56,10 +71,6 @@ void main(){ 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; - - EmitVertex(); } EndPrimitive(); diff --git a/engine/src/ext/gltf/graph.cpp b/engine/src/ext/gltf/graph.cpp index 4d2e0b00..135323fe 100644 --- a/engine/src/ext/gltf/graph.cpp +++ b/engine/src/ext/gltf/graph.cpp @@ -93,8 +93,8 @@ namespace { { auto& shader = graphic.material.getShader("fragment", "vxgi"); struct SpecializationConstant { + uint32_t cascades = 4; uint32_t textures = 256; - uint32_t cascades = 2; }; auto& specializationConstants = shader.specializationConstants.get(); specializationConstants.textures = texture2Ds; diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index ba4c577a..aeb94dad 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -213,32 +213,31 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { auto& scene = uf::scene::getCurrentScene(); auto& shader = blitter.material.shaders.back(); - size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(256); - size_t maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(256); - - UF_DEBUG_MSG( maxLights << "\t" << maxTextures ); + auto& sceneMetadataJson = scene.getComponent(); + size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(256); + size_t maxTextures = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(256); + size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as(4); if ( ext::vulkan::settings::experimental::deferredMode == "vxgi" ) { struct SpecializationConstant { + uint32_t maxCascades = 4; 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); + specializationConstants.maxCascades = maxCascades; 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; + if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures; + else if ( name == "voxelId" ) layout.descriptorCount = maxCascades; + else if ( name == "voxelUv" ) layout.descriptorCount = maxCascades; + else if ( name == "voxelNormal" ) layout.descriptorCount = maxCascades; + else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades; } }); } else { @@ -247,14 +246,13 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { }; 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; + if ( layout.binding == binding ) layout.descriptorCount = maxTextures; } }); } diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 0d1de059..a4298f53 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -37,13 +37,14 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD descriptor.parse(metadata["descriptor"]); std::string type = metadata["type"].as(); std::string target = metadata["target"].as(); - if ( pass == 0 && type == "vxgi" ) { + size_t subpasses = metadata["subpasses"].as(); + if ( 0 <= pass && pass < subpasses && 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 ) { @@ -347,27 +348,29 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { auto& shader = blitter.material.getShader("compute"); struct SpecializationConstant { - uint32_t maxTextures = 512; - uint32_t maxCascades = 1; + uint32_t maxCascades = 4; + uint32_t maxTextures = 256; }; auto& specializationConstants = shader.specializationConstants.get(); - auto& metadata = scene.getComponent(); - 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); + auto& sceneMetadataJson = scene.getComponent(); + size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(256); + size_t maxTextures = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(256); + size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as(4); + specializationConstants.maxTextures = maxTextures; + specializationConstants.maxCascades = maxCascades; 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; + if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures; + else if ( name == "voxelId" ) layout.descriptorCount = maxCascades; + else if ( name == "voxelUv" ) layout.descriptorCount = maxCascades; + else if ( name == "voxelNormal" ) layout.descriptorCount = maxCascades; + else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades; } }); @@ -472,7 +475,6 @@ void ext::vulkan::RenderTargetRenderMode::render() { submitInfo.commandBufferCount = 1; VK_CHECK_RESULT(vkQueueSubmit(device->getQueue( Device::QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer])); - //vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[states::currentBuffer]); /* VkSemaphoreWaitInfo waitInfo = {}; waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; diff --git a/ext/behaviors/voxelizer/behavior.cpp b/ext/behaviors/voxelizer/behavior.cpp index 6fecf387..d8c8b4fa 100644 --- a/ext/behaviors/voxelizer/behavior.cpp +++ b/ext/behaviors/voxelizer/behavior.cpp @@ -14,7 +14,6 @@ #include "../scene/behavior.h" #include -#define COMP_SHADER_USED 1 UF_BEHAVIOR_REGISTER_CPP(ext::VoxelizerBehavior) #define this (&self) @@ -73,19 +72,16 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { uf::renderer::addRenderMode( &renderMode, metadata.renderModeName ); renderMode.metadata["type"] = "vxgi"; renderMode.metadata["samples"] = 2; + renderMode.metadata["subpasses"] = metadata.cascades; renderMode.blitter.device = &ext::vulkan::device; renderMode.width = metadata.fragmentSize.x; renderMode.height = metadata.fragmentSize.y; - #if COMP_SHADER_USED + renderMode.metadata["shaders"]["compute"] = "/shaders/display/vxgi.comp.spv"; renderMode.blitter.descriptor.renderMode = metadata.renderModeName; renderMode.blitter.descriptor.subpass = -1; renderMode.blitter.process = true; - #else - renderMode.metadata["shaders"] = false; - renderMode.blitter.process = false; - #endif 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); @@ -109,16 +105,48 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { 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 ); + + for ( auto& t : sceneTextures.voxels.radiance ) { + VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED + imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED + imageMemoryBarrier.subresourceRange.baseMipLevel = 0; + imageMemoryBarrier.subresourceRange.levelCount = t.mips; + imageMemoryBarrier.subresourceRange.baseArrayLayer = 0; + imageMemoryBarrier.subresourceRange.layerCount = 1; + imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + { + VkPipelineStageFlags srcStageMask, dstStageMask; + imageMemoryBarrier.image = t.image; + imageMemoryBarrier.oldLayout = t.imageLayout; + imageMemoryBarrier.newLayout = t.imageLayout; + + imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + + vkCmdPipelineBarrier( commandBuffer, + srcStageMask, dstStageMask, + VK_FLAGS_NONE, + 0, NULL, + 0, NULL, + 1, &imageMemoryBarrier + ); + + t.imageLayout = imageMemoryBarrier.newLayout; + } + } }); renderMode.bindCallback( renderMode.CALLBACK_END, [&]( VkCommandBuffer commandBuffer ){ // parse voxel lighting - #if COMP_SHADER_USED if ( renderMode.blitter.initialized ) { auto& pipeline = renderMode.blitter.getPipeline(); pipeline.record(renderMode.blitter, commandBuffer); vkCmdDispatch(commandBuffer, metadata.voxelSize.x / metadata.dispatchSize.x, metadata.voxelSize.y / metadata.dispatchSize.y, metadata.voxelSize.z / metadata.dispatchSize.z); } - #endif + // generate mipmaps VkImageSubresourceRange subresourceRange = {}; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -143,6 +171,40 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { subresourceRange ); } + + // sync + for ( auto& t : sceneTextures.voxels.radiance ) { + VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED + imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED + imageMemoryBarrier.subresourceRange.baseMipLevel = 0; + imageMemoryBarrier.subresourceRange.levelCount = t.mips; + imageMemoryBarrier.subresourceRange.baseArrayLayer = 0; + imageMemoryBarrier.subresourceRange.layerCount = 1; + imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + { + VkPipelineStageFlags srcStageMask, dstStageMask; + imageMemoryBarrier.image = t.image; + imageMemoryBarrier.oldLayout = t.imageLayout; + imageMemoryBarrier.newLayout = t.imageLayout; + + imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + + vkCmdPipelineBarrier( commandBuffer, + srcStageMask, dstStageMask, + VK_FLAGS_NONE, + 0, NULL, + 0, NULL, + 1, &imageMemoryBarrier + ); + + t.imageLayout = imageMemoryBarrier.newLayout; + } + } }); } #endif @@ -201,11 +263,9 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) { } } } -#if COMP_SHADER_USED ext::ExtSceneBehavior::bindBuffers( scene, metadata.renderModeName, true ); ext::ExtSceneBehavior::bindBuffers( scene ); #endif -#endif } void ext::VoxelizerBehavior::render( uf::Object& self ){} void ext::VoxelizerBehavior::destroy( uf::Object& self ){ diff --git a/ext/main.cpp b/ext/main.cpp index e1542ce4..3193e0d5 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -234,6 +234,13 @@ void EXT_API ext::initialize() { } } + /* Create initial scene (kludge) */ { + uf::Scene& scene = uf::instantiator::instantiate(); //new uf::Scene; + uf::scene::scenes.push_back(&scene); + auto& metadata = scene.getComponent(); + metadata["system"]["config"] = ::config; + } + if ( ::config["engine"]["limiters"]["framerate"].as() == "auto" && ::config["window"]["refresh rate"].is() ) { double scale = 1.0; size_t refreshRate = ::config["window"]["refresh rate"].as(); @@ -275,9 +282,6 @@ void EXT_API ext::initialize() { ::config["engine"]["threads"]["workers"] = threads; uf::iostream << "Using " << threads << " worker threads" << "\n"; } - if ( ::config["engine"]["scenes"]["use graph"].is() ) { - uf::scene::useGraph = ::config["engine"]["scenes"]["use graph"].as(); - } #if UF_USE_BULLET // set bullet parameters @@ -423,13 +427,6 @@ void EXT_API ext::initialize() { #endif } - /* Create initial scene (kludge) */ { - uf::Scene& scene = uf::instantiator::instantiate(); //new uf::Scene; - uf::scene::scenes.push_back(&scene); - auto& metadata = scene.getComponent(); - metadata["system"]["config"] = ::config; - } - /* Initialize Vulkan */ { #if UF_USE_VULKAN // setup render mode @@ -440,8 +437,9 @@ void EXT_API ext::initialize() { } if ( ::config["engine"]["render modes"]["deferred"].as() ) { uf::renderer::addRenderMode( new uf::renderer::DeferredRenderMode, "" ); + auto& renderMode = uf::renderer::getRenderMode("Deferred", true); + // renderMode.metadata["system"]["config"] = ::config; if ( ::config["engine"]["render modes"]["stereo deferred"].as() ) { - auto& renderMode = uf::renderer::getRenderMode("Deferred", true); renderMode.metadata["eyes"] = 2; } }