rabbithole of swapping VXGI to SVOGI (currently enabled arbitrary regions to voxelize into (mostly working)), repaired shadowmaps (kind of flickers from depth precision when moving), to-do: fix annoying race issue when GPU is under load that is not fixed with N-buffered attachments, but is fixed with vkDeviceWaitIdle (although this is a horribad bandaid fix)
This commit is contained in:
parent
08134804cf
commit
a43b1567b3
@ -3,10 +3,10 @@
|
||||
"scenes": {
|
||||
"start": "StartMenu",
|
||||
"lights": { "enabled": true,
|
||||
"lightmaps": true,
|
||||
"lightmaps": false,
|
||||
"max": 32,
|
||||
"shadows": {
|
||||
"enabled": false,
|
||||
"enabled": true,
|
||||
"update": 4,
|
||||
"max": 16,
|
||||
"samples": 1
|
||||
@ -27,17 +27,15 @@
|
||||
}
|
||||
},
|
||||
"vxgi": {
|
||||
"limiter": 0,
|
||||
// "limiter": 0.0125,
|
||||
// "limiter": 5,
|
||||
// "limiter": 0,
|
||||
"limiter": 0.0125,
|
||||
// "limiter": 1,
|
||||
"size": 256,
|
||||
"dispatch": 16,
|
||||
"cascades": 3,
|
||||
"cascadePower": 1.5,
|
||||
"regions": 3,
|
||||
"granularity": 32,
|
||||
"voxelizeScale": 1,
|
||||
"occlusionFalloff": 2,
|
||||
"traceStartOffsetFactor": 1,
|
||||
"traceStartOffsetFactor": 0.1,
|
||||
"filtering": "LINEAR",
|
||||
"shadows": 0,
|
||||
"extents": {
|
||||
|
||||
@ -15,7 +15,7 @@ layout (binding = 6, set = 1) uniform sampler2D samplerTextures[TEXTURES];
|
||||
layout (binding = 7, set = 1) uniform samplerCube samplerCubemaps[CUBEMAPS];
|
||||
layout (binding = 8, set = 0) uniform sampler3D samplerNoise;
|
||||
#if VXGI
|
||||
layout (binding = 9, set = 0) uniform sampler3D voxelOutput[CASCADES];
|
||||
layout (binding = 9, set = 0) uniform sampler3D voxelOutput[REGIONS];
|
||||
#endif
|
||||
#if RT
|
||||
layout (binding = 10, set = 0) uniform accelerationStructureEXT tlas;
|
||||
|
||||
@ -231,12 +231,6 @@ vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) {
|
||||
const float tEnd = max(0, min( tmax.x, min(tmax.y, tmax.z) ) - tStart);
|
||||
return vec2(tStart, tEnd);
|
||||
}
|
||||
#if VXGI
|
||||
float cascadePower( uint x ) {
|
||||
return pow(1 + x, ubo.settings.vxgi.cascadePower);
|
||||
// return max( 1, x * ubo.settings.vxgi.cascadePower );
|
||||
}
|
||||
#endif
|
||||
#if FRAGMENT
|
||||
void whitenoise(inout vec3 color, const vec4 parameters) {
|
||||
const float flicker = parameters.x;
|
||||
|
||||
@ -250,17 +250,10 @@ struct SettingsBloom {
|
||||
uint padding;
|
||||
};
|
||||
struct SettingsVxgi {
|
||||
mat4 matrix;
|
||||
|
||||
float cascadePower;
|
||||
float granularity;
|
||||
float voxelizeScale;
|
||||
float occlusionFalloff;
|
||||
|
||||
float traceStartOffsetFactor;
|
||||
uint shadows;
|
||||
uint padding2;
|
||||
uint padding3;
|
||||
};
|
||||
struct SettingsRayTrace {
|
||||
vec2 defaultRayBounds;
|
||||
@ -326,4 +319,11 @@ struct RayTracePayload {
|
||||
uint primitiveID;
|
||||
vec2 attributes;
|
||||
// Triangle triangle;
|
||||
};
|
||||
|
||||
struct Region {
|
||||
vec3 minBounds;
|
||||
uint index;
|
||||
vec3 maxBounds;
|
||||
uint size;
|
||||
};
|
||||
@ -1,100 +1,87 @@
|
||||
// GI
|
||||
float cascadeScales[CASCADES];
|
||||
float cascadeScalesInv[CASCADES];
|
||||
void precomputeCascades() {
|
||||
for ( int i = 0; i < CASCADES; ++i ) {
|
||||
cascadeScales[i] = cascadePower(i);
|
||||
cascadeScalesInv[i] = 1.0 / cascadeScales[i];
|
||||
uint findRegion(vec3 pos) {
|
||||
for ( uint i = 0; i < regions.length(); ++i ) {
|
||||
Region r = regions[i];
|
||||
if ( all(greaterThanEqual(pos, r.minBounds)) && all(lessThanEqual(pos, r.maxBounds)) ) return i;
|
||||
}
|
||||
return regions.length();
|
||||
}
|
||||
|
||||
vec4 voxelTrace( inout Ray ray, float aperture, float maxDistance ) {
|
||||
ray.direction.x = abs(ray.direction.x) < 0.00001 ? 0.00001 : ray.direction.x;
|
||||
ray.direction.y = abs(ray.direction.y) < 0.00001 ? 0.00001 : ray.direction.y;
|
||||
ray.direction.z = abs(ray.direction.z) < 0.00001 ? 0.00001 : ray.direction.z;
|
||||
|
||||
ray.origin += ray.direction * voxelInfo.radianceSizeRecip * 1.5;
|
||||
|
||||
#if VXGI_NDC
|
||||
ray.origin = vec3( ubo.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) );
|
||||
ray.direction = vec3( ubo.settings.vxgi.matrix * vec4( ray.direction, 0.0 ) );
|
||||
float absMax = max3(abs(ray.origin));
|
||||
#else
|
||||
const float voxelOrigin = vec3( ubo.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) );
|
||||
float absMax = max3(abs(voxelOrigin));
|
||||
#endif
|
||||
uint regionIdx = findRegion(ray.origin);
|
||||
if (regionIdx == regions.length()) return vec4(0);
|
||||
|
||||
uint cascade = 0;
|
||||
for ( uint c = 0; c < CASCADES - 1; ++c ) {
|
||||
if ( absMax * cascadeScalesInv[c] < (1.0 - voxelInfo.radianceSizeRecip)) {
|
||||
cascade = c;
|
||||
break;
|
||||
}
|
||||
cascade = CASCADES - 1;
|
||||
}
|
||||
|
||||
const float maxCascadeScale = cascadeScales[CASCADES-1];
|
||||
float currentCascadeScale = cascadeScales[cascade];
|
||||
float currentCascadeScaleInv = cascadeScalesInv[cascade];
|
||||
Region region = regions[regionIdx];
|
||||
|
||||
const float granularity = ubo.settings.vxgi.granularity;
|
||||
const float occlusionFalloff = ubo.settings.vxgi.occlusionFalloff;
|
||||
const float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
||||
|
||||
const uint maxSteps = uint(voxelInfo.radianceSize * maxCascadeScale * granularity);
|
||||
|
||||
const uint maxSteps = uint(region.size * granularity);
|
||||
const float maxRadiance = 0.90;
|
||||
// box
|
||||
const vec2 rayBoxInfoA = rayBoxDst( voxelInfo.min * currentCascadeScale, voxelInfo.max * currentCascadeScale, ray );
|
||||
const vec2 rayBoxInfoB = rayBoxDst( voxelInfo.min * maxCascadeScale, voxelInfo.max * maxCascadeScale, ray );
|
||||
|
||||
const float tStart = rayBoxInfoA.x;
|
||||
const float tEnd = maxDistance > 0 ? min(maxDistance, rayBoxInfoB.y) : rayBoxInfoB.y;
|
||||
const float tDelta = voxelInfo.radianceSizeRecip * granularity;
|
||||
const vec2 rayBoxInfo = rayBoxDst( region.minBounds, region.maxBounds, ray );
|
||||
const float tStart = rayBoxInfo.x;
|
||||
const float tEnd = maxDistance > 0 ? min(maxDistance, rayBoxInfo.y) : rayBoxInfo.y;
|
||||
|
||||
float voxelWorldSize = (region.maxBounds.x - region.minBounds.x) / float(region.size);
|
||||
float tDelta = voxelWorldSize * granularity;
|
||||
|
||||
// marcher
|
||||
ray.distance = tStart + tDelta * ubo.settings.vxgi.traceStartOffsetFactor;
|
||||
ray.position = vec3(0);
|
||||
ray.distance += tDelta * rand2(gl_GlobalInvocationID.xy);
|
||||
|
||||
vec4 radiance = vec4(0);
|
||||
vec3 uvw = vec3(0);
|
||||
float coneDiameter = coneCoefficient * ray.distance;
|
||||
float level = aperture > 0 ? log2( coneDiameter ) : 0;
|
||||
vec4 color = vec4(0);
|
||||
float occlusion = 0;
|
||||
uint stepCounter = 0;
|
||||
|
||||
ray.distance += tDelta * rand2(gl_GlobalInvocationID.xy);
|
||||
|
||||
while ( color.a < maxRadiance && occlusion < 1.0 && ray.distance < tEnd && stepCounter++ < maxSteps ) {
|
||||
float stepScale = max(1.0, (coneDiameter * currentCascadeScale) * 1.5);
|
||||
float coneDiameter = coneCoefficient * ray.distance;
|
||||
float stepScale = max(1.0, (coneDiameter * float(region.size)) * 1.5);
|
||||
|
||||
ray.distance += tDelta * stepScale;
|
||||
ray.position = ray.origin + ray.direction * ray.distance;
|
||||
|
||||
absMax = max3(abs(ray.position));
|
||||
if ( absMax * currentCascadeScaleInv > 0.99 ) {
|
||||
if ( ++cascade >= CASCADES ) break;
|
||||
if (any(lessThan(ray.position, region.minBounds)) || any(greaterThan(ray.position, region.maxBounds))) {
|
||||
regionIdx = findRegion(ray.position);
|
||||
if (regionIdx == regions.length()) break;
|
||||
|
||||
currentCascadeScale = cascadeScales[cascade];
|
||||
currentCascadeScaleInv = cascadeScalesInv[cascade];
|
||||
region = regions[regionIdx];
|
||||
|
||||
ray.distance += tDelta * currentCascadeScale;
|
||||
continue;
|
||||
voxelWorldSize = (region.maxBounds.x - region.minBounds.x) / float(region.size);
|
||||
tDelta = voxelWorldSize * granularity;
|
||||
}
|
||||
|
||||
uvw = ray.position * currentCascadeScaleInv * 0.5 + 0.5;
|
||||
coneDiameter = coneCoefficient * ray.distance;
|
||||
level = aperture > 0 ? log2( coneDiameter ) : 0;
|
||||
vec3 uvw = (ray.position - region.minBounds) / (region.maxBounds - region.minBounds);
|
||||
|
||||
float level = aperture > 0 ? log2( coneDiameter * float(region.size) ) : 0;
|
||||
vec4 radiance = textureLod(voxelOutput[nonuniformEXT(regionIdx)], uvw, level);
|
||||
|
||||
radiance = textureLod(voxelOutput[nonuniformEXT(cascade)], uvw.xzy, level);
|
||||
|
||||
color.rgb += (1.0 - color.a) * radiance.rgb * radiance.a;
|
||||
color.a += (1.0 - color.a) * radiance.a;
|
||||
|
||||
occlusion += ((1.0f - occlusion) * radiance.a) / (1.0f + occlusionFalloff * coneDiameter);
|
||||
}
|
||||
return maxDistance > 0 ? color : vec4(color.rgb, occlusion);
|
||||
|
||||
vec4 finalColor = maxDistance > 0 ? color : vec4(color.rgb, occlusion);
|
||||
|
||||
// if (any(isnan(finalColor)) || any(isinf(finalColor))) return vec4(0.0);
|
||||
|
||||
return finalColor;
|
||||
}
|
||||
|
||||
vec4 voxelConeTrace( inout Ray ray, float aperture ) {
|
||||
return voxelTrace( ray, aperture, 0 );
|
||||
return voxelTrace( ray, aperture, 4096.0 );
|
||||
}
|
||||
|
||||
vec4 voxelTrace( inout Ray ray, float maxDistance ) {
|
||||
return voxelTrace( ray, 0, maxDistance );
|
||||
return voxelTrace( ray, 0.0, maxDistance );
|
||||
}
|
||||
|
||||
uint voxelShadowsCount = 0;
|
||||
float shadowFactorVXGI( const Light light, float def ) {
|
||||
if ( ubo.settings.vxgi.shadows < ++voxelShadowsCount ) return 1.0;
|
||||
@ -109,20 +96,12 @@ float shadowFactorVXGI( const Light light, float def ) {
|
||||
return 1.0 - voxelTrace( ray, SHADOW_APERTURE, z ).a;
|
||||
}
|
||||
void indirectLightingVXGI() {
|
||||
precomputeCascades();
|
||||
|
||||
voxelInfo.radianceSize = textureSize( voxelOutput[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 );
|
||||
#else
|
||||
const mat4 inverseOrtho = inverse( ubo.settings.vxgi.matrix );
|
||||
voxelInfo.min = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) );
|
||||
voxelInfo.max = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) );
|
||||
#endif
|
||||
voxelInfo.min = vec3( -1.0 );
|
||||
voxelInfo.max = vec3( 1.0 );
|
||||
|
||||
vec4 indirectDiffuse = vec4(0);
|
||||
vec4 indirectSpecular = vec4(0);
|
||||
@ -135,12 +114,12 @@ void indirectLightingVXGI() {
|
||||
|
||||
#if 0
|
||||
{
|
||||
Ray ray;
|
||||
ray.direction = N;
|
||||
ray.origin = P + N * (voxelInfo.radianceSizeRecip * 4.0);
|
||||
Ray ray;
|
||||
ray.direction = N;
|
||||
ray.origin = P + N * (voxelInfo.radianceSizeRecip * 4.0);
|
||||
|
||||
indirectDiffuse = voxelConeTrace(ray, 1.0f);
|
||||
surface.material.occlusion += 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0);
|
||||
indirectDiffuse = voxelConeTrace(ray, 1.0f);
|
||||
surface.material.occlusion += 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0);
|
||||
}
|
||||
#else
|
||||
const uint CONES_COUNT = 4;
|
||||
@ -159,7 +138,7 @@ void indirectLightingVXGI() {
|
||||
for ( uint i = 0; i < CONES_COUNT; ++i ) {
|
||||
Ray ray;
|
||||
ray.direction = CONES[i].xyz;
|
||||
ray.origin = P; // + ray.direction;
|
||||
ray.origin = P;
|
||||
indirectDiffuse += voxelConeTrace( ray, DIFFUSE_CONE_APERTURE ) * weight;
|
||||
weight = PI * 0.15f;
|
||||
}
|
||||
@ -168,22 +147,21 @@ void indirectLightingVXGI() {
|
||||
indirectDiffuse *= DIFFUSE_INDIRECT_FACTOR;
|
||||
#endif
|
||||
|
||||
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.0f - surface.material.metallic) * (1.0f - surface.material.roughness); // * 0.25; // 1.0f;
|
||||
const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * surface.material.roughness), 0.0174533f, PI);
|
||||
const float SPECULAR_INDIRECT_FACTOR = (1.0f - surface.material.metallic) * (1.0f - surface.material.roughness);
|
||||
if ( SPECULAR_INDIRECT_FACTOR > 0.0f ) {
|
||||
const vec3 R = reflect( normalize(P - surface.ray.origin), N );
|
||||
Ray ray;
|
||||
ray.direction = R;
|
||||
ray.origin = P; // + ray.direction;
|
||||
ray.origin = P;
|
||||
indirectSpecular = voxelConeTrace( ray, SPECULAR_CONE_APERTURE );
|
||||
}
|
||||
indirectSpecular *= SPECULAR_INDIRECT_FACTOR;
|
||||
|
||||
// Calculate Fresnel
|
||||
{
|
||||
const vec3 V = normalize(surface.ray.origin - surface.position.world);
|
||||
const vec3 N = surface.normal.world;
|
||||
const float NdotV = max(dot(N, V), 0.0);
|
||||
const vec3 N_dir = surface.normal.world;
|
||||
const float NdotV = max(dot(N_dir, V), 0.0);
|
||||
|
||||
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
|
||||
const vec3 F = fresnelSchlick(F0, NdotV);
|
||||
@ -192,9 +170,7 @@ void indirectLightingVXGI() {
|
||||
}
|
||||
|
||||
surface.material.indirect += indirectDiffuse + indirectSpecular;
|
||||
|
||||
// deferred sampling doesn't have a blended albedo buffer
|
||||
// in place we'll just cone trace behind the window
|
||||
|
||||
#if !RT
|
||||
if ( 0.1 < surface.material.albedo.a && surface.material.albedo.a < 1.0 ) {
|
||||
Ray ray;
|
||||
|
||||
@ -22,7 +22,7 @@ layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
|
||||
layout (constant_id = 0) const uint TEXTURES = 512;
|
||||
layout (constant_id = 1) const uint CUBEMAPS = 128;
|
||||
#if VXGI
|
||||
layout (constant_id = 2) const uint CASCADES = 16;
|
||||
layout (constant_id = 2) const uint REGIONS = 16;
|
||||
#endif
|
||||
|
||||
#if !MULTISAMPLING
|
||||
@ -99,10 +99,14 @@ layout (binding = 20, set = 1) uniform sampler2D samplerTextures[TEXTURES];
|
||||
layout (binding = 21, set = 1) uniform samplerCube samplerCubemaps[CUBEMAPS];
|
||||
layout (binding = 22, set = 0) uniform sampler3D samplerNoise;
|
||||
#if VXGI
|
||||
layout (binding = 23, set = 0) uniform sampler3D voxelOutput[CASCADES];
|
||||
// layout (binding = 23, set = 0) uniform sampler3D voxelOutput[REGIONS];
|
||||
layout (binding = 23, set = 0) uniform sampler3D voxelOutput[REGIONS];
|
||||
layout (std140, binding = 24, set = 0) readonly buffer Regions {
|
||||
Region regions[];
|
||||
};
|
||||
#endif
|
||||
#if RT
|
||||
layout (binding = 24, set = 0) uniform accelerationStructureEXT tlas;
|
||||
layout (binding = 25, set = 0) uniform accelerationStructureEXT tlas;
|
||||
#endif
|
||||
|
||||
#if BUFFER_REFERENCE
|
||||
@ -326,7 +330,7 @@ void directLighting() {
|
||||
surface.material.indirect.rgb = vec3(0);
|
||||
surface.fragment.rgb = radiance.rgb;
|
||||
surface.fragment.a = 1; // radiance.a;
|
||||
//return;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
|
||||
|
||||
layout (constant_id = 0) const uint TEXTURES = 512;
|
||||
layout (constant_id = 1) const uint CUBEMAPS = 128;
|
||||
layout (constant_id = 2) const uint CASCADES = 16;
|
||||
layout (constant_id = 2) const uint REGIONS = 16;
|
||||
|
||||
#include "../../common/macros.h"
|
||||
#include "../../common/structs.h"
|
||||
@ -52,10 +52,10 @@ layout (std140, binding = 7) readonly buffer Lights {
|
||||
layout (binding = 8) uniform sampler2D samplerTextures[TEXTURES];
|
||||
layout (binding = 9) uniform samplerCube samplerCubemaps[CUBEMAPS];
|
||||
|
||||
layout (binding = 10, r32ui) uniform readonly uimage3D voxelId[CASCADES];
|
||||
layout (binding = 11, r32ui) uniform readonly uimage3D voxelNormal[CASCADES];
|
||||
layout (binding = 12, r32ui) uniform readonly uimage3D voxelRadiance[CASCADES];
|
||||
layout (binding = 13, rgba8) uniform writeonly image3D voxelOutput[CASCADES];
|
||||
layout (binding = 10, r32ui) uniform readonly uimage3D voxelId[REGIONS];
|
||||
layout (binding = 11, r32ui) uniform readonly uimage3D voxelNormal[REGIONS];
|
||||
layout (binding = 12, r32ui) uniform readonly uimage3D voxelRadiance[REGIONS];
|
||||
layout (binding = 13, rgba8) uniform writeonly image3D voxelOutput[REGIONS];
|
||||
|
||||
#include "../../common/functions.h"
|
||||
#include "../../common/light.h"
|
||||
@ -63,12 +63,12 @@ layout (binding = 13, rgba8) uniform writeonly image3D voxelOutput[CASCADES];
|
||||
#include "../../common/shadows.h"
|
||||
|
||||
void main() {
|
||||
const vec3 tUvw = gl_GlobalInvocationID.xzy;
|
||||
for ( uint CASCADE = 0; CASCADE < CASCADES; ++CASCADE ) {
|
||||
const vec3 tUvw = gl_GlobalInvocationID.xyz;
|
||||
for ( uint REGION = 0; REGION < REGIONS; ++REGION ) {
|
||||
#if 0
|
||||
vec4 A = unpackUnorm4x8(imageLoad(voxelRadiance[CASCADE], ivec3(tUvw)).r);
|
||||
vec4 A = unpackUnorm4x8(imageLoad(voxelRadiance[REGION], ivec3(tUvw)).r);
|
||||
A.a = length(luma(A.rgb)) > 0.001 ? 1 : 0;
|
||||
imageStore(voxelOutput[CASCADE], ivec3(tUvw), A);
|
||||
imageStore(voxelOutput[REGION], ivec3(tUvw), A);
|
||||
#else
|
||||
surface.pass = 0; // PushConstant.pass;
|
||||
surface.fragment = vec4(0);
|
||||
@ -76,7 +76,7 @@ void main() {
|
||||
surface.motion = vec2(0);
|
||||
surface.material.indirect = vec4(0);
|
||||
|
||||
const uint packedID = imageLoad(voxelId[CASCADE], ivec3(tUvw) ).x;
|
||||
const uint packedID = imageLoad(voxelId[REGION], ivec3(tUvw) ).x;
|
||||
const uvec2 ID = uvec2(
|
||||
(packedID & 0xFFFF),
|
||||
(packedID >> 16)
|
||||
@ -89,7 +89,7 @@ void main() {
|
||||
// if ( ID.x == 0 || ID.y == 0 ) {
|
||||
#if 1
|
||||
if ( DISCARD_DUE_TO_DIVERGENCE ) {
|
||||
imageStore(voxelOutput[CASCADE], ivec3(tUvw), vec4(0));
|
||||
imageStore(voxelOutput[REGION], ivec3(tUvw), vec4(0));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
@ -102,9 +102,9 @@ void main() {
|
||||
surface.fragment = material.colorEmissive;
|
||||
|
||||
#if 0
|
||||
vec4 A = imageLoad(voxelOutput[CASCADE], ivec3(tUvw) );
|
||||
vec4 A = imageLoad(voxelOutput[REGION], ivec3(tUvw) );
|
||||
#else
|
||||
vec4 A = unpackUnorm4x8(imageLoad(voxelRadiance[CASCADE], ivec3(tUvw)).r);
|
||||
vec4 A = unpackUnorm4x8(imageLoad(voxelRadiance[REGION], ivec3(tUvw)).r);
|
||||
A.a = float(uint(A.a * 255.0 + 0.5) & 0xF) / 15.0;
|
||||
#endif
|
||||
|
||||
@ -134,9 +134,9 @@ void main() {
|
||||
#endif
|
||||
|
||||
if ( DISCARD_DUE_TO_DIVERGENCE ) {
|
||||
imageStore(voxelOutput[CASCADE], ivec3(tUvw), vec4(0));
|
||||
imageStore(voxelOutput[REGION], ivec3(tUvw), vec4(0));
|
||||
} else {
|
||||
imageStore(voxelOutput[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, surface.material.albedo.a));
|
||||
imageStore(voxelOutput[REGION], ivec3(tUvw), vec4(surface.fragment.rgb, surface.material.albedo.a));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
|
||||
|
||||
layout (constant_id = 0) const uint CASCADES = 8;
|
||||
layout (constant_id = 0) const uint REGIONS = 8;
|
||||
layout (constant_id = 1) const uint MIPS = 9; // 256^3 texture = 9 mips
|
||||
|
||||
layout(push_constant) uniform PushBlock {
|
||||
@ -24,8 +24,8 @@ layout(push_constant) uniform PushBlock {
|
||||
uint workGroupOffset;
|
||||
} PushConstant_;
|
||||
|
||||
layout (binding = 0) uniform sampler3D voxelRadiance[CASCADES];
|
||||
layout (binding = 1, rgba8) coherent uniform image3D voxelMips[CASCADES * (MIPS - 1)];
|
||||
layout (binding = 0) uniform sampler3D voxelRadiance[REGIONS];
|
||||
layout (binding = 1, rgba8) coherent uniform image3D voxelMips[REGIONS * (MIPS - 1)];
|
||||
|
||||
layout (binding = 2, std430) buffer AtomicCounter {
|
||||
uint counter;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#version 450
|
||||
#pragma shader_stage(fragment)
|
||||
|
||||
// to-do: convert to use functions.h surface population functions
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
|
||||
#define FRAGMENT 1
|
||||
#define DEFERRED_SAMPLING 0
|
||||
@ -10,37 +10,39 @@
|
||||
#define BLEND 0
|
||||
#define USE_LIGHTMAP 1
|
||||
layout (constant_id = 0) const uint TEXTURES = 512;
|
||||
layout (constant_id = 1) const uint CASCADES = 16;
|
||||
layout (constant_id = 1) const uint REGIONS = 16;
|
||||
|
||||
#define MAX_TEXTURES textures.length()
|
||||
#include "../../common/macros.h"
|
||||
#include "../../common/structs.h"
|
||||
|
||||
layout (binding = 6) uniform sampler2D samplerTextures[TEXTURES];
|
||||
layout (std140, binding = 7) readonly buffer DrawCommands {
|
||||
layout (binding = 7) uniform sampler2D samplerTextures[TEXTURES];
|
||||
layout (std140, binding = 8) readonly buffer DrawCommands {
|
||||
DrawCommand drawCommands[];
|
||||
};
|
||||
layout (std140, binding = 8) readonly buffer Instances {
|
||||
layout (std140, binding = 9) readonly buffer Instances {
|
||||
Instance instances[];
|
||||
};
|
||||
layout (std140, binding = 9) readonly buffer InstanceAddresseses {
|
||||
layout (std140, binding = 10) readonly buffer InstanceAddresseses {
|
||||
InstanceAddresses addresses[];
|
||||
};
|
||||
|
||||
layout (std140, binding = 10) readonly buffer Materials {
|
||||
layout (std140, binding = 11) readonly buffer Materials {
|
||||
Material materials[];
|
||||
};
|
||||
layout (std140, binding = 11) readonly buffer Textures {
|
||||
layout (std140, binding = 12) readonly buffer Textures {
|
||||
Texture textures[];
|
||||
};
|
||||
layout (std140, binding = 12) readonly buffer Lights {
|
||||
layout (std140, binding = 13) readonly buffer Lights {
|
||||
Light lights[];
|
||||
};
|
||||
layout (std140, binding = 14) readonly buffer RegionsBuffer {
|
||||
Region regions[];
|
||||
};
|
||||
|
||||
layout (binding = 13, r32ui) uniform volatile uimage3D voxelId[CASCADES];
|
||||
layout (binding = 14, r32ui) uniform volatile uimage3D voxelNormal[CASCADES];
|
||||
layout (binding = 15, r32ui) uniform volatile uimage3D voxelRadiance[CASCADES];
|
||||
layout (binding = 16, rgba8) uniform writeonly image3D voxelOutput[CASCADES];
|
||||
layout (binding = 15, r32ui) uniform volatile uimage3D voxelId[REGIONS];
|
||||
layout (binding = 16, r32ui) uniform volatile uimage3D voxelNormal[REGIONS];
|
||||
layout (binding = 17, r32ui) uniform volatile uimage3D voxelRadiance[REGIONS];
|
||||
layout (binding = 18, rgba8) uniform writeonly image3D voxelOutput[REGIONS];
|
||||
|
||||
layout (location = 0) flat in uvec4 inId;
|
||||
layout (location = 1) flat in vec4 inPOS0;
|
||||
@ -55,12 +57,16 @@ layout (location = 8) in vec3 inTangent;
|
||||
#include "../../common/functions.h"
|
||||
|
||||
void main() {
|
||||
const uint CASCADE = inId.w;
|
||||
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;
|
||||
const uint REGION_INDEX = inId.w;
|
||||
if ( REGIONS <= REGION_INDEX ) discard;
|
||||
|
||||
const uint triangleID = uint(inId.x); // gl_PrimitiveID
|
||||
Region region = regions[REGION_INDEX];
|
||||
|
||||
const vec3 P = (inPosition.xyz - region.minBounds) / (region.maxBounds - region.minBounds);
|
||||
const float epsilon = 0.001;
|
||||
if ( any(lessThan(P, vec3(-epsilon))) || any(greaterThan(P, vec3(1.0 + epsilon))) ) discard;
|
||||
|
||||
const uint triangleID = uint(inId.x);
|
||||
const uint drawID = uint(inId.y);
|
||||
const uint instanceID = uint(inId.z);
|
||||
|
||||
@ -75,22 +81,12 @@ void main() {
|
||||
surface.instance = instance;
|
||||
|
||||
vec4 A = material.colorBase;
|
||||
float M = material.factorMetallic;
|
||||
float R = material.factorRoughness;
|
||||
float AO = material.factorOcclusion;
|
||||
|
||||
// sample albedo
|
||||
|
||||
if ( validTextureIndex( material.indexAlbedo ) ) {
|
||||
A = sampleTexture( material.indexAlbedo );
|
||||
}
|
||||
// alpha mode OPAQUE
|
||||
if ( material.modeAlpha == 0 ) {
|
||||
A.a = 1;
|
||||
// alpha mode BLEND
|
||||
} else if ( material.modeAlpha == 1 ) {
|
||||
float dither = interleavedGradientNoise(gl_FragCoord.xy);
|
||||
// if ( A.a < dither ) discard;
|
||||
// alpha mode MASK
|
||||
} else if ( material.modeAlpha == 2 ) {
|
||||
if ( A.a < abs(material.factorAlphaCutoff) ) discard;
|
||||
A.a = 1;
|
||||
@ -103,33 +99,31 @@ void main() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// sample normal
|
||||
vec3 N = inNormal;
|
||||
vec3 T = inTangent;
|
||||
T = normalize(T - dot(T, N) * N);
|
||||
vec3 B = cross(T, N);
|
||||
mat3 TBN = mat3(T, B, N);
|
||||
// mat3 TBN = mat3(N, B, T);
|
||||
if ( T != vec3(0) && validTextureIndex( material.indexNormal ) ) {
|
||||
N = TBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - 1.0 );
|
||||
}
|
||||
|
||||
const ivec3 uvw = ivec3(P * imageSize(voxelOutput[CASCADE]));
|
||||
const ivec3 uvw = ivec3(P * imageSize(voxelOutput[nonuniformEXT(REGION_INDEX)]));
|
||||
|
||||
{
|
||||
uint packedId = ( instanceID + 1 ) << 16 | ( drawID + 1 );
|
||||
imageAtomicMax(voxelId[CASCADE], ivec3(uvw), packedId);
|
||||
imageAtomicMax(voxelId[nonuniformEXT(REGION_INDEX)], uvw, packedId);
|
||||
}
|
||||
{
|
||||
vec2 N_E = encodeNormals( normalize( N ) );
|
||||
uint packedNormal = packHalf2x16(N_E);
|
||||
imageAtomicMax(voxelNormal[CASCADE], uvw, packedNormal);
|
||||
imageAtomicMax(voxelNormal[nonuniformEXT(REGION_INDEX)], uvw, packedNormal);
|
||||
}
|
||||
{
|
||||
uint l = uint(clamp(luma(A.rgb), 0.0, 1.0) * 15.0) & 0xF;
|
||||
uint a = uint(clamp( A.a, 0.0, 1.0) * 15.0) & 0xF;
|
||||
uint a = uint(clamp( A.a, 0.0, 1.0) * 15.0) & 0xF;
|
||||
float packedLumaAlpha = float((l << 4) | a) / 255.0;
|
||||
uint packedRadiance = packUnorm4x8(vec4(A.rgb, packedLumaAlpha));
|
||||
imageAtomicMax(voxelRadiance[CASCADE], uvw, packedRadiance);
|
||||
imageAtomicMax(voxelRadiance[nonuniformEXT(REGION_INDEX)], uvw, packedRadiance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#version 450
|
||||
#pragma shader_stage(geometry)
|
||||
#extension GL_EXT_multiview : require
|
||||
#extension GL_EXT_multiview : require
|
||||
|
||||
layout(triangles) in;
|
||||
layout(triangle_strip, max_vertices = 3) out;
|
||||
@ -25,72 +25,87 @@ layout (location = 6) out vec2 outSt;
|
||||
layout (location = 7) out vec3 outNormal;
|
||||
layout (location = 8) out vec3 outTangent;
|
||||
|
||||
#include "../../common/macros.h"
|
||||
#include "../../common/structs.h"
|
||||
|
||||
layout (binding = 5) uniform UBO {
|
||||
mat4 voxel;
|
||||
|
||||
float cascadePower;
|
||||
float granularity;
|
||||
float voxelizeScale;
|
||||
float occlusionFalloff;
|
||||
|
||||
uint shadows;
|
||||
uint padding1;
|
||||
uint padding2;
|
||||
uint padding3;
|
||||
} ubo;
|
||||
|
||||
float cascadePower( uint x ) {
|
||||
return pow(1 + x, ubo.cascadePower);
|
||||
// return max( 1, x * ubo.cascadePower );
|
||||
}
|
||||
layout (std140, binding = 6) readonly buffer RegionsBuffer {
|
||||
Region regions[];
|
||||
};
|
||||
|
||||
#define USE_CROSS 0
|
||||
void main(){
|
||||
const float HALF_PIXEL = ubo.voxelizeScale;
|
||||
const vec3 C = ( inPosition[0] + inPosition[1] + inPosition[2] ) / 3.0;
|
||||
const vec3 triMin = min(inPosition[0], min(inPosition[1], inPosition[2]));
|
||||
const vec3 triMax = max(inPosition[0], max(inPosition[1], inPosition[2]));
|
||||
|
||||
uint emittedTriangles = 0;
|
||||
for (uint r = 0; r < regions.length(); ++r) {
|
||||
Region region = regions[r];
|
||||
if ( region.size == 0 ) continue;
|
||||
|
||||
const float margin = (region.maxBounds.x - region.minBounds.x) / float(region.size) * 1.0;
|
||||
|
||||
bool intersects = (triMin.x - margin <= region.maxBounds.x && triMax.x + margin >= region.minBounds.x) &&
|
||||
(triMin.y - margin <= region.maxBounds.y && triMax.y + margin >= region.minBounds.y) &&
|
||||
(triMin.z - margin <= region.maxBounds.z && triMax.z + margin >= region.minBounds.z);
|
||||
|
||||
if ( !intersects ) continue;
|
||||
const float HALF_PIXEL = (region.maxBounds.x - region.minBounds.x) / float(region.size) * 0.5;
|
||||
const vec3 C = ( inPosition[0] + inPosition[1] + inPosition[2] ) / 3.0;
|
||||
|
||||
#if USE_CROSS
|
||||
const vec3 N = abs(cross(inPosition[2] - inPosition[0], inPosition[1] - inPosition[0]));
|
||||
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;
|
||||
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
|
||||
|
||||
const uint CASCADE = gl_ViewIndex; // inId[0].w;
|
||||
const float power = cascadePower(CASCADE);
|
||||
vec3 P[3] = {
|
||||
vec3( ubo.voxel * vec4( inPosition[0], 1 ) ) / power,
|
||||
vec3( ubo.voxel * vec4( inPosition[1], 1 ) ) / power,
|
||||
vec3( ubo.voxel * vec4( inPosition[2], 1 ) ) / power,
|
||||
};
|
||||
|
||||
#pragma unroll 3
|
||||
for( uint i = 0; i < 3; ++i ){
|
||||
const vec3 D = normalize( inPosition[i] - C ) * HALF_PIXEL;
|
||||
vec3 P[3];
|
||||
#pragma unroll 3
|
||||
for( uint i = 0; i < 3; ++i ){
|
||||
vec3 localPos = (inPosition[i] - region.minBounds) / (region.maxBounds - region.minBounds);
|
||||
P[i] = localPos * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
outPosition = P[i] + D;
|
||||
outPOS0 = inPOS0[i];
|
||||
outPOS1 = inPOS1[i];
|
||||
outUv = inUv[i];
|
||||
outSt = inSt[i];
|
||||
outColor = inColor[i];
|
||||
outNormal = inNormal[i];
|
||||
outTangent = inTangent[i];
|
||||
outId = inId[i];
|
||||
outId.w = gl_ViewIndex;
|
||||
|
||||
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);
|
||||
else gl_Position = vec4(P.x, P.z, 0, 1);
|
||||
#else
|
||||
if ( A == 0 ) gl_Position = vec4(P.zy, 0, 1 );
|
||||
else if ( A == 1 ) gl_Position = vec4(P.xz, 0, 1 );
|
||||
else if ( A == 2 ) gl_Position = vec4(P.xy, 0, 1 );
|
||||
#endif
|
||||
EmitVertex();
|
||||
#pragma unroll 3
|
||||
for( uint i = 0; i < 3; ++i ){
|
||||
const vec3 D = normalize( inPosition[i] - C ) * HALF_PIXEL;
|
||||
vec3 projectedD = D / (region.maxBounds - region.minBounds) * 2.0;
|
||||
|
||||
outPosition = inPosition[i] + D;
|
||||
outPOS0 = inPOS0[i];
|
||||
outPOS1 = inPOS1[i];
|
||||
outUv = inUv[i];
|
||||
outSt = inSt[i];
|
||||
outColor = inColor[i];
|
||||
outNormal = inNormal[i];
|
||||
outTangent = inTangent[i];
|
||||
outId = inId[i];
|
||||
outId.w = r;
|
||||
|
||||
const vec3 finalP = P[i] + projectedD;
|
||||
#if USE_CROSS
|
||||
if ( N.z > N.x && N.z > N.y ) gl_Position = vec4(finalP.x, finalP.y, 0, 1);
|
||||
else if ( N.x > N.y && N.x > N.z ) gl_Position = vec4(finalP.y, finalP.z, 0, 1);
|
||||
else gl_Position = vec4(finalP.x, finalP.z, 0, 1);
|
||||
#else
|
||||
if ( A == 0 ) gl_Position = vec4(finalP.zy, 0, 1 );
|
||||
else if ( A == 1 ) gl_Position = vec4(finalP.xz, 0, 1 );
|
||||
else if ( A == 2 ) gl_Position = vec4(finalP.xy, 0, 1 );
|
||||
#endif
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
|
||||
emittedTriangles++;
|
||||
if ( emittedTriangles >= 4 ) break;
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
@ -115,6 +115,7 @@ namespace pod {
|
||||
|
||||
uf::stl::vector<uf::renderer::Texture2D> shadow2Ds;
|
||||
uf::stl::vector<uf::renderer::TextureCube> shadowCubes;
|
||||
uf::stl::vector<pod::Region> regions;
|
||||
|
||||
// flattened variants
|
||||
uf::stl::vector<pod::Primitive> flattenedPrimitives;
|
||||
@ -130,6 +131,7 @@ namespace pod {
|
||||
uf::renderer::Buffer material;
|
||||
uf::renderer::Buffer texture;
|
||||
uf::renderer::Buffer light;
|
||||
uf::renderer::Buffer region;
|
||||
|
||||
uf::renderer::Texture2D depthPyramid;
|
||||
} buffers;
|
||||
|
||||
@ -113,6 +113,13 @@ namespace pod {
|
||||
uf::Image data;
|
||||
uf::renderer::Texture2D handle;
|
||||
};
|
||||
|
||||
struct UF_API Region {
|
||||
pod::Vector3f minBounds = {};
|
||||
alignas(4) uint32_t index = 0;
|
||||
pod::Vector3f maxBounds = {};
|
||||
alignas(4) uint32_t size = 64;
|
||||
};
|
||||
}
|
||||
|
||||
namespace pod {
|
||||
|
||||
@ -16,7 +16,6 @@ namespace ext {
|
||||
virtual void initialize( Device& device );
|
||||
virtual void build( bool = true );
|
||||
virtual void tick();
|
||||
virtual VkSubmitInfo queue();
|
||||
virtual void render();
|
||||
virtual void destroy();
|
||||
};
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include <uf/utils/memory/vector.h>
|
||||
#include <stdint.h>
|
||||
#include <limits>
|
||||
|
||||
namespace pod {
|
||||
template<typename T, typename U = uint16_t>
|
||||
@ -20,8 +21,9 @@ namespace uf {
|
||||
namespace rle {
|
||||
template<typename T, typename U = uint16_t>
|
||||
typename pod::RLE<T,U>::string_t encode( const uf::stl::vector<T>& );
|
||||
|
||||
template<typename T, typename U = uint16_t>
|
||||
uf::stl::vector<T> decode( const pod::RLE<T,U>& );
|
||||
uf::stl::vector<T> decode( const uf::stl::vector<pod::RLE<T,U>>& );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,24 +1,34 @@
|
||||
template<typename T, typename U>
|
||||
typename pod::RLE<T,U>::string_t uf::rle::encode( const uf::stl::vector<T>& source ) {
|
||||
typename pod::RLE<T,U>::string_t destination;
|
||||
if ( source.empty() ) return destination;
|
||||
|
||||
destination.reserve( source.size() );
|
||||
|
||||
for ( std::size_t i = 0; i < source.size(); ++i ) {
|
||||
pod::RLE<T,U> reg = { 1, source[i] };
|
||||
while ( i + 1 < source.size() && source[i] == source[i + 1] ) ++reg.length, ++i;
|
||||
destination.push_back( reg );
|
||||
for ( size_t i = 0; i < source.size(); ++i ) {
|
||||
auto reg = pod::RLE<T,U>{ 1, source[i] };
|
||||
|
||||
while ( i + 1 < source.size() && source[i] == source[i + 1] && reg.length < std::numeric_limits<U>::max() ) {
|
||||
++reg.length;
|
||||
++i;
|
||||
}
|
||||
destination.emplace_back( reg );
|
||||
}
|
||||
|
||||
destination.shrink_to_fit();
|
||||
return destination;
|
||||
}
|
||||
template<typename T, typename U>
|
||||
uf::stl::vector<T> uf::rle::decode( const pod::RLE<T,U>& source ) {
|
||||
uf::stl::vector<T> destination;
|
||||
|
||||
for ( auto& s : source ) {
|
||||
template<typename T, typename U>
|
||||
uf::stl::vector<T> uf::rle::decode( const uf::stl::vector<pod::RLE<T,U>>& source ) {
|
||||
uf::stl::vector<T> destination;
|
||||
if ( source.empty() ) return destination;
|
||||
|
||||
for ( const auto& s : source ) {
|
||||
destination.reserve( destination.size() + s.length );
|
||||
for ( std::size_t i = 0; i < s.length; ++i ) destination.push_back(s.value);
|
||||
for ( size_t i = 0; i < s.length; ++i ) {
|
||||
destination.emplace_back(s.value);
|
||||
}
|
||||
}
|
||||
|
||||
destination.shrink_to_fit();
|
||||
|
||||
@ -208,27 +208,27 @@ void ext::RayTraceSceneBehavior::tick( uf::Object& self ) {
|
||||
size_t maxTextures2D = uf::config["engine"]["scenes"]["textures"]["max"]["2D"].as<size_t>(512);
|
||||
size_t maxTexturesCube = uf::config["engine"]["scenes"]["textures"]["max"]["cube"].as<size_t>(128);
|
||||
size_t maxTextures3D = uf::config["engine"]["scenes"]["textures"]["max"]["3D"].as<size_t>(1);
|
||||
size_t maxCascades = uf::config["engine"]["scenes"]["vxgi"]["cascades"].as<size_t>(16);
|
||||
size_t maxRegions = uf::config["engine"]["scenes"]["vxgi"]["regions"].as<size_t>(64);
|
||||
|
||||
shader.aliasBuffer( storage.buffers.instance );
|
||||
shader.aliasBuffer( storage.buffers.addresses );
|
||||
shader.aliasBuffer( storage.buffers.object );
|
||||
shader.aliasBuffer( storage.buffers.material );
|
||||
shader.aliasBuffer( storage.buffers.texture );
|
||||
shader.aliasBuffer( storage.buffers.light );
|
||||
shader.aliasBuffer( "instance", storage.buffers.instance );
|
||||
shader.aliasBuffer( "addresses", storage.buffers.addresses );
|
||||
shader.aliasBuffer( "object", storage.buffers.object );
|
||||
shader.aliasBuffer( "material", storage.buffers.material );
|
||||
shader.aliasBuffer( "texture", storage.buffers.texture );
|
||||
shader.aliasBuffer( "light", storage.buffers.light );
|
||||
|
||||
shader.setSpecializationConstants({
|
||||
{ "TEXTURES", maxTextures2D },
|
||||
{ "CUBEMAPS", maxTexturesCube },
|
||||
{ "CASCADES", maxCascades },
|
||||
{ "REGIONS", maxRegions },
|
||||
});
|
||||
shader.setDescriptorCounts({
|
||||
{ "samplerTextures", maxTextures2D },
|
||||
{ "samplerCubemaps", maxTexturesCube },
|
||||
{ "voxelId", maxCascades },
|
||||
{ "voxelNormal", maxCascades },
|
||||
{ "voxelRadiance", maxCascades },
|
||||
{ "voxelOutput", maxCascades },
|
||||
{ "voxelId", maxRegions },
|
||||
{ "voxelNormal", maxRegions },
|
||||
{ "voxelRadiance", maxRegions },
|
||||
{ "voxelOutput", maxRegions },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -551,7 +551,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
|
||||
if ( image.viewType == uf::renderer::enums::Image::VIEW_TYPE_CUBE ) {
|
||||
textureCubeOffset++;
|
||||
} else {
|
||||
} else if ( image.viewType == uf::renderer::enums::Image::VIEW_TYPE_2D ) {
|
||||
texture2dOffset++;
|
||||
}
|
||||
}
|
||||
@ -626,9 +626,10 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
constexpr uint32_t MODE_CUBEMAP = 1;
|
||||
constexpr uint32_t MODE_SEPARATE_2DS = 2;
|
||||
|
||||
//for ( uint32_t i = 0; i < entities.size(); ++i ) {
|
||||
for ( auto idx : indices ) {
|
||||
auto& info = entities[idx];
|
||||
for ( uint32_t i = 0; i < entities.size(); ++i ) {
|
||||
auto& info = entities[i];
|
||||
//for ( auto idx : indices ) {
|
||||
// auto& info = entities[idx];
|
||||
uf::Entity* entity = info.entity;
|
||||
|
||||
int32_t boundIndexMap = -1;
|
||||
@ -1110,14 +1111,13 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic
|
||||
} bloom;
|
||||
|
||||
struct VXGI {
|
||||
alignas(16) pod::Matrix4f matrix;
|
||||
alignas(4) float cascadePower;
|
||||
alignas(4) float granularity;
|
||||
alignas(4) float voxelizeScale;
|
||||
alignas(4) float occlusionFalloff;
|
||||
|
||||
alignas(4) float traceStartOffsetFactor;
|
||||
|
||||
alignas(4) uint32_t shadows;
|
||||
alignas(4) uint32_t padding1;
|
||||
alignas(4) uint32_t padding2;
|
||||
alignas(4) uint32_t padding3;
|
||||
} vxgi;
|
||||
@ -1260,12 +1260,9 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic
|
||||
.threshold = metadata.bloom.threshold,
|
||||
};
|
||||
uniforms.settings.vxgi = UniformDescriptor::Settings::VXGI{
|
||||
.matrix = metadataVxgi.extents.matrix,
|
||||
.cascadePower = metadataVxgi.cascadePower,
|
||||
.granularity = metadataVxgi.granularity,
|
||||
.voxelizeScale = 1.0f / (metadataVxgi.voxelizeScale * std::max<uint32_t>( metadataVxgi.voxelSize.x, std::max<uint32_t>(metadataVxgi.voxelSize.y, metadataVxgi.voxelSize.z))),
|
||||
.occlusionFalloff = metadataVxgi.occlusionFalloff,
|
||||
|
||||
.traceStartOffsetFactor = metadataVxgi.traceStartOffsetFactor,
|
||||
.shadows = metadataVxgi.shadows,
|
||||
};
|
||||
|
||||
@ -27,7 +27,7 @@ namespace {
|
||||
};
|
||||
struct PushConstants {
|
||||
uint32_t mips;
|
||||
uint32_t cascade;
|
||||
uint32_t region;
|
||||
uint32_t numWorkGroups;
|
||||
uint32_t workGroupOffset;
|
||||
};
|
||||
@ -49,7 +49,7 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) {
|
||||
UF_BEHAVIOR_METADATA_BIND_SERIALIZER_HOOKS(metadata, metadataJson);
|
||||
|
||||
auto mips = uf::vector::mips( metadata.voxelSize );
|
||||
for ( size_t i = 0; i < metadata.cascades; ++i ) {
|
||||
for ( size_t i = 0; i < metadata.regions; ++i ) {
|
||||
const bool HDR = false;
|
||||
auto& id = sceneTextures.voxels.id.emplace_back();
|
||||
id.sampler.descriptor.filter.min = uf::renderer::enums::Filter::NEAREST;
|
||||
@ -131,8 +131,8 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) {
|
||||
}
|
||||
renderMode.metadata.pipelines.emplace_back(uf::renderer::settings::pipelines::names::vxgi);
|
||||
renderMode.metadata.samples = 1;
|
||||
// renderMode.metadata.subpasses = metadata.cascades;
|
||||
renderMode.metadata.views = metadata.cascades;
|
||||
// renderMode.metadata.subpasses = metadata.regions;
|
||||
renderMode.metadata.views = metadata.regions;
|
||||
|
||||
renderMode.width = metadata.fragmentSize.x;
|
||||
renderMode.height = metadata.fragmentSize.y;
|
||||
@ -152,7 +152,7 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) {
|
||||
size_t maxTextures2D = uf::config["engine"]["scenes"]["textures"]["max"]["2D"].as<size_t>(512);
|
||||
size_t maxTexturesCube = uf::config["engine"]["scenes"]["textures"]["max"]["cube"].as<size_t>(128);
|
||||
size_t maxTextures3D = uf::config["engine"]["scenes"]["textures"]["max"]["3D"].as<size_t>(1);
|
||||
size_t maxCascades = uf::config["engine"]["scenes"]["vxgi"]["cascades"].as<size_t>(16);
|
||||
size_t maxRegions = uf::config["engine"]["scenes"]["vxgi"]["regions"].as<size_t>(16);
|
||||
size_t maxMips = uf::vector::mips( pod::Vector3ui{ 256, 256, 256 } ); // log2(256) = 9
|
||||
|
||||
renderMode.metadata.json["shaders"] = true;
|
||||
@ -163,15 +163,15 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) {
|
||||
shader.setSpecializationConstants({
|
||||
{ "TEXTURES", maxTextures2D },
|
||||
{ "CUBEMAPS", maxTexturesCube },
|
||||
{ "CASCADES", maxCascades },
|
||||
{ "REGIONS", maxRegions },
|
||||
});
|
||||
shader.setDescriptorCounts({
|
||||
{ "samplerTextures", maxTextures2D },
|
||||
{ "samplerCubemaps", maxTexturesCube },
|
||||
{ "voxelId", maxCascades },
|
||||
{ "voxelNormal", maxCascades },
|
||||
{ "voxelRadiance", maxCascades },
|
||||
{ "voxelOutput", maxCascades },
|
||||
{ "voxelId", maxRegions },
|
||||
{ "voxelNormal", maxRegions },
|
||||
{ "voxelRadiance", maxRegions },
|
||||
{ "voxelOutput", maxRegions },
|
||||
});
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
@ -193,12 +193,12 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) {
|
||||
shader.setSpecializationConstants({
|
||||
{ "TEXTURES", maxTextures2D },
|
||||
{ "CUBEMAPS", maxTexturesCube },
|
||||
{ "CASCADES", maxCascades },
|
||||
{ "REGIONS", maxRegions },
|
||||
{ "MIPS", maxMips },
|
||||
});
|
||||
shader.setDescriptorCounts({
|
||||
{ "voxelRadiance", maxCascades },
|
||||
{ "voxelMips", maxCascades * (maxMips - 1) },
|
||||
{ "voxelRadiance", maxRegions },
|
||||
{ "voxelMips", maxRegions * (maxMips - 1) },
|
||||
});
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
@ -214,6 +214,21 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) {
|
||||
#endif
|
||||
|
||||
renderMode.bindCallback( renderMode.CALLBACK_BEGIN, [&]( VkCommandBuffer commandBuffer, size_t _ ){
|
||||
VkMemoryBarrier warBarrier = {};
|
||||
warBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
warBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
warBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0,
|
||||
1, &warBarrier,
|
||||
0, nullptr,
|
||||
0, nullptr
|
||||
);
|
||||
|
||||
// clear textures
|
||||
VkImageSubresourceRange subresourceRange = {};
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
@ -226,37 +241,94 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) {
|
||||
for ( auto& t : sceneTextures.voxels.id ) vkCmdClearColorImage( commandBuffer, t.image, t.layout, &clearColor, 1, &subresourceRange );
|
||||
for ( auto& t : sceneTextures.voxels.normal ) vkCmdClearColorImage( commandBuffer, t.image, t.layout, &clearColor, 1, &subresourceRange );
|
||||
for ( auto& t : sceneTextures.voxels.radiance ) vkCmdClearColorImage( commandBuffer, t.image, t.layout, &clearColor, 1, &subresourceRange );
|
||||
#if !ALIAS_OUTPUT_TO_RADIANCE
|
||||
for ( auto& t : sceneTextures.voxels.output ) vkCmdClearColorImage( commandBuffer, t.image, t.layout, &clearColor, 1, &subresourceRange );
|
||||
#endif
|
||||
VkMemoryBarrier clearBarrier = {};
|
||||
clearBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
clearBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
clearBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0,
|
||||
1, &clearBarrier,
|
||||
0, nullptr,
|
||||
0, nullptr
|
||||
);
|
||||
});
|
||||
|
||||
//
|
||||
renderMode.bindCallback( renderMode.CALLBACK_END, [&]( VkCommandBuffer commandBuffer, size_t _ ){
|
||||
// parse voxel lighting
|
||||
VkMemoryBarrier fragToCompBarrier = {};
|
||||
fragToCompBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
fragToCompBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
fragToCompBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0,
|
||||
1, &fragToCompBarrier,
|
||||
0, nullptr,
|
||||
0, nullptr
|
||||
);
|
||||
|
||||
if ( blitter.initialized ) {
|
||||
auto descriptor = blitter.descriptor;
|
||||
//descriptor.pipeline = "lighting";
|
||||
blitter.record( commandBuffer, descriptor );
|
||||
}
|
||||
|
||||
// generate mipmaps
|
||||
|
||||
VkMemoryBarrier compToCompBarrier = {};
|
||||
compToCompBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
compToCompBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
compToCompBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0,
|
||||
1, &compToCompBarrier,
|
||||
0, nullptr,
|
||||
0, nullptr
|
||||
);
|
||||
|
||||
#if COMPUTE_MIPMAP_GENERATION
|
||||
if ( blitter.initialized ) {
|
||||
auto& shader = blitter.material.getShader("compute", "mipmap");
|
||||
auto mips = uf::vector::mips( pod::Vector3ui{ blitter.descriptor.bind.width, blitter.descriptor.bind.height, blitter.descriptor.bind.depth } );
|
||||
|
||||
for ( auto cascade = 0; cascade < sceneTextures.voxels.output.size(); ++cascade ) {
|
||||
uint32_t wgX = (blitter.descriptor.bind.width + 15) / 16;
|
||||
uint32_t wgY = (blitter.descriptor.bind.height + 15) / 16;
|
||||
uint32_t wgZ = (blitter.descriptor.bind.depth + 15) / 16;
|
||||
uint32_t totalWorkGroups = wgX * wgY * wgZ;
|
||||
|
||||
for ( auto region = 0; region < sceneTextures.voxels.output.size(); ++region ) {
|
||||
vkCmdFillBuffer(commandBuffer, metadata.atomicCounter.buffer, 0, 4, 0);
|
||||
|
||||
VkMemoryBarrier counterBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
||||
counterBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
counterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
counterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &counterBarrier, 0, nullptr, 0, nullptr);
|
||||
|
||||
vkCmdPipelineBarrier(commandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0,
|
||||
1, &counterBarrier,
|
||||
0, nullptr,
|
||||
0, nullptr
|
||||
);
|
||||
|
||||
auto& pushConstant = shader.pushConstants.front().get<::PushConstants>();
|
||||
pushConstant = {
|
||||
.mips = mips,
|
||||
.cascade = cascade,
|
||||
.numWorkGroups = 0,
|
||||
.region = region,
|
||||
.numWorkGroups = totalWorkGroups,
|
||||
.workGroupOffset = 0,
|
||||
};
|
||||
auto descriptor = blitter.descriptor;
|
||||
@ -278,7 +350,23 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) {
|
||||
t.setImageLayout( commandBuffer, t.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, t.layout, subresourceRange );
|
||||
}
|
||||
#endif
|
||||
|
||||
VkMemoryBarrier compToDeferredBarrier = {};
|
||||
compToDeferredBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
compToDeferredBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
compToDeferredBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0,
|
||||
1, &compToDeferredBarrier,
|
||||
0, nullptr,
|
||||
0, nullptr
|
||||
);
|
||||
});
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -286,6 +374,9 @@ void ext::VoxelizerSceneBehavior::tick( uf::Object& self ) {
|
||||
#if UF_USE_VULKAN
|
||||
if ( !this->hasComponent<uf::renderer::RenderTargetRenderMode>() ) return;
|
||||
|
||||
// extremely cringe but the load placed on the GPU causes a nasty issue
|
||||
vkDeviceWaitIdle(ext::vulkan::device.logicalDevice);
|
||||
|
||||
auto& metadata = this->getComponent<ext::VoxelizerSceneBehavior::Metadata>();
|
||||
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
||||
|
||||
@ -307,37 +398,43 @@ void ext::VoxelizerSceneBehavior::tick( uf::Object& self ) {
|
||||
}
|
||||
|
||||
#if 1
|
||||
// bool should = false;
|
||||
// if ( renderMode.metadata.limiter.frequency <= 0 && renderMode.metadata.limiter.timer <= 0 ) should = true;
|
||||
// else if ( renderMode.metadata.limiter.timer + renderMode.metadata.limiter.frequency >= renderMode.metadata.limiter.frequency ) should = true;
|
||||
|
||||
// if ( renderMode.execute ) {
|
||||
if ( renderMode.metadata.limiter.execute ) {
|
||||
// if ( should ) {
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = scene.getCamera( controller );
|
||||
auto controllerTransform = uf::transform::flatten( camera.getTransform() );
|
||||
|
||||
float voxelWorldSizeX = (metadata.extents.max.x - metadata.extents.min.x) / (float)(metadata.voxelSize.x);
|
||||
float voxelWorldSizeY = (metadata.extents.max.y - metadata.extents.min.y) / (float)(metadata.voxelSize.y);
|
||||
float voxelWorldSizeZ = (metadata.extents.max.z - metadata.extents.min.z) / (float)(metadata.voxelSize.z);
|
||||
|
||||
pod::Vector3f controllerPosition = controllerTransform.position - metadata.extents.min;
|
||||
// update storage regions
|
||||
auto& storage = uf::graph::getStorage( *this );
|
||||
{
|
||||
storage.regions.clear();
|
||||
for ( uint32_t i = 0; i < metadata.regions; ++i ) {
|
||||
float scale = std::pow(2.0f, static_cast<float>(i));
|
||||
|
||||
controllerPosition.x = std::floor(controllerPosition.x / voxelWorldSizeX) * voxelWorldSizeX;
|
||||
controllerPosition.y = std::floor(controllerPosition.y / voxelWorldSizeY) * voxelWorldSizeY;
|
||||
controllerPosition.z = std::floor(controllerPosition.z / voxelWorldSizeZ) * voxelWorldSizeZ;
|
||||
pod::Vector3f halfExtents = (metadata.extents.max - metadata.extents.min) * 0.5f * scale;
|
||||
|
||||
controllerPosition += metadata.extents.min;
|
||||
pod::Region region;
|
||||
region.minBounds = controllerTransform.position - halfExtents;
|
||||
region.maxBounds = controllerTransform.position + halfExtents;
|
||||
region.index = i;
|
||||
region.size = metadata.voxelSize.x;
|
||||
|
||||
controllerPosition.x = std::floor(controllerPosition.x / voxelWorldSizeX) * voxelWorldSizeX;
|
||||
controllerPosition.y = std::floor(controllerPosition.y / voxelWorldSizeY) * voxelWorldSizeY;
|
||||
controllerPosition.z = -std::floor(controllerPosition.z / voxelWorldSizeZ) * voxelWorldSizeZ;
|
||||
storage.regions.emplace_back( region );
|
||||
}
|
||||
|
||||
pod::Vector3f min = metadata.extents.min + controllerPosition;
|
||||
pod::Vector3f max = metadata.extents.max + controllerPosition;
|
||||
|
||||
metadata.extents.matrix = uf::matrix::orthographic( min.x, max.x, min.y, max.y, min.z, max.z );
|
||||
size_t maxRegions = uf::config["engine"]["scenes"]["vxgi"]["regions"].as<size_t>(16);
|
||||
while ( storage.regions.size() < maxRegions ) {
|
||||
pod::Region dummy;
|
||||
dummy.minBounds = { 0.0f, 0.0f, 0.0f };
|
||||
dummy.maxBounds = { 0.0f, 0.0f, 0.0f };
|
||||
dummy.index = 0;
|
||||
dummy.size = 0;
|
||||
storage.regions.emplace_back( dummy );
|
||||
}
|
||||
auto rebuild = storage.buffers.region.update( (const void*) storage.regions.data(), storage.regions.size() * sizeof(pod::Region) );
|
||||
if ( rebuild ) {
|
||||
storage.stale = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto/*&*/ graph = scene.getGraph();
|
||||
for ( auto entity : graph ) {
|
||||
@ -346,27 +443,17 @@ void ext::VoxelizerSceneBehavior::tick( uf::Object& self ) {
|
||||
if ( blitter.material.hasShader("geometry", uf::renderer::settings::pipelines::names::vxgi) ) {
|
||||
auto& shader = blitter.material.getShader("geometry", uf::renderer::settings::pipelines::names::vxgi);
|
||||
struct UniformDescriptor {
|
||||
/*alignas(16)*/ pod::Matrix4f matrix;
|
||||
/*alignas(4)*/ float cascadePower;
|
||||
/*alignas(4)*/ float granularity;
|
||||
/*alignas(4)*/ float voxelizeScale;
|
||||
/*alignas(4)*/ float occlusionFalloff;
|
||||
|
||||
/*alignas(4)*/ float traceStartOffsetFactor;
|
||||
/*alignas(4)*/ float occlusionFalloff;
|
||||
/*alignas(4)*/ uint32_t shadows;
|
||||
/*alignas(4)*/ uint32_t padding2;
|
||||
/*alignas(4)*/ uint32_t padding3;
|
||||
/*alignas(4)*/ uint32_t regions;
|
||||
};
|
||||
|
||||
UniformDescriptor uniforms = {
|
||||
.matrix = metadata.extents.matrix,
|
||||
.cascadePower = metadata.cascadePower,
|
||||
.granularity = metadata.granularity,
|
||||
.voxelizeScale = 1.0f / (metadata.voxelizeScale * std::max<uint32_t>( metadata.voxelSize.x, std::max<uint32_t>(metadata.voxelSize.y, metadata.voxelSize.z))),
|
||||
.occlusionFalloff = metadata.occlusionFalloff,
|
||||
|
||||
.traceStartOffsetFactor = metadata.traceStartOffsetFactor,
|
||||
.occlusionFalloff = metadata.occlusionFalloff,
|
||||
.shadows = metadata.shadows,
|
||||
.regions = storage.regions.size(),
|
||||
};
|
||||
shader.updateBuffer( (const void*) &uniforms, sizeof(uniforms), shader.getUniformBuffer("UBO") );
|
||||
}
|
||||
@ -404,10 +491,8 @@ void ext::VoxelizerSceneBehavior::Metadata::serialize( uf::Object& self, uf::Ser
|
||||
serializer["vxgi"]["limiter"] = /*this->*/limiter.frequency;
|
||||
serializer["vxgi"]["dispatch"] = /*this->*/dispatchSize.x;
|
||||
|
||||
serializer["vxgi"]["cascades"] = /*this->*/cascades;
|
||||
serializer["vxgi"]["cascadePower"] = /*this->*/cascadePower;
|
||||
serializer["vxgi"]["regions"] = /*this->*/regions;
|
||||
serializer["vxgi"]["granularity"] = /*this->*/granularity;
|
||||
serializer["vxgi"]["voxelizeScale"] = /*this->*/voxelizeScale;
|
||||
serializer["vxgi"]["occlusionFalloff"] = /*this->*/occlusionFalloff;
|
||||
serializer["vxgi"]["traceStartOffsetFactor"] = /*this->*/traceStartOffsetFactor;
|
||||
serializer["vxgi"]["shadows"] = /*this->*/shadows;
|
||||
@ -436,10 +521,8 @@ void ext::VoxelizerSceneBehavior::Metadata::deserialize( uf::Object& self, uf::S
|
||||
/*this->*/dispatchSize.y = serializer["vxgi"]["dispatch"].as(/*this->*/dispatchSize.x);
|
||||
/*this->*/dispatchSize.z = serializer["vxgi"]["dispatch"].as(/*this->*/dispatchSize.x);
|
||||
|
||||
/*this->*/cascades = serializer["vxgi"]["cascades"].as(/*this->*/cascades);
|
||||
/*this->*/cascadePower = serializer["vxgi"]["cascadePower"].as(/*this->*/cascadePower);
|
||||
/*this->*/regions = serializer["vxgi"]["regions"].as(/*this->*/regions);
|
||||
/*this->*/granularity = serializer["vxgi"]["granularity"].as(/*this->*/granularity);
|
||||
/*this->*/voxelizeScale = serializer["vxgi"]["voxelizeScale"].as(/*this->*/voxelizeScale);
|
||||
/*this->*/occlusionFalloff = serializer["vxgi"]["occlusionFalloff"].as(/*this->*/occlusionFalloff);
|
||||
/*this->*/traceStartOffsetFactor = serializer["vxgi"]["traceStartOffsetFactor"].as(/*this->*/traceStartOffsetFactor);
|
||||
/*this->*/shadows = serializer["vxgi"]["shadows"].as(/*this->*/shadows);
|
||||
|
||||
@ -24,7 +24,7 @@ namespace ext {
|
||||
uf::stl::vector<VkImageView> views;
|
||||
#endif
|
||||
|
||||
size_t cascades = 0;
|
||||
size_t regions = 0;
|
||||
float cascadePower = 0;
|
||||
float granularity = 0;
|
||||
float voxelizeScale = 0;
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include <uf/utils/math/physics/broadphase/bvh.h>
|
||||
|
||||
#include <uf/engine/ext.h>
|
||||
#include "../ext/voxelizer/behavior.h" // yucky
|
||||
|
||||
#if UF_ENV_DREAMCAST
|
||||
#define UF_DEBUG_TIMER_MULTITRACE_START(...) UF_TIMER_MULTITRACE_START(__VA_ARGS__)
|
||||
@ -208,17 +209,17 @@ namespace {
|
||||
size_t maxTextures = storage.textures.map.size();
|
||||
size_t maxCubemaps = uf::config["engine"]["scenes"]["textures"]["max"]["cube"].as<size_t>(128);
|
||||
size_t maxTextures3D = uf::config["engine"]["scenes"]["textures"]["max"]["3D"].as<size_t>(128);
|
||||
uint32_t maxCascades = sceneTextures.voxels.id.size();
|
||||
uint32_t maxRegions = sceneTextures.voxels.id.size();
|
||||
|
||||
shader.setSpecializationConstants({
|
||||
{ "TEXTURES", maxTextures },
|
||||
{ "CUBEMAPS", maxCubemaps },
|
||||
{ "CASCADES", maxCascades },
|
||||
{ "REGIONS", maxRegions },
|
||||
});
|
||||
shader.setDescriptorCounts({
|
||||
{ "samplerTextures", maxTextures },
|
||||
{ "samplerCubemaps", maxCubemaps },
|
||||
{ "voxelOutput", maxCascades },
|
||||
{ "voxelOutput", maxRegions },
|
||||
});
|
||||
#endif
|
||||
}
|
||||
@ -279,21 +280,21 @@ namespace {
|
||||
}
|
||||
|
||||
uint32_t maxTextures = texture2Ds;
|
||||
uint32_t maxCascades = sceneTextures.voxels.id.size();
|
||||
uint32_t maxRegions = sceneTextures.voxels.id.size();
|
||||
|
||||
// fragment shader
|
||||
{
|
||||
auto& shader = graphic.material.getShader("fragment", uf::renderer::settings::pipelines::names::vxgi);
|
||||
shader.setSpecializationConstants({
|
||||
{ "TEXTURES", maxTextures },
|
||||
{ "CASCADES", maxCascades },
|
||||
{ "REGIONS", maxRegions },
|
||||
});
|
||||
shader.setDescriptorCounts({
|
||||
{ "samplerTextures", maxTextures },
|
||||
{ "voxelId", maxCascades },
|
||||
{ "voxelNormal", maxCascades },
|
||||
{ "voxelRadiance", maxCascades },
|
||||
{ "voxelOutput", maxCascades },
|
||||
{ "voxelId", maxRegions },
|
||||
{ "voxelNormal", maxRegions },
|
||||
{ "voxelRadiance", maxRegions },
|
||||
{ "voxelOutput", maxRegions },
|
||||
});
|
||||
|
||||
for ( auto& t : sceneTextures.voxels.id ) shader.textures.emplace_back().aliasTexture(t);
|
||||
@ -411,11 +412,11 @@ namespace {
|
||||
|
||||
// bind buffers
|
||||
::resetBuffers( shader );
|
||||
shader.aliasBuffer( storage.buffers.joint );
|
||||
shader.aliasBuffer( vertexPositionBuffer );
|
||||
shader.aliasBuffer( vertexJointsBuffer );
|
||||
shader.aliasBuffer( vertexWeightsBuffer );
|
||||
shader.aliasBuffer( vertexOutPosition );
|
||||
shader.aliasBuffer( "joint", storage.buffers.joint );
|
||||
shader.aliasBuffer( "vertexPositionBuffer", vertexPositionBuffer );
|
||||
shader.aliasBuffer( "vertexJointsBuffer", vertexJointsBuffer );
|
||||
shader.aliasBuffer( "vertexWeightsBuffer", vertexWeightsBuffer );
|
||||
shader.aliasBuffer( "vertexOutPosition", vertexOutPosition );
|
||||
}
|
||||
|
||||
graphic.generateBottomAccelerationStructures();
|
||||
@ -502,6 +503,13 @@ namespace {
|
||||
|
||||
// vxgi pipeline
|
||||
if ( uf::renderer::settings::pipelines::vxgi ) {
|
||||
// geom
|
||||
{
|
||||
auto& shader = graphic.material.getShader("geometry", uf::renderer::settings::pipelines::names::vxgi);
|
||||
|
||||
::resetBuffers( shader );
|
||||
shader.aliasBuffer( "region", storage.buffers.region );
|
||||
}
|
||||
// fragment shader
|
||||
{
|
||||
auto& shader = graphic.material.getShader("fragment", uf::renderer::settings::pipelines::names::vxgi);
|
||||
@ -514,6 +522,7 @@ namespace {
|
||||
shader.aliasBuffer( "material", storage.buffers.material );
|
||||
shader.aliasBuffer( "texture", storage.buffers.texture );
|
||||
shader.aliasBuffer( "light", storage.buffers.light );
|
||||
shader.aliasBuffer( "region", storage.buffers.region );
|
||||
}
|
||||
}
|
||||
// baking pipeline
|
||||
@ -1770,6 +1779,7 @@ void uf::graph::initialize( pod::Graph::Storage& storage, size_t initialElements
|
||||
if ( !storage.buffers.material.buffer ) storage.buffers.material.initialize( (const void*) nullptr, sizeof(pod::Material) * initialElements, uf::renderer::enums::Buffer::STORAGE );
|
||||
if ( !storage.buffers.texture.buffer ) storage.buffers.texture.initialize( (const void*) nullptr, sizeof(pod::Texture) * initialElements, uf::renderer::enums::Buffer::STORAGE );
|
||||
if ( !storage.buffers.light.buffer ) storage.buffers.light.initialize( (const void*) nullptr, sizeof(pod::Light) * initialElements, uf::renderer::enums::Buffer::STORAGE );
|
||||
if ( !storage.buffers.region.buffer ) storage.buffers.region.initialize( (const void*) nullptr, sizeof(pod::Region) * initialElements, uf::renderer::enums::Buffer::STORAGE );
|
||||
}
|
||||
|
||||
void uf::graph::initialize( pod::Graph& graph ) {
|
||||
@ -1935,6 +1945,7 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
|
||||
rebuild = storage.buffers.lodMetadata.update( (const void*) lodMetadata.data(), lodMetadata.size() * sizeof(pod::LODMetadata) ) || rebuild;
|
||||
rebuild = storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) ) || rebuild;
|
||||
rebuild = storage.buffers.texture.update( (const void*) textures.data(), textures.size() * sizeof(pod::Texture) ) || rebuild;
|
||||
// rebuild = storage.buffers.region.update( (const void*) storage.regions.data(), storage.regions.size() * sizeof(pod::Region) ) || rebuild;
|
||||
|
||||
storage.stale = false;
|
||||
}
|
||||
@ -1956,9 +1967,11 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
|
||||
shader.aliasBuffer( "drawCommands", storage.buffers.drawCommands );
|
||||
shader.aliasBuffer( "instance", storage.buffers.instance );
|
||||
shader.aliasBuffer( "addresses", storage.buffers.addresses );
|
||||
shader.aliasBuffer( "object", storage.buffers.object );
|
||||
shader.aliasBuffer( "material", storage.buffers.material );
|
||||
shader.aliasBuffer( "texture", storage.buffers.texture );
|
||||
shader.aliasBuffer( "light", storage.buffers.light );
|
||||
shader.aliasBuffer( "region", storage.buffers.region );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -2096,13 +2109,13 @@ void uf::graph::render( pod::Graph::Storage& storage ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
storage.buffers.camera.update( (const void*) &viewport, sizeof(pod::Camera::Viewports) );
|
||||
|
||||
#if UF_USE_VULKAN
|
||||
if ( !renderMode || !renderMode->hasBuffer("camera") || renderMode->getType() == "Swapchain" ) return;
|
||||
auto& buffer = renderMode->getBuffer("camera");
|
||||
buffer.update( (const void*) &viewport, sizeof(pod::Camera::Viewports) );
|
||||
if ( renderMode->hasBuffer("camera") ) {
|
||||
auto& buffer = renderMode->getBuffer("camera");
|
||||
buffer.update( (const void*) &viewport, sizeof(pod::Camera::Viewports) );
|
||||
} else
|
||||
#endif
|
||||
storage.buffers.camera.update( (const void*) &viewport, sizeof(pod::Camera::Viewports) );
|
||||
}
|
||||
void uf::graph::destroy( bool soft ) {
|
||||
soft = false;
|
||||
@ -2162,6 +2175,7 @@ void uf::graph::destroy( pod::Graph::Storage& storage, bool soft ) {
|
||||
storage.buffers.material.destroy(true);
|
||||
storage.buffers.texture.destroy(true);
|
||||
storage.buffers.light.destroy(true);
|
||||
storage.buffers.region.destroy(true);
|
||||
storage.buffers.depthPyramid.destroy(true);
|
||||
}
|
||||
|
||||
@ -2839,6 +2853,86 @@ void uf::graph::reload( pod::Graph& graph ) {
|
||||
if ( !readQueue.empty() ) {
|
||||
executing = true;
|
||||
}
|
||||
/*
|
||||
// to-do: finish implementing
|
||||
if ( uf::renderer::settings::pipelines::vxgi ) {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
// auto& metadataVxgi = // to-do: bind settings properly, can probably just fill it out with a dummy struct to test with for the moment
|
||||
struct {
|
||||
pod::Vector3f voxelSize = { 64, 64, 64 };
|
||||
size_t cascades = 256;
|
||||
} metadataVxgi;
|
||||
|
||||
storage.regions.clear();
|
||||
struct RegionBounds {
|
||||
pod::Vector3f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
|
||||
pod::Vector3f max = {-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max(),-std::numeric_limits<float>::max() };
|
||||
bool initialized = false; // could probably just check if min/max are not max/-max'd
|
||||
};
|
||||
uf::stl::unordered_map<int32_t, RegionBounds> sectors;
|
||||
uf::stl::unordered_map<int32_t, uint32_t> indexMap;
|
||||
|
||||
for ( auto& node : graph.nodes ) {
|
||||
if ( !(0 <= node.mesh && node.mesh < graph.meshes.size()) ) continue;
|
||||
if ( !node.entity ) continue;
|
||||
|
||||
auto& entity = node.entity->as<uf::Object>();
|
||||
auto& transform = entity.getComponent<pod::Transform<>>();
|
||||
auto worldTransform = uf::transform::flatten( transform );
|
||||
auto model = uf::transform::model( transform );
|
||||
|
||||
auto& key = graph.primitives[node.mesh];
|
||||
auto& primitives = storage.primitives.map[key];
|
||||
|
||||
for ( auto& primitive : primitives ) {
|
||||
int32_t regionID = primitive.instance.lightmapID;
|
||||
if ( regionID < 0 ) continue;
|
||||
|
||||
auto& bounds = primitive.instance.bounds;
|
||||
auto& sector = sectors[regionID];
|
||||
|
||||
pod::Vector3f corners[8] = {
|
||||
{bounds.min.x, bounds.min.y, bounds.min.z},
|
||||
{bounds.max.x, bounds.min.y, bounds.min.z},
|
||||
{bounds.min.x, bounds.max.y, bounds.min.z},
|
||||
{bounds.max.x, bounds.max.y, bounds.min.z},
|
||||
{bounds.min.x, bounds.min.y, bounds.max.z},
|
||||
{bounds.max.x, bounds.min.y, bounds.max.z},
|
||||
{bounds.min.x, bounds.max.y, bounds.max.z},
|
||||
{bounds.max.x, bounds.max.y, bounds.max.z}
|
||||
};
|
||||
|
||||
for ( int c = 0; c < 8; ++c ) {
|
||||
pod::Vector3f transformed = uf::matrix::multiply( model, corners[c], 1.0f );
|
||||
sector.min = uf::vector::min( sector.min, transformed );
|
||||
sector.max = uf::vector::max( sector.max, transformed );
|
||||
}
|
||||
sector.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto& [regionID, sector] : sectors ) {
|
||||
if ( !sector.initialized ) continue;
|
||||
if ( indexMap.count(regionID) == 0 ) {
|
||||
uint32_t nextIndex = storage.regions.size();
|
||||
if ( nextIndex >= metadataVxgi.cascades ) continue;
|
||||
indexMap[regionID] = nextIndex;
|
||||
}
|
||||
|
||||
float padding = 2.0f;
|
||||
pod::Region region = {};
|
||||
region.minBounds = sector.min - padding;
|
||||
region.maxBounds = sector.max + padding;
|
||||
region.size = metadataVxgi.voxelSize.x;
|
||||
region.index = indexMap[regionID];
|
||||
|
||||
storage.regions.emplace_back( region );
|
||||
if ( storage.regions.size() >= metadataVxgi.cascades ) break;
|
||||
}
|
||||
|
||||
storage.stale = true;
|
||||
}
|
||||
*/
|
||||
|
||||
uf::asset::processIO( readQueue, true, false ); // async, wait
|
||||
}
|
||||
|
||||
@ -385,14 +385,15 @@ VkSubmitInfo ext::vulkan::RenderMode::queue() {
|
||||
if ( !metadata.limiter.execute ) return {};
|
||||
|
||||
auto& commands = getCommands( this->mostRecentCommandPoolId );
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pWaitDstStageMask = NULL; // Pointer to the list of pipeline stages that the semaphore waits will occur at
|
||||
submitInfo.pWaitSemaphores = NULL; // Semaphore(s) to wait upon before the submitted command buffer starts executing
|
||||
submitInfo.waitSemaphoreCount = 0; // One wait semaphore
|
||||
submitInfo.pSignalSemaphores = NULL; // Semaphore(s) to be signaled when command buffers have completed
|
||||
submitInfo.signalSemaphoreCount = 0; // One signal semaphore
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission)
|
||||
submitInfo.pWaitDstStageMask = NULL;
|
||||
submitInfo.pWaitSemaphores = NULL;
|
||||
submitInfo.waitSemaphoreCount = 0;
|
||||
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[states::currentBuffer];
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer];
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
||||
return submitInfo;
|
||||
|
||||
@ -267,16 +267,34 @@ void ext::vulkan::BaseRenderMode::render() {
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );
|
||||
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
|
||||
|
||||
{
|
||||
VkSubmitInfo submitInfo = this->queue();
|
||||
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
|
||||
|
||||
STATIC_THREAD_LOCAL(uf::stl::vector<VkSemaphore>, waitSemaphores);
|
||||
STATIC_THREAD_LOCAL(uf::stl::vector<VkPipelineStageFlags>, waitStages);
|
||||
|
||||
waitSemaphores.push_back(swapchain.presentCompleteSemaphores[states::currentBuffer]);
|
||||
waitStages.push_back(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
|
||||
|
||||
for ( auto* layer : layers ) {
|
||||
if ( !layer || !layer->executed ) continue;
|
||||
|
||||
waitSemaphores.push_back(layer->renderCompleteSemaphores[states::currentBuffer]);
|
||||
waitStages.push_back(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
|
||||
}
|
||||
|
||||
submitInfo.waitSemaphoreCount = waitSemaphores.size();
|
||||
submitInfo.pWaitSemaphores = waitSemaphores.data();
|
||||
submitInfo.pWaitDstStageMask = waitStages.data();
|
||||
|
||||
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, fences[states::currentBuffer]);
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
VkSubmitInfo submitInfo = this->queue();
|
||||
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
|
||||
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, fences[states::currentBuffer]);
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
}
|
||||
|
||||
VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( QueueEnum::PRESENT ), ::imageIndex, renderCompleteSemaphores[::imageIndex]));
|
||||
VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( QueueEnum::PRESENT ), ::imageIndex, renderCompleteSemaphores[states::currentBuffer]));
|
||||
|
||||
states::currentBuffer = (states::currentBuffer + 1) % ext::vulkan::swapchain.buffers;
|
||||
this->executed = true;
|
||||
|
||||
@ -342,20 +342,20 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
size_t maxTextures2D = uf::config["engine"]["scenes"]["textures"]["max"]["2D"].as<size_t>(512);
|
||||
size_t maxTexturesCube = uf::config["engine"]["scenes"]["textures"]["max"]["cube"].as<size_t>(128);
|
||||
size_t maxTextures3D = uf::config["engine"]["scenes"]["textures"]["max"]["3D"].as<size_t>(128);
|
||||
size_t maxCascades = uf::config["engine"]["scenes"]["vxgi"]["cascades"].as<size_t>(16);
|
||||
size_t maxRegions = uf::config["engine"]["scenes"]["vxgi"]["regions"].as<size_t>(64);
|
||||
|
||||
shader.setSpecializationConstants({
|
||||
{ "TEXTURES", maxTextures2D },
|
||||
{ "CUBEMAPS", maxTexturesCube },
|
||||
{ "CASCADES", maxCascades },
|
||||
{ "REGIONS", maxRegions },
|
||||
});
|
||||
shader.setDescriptorCounts({
|
||||
{ "samplerTextures", maxTextures2D },
|
||||
{ "samplerCubemaps", maxTexturesCube },
|
||||
{ "voxelId", maxCascades },
|
||||
{ "voxelNormal", maxCascades },
|
||||
{ "voxelRadiance", maxCascades },
|
||||
{ "voxelOutput", maxCascades },
|
||||
{ "voxelId", maxRegions },
|
||||
{ "voxelNormal", maxRegions },
|
||||
{ "voxelRadiance", maxRegions },
|
||||
{ "voxelOutput", maxRegions },
|
||||
});
|
||||
|
||||
shader.aliasAttachment("id", this);
|
||||
@ -545,15 +545,16 @@ void ext::vulkan::DeferredRenderMode::build( bool resized ) {
|
||||
auto& shader = blitter.material.getShader("compute", "deferred");
|
||||
|
||||
shader.metadata.aliases.buffers.clear();
|
||||
shader.aliasBuffer( storage.buffers.camera );
|
||||
// shader.aliasBuffer( storage.buffers.joint );
|
||||
shader.aliasBuffer( storage.buffers.drawCommands );
|
||||
shader.aliasBuffer( storage.buffers.instance );
|
||||
shader.aliasBuffer( storage.buffers.addresses );
|
||||
shader.aliasBuffer( storage.buffers.object );
|
||||
shader.aliasBuffer( storage.buffers.material );
|
||||
shader.aliasBuffer( storage.buffers.texture );
|
||||
shader.aliasBuffer( storage.buffers.light );
|
||||
shader.aliasBuffer( "camera", storage.buffers.camera );
|
||||
// shader.aliasBuffer( "joint", storage.buffers.joint );
|
||||
shader.aliasBuffer( "drawCommands", storage.buffers.drawCommands );
|
||||
shader.aliasBuffer( "instance", storage.buffers.instance );
|
||||
shader.aliasBuffer( "addresses", storage.buffers.addresses );
|
||||
shader.aliasBuffer( "object", storage.buffers.object );
|
||||
shader.aliasBuffer( "material", storage.buffers.material );
|
||||
shader.aliasBuffer( "texture", storage.buffers.texture );
|
||||
shader.aliasBuffer( "light", storage.buffers.light );
|
||||
shader.aliasBuffer( "region", storage.buffers.region );
|
||||
}
|
||||
|
||||
// (re)initialize pipelines
|
||||
@ -660,21 +661,6 @@ void ext::vulkan::DeferredRenderMode::tick() {
|
||||
this->build( resized );
|
||||
}
|
||||
}
|
||||
VkSubmitInfo ext::vulkan::DeferredRenderMode::queue() {
|
||||
auto& commands = getCommands( this->mostRecentCommandPoolId );
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pWaitDstStageMask = NULL;
|
||||
submitInfo.pWaitSemaphores = NULL;
|
||||
submitInfo.waitSemaphoreCount = 0;
|
||||
submitInfo.pSignalSemaphores = NULL;
|
||||
submitInfo.signalSemaphoreCount = 0;
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer];
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
||||
return submitInfo;
|
||||
}
|
||||
void ext::vulkan::DeferredRenderMode::render() {
|
||||
if ( this->commands.container().empty() ) return;
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderTargetRenderMode::bindGraphicD
|
||||
descriptor.cullMode = VK_CULL_MODE_NONE;
|
||||
descriptor.depth.test = false;
|
||||
descriptor.depth.write = false;
|
||||
} else if ( metadata.type == "depth" ) {
|
||||
} else if ( metadata.type == "depth" || metadata.type == uf::renderer::settings::pipelines::names::vxgi ) {
|
||||
descriptor.cullMode = VK_CULL_MODE_NONE;
|
||||
}
|
||||
return descriptor;
|
||||
@ -43,7 +43,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
|
||||
|
||||
//
|
||||
if ( metadata.type == "depth" ) {
|
||||
buffers.emplace_back().initialize( NULL, sizeof(pod::Camera::Viewports), uf::renderer::enums::Buffer::UNIFORM );
|
||||
this->metadata.buffers["camera"] = this->initializeBuffer( (const void*) nullptr, sizeof(pod::Camera::Viewports), uf::renderer::enums::Buffer::UNIFORM );
|
||||
}
|
||||
|
||||
if ( metadata.type == "depth" || metadata.type == uf::renderer::settings::pipelines::names::vxgi ) {
|
||||
@ -247,15 +247,16 @@ void ext::vulkan::RenderTargetRenderMode::build( bool resized ) {
|
||||
if ( metadata.type == uf::renderer::settings::pipelines::names::vxgi ) {
|
||||
auto& shader = blitter.material.getShader("compute");
|
||||
|
||||
// shader.aliasBuffer( storage.buffers.camera );
|
||||
// shader.aliasBuffer( storage.buffers.joint );
|
||||
shader.aliasBuffer( storage.buffers.drawCommands );
|
||||
shader.aliasBuffer( storage.buffers.instance );
|
||||
shader.aliasBuffer( storage.buffers.addresses );
|
||||
shader.aliasBuffer( storage.buffers.object );
|
||||
shader.aliasBuffer( storage.buffers.material );
|
||||
shader.aliasBuffer( storage.buffers.texture );
|
||||
shader.aliasBuffer( storage.buffers.light );
|
||||
// shader.aliasBuffer( "camera", storage.buffers.camera );
|
||||
// shader.aliasBuffer( "joint", storage.buffers.joint );
|
||||
shader.aliasBuffer( "drawCommands", storage.buffers.drawCommands );
|
||||
shader.aliasBuffer( "instance", storage.buffers.instance );
|
||||
shader.aliasBuffer( "addresses", storage.buffers.addresses );
|
||||
shader.aliasBuffer( "object", storage.buffers.object );
|
||||
shader.aliasBuffer( "material", storage.buffers.material );
|
||||
shader.aliasBuffer( "texture", storage.buffers.texture );
|
||||
shader.aliasBuffer( "light", storage.buffers.light );
|
||||
shader.aliasBuffer( "region", storage.buffers.region );
|
||||
}
|
||||
|
||||
// (re)initialize pipelines
|
||||
|
||||
@ -8,7 +8,7 @@ namespace {
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
) {
|
||||
uf::stl::unordered_set<VkImage> transitioned;
|
||||
|
||||
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
@ -51,11 +51,17 @@ namespace {
|
||||
if ( isDepth && layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) {
|
||||
oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, image, oldLayout, descriptor.layout, subresourceRange );
|
||||
|
||||
VkImageLayout targetLayout = descriptor.layout;
|
||||
if ( isDepth && targetLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) {
|
||||
targetLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, image, oldLayout, targetLayout, subresourceRange );
|
||||
if ( mips > 1 ) {
|
||||
subresourceRange.baseMipLevel = 1;
|
||||
subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, image, initialLayout, descriptor.layout, subresourceRange );
|
||||
uf::renderer::Texture::setImageLayout( commandBuffer, image, initialLayout, targetLayout, subresourceRange );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -518,7 +518,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
|
||||
.size = bufferSize,
|
||||
};
|
||||
|
||||
if ( IS_DYNAMIC(name) ) {
|
||||
if ( VK_UBO_USE_N_BUFFERS && IS_DYNAMIC(name) ) {
|
||||
descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||
metadata.dynamicRanges.emplace_back( bufferSize );
|
||||
}
|
||||
|
||||
@ -274,7 +274,7 @@ void uf::debug::drawLines( float dt ) {
|
||||
// vertex shader
|
||||
{
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
shader.aliasBuffer( storage.buffers.camera );
|
||||
shader.aliasBuffer( "camera", storage.buffers.camera );
|
||||
#if UF_USE_VULKAN
|
||||
uint32_t maxPasses = 6;
|
||||
shader.setSpecializationConstants({
|
||||
@ -368,7 +368,7 @@ void uf::debug::drawTexts( float dt ) {
|
||||
// vertex shader
|
||||
{
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
shader.aliasBuffer( storage.buffers.camera );
|
||||
shader.aliasBuffer( "camera", storage.buffers.camera );
|
||||
#if UF_USE_VULKAN
|
||||
uint32_t maxPasses = 6;
|
||||
shader.setSpecializationConstants({
|
||||
|
||||
Loading…
Reference in New Issue
Block a user