From e7da8db0006bd4519c8528917ed8c6e6e04ea992 Mon Sep 17 00:00:00 2001 From: mrq Date: Sun, 16 May 2021 00:00:00 -0500 Subject: [PATCH] Commit for 2021.05.16.7z --- Makefile | 16 +- .../base/{frag.glsl => base.frag.glsl} | 26 +- .../base/{vert.glsl => base.vert.glsl} | 1 + bin/data/shaders/base/colored.vert.glsl | 1 + bin/data/shaders/common/fog.h | 56 ++ bin/data/shaders/common/functions.h | 73 ++ bin/data/shaders/common/macros.h | 47 + bin/data/shaders/common/pbr.h | 54 ++ bin/data/shaders/common/shadows.h | 64 ++ bin/data/shaders/common/structs.h | 138 +++ bin/data/shaders/common/vxgi.h | 194 +++++ .../display/{vert.glsl => base.vert.glsl} | 1 + bin/data/shaders/display/blit.frag.glsl | 1 + bin/data/shaders/display/blit.vert.glsl | 1 + .../shaders/display/mip.gaussian.comp.glsl | 67 ++ .../shaders/display/rendertarget.frag.glsl | 44 +- .../display/rendertarget.no-msaa.frag.glsl | 51 ++ .../shaders/display/rendertarget.vert.glsl | 1 + bin/data/shaders/display/subpass.frag.glsl | 602 +------------ bin/data/shaders/display/subpass.h | 219 +++++ .../shaders/display/subpass.no-msaa.frag.glsl | 15 + .../shaders/display/subpass.old.frag.glsl | 559 ------------ bin/data/shaders/display/subpass.vert.glsl | 1 + .../shaders/display/subpass.vxgi.frag.glsl | 821 +----------------- .../display/subpass.vxgi.no-msaa.frag.glsl | 17 + bin/data/shaders/display/vxgi.comp.glsl | 15 +- bin/data/shaders/gltf/baked.frag.glsl | 64 +- bin/data/shaders/gltf/baking/bake.frag.glsl | 219 +---- bin/data/shaders/gltf/baking/bake.vert.glsl | 1 + bin/data/shaders/gltf/base.frag.glsl | 60 +- bin/data/shaders/gltf/base.vert.glsl | 1 + bin/data/shaders/gltf/instanced.vert.glsl | 1 + .../shaders/gltf/skinned.instanced.vert.glsl | 1 + bin/data/shaders/gltf/skinned.vert.glsl | 1 + bin/data/shaders/gltf/voxelize.frag.glsl | 93 +- bin/data/shaders/gltf/voxelize.geom.glsl | 19 +- bin/data/shaders/gui/base.frag.glsl | 23 +- bin/data/shaders/gui/base.vert.glsl | 1 + bin/data/shaders/gui/text.frag.glsl | 7 +- bin/data/shaders/gui/text.vert.glsl | 1 + bin/data/shaders/heightmap/frag.glsl | 19 - bin/data/shaders/heightmap/vert.glsl | 52 -- .../line/{frag.glsl => base.frag.glsl} | 1 + .../line/{vert.glsl => base.vert.glsl} | 1 + bin/data/shaders/noise/frag.glsl | 23 - .../raytracing/{comp.glsl => base.comp.glsl} | 1 + .../terrain/{frag.glsl => base.frag.glsl} | 1 + .../terrain/{vert.glsl => base.vert.glsl} | 1 + bin/data/shaders/texture/frag.glsl | 11 - bin/data/shaders/texture/vert.glsl | 14 - client/client/ext.cpp | 205 +---- client/main.cpp | 5 +- engine/inc/uf/ext/gltf/pod.h | 1 + engine/inc/uf/ext/vulkan/buffer.h | 2 + engine/inc/uf/ext/vulkan/graphic.h | 49 +- engine/inc/uf/ext/vulkan/shader.h | 61 ++ engine/inc/uf/ext/vulkan/texture.h | 6 +- engine/inc/uf/utils/io/file.h | 12 + engine/inc/uf/utils/io/file.inl | 0 engine/src/engine/asset/asset.cpp | 9 +- engine/src/ext/bullet/bullet.cpp | 2 +- engine/src/ext/gltf/graph.cpp | 4 +- engine/src/ext/ultralight/ultralight.cpp | 7 +- engine/src/ext/vulkan/buffer.cpp | 67 +- engine/src/ext/vulkan/device.cpp | 53 +- engine/src/ext/vulkan/graphic.cpp | 781 +---------------- .../src/ext/vulkan/rendermodes/deferred.cpp | 45 +- .../ext/vulkan/rendermodes/rendertarget.cpp | 39 +- engine/src/ext/vulkan/rendertarget.cpp | 23 +- engine/src/ext/vulkan/shader.cpp | 787 +++++++++++++++++ engine/src/ext/vulkan/texture.cpp | 41 +- engine/src/ext/vulkan/vulkan.cpp | 17 +- engine/src/spec/controller/windows.cpp | 9 +- engine/src/spec/window/windows.cpp | 42 +- engine/src/utils/io/file.cpp | 10 + engine/src/utils/window/window.cpp | 68 +- ext/behaviors/hands/behavior.cpp | 18 +- ext/behaviors/light/behavior.cpp | 17 +- ext/behaviors/noise/behavior.cpp | 4 +- ext/behaviors/player/behavior.cpp | 76 +- ext/behaviors/scene/behavior.cpp | 41 +- ext/behaviors/sprite/behavior.cpp | 4 +- ext/behaviors/voxelizer/behavior.cpp | 86 +- ext/gui/behavior.cpp | 19 +- ext/gui/html/behavior.cpp | 11 +- ext/gui/manager/behavior.cpp | 12 +- ext/inits/persistence.inl | 10 +- ext/scenes/worldscape/terrain/behavior.cpp | 4 +- ext/scenes/worldscape/terrain/region.cpp | 4 +- 89 files changed, 2496 insertions(+), 3856 deletions(-) rename bin/data/shaders/base/{frag.glsl => base.frag.glsl} (62%) rename bin/data/shaders/base/{vert.glsl => base.vert.glsl} (93%) create mode 100644 bin/data/shaders/common/fog.h create mode 100644 bin/data/shaders/common/functions.h create mode 100644 bin/data/shaders/common/macros.h create mode 100644 bin/data/shaders/common/pbr.h create mode 100644 bin/data/shaders/common/shadows.h create mode 100644 bin/data/shaders/common/structs.h create mode 100644 bin/data/shaders/common/vxgi.h rename bin/data/shaders/display/{vert.glsl => base.vert.glsl} (84%) create mode 100644 bin/data/shaders/display/mip.gaussian.comp.glsl create mode 100644 bin/data/shaders/display/rendertarget.no-msaa.frag.glsl create mode 100644 bin/data/shaders/display/subpass.h create mode 100644 bin/data/shaders/display/subpass.no-msaa.frag.glsl delete mode 100644 bin/data/shaders/display/subpass.old.frag.glsl create mode 100644 bin/data/shaders/display/subpass.vxgi.no-msaa.frag.glsl delete mode 100644 bin/data/shaders/heightmap/frag.glsl delete mode 100644 bin/data/shaders/heightmap/vert.glsl rename bin/data/shaders/line/{frag.glsl => base.frag.glsl} (81%) rename bin/data/shaders/line/{vert.glsl => base.vert.glsl} (91%) delete mode 100644 bin/data/shaders/noise/frag.glsl rename bin/data/shaders/raytracing/{comp.glsl => base.comp.glsl} (96%) rename bin/data/shaders/terrain/{frag.glsl => base.frag.glsl} (91%) rename bin/data/shaders/terrain/{vert.glsl => base.vert.glsl} (94%) delete mode 100644 bin/data/shaders/texture/frag.glsl delete mode 100644 bin/data/shaders/texture/vert.glsl create mode 100644 engine/inc/uf/ext/vulkan/shader.h create mode 100644 engine/inc/uf/utils/io/file.inl create mode 100644 engine/src/ext/vulkan/shader.cpp diff --git a/Makefile b/Makefile index 96f5768c..d7ae9a7a 100644 --- a/Makefile +++ b/Makefile @@ -24,8 +24,11 @@ LIB_NAME += uf EXT_LIB_NAME += ext #VULKAN_SDK_PATH += /c/VulkanSDK/1.2.154.0/ -VULKAN_SDK_PATH += /c/VulkanSDK/1.2.162.0/ -GLSL_VALIDATOR += $(VULKAN_SDK_PATH)/Bin32/glslangValidator +#VULKAN_SDK_PATH += /c/VulkanSDK/1.2.162.0/ +VULKAN_SDK_PATH += /c/VulkanSDK/1.2.176.1/ +#GLSL_VALIDATOR += $(VULKAN_SDK_PATH)/Bin32/glslangValidator +GLSL_VALIDATOR += $(VULKAN_SDK_PATH)/Bin32/glslc +SPV_OPTIMIZER += $(VULKAN_SDK_PATH)/Bin32/spirv-opt # Base Engine's DLL INC_DIR += $(ENGINE_INC_DIR)/$(ARCH)/$(PREFIX) DEPS += @@ -39,7 +42,7 @@ INCS += -I$(ENGINE_INC_DIR) -I$(INC_DIR) -I$(VULKAN_SDK_PATH)/include -I/mi LIBS += -L$(ENGINE_LIB_DIR) -L$(LIB_DIR) -L$(LIB_DIR)/$(PREFIX) -L$(VULKAN_SDK_PATH)/Lib ifneq (,$(findstring win64,$(ARCH))) - REQ_DEPS += vulkan json:nlohmann png openal ogg freetype ncurses curl luajit bullet meshoptimizer xatlas # draco discord + REQ_DEPS += vulkan json:nlohmann png openal ogg freetype ncurses curl luajit bullet meshoptimizer xatlas openvr # draco discord FLAGS += DEPS += -lgdi32 else ifneq (,$(findstring dreamcast,$(ARCH))) @@ -240,7 +243,9 @@ $(TARGET): $(OBJS) endif %.spv: %.glsl - $(GLSL_VALIDATOR) -V -o $@ $< +# $(GLSL_VALIDATOR) -V -o $@ $< + $(GLSL_VALIDATOR) -std=450 -o $@ $< + $(SPV_OPTIMIZER) --preserve-bindings --preserve-spec-constants -O $@ -o $@ ifneq (,$(findstring dreamcast,$(ARCH))) clean: @@ -283,4 +288,7 @@ clean-exe: -rm $(EX_DLL) -rm $(EXT_EX_DLL) -rm $(TARGET) + -rm $(TARGET_SHADERS) + +clean-shaders: -rm $(TARGET_SHADERS) \ No newline at end of file diff --git a/bin/data/shaders/base/frag.glsl b/bin/data/shaders/base/base.frag.glsl similarity index 62% rename from bin/data/shaders/base/frag.glsl rename to bin/data/shaders/base/base.frag.glsl index 177d0217..e8cc6c81 100644 --- a/bin/data/shaders/base/frag.glsl +++ b/bin/data/shaders/base/base.frag.glsl @@ -1,7 +1,11 @@ #version 450 +#pragma shader_stage(fragment) -#define UF_DEFERRED_SAMPLING 0 -#define UF_CAN_DISCARD 1 +#define TEXTURES 1 +#define MAX_TEXTURES TEXTURES +#include "../common/macros.h" +#include "../common/structs.h" +#include "../common/functions.h" layout (binding = 1) uniform sampler2D samplerTexture; @@ -12,36 +16,26 @@ layout (location = 3) in vec3 inPosition; layout (location = 0) out uvec2 outId; layout (location = 1) out vec2 outNormals; -#if UF_DEFERRED_SAMPLING +#if DEFERRED_SAMPLING layout (location = 2) out vec2 outUvs; #else layout (location = 2) out vec4 outAlbedo; #endif -vec2 encodeNormals( vec3 n ) { - float p = sqrt(n.z*8+8); - return n.xy/p + 0.5; -} -float mipLevel( in vec2 uv ) { - vec2 dx_vtc = dFdx(uv); - vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); -} - void main() { float mip = mipLevel(inUv.xy); vec2 uv = inUv.xy; vec4 C = vec4(1, 1, 1, 1); vec3 P = inPosition; vec3 N = inNormal; -#if UF_DEFERRED_SAMPLING +#if DEFERRED_SAMPLING outUvs = wrap(inUv.xy); vec4 outAlbedo = vec4(0,0,0,0); #endif -#if !UF_DEFERRED_SAMPLING || UF_CAN_DISCARD +#if !DEFERRED_SAMPLING || CAN_DISCARD C = textureLod( samplerTexture, uv, mip ); #endif -#if !UF_DEFERRED_SAMPLING +#if !DEFERRED_SAMPLING outAlbedo = C * inColor; #endif outNormals = encodeNormals( N ); diff --git a/bin/data/shaders/base/vert.glsl b/bin/data/shaders/base/base.vert.glsl similarity index 93% rename from bin/data/shaders/base/vert.glsl rename to bin/data/shaders/base/base.vert.glsl index 0c83f290..41e163bf 100644 --- a/bin/data/shaders/base/vert.glsl +++ b/bin/data/shaders/base/base.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec3 inPos; diff --git a/bin/data/shaders/base/colored.vert.glsl b/bin/data/shaders/base/colored.vert.glsl index f2d96b4a..579f5372 100644 --- a/bin/data/shaders/base/colored.vert.glsl +++ b/bin/data/shaders/base/colored.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec3 inPos; diff --git a/bin/data/shaders/common/fog.h b/bin/data/shaders/common/fog.h new file mode 100644 index 00000000..5391e33d --- /dev/null +++ b/bin/data/shaders/common/fog.h @@ -0,0 +1,56 @@ +// Perlin Fog +void fog( in Ray ray, inout vec3 i, float scale ) { + if ( ubo.fog.stepScale <= 0 || ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return; +#if FOG_RAY_MARCH + const float range = ubo.fog.range.y; + const vec3 boundsMin = vec3(-range,-range,-range) + ray.origin; + const vec3 boundsMax = vec3(range,range,range) + ray.origin; + const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); + + const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, ray ); + const float dstToBox = rayBoxInfo.x; + const float dstInsideBox = rayBoxInfo.y; + const float depth = surface.position.eye.z; + + const float aperture = PI * 0.5; + const float coneCoefficient = 2.0 * tan(aperture * 0.5); + + // march + if ( 0 <= dstInsideBox && dstToBox <= depth ) { + float stepSize = dstInsideBox / numSteps; + float dstLimit = min( depth - dstToBox, dstInsideBox ); + float totalDensity = 0; + float transmittance = 1; + float lightFactor = scale; + float coneDiameter = coneCoefficient * ray.distance; + float level = aperture > 0 ? log2( coneDiameter ) : 0; + float density = 0; + vec3 uvw; + ray.distance = dstToBox; + while ( ray.distance < dstLimit ) { + ray.distance += stepSize; + ray.position = ray.origin + ray.direction * ray.distance; + coneDiameter = coneCoefficient * ray.distance; + level = aperture > 0 ? log2( coneDiameter ) : 0; + uvw = ray.position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01; + density = max(0, textureLod(samplerNoise, uvw, level).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier; + if ( density > 0 ) { + density = exp(-density * stepSize * ubo.fog.absorbtion); + transmittance *= density; + lightFactor *= density; + if ( transmittance < 0.1 ) break; + } + } + i.rgb = mix(ubo.fog.color.rgb, i.rgb, transmittance ); + } +#endif +#if FOG_BASIC + const vec3 color = ubo.fog.color.rgb; + const float inner = ubo.fog.range.x; + const float outer = ubo.fog.range.y * scale; + const float distance = length(-surface.position.eye); + const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 ); + + i.rgb = mix(i.rgb, color, factor); +#endif +} \ No newline at end of file diff --git a/bin/data/shaders/common/functions.h b/bin/data/shaders/common/functions.h new file mode 100644 index 00000000..c33cdf6e --- /dev/null +++ b/bin/data/shaders/common/functions.h @@ -0,0 +1,73 @@ +// Helper Functions +float random(vec3 seed, int i){ return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453); } +float rand2(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453); } +float rand3(vec3 co){ return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); } +float max3( vec3 v ) { return max(max(v.x, v.y), v.z); } +float min3( vec3 v ) { return min(min(v.x, v.y), v.z); } +uint biasedRound( float x, float bias ) { return uint( ( x < bias ) ? floor(x) : ceil(x)); } +float wrap( float i ) { return fract(i); } +vec2 wrap( vec2 uv ) { return vec2( wrap( uv.x ), wrap( uv.y ) ); } +vec3 orthogonal(vec3 u){ + u = normalize(u); + const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. + return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); +} +void whitenoise(inout vec3 color, const vec4 parameters) { + const float flicker = parameters.x; + const float pieces = parameters.y; + const float blend = parameters.z; + const float time = parameters.w; + if ( blend < 0.0001 ) return; + const float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); + const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); + color = mix( color, vec3(whiteNoise), blend ); +} +vec3 decodeNormals( vec2 enc ) { + const vec2 ang = enc*2-1; + const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); + const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); + return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); +} +vec2 encodeNormals( vec3 n ) { +// float p = sqrt(n.z*8+8); +// return n.xy/p + 0.5; + return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5; +} +float mipLevel( in vec2 uv ) { + const vec2 dx_vtc = dFdx(uv); + const vec2 dy_vtc = dFdy(uv); + return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); +} +bool validTextureIndex( int textureIndex ) { + return 0 <= textureIndex && textureIndex < MAX_TEXTURES; +} +vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) { + const vec3 t0 = (boundsMin - ray.origin) / ray.direction; + const vec3 t1 = (boundsMax - ray.origin) / ray.direction; + const vec3 tmin = min(t0, t1); + const vec3 tmax = max(t0, t1); + const float tStart = max(0, max( max(tmin.x, tmin.y), tmin.z )); + const float tEnd = max(0, min( tmax.x, min(tmax.y, tmax.z) ) - tStart); + return vec2(tStart, tEnd); +} +vec4 resolve( subpassInputMS t, const uint samples ) { + vec4 resolved = vec4(0); + for ( int i = 0; i < samples; ++i ) resolved += subpassLoad(t, i); + resolved /= vec4(samples); + return resolved; +} +uvec4 resolve( usubpassInputMS t, const uint samples ) { + uvec4 resolved = uvec4(0); + for ( int i = 0; i < samples; ++i ) resolved += subpassLoad(t, i); + resolved /= uvec4(samples); + return resolved; +} +vec4 resolve( sampler2DMS t, ivec2 uv ) { + vec4 resolved = vec4(0); + int samples = textureSamples(t); + for ( int i = 0; i < samples; ++i ) { + resolved += texelFetch(t, uv, i); + } + resolved /= float(samples); + return resolved; +} \ No newline at end of file diff --git a/bin/data/shaders/common/macros.h b/bin/data/shaders/common/macros.h new file mode 100644 index 00000000..5f53f880 --- /dev/null +++ b/bin/data/shaders/common/macros.h @@ -0,0 +1,47 @@ +#ifndef MULTISAMPLING + #define MULTISAMPLING 1 +#endif +#ifndef DEFERRED_SAMPLING + #define DEFERRED_SAMPLING 1 +#endif +#ifndef CAN_DISCARD + #define CAN_DISCARD 1 +#endif +#ifndef USE_LIGHTMAP + #define USE_LIGHTMAP 1 +#endif +#if VXGI + #define VXGI_NDC 1 + #define VXGI_SHADOWS 0 +#endif +#ifndef MAX_TEXTURES + #define MAX_TEXTURES TEXTURES +#endif +#ifndef FOG + #define FOG 1 +#endif +#ifndef FOG_RAY_MARCH + #define FOG_RAY_MARCH 1 +#endif + +#ifndef WHITENOISE + #define WHITENOISE 1 +#endif +#ifndef GAMMA_CORRECT + #define GAMMA_CORRECT 1 +#endif +#ifndef TONE_MAP + #define TONE_MAP 1 +#endif +#ifndef LAMBERT + #define LAMBERT 0 +#endif +#ifndef PBR + #define PBR 1 +#endif + +const float PI = 3.14159265359; +const float EPSILON = 0.00001; +const float SQRT2 = 1.41421356237; + +const float LIGHT_POWER_CUTOFF = 0.0005; \ No newline at end of file diff --git a/bin/data/shaders/common/pbr.h b/bin/data/shaders/common/pbr.h new file mode 100644 index 00000000..6dccd9e3 --- /dev/null +++ b/bin/data/shaders/common/pbr.h @@ -0,0 +1,54 @@ +// PBR +float shadowFactor( const Light light, float def ); +float ndfGGX(float cosLh, float roughness) { + const float alpha = roughness * roughness; + const float alphaSq = alpha * alpha; + const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; + return alphaSq / (PI * denom * denom); +} +float gaSchlickG1(float cosTheta, float k) { return cosTheta / (cosTheta * (1.0 - k) + k); } +float gaSchlickGGX(float cosLi, float cosLo, float roughness) { + const float r = roughness + 1.0; + const float k = (r * r) / 8.0; + return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); +} +vec3 fresnelSchlick(vec3 F0, float cosTheta) { return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); } +void pbr() { + const float Rs = 4.0; // specular lighting looks gross without this + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize( -surface.position.eye ); + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); + + for ( uint i = 0; i < ubo.lights; ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + const vec3 Lp = light.position; + const vec3 Liu = vec3(ubo.matrices.view[surface.pass] * vec4(light.position, 1)) - surface.position.eye; + const vec3 Li = normalize(Liu); + const float Ls = shadowFactor( light, 0.0 ); + const float La = 1.0 / (PI * pow(length(Liu), 2.0)); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + #if LAMBERT + const vec3 diffuse = surface.material.albedo.rgb; + const vec3 specular = vec3(0); + #elif PBR + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); + + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, surface.material.roughness * Rs ); + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); + const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; + const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + #endif + // lightmapped, compute only specular + if ( light.type >= 0 && 0 <= surface.material.indexLightmap ) surface.fragment.rgb += (specular) * Lr * cosLi; + // point light, compute only diffuse + // else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi; + else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; + surface.fragment.a += light.power * La * Ls; + } +} \ No newline at end of file diff --git a/bin/data/shaders/common/shadows.h b/bin/data/shaders/common/shadows.h new file mode 100644 index 00000000..06b2f45d --- /dev/null +++ b/bin/data/shaders/common/shadows.h @@ -0,0 +1,64 @@ +const vec2 poissonDisk[16] = vec2[]( + vec2( -0.94201624, -0.39906216 ), + vec2( 0.94558609, -0.76890725 ), + vec2( -0.094184101, -0.92938870 ), + vec2( 0.34495938, 0.29387760 ), + vec2( -0.91588581, 0.45771432 ), + vec2( -0.81544232, -0.87912464 ), + vec2( -0.38277543, 0.27676845 ), + vec2( 0.97484398, 0.75648379 ), + vec2( 0.44323325, -0.97511554 ), + vec2( 0.53742981, -0.47373420 ), + vec2( -0.26496911, -0.41893023 ), + vec2( 0.79197514, 0.19090188 ), + vec2( -0.24188840, 0.99706507 ), + vec2( -0.81409955, 0.91437590 ), + vec2( 0.19984126, 0.78641367 ), + vec2( 0.14383161, -0.14100790 ) +); + +#ifndef SHADOW_SAMPLES + #define SHADOW_SAMPLES ubo.shadowSamples +#endif + +float shadowFactor( const Light light, float def ) { + if ( !validTextureIndex(light.mapIndex) ) { + #if VXGI + return voxelShadowFactor( light, def ); + #else + return 1.0; + #endif + } + + vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); + positionClip.xyz /= positionClip.w; + + if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; + if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; + if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; + + float factor = 1.0; + + // spot light + if ( abs(light.type) == 2 || abs(light.type) == 3 ) { + const float dist = length( positionClip.xy ); + if ( dist > 0.5 ) return def; //0.0; + + // spot light with attenuation + if ( abs(light.type) == 3 ) { + factor = 1.0 - (pow(dist * 2,2.0)); + } + } + + const vec2 uv = positionClip.xy * 0.5 + 0.5; + const float bias = light.depthBias; + const float eyeDepth = positionClip.z; + const int samples = int(SHADOW_SAMPLES); + if ( samples < 1 ) return eyeDepth < texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv).r - bias ? 0.0 : factor; + for ( int i = 0; i < samples; ++i ) { + const int index = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; + const float lightDepth = texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv + poissonDisk[index] / 700.0 ).r; + if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; + } + return factor; +} \ No newline at end of file diff --git a/bin/data/shaders/common/structs.h b/bin/data/shaders/common/structs.h new file mode 100644 index 00000000..f579bd9f --- /dev/null +++ b/bin/data/shaders/common/structs.h @@ -0,0 +1,138 @@ +struct Matrices { + mat4 view[2]; + mat4 projection[2]; + mat4 iView[2]; + mat4 iProjection[2]; + mat4 iProjectionView[2]; + vec4 eyePos[2]; + mat4 vxgi; +}; + +struct Cursor { + vec2 position; + vec2 radius; + vec4 color; +}; + +struct Ray { + vec3 origin; + vec3 direction; + + vec3 position; + float distance; +}; + +struct Space { + vec3 eye; + vec3 world; +}; + +struct Fog { + vec3 color; + float stepScale; + + vec3 offset; + float densityScale; + + float densityThreshold; + float densityMultiplier; + float absorbtion; + float padding1; + + vec2 range; + float padding2; + float padding3; +}; + +struct Mode { + uint type; + uint scalar; + vec2 padding; + vec4 parameters; +}; + +struct Light { + vec3 position; + float radius; + + vec3 color; + float power; + + int type; + int mapIndex; + float depthBias; + float padding; + + mat4 view; + mat4 projection; +}; + +struct Material { + vec4 colorBase; + vec4 colorEmissive; + + float factorMetallic; + float factorRoughness; + float factorOcclusion; + float factorAlphaCutoff; + + int indexAlbedo; + int indexNormal; + int indexEmissive; + int indexOcclusion; + + int indexMetallicRoughness; + int indexAtlas; + int indexLightmap; + int modeAlpha; +}; + +struct Texture { + int index; + int samp; + int remap; + float blend; + + vec4 lerp; +}; + +struct DrawCall { + int materialIndex; + uint materials; + int textureIndex; + uint textures; +}; + +struct SurfaceMaterial { + uint id; + + vec4 albedo; + vec4 indirect; + + float metallic; + float roughness; + float occlusion; + int indexLightmap; + +}; + +struct Surface { + uint pass; + vec2 uv; + Space position; + Space normal; + + Ray ray; + + SurfaceMaterial material; + + vec4 fragment; +} surface; + +struct Voxel { + uvec2 id; + vec3 position; + vec3 normal; + vec2 uv; + vec4 color; +}; \ No newline at end of file diff --git a/bin/data/shaders/common/vxgi.h b/bin/data/shaders/common/vxgi.h new file mode 100644 index 00000000..b6d7eaf5 --- /dev/null +++ b/bin/data/shaders/common/vxgi.h @@ -0,0 +1,194 @@ +// GI +struct VoxelInfo { + vec3 min; + vec3 max; + + float mipmapLevels; + float radianceSize; + float radianceSizeRecip; +} voxelInfo; +float cascadePower( uint x ) { + return pow(1 + x, ubo.cascadePower); +// return max( 1, x * ubo.cascadePower ); +} +uint cascadeIndex( vec3 v ) { + float x = max3( abs( v ) ); + for ( uint cascade = 0; cascade < CASCADES; ++cascade ) + if ( x / cascadePower(cascade) < 1 - voxelInfo.radianceSizeRecip ) return cascade; + return CASCADES - 1; +} + +vec4 voxelTrace( inout Ray ray, float aperture, float maxDistance ) { + ray.origin += ray.direction * voxelInfo.radianceSizeRecip * 2 * SQRT2; +#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 ) ); + uint cascade = cascadeIndex(ray.origin); +#else + uint cascade = cascadeIndex( vec3( ubo.matrices.vxgi * vec4( ray.origin, 1.0 ) ) ); +#endif + const float granularityRecip = 2.0; // 0.25f * (CASCADES - cascade); + const float granularity = 1.0f / granularityRecip; + const float occlusionFalloff = 128.0f; + const vec3 voxelBounds = voxelInfo.max - voxelInfo.min; + const vec3 voxelBoundsRecip = 1.0f / voxelBounds; + const float coneCoefficient = 2.0 * tan(aperture * 0.5); + const uint maxSteps = uint(voxelInfo.radianceSize * cascadePower(CASCADES-1) * granularityRecip); + // box + const vec2 rayBoxInfoA = rayBoxDst( voxelInfo.min * cascadePower(cascade), voxelInfo.max * cascadePower(cascade), ray ); + const vec2 rayBoxInfoB = rayBoxDst( voxelInfo.min * cascadePower(CASCADES-1), voxelInfo.max * cascadePower(CASCADES-1), ray ); + + const float tStart = rayBoxInfoA.x; + const float tEnd = maxDistance > 0 ? min(maxDistance, rayBoxInfoB.y) : rayBoxInfoB.y; + const float tDelta = voxelInfo.radianceSizeRecip * granularityRecip; + // marcher + ray.distance = tStart; + ray.position = vec3(0); + + 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.0; + uint stepCounter = 0; + while ( color.a < 1.0 && occlusion < 1.0 && ray.distance < tEnd && stepCounter++ < maxSteps ) { + ray.distance += tDelta * cascadePower(cascade) * max(1, coneDiameter); + ray.position = ray.origin + ray.direction * ray.distance; + + #if VXGI_NDC + uvw = ray.position; + #else + uvw = vec3( ubo.matrices.vxgi * vec4( ray.position, 1.0 ) ); + #endif + cascade = cascadeIndex( uvw ); + uvw = (uvw / cascadePower(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 = aperture > 0 ? log2( coneDiameter ) : 0; + if ( level >= voxelInfo.mipmapLevels ) break; + radiance = textureLod(voxelRadiance[nonuniformEXT(cascade)], uvw.xzy, level); + color += (1.0 - color.a) * radiance; + occlusion += ((1.0f - occlusion) * radiance.a) / (1.0f + occlusionFalloff * coneDiameter); + } + return maxDistance > 0 ? color : vec4(color.rgb, occlusion); +// return vec4(color.rgb, occlusion); +} +vec4 voxelConeTrace( inout Ray ray, float aperture ) { + return voxelTrace( ray, aperture, 0 ); +} +vec4 voxelTrace( inout Ray ray, float maxDistance ) { + return voxelTrace( ray, 0, maxDistance ); +} +uint voxelShadowsCount = 0; +float voxelShadowFactor( const Light light, float def ) { + if ( voxelShadowsCount++ > ubo.shadowSamples ) return 1.0; + + const float SHADOW_APERTURE = 0.2; + const float DEPTH_BIAS = 0.0; + + Ray ray; + ray.direction = normalize( light.position - surface.position.world ); + ray.origin = surface.position.world + ray.direction * 0.5; + float z = distance( surface.position.world, light.position ) - DEPTH_BIAS; + return 1.0 - voxelTrace( ray, SHADOW_APERTURE, z ).a; +} +void indirectLighting() { + voxelInfo.radianceSize = textureSize( voxelRadiance[0], 0 ).x; + voxelInfo.radianceSizeRecip = 1.0 / voxelInfo.radianceSize; + voxelInfo.mipmapLevels = log2(voxelInfo.radianceSize) + 1; +#if VXGI_NDC + voxelInfo.min = vec3( -1 ); + voxelInfo.max = vec3( 1 ); +#else + const mat4 inverseOrtho = inverse( ubo.matrices.vxgi ); + voxelInfo.min = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) ); + voxelInfo.max = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) ); +#endif + + const vec3 P = surface.position.world; + const vec3 N = surface.normal.world; + +#if 1 + const vec3 right = normalize(orthogonal(N)); + const vec3 up = normalize(cross(right, N)); + + const uint CONES_COUNT = 6; + const vec3 CONES[] = { + N, + normalize(N + 0.0f * right + 0.866025f * up), + normalize(N + 0.823639f * right + 0.267617f * up), + normalize(N + 0.509037f * right + -0.7006629f * up), + normalize(N + -0.50937f * right + -0.7006629f * up), + normalize(N + -0.823639f * right + 0.267617f * up), + }; +#else + const vec3 ortho = normalize(orthogonal(N)); + const vec3 ortho2 = normalize(cross(ortho, N)); + + const vec3 corner = 0.5f * (ortho + ortho2); + const vec3 corner2 = 0.5f * (ortho - ortho2); + + const uint CONES_COUNT = 9; + const vec3 CONES[] = { + N, + normalize(mix(N, ortho, 0.5)), + normalize(mix(N, -ortho, 0.5)), + normalize(mix(N, ortho2, 0.5)), + normalize(mix(N, -ortho2, 0.5)), + normalize(mix(N, corner, 0.5)), + normalize(mix(N, -corner, 0.5)), + normalize(mix(N, corner2, 0.5)), + normalize(mix(N, -corner2, 0.5)), + }; +#endif + + const float DIFFUSE_CONE_APERTURE = 2.0 * 0.57735f; + const float DIFFUSE_INDIRECT_FACTOR = 1.0f / float(CONES_COUNT); + + const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * surface.material.roughness), 0.0174533f, PI); // tan( R * PI * 0.5f * 0.1f ); + const float SPECULAR_INDIRECT_FACTOR = (1.0 - surface.material.metallic) * 0.5; // 1.0f; + + vec4 indirectDiffuse = vec4(0); + vec4 indirectSpecular = vec4(0); + +// outFragColor.rgb = voxelConeTrace( surface.ray, 0 ).rgb; return; + if ( DIFFUSE_INDIRECT_FACTOR > 0.0f ) { + float weight = PI * 0.25f; + for ( uint i = 0; i < CONES_COUNT; ++i ) { + Ray ray; + ray.direction = CONES[i].xyz; + ray.origin = P; // + ray.direction; + indirectDiffuse += voxelConeTrace( ray, DIFFUSE_CONE_APERTURE ) * weight; + weight = PI * 0.15f; + } + surface.material.occlusion = 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0); + // outFragColor.rgb = indirectDiffuse.rgb; return; + // outFragColor.rgb = vec3(surface.material.occlusion); return; + } + if ( SPECULAR_INDIRECT_FACTOR > 0.0f ) { + const vec3 R = reflect( normalize(P - surface.ray.origin), N ); + Ray ray; + ray.direction = R; + ray.origin = P; // + ray.direction; + indirectSpecular = voxelConeTrace( ray, SPECULAR_CONE_APERTURE ); + // outFragColor.rgb = indirectSpecular.rgb; return; + if ( length(indirectSpecular) < 0.0125 ) { + // indirectSpecular += (1.0 - indirectSpecular.a) * texture( samplerSkybox, R ); + } + } + + surface.material.indirect = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR; +// outFragColor.rgb = surface.material.indirect.rgb; return; +#if DEFERRED_SAMPLING + // deferred sampling doesn't have a blended albedo buffer + // in place we'll just cone trace behind the window + if ( surface.material.albedo.a < 1.0 ) { + Ray ray; + ray.direction = surface.ray.direction; + ray.origin = surface.position.world; // + ray.direction; + vec4 radiance = voxelConeTrace( ray, surface.material.albedo.a ); + surface.fragment.rgb += (1.0 - surface.material.albedo.a) * radiance.rgb; + } +#endif +} \ No newline at end of file diff --git a/bin/data/shaders/display/vert.glsl b/bin/data/shaders/display/base.vert.glsl similarity index 84% rename from bin/data/shaders/display/vert.glsl rename to bin/data/shaders/display/base.vert.glsl index 9d3a6de8..72856791 100644 --- a/bin/data/shaders/display/vert.glsl +++ b/bin/data/shaders/display/base.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (location = 0) in vec2 inPos; layout (location = 1) in vec2 inUv; diff --git a/bin/data/shaders/display/blit.frag.glsl b/bin/data/shaders/display/blit.frag.glsl index 64e61a6a..46c10f8e 100644 --- a/bin/data/shaders/display/blit.frag.glsl +++ b/bin/data/shaders/display/blit.frag.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(fragment) #extension GL_EXT_samplerless_texture_functions : require layout (binding = 1) uniform sampler samp; diff --git a/bin/data/shaders/display/blit.vert.glsl b/bin/data/shaders/display/blit.vert.glsl index e9638741..56d2225d 100644 --- a/bin/data/shaders/display/blit.vert.glsl +++ b/bin/data/shaders/display/blit.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (location = 0) in vec2 inPos; layout (location = 1) in vec2 inUv; diff --git a/bin/data/shaders/display/mip.gaussian.comp.glsl b/bin/data/shaders/display/mip.gaussian.comp.glsl new file mode 100644 index 00000000..dae6f972 --- /dev/null +++ b/bin/data/shaders/display/mip.gaussian.comp.glsl @@ -0,0 +1,67 @@ +#version 450 +#pragma shader_stage(compute) +#extension GL_EXT_samplerless_texture_functions : require + +layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; + +layout (constant_id = 0) const uint CASCADES = 16; +layout (constant_id = 1) const uint MIPS = 16; + +layout( push_constant ) uniform PushBlock { + uint cascade; + uint mip; +} PushConstant; + +layout (binding = 1, rg16f) uniform volatile coherent image3D voxelRadiance[CASCADES * MIPS]; + +const float gaussianWeights[] = { + //Top slice + 1 / 64.0f, + 1 / 32.0f, + 1 / 64.0f, + 1 / 32.0f, + 1 / 16.0f, + 1 / 32.0f, + 1 / 64.0f, + 1 / 32.0f, + 1 / 64.0f, + + //Center slice + 1 / 32.0f, + 1 / 16.0f, + 1 / 32.0f, + 1 / 16.0f, + 1 / 4.0f, + 1 / 16.0f, + 1 / 32.0f, + 1 / 16.0f, + 1 / 32.0f, + + //Bottom slice + 1 / 64.0f, + 1 / 32.0f, + 1 / 64.0f, + 1 / 32.0f, + 1 / 16.0f, + 1 / 32.0f, + 1 / 64.0f, + 1 / 32.0f, + 1 / 64.0f, +}; + +void main() { + const ivec3 inUVW = ivec3(gl_GlobalInvocationID.xyz) * 2; + const ivec3 outUVW = ivec3(gl_GlobalInvocationID.xyz); + const uint CASCADE_IN = PushConstant.cascade * CASCADES + PushConstant.mip; + const uint CASCADE_OUT = PushConstant.cascade * CASCADES + (PushConstant.mip + 1); + + vec4 color = vec4(0); + for ( int z = -1; z <= 1; ++z ) { + for ( int y = -1; y <= 1; ++y ) { + for ( int x = -1; x <= 1; ++x ) { + color += imageLoad( voxelRadiance[CASCADE_IN], inUVW + ivec3(x,y,z) ) * gaussianWeights[x + 1 + (y + 1) * 3 + (z + 1) * 9]; + } + } + } + imageStore(voxelRadiance[CASCADE_OUT], ivec3(outUVW), vec4(color)); +} \ No newline at end of file diff --git a/bin/data/shaders/display/rendertarget.frag.glsl b/bin/data/shaders/display/rendertarget.frag.glsl index 9a63e7b4..d434b200 100644 --- a/bin/data/shaders/display/rendertarget.frag.glsl +++ b/bin/data/shaders/display/rendertarget.frag.glsl @@ -1,9 +1,13 @@ #version 450 +#pragma shader_stage(fragment) #extension GL_EXT_samplerless_texture_functions : require -#define MULTISAMPLING 1 +#define TEXTURES 1 #define DEFERRED_SAMPLING 0 -#define CAN_DISCARD 1 + +#include "../common/macros.h" +#include "../common/structs.h" +#include "../common/functions.h" #if !MULTISAMPLING layout (binding = 1) uniform usampler2D textureId; @@ -23,22 +27,6 @@ #endif #endif -struct Cursor { - vec2 position; - vec2 radius; - vec4 color; -}; - -vec4 resolve( sampler2DMS t, ivec2 uv ) { - vec4 resolved = vec4(0); - int samples = textureSamples(t); - for ( int i = 0; i < samples; ++i ) { - resolved += texelFetch(t, uv, i); - } - resolved /= float(samples); - return resolved; -} - layout (location = 0) in vec2 inUv; layout (location = 1) in float inAlpha; layout (location = 2) in Cursor inCursor; @@ -46,27 +34,13 @@ layout (location = 2) in Cursor inCursor; layout (location = 0) out vec4 outAlbedo; void main() { -#if !MULTISAMPLING - ivec2 screenSize = textureSize(textureId, 0); -#else - ivec2 screenSize = textureSize(textureId); -#endif - ivec2 uv = ivec2(inUv * screenSize); - if ( inCursor.radius.x <= 0 || inCursor.radius.y <= 0 ) { - #if !MULTISAMPLING - outAlbedo = texture( textureAlbedo, uv ).rgba; - #else - outAlbedo = resolve( textureAlbedo, uv ); - #endif - return; - } - float dist = pow(inUv.x - inCursor.position.x, 2) / pow(inCursor.radius.x, 2) + pow(inUv.y - inCursor.position.y, 2) / pow(inCursor.radius.y, 2); - #if !MULTISAMPLING outAlbedo = texture( textureAlbedo, inUv ); #else - outAlbedo = resolve( textureAlbedo, uv ); + outAlbedo = resolve( textureAlbedo, ivec2(inUv * textureSize(textureId)) ); #endif + if ( inCursor.radius.x <= 0 || inCursor.radius.y <= 0 ) return; + float dist = pow(inUv.x - inCursor.position.x, 2) / pow(inCursor.radius.x, 2) + pow(inUv.y - inCursor.position.y, 2) / pow(inCursor.radius.y, 2); if ( dist <= 1 ) { float attenuation = dist; diff --git a/bin/data/shaders/display/rendertarget.no-msaa.frag.glsl b/bin/data/shaders/display/rendertarget.no-msaa.frag.glsl new file mode 100644 index 00000000..eb017ad4 --- /dev/null +++ b/bin/data/shaders/display/rendertarget.no-msaa.frag.glsl @@ -0,0 +1,51 @@ +#version 450 +#pragma shader_stage(fragment) +#extension GL_EXT_samplerless_texture_functions : require + +#define TEXTURES 1 +#define DEFERRED_SAMPLING 0 +#define MULTISAMPLING 0 + +#include "../common/macros.h" +#include "../common/structs.h" +#include "../common/functions.h" + +#if !MULTISAMPLING + layout (binding = 1) uniform usampler2D textureId; + layout (binding = 2) uniform sampler2D textureNormals; + #if DEFERRED_SAMPLING + layout (binding = 3) uniform sampler2D textureUvs; + #else + layout (binding = 3) uniform sampler2D textureAlbedo; + #endif +#else + layout (binding = 1) uniform usampler2DMS textureId; + layout (binding = 2) uniform sampler2DMS textureNormals; + #if DEFERRED_SAMPLING + layout (binding = 3) uniform sampler2DMS textureUvs; + #else + layout (binding = 3) uniform sampler2DMS textureAlbedo; + #endif +#endif + +layout (location = 0) in vec2 inUv; +layout (location = 1) in float inAlpha; +layout (location = 2) in Cursor inCursor; + +layout (location = 0) out vec4 outAlbedo; + +void main() { +#if !MULTISAMPLING + outAlbedo = texture( textureAlbedo, inUv ); +#else + outAlbedo = resolve( textureAlbedo, ivec2(inUv * textureSize(textureId)) ); +#endif + if ( inCursor.radius.x <= 0 || inCursor.radius.y <= 0 ) return; + float dist = pow(inUv.x - inCursor.position.x, 2) / pow(inCursor.radius.x, 2) + pow(inUv.y - inCursor.position.y, 2) / pow(inCursor.radius.y, 2); + + if ( dist <= 1 ) { + float attenuation = dist; + outAlbedo.rgb = mix( inCursor.color.rgb * inCursor.color.a, outAlbedo.rgb, attenuation ); + } + if ( inAlpha < 1.0 ) outAlbedo.a = inAlpha; +} \ No newline at end of file diff --git a/bin/data/shaders/display/rendertarget.vert.glsl b/bin/data/shaders/display/rendertarget.vert.glsl index c90a0fb3..a269a50f 100644 --- a/bin/data/shaders/display/rendertarget.vert.glsl +++ b/bin/data/shaders/display/rendertarget.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (location = 0) in vec2 inPos; layout (location = 1) in vec2 inUv; diff --git a/bin/data/shaders/display/subpass.frag.glsl b/bin/data/shaders/display/subpass.frag.glsl index 05d979be..2c7941d3 100644 --- a/bin/data/shaders/display/subpass.frag.glsl +++ b/bin/data/shaders/display/subpass.frag.glsl @@ -1,602 +1,14 @@ #version 450 -#extension GL_EXT_samplerless_texture_functions : require +#pragma shader_stage(fragment) -#define MULTISAMPLING 1 -#define DEFERRED_SAMPLING 1 - -#define FOG 1 -#define FOG_RAY_MARCH 1 - -#define WHITENOISE 1 -#define GAMMA_CORRECT 1 -#define TONE_MAP 1 - -#define LAMBERT 0 -#define PBR 1 - -const float PI = 3.14159265359; -const float EPSILON = 0.00001; -const float SQRT2 = 1.41421356237; - -const float LIGHT_POWER_CUTOFF = 0.005; - -const vec2 poissonDisk[16] = vec2[]( - vec2( -0.94201624, -0.39906216 ), - vec2( 0.94558609, -0.76890725 ), - vec2( -0.094184101, -0.92938870 ), - vec2( 0.34495938, 0.29387760 ), - vec2( -0.91588581, 0.45771432 ), - vec2( -0.81544232, -0.87912464 ), - vec2( -0.38277543, 0.27676845 ), - vec2( 0.97484398, 0.75648379 ), - vec2( 0.44323325, -0.97511554 ), - vec2( 0.53742981, -0.47373420 ), - vec2( -0.26496911, -0.41893023 ), - vec2( 0.79197514, 0.19090188 ), - vec2( -0.24188840, 0.99706507 ), - vec2( -0.81409955, 0.91437590 ), - vec2( 0.19984126, 0.78641367 ), - vec2( 0.14383161, -0.14100790 ) -); - -layout (constant_id = 0) const uint TEXTURES = 512; - -struct Matrices { - mat4 view[2]; - mat4 projection[2]; - mat4 iView[2]; - mat4 iProjection[2]; - mat4 iProjectionView[2]; - vec4 eyePos[2]; - mat4 vxgi; -}; - -struct Ray { - vec3 origin; - vec3 direction; - - vec3 position; - float distance; -}; - -struct Space { - vec3 eye; - vec3 world; -}; - -struct Fog { - vec3 color; - float stepScale; - - vec3 offset; - float densityScale; - - float densityThreshold; - float densityMultiplier; - float absorbtion; - float padding1; - - vec2 range; - float padding2; - float padding3; -}; - -struct Mode { - uint type; - uint scalar; - vec2 padding; - vec4 parameters; -}; - -struct Light { - vec3 position; - float radius; - - vec3 color; - float power; - - int type; - int mapIndex; - float depthBias; - float padding; - - mat4 view; - mat4 projection; -}; - -struct Material { - vec4 colorBase; - vec4 colorEmissive; - - float factorMetallic; - float factorRoughness; - float factorOcclusion; - float factorAlphaCutoff; - - int indexAlbedo; - int indexNormal; - int indexEmissive; - int indexOcclusion; - - int indexMetallicRoughness; - int indexAtlas; - int indexLightmap; - int modeAlpha; -}; - -struct Texture { - int index; - int samp; - int remap; - float blend; - - vec4 lerp; -}; - -struct DrawCall { - int materialIndex; - uint materials; - int textureIndex; - uint textures; -}; - -struct SurfaceMaterial { - uint id; - - vec4 albedo; - vec4 indirect; - - float metallic; - float roughness; - float occlusion; -}; - -struct Surface { - vec2 uv; - Space position; - Space normal; - - Ray ray; - - SurfaceMaterial material; - - vec4 fragment; -} surface; - -struct Voxel { - uvec2 id; - vec3 position; - 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; - #if DEFERRED_SAMPLING - layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerUv; - #else - layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo; - #endif - layout (input_attachment_index = 3, binding = 3) uniform subpassInput samplerDepth; -#else - layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId; - layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal; - #if DEFERRED_SAMPLING - layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerUv; - #else - layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo; - #endif - layout (input_attachment_index = 3, binding = 3) uniform subpassInputMS samplerDepth; -#endif - -layout (binding = 4) uniform UBO { - Matrices matrices; - - Mode mode; - Fog fog; - - uint lights; - uint materials; - uint textures; - uint drawCalls; - - vec3 ambient; - float gamma; - - float exposure; - uint msaa; - uint shadowSamples; - uint padding1; -} ubo; - -layout (std140, binding = 5) readonly buffer Lights { - Light lights[]; -}; -layout (std140, binding = 6) readonly buffer Materials { - Material materials[]; -}; -layout (std140, binding = 7) readonly buffer Textures { - Texture textures[]; -}; -layout (std140, binding = 8) readonly buffer DrawCalls { - DrawCall drawCalls[]; -}; - -layout (binding = 9) uniform sampler3D samplerNoise; -layout (binding = 10) uniform samplerCube samplerSkybox; -layout (binding = 11) uniform sampler2D samplerTextures[TEXTURES]; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat uint inPushConstantPass; - -layout (location = 0) out vec4 outFragColor; - -// GGX/Towbridge-Reitz normal distribution function. -// Uses Disney's reparametrization of alpha = roughness^2. -float ndfGGX(float cosLh, float roughness) { - const float alpha = roughness * roughness; - const float alphaSq = alpha * alpha; - const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; - return alphaSq / (PI * denom * denom); -} - -// Single term for separable Schlick-GGX below. -float gaSchlickG1(float cosTheta, float k) { - return cosTheta / (cosTheta * (1.0 - k) + k); -} - -// Schlick-GGX approximation of geometric attenuation function using Smith's method. -float gaSchlickGGX(float cosLi, float cosLo, float roughness) { - const float r = roughness + 1.0; - const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. - return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); -} -vec3 fresnelSchlick(vec3 F0, float cosTheta) { - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); -} - -float random(vec3 seed, int i){ - return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453); -} - -// Returns a vector that is orthogonal to u. -vec3 orthogonal(vec3 u){ - u = normalize(u); - const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. - return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); -} -float rand2(vec2 co){ - return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453); -} -float rand3(vec3 co){ - return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); -} -void whitenoise(inout vec3 color) { - const float flicker = ubo.mode.parameters.x; - const float pieces = ubo.mode.parameters.y; - const float blend = ubo.mode.parameters.z; - const float time = ubo.mode.parameters.w; - if ( blend < 0.0001 ) return; - const float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); - const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); - color = mix( color, vec3(whiteNoise), blend ); -} -vec3 gamma( vec3 i ) { - return pow(i.rgb, vec3(1.0 / 2.2)); -} - -vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) { - const vec3 t0 = (boundsMin - ray.origin) / ray.direction; - const vec3 t1 = (boundsMax - ray.origin) / ray.direction; - const vec3 tmin = min(t0, t1); - const vec3 tmax = max(t0, t1); - const float tStart = max(0, max( max(tmin.x, tmin.y), tmin.z )); - const float tEnd = max(0, min( tmax.x, min(tmax.y, tmax.z) ) - tStart); - return vec2(tStart, tEnd); -} - -float sampleDensity( vec3 position ) { - const vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01; - return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier; -} - -void fog( in Ray ray, inout vec3 i, float scale ) { - if ( ubo.fog.stepScale <= 0 ) return; - if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return; - -#if FOG_RAY_MARCH - const float range = ubo.fog.range.y; - const vec3 boundsMin = vec3(-range,-range,-range) + ray.origin; - const vec3 boundsMax = vec3(range,range,range) + ray.origin; - const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); - - const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, ray ); - const float dstToBox = rayBoxInfo.x; - const float dstInsideBox = rayBoxInfo.y; - const float depth = surface.position.eye.z; - - float lightEnergy = 0; - // march - if ( 0 <= dstInsideBox && dstToBox <= depth ) { - float dstTravelled = 0; - float stepSize = dstInsideBox / numSteps; - float dstLimit = min( depth - dstToBox, dstInsideBox ); - float totalDensity = 0; - float transmittance = 1; - while ( dstTravelled < dstLimit ) { - vec3 rayPos = ray.origin + ray.direction * (dstToBox + dstTravelled); - float density = sampleDensity(rayPos); - if ( density > 0 ) { - transmittance *= exp(-density * stepSize * ubo.fog.absorbtion); - if ( transmittance < 0.01 ) break; - } - dstTravelled += stepSize; - } - 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; - const float distance = length(-surface.position.eye); - const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 ); - - i.rgb = mix(i.rgb, color, factor); -#endif -} - -vec3 decodeNormals( vec2 enc ) { - const vec2 ang = enc*2-1; - const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); - const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); - return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); -} -float wrap( float i ) { - return fract(i); -} -vec2 wrap( vec2 uv ) { - return vec2( wrap( uv.x ), wrap( uv.y ) ); -} -float mipLevel( in vec2 uv ) { - const vec2 dx_vtc = dFdx(uv); - const vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); -} -bool validTextureIndex( int textureIndex ) { - return 0 <= textureIndex; // && textureIndex < ubo.textures; -} -vec4 resolve( subpassInputMS t ) { - const int samples = int(ubo.msaa); - vec4 resolved = vec4(0); - for ( int i = 0; i < samples; ++i ) { - resolved += subpassLoad(t, i); - } - resolved /= vec4(samples); - return resolved; -} -uvec4 resolve( usubpassInputMS t ) { - const int samples = int(ubo.msaa); - uvec4 resolved = uvec4(0); - for ( int i = 0; i < samples; ++i ) { - resolved += subpassLoad(t, i); - } - resolved /= uvec4(samples); - return resolved; -} - -float shadowFactor( const Light light, float def ) { - if ( !validTextureIndex(light.mapIndex) ) return 1.0; - - vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); - positionClip.xyz /= positionClip.w; - - if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; - if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; - if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; - - float factor = 1.0; - - // spot light - if ( abs(light.type) == 2 || abs(light.type) == 3 ) { - const float dist = length( positionClip.xy ); - if ( dist > 0.5 ) return def; //0.0; - - // spot light with attenuation - if ( abs(light.type) == 3 ) { - factor = 1.0 - (pow(dist * 2,2.0)); - } - } - - const vec2 uv = positionClip.xy * 0.5 + 0.5; - const float bias = light.depthBias; - const float eyeDepth = positionClip.z; - const int samples = int(ubo.shadowSamples); - if ( samples < 1 ) return eyeDepth < texture(samplerTextures[light.mapIndex], uv).r - bias ? 0.0 : factor; - for ( int i = 0; i < samples; ++i ) { - const int index = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; - const float lightDepth = texture(samplerTextures[light.mapIndex], uv + poissonDisk[index] / 700.0 ).r; - if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; - } - return factor; -} - -vec4 postProcess() { -#if FOG - fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); -#endif -#if TONE_MAP - surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * ubo.exposure); -#endif -#if GAMMA_CORRECT - surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / ubo.gamma)); -#endif -#if WHITENOISE - if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) whitenoise(surface.fragment.rgb); -#endif - - return vec4(surface.fragment.rgb,1); -} +#include "./subpass.h" void main() { - { - #if !MULTISAMPLING - const float depth = subpassLoad(samplerDepth).r; - #else - const float depth = resolve( samplerDepth ).r; - #endif + populateSurface(); - vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0); - positionEye /= positionEye.w; - surface.position.eye = positionEye.xyz; - surface.position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye ); - } -#if 0 - { - const vec4 near4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - const vec4 far4 = ubo.matrices.iProjectionView[inPushConstantPass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - const vec3 near3 = near4.xyz / near4.w; - const vec3 far3 = far4.xyz / far4.w; + const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion; + surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); - surface.ray.origin = near3; - surface.ray.direction = normalize( far3 - near3 ); - } - // separate our ray direction due to floating point precision problems - { - const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) ); - const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - const vec3 near3 = near4.xyz / near4.w; - const vec3 far3 = far4.xyz / far4.w; - - surface.ray.direction = normalize( far3 - near3 ); - } -#else - { - const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) ); - const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - const vec3 near3 = near4.xyz / near4.w; - const vec3 far3 = far4.xyz / far4.w; - - surface.ray.direction = normalize( far3 - near3 ); - surface.ray.origin = ubo.matrices.eyePos[inPushConstantPass].xyz; - } -#endif -#if !MULTISAMPLING - surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); - const uvec2 ID = subpassLoad(samplerId).xy; -#else - surface.normal.world = decodeNormals( resolve(samplerNormal).xy ); - const uvec2 ID = resolve(samplerId).xy; -#endif - surface.normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(surface.normal.world, 0.0) ); - - if ( ID.x == 0 || ID.y == 0 ) { - surface.fragment.rgb = texture( samplerSkybox, surface.ray.direction ).rgb; - surface.fragment.a = 0.0; - outFragColor = postProcess(); - return; - } - const uint drawId = ID.x - 1; - const DrawCall drawCall = drawCalls[drawId]; - surface.material.id = ID.y + drawCall.materialIndex - 1; - const Material material = materials[surface.material.id]; - surface.material.albedo = material.colorBase; - surface.fragment = material.colorEmissive; -#if DEFERRED_SAMPLING -#if !MULTISAMPLING - surface.uv = subpassLoad(samplerUv).xy; -#else - surface.uv = resolve(samplerUv).xy; -#endif - const float mip = mipLevel(inUv.xy); - const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas ); - Texture textureAtlas; - if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas]; - if ( validTextureIndex( drawCall.textureIndex + material.indexAlbedo ) ) { - const Texture t = textures[drawCall.textureIndex + material.indexAlbedo]; - surface.material.albedo = textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); - } - // OPAQUE - if ( material.modeAlpha == 0 ) { - surface.material.albedo.a = 1; - // BLEND - } else if ( material.modeAlpha == 1 ) { - - // MASK - } else if ( material.modeAlpha == 2 ) { - - } - // Emissive textures - if ( validTextureIndex( drawCall.textureIndex + material.indexEmissive ) ) { - const Texture t = textures[drawCall.textureIndex + material.indexEmissive]; - surface.fragment += textureLod( samplerTextures[(useAtlas)?textureAtlas.index:t.index], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); - } -#else -#if !MULTISAMPLING - surface.material.albedo = subpassLoad(samplerAlbedo); -#else - surface.material.albedo = resolve(samplerAlbedo); -#endif -#endif - surface.material.metallic = material.factorMetallic; - surface.material.roughness = material.factorRoughness; - surface.material.occlusion = material.factorOcclusion; - - if ( 0 <= material.indexLightmap ) { - surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion; - } else { - surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion; - } - - // corrections - surface.material.roughness *= 4.0; - - { - const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); - const vec3 Lo = normalize( -surface.position.eye ); - const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); - - for ( uint i = 0; i < ubo.lights; ++i ) { - const Light light = lights[i]; - if ( light.power <= LIGHT_POWER_CUTOFF ) continue; - const vec3 Lp = light.position; - const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - surface.position.eye; - const vec3 Li = normalize(Liu); - #if VXGI_SHADOWS - const float Ls = i < ubo.shadowSamples ? shadowFactor( light, 0.0 ) : 1.0; - #else - const float Ls = shadowFactor( light, 0.0 ); - #endif - const float La = 1.0 / (PI * pow(length(Liu), 2.0)); - if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; - - const float cosLi = max(0.0, dot(surface.normal.eye, Li)); - const vec3 Lr = light.color.rgb * light.power * La * Ls; - #if LAMBERT - const vec3 diffuse = surface.material.albedo.rgb; - const vec3 specular = vec3(0); - #elif PBR - const vec3 Lh = normalize(Li + Lo); - const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); - - const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); - const float D = ndfGGX( cosLh, surface.material.roughness ); - const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); - const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; - const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); - #endif - // lightmapped, compute only specular - if ( light.type >= 0 && 0 <= material.indexLightmap ) surface.fragment.rgb += (specular) * Lr * cosLi; - // point light, compute only diffuse - // else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi; - else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; - surface.fragment.a += light.power * La * Ls; - } - } - - outFragColor = postProcess(); + pbr(); + postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.h b/bin/data/shaders/display/subpass.h new file mode 100644 index 00000000..a1368c05 --- /dev/null +++ b/bin/data/shaders/display/subpass.h @@ -0,0 +1,219 @@ +#extension GL_EXT_samplerless_texture_functions : require +#extension GL_EXT_nonuniform_qualifier : enable + +#define MAX_TEXTURES TEXTURES +#include "../common/macros.h" + +layout (constant_id = 0) const uint TEXTURES = 512; +#if VXGI + layout (constant_id = 1) const uint CASCADES = 16; +#endif + +#if !MULTISAMPLING + layout (input_attachment_index = 0, binding = 0) uniform usubpassInput samplerId; + layout (input_attachment_index = 1, binding = 1) uniform subpassInput samplerNormal; + #if DEFERRED_SAMPLING + layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerUv; + #else + layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo; + #endif + layout (input_attachment_index = 3, binding = 3) uniform subpassInput samplerDepth; +#else + layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId; + layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal; + #if DEFERRED_SAMPLING + layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerUv; + #else + layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo; + #endif + layout (input_attachment_index = 3, binding = 3) uniform subpassInputMS samplerDepth; +#endif + +#include "../common/structs.h" + +layout (binding = 4) uniform UBO { + Matrices matrices; + + Mode mode; + Fog fog; + + uint lights; + uint materials; + uint textures; + uint drawCalls; + + vec3 ambient; + float gamma; + + float exposure; + uint msaa; + uint shadowSamples; + float cascadePower; +} ubo; + +layout (std140, binding = 5) readonly buffer Lights { + Light lights[]; +}; +layout (std140, binding = 6) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 7) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 8) readonly buffer DrawCalls { + DrawCall drawCalls[]; +}; + +#if VXGI + layout (binding = 9) uniform usampler3D voxelId[CASCADES]; + layout (binding = 10) uniform sampler3D voxelUv[CASCADES]; + layout (binding = 11) uniform sampler3D voxelNormal[CASCADES]; + layout (binding = 12) uniform sampler3D voxelRadiance[CASCADES]; + + layout (binding = 13) uniform sampler3D samplerNoise; + layout (binding = 14) uniform samplerCube samplerSkybox; + layout (binding = 15) uniform sampler2D samplerTextures[TEXTURES]; +#else + layout (binding = 9) uniform sampler3D samplerNoise; + layout (binding = 10) uniform samplerCube samplerSkybox; + layout (binding = 11) uniform sampler2D samplerTextures[TEXTURES]; +#endif + +layout (location = 0) in vec2 inUv; +layout (location = 1) in flat uint inPushConstantPass; + +layout (location = 0) out vec4 outFragColor; + +#include "../common/functions.h" +#include "../common/fog.h" +#include "../common/pbr.h" +#if VXGI + #include "../common/vxgi.h" +#endif +#include "../common/shadows.h" + +void postProcess() { +#if FOG + fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); +#endif +#if TONE_MAP + surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * ubo.exposure); +#endif +#if GAMMA_CORRECT + surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / ubo.gamma)); +#endif +#if WHITENOISE + if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) whitenoise(surface.fragment.rgb, ubo.mode.parameters); +#endif + + outFragColor = vec4(surface.fragment.rgb,1); +} + +void populateSurface() { + surface.pass = inPushConstantPass; + { + #if !MULTISAMPLING + const float depth = subpassLoad(samplerDepth).r; + #else + const float depth = resolve(samplerDepth, ubo.msaa).r; + #endif + + vec4 positionEye = ubo.matrices.iProjection[surface.pass] * vec4(inUv * 2.0 - 1.0, depth, 1.0); + positionEye /= positionEye.w; + surface.position.eye = positionEye.xyz; + surface.position.world = vec3( ubo.matrices.iView[surface.pass] * positionEye ); + } +#if 0 + { + const vec4 near4 = ubo.matrices.iProjectionView[surface.pass] * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); + const vec4 far4 = ubo.matrices.iProjectionView[surface.pass] * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); + const vec3 near3 = near4.xyz / near4.w; + const vec3 far3 = far4.xyz / far4.w; + + surface.ray.origin = near3; + surface.ray.direction = normalize( far3 - near3 ); + } + // separate our ray direction due to floating point precision problems + { + const mat4 iProjectionView = inverse( ubo.matrices.projection[surface.pass] * mat4(mat3(ubo.matrices.view[surface.pass])) ); + const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); + const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); + const vec3 near3 = near4.xyz / near4.w; + const vec3 far3 = far4.xyz / far4.w; + + surface.ray.direction = normalize( far3 - near3 ); + } +#else + { + const mat4 iProjectionView = inverse( ubo.matrices.projection[surface.pass] * mat4(mat3(ubo.matrices.view[surface.pass])) ); + const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); + const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); + const vec3 near3 = near4.xyz / near4.w; + const vec3 far3 = far4.xyz / far4.w; + + surface.ray.direction = normalize( far3 - near3 ); + surface.ray.origin = ubo.matrices.eyePos[surface.pass].xyz; + } +#endif +#if !MULTISAMPLING + surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); + const uvec2 ID = subpassLoad(samplerId).xy; +#else + surface.normal.world = decodeNormals( resolve(samplerNormal, ubo.msaa).xy ); + const uvec2 ID = subpassLoad(samplerId, 0).xy; //resolve(samplerId, ubo.msaa).xy; +#endif + surface.normal.eye = vec3( ubo.matrices.view[surface.pass] * vec4(surface.normal.world, 0.0) ); + + if ( ID.x == 0 || ID.y == 0 ) { + surface.fragment.rgb = texture( samplerSkybox, surface.ray.direction ).rgb; + surface.fragment.a = 0.0; + postProcess(); + return; + } + const uint drawId = ID.x - 1; + const DrawCall drawCall = drawCalls[drawId]; + surface.material.id = ID.y + drawCall.materialIndex - 1; + const Material material = materials[surface.material.id]; + surface.material.albedo = material.colorBase; + surface.fragment = material.colorEmissive; +#if DEFERRED_SAMPLING +#if !MULTISAMPLING + surface.uv = subpassLoad(samplerUv).xy; +#else + surface.uv = resolve(samplerUv, ubo.msaa).xy; +#endif + const float mip = mipLevel(inUv.xy); + const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas ); + Texture textureAtlas; + if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas]; + if ( validTextureIndex( drawCall.textureIndex + material.indexAlbedo ) ) { + const Texture t = textures[drawCall.textureIndex + material.indexAlbedo]; + surface.material.albedo = textureLod( samplerTextures[nonuniformEXT((useAtlas)?textureAtlas.index:t.index)], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); + } + // OPAQUE + if ( material.modeAlpha == 0 ) { + surface.material.albedo.a = 1; + // BLEND + } else if ( material.modeAlpha == 1 ) { + + // MASK + } else if ( material.modeAlpha == 2 ) { + + } + // Emissive textures + if ( validTextureIndex( drawCall.textureIndex + material.indexEmissive ) ) { + const Texture t = textures[drawCall.textureIndex + material.indexEmissive]; + surface.fragment += textureLod( samplerTextures[nonuniformEXT((useAtlas)?textureAtlas.index:t.index)], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); + } +#else +#if !MULTISAMPLING + surface.material.albedo = subpassLoad(samplerAlbedo); +#else + surface.material.albedo = resolve(samplerAlbedo, ubo.msaa); +#endif +#endif + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; + surface.material.indexLightmap = material.indexLightmap; +} \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.no-msaa.frag.glsl b/bin/data/shaders/display/subpass.no-msaa.frag.glsl new file mode 100644 index 00000000..b4eafa74 --- /dev/null +++ b/bin/data/shaders/display/subpass.no-msaa.frag.glsl @@ -0,0 +1,15 @@ +#version 450 +#pragma shader_stage(fragment) + +#define MULTISAMPLING 0 +#include "./subpass.h" + +void main() { + populateSurface(); + + const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion; + surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); + + pbr(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.old.frag.glsl b/bin/data/shaders/display/subpass.old.frag.glsl deleted file mode 100644 index 705a45d0..00000000 --- a/bin/data/shaders/display/subpass.old.frag.glsl +++ /dev/null @@ -1,559 +0,0 @@ -#version 450 -#extension GL_EXT_samplerless_texture_functions : require - -layout (constant_id = 0) const uint LIGHTS = 256; - -layout (input_attachment_index = 0, binding = 1) uniform subpassInput samplerAlbedoMetallic; -layout (input_attachment_index = 0, binding = 2) uniform subpassInput samplerNormalRoughness; -layout (input_attachment_index = 0, binding = 3) uniform subpassInput samplerDepth; - -layout (binding = 5) uniform sampler3D samplerNoise; -layout (binding = 6) uniform sampler2D samplerShadows[LIGHTS]; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat uint inPushConstantPass; - -layout (location = 0) out vec4 outFragColor; - -/* -const vec2 poissonDisk[4] = vec2[]( - vec2( -0.94201624, -0.39906216 ), - vec2( 0.94558609, -0.76890725 ), - vec2( -0.094184101, -0.92938870 ), - vec2( 0.34495938, 0.29387760 ) -); -*/ -vec2 poissonDisk[16] = vec2[]( - vec2( -0.94201624, -0.39906216 ), - vec2( 0.94558609, -0.76890725 ), - vec2( -0.094184101, -0.92938870 ), - vec2( 0.34495938, 0.29387760 ), - vec2( -0.91588581, 0.45771432 ), - vec2( -0.81544232, -0.87912464 ), - vec2( -0.38277543, 0.27676845 ), - vec2( 0.97484398, 0.75648379 ), - vec2( 0.44323325, -0.97511554 ), - vec2( 0.53742981, -0.47373420 ), - vec2( -0.26496911, -0.41893023 ), - vec2( 0.79197514, 0.19090188 ), - vec2( -0.24188840, 0.99706507 ), - vec2( -0.81409955, 0.91437590 ), - vec2( 0.19984126, 0.78641367 ), - vec2( 0.14383161, -0.14100790 ) -); - -struct Light { - vec3 position; - float radius; - - vec3 color; - float power; - - int type; - float depthBias; - float padding1; - float padding2; - - mat4 view; - mat4 projection; -}; - -struct Matrices { - mat4 view[2]; - mat4 projection[2]; -}; - -struct Space { - vec3 eye; - vec3 world; -} position, normal, view; - -struct Fog { - vec3 color; - float stepScale; - - vec3 offset; - float densityScale; - - float densityThreshold; - float densityMultiplier; - float absorbtion; - float padding1; - - vec2 range; - float padding2; - float padding3; -}; - -struct Mode { - uint type; - uint scalar; - vec2 padding; - vec4 parameters; -}; - -layout (binding = 0) uniform UBO { - Matrices matrices; - vec3 ambient; - float kexp; - Mode mode; - Fog fog; - Light lights[LIGHTS]; -} ubo; - -void phong( Light light, vec4 albedoSpecular, inout vec3 i ) { - vec3 Ls = vec3(1.0, 1.0, 1.0); // light specular - vec3 Ld = light.color; // light color - vec3 La = vec3(1.0, 1.0, 1.0); - - vec3 Ks = vec3(albedoSpecular.a); // material specular - vec3 Kd = albedoSpecular.rgb; // material diffuse - vec3 Ka = vec3(1.0, 1.0, 1.0); - - float Kexp = ubo.kexp; - - vec3 V = position.eye; - vec3 N = normal.eye; - vec3 L = light.position.xyz - V; - float dist = length(L); -// if ( light.radius > 0.001 && light.radius < dist ) return; - - vec3 D = normalize(L); - float d_dot = max(dot( D, N ), 0.0); - - vec3 R = reflect( -D, N ); - vec3 S = normalize(-V); - float s_factor = pow( max(dot( R, S ), 0.0), Kexp ); - if ( Kexp < 0.0001 ) s_factor = 0; - - float radiance = light.power / (dist * dist); - - vec3 Ia = La * Ka; - vec3 Id = Ld * Kd * d_dot * radiance; - vec3 Is = Ls * Ks * s_factor * radiance; - - i += Id + Is; -} - -const float PI = 3.14159265359; -float DistributionGGX(vec3 N, vec3 H, float roughness) { - float a = roughness*roughness; - float a2 = a*a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH*NdotH; - - float num = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; -} - -float GeometrySchlickGGX(float NdotV, float roughness) { - float r = (roughness + 1.0); - float k = (r*r) / 8.0; - - float num = NdotV; - float denom = NdotV * (1.0 - k) + k; - - return num / denom; -} -float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { - float NdotV = max(dot(N, V), 0.0); - float NdotL = max(dot(N, L), 0.0); - float ggx2 = GeometrySchlickGGX(NdotV, roughness); - float ggx1 = GeometrySchlickGGX(NdotL, roughness); - - return ggx1 * ggx2; -} -vec3 fresnelSchlick(float cosTheta, vec3 F0) { - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); -} - -float random(vec3 seed, int i){ - vec4 seed4 = vec4(seed,i); - float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673)); - return fract(sin(dot_product) * 43758.5453); -} - -float shadowFactor( Light light, uint shadowMap ) { - vec4 positionClip = light.projection * light.view * vec4(position.world, 1.0); - positionClip.xyz /= positionClip.w; - - if ( positionClip.x < -1 || positionClip.x >= 1 ) return 0.0; - if ( positionClip.y < -1 || positionClip.y >= 1 ) return 0.0; - if ( positionClip.z <= 0 || positionClip.z >= 1 ) return 0.0; - - float factor = 1.0; - - // spot light - if ( light.type == -2 || light.type == -3 ) { - float dist = length( positionClip.xy ); - if ( dist > 0.5 ) return 0.0; - - // spot light with attenuation - if ( light.type == -3 ) { - factor = 1.0 - (pow(dist * 2,2.0)); - } - } - - vec2 uv = positionClip.xy * 0.5 + 0.5; - float bias = light.depthBias; - if ( !true ) { - float cosTheta = clamp(dot(normal.eye, normalize(light.position.xyz - position.eye)), 0, 1); - bias = clamp(bias * tan(acos(cosTheta)), 0, 0.01); - } else if ( true ) { - bias = max(bias * 10 * (1.0 - dot(normal.eye, normalize(light.position.xyz - position.eye))), bias); - } - - float eyeDepth = positionClip.z; - int samples = poissonDisk.length(); - if ( samples <= 1 ) { - return eyeDepth < texture(samplerShadows[shadowMap], uv).r - bias ? 0.0 : factor; - } - for ( int i = 0; i < samples; ++i ) { - // int index = i; - // int index = int( float(samples) * random(gl_FragCoord.xyy, i) ) % samples; - int index = int( float(samples) * random(floor(position.world.xyz * 1000.0), i)) % samples; - float lightDepth = texture(samplerShadows[shadowMap], uv + poissonDisk[index] / 700.0 ).r; - if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; - } - return factor; -} -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} -const int indexMatrix16x16[256] = int[](0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255, - 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127, - 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223, - 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95, - 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247, - 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119, - 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215, - 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87, - 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253, - 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125, - 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221, - 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93, - 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245, - 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117, - 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213, - 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85); -float indexValue16x16( float scale ) { - int x = int(mod(gl_FragCoord.x * scale, 16)); - int y = int(mod(gl_FragCoord.y * scale, 16)); - return indexMatrix16x16[(x + y * 16)] / 256.0; -} -const int indexMatrix8x8[64] = int[](0, 32, 8, 40, 2, 34, 10, 42, - 48, 16, 56, 24, 50, 18, 58, 26, - 12, 44, 4, 36, 14, 46, 6, 38, - 60, 28, 52, 20, 62, 30, 54, 22, - 3, 35, 11, 43, 1, 33, 9, 41, - 51, 19, 59, 27, 49, 17, 57, 25, - 15, 47, 7, 39, 13, 45, 5, 37, - 63, 31, 55, 23, 61, 29, 53, 21); -float indexValue8x8( float scale ) { - int x = int(mod(gl_FragCoord.x * scale, 8)); - int y = int(mod(gl_FragCoord.y * scale, 8)); - return indexMatrix8x8[(x + y * 8)] / 64.0; -} -const int indexMatrix4x4[16] = int[](0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5); -float indexValue4x4( float scale ) { - int x = int(mod(gl_FragCoord.x * scale, 4)); - int y = int(mod(gl_FragCoord.y * scale, 4)); - return indexMatrix4x4[(x + y * 4)] / 16.0; -} -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; -/* - for (int i = 0; i < palette.length(); ++i) { - temp = rgbToHsl(palette[i].rgb); - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } -*/ - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = 1; // -0.5 - fract(ubo.mode.parameters.w / 8.0); - if ( ubo.mode.scalar == 16 ) { - d = indexValue16x16(1); - } else if ( ubo.mode.scalar == 8 ) { - d = indexValue8x8(1); - } else if ( ubo.mode.scalar == 4 ) { - d = indexValue4x4(1); - } - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} -void dither(inout vec3 color) { - vec3 hsl = rgbToHsl(color); - hsl.x = dither(hsl.x); - color = hslToRgb(hsl); -} -void dither1(inout vec3 color) { - vec3 hsl = rgbToHsl(color); - - float d = 0; - vec3 cs[2] = { hsl, hsl }; // closestColors(hsl.x); - float scale = 1; - if ( ubo.mode.scalar == 16 ) { - d = indexValue16x16(scale); - } else if ( ubo.mode.scalar == 8 ) { - d = indexValue8x8(scale); - } else if ( ubo.mode.scalar == 4 ) { - d = indexValue4x4(scale); - } - float hueDiff = hueDistance(hsl.x, cs[0].x) / hueDistance(cs[1].x, cs[0].x); - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? cs[0] : cs[1]; - resultColor.z = (lightnessDiff < d) ? l1 : l2; - color = hslToRgb(resultColor); -} -vec3 dither2() { - vec3 vDither = dot( vec2( 171.0, 231.0 ), inUv.xy + ubo.mode.parameters.w ).xxx; - vDither.rgb = fract( vDither.rgb / vec3( 103.0, 71.0, 97.0 ) ) - vec3( 0.5, 0.5, 0.5 ); - return ( vDither.rgb / 255.0 ) * 0.375; -} - -float rand2(vec2 co){ - return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453); -} -float rand3(vec3 co){ - return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); -} -void whitenoise(inout vec3 color) { - float flicker = ubo.mode.parameters.x; - float pieces = ubo.mode.parameters.y; - float blend = ubo.mode.parameters.z; - float time = ubo.mode.parameters.w; - if ( blend < 0.0001 ) return; - float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); -// float whiteNoise = rand3( floor(position.world / pieces) + floor(time * 2) ); - float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); - color = mix( color, vec3(whiteNoise), blend ); -} - -void pbr( Light light, vec3 albedo, float metallic, float roughness, vec3 lightPositionWorld, inout vec3 i ) { - vec3 F0 = vec3(0.04); - F0 = mix(F0, albedo, metallic); - - vec3 N = normalize(normal.eye); - vec3 L = light.position.xyz - position.eye; - float dist = length(L); -// if ( light.radius > 0.001 && light.radius < dist ) return; - - vec3 D = normalize(L); - vec3 V = normalize(-position.eye); - vec3 H = normalize(V + D); - - float NdotD = max(dot(N, D), 0.0); - float NdotV = max(dot(N, V), 0.0); - - vec3 radiance = light.color.rgb * light.power / (dist * dist); -/* - if ( light.radius > 0.0001 ) { - radiance *= clamp( light.radius / (pow(dist, 2.0) + 1.0), 0.0, 1.0 ); - } else if ( false ) { - radiance /= dist * dist; - } -*/ - - // cook-torrance brdf - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, D, roughness); - vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0); - - vec3 kS = F; - vec3 kD = vec3(1.0) - kS; - kD *= 1.0 - metallic; - - vec3 numerator = NDF * G * F; - float denominator = 4.0 * NdotV * NdotD; - vec3 specular = numerator / max(denominator, 0.001); - - // add to outgoing radiance Lo - i += (kD * albedo / PI + specular) * radiance * NdotD; -} - -vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, vec3 rayOrigin, vec3 rayDir ) { - vec3 t0 = (boundsMin - rayOrigin) / rayDir; - vec3 t1 = (boundsMax - rayOrigin) / rayDir; - vec3 tmin = min(t0, t1); - vec3 tmax = max(t0, t1); - float dstA = max( max(tmin.x, tmin.y), tmin.z ); - float dstB = min( tmax.x, min(tmax.y, tmax.z) ); - float dstToBox = max(0, dstA); - float dstInsideBox = max(0, dstB - dstToBox); - return vec2(dstToBox, dstInsideBox); -} - -float sampleDensity( vec3 position ) { - vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01; - return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier; -} - -void fog( inout vec3 i, float scale ) { - if ( ubo.fog.stepScale <= 0 ) return; - if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return; - - mat4 iProjView = inverse( ubo.matrices.projection[inPushConstantPass] * ubo.matrices.view[inPushConstantPass] ); - vec4 near4 = iProjView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - vec4 far4 = iProjView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - vec3 near3 = near4.xyz / near4.w; - vec3 far3 = far4.xyz / far4.w; - - vec3 rayOrigin = near3; - vec3 rayDir = normalize( far3 - near3 ); - - float range = ubo.fog.range.y; - vec3 boundsMin = vec3(-range,-range,-range) + rayOrigin; - vec3 boundsMax = vec3(range,range,range) + rayOrigin; - int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); - - vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, rayOrigin, rayDir ); - float dstToBox = rayBoxInfo.x; - float dstInsideBox = rayBoxInfo.y; - float depth = position.eye.z; - - float lightEnergy = 0; - // march - if ( 0 <= dstInsideBox && dstToBox <= depth ) { - float dstTravelled = 0; - float stepSize = dstInsideBox / numSteps; - float dstLimit = min( depth - dstToBox, dstInsideBox ); - float totalDensity = 0; - float transmittance = 1; - while ( dstTravelled < dstLimit ) { - vec3 rayPos = rayOrigin + rayDir * (dstToBox + dstTravelled); - float density = sampleDensity(rayPos); - if ( density > 0 ) { - transmittance *= exp(-density * stepSize * ubo.fog.absorbtion); - if ( transmittance < 0.01 ) break; - } - dstTravelled += stepSize; - } - i.rgb = mix(ubo.fog.color.rgb, i.rgb, transmittance); - } - - vec3 color = ubo.fog.color.rgb; - float inner = ubo.fog.range.x; - float outer = ubo.fog.range.y * scale; - float distance = length(-position.eye); - float factor = (distance - inner) / (outer - inner); - factor = clamp( factor, 0.0, 1.0 ); - - i.rgb = mix(i.rgb, color, factor); -} - -void main() { - vec4 albedoMetallic = subpassLoad(samplerAlbedoMetallic); - vec4 normalRoughness = subpassLoad(samplerNormalRoughness); -// vec4 positionAO = subpassLoad(samplerPositionAO); - - normal.eye = normalRoughness.rgb; - { - mat4 iProj = inverse( ubo.matrices.projection[inPushConstantPass] ); - mat4 iView = inverse( ubo.matrices.view[inPushConstantPass] ); - float depth = subpassLoad(samplerDepth).r; - - vec4 positionClip = vec4(inUv * 2.0 - 1.0, depth, 1.0); - vec4 positionEye = iProj * positionClip; - positionEye /= positionEye.w; - position.eye = positionEye.xyz; - - vec4 positionWorld = iView * positionEye; - position.world = positionWorld.xyz; - } - - bool usePbr = true; - bool gammaCorrect = false; - float litFactor = 1.0; - float ao = 1; // positionAO.a; - vec3 fragColor = albedoMetallic.rgb * ubo.ambient.rgb * ao; - for ( uint i = 0; i < LIGHTS; ++i ) { - Light light = ubo.lights[i]; - - if ( light.power <= 0.001 ) continue; - vec3 lightPositionWorld = light.position.xyz; - light.position.xyz = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position.xyz, 1)); - if ( light.type < 0 ) { - float factor = shadowFactor( light, i ); - if ( factor <= 0.0001 ) continue; - light.power *= factor; - litFactor += light.power; - } - if ( usePbr ) { - pbr( light, albedoMetallic.rgb, albedoMetallic.a, normalRoughness.a, lightPositionWorld, fragColor ); - } else - phong( light, albedoMetallic, fragColor ); - } - - if ( gammaCorrect ) { - fragColor = fragColor / (fragColor + vec3(1.0)); - fragColor = pow(fragColor, vec3(1.0/2.2)); - } - - fog(fragColor, litFactor); - -/* - if ( (ubo.mode.type & (0x1 << 0)) == (0x1 << 0) ) { - //dither1(fragColor); - fragColor += dither2(); - } - if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) { - whitenoise(fragColor); - } -*/ - outFragColor = vec4(fragColor,1); -} \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.vert.glsl b/bin/data/shaders/display/subpass.vert.glsl index 72ebf0a1..84260106 100644 --- a/bin/data/shaders/display/subpass.vert.glsl +++ b/bin/data/shaders/display/subpass.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (location = 0) in vec2 inPos; layout (location = 1) in vec2 inUv; diff --git a/bin/data/shaders/display/subpass.vxgi.frag.glsl b/bin/data/shaders/display/subpass.vxgi.frag.glsl index 532a9855..e8a51e8c 100644 --- a/bin/data/shaders/display/subpass.vxgi.frag.glsl +++ b/bin/data/shaders/display/subpass.vxgi.frag.glsl @@ -1,820 +1,17 @@ #version 450 -#extension GL_EXT_samplerless_texture_functions : require -#extension GL_EXT_nonuniform_qualifier : enable +#pragma shader_stage(fragment) -#define MULTISAMPLING 1 -#define DEFERRED_SAMPLING 1 +#define VXGI 1 -#define VXGI_NDC 1 -#define VXGI_SHADOWS 1 - -#define FOG 1 -#define FOG_RAY_MARCH 1 - -#define WHITENOISE 1 -#define GAMMA_CORRECT 1 -#define TONE_MAP 1 - -#define LAMBERT 0 -#define PBR 1 - -const float PI = 3.14159265359; -const float EPSILON = 0.00001; -const float SQRT2 = 1.41421356237; - -const float LIGHT_POWER_CUTOFF = 0.0005; - -const vec2 poissonDisk[16] = vec2[]( - vec2( -0.94201624, -0.39906216 ), - vec2( 0.94558609, -0.76890725 ), - vec2( -0.094184101, -0.92938870 ), - vec2( 0.34495938, 0.29387760 ), - vec2( -0.91588581, 0.45771432 ), - vec2( -0.81544232, -0.87912464 ), - vec2( -0.38277543, 0.27676845 ), - vec2( 0.97484398, 0.75648379 ), - vec2( 0.44323325, -0.97511554 ), - vec2( 0.53742981, -0.47373420 ), - vec2( -0.26496911, -0.41893023 ), - vec2( 0.79197514, 0.19090188 ), - vec2( -0.24188840, 0.99706507 ), - vec2( -0.81409955, 0.91437590 ), - vec2( 0.19984126, 0.78641367 ), - vec2( 0.14383161, -0.14100790 ) -); - -layout (constant_id = 0) const uint CASCADES = 16; -layout (constant_id = 1) const uint TEXTURES = 512; - -struct Matrices { - mat4 view[2]; - mat4 projection[2]; - mat4 iView[2]; - mat4 iProjection[2]; - mat4 iProjectionView[2]; - vec4 eyePos[2]; - mat4 vxgi; -}; - -struct Ray { - vec3 origin; - vec3 direction; - - vec3 position; - float distance; -}; - -struct Space { - vec3 eye; - vec3 world; -}; - -struct Fog { - vec3 color; - float stepScale; - - vec3 offset; - float densityScale; - - float densityThreshold; - float densityMultiplier; - float absorbtion; - float padding1; - - vec2 range; - float padding2; - float padding3; -}; - -struct Mode { - uint type; - uint scalar; - vec2 padding; - vec4 parameters; -}; - -struct Light { - vec3 position; - float radius; - - vec3 color; - float power; - - int type; - int mapIndex; - float depthBias; - float padding; - - mat4 view; - mat4 projection; -}; - -struct Material { - vec4 colorBase; - vec4 colorEmissive; - - float factorMetallic; - float factorRoughness; - float factorOcclusion; - float factorAlphaCutoff; - - int indexAlbedo; - int indexNormal; - int indexEmissive; - int indexOcclusion; - - int indexMetallicRoughness; - int indexAtlas; - int indexLightmap; - int modeAlpha; -}; - -struct Texture { - int index; - int samp; - int remap; - float blend; - - vec4 lerp; -}; - -struct DrawCall { - int materialIndex; - uint materials; - int textureIndex; - uint textures; -}; - -struct SurfaceMaterial { - uint id; - - vec4 albedo; - vec4 indirect; - - float metallic; - float roughness; - float occlusion; -}; - -struct Surface { - vec2 uv; - Space position; - Space normal; - - Ray ray; - - SurfaceMaterial material; - - vec4 fragment; -} surface; - -struct Voxel { - uvec2 id; - vec3 position; - 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; - #if DEFERRED_SAMPLING - layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerUv; - #else - layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo; - #endif - layout (input_attachment_index = 3, binding = 3) uniform subpassInput samplerDepth; -#else - layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId; - layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal; - #if DEFERRED_SAMPLING - layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerUv; - #else - layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo; - #endif - layout (input_attachment_index = 3, binding = 3) uniform subpassInputMS samplerDepth; -#endif - -layout (binding = 4) uniform UBO { - Matrices matrices; - - Mode mode; - Fog fog; - - uint lights; - uint materials; - uint textures; - uint drawCalls; - - vec3 ambient; - float gamma; - - float exposure; - uint msaa; - uint shadowSamples; - float cascadePower; -} ubo; - -layout (std140, binding = 5) readonly buffer Lights { - Light lights[]; -}; -layout (std140, binding = 6) readonly buffer Materials { - Material materials[]; -}; -layout (std140, binding = 7) readonly buffer Textures { - Texture textures[]; -}; -layout (std140, binding = 8) readonly buffer DrawCalls { - DrawCall drawCalls[]; -}; - -layout (binding = 9) uniform usampler3D voxelId[CASCADES]; -layout (binding = 10) uniform sampler3D voxelUv[CASCADES]; -layout (binding = 11) uniform sampler3D voxelNormal[CASCADES]; -layout (binding = 12) uniform sampler3D voxelRadiance[CASCADES]; - -layout (binding = 13) uniform sampler3D samplerNoise; -layout (binding = 14) uniform samplerCube samplerSkybox; -layout (binding = 15) uniform sampler2D samplerTextures[TEXTURES]; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat uint inPushConstantPass; - -layout (location = 0) out vec4 outFragColor; - -// GGX/Towbridge-Reitz normal distribution function. -// Uses Disney's reparametrization of alpha = roughness^2. -float ndfGGX(float cosLh, float roughness) { - const float alpha = roughness * roughness; - const float alphaSq = alpha * alpha; - const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; - return alphaSq / (PI * denom * denom); -} - -// Single term for separable Schlick-GGX below. -float gaSchlickG1(float cosTheta, float k) { - return cosTheta / (cosTheta * (1.0 - k) + k); -} - -// Schlick-GGX approximation of geometric attenuation function using Smith's method. -float gaSchlickGGX(float cosLi, float cosLo, float roughness) { - const float r = roughness + 1.0; - const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. - return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); -} -vec3 fresnelSchlick(vec3 F0, float cosTheta) { - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); -} - -float random(vec3 seed, int i){ - return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453); -} - -// Returns a vector that is orthogonal to u. -vec3 orthogonal(vec3 u){ - u = normalize(u); - const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. - return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); -} -float rand2(vec2 co){ - return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453); -} -float rand3(vec3 co){ - return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); -} -void whitenoise(inout vec3 color) { - const float flicker = ubo.mode.parameters.x; - const float pieces = ubo.mode.parameters.y; - const float blend = ubo.mode.parameters.z; - const float time = ubo.mode.parameters.w; - if ( blend < 0.0001 ) return; - const float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); - const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); - color = mix( color, vec3(whiteNoise), blend ); -} -vec3 gamma( vec3 i ) { - return pow(i.rgb, vec3(1.0 / 2.2)); -} - -vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) { - const vec3 t0 = (boundsMin - ray.origin) / ray.direction; - const vec3 t1 = (boundsMax - ray.origin) / ray.direction; - const vec3 tmin = min(t0, t1); - const vec3 tmax = max(t0, t1); - const float tStart = max(0, max( max(tmin.x, tmin.y), tmin.z )); - const float tEnd = max(0, min( tmax.x, min(tmax.y, tmax.z) ) - tStart); - return vec2(tStart, tEnd); -} - -float sampleDensity( vec3 position ) { - const vec3 uvw = position * ubo.fog.densityScale * 0.001 + ubo.fog.offset * 0.01; - return max(0, texture(samplerNoise, uvw).r - ubo.fog.densityThreshold) * ubo.fog.densityMultiplier; -} - -void fog( in Ray ray, inout vec3 i, float scale ) { - if ( ubo.fog.stepScale <= 0 ) return; - if ( ubo.fog.range.x == 0 || ubo.fog.range.y == 0 ) return; - -#if FOG_RAY_MARCH - const float range = ubo.fog.range.y; - const vec3 boundsMin = vec3(-range,-range,-range) + ray.origin; - const vec3 boundsMax = vec3(range,range,range) + ray.origin; - const int numSteps = int(length(boundsMax - boundsMin) * ubo.fog.stepScale ); - - const vec2 rayBoxInfo = rayBoxDst( boundsMin, boundsMax, ray ); - const float dstToBox = rayBoxInfo.x; - const float dstInsideBox = rayBoxInfo.y; - const float depth = surface.position.eye.z; - - float lightEnergy = 0; - // march - if ( 0 <= dstInsideBox && dstToBox <= depth ) { - float dstTravelled = 0; - float stepSize = dstInsideBox / numSteps; - float dstLimit = min( depth - dstToBox, dstInsideBox ); - float totalDensity = 0; - float transmittance = 1; - while ( dstTravelled < dstLimit ) { - vec3 rayPos = ray.origin + ray.direction * (dstToBox + dstTravelled); - float density = sampleDensity(rayPos); - if ( density > 0 ) { - transmittance *= exp(-density * stepSize * ubo.fog.absorbtion); - if ( transmittance < 0.01 ) break; - } - dstTravelled += stepSize; - } - 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; - const float distance = length(-surface.position.eye); - const float factor = clamp( (distance - inner) / (outer - inner), 0.0, 1.0 ); - - i.rgb = mix(i.rgb, color, factor); -#endif -} - -vec3 decodeNormals( vec2 enc ) { - const vec2 ang = enc*2-1; - const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); - const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); - return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); -} -float wrap( float i ) { - return fract(i); -} -vec2 wrap( vec2 uv ) { - return vec2( wrap( uv.x ), wrap( uv.y ) ); -} -float mipLevel( in vec2 uv ) { - const vec2 dx_vtc = dFdx(uv); - const vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); -} -bool validTextureIndex( int textureIndex ) { - return 0 <= textureIndex; // && textureIndex < ubo.textures; -} -vec4 resolve( subpassInputMS t ) { - const int samples = int(ubo.msaa); - vec4 resolved = vec4(0); - for ( int i = 0; i < samples; ++i ) { - resolved += subpassLoad(t, i); - } - resolved /= vec4(samples); - return resolved; -} -uvec4 resolve( usubpassInputMS t ) { - const int samples = int(ubo.msaa); - uvec4 resolved = uvec4(0); - for ( int i = 0; i < samples; ++i ) { - resolved += subpassLoad(t, i); - } - resolved /= uvec4(samples); - return resolved; -} - -#if !VXGI_SHADOWS -float shadowFactor( const Light light, float def ) { - if ( !validTextureIndex(light.mapIndex) ) return 1.0; - - vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); - positionClip.xyz /= positionClip.w; - - if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; - if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; - if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; - - float factor = 1.0; - - // spot light - if ( abs(light.type) == 2 || abs(light.type) == 3 ) { - const float dist = length( positionClip.xy ); - if ( dist > 0.5 ) return def; //0.0; - - // spot light with attenuation - if ( abs(light.type) == 3 ) { - factor = 1.0 - (pow(dist * 2,2.0)); - } - } - - const vec2 uv = positionClip.xy * 0.5 + 0.5; - const float bias = light.depthBias; - const float eyeDepth = positionClip.z; - const int samples = int(ubo.shadowSamples); - if ( samples < 1 ) return eyeDepth < texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv).r - bias ? 0.0 : factor; - for ( int i = 0; i < samples; ++i ) { - const int index = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; - const float lightDepth = texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv + poissonDisk[index] / 700.0 ).r; - if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; - } - return factor; -} -#endif - -vec4 postProcess() { -#if FOG - fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); -#endif -#if TONE_MAP - surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * ubo.exposure); -#endif -#if GAMMA_CORRECT - surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / ubo.gamma)); -#endif -#if WHITENOISE - if ( (ubo.mode.type & (0x1 << 1)) == (0x1 << 1) ) whitenoise(surface.fragment.rgb); -#endif - - return vec4(surface.fragment.rgb,1); -} - -struct VoxelInfo { - vec3 min; - vec3 max; - - float mipmapLevels; - float radianceSize; - float radianceSizeRecip; -} voxelInfo; - -uint BIASED_ROUND( float x ) { - return uint( (x < 1 - voxelInfo.radianceSizeRecip) ? floor(x) : ceil(x)); -} -float SCALE_CASCADE( uint x ) { - return pow(1 + x, ubo.cascadePower); -} - -vec4 voxelTrace( inout Ray ray, float aperture, float maxDistance ) { - uint CASCADE = 0; -#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 ) ); - - CASCADE = BIASED_ROUND(clamp( max( max( abs(ray.origin.x), abs(ray.origin.y) ), abs(ray.origin.z) ), 0, CASCADES - 1 )); -#else -{ - 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 = 12.0f; - const float granularity = 1.0f / granularityRecip; - const float occlusionFalloff = 128.0f; - - const vec3 voxelBounds = voxelInfo.max - voxelInfo.min; - const vec3 voxelBoundsRecip = 1.0f / voxelBounds; - - const float coneCoefficient = 2.0 * tan(aperture * 0.5); - const uint maxSteps = uint(voxelInfo.radianceSize * CASCADES * granularityRecip); - // box - 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); - const float tDelta = voxelInfo.radianceSizeRecip * granularityRecip; - // marcher - ray.distance = tStart + tDelta * 4 * (1 + CASCADE); - ray.position = vec3(0); - - 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.0; - uint stepCounter = 0; -#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; - #else - uvw = vec3( ubo.matrices.vxgi * vec4( ray.position, 1.0 ) ); - #endif - 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 = aperture > 0 ? log2( coneDiameter ) : 0; - - if ( level >= voxelInfo.mipmapLevels ) break; - - radiance = textureLod(voxelRadiance[nonuniformEXT(CASCADE)], uvw.xzy, level); - - color += (1.0 - color.a) * radiance; - occlusion += ((1.0f - occlusion) * radiance.a) / (1.0f + occlusionFalloff * coneDiameter); - } - return maxDistance > 0 ? color : vec4(color.rgb, occlusion); -// return vec4(color.rgb, occlusion); -} -vec4 voxelConeTrace( inout Ray ray, float aperture ) { - return voxelTrace( ray, aperture, 0 ); -} -vec4 voxelTrace( inout Ray ray, float maxDistance ) { - return voxelTrace( ray, 0, maxDistance ); -} - -#if VXGI_SHADOWS -float shadowFactor( const Light light, float def ) { - const float SHADOW_APERTURE = 0.2; - const float DEPTH_BIAS = 0.0; - - Ray ray; - ray.direction = normalize( light.position - surface.position.world ); - ray.origin = surface.position.world + ray.direction * 0.5; - float z = distance( surface.position.world, light.position ) - DEPTH_BIAS; - return 1.0 - voxelTrace( ray, SHADOW_APERTURE, z ).a; -} -#endif +#include "./subpass.h" void main() { - { - #if !MULTISAMPLING - const float depth = subpassLoad(samplerDepth).r; - #else - const float depth = resolve( samplerDepth ).r; - #endif + populateSurface(); + indirectLighting(); - vec4 positionEye = ubo.matrices.iProjection[inPushConstantPass] * vec4(inUv * 2.0 - 1.0, depth, 1.0); - positionEye /= positionEye.w; - surface.position.eye = positionEye.xyz; - surface.position.world = vec3( ubo.matrices.iView[inPushConstantPass] * positionEye ); - } -#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)); - const vec3 near3 = near4.xyz / near4.w; - const vec3 far3 = far4.xyz / far4.w; + const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; + surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); - surface.ray.origin = near3; - surface.ray.direction = normalize( far3 - near3 ); - } - // separate our ray direction due to floating point precision problems - { - const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) ); - const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - const vec3 near3 = near4.xyz / near4.w; - const vec3 far3 = far4.xyz / far4.w; - - surface.ray.direction = normalize( far3 - near3 ); - } -#else - { - const mat4 iProjectionView = inverse( ubo.matrices.projection[inPushConstantPass] * mat4(mat3(ubo.matrices.view[inPushConstantPass])) ); - const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0)); - const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0)); - const vec3 near3 = near4.xyz / near4.w; - const vec3 far3 = far4.xyz / far4.w; - - surface.ray.direction = normalize( far3 - near3 ); - surface.ray.origin = ubo.matrices.eyePos[inPushConstantPass].xyz; - } -#endif -#if !MULTISAMPLING - surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); - const uvec2 ID = subpassLoad(samplerId).xy; -#else - surface.normal.world = decodeNormals( resolve(samplerNormal).xy ); - const uvec2 ID = resolve(samplerId).xy; -#endif - surface.normal.eye = vec3( ubo.matrices.view[inPushConstantPass] * vec4(surface.normal.world, 0.0) ); - - if ( ID.x == 0 || ID.y == 0 ) { - surface.fragment.rgb = texture( samplerSkybox, surface.ray.direction ).rgb; - surface.fragment.a = 0.0; - outFragColor = postProcess(); - return; - } - const uint drawId = ID.x - 1; - const DrawCall drawCall = drawCalls[drawId]; - surface.material.id = ID.y + drawCall.materialIndex - 1; - const Material material = materials[surface.material.id]; - surface.material.albedo = material.colorBase; - surface.fragment = material.colorEmissive; -#if DEFERRED_SAMPLING -#if !MULTISAMPLING - surface.uv = subpassLoad(samplerUv).xy; -#else - surface.uv = resolve(samplerUv).xy; -#endif - const float mip = mipLevel(inUv.xy); - const bool useAtlas = validTextureIndex( drawCall.textureIndex + material.indexAtlas ); - Texture textureAtlas; - if ( useAtlas ) textureAtlas = textures[drawCall.textureIndex + material.indexAtlas]; - if ( validTextureIndex( drawCall.textureIndex + material.indexAlbedo ) ) { - const Texture t = textures[drawCall.textureIndex + material.indexAlbedo]; - surface.material.albedo = textureLod( samplerTextures[nonuniformEXT((useAtlas)?textureAtlas.index:t.index)], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); - } - // OPAQUE - if ( material.modeAlpha == 0 ) { - surface.material.albedo.a = 1; - // BLEND - } else if ( material.modeAlpha == 1 ) { - - // MASK - } else if ( material.modeAlpha == 2 ) { - - } - // Emissive textures - if ( validTextureIndex( drawCall.textureIndex + material.indexEmissive ) ) { - const Texture t = textures[drawCall.textureIndex + material.indexEmissive]; - surface.fragment += textureLod( samplerTextures[nonuniformEXT((useAtlas)?textureAtlas.index:t.index)], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, surface.uv ) : surface.uv, mip ); - } -#else -#if !MULTISAMPLING - surface.material.albedo = subpassLoad(samplerAlbedo); -#else - surface.material.albedo = resolve(samplerAlbedo); -#endif -#endif - surface.material.metallic = material.factorMetallic; - surface.material.roughness = material.factorRoughness; - surface.material.occlusion = material.factorOcclusion; - // GI - { - voxelInfo.radianceSize = textureSize( voxelRadiance[0], 0 ).x; - voxelInfo.radianceSizeRecip = 1.0 / voxelInfo.radianceSize; - voxelInfo.mipmapLevels = log2(voxelInfo.radianceSize) + 1; - #if VXGI_NDC - voxelInfo.min = vec3( -1 ); - voxelInfo.max = vec3( 1 ); - #else - const mat4 inverseOrtho = inverse( ubo.matrices.vxgi ); - voxelInfo.min = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) ); - voxelInfo.max = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) ); - #endif - } - { - const vec3 P = surface.position.world; - const vec3 N = surface.normal.world; - - #if 1 - const vec3 right = normalize(orthogonal(N)); - const vec3 up = normalize(cross(right, N)); - - const uint CONES_COUNT = 6; - const vec3 CONES[] = { - N, - normalize(N + 0.0f * right + 0.866025f * up), - normalize(N + 0.823639f * right + 0.267617f * up), - normalize(N + 0.509037f * right + -0.7006629f * up), - normalize(N + -0.50937f * right + -0.7006629f * up), - normalize(N + -0.823639f * right + 0.267617f * up), - }; - #else - const vec3 ortho = normalize(orthogonal(N)); - const vec3 ortho2 = normalize(cross(ortho, N)); - - const vec3 corner = 0.5f * (ortho + ortho2); - const vec3 corner2 = 0.5f * (ortho - ortho2); - - const uint CONES_COUNT = 9; - const vec3 CONES[] = { - N, - normalize(mix(N, ortho, 0.5)), - normalize(mix(N, -ortho, 0.5)), - normalize(mix(N, ortho2, 0.5)), - normalize(mix(N, -ortho2, 0.5)), - normalize(mix(N, corner, 0.5)), - normalize(mix(N, -corner, 0.5)), - normalize(mix(N, corner2, 0.5)), - normalize(mix(N, -corner2, 0.5)), - }; - #endif - - const float DIFFUSE_CONE_APERTURE = 0.57735f; - const float DIFFUSE_INDIRECT_FACTOR = 1.0f / float(CONES_COUNT); - - const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * surface.material.roughness), 0.0174533f, PI); // tan( R * PI * 0.5f * 0.1f ); - const float SPECULAR_INDIRECT_FACTOR = (1.0 - surface.material.metallic) * 0.5; // 1.0f; - - vec4 indirectDiffuse = vec4(0); - vec4 indirectSpecular = vec4(0); - - // outFragColor.rgb = voxelConeTrace( surface.ray, 0 ).rgb; return; - - 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 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); - // outFragColor.rgb = indirectDiffuse.rgb; return; - // outFragColor.rgb = vec3(surface.material.occlusion); return; - } - if ( SPECULAR_INDIRECT_FACTOR > 0.0f ) { - 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; - } - surface.material.indirect = indirectDiffuse * DIFFUSE_INDIRECT_FACTOR + indirectSpecular * SPECULAR_INDIRECT_FACTOR; - // outFragColor.rgb = surface.material.indirect.rgb; return; - } - - if ( 0 <= material.indexLightmap ) { - surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; - } else { - surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; - } -#if DEFERRED_SAMPLING - // deferred sampling doesn't have a blended albedo buffer - // in place we'll just cone trace behind the window - if ( surface.material.albedo.a < 1.0 ) { - Ray ray; - ray.origin = surface.position.world; - ray.direction = surface.ray.direction; - vec4 radiance = voxelConeTrace( ray, surface.material.albedo.a ); - surface.fragment.rgb += (1.0 - surface.material.albedo.a) * radiance.rgb; - } -#endif - - // corrections - surface.material.roughness *= 4.0; - - { - const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); - const vec3 Lo = normalize( -surface.position.eye ); - const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); - - for ( uint i = 0; i < ubo.lights; ++i ) { - const Light light = lights[i]; - if ( light.power <= LIGHT_POWER_CUTOFF ) continue; - const vec3 Lp = light.position; - const vec3 Liu = vec3(ubo.matrices.view[inPushConstantPass] * vec4(light.position, 1)) - surface.position.eye; - const vec3 Li = normalize(Liu); - #if VXGI_SHADOWS - const float Ls = i < ubo.shadowSamples ? shadowFactor( light, 0.0 ) : 1.0; - #else - const float Ls = shadowFactor( light, 0.0 ); - #endif - const float La = 1.0 / (PI * pow(length(Liu), 2.0)); - if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; - - const float cosLi = max(0.0, dot(surface.normal.eye, Li)); - const vec3 Lr = light.color.rgb * light.power * La * Ls; - #if LAMBERT - const vec3 diffuse = surface.material.albedo.rgb; - const vec3 specular = vec3(0); - #elif PBR - const vec3 Lh = normalize(Li + Lo); - const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); - - const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); - const float D = ndfGGX( cosLh, surface.material.roughness ); - const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); - const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; - const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); - #endif - // lightmapped, compute only specular - if ( light.type >= 0 && 0 <= material.indexLightmap ) surface.fragment.rgb += (specular) * Lr * cosLi; - // point light, compute only diffuse - // else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi; - else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; - // surface.fragment.a += light.power * La * Ls; - } - } - - outFragColor = postProcess(); + pbr(); + postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.vxgi.no-msaa.frag.glsl b/bin/data/shaders/display/subpass.vxgi.no-msaa.frag.glsl new file mode 100644 index 00000000..ea9f608d --- /dev/null +++ b/bin/data/shaders/display/subpass.vxgi.no-msaa.frag.glsl @@ -0,0 +1,17 @@ +#version 450 +#pragma shader_stage(fragment) + +#define VXGI 1 +#define MULTISAMPLING 0 +#include "./subpass.h" + +void main() { + populateSurface(); + indirectLighting(); + + const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; + surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); + + pbr(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders/display/vxgi.comp.glsl b/bin/data/shaders/display/vxgi.comp.glsl index c3a20196..5fe1e751 100644 --- a/bin/data/shaders/display/vxgi.comp.glsl +++ b/bin/data/shaders/display/vxgi.comp.glsl @@ -1,11 +1,13 @@ #version 450 +#pragma shader_stage(compute) + #extension GL_EXT_samplerless_texture_functions : require #extension GL_EXT_nonuniform_qualifier : enable layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; #define MULTISAMPLING 1 -#define DEFERRED_SAMPLING 1 +#define DEFERRED_SAMPLING 0 #define LAMBERT 1 #define PBR 0 @@ -176,7 +178,11 @@ layout (std140, binding = 8) readonly buffer DrawCalls { layout (binding = 9, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; layout (binding = 10, rg16f) uniform volatile coherent image3D voxelUv[CASCADES]; layout (binding = 11, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; -layout (binding = 12, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#if VXGI_HDR + layout (binding = 12, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#else + layout (binding = 12, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#endif layout (binding = 13) uniform sampler3D samplerNoise; layout (binding = 14) uniform samplerCube samplerSkybox; @@ -281,8 +287,9 @@ float shadowFactor( const Light light, float def ) { #endif } -float SCALE_CASCADE( uint x ) { +float cascadePower( uint x ) { return pow(1 + x, ubo.cascadePower); +// return max( 1, x * ubo.cascadePower ); } void main() { @@ -291,7 +298,7 @@ void main() { 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])) * 2.0f - 1.0f) * SCALE_CASCADE(CASCADE); + surface.position.eye = (vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelRadiance[CASCADE])) * 2.0f - 1.0f) * cascadePower(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/baked.frag.glsl b/bin/data/shaders/gltf/baked.frag.glsl index 6eef61e2..0ed0bf30 100644 --- a/bin/data/shaders/gltf/baked.frag.glsl +++ b/bin/data/shaders/gltf/baked.frag.glsl @@ -1,40 +1,15 @@ #version 450 +#pragma shader_stage(fragment) -#define UF_DEFERRED_SAMPLING 0 -#define UF_CAN_DISCARD 1 - -#define PI 3.1415926536f - +#define MAX_TEXTURES TEXTURES layout (constant_id = 0) const uint TEXTURES = 1; + +#include "../common/macros.h" +#include "../common/structs.h" +#include "../common/functions.h" + layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; -struct Material { - vec4 colorBase; - vec4 colorEmissive; - - float factorMetallic; - float factorRoughness; - float factorOcclusion; - float factorAlphaCutoff; - - int indexAlbedo; - int indexNormal; - int indexEmissive; - int indexOcclusion; - - int indexMetallicRoughness; - int modeAlpha; - int padding1; - int padding2; -}; -struct Texture { - int index; - int samp; - int remap; - float blend; - - vec4 lerp; -}; layout (std140, binding = 1) readonly buffer Materials { Material materials[]; }; @@ -52,42 +27,23 @@ layout (location = 8) flat in ivec4 inId; layout (location = 0) out uvec2 outId; layout (location = 1) out vec2 outNormals; -#if UF_DEFERRED_SAMPLING +#if DEFERRED_SAMPLING layout (location = 2) out vec2 outUvs; #else layout (location = 2) out vec4 outAlbedo; #endif -vec2 encodeNormals( vec3 n ) { -// return n.xy / sqrt(n.z*8+8) + 0.5; - return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5; -} - -float wrap( float i ) { - return fract(i); -} -vec2 wrap( vec2 uv ) { - return vec2( wrap( uv.x ), wrap( uv.y ) ); -} -float mipLevel( in vec2 uv ) { - const vec2 dx_vtc = dFdx(uv); - const vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); -} -bool validTextureIndex( int textureIndex ) { - return 0 <= textureIndex && textureIndex < TEXTURES; -} void main() { const float mip = mipLevel(inUv.xy); const vec2 uv = wrap(inUv.xy); vec4 A = vec4(0, 0, 0, 0); const vec3 P = inPosition; const vec3 N = inNormal; -#if UF_DEFERRED_SAMPLING +#if DEFERRED_SAMPLING outUvs = wrap(inUv.xy); const vec4 outAlbedo = vec4(0,0,0,0); #endif -#if !UF_DEFERRED_SAMPLING +#if !DEFERRED_SAMPLING A = textureLod( samplerTextures[0], inSt, mip ); #endif outNormals = encodeNormals( N ); diff --git a/bin/data/shaders/gltf/baking/bake.frag.glsl b/bin/data/shaders/gltf/baking/bake.frag.glsl index 06974b3a..a18d2a2c 100644 --- a/bin/data/shaders/gltf/baking/bake.frag.glsl +++ b/bin/data/shaders/gltf/baking/bake.frag.glsl @@ -1,117 +1,20 @@ #version 450 +#pragma shader_stage(fragment) + #extension GL_EXT_nonuniform_qualifier : enable -#define LAMBERT 1 -#define PBR 0 - -const float PI = 3.14159265359; -const float EPSILON = 0.00001; - -const float LIGHT_POWER_CUTOFF = 0.005; - - -const vec2 poissonDisk[16] = vec2[]( - vec2( -0.94201624, -0.39906216 ), - vec2( 0.94558609, -0.76890725 ), - vec2( -0.094184101, -0.92938870 ), - vec2( 0.34495938, 0.29387760 ), - vec2( -0.91588581, 0.45771432 ), - vec2( -0.81544232, -0.87912464 ), - vec2( -0.38277543, 0.27676845 ), - vec2( 0.97484398, 0.75648379 ), - vec2( 0.44323325, -0.97511554 ), - vec2( 0.53742981, -0.47373420 ), - vec2( -0.26496911, -0.41893023 ), - vec2( 0.79197514, 0.19090188 ), - vec2( -0.24188840, 0.99706507 ), - vec2( -0.81409955, 0.91437590 ), - vec2( 0.19984126, 0.78641367 ), - vec2( 0.14383161, -0.14100790 ) -); - layout (constant_id = 0) const uint TEXTURES = 1; layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; -struct Material { - vec4 colorBase; - vec4 colorEmissive; +#define SHADOW_SAMPLES 16 - float factorMetallic; - float factorRoughness; - float factorOcclusion; - float factorAlphaCutoff; +#define PBR 0 +#define LAMBERT 1 - int indexAlbedo; - int indexNormal; - int indexEmissive; - int indexOcclusion; - - int indexMetallicRoughness; - int indexAtlas; - int indexLightmap; - int modeAlpha; -}; - -struct Texture { - int index; - int samp; - int remap; - float blend; - - vec4 lerp; -}; - -struct Light { - vec3 position; - float radius; - - vec3 color; - float power; - - int type; - int mapIndex; - float depthBias; - float padding; - - mat4 view; - mat4 projection; -}; - -struct Ray { - vec3 origin; - vec3 direction; - - vec3 position; - float distance; -}; - -struct Space { - vec3 eye; - vec3 world; -}; - -struct SurfaceMaterial { - uint id; - - vec4 albedo; - vec4 indirect; - - float metallic; - float roughness; - float occlusion; -}; - -struct Surface { - vec2 uv; - Space position; - Space normal; - - Ray ray; - - SurfaceMaterial material; - - vec4 fragment; -} surface; +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" +#include "../../common/shadows.h" layout (std140, binding = 3) readonly buffer Materials { Material materials[]; @@ -132,110 +35,6 @@ layout (location = 7) flat in ivec4 inId; layout (location = 0) out vec4 outAlbedo; -// GGX/Towbridge-Reitz normal distribution function. -// Uses Disney's reparametrization of alpha = roughness^2. -float ndfGGX(float cosLh, float roughness) { - const float alpha = roughness * roughness; - const float alphaSq = alpha * alpha; - const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; - return alphaSq / (PI * denom * denom); -} - -// Single term for separable Schlick-GGX below. -float gaSchlickG1(float cosTheta, float k) { - return cosTheta / (cosTheta * (1.0 - k) + k); -} - -// Schlick-GGX approximation of geometric attenuation function using Smith's method. -float gaSchlickGGX(float cosLi, float cosLo, float roughness) { - const float r = roughness + 1.0; - const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. - return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); -} -vec3 fresnelSchlick(vec3 F0, float cosTheta) { - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); -} - -float random(vec3 seed, int i){ - return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453); -} - -// Returns a vector that is orthogonal to u. -vec3 orthogonal(vec3 u){ - u = normalize(u); - const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. - return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); -} -float rand2(vec2 co){ - return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453); -} -float rand3(vec3 co){ - return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); -} - -vec3 decodeNormals( vec2 enc ) { - const vec2 ang = enc*2-1; - const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); - const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); - return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); -/* - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - return normalize( vec3(fenc * g, 1 - f / 2) ); -*/ -} -float wrap( float i ) { - return fract(i); -} -vec2 wrap( vec2 uv ) { - return vec2( wrap( uv.x ), wrap( uv.y ) ); -} -float mipLevel( in vec2 uv ) { - const vec2 dx_vtc = dFdx(uv); - const vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); -} -bool validTextureIndex( int textureIndex ) { - return 0 <= textureIndex; // && textureIndex < ubo.textures; -} - -float shadowFactor( const Light light, float def ) { - if ( !validTextureIndex(light.mapIndex) ) return 1.0; - - vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); - positionClip.xyz /= positionClip.w; - - if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; - if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; - if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; - - float factor = 1.0; - - // spot light - if ( abs(light.type) == 2 || abs(light.type) == 3 ) { - const float dist = length( positionClip.xy ); - if ( dist > 0.5 ) return def; //0.0; - - // spot light with attenuation - if ( abs(light.type) == 3 ) { - factor = 1.0 - (pow(dist * 2,2.0)); - } - } - - const vec2 uv = positionClip.xy * 0.5 + 0.5; - const float bias = light.depthBias; - const float eyeDepth = positionClip.z; - const int samples = 16; //int(ubo.poissonSamples); - if ( samples <= 1 ) return eyeDepth < texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv).r - bias ? 0.0 : factor; - for ( int i = 0; i < samples; ++i ) { - const int index = int( float(samples) * random(floor(surface.position.world * 1000.0), i)) % samples; - const float lightDepth = texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv + poissonDisk[index] / 700.0 ).r; - if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; - } - return factor; -} - void main() { vec4 A = vec4(1, 1, 1, 1); surface.normal.world = normalize( inNormal ); diff --git a/bin/data/shaders/gltf/baking/bake.vert.glsl b/bin/data/shaders/gltf/baking/bake.vert.glsl index 6f95d061..d19901ad 100644 --- a/bin/data/shaders/gltf/baking/bake.vert.glsl +++ b/bin/data/shaders/gltf/baking/bake.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec3 inPos; diff --git a/bin/data/shaders/gltf/base.frag.glsl b/bin/data/shaders/gltf/base.frag.glsl index 47b43810..23e96c31 100644 --- a/bin/data/shaders/gltf/base.frag.glsl +++ b/bin/data/shaders/gltf/base.frag.glsl @@ -1,40 +1,16 @@ #version 450 +#pragma shader_stage(fragment) + #extension GL_EXT_nonuniform_qualifier : enable -#define DEFERRED_SAMPLING 1 -#define CAN_DISCARD 1 -#define USE_LIGHTMAP 1 - +#define MAX_TEXTURES textures.length() layout (constant_id = 0) const uint TEXTURES = 1; + +#include "../common/macros.h" +#include "../common/structs.h" + layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; -struct Material { - vec4 colorBase; - vec4 colorEmissive; - - float factorMetallic; - float factorRoughness; - float factorOcclusion; - float factorAlphaCutoff; - - int indexAlbedo; - int indexNormal; - int indexEmissive; - int indexOcclusion; - - int indexMetallicRoughness; - int indexAtlas; - int indexLightmap; - int modeAlpha; -}; -struct Texture { - int index; - int samp; - int remap; - float blend; - - vec4 lerp; -}; layout (std140, binding = 1) readonly buffer Materials { Material materials[]; }; @@ -42,6 +18,8 @@ layout (std140, binding = 2) readonly buffer Textures { Texture textures[]; }; +#include "../common/functions.h" + layout (location = 0) in vec2 inUv; layout (location = 1) in vec2 inSt; layout (location = 2) in vec4 inColor; @@ -58,26 +36,6 @@ layout (location = 1) out vec2 outNormals; layout (location = 2) out vec4 outAlbedo; #endif -#define PI 3.1415926536f - -vec2 encodeNormals( vec3 n ) { -// return n.xy / sqrt(n.z*8+8) + 0.5; - return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5; -} -float wrap( float i ) { - return fract(i); -} -vec2 wrap( vec2 uv ) { - return vec2( wrap( uv.x ), wrap( uv.y ) ); -} -float mipLevel( in vec2 uv ) { - const vec2 dx_vtc = dFdx(uv); - const vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); -} -bool validTextureIndex( int textureIndex ) { - return 0 <= textureIndex && textureIndex < textures.length(); -} void main() { const float mip = mipLevel(inUv.xy); const vec2 uv = wrap(inUv.xy); diff --git a/bin/data/shaders/gltf/base.vert.glsl b/bin/data/shaders/gltf/base.vert.glsl index 5bdd45a2..0a09a548 100644 --- a/bin/data/shaders/gltf/base.vert.glsl +++ b/bin/data/shaders/gltf/base.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec3 inPos; diff --git a/bin/data/shaders/gltf/instanced.vert.glsl b/bin/data/shaders/gltf/instanced.vert.glsl index 02e4bb9a..1242b2ba 100644 --- a/bin/data/shaders/gltf/instanced.vert.glsl +++ b/bin/data/shaders/gltf/instanced.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec3 inPos; diff --git a/bin/data/shaders/gltf/skinned.instanced.vert.glsl b/bin/data/shaders/gltf/skinned.instanced.vert.glsl index 54cd6e09..c7d89674 100644 --- a/bin/data/shaders/gltf/skinned.instanced.vert.glsl +++ b/bin/data/shaders/gltf/skinned.instanced.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec3 inPos; diff --git a/bin/data/shaders/gltf/skinned.vert.glsl b/bin/data/shaders/gltf/skinned.vert.glsl index da2832ce..d1f1633b 100644 --- a/bin/data/shaders/gltf/skinned.vert.glsl +++ b/bin/data/shaders/gltf/skinned.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec3 inPos; diff --git a/bin/data/shaders/gltf/voxelize.frag.glsl b/bin/data/shaders/gltf/voxelize.frag.glsl index 9b5e6cf9..1a8a5369 100644 --- a/bin/data/shaders/gltf/voxelize.frag.glsl +++ b/bin/data/shaders/gltf/voxelize.frag.glsl @@ -1,41 +1,17 @@ #version 450 +#pragma shader_stage(fragment) #extension GL_EXT_nonuniform_qualifier : enable -#define DEFERRED_SAMPLING 1 -#define USE_LIGHTMAP 1 - -#define PI 3.1415926536f +#define BLEND 1 +#define DEPTH_TEST 1 layout (constant_id = 0) const uint CASCADES = 16; layout (constant_id = 1) const uint TEXTURES = 512; -struct Material { - vec4 colorBase; - vec4 colorEmissive; +#define MAX_TEXTURES textures.length() +#include "../common/macros.h" +#include "../common/structs.h" - float factorMetallic; - float factorRoughness; - float factorOcclusion; - float factorAlphaCutoff; - - int indexAlbedo; - int indexNormal; - int indexEmissive; - int indexOcclusion; - - int indexMetallicRoughness; - int indexAtlas; - int indexLightmap; - int modeAlpha; -}; -struct Texture { - int index; - int samp; - int remap; - float blend; - - vec4 lerp; -}; layout (std140, binding = 0) readonly buffer Materials { Material materials[]; }; @@ -43,6 +19,7 @@ layout (std140, binding = 1) readonly buffer Textures { Texture textures[]; }; +#include "../common/functions.h" layout (location = 0) in vec2 inUv; layout (location = 1) in vec2 inSt; @@ -57,7 +34,12 @@ layout (binding = 7) uniform sampler2D samplerTextures[TEXTURES]; layout (binding = 8, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; layout (binding = 9, rg16f) uniform volatile coherent image3D voxelUv[CASCADES]; layout (binding = 10, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; -layout (binding = 11, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#if VXGI_HDR + layout (binding = 11, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#else + layout (binding = 11, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#endif +// layout (binding = 12, r16f) uniform volatile coherent image3D voxelDepth[CASCADES]; layout (location = 0) out uvec2 outId; layout (location = 1) out vec2 outNormals; @@ -67,25 +49,6 @@ layout (location = 1) out vec2 outNormals; layout (location = 2) out vec4 outAlbedo; #endif -vec2 encodeNormals( vec3 n ) { -// return n.xy / sqrt(n.z*8+8) + 0.5; - return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5; -} -float wrap( float i ) { - return fract(i); -} -vec2 wrap( vec2 uv ) { - return vec2( wrap( uv.x ), wrap( uv.y ) ); -} -float mipLevel( in vec2 uv ) { - const vec2 dx_vtc = dFdx(uv); - const vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); -} -bool validTextureIndex( int textureIndex ) { - return 0 <= textureIndex && textureIndex < textures.length(); -} - void main() { const uint CASCADE = inId.z; if ( CASCADES <= CASCADE ) discard; @@ -95,7 +58,7 @@ void main() { vec4 A = vec4(0, 0, 0, 0); const vec3 N = inNormal; const vec2 uv = wrap(inUv.xy); - const float mip = mipLevel(inUv.xy); + const float mip = 0; // mipLevel(inUv.xy); const int materialId = int(inId.y); const Material material = materials[materialId]; @@ -136,13 +99,35 @@ void main() { } #endif - const vec4 outAlbedo = A * inColor; + const float outDepth = length(inPosition.xzy); + const vec4 inAlbedo = imageLoad(voxelRadiance[CASCADE], ivec3(P * imageSize(voxelRadiance[CASCADE]))); +#if DEPTH_TEST + { + // const float depth = imageLoad(voxelDepth[CASCADE], ivec3(P * imageSize(voxelDepth[CASCADE]))).r; + const float inDepth = inAlbedo.a; + if ( inDepth != 0 && inDepth < outDepth ) discard; + // imageStore(voxelDepth[CASCADE], ivec3(P * imageSize(voxelUv[CASCADE])), vec4(inDepth, 0, 0, 0)); + } +#endif + +// const vec4 outAlbedo = A * inColor; + const vec4 outAlbedo = vec4( A.rgb * inColor.rgb, outDepth ); const uvec2 outId = uvec2(inId.w+1, inId.y+1); const vec2 outNormals = encodeNormals( normalize( N ) ); const vec2 outUvs = wrap(inUv.xy); - 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)); +#if BLEND + { + const ivec3 uvw = ivec3(P * imageSize(voxelNormal[CASCADE])); + const vec3 inNormal = decodeNormals( imageLoad(voxelNormal[CASCADE], uvw).xy ); + const vec4 store = vec4( encodeNormals(normalize(inNormal + N)), 0, 0 ); + imageStore(voxelNormal[CASCADE], uvw, store); + + imageStore(voxelRadiance[CASCADE], ivec3(P * imageSize(voxelRadiance[CASCADE])), inAlbedo.a > 0 ? (inAlbedo + outAlbedo) * 0.5 : outAlbedo); + } +#else + imageStore(voxelNormal[CASCADE], ivec3(P * imageSize(voxelNormal[CASCADE])), vec4(outNormals, 0, 0)); imageStore(voxelRadiance[CASCADE], ivec3(P * imageSize(voxelRadiance[CASCADE])), outAlbedo); +#endif } \ 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 e0450afa..24bf0379 100644 --- a/bin/data/shaders/gltf/voxelize.geom.glsl +++ b/bin/data/shaders/gltf/voxelize.geom.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(geometry) layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; @@ -27,8 +28,9 @@ layout (binding = 6) uniform UBO { float padding3; } ubo; -float SCALE_CASCADE( uint x ) { +float cascadePower( uint x ) { return pow(1 + x, ubo.cascadePower); +// return max( 1, x * ubo.cascadePower ); } void main(){ @@ -47,12 +49,11 @@ void main(){ 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), + vec3( ubo.voxel * vec4( inPosition[0], 1 ) ) / cascadePower(CASCADE), + vec3( ubo.voxel * vec4( inPosition[1], 1 ) ) / cascadePower(CASCADE), + vec3( ubo.voxel * vec4( inPosition[2], 1 ) ) / cascadePower(CASCADE), }; - for( uint i = 0; i < 3; ++i ){ const vec3 D = normalize( inPosition[i] - C ) * HALF_PIXEL; @@ -61,7 +62,7 @@ void main(){ outColor = inColor[i]; outNormal = inNormal[i]; outTBN = inTBN[i]; - outPosition = P[i]; // + D; + outPosition = P[i] + D; outId = inId[i]; const vec3 P = outPosition; // + D; @@ -70,9 +71,9 @@ void main(){ else if ( N.x > N.y && N.x > N.z ) gl_Position = vec4(P.y, P.z, 0, 1); else gl_Position = vec4(P.x, P.z, 0, 1); #else - if ( A == 0 ) gl_Position = vec4(P.zy, 1, 1 ); - else if ( A == 1 ) gl_Position = vec4(P.xz, 1, 1 ); - else if ( A == 2 ) gl_Position = vec4(P.xy, 1, 1 ); + 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(); } diff --git a/bin/data/shaders/gui/base.frag.glsl b/bin/data/shaders/gui/base.frag.glsl index 1119afa1..6ac4c46b 100644 --- a/bin/data/shaders/gui/base.frag.glsl +++ b/bin/data/shaders/gui/base.frag.glsl @@ -1,7 +1,12 @@ #version 450 +#pragma shader_stage(fragment) +#define TEXTURES 1 #define DEFERRED_SAMPLING 0 -#define CAN_DISCARD 1 + +#include "../common/macros.h" +#include "../common/structs.h" +#include "../common/functions.h" layout (binding = 1) uniform sampler2D samplerTexture; @@ -24,22 +29,6 @@ layout (location = 1) out vec2 outNormals; layout (location = 2) out vec4 outAlbedo; #endif -float wrap( float i ) { - return fract(i); -} -vec2 wrap( vec2 uv ) { - return vec2( wrap( uv.x ), wrap( uv.y ) ); -} -vec2 encodeNormals( vec3 n ) { - float p = sqrt(n.z*8+8); - return n.xy/p + 0.5; -} -float mipLevel( in vec2 uv ) { - vec2 dx_vtc = dFdx(uv); - vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); -} - void main() { if ( inUv.x < inGui.offset.x ) discard; if ( inUv.y < inGui.offset.y ) discard; diff --git a/bin/data/shaders/gui/base.vert.glsl b/bin/data/shaders/gui/base.vert.glsl index 9828ff94..03d72e61 100644 --- a/bin/data/shaders/gui/base.vert.glsl +++ b/bin/data/shaders/gui/base.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec2 inPos; diff --git a/bin/data/shaders/gui/text.frag.glsl b/bin/data/shaders/gui/text.frag.glsl index ad40d261..b7b595ee 100644 --- a/bin/data/shaders/gui/text.frag.glsl +++ b/bin/data/shaders/gui/text.frag.glsl @@ -1,7 +1,12 @@ #version 450 +#pragma shader_stage(fragment) +#define TEXTURES 1 #define DEFERRED_SAMPLING 0 -#define CAN_DISCARD 1 + +#include "../common/macros.h" +#include "../common/structs.h" +#include "../common/functions.h" layout (binding = 1) uniform sampler2D samplerTexture; diff --git a/bin/data/shaders/gui/text.vert.glsl b/bin/data/shaders/gui/text.vert.glsl index 487894d2..4fe810e1 100644 --- a/bin/data/shaders/gui/text.vert.glsl +++ b/bin/data/shaders/gui/text.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec2 inPos; diff --git a/bin/data/shaders/heightmap/frag.glsl b/bin/data/shaders/heightmap/frag.glsl deleted file mode 100644 index 7aa5d840..00000000 --- a/bin/data/shaders/heightmap/frag.glsl +++ /dev/null @@ -1,19 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in vec3 inNormal; -layout (location = 2) in vec4 inColor; - -layout (location = 0) out vec4 outAlbedoSpecular; -layout (location = 1) out vec4 outNormal; - -void main() { - outAlbedoSpecular = texture(samplerColor, inUv); - outAlbedoSpecular = vec4(1,1,1,1); - outAlbedoSpecular.rgb *= inColor.rgb; - outAlbedoSpecular.a = 1; -// outPosition = vec4(inPosition, 1.0); - outNormal = vec4(normalize(inNormal), 1.0); -} \ No newline at end of file diff --git a/bin/data/shaders/heightmap/vert.glsl b/bin/data/shaders/heightmap/vert.glsl deleted file mode 100644 index f802c523..00000000 --- a/bin/data/shaders/heightmap/vert.glsl +++ /dev/null @@ -1,52 +0,0 @@ -#version 450 - -layout (constant_id = 0) const uint PASSES = 6; -layout (location = 0) in vec3 inPos; -layout (location = 1) in vec2 inUv; -layout (location = 2) in vec3 inNormal; -layout (location = 3) in uint inColor; - -layout( push_constant ) uniform PushBlock { - uint pass; - uint draw; -} PushConstant; - -struct Matrices { - mat4 model; - mat4 view[PASSES]; - mat4 projection[PASSES]; -}; - -layout (binding = 0) uniform UBO { - Matrices matrices; - vec4 color; -} ubo; - -layout (location = 0) out vec2 outUv; -layout (location = 1) out vec3 outNormal; -layout (location = 2) out vec4 outColor; - -out gl_PerVertex { - vec4 gl_Position; -}; - - -void main() { - outUv = inUv; -// outColor = ubo.color; - -// outPosition = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0)); - outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0)); - -// outPosition = vec3(ubo.matrices.model * vec4(inPos.xyz, 1.0)); -// outNormal = vec3(ubo.matrices.model * vec4(inNormal.xyz, 0.0)); - - outColor.a = (inColor >> 24u) & 0xFF; - outColor.b = (inColor >> 16u) & 0xFF; - outColor.g = (inColor >> 8u) & 0xFF; - outColor.r = (inColor ) & 0xFF; - outColor.rgb /= 256.0; - outColor.a = 0.5; - - gl_Position = ubo.matrices.projection[PushConstant.pass] * ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inPos.xyz, 1.0); -} \ No newline at end of file diff --git a/bin/data/shaders/line/frag.glsl b/bin/data/shaders/line/base.frag.glsl similarity index 81% rename from bin/data/shaders/line/frag.glsl rename to bin/data/shaders/line/base.frag.glsl index b996dd27..32b41c5b 100644 --- a/bin/data/shaders/line/frag.glsl +++ b/bin/data/shaders/line/base.frag.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(fragment) layout (location = 0) in vec3 inColor; diff --git a/bin/data/shaders/line/vert.glsl b/bin/data/shaders/line/base.vert.glsl similarity index 91% rename from bin/data/shaders/line/vert.glsl rename to bin/data/shaders/line/base.vert.glsl index 215c618f..71766a52 100644 --- a/bin/data/shaders/line/vert.glsl +++ b/bin/data/shaders/line/base.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec3 inPos; diff --git a/bin/data/shaders/noise/frag.glsl b/bin/data/shaders/noise/frag.glsl deleted file mode 100644 index 2b8bc5da..00000000 --- a/bin/data/shaders/noise/frag.glsl +++ /dev/null @@ -1,23 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler3D samplerColor; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in vec4 inColor; -layout (location = 2) in vec3 inNormal; -layout (location = 3) in vec3 inPosition; - -layout (location = 0) out vec4 outAlbedoSpecular; -layout (location = 1) out vec4 outNormal; -layout (location = 2) out vec4 outPosition; - -layout (binding = 2) uniform UBO { - float slice; -} ubo; - -void main() { - outAlbedoSpecular.rgb = vec3(texture(samplerColor, vec3(inUv,ubo.slice)).r); - outAlbedoSpecular.a = 1; - outNormal = vec4(inNormal,1); - outPosition = vec4(inPosition,1); -} \ No newline at end of file diff --git a/bin/data/shaders/raytracing/comp.glsl b/bin/data/shaders/raytracing/base.comp.glsl similarity index 96% rename from bin/data/shaders/raytracing/comp.glsl rename to bin/data/shaders/raytracing/base.comp.glsl index dbc8fc79..a65abec0 100644 --- a/bin/data/shaders/raytracing/comp.glsl +++ b/bin/data/shaders/raytracing/base.comp.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(compute) layout (local_size_x = 32, local_size_y = 32) in; diff --git a/bin/data/shaders/terrain/frag.glsl b/bin/data/shaders/terrain/base.frag.glsl similarity index 91% rename from bin/data/shaders/terrain/frag.glsl rename to bin/data/shaders/terrain/base.frag.glsl index cfe7cd4b..52e6b022 100644 --- a/bin/data/shaders/terrain/frag.glsl +++ b/bin/data/shaders/terrain/base.frag.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(fragment) layout (binding = 1) uniform sampler2D samplerColor; diff --git a/bin/data/shaders/terrain/vert.glsl b/bin/data/shaders/terrain/base.vert.glsl similarity index 94% rename from bin/data/shaders/terrain/vert.glsl rename to bin/data/shaders/terrain/base.vert.glsl index 7c6d8752..bb0a37e6 100644 --- a/bin/data/shaders/terrain/vert.glsl +++ b/bin/data/shaders/terrain/base.vert.glsl @@ -1,4 +1,5 @@ #version 450 +#pragma shader_stage(vertex) layout (constant_id = 0) const uint PASSES = 6; layout (location = 0) in vec3 inPos; diff --git a/bin/data/shaders/texture/frag.glsl b/bin/data/shaders/texture/frag.glsl deleted file mode 100644 index 6ebfac38..00000000 --- a/bin/data/shaders/texture/frag.glsl +++ /dev/null @@ -1,11 +0,0 @@ -#version 450 - -layout (binding = 0) uniform sampler2D samplerColor; -layout (location = 0) in vec2 inUV; -layout (location = 0) out vec4 outFragColor; - -void main() { - vec4 sampledColor = texture(samplerColor, inUV); - if ( sampledColor.r <= 0.000001 && sampledColor.g <= 0.000001 && sampledColor.b <= 0.000001 ) discard; - outFragColor = sampledColor; -} \ No newline at end of file diff --git a/bin/data/shaders/texture/vert.glsl b/bin/data/shaders/texture/vert.glsl deleted file mode 100644 index 8e19c440..00000000 --- a/bin/data/shaders/texture/vert.glsl +++ /dev/null @@ -1,14 +0,0 @@ -#version 450 - -layout (location = 0) out vec2 outUV; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f + -1.0f, 0.0f, 1.0f); -} \ No newline at end of file diff --git a/client/client/ext.cpp b/client/client/ext.cpp index 4938151b..debeebaa 100644 --- a/client/client/ext.cpp +++ b/client/client/ext.cpp @@ -19,34 +19,17 @@ void client::initialize() { uf::renderer::device.window = &client::window; ext::load(); -#if 1 + client::config = ext::config; -#else - /* Initialize config */ { - struct { - uf::Serializer ext; - uf::Serializer fallback; - } config; - /* Get configuration */ { - config.ext = ext::config.serialize(); - } - /* Merge */ { - client::config = config.ext; - client::config.merge( config.fallback, true ); - } - } -#endif + /* Initialize window */ { // Window size - pod::Vector2i size; { - size.x = client::config["window"]["size"]["x"].as(); - size.y = client::config["window"]["size"]["y"].as(); - // request system size - if ( size.x <= 0 && size.y <= 0 ) { - auto resolution = client::window.getResolution(); - client::config["window"]["size"]["x"] = (size.x = resolution.x); - client::config["window"]["size"]["y"] = (size.y = resolution.y); - } + pod::Vector2i size = uf::vector::decode( client::config["window"]["size"], pod::Vector2i{} ); + // request system size + if ( size.x <= 0 && size.y <= 0 ) { + auto resolution = client::window.getResolution(); + client::config["window"]["size"][0] = (size.x = resolution.x); + client::config["window"]["size"][1] = (size.y = resolution.y); } // Window title uf::String title; { @@ -71,26 +54,14 @@ void client::initialize() { // client::window.setPosition({0, 0}); // client::window.setMouseGrabbed(true); - /* Set Icon */ if ( client::config["window"]["icon"].is() ) { + if ( client::config["window"]["icon"].is() ) { uf::Image icon; icon.open(client::config["window"]["icon"].as()); client::window.setIcon({(int) icon.getDimensions().x, (int) icon.getDimensions().y}, ((uint8_t*)icon.getPixelsPtr())); } - client::window.setTitle(title); { - uf::Serializer json; - std::string hook = "window:Title.Changed"; - json["type"] = hook; - json["invoker"] = "os"; - json["window"]["title"] = std::string(title); - uf::hooks.call( hook, json ); - } - #endif - /* - uf::hooks.shouldPreferReadable(); - if ( client::config["engine"]["hook"]["mode"] == "Readable" ) { - } - */ + client::window.setTitle(title); + #endif } #if UF_USE_OPENAL @@ -104,105 +75,53 @@ void client::initialize() { #endif /* Initialize hooks */ { - // if ( client::config["engine"]["hook"]["mode"] == "Both" || client::config["engine"]["hook"]["mode"] == "Readable" ) { - uf::hooks.addHook( "window:Mouse.CursorVisibility", [&](const ext::json::Value& json){ - client::window.setCursorVisible(json["state"].as()); - client::window.setMouseGrabbed(!json["state"].as()); - client::config["mouse"]["visible"] = json["state"].as(); - client::config["window"]["mouse"]["center"] = !json["state"].as(); - }); - uf::hooks.addHook( "window:Mouse.Lock", [&](const ext::json::Value& json){ - if ( client::window.hasFocus() ) { - client::window.setMousePosition(client::window.getSize()/2); - } - }); - uf::hooks.addHook( "window:Closed", [&](const ext::json::Value& json){ - client::ready = false; - // std::exit(EXIT_SUCCESS); - } ); - uf::hooks.addHook( "window:Title.Changed", [&](const ext::json::Value& json){ - if ( json["invoker"] != "os" ) { - if ( !ext::json::isObject( json["window"] ) ) return; - uf::String title = json["window"]["title"].as(); - client::window.setTitle(title); - } - } ); - uf::hooks.addHook( "window:Resized", [&](const ext::json::Value& json){ - pod::Vector2i size; { - size.x = json["window"]["size"]["x"].as(); - size.y = json["window"]["size"]["y"].as(); - } - if ( json["invoker"] != "os" ) { - client::window.setSize(size); - } - // Update viewport - if ( !ext::json::isArray( client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"] ) ) { - float scale = client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].is() ? client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].as() : 1; - uf::renderer::settings::width = size.x * scale; - uf::renderer::settings::height = size.y * scale; - } + uf::hooks.addHook( "window:Mouse.CursorVisibility", [&](const ext::json::Value& json){ + client::window.setCursorVisible(json["state"].as()); + client::window.setMouseGrabbed(!json["state"].as()); + client::config["mouse"]["visible"] = json["state"].as(); + client::config["window"]["mouse"]["center"] = !json["state"].as(); + }); + uf::hooks.addHook( "window:Mouse.Lock", [&](const ext::json::Value& json){ + if ( client::window.hasFocus() ) { + client::window.setMousePosition(client::window.getSize()/2); + } + }); + uf::hooks.addHook( "window:Closed", [&](const ext::json::Value& json){ + client::ready = false; + } ); + uf::hooks.addHook( "window:Title.Changed", [&](const ext::json::Value& json){ + if ( json["invoker"] != "os" ) { + if ( !ext::json::isObject( json["window"] ) ) return; + uf::String title = json["window"]["title"].as(); + client::window.setTitle(title); + } + } ); + uf::hooks.addHook( "window:Resized", [&](const ext::json::Value& json){ + pod::Vector2i size = uf::vector::decode( json["window"]["size"], pod::Vector2i{} ); + if ( json["invoker"] != "os" ) client::window.setSize(size); + // Update viewport + if ( !ext::json::isArray( client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"] ) ) { + float scale = client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].is() ? client::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].as() : 1; + uf::renderer::settings::width = size.x * scale; + uf::renderer::settings::height = size.y * scale; + } - uf::renderer::states::resized = true; - } ); - /* - } - else if ( client::config["engine"]["hook"]["mode"] == "Both" || client::config["engine"]["hook"]["mode"] == "Optimal" ) { - uf::hooks.addHook( "window:Closed", [&](const uf::OptimalHook::argument_t& userdata)->uf::OptimalHook::return_t{ - client::ready = false; - std::exit(EXIT_SUCCESS); - return NULL; - } ); - uf::hooks.addHook( "window:Title.Changed", [&](const uf::OptimalHook::argument_t& userdata)->uf::OptimalHook::return_t{ - // Hook information - struct Hook { - std::string type; - std::string invoker; - - struct { - std::string title; - } window; - }; - const Hook& hook = uf::userdata::get(userdata); - if ( hook.invoker != "os" ) { - uf::String title = hook.window.title; - client::window.setTitle(title); - } - return NULL; - } ); - uf::hooks.addHook( "window:Resized", [&](const uf::OptimalHook::argument_t& userdata)->uf::OptimalHook::return_t{ - // Hook information - struct Hook { - std::string type; - std::string invoker; - - struct { - pod::Vector2i size; - } window; - }; - const Hook& hook = uf::userdata::get(userdata); - if ( hook.invoker != "os" ) { - client::window.setSize(hook.window.size); - } - // Update viewport - return NULL; - } ); - } - */ + uf::renderer::states::resized = true; + } ); } #if !UF_ENV_DREAMCAST if ( client::config["window"]["mode"].as() == "fullscreen" ) client::window.switchToFullscreen(); if ( client::config["window"]["mode"].as() == "borderless" ) client::window.switchToFullscreen( true ); #endif + client::ready = true; #if UF_ENV_DREAMCAST client::window.pollEvents(); #endif } void client::tick() { -// uf::hooks.call("system:Tick"); client::window.pollEvents(); - // call mouse move - // query lock + if ( client::window.hasFocus() && client::config["window"]["mouse"]["center"].as() ) { auto previous = client::window.getMousePosition(); client::window.setMousePosition(client::window.getSize()/2); @@ -211,41 +130,13 @@ void client::tick() { auto size = client::window.getSize(); uf::Serializer payload; payload["invoker"] = "client"; - payload["mouse"]["delta"]["x"] = previous.x - current.x; - payload["mouse"]["delta"]["y"] = previous.y - current.y; - payload["mouse"]["position"]["x"] = current.x; - payload["mouse"]["position"]["y"] = current.y; - payload["mouse"]["size"]["x"] = size.x; - payload["mouse"]["size"]["y"] = size.y; + payload["mouse"]["delta"] = uf::vector::encode( previous - current ); + payload["mouse"]["position"] = uf::vector::encode( current ); + payload["mouse"]["size"] = uf::vector::encode( size ); payload["mouse"]["state"] = "???"; payload["type"] = "window:Mouse.Moved"; uf::hooks.call("window:Mouse.Moved", payload); } -/* -{ - "invoker" : "os", - "mouse" : - { - "delta" : - { - "x" : -17, - "y" : -12 - }, - "position" : - { - "x" : 371, - "y" : 276 - }, - "size" : - { - "x" : 800, - "y" : 600 - }, - "state" : "???" - }, - "type" : "window:Mouse.Moved" -} -*/ } void client::render() { diff --git a/client/main.cpp b/client/main.cpp index d4841cbc..d9d86b16 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -47,8 +47,9 @@ int main(int argc, char** argv){ json["type"] = hook; json["invoker"] = "ext"; - json["window"]["size"]["x"] = client::config["window"]["size"]["x"]; - json["window"]["size"]["y"] = client::config["window"]["size"]["y"]; + json["window"]["size"] = client::config["window"]["size"]; + // json["window"]["size"]["x"] = client::config["window"]["size"]["x"]; + // json["window"]["size"]["y"] = client::config["window"]["size"]["y"]; uf::hooks.call(hook, json); } #if UF_ENV_DREAMCAST diff --git a/engine/inc/uf/ext/gltf/pod.h b/engine/inc/uf/ext/gltf/pod.h index e6a572ea..bd8bbf72 100644 --- a/engine/inc/uf/ext/gltf/pod.h +++ b/engine/inc/uf/ext/gltf/pod.h @@ -14,6 +14,7 @@ namespace pod { std::vector uv; std::vector normal; std::vector radiance; + std::vector depth; pod::Matrix4f matrix; float cascadePower = 2.0; diff --git a/engine/inc/uf/ext/vulkan/buffer.h b/engine/inc/uf/ext/vulkan/buffer.h index bfcd8d58..74e28826 100644 --- a/engine/inc/uf/ext/vulkan/buffer.h +++ b/engine/inc/uf/ext/vulkan/buffer.h @@ -56,6 +56,8 @@ namespace ext { ~Buffer(); void initialize( VkDevice device ); void destroy(); + + void aliasBuffer( const Buffer& ); }; struct UF_API Buffers { std::vector buffers; diff --git a/engine/inc/uf/ext/vulkan/graphic.h b/engine/inc/uf/ext/vulkan/graphic.h index e338b8b3..fff21156 100644 --- a/engine/inc/uf/ext/vulkan/graphic.h +++ b/engine/inc/uf/ext/vulkan/graphic.h @@ -4,60 +4,13 @@ #include #include #include +#include #include #include -#define UF_GRAPHIC_POINTERED_USERDATA 1 - namespace ext { namespace vulkan { - #if UF_GRAPHIC_POINTERED_USERDATA - typedef uf::PointeredUserdata userdata_t; - #else - typedef uf::Userdata userdata_t; - #endif - - ext::json::Value definitionToJson(/*const*/ ext::json::Value& definition ); - ext::vulkan::userdata_t jsonToUserdata( const ext::json::Value& payload, const ext::json::Value& definition ); - struct Graphic; - struct UF_API Shader : public Buffers { - bool aliased = false; - - Device* device = NULL; - std::string filename = ""; - - VkShaderModule module = VK_NULL_HANDLE; - VkPipelineShaderStageCreateInfo descriptor; - std::vector descriptorSetLayoutBindings; - std::vector specializationMapEntries; - VkSpecializationInfo specializationInfo; - - uf::Serializer metadata; - - ext::vulkan::userdata_t specializationConstants; - std::vector pushConstants; - std::vector uniforms; - // ~Shader(); - void initialize( Device& device, const std::string&, VkShaderStageFlagBits ); - void destroy(); - bool validate(); - - bool hasUniform( const std::string& name ); - - Buffer* getUniformBuffer( const std::string& name ); - ext::vulkan::userdata_t& getUniform( const std::string& name ); - uf::Serializer getUniformJson( const std::string& name, bool cache = true ); - ext::vulkan::userdata_t getUniformUserdata( const std::string& name, const ext::json::Value& payload ); - bool updateUniform( const std::string& name ); - bool updateUniform( const std::string& name, const ext::vulkan::userdata_t& ); - bool updateUniform( const std::string& name, const ext::json::Value& payload ); - - bool hasStorage( const std::string& name ); - Buffer* getStorageBuffer( const std::string& name ); - uf::Serializer getStorageJson( const std::string& name, bool cache = true ); - ext::vulkan::userdata_t getStorageUserdata( const std::string& name, const ext::json::Value& payload ); - }; struct UF_API Pipeline { bool aliased = false; diff --git a/engine/inc/uf/ext/vulkan/shader.h b/engine/inc/uf/ext/vulkan/shader.h new file mode 100644 index 00000000..8c60e7a8 --- /dev/null +++ b/engine/inc/uf/ext/vulkan/shader.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#define UF_GRAPHIC_POINTERED_USERDATA 1 + +namespace ext { + namespace vulkan { + #if UF_GRAPHIC_POINTERED_USERDATA + typedef uf::PointeredUserdata userdata_t; + #else + typedef uf::Userdata userdata_t; + #endif + + ext::json::Value definitionToJson(/*const*/ ext::json::Value& definition ); + ext::vulkan::userdata_t jsonToUserdata( const ext::json::Value& payload, const ext::json::Value& definition ); + + struct UF_API Shader : public Buffers { + bool aliased = false; + + Device* device = NULL; + std::string filename = ""; + + VkShaderModule module = VK_NULL_HANDLE; + VkPipelineShaderStageCreateInfo descriptor; + std::vector descriptorSetLayoutBindings; + std::vector specializationMapEntries; + VkSpecializationInfo specializationInfo; + + uf::Serializer metadata; + + ext::vulkan::userdata_t specializationConstants; + std::vector pushConstants; + std::vector uniforms; + // ~Shader(); + void initialize( Device& device, const std::string&, VkShaderStageFlagBits ); + void destroy(); + bool validate(); + + bool hasUniform( const std::string& name ); + + Buffer* getUniformBuffer( const std::string& name ); + ext::vulkan::userdata_t& getUniform( const std::string& name ); + uf::Serializer getUniformJson( const std::string& name, bool cache = true ); + ext::vulkan::userdata_t getUniformUserdata( const std::string& name, const ext::json::Value& payload ); + bool updateUniform( const std::string& name ); + bool updateUniform( const std::string& name, const ext::vulkan::userdata_t& ); + bool updateUniform( const std::string& name, const ext::json::Value& payload ); + + bool hasStorage( const std::string& name ); + Buffer* getStorageBuffer( const std::string& name ); + uf::Serializer getStorageJson( const std::string& name, bool cache = true ); + ext::vulkan::userdata_t getStorageUserdata( const std::string& name, const ext::json::Value& payload ); + }; + } +} \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/texture.h b/engine/inc/uf/ext/vulkan/texture.h index 383a3bac..c9c79e6c 100644 --- a/engine/inc/uf/ext/vulkan/texture.h +++ b/engine/inc/uf/ext/vulkan/texture.h @@ -11,7 +11,7 @@ namespace ext { Device* device = NULL; VkSampler sampler; - struct { + struct Descriptor { struct { VkFilter min = VK_FILTER_LINEAR; VkFilter mag = VK_FILTER_LINEAR; @@ -38,7 +38,11 @@ namespace ext { void initialize( Device& device ); void destroy(); + + static std::vector samplers; + static ext::vulkan::Sampler retrieve( const Descriptor& info ); }; + struct UF_API Texture { Device* device = nullptr; diff --git a/engine/inc/uf/utils/io/file.h b/engine/inc/uf/utils/io/file.h index a95a297b..5f53686a 100644 --- a/engine/inc/uf/utils/io/file.h +++ b/engine/inc/uf/utils/io/file.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace uf { namespace io { @@ -15,8 +16,19 @@ namespace uf { std::string UF_API extension( const std::string&, int32_t ); std::string UF_API directory( const std::string& ); std::string UF_API sanitize( const std::string&, const std::string& = "" ); + std::string UF_API readAsString( const std::string&, const std::string& = "" ); std::vector UF_API readAsBuffer( const std::string&, const std::string& = "" ); + + size_t UF_API write( const std::string& filename, const void*, size_t = SIZE_MAX ); + + template inline size_t write( const std::string& filename, const std::vector& buffer, size_t size = SIZE_MAX ) { + return write( filename, buffer.data(), std::min( buffer.size(), size ) ); + } + inline size_t write( const std::string& filename, const std::string& string, size_t size = SIZE_MAX ) { + return write( filename, string.c_str(), std::min( string.size(), size ) ); + } + std::string UF_API hash( const std::string& ); bool UF_API exists( const std::string& ); size_t UF_API mtime( const std::string& ); diff --git a/engine/inc/uf/utils/io/file.inl b/engine/inc/uf/utils/io/file.inl new file mode 100644 index 00000000..e69de29b diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index bff1125f..9c689d3a 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -25,7 +25,6 @@ namespace { uf::iostream << "HTTP Error " << http.code << " on GET " << url << "\n"; return false; } - std::ofstream output; std::string actual = hash; if ( hash != "" && (actual = uf::string::sha256(url)) != hash ) { @@ -33,9 +32,7 @@ namespace { return false; } - output.open("./" + filename, std::ios::binary); - output.write( http.response.c_str(), http.response.size() ); - output.close(); + uf::io::write( "./" + filename, http.response ); return true; } std::string hashed( const std::string& uri ) { @@ -103,7 +100,7 @@ std::string uf::Asset::cache( const std::string& uri, const std::string& hash, c std::string extension = uf::io::extension( uri ); if ( uri.substr(0,5) == "https" ) { std::string hash = hashed( uri ); - std::string cached = uf::io::root + "/cache/" + hash + "." + extension; + std::string cached = uf::io::root + "/cache/http/" + hash + "." + extension; if ( !uf::io::exists( cached ) && !retrieve( uri, cached, hash ) ) { uf::iostream << "Failed to preload `" + uri + "` (`" + cached + "`): HTTP error" << "\n"; return ""; @@ -126,7 +123,7 @@ std::string uf::Asset::load( const std::string& uri, const std::string& hash, co std::string extension = uf::io::extension( uri ); if ( uri.substr(0,5) == "https" ) { std::string hash = hashed( uri ); - std::string cached = uf::io::root + "/cache/" + hash + "." + extension; + std::string cached = uf::io::root + "/cache/http/" + hash + "." + extension; if ( !uf::io::exists( cached ) && !retrieve( uri, cached, hash ) ) { uf::iostream << "Failed to load `" + uri + "` (`" + cached + "`): HTTP error" << "\n"; return ""; diff --git a/engine/src/ext/bullet/bullet.cpp b/engine/src/ext/bullet/bullet.cpp index 660833f4..b8923f75 100644 --- a/engine/src/ext/bullet/bullet.cpp +++ b/engine/src/ext/bullet/bullet.cpp @@ -386,7 +386,7 @@ void UF_API ext::bullet::debugDraw( uf::Object& object ) { graphic.descriptor.cullMode = uf::renderer::enums::CullMode::NONE; graphic.material.attachShader(uf::io::root + "/shaders/base/colored.vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader(uf::io::root + "/shaders/base/frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root + "/shaders/base/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); graphic.initialize(); graphic.initializeMesh( mesh, 0 ); diff --git a/engine/src/ext/gltf/graph.cpp b/engine/src/ext/gltf/graph.cpp index 0500ceac..00be4e2b 100644 --- a/engine/src/ext/gltf/graph.cpp +++ b/engine/src/ext/gltf/graph.cpp @@ -98,7 +98,7 @@ namespace { }; auto& specializationConstants = shader.specializationConstants.get(); specializationConstants.textures = texture2Ds; - specializationConstants.cascades = texture3Ds / 4; + specializationConstants.cascades = texture3Ds / 4; // 5; ext::json::forEach( shader.metadata["specializationConstants"], [&]( ext::json::Value& sc ){ std::string name = sc["name"].as(); if ( name == "TEXTURES" ) sc["value"] = specializationConstants.textures; @@ -114,6 +114,7 @@ namespace { else if ( name == "voxelUv" ) layout.descriptorCount = specializationConstants.cascades; else if ( name == "voxelNormal" ) layout.descriptorCount = specializationConstants.cascades; else if ( name == "voxelRadiance" ) layout.descriptorCount = specializationConstants.cascades; + // else if ( name == "voxelDepth" ) layout.descriptorCount = specializationConstants.cascades; } }); } @@ -154,6 +155,7 @@ namespace { for ( auto& t : sceneTextures.voxels.uv ) graphic.material.textures.emplace_back().aliasTexture(t); for ( auto& t : sceneTextures.voxels.normal ) graphic.material.textures.emplace_back().aliasTexture(t); for ( auto& t : sceneTextures.voxels.radiance ) graphic.material.textures.emplace_back().aliasTexture(t); + // for ( auto& t : sceneTextures.voxels.depth ) graphic.material.textures.emplace_back().aliasTexture(t); } } if ( graph.metadata["flags"]["LOAD"].as() ) { diff --git a/engine/src/ext/ultralight/ultralight.cpp b/engine/src/ext/ultralight/ultralight.cpp index 632dab47..46421539 100644 --- a/engine/src/ext/ultralight/ultralight.cpp +++ b/engine/src/ext/ultralight/ultralight.cpp @@ -143,9 +143,10 @@ namespace UL { else if ( s == "Middle" ) button = ULMouseButton::kMouseButton_Middle; else if ( s == "Right" ) button = ULMouseButton::kMouseButton_Right; } - int x = event["mouse"]["position"]["x"].as() / ext::ultralight::scale; - int y = event["mouse"]["position"]["y"].as() / ext::ultralight::scale; - handle = ulCreateMouseEvent( type, x, y, button ); + auto mouse = uf::vector::decode( event["mouse"]["position"], pod::Vector2i{} ) / ext::ultralight::scale; + // int x = event["mouse"]["position"]["x"].as() / ext::ultralight::scale; + // int y = event["mouse"]["position"]["y"].as() / ext::ultralight::scale; + handle = ulCreateMouseEvent( type, mouse.x, mouse.y, button ); } ~MouseEvent() { if ( !handle ) return; diff --git a/engine/src/ext/vulkan/buffer.cpp b/engine/src/ext/vulkan/buffer.cpp index bd439d20..9b5a5e51 100644 --- a/engine/src/ext/vulkan/buffer.cpp +++ b/engine/src/ext/vulkan/buffer.cpp @@ -6,16 +6,26 @@ #include #include +void ext::vulkan::Buffer::aliasBuffer( const ext::vulkan::Buffer& buffer ) { + this->buffer = buffer.buffer; + this->memory = buffer.memory; + this->descriptor = buffer.descriptor; + this->size = buffer.size; + this->alignment = buffer.alignment; + this->mapped = buffer.mapped; + this->usage = buffer.usage; + this->memoryProperties = buffer.memoryProperties; + this->memAlloc = buffer.memAlloc; + this->memReqs = buffer.memReqs; + this->allocation = buffer.allocation; + this->allocationInfo = buffer.allocationInfo; +} + VkResult ext::vulkan::Buffer::map( VkDeviceSize size, VkDeviceSize offset ) { // return vkMapMemory( device, memory, offset, size, 0, &mapped ); return vmaMapMemory( allocator, allocation, &mapped ); } -/** -* Unmap a mapped memory range -* -* @note Does not return a result as vkUnmapMemory can't fail -*/ void ext::vulkan::Buffer::unmap() { if ( !mapped ) return; // vkUnmapMemory( device, memory ); @@ -23,54 +33,23 @@ void ext::vulkan::Buffer::unmap() { mapped = nullptr; } -/** -* Attach the allocated memory block to the buffer -* -* @param offset (Optional) Byte offset (from the beginning) for the memory region to bind -* -* @return VkResult of the bindBufferMemory call -*/ VkResult ext::vulkan::Buffer::bind( VkDeviceSize offset ) { // return vkBindBufferMemory( device, buffer, memory, offset ); // return vmaBindBufferMemory( allocator, allocation, buffer ); return VK_SUCCESS; } -/** -* Setup the default descriptor for this buffer -* -* @param size (Optional) Size of the memory range of the descriptor -* @param offset (Optional) Byte offset from beginning -* -*/ void ext::vulkan::Buffer::setupDescriptor( VkDeviceSize size, VkDeviceSize offset ) { descriptor.offset = offset; descriptor.buffer = buffer; descriptor.range = size; } -/** -* Copies the specified data to the mapped buffer -* -* @param data Pointer to the data to copy -* @param size Size of the data to copy in machine units -* -*/ void ext::vulkan::Buffer::copyTo( void* data, VkDeviceSize size ) { assert(mapped); memcpy(mapped, data, size); } -/** -* Flush a memory range of the buffer to make it visible to the device -* -* @note Only required for non-coherent memory -* -* @param size (Optional) Size of the memory range to flush. Pass VK_WHOLE_SIZE to flush the complete buffer range. -* @param offset (Optional) Byte offset from beginning -* -* @return VkResult of the flush call -*/ VkResult ext::vulkan::Buffer::flush( VkDeviceSize size, VkDeviceSize offset ) { /* VkMappedMemoryRange mappedRange = {}; @@ -83,16 +62,6 @@ VkResult ext::vulkan::Buffer::flush( VkDeviceSize size, VkDeviceSize offset ) { return VK_SUCCESS; } -/** -* Invalidate a memory range of the buffer to make it visible to the host -* -* @note Only required for non-coherent memory -* -* @param size (Optional) Size of the memory range to invalidate. Pass VK_WHOLE_SIZE to invalidate the complete buffer range. -* @param offset (Optional) Byte offset from beginning -* -* @return VkResult of the invalidate call -*/ VkResult ext::vulkan::Buffer::invalidate( VkDeviceSize size, VkDeviceSize offset ) { /* VkMappedMemoryRange mappedRange = {}; @@ -130,6 +99,8 @@ void ext::vulkan::Buffer::initialize( VkDevice device ) { this->device = device; } void ext::vulkan::Buffer::destroy() { + if ( !device ) return; + if ( buffer ) { vmaDestroyBuffer( allocator, buffer, allocation ); // vkDestroyBuffer(device, buffer, nullptr); @@ -155,7 +126,9 @@ ext::vulkan::Buffers::~Buffers() { } */ void ext::vulkan::Buffers::destroy() { - for ( auto& buffer : buffers ) buffer.destroy(); + for ( auto& buffer : buffers ) { + if ( buffer.device ) buffer.destroy(); + } buffers.clear(); } diff --git a/engine/src/ext/vulkan/device.cpp b/engine/src/ext/vulkan/device.cpp index eb522794..cc3e3bb6 100644 --- a/engine/src/ext/vulkan/device.cpp +++ b/engine/src/ext/vulkan/device.cpp @@ -253,7 +253,7 @@ uint32_t ext::vulkan::Device::getMemoryType( uint32_t typeBits, VkMemoryProperty *memTypeFound = false; return 0; } - // UF_EXCEPTION("Could not find a matching memory type"); + UF_EXCEPTION("Could not find a matching memory type"); } int ext::vulkan::Device::rate( VkPhysicalDevice device ) { @@ -728,7 +728,7 @@ void ext::vulkan::Device::initialize() { queueInfo.pQueuePriorities = &defaultQueuePriority; queueCreateInfos.push_back(queueInfo); } else { - queueFamilyIndices.graphics = VK_NULL_HANDLE; + queueFamilyIndices.graphics = NULL; // VK_NULL_HANDLE; } // Dedicated compute queue if ( requestedQueueTypes & VK_QUEUE_COMPUTE_BIT ) { @@ -782,16 +782,31 @@ void ext::vulkan::Device::initialize() { deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data(); } - if ( vkCreateDevice( this->physicalDevice, &deviceCreateInfo, nullptr, &this->logicalDevice) != VK_SUCCESS ) + VkPhysicalDeviceFeatures2 physicalDeviceFeatures2{}; + VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures{}; + { + deviceCreateInfo.pEnabledFeatures = nullptr; + deviceCreateInfo.pNext = &physicalDeviceFeatures2; + } + { + physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + physicalDeviceFeatures2.features = enabledFeatures; + physicalDeviceFeatures2.pNext = &descriptorIndexingFeatures; + } + { + descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; + descriptorIndexingFeatures.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; + descriptorIndexingFeatures.shaderStorageImageArrayNonUniformIndexing = VK_TRUE; + descriptorIndexingFeatures.runtimeDescriptorArray = VK_TRUE; + descriptorIndexingFeatures.descriptorBindingVariableDescriptorCount = VK_TRUE; + } + + if ( vkCreateDevice( this->physicalDevice, &deviceCreateInfo, nullptr, &this->logicalDevice) != VK_SUCCESS ) { UF_EXCEPTION("failed to create logical device!"); - - - + } { uf::Serializer payload = ext::json::array(); - for ( auto* c_str : deviceExtensions ) { - payload.emplace_back( std::string(c_str) ); - } + for ( auto* c_str : deviceExtensions ) payload.emplace_back( std::string(c_str) ); uf::hooks.call("vulkan:Device.ExtensionsEnabled", payload); } { @@ -911,6 +926,15 @@ void ext::vulkan::Device::initialize() { { VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {}; pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + + std::vector buffer; + // read from cache on disk + if ( uf::io::exists( uf::io::root + "/cache/vulkan/cache.bin" ) ) { + buffer = uf::io::readAsBuffer( uf::io::root + "/cache/vulkan/cache.bin" ); + pipelineCacheCreateInfo.initialDataSize = buffer.size(); + pipelineCacheCreateInfo.pInitialData = buffer.data(); + } + VK_CHECK_RESULT(vkCreatePipelineCache( device, &pipelineCacheCreateInfo, nullptr, &this->pipelineCache)); } // setup allocator @@ -926,6 +950,17 @@ void ext::vulkan::Device::initialize() { void ext::vulkan::Device::destroy() { if ( this->pipelineCache ) { + // write cache on disk + { + size_t size{}; + VK_CHECK_RESULT(vkGetPipelineCacheData(this->logicalDevice, this->pipelineCache, &size, NULL)); + + std::vector data(size); + VK_CHECK_RESULT(vkGetPipelineCacheData(this->logicalDevice, this->pipelineCache, &size, data.data())); + + uf::io::write( uf::io::root + "/cache/vulkan/cache.bin", data ); + } + vkDestroyPipelineCache( this->logicalDevice, this->pipelineCache, nullptr ); this->pipelineCache = nullptr; } diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 092e439d..24055f23 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -17,787 +17,13 @@ namespace { uint32_t VERTEX_BUFFER_BIND_ID = 0; } -ext::json::Value ext::vulkan::definitionToJson(/*const*/ ext::json::Value& definition ) { - ext::json::Value member; - // is object - if ( !ext::json::isNull(definition["members"]) ) { - ext::json::forEach(definition["members"], [&](/*const*/ ext::json::Value& value){ - std::string key = uf::string::split(value["name"].as(), " ").back(); - member[key] = ext::vulkan::definitionToJson(value); - }); - // is primitive - } else if ( !ext::json::isNull(definition["value"]) ) { - // is array of structs - if ( definition["struct"].as() ) { - ext::json::forEach(definition["value"], [&](/*const*/ ext::json::Value& value){ - ext::json::Value parsed; - parsed["name"] = definition["name"]; - parsed["size"] = definition["size"]; - parsed["struct"] = definition["struct"]; - parsed["members"] = value; - parsed = ext::vulkan::definitionToJson(parsed); - member.emplace_back(parsed); - }); - } else { - member = definition["value"]; - } - } - return member; -} -ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& payload, const ext::json::Value& definition ) { - size_t bufferLen = definition["size"].as(); - - ext::vulkan::userdata_t userdata; - userdata.create(bufferLen); - - uint8_t* byteBuffer = (uint8_t*) (void*) userdata; - uint8_t* byteBufferStart = byteBuffer; - uint8_t* byteBufferEnd = byteBuffer + bufferLen; - -#if UF_JSON_NLOHMANN_ORDERED - // JSON is ordered, we can just push directly -#define UF_SHADER_TRACK_NAMES 0 -#if UF_SHADER_TRACK_NAMES - std::vector variableName; -#endif - std::function parse = [&]( const ext::json::Value& value ){ - // is array or object - #if UF_SHADER_TRACK_NAMES - if ( ext::json::isObject(value) ) { - ext::json::forEach(value, [&]( const std::string& name, const ext::json::Value& member ){ - #if UF_SHADER_TRACK_NAMES - variableName.emplace_back(name); - #endif - parse(member); - }); - #if UF_SHADER_TRACK_NAMES - if ( !variableName.empty() ) variableName.pop_back(); - #endif - return; - } - if ( ext::json::isArray(value) ) { - ext::json::forEach(value, [&]( size_t i, const ext::json::Value& element ){ - variableName.emplace_back("["+std::to_string(i)+"]"); - parse(element); - }); - #if UF_SHADER_TRACK_NAMES - if ( !variableName.empty() ) variableName.pop_back(); - #endif - return; - } - #else - if ( ext::json::isArray(value) || ext::json::isObject(value) ) { - ext::json::forEach(value, parse); - return; - } - #endif - #if UF_SHADER_TRACK_NAMES - std::string path = uf::string::join(variableName, "."); - path = uf::string::replace( path, ".[", "[" ); - VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = " << value.dump()); - #endif - // is strictly an int - if ( value.is(true) ) { - size_t size = sizeof(int32_t); - auto get = value.as(); - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - // is strictly an unsigned int - } else if ( value.is(true) ) { - size_t size = sizeof(uint32_t); - auto get = value.as(); - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - // is strictly a float - } else if ( value.is(true) ) { - size_t size = sizeof(float); - auto get = value.as(); - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } - #if UF_SHADER_TRACK_NAMES - if ( !variableName.empty() ) variableName.pop_back(); - #endif - }; -#if UF_SHADER_TRACK_NAMES - VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename); - VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); -#endif - parse(payload); -#if UF_SHADER_TRACK_NAMES - VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); -#endif -#else - auto pushValue = [&]( const std::string& primitive, const ext::json::Value& input ){ - if ( primitive == "bool" ) { - size_t size = sizeof(bool); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - auto get = input.as(); - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "int8_t" ) { - size_t size = sizeof(int8_t); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - - // auto get = input.as(); - // memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "uint8_t" ) { - size_t size = sizeof(uint8_t); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - // auto get = input.as(); - // memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "int16_t" ) { - size_t size = sizeof(int16_t); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - // auto get = input.as(); - // memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "uint16_t" ) { - size_t size = sizeof(uint16_t); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - // auto get = input.as(); - // memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "int32_t" ) { - size_t size = sizeof(int32_t); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - auto get = input.as(); - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } - else if ( primitive == "uint32_t" ) { - size_t size = sizeof(uint32_t); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - auto get = input.as(); - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "int64_t" ) { - size_t size = sizeof(int64_t); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - auto get = input.as(); - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "uint64_t" ) { - size_t size = sizeof(uint64_t); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - auto get = input.as(); - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "half" ) { - size_t size = sizeof(float); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - // auto get = input.as(); - // memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "float" ) { - size_t size = sizeof(float); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - auto get = input.as(); - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } else if ( primitive == "double" ) { - auto get = input.as(); - size_t size = sizeof(double); // v["size"].as(); - if ( byteBufferEnd < byteBuffer + size ) return false; // overflow - memcpy( byteBuffer, &get, size ); - byteBuffer += size; - } - return true; - }; - #define UF_SHADER_TRACK_NAMES 0 - #if UF_SHADER_TRACK_NAMES - bool SKIP_ADD = false; - std::vector variableName; - #endif - std::function parseDefinition = [&](const ext::json::Value& input, const ext::json::Value& definition ){ - #if UF_SHADER_TRACK_NAMES - if ( SKIP_ADD ) { - SKIP_ADD = false; - } else { - auto split = uf::string::split(definition["name"].as(), " "); - std::string type = split.front(); - std::string name = split.back(); - variableName.emplace_back(name); - } - #endif - // is object - if ( !ext::json::isNull(definition["members"]) ) { - ext::json::forEach(definition["members"], [&](const ext::json::Value& member){ - std::string key = uf::string::split(member["name"].as(), " ").back(); - parseDefinition(input[key], member); - }); - // is array or primitive - } else if ( !ext::json::isNull(definition["value"]) ) { - // is object - auto split = uf::string::split(definition["name"].as(), " "); - std::string type = split.front(); - std::string name = split.back(); - std::regex regex("^(?:(.+?)\\<)?(.+?)(?:\\>)?(?:\\[(\\d+)\\])?$"); - std::smatch match; - if ( !std::regex_search( type, match, regex ) ) { - std::cout << "Ill formatted typename: " << definition["name"].as() << std::endl; - return; - } - std::string vectorMatrix = match[1].str(); - std::string primitive = match[2].str(); - std::string arraySize = match[3].str(); - if ( ext::json::isObject(input) ) { - ext::json::Value cloned; - cloned["name"] = definition["name"]; - cloned["size"] = definition["size"].as() / definition["value"].size(); - cloned["members"] = definition["value"][0]; - parseDefinition( input, cloned ); - } - // is array - else if ( ext::json::isArray(input) ) { - ext::json::forEach( input, [&]( size_t i, const ext::json::Value& value){ - #if UF_SHADER_TRACK_NAMES - variableName.emplace_back("["+std::to_string(i)+"]"); - SKIP_ADD = true; - #endif - parseDefinition(input[i], definition); - }); - } - // is primitive - else { - #if UF_SHADER_TRACK_NAMES - std::string path = uf::string::join(variableName, "."); - path = uf::string::replace( path, ".[", "[" ); - VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = (" << primitive << ") " << input.dump()); - #endif - pushValue( primitive, input ); - } - } - #if UF_SHADER_TRACK_NAMES - if ( !variableName.empty() ) variableName.pop_back(); - #endif - }; - auto& definitions = metadata["definitions"]["uniforms"][name]; -#if UF_SHADER_TRACK_NAMES - VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename); - VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); -#endif - parseDefinition(payload, definitions); -#if UF_SHADER_TRACK_NAMES - VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); -#endif -#endif - return userdata; -} -/* -ext::vulkan::Shader::~Shader() { - if ( !aliased ) destroy(); -} -*/ -void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::string& filename, VkShaderStageFlagBits stage ) { - this->device = &device; - ext::vulkan::Buffers::initialize( device ); - aliased = false; - - std::string spirv; - - { - std::ifstream is(this->filename = filename, std::ios::binary | std::ios::in | std::ios::ate); - if ( !is.is_open() ) { - VK_VALIDATION_MESSAGE("Error: Could not open shader file \"" << filename << "\""); - return; - } - is.seekg(0, std::ios::end); spirv.reserve(is.tellg()); is.seekg(0, std::ios::beg); - spirv.assign((std::istreambuf_iterator(is)), std::istreambuf_iterator()); - - assert(spirv.size() > 0); - } - - { - - VkShaderModuleCreateInfo moduleCreateInfo = {}; - moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - moduleCreateInfo.codeSize = spirv.size(); - moduleCreateInfo.pCode = (uint32_t*) spirv.data(); - - VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &module)); - } - - { - descriptor.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - descriptor.stage = stage; - descriptor.module = module; - descriptor.pName = "main"; - - assert(descriptor.module != VK_NULL_HANDLE); - } - // set up metadata - { - metadata["filename"] = filename; - metadata["type"] = ""; - } - // do reflection - { - spirv_cross::Compiler comp( (uint32_t*) &spirv[0], spirv.size() / 4 ); - spirv_cross::ShaderResources res = comp.get_shader_resources(); - - std::function parseMembers = [&]( spirv_cross::TypeID type_id ) { - auto parseMember = [&]( auto type_id ){ - uf::Serializer payload; - - auto type = comp.get_type(type_id); - - std::string name = ""; - size_t size = 1; - ext::json::Value value; - switch ( type.basetype ) { - case spirv_cross::SPIRType::BaseType::Boolean: name = "bool"; size = sizeof(bool); value = (bool) 0; break; - case spirv_cross::SPIRType::BaseType::SByte: name = "int8_t"; size = sizeof(int8_t); value = (int8_t) 0; break; - case spirv_cross::SPIRType::BaseType::UByte: name = "uint8_t"; size = sizeof(uint8_t); value = (uint8_t) 0; break; - case spirv_cross::SPIRType::BaseType::Short: name = "int16_t"; size = sizeof(int16_t); value = (int16_t) 0; break; - case spirv_cross::SPIRType::BaseType::UShort: name = "uint16_t"; size = sizeof(uint16_t); value = (uint16_t) 0; break; - case spirv_cross::SPIRType::BaseType::Int: name = "int32_t"; size = sizeof(int32_t); value = (int32_t) 0; break; - case spirv_cross::SPIRType::BaseType::UInt: name = "uint32_t"; size = sizeof(uint32_t); value = (uint32_t) 0; break; - case spirv_cross::SPIRType::BaseType::Int64: name = "int64_t"; size = sizeof(int64_t); value = (int64_t) 0; break; - case spirv_cross::SPIRType::BaseType::UInt64: name = "uint64_t"; size = sizeof(uint64_t); value = (uint64_t) 0; break; - case spirv_cross::SPIRType::BaseType::Half: name = "half"; size = sizeof(float)/2; value = (float) 0; break; - case spirv_cross::SPIRType::BaseType::Float: name = "float"; size = sizeof(float); value = (float) 0; break; - case spirv_cross::SPIRType::BaseType::Double: name = "double"; size = sizeof(double); value = (double) 0; break; - case spirv_cross::SPIRType::BaseType::Image: name = "image2D"; break; - case spirv_cross::SPIRType::BaseType::SampledImage: name = "sampler2D"; break; - case spirv_cross::SPIRType::BaseType::Sampler: name = "sampler"; break; - default: - name = comp.get_name(type_id); - size = comp.get_declared_struct_size(type); - break; - } - if ( name == "" ) name = comp.get_name(type.type_alias); - if ( name == "" ) name = comp.get_name(type.type_alias); - if ( name == "" ) name = comp.get_name(type.parent_type); - if ( name == "" ) name = comp.get_fallback_name(type_id); - if ( type.vecsize > 1 ) { - name = "<"+name+">"; - if ( type.columns > 1 ) { - name = "Matrix"+std::to_string(type.vecsize)+"x"+std::to_string(type.columns)+name; - } else { - name = "Vector"+std::to_string(type.vecsize)+name; - } - } - { - ext::json::Value source = value; - value = ext::json::array(); - for ( size_t i = 0; i < type.vecsize * type.columns; ++i ) { - value.emplace_back(source); - } - size *= type.columns * type.vecsize; - } - for ( auto arraySize : type.array ) { - if ( arraySize > 1 ) { - ext::json::Value source = value; - value = ext::json::array(); - for ( size_t i = 0; i < arraySize; ++i ) { - value.emplace_back(source); - } - name += "[" + std::to_string(arraySize) + "]"; - size *= arraySize; - } - } - if ( ext::json::isArray(value) && value.size() == 1 ) { - value = value[0]; - } - payload["name"] = name; - payload["size"] = size; - payload["value"] = value; - return payload; - }; - uf::Serializer payload = ext::json::array(); - const auto& type = comp.get_type(type_id); - for ( auto& member_type_id : type.member_types ) { - const auto& member_type = comp.get_type(member_type_id); - std::string name = comp.get_member_name(type.type_alias, payload.size()); - if ( name == "" ) name = comp.get_member_name(type.parent_type, payload.size()); - if ( name == "" ) name = comp.get_member_name(type_id, payload.size()); - - auto& entry = payload.emplace_back(); - auto parsed = parseMember(member_type_id); - std::string type_name = parsed["name"]; - entry["name"] = type_name + " " + name; - if ( member_type.basetype == spirv_cross::SPIRType::BaseType::Struct ) { - entry["struct"] = true; - auto parsed = parseMembers(member_type_id); - if ( !member_type.array.empty() && member_type.array[0] > 1 ) { - size_t size = comp.get_declared_struct_size(member_type); - for ( auto arraySize : member_type.array ) { - ext::json::Value source = parsed; - parsed = ext::json::array(); - for ( size_t i = 0; i < arraySize; ++i ) { - parsed.emplace_back(source); - } - size = size * arraySize; - } - entry["size"] = size; - entry["value"] = parsed; - } else { - entry["size"] = comp.get_declared_struct_size(member_type); - entry["members"] = parsed; - } - } else { - entry["size"] = parsed["size"]; - entry["value"] = parsed["value"]; - } - } - return payload; - }; - - auto parseResource = [&]( const spirv_cross::Resource& resource, VkDescriptorType descriptorType, size_t index ) { - const auto& type = comp.get_type(resource.type_id); - const auto& base_type = comp.get_type(resource.base_type_id); - std::string name = resource.name; - size_t arraySize = 1; - if ( !type.array.empty() ) { - arraySize = type.array[0]; - } - - switch ( descriptorType ) { - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { - std::string tname = ""; - switch ( type.image.dim ) { - case spv::Dim::Dim1D: tname = "1D"; break; - case spv::Dim::Dim2D: tname = "2D"; break; - case spv::Dim::Dim3D: tname = "3D"; break; - case spv::Dim::DimCube: tname = "Cube"; break; - case spv::Dim::DimRect: tname = "Rect"; break; - case spv::Dim::DimBuffer: tname = "Buffer"; break; - case spv::Dim::DimSubpassData: tname = "SubpassData"; break; - - } - size_t binding = comp.get_decoration(resource.id, spv::DecorationBinding); - std::string key = std::to_string(binding); - metadata["definitions"]["textures"][key]["name"] = name; - metadata["definitions"]["textures"][key]["index"] = index; - metadata["definitions"]["textures"][key]["binding"] = binding; - metadata["definitions"]["textures"][key]["size"] = arraySize; - metadata["definitions"]["textures"][key]["type"] = tname; - } break; - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { - size_t bufferSize = comp.get_declared_struct_size(base_type); - if ( bufferSize <= 0 ) break; - if ( bufferSize > device.properties.limits.maxUniformBufferRange ) { - VK_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer length of " << bufferSize << " for shader " << filename); - bufferSize = device.properties.limits.maxUniformBufferRange; - } - size_t misalignment = bufferSize % device.properties.limits.minStorageBufferOffsetAlignment; - if ( misalignment != 0 ) { - VK_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer alignment of " << misalignment << " for shader " << filename << ", correcting..."); - bufferSize += misalignment; - } - { - VK_DEBUG_VALIDATION_MESSAGE("Uniform size of " << bufferSize << " for shader " << filename); - auto& uniform = uniforms.emplace_back(); - uniform.create( bufferSize ); - } - // generate definition to JSON - { - metadata["definitions"]["uniforms"][name]["name"] = name; - metadata["definitions"]["uniforms"][name]["index"] = index; - metadata["definitions"]["uniforms"][name]["size"] = bufferSize; - metadata["definitions"]["uniforms"][name]["members"] = parseMembers(resource.type_id); - } - } break; - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: { - // generate definition to JSON - { - metadata["definitions"]["storage"][name]["name"] = name; - metadata["definitions"]["storage"][name]["index"] = index; - metadata["definitions"]["storage"][name]["members"] = parseMembers(resource.type_id); - } - // test - { - // updateUniform(name, getUniform(name)); - } - } break; - } - descriptorSetLayoutBindings.push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, comp.get_decoration(resource.id, spv::DecorationBinding), arraySize ) ); - }; - - - //for ( const auto& resource : res.key ) { - #define LOOP_RESOURCES( key, type ) for ( size_t i = 0; i < res.key.size(); ++i ) {\ - const auto& resource = res.key[i];\ - VK_DEBUG_VALIDATION_MESSAGE("["< device.properties.limits.maxPushConstantsSize ) { - VK_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of " << size << " for shader " << filename); - size = device.properties.limits.maxPushConstantsSize; - } - VK_DEBUG_VALIDATION_MESSAGE("Push constant size of " << size << " for shader " << filename); - { - auto& pushConstant = pushConstants.emplace_back(); - pushConstant.create( size ); - } - // generate definition to JSON - { - metadata["definitions"]["pushConstants"][name]["name"] = name; - metadata["definitions"]["pushConstants"][name]["size"] = size; - metadata["definitions"]["pushConstants"][name]["index"] = pushConstants.size() - 1; - metadata["definitions"]["pushConstants"][name]["members"] = parseMembers(resource.type_id); - } - } - - size_t specializationSize = 0; - for ( const auto& constant : comp.get_specialization_constants() ) { - const auto& value = comp.get_constant(constant.id); - const auto& type = comp.get_type(value.constant_type); - size_t size = 4; //comp.get_declared_struct_size(type); - - VkSpecializationMapEntry specializationMapEntry; - specializationMapEntry.constantID = constant.constant_id; - specializationMapEntry.size = size; - specializationMapEntry.offset = specializationSize; - specializationMapEntries.push_back(specializationMapEntry); - specializationSize += size; - } - if ( specializationSize > 0 ) { - specializationConstants.create( specializationSize ); - VK_DEBUG_VALIDATION_MESSAGE("Specialization constants size of " << specializationSize << " for shader " << filename); - - uint8_t* s = (uint8_t*) (void*) specializationConstants; - size_t offset = 0; - - metadata["specializationConstants"] = ext::json::array(); - for ( const auto& constant : comp.get_specialization_constants() ) { - const auto& value = comp.get_constant(constant.id); - const auto& type = comp.get_type(value.constant_type); - std::string name = comp.get_name (constant.id); - - ext::json::Value member; - - size_t size = 4; - uint8_t buffer[size]; - switch ( type.basetype ) { - case spirv_cross::SPIRType::UInt: { - auto v = value.scalar(); - member["type"] = "uint32_t"; - member["value"] = v; - member["validate"] = true; - memcpy( &buffer[0], &v, sizeof(v) ); - } break; - case spirv_cross::SPIRType::Int: { - auto v = value.scalar_i32(); - member["type"] = "int32_t"; - member["value"] = v; - memcpy( &buffer[0], &v, sizeof(v) ); - } break; - case spirv_cross::SPIRType::Float: { - auto v = value.scalar_f32(); - member["type"] = "float"; - member["value"] = v; - memcpy( &buffer[0], &v, sizeof(v) ); - } break; - case spirv_cross::SPIRType::Boolean: { - auto v = value.scalar()!=0; - member["type"] = "bool"; - member["value"] = v; - memcpy( &buffer[0], &v, sizeof(v) ); - } break; - default: { - VK_DEBUG_VALIDATION_MESSAGE("Unregistered specialization constant type at offset " << offset << " for shader " << filename ); - } break; - } - member["name"] = name; - member["size"] = size; - member["default"] = member["value"]; - VK_DEBUG_VALIDATION_MESSAGE("Specialization constant: " << member["type"].as() << " " << name << " = " << member["value"].dump() << "; at offset " << offset << " for shader " << filename ); - metadata["specializationConstants"].emplace_back(member); - - memcpy( &s[offset], &buffer, size ); - offset += size; - } - /* - { - specializationInfo = {}; - specializationInfo.dataSize = specializationSize; - specializationInfo.mapEntryCount = specializationMapEntries.size(); - specializationInfo.pMapEntries = specializationMapEntries.data(); - specializationInfo.pData = (void*) specializationConstants; - descriptor.pSpecializationInfo = &specializationInfo; - } - */ - } - /* - */ - // LOOP_RESOURCES( stage_inputs, VkVertexInputAttributeDescription ); - // LOOP_RESOURCES( stage_outputs, VkPipelineColorBlendAttachmentState ); - } - - // organize layouts - { - std::sort( descriptorSetLayoutBindings.begin(), descriptorSetLayoutBindings.end(), [&]( const VkDescriptorSetLayoutBinding& l, const VkDescriptorSetLayoutBinding& r ){ - return l.binding < r.binding; - } ); - } - - // update uniform buffers - for ( auto& uniform : uniforms ) { - auto& userdata = uniform.data(); - initializeBuffer( - (void*) userdata.data, - userdata.len, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT - ); - } -} - -void ext::vulkan::Shader::destroy() { - if ( aliased ) return; - if ( !device ) return; - - ext::vulkan::Buffers::destroy(); - - if ( module != VK_NULL_HANDLE ) { - vkDestroyShaderModule( *device, module, nullptr ); - module = VK_NULL_HANDLE; - descriptor = {}; - } - for ( auto& userdata : uniforms ) userdata.destroy(); - for ( auto& userdata : pushConstants ) userdata.destroy(); - uniforms.clear(); - pushConstants.clear(); -} - -bool ext::vulkan::Shader::validate() { - // check if uniforms match buffer size - bool valid = true; - { - auto it = uniforms.begin(); - for ( auto& buffer : buffers ) { - if ( !(buffer.usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) ) continue; - if ( it == uniforms.end() ) break; - auto& uniform = *(it++); - if ( uniform.data().len != buffer.allocationInfo.size ) { - VK_DEBUG_VALIDATION_MESSAGE("Uniform size mismatch: Expected " << buffer.allocationInfo.size << ", got " << uniform.data().len << "; fixing..."); - uniform.destroy(); - uniform.create(buffer.allocationInfo.size); - valid = false; - } - } - } - return valid; -} -bool ext::vulkan::Shader::hasUniform( const std::string& name ) { - return !ext::json::isNull(metadata["definitions"]["uniforms"][name]); -} -ext::vulkan::Buffer* ext::vulkan::Shader::getUniformBuffer( const std::string& name ) { - if ( !hasUniform(name) ) return NULL; - size_t uniformIndex = metadata["definitions"]["uniforms"][name]["index"].as(); - for ( size_t bufferIndex = 0, uniformCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { - if ( !(buffers[bufferIndex].usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) ) continue; - if ( uniformCounter++ != uniformIndex ) continue; - return &buffers[bufferIndex]; - } - return NULL; -} -ext::vulkan::userdata_t& ext::vulkan::Shader::getUniform( const std::string& name ) { - if ( !hasUniform(name) ) { - static ext::vulkan::userdata_t null; - return null; - } - auto& definition = metadata["definitions"]["uniforms"][name]; - size_t uniformSize = definition["size"].as(); - size_t uniformIndex = definition["index"].as(); - auto& userdata = uniforms[uniformIndex]; - return userdata; -} -bool ext::vulkan::Shader::updateUniform( const std::string& name ) { - if ( !hasUniform(name) ) return false; - auto& uniform = getUniform(name); - return updateUniform(name, uniform); -} -bool ext::vulkan::Shader::updateUniform( const std::string& name, const ext::vulkan::userdata_t& userdata ) { - if ( !hasUniform(name) ) return false; - auto* bufferObject = getUniformBuffer(name); - if ( !bufferObject ) return false; - size_t size = std::max(metadata["definitions"]["uniforms"][name]["size"].as(), bufferObject->allocationInfo.size); - updateBuffer( (void*) userdata, size, *bufferObject ); - return true; -} - -uf::Serializer ext::vulkan::Shader::getUniformJson( const std::string& name, bool cache ) { - if ( !hasUniform(name) ) return ext::json::null(); - if ( cache && !ext::json::isNull(metadata["uniforms"][name]) ) return metadata["uniforms"][name]; - auto& definition = metadata["definitions"]["uniforms"][name]; - if ( cache ) return metadata["uniforms"][name] = definitionToJson(definition); - return definitionToJson(definition); -} -ext::vulkan::userdata_t ext::vulkan::Shader::getUniformUserdata( const std::string& name, const ext::json::Value& payload ) { - if ( !hasUniform(name) ) return false; - return jsonToUserdata(payload, metadata["definitions"]["uniforms"][name]); -} -bool ext::vulkan::Shader::updateUniform( const std::string& name, const ext::json::Value& payload ) { - if ( !hasUniform(name) ) return false; - - auto* bufferObject = getUniformBuffer(name); - if ( !bufferObject ) return false; - - auto uniform = getUniformUserdata( name, payload ); - updateBuffer( (void*) uniform, uniform.data().len, *bufferObject ); - return true; -} - -bool ext::vulkan::Shader::hasStorage( const std::string& name ) { - return !ext::json::isNull(metadata["definitions"]["storage"][name]); -} - -ext::vulkan::Buffer* ext::vulkan::Shader::getStorageBuffer( const std::string& name ) { - if ( !hasStorage(name) ) return NULL; - size_t storageIndex = metadata["definitions"]["storage"][name]["index"].as(); - for ( size_t bufferIndex = 0, storageCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { - if ( !(buffers[bufferIndex].usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) ) continue; - if ( storageCounter++ != storageIndex ) continue; - return &buffers[bufferIndex]; - } - return NULL; -} -uf::Serializer ext::vulkan::Shader::getStorageJson( const std::string& name, bool cache ) { - if ( !hasStorage(name) ) return ext::json::null(); - if ( cache && !ext::json::isNull(metadata["storage"][name]) ) return metadata["storage"][name]; - auto& definition = metadata["definitions"]["storage"][name]; - if ( cache ) return metadata["storage"][name] = definitionToJson(definition); - return definitionToJson(definition); -} -ext::vulkan::userdata_t ext::vulkan::Shader::getStorageUserdata( const std::string& name, const ext::json::Value& payload ) { - if ( !hasStorage(name) ) return false; - return jsonToUserdata(payload, metadata["definitions"]["storage"][name]); -} void ext::vulkan::Pipeline::initialize( Graphic& graphic ) { return this->initialize( graphic, graphic.descriptor ); } void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& descriptor ) { this->device = graphic.device; - //this->descriptor = descriptor; + this->descriptor = descriptor; Device& device = *graphic.device; metadata["name"] = descriptor.pipeline; @@ -1123,11 +349,14 @@ void ext::vulkan::Pipeline::record( Graphic& graphic, VkCommandBuffer commandBuf vkCmdBindPipeline(commandBuffer, bindPoint, pipeline); } void ext::vulkan::Pipeline::update( Graphic& graphic ) { - return this->update( graphic, graphic.descriptor ); +// return this->update( graphic, graphic.descriptor ); + return this->update( graphic, descriptor ); } void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descriptor ) { // if ( descriptorSet == VK_NULL_HANDLE ) return; + this->descriptor = descriptor; + //descriptor = d; RenderMode& renderMode = ext::vulkan::getRenderMode(descriptor.renderMode, true); auto& renderTarget = renderMode.getRenderTarget(descriptor.renderTarget ); diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 2205c4c9..38442675 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -42,11 +42,11 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { ext::vulkan::RenderMode::initialize( device ); renderTarget.device = &device; size_t eyes = metadata["eyes"].as(); + size_t msaa = ext::vulkan::settings::msaa; for ( size_t eye = 0; eye < eyes; ++eye ) { struct { size_t id, normals, uvs, albedo, depth, output, debug; } attachments; - size_t msaa = ext::vulkan::settings::msaa; attachments.id = renderTarget.attach(RenderTarget::Attachment::Descriptor{ /*.format = */VK_FORMAT_R16G16_UINT, @@ -122,7 +122,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { }); } metadata["outputs"].emplace_back(attachments.output); - + #if 0 attachments.debug = renderTarget.attach(RenderTarget::Attachment::Descriptor{ /*.format = */VK_FORMAT_R16G16B16A16_SFLOAT, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, @@ -130,6 +130,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.blend = */false, /*.samples = */1, }); + #endif if ( ext::vulkan::settings::experimental::deferredMode != "" ) { // First pass: fill the G-Buffer @@ -147,7 +148,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { { renderTarget.addPass( /*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - /*.colors =*/ { attachments.output, attachments.debug }, + /*.colors =*/ { attachments.output }, /*.inputs =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.depth }, /*.resolve =*/ {}, /*.depth = */ attachments.depth, @@ -170,7 +171,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { { renderTarget.addPass( /*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - /*.colors =*/ { attachments.output, attachments.debug }, + /*.colors =*/ { attachments.output }, /*.inputs =*/ { attachments.id, attachments.normals, attachments.albedo, attachments.depth }, /*.resolve =*/ {}, /*.depth = */ attachments.depth, @@ -198,17 +199,14 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { blitter.initialize( this->getName() ); blitter.initializeMesh( mesh ); + std::string fragmentShaderFilename = ( msaa <= 1 ) ? "no-msaa." : ""; if ( ext::vulkan::settings::experimental::deferredMode == "vxgi" ) { - blitter.material.initializeShaders({ - {uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, - {uf::io::root+"/shaders/display/subpass.vxgi.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} - }); - } else { - blitter.material.initializeShaders({ - {uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, - {uf::io::root+"/shaders/display/subpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} - }); + fragmentShaderFilename = ( msaa <= 1 ) ? "vxgi.no-msaa." : "vxgi."; } + blitter.material.initializeShaders({ + {uf::io::root+"/shaders/display/subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, + {uf::io::root+"/shaders/display/subpass." + fragmentShaderFilename + "frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} + }); { auto& scene = uf::scene::getCurrentScene(); @@ -220,8 +218,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { if ( ext::vulkan::settings::experimental::deferredMode == "vxgi" ) { struct SpecializationConstant { - uint32_t maxCascades = 16; uint32_t maxTextures = 512; + uint32_t maxCascades = 16; }; auto& specializationConstants = shader.specializationConstants.get(); @@ -287,13 +285,13 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); } - blitter.initializePipeline(); + // blitter.initializePipeline(); for ( size_t eye = 0; eye < eyes; ++eye ) { - ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; - descriptor.subpass = 2 * eye + 1; - if ( blitter.hasPipeline( descriptor ) ) continue; - blitter.initializePipeline( descriptor ); + blitter.descriptor.subpass = 2 * eye + 1; + if ( blitter.hasPipeline( blitter.descriptor ) ) continue; + blitter.initializePipeline( blitter.descriptor ); } + blitter.descriptor.subpass = 1; } } void ext::vulkan::DeferredRenderMode::tick() { @@ -303,7 +301,14 @@ void ext::vulkan::DeferredRenderMode::tick() { renderTarget.initialize( *renderTarget.device ); // update blitter descriptor set if ( blitter.initialized ) { - blitter.getPipeline().update( blitter ); + size_t eyes = metadata["eyes"].as(); + for ( size_t eye = 0; eye < eyes; ++eye ) { + blitter.descriptor.subpass = 2 * eye + 1; + if ( !blitter.hasPipeline( blitter.descriptor ) ) continue; + blitter.getPipeline( blitter.descriptor ).update( blitter, blitter.descriptor ); + } + blitter.descriptor.subpass = 1; + // blitter.getPipeline().update( blitter ); // blitter.updatePipelines(); } } diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 82fb5bcc..de37f233 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -61,7 +61,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { this->setTarget( this->getName() ); std::string type = metadata["type"].as(); size_t subpasses = metadata["subpasses"].as(); - size_t msaa = metadata["samples"].is() ? ext::vulkan::sampleCount(metadata["samples"].as()) : ext::vulkan::settings::msaa; + size_t msaa = metadata["samples"].is() ? ext::vulkan::sampleCount(metadata["samples"].as()) : ext::vulkan::settings::msaa; if ( subpasses == 0 ) subpasses = 1; renderTarget.device = &device; for ( size_t currentPass = 0; currentPass < subpasses; ++currentPass ) { @@ -338,9 +338,10 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { // do not attach if we're requesting no blitter shaders blitter.process = false; } else { + std::string fragmentShaderFilename = ( msaa <= 1 ) ? "no-msaa." : ""; blitter.material.initializeShaders({ - {uf::io::root+"/shaders/display/renderTarget.vert.spv", ext::vulkan::enums::Shader::VERTEX}, - {uf::io::root+"/shaders/display/renderTarget.frag.spv", ext::vulkan::enums::Shader::FRAGMENT} + {uf::io::root+"/shaders/display/renderTarget.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, + {uf::io::root+"/shaders/display/renderTarget." + fragmentShaderFilename + "frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} }); } if ( metadata["type"].as() == "vxgi" ) { @@ -420,6 +421,18 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { texture.aliasAttachment(attachment); } } + /* + if ( blitter.process ) { + auto& mainRenderMode = ext::vulkan::getRenderMode(""); + size_t eyes = mainRenderMode.metadata["eyes"].as(); + for ( size_t eye = 0; eye < eyes; ++eye ) { + ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; + descriptor.subpass = 2 * eye + 1; + if ( blitter.hasPipeline( descriptor ) ) continue; + blitter.initializePipeline( descriptor ); + } + } + */ } } @@ -428,7 +441,9 @@ void ext::vulkan::RenderTargetRenderMode::tick() { if ( metadata["type"].as() == "vxgi" ) { if ( ext::vulkan::states::resized ) { renderTarget.initialize( *renderTarget.device ); - if ( blitter.process ) blitter.getPipeline().update( blitter ); + if ( blitter.process ) { + blitter.getPipeline().update( blitter ); + } } return; } @@ -445,7 +460,21 @@ void ext::vulkan::RenderTargetRenderMode::tick() { texture.sampler.descriptor.filter.mag = filter; texture.aliasAttachment(attachment); } - if ( blitter.process ) blitter.getPipeline().update( blitter ); + if ( blitter.process ) { + auto& mainRenderMode = ext::vulkan::getRenderMode(""); + size_t eyes = mainRenderMode.metadata["eyes"].as(); + for ( size_t eye = 0; eye < eyes; ++eye ) { + ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; + descriptor.subpass = 2 * eye + 1; + if ( !blitter.hasPipeline( descriptor ) ) { + // continue; + blitter.initializePipeline( descriptor ); + } else { + blitter.getPipeline( descriptor ).update( blitter, descriptor ); + } + } + // blitter.getPipeline().update( blitter ); + } } } void ext::vulkan::RenderTargetRenderMode::destroy() { diff --git a/engine/src/ext/vulkan/rendertarget.cpp b/engine/src/ext/vulkan/rendertarget.cpp index ccc203fd..35f12207 100644 --- a/engine/src/ext/vulkan/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendertarget.cpp @@ -197,12 +197,13 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { } } descriptions.push_back(description); - /* - std::cout << "Pass: " << descriptions.size() - 1 << std::endl; - for ( auto& color : pass.colors ) std::cout << "Color: " << color.attachment << "\t" << std::hex << color.layout << "\t" << this->attachments[color.attachment].image << std::endl; - for ( auto& input : pass.inputs ) std::cout << "Input: " << input.attachment << "\t" << std::hex << input.layout << "\t" << this->attachments[input.attachment].image << std::endl; + + #if 0 + UF_DEBUG_MSG("Pass: " << descriptions.size() - 1); + for ( auto& color : pass.colors ) UF_DEBUG_MSG("Color: " << color.attachment << "\t" << std::hex << color.layout << "\t" << this->attachments[color.attachment].image); + for ( auto& input : pass.inputs ) UF_DEBUG_MSG("Input: " << input.attachment << "\t" << std::hex << input.layout << "\t" << this->attachments[input.attachment].image); std::cout << std::endl; - */ + #endif // transition dependency between subpasses dependency.srcSubpass = dependency.dstSubpass; dependency.srcStageMask = dependency.dstStageMask; @@ -253,15 +254,15 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { dependencies.push_back(dependency); } - /* + + #if 0 for ( auto& dependency : dependencies ) { - std::cout << "Pass: " << dependency.srcSubpass << " -> " << dependency.dstSubpass << std::endl; - std::cout << "\tStage: " << std::hex << dependency.srcStageMask << " -> " << std::hex << dependency.dstStageMask << std::endl; - std::cout << "\tAccess: " << std::hex << dependency.srcAccessMask << " -> " << std::hex << dependency.dstAccessMask << std::endl; + UF_DEBUG_MSG("Pass: " << dependency.srcSubpass << " -> " << dependency.dstSubpass); + UF_DEBUG_MSG("\tStage: " << std::hex << dependency.srcStageMask << " -> " << std::hex << dependency.dstStageMask); + UF_DEBUG_MSG("\tAccess: " << std::hex << dependency.srcAccessMask << " -> " << std::hex << dependency.dstAccessMask); } std::cout << std::endl; - */ - + #endif VkRenderPassCreateInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; renderPassInfo.flags = 0; diff --git a/engine/src/ext/vulkan/shader.cpp b/engine/src/ext/vulkan/shader.cpp new file mode 100644 index 00000000..7297ea2b --- /dev/null +++ b/engine/src/ext/vulkan/shader.cpp @@ -0,0 +1,787 @@ +#if UF_USE_VULKAN + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define VK_DEBUG_VALIDATION_MESSAGE(x)\ + //VK_VALIDATION_MESSAGE(x); + +ext::json::Value ext::vulkan::definitionToJson(/*const*/ ext::json::Value& definition ) { + ext::json::Value member; + // is object + if ( !ext::json::isNull(definition["members"]) ) { + ext::json::forEach(definition["members"], [&](/*const*/ ext::json::Value& value){ + std::string key = uf::string::split(value["name"].as(), " ").back(); + member[key] = ext::vulkan::definitionToJson(value); + }); + // is primitive + } else if ( !ext::json::isNull(definition["value"]) ) { + // is array of structs + if ( definition["struct"].as() ) { + ext::json::forEach(definition["value"], [&](/*const*/ ext::json::Value& value){ + ext::json::Value parsed; + parsed["name"] = definition["name"]; + parsed["size"] = definition["size"]; + parsed["struct"] = definition["struct"]; + parsed["members"] = value; + parsed = ext::vulkan::definitionToJson(parsed); + member.emplace_back(parsed); + }); + } else { + member = definition["value"]; + } + } + return member; +} +ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& payload, const ext::json::Value& definition ) { + size_t bufferLen = definition["size"].as(); + + ext::vulkan::userdata_t userdata; + userdata.create(bufferLen); + + uint8_t* byteBuffer = (uint8_t*) (void*) userdata; + uint8_t* byteBufferStart = byteBuffer; + uint8_t* byteBufferEnd = byteBuffer + bufferLen; + +#if UF_JSON_NLOHMANN_ORDERED + // JSON is ordered, we can just push directly +#define UF_SHADER_TRACK_NAMES 0 +#if UF_SHADER_TRACK_NAMES + std::vector variableName; +#endif + std::function parse = [&]( const ext::json::Value& value ){ + // is array or object + #if UF_SHADER_TRACK_NAMES + if ( ext::json::isObject(value) ) { + ext::json::forEach(value, [&]( const std::string& name, const ext::json::Value& member ){ + #if UF_SHADER_TRACK_NAMES + variableName.emplace_back(name); + #endif + parse(member); + }); + #if UF_SHADER_TRACK_NAMES + if ( !variableName.empty() ) variableName.pop_back(); + #endif + return; + } + if ( ext::json::isArray(value) ) { + ext::json::forEach(value, [&]( size_t i, const ext::json::Value& element ){ + variableName.emplace_back("["+std::to_string(i)+"]"); + parse(element); + }); + #if UF_SHADER_TRACK_NAMES + if ( !variableName.empty() ) variableName.pop_back(); + #endif + return; + } + #else + if ( ext::json::isArray(value) || ext::json::isObject(value) ) { + ext::json::forEach(value, parse); + return; + } + #endif + #if UF_SHADER_TRACK_NAMES + std::string path = uf::string::join(variableName, "."); + path = uf::string::replace( path, ".[", "[" ); + VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = " << value.dump()); + #endif + // is strictly an int + if ( value.is(true) ) { + size_t size = sizeof(int32_t); + auto get = value.as(); + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + // is strictly an unsigned int + } else if ( value.is(true) ) { + size_t size = sizeof(uint32_t); + auto get = value.as(); + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + // is strictly a float + } else if ( value.is(true) ) { + size_t size = sizeof(float); + auto get = value.as(); + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } + #if UF_SHADER_TRACK_NAMES + if ( !variableName.empty() ) variableName.pop_back(); + #endif + }; +#if UF_SHADER_TRACK_NAMES + VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename); + VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); +#endif + parse(payload); +#if UF_SHADER_TRACK_NAMES + VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); +#endif +#else + auto pushValue = [&]( const std::string& primitive, const ext::json::Value& input ){ + if ( primitive == "bool" ) { + size_t size = sizeof(bool); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + auto get = input.as(); + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "int8_t" ) { + size_t size = sizeof(int8_t); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + + // auto get = input.as(); + // memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "uint8_t" ) { + size_t size = sizeof(uint8_t); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + // auto get = input.as(); + // memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "int16_t" ) { + size_t size = sizeof(int16_t); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + // auto get = input.as(); + // memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "uint16_t" ) { + size_t size = sizeof(uint16_t); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + // auto get = input.as(); + // memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "int32_t" ) { + size_t size = sizeof(int32_t); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + auto get = input.as(); + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } + else if ( primitive == "uint32_t" ) { + size_t size = sizeof(uint32_t); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + auto get = input.as(); + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "int64_t" ) { + size_t size = sizeof(int64_t); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + auto get = input.as(); + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "uint64_t" ) { + size_t size = sizeof(uint64_t); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + auto get = input.as(); + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "half" ) { + size_t size = sizeof(float); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + // auto get = input.as(); + // memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "float" ) { + size_t size = sizeof(float); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + auto get = input.as(); + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } else if ( primitive == "double" ) { + auto get = input.as(); + size_t size = sizeof(double); // v["size"].as(); + if ( byteBufferEnd < byteBuffer + size ) return false; // overflow + memcpy( byteBuffer, &get, size ); + byteBuffer += size; + } + return true; + }; + #define UF_SHADER_TRACK_NAMES 0 + #if UF_SHADER_TRACK_NAMES + bool SKIP_ADD = false; + std::vector variableName; + #endif + std::function parseDefinition = [&](const ext::json::Value& input, const ext::json::Value& definition ){ + #if UF_SHADER_TRACK_NAMES + if ( SKIP_ADD ) { + SKIP_ADD = false; + } else { + auto split = uf::string::split(definition["name"].as(), " "); + std::string type = split.front(); + std::string name = split.back(); + variableName.emplace_back(name); + } + #endif + // is object + if ( !ext::json::isNull(definition["members"]) ) { + ext::json::forEach(definition["members"], [&](const ext::json::Value& member){ + std::string key = uf::string::split(member["name"].as(), " ").back(); + parseDefinition(input[key], member); + }); + // is array or primitive + } else if ( !ext::json::isNull(definition["value"]) ) { + // is object + auto split = uf::string::split(definition["name"].as(), " "); + std::string type = split.front(); + std::string name = split.back(); + std::regex regex("^(?:(.+?)\\<)?(.+?)(?:\\>)?(?:\\[(\\d+)\\])?$"); + std::smatch match; + if ( !std::regex_search( type, match, regex ) ) { + std::cout << "Ill formatted typename: " << definition["name"].as() << std::endl; + return; + } + std::string vectorMatrix = match[1].str(); + std::string primitive = match[2].str(); + std::string arraySize = match[3].str(); + if ( ext::json::isObject(input) ) { + ext::json::Value cloned; + cloned["name"] = definition["name"]; + cloned["size"] = definition["size"].as() / definition["value"].size(); + cloned["members"] = definition["value"][0]; + parseDefinition( input, cloned ); + } + // is array + else if ( ext::json::isArray(input) ) { + ext::json::forEach( input, [&]( size_t i, const ext::json::Value& value){ + #if UF_SHADER_TRACK_NAMES + variableName.emplace_back("["+std::to_string(i)+"]"); + SKIP_ADD = true; + #endif + parseDefinition(input[i], definition); + }); + } + // is primitive + else { + #if UF_SHADER_TRACK_NAMES + std::string path = uf::string::join(variableName, "."); + path = uf::string::replace( path, ".[", "[" ); + VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = (" << primitive << ") " << input.dump()); + #endif + pushValue( primitive, input ); + } + } + #if UF_SHADER_TRACK_NAMES + if ( !variableName.empty() ) variableName.pop_back(); + #endif + }; + auto& definitions = metadata["definitions"]["uniforms"][name]; +#if UF_SHADER_TRACK_NAMES + VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename); + VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); +#endif + parseDefinition(payload, definitions); +#if UF_SHADER_TRACK_NAMES + VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); +#endif +#endif + return userdata; +} + +void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::string& filename, VkShaderStageFlagBits stage ) { + this->device = &device; + ext::vulkan::Buffers::initialize( device ); + + std::string spirv; + + { + std::ifstream is(this->filename = filename, std::ios::binary | std::ios::in | std::ios::ate); + if ( !is.is_open() ) { + VK_VALIDATION_MESSAGE("Error: Could not open shader file \"" << filename << "\""); + return; + } + is.seekg(0, std::ios::end); spirv.reserve(is.tellg()); is.seekg(0, std::ios::beg); + spirv.assign((std::istreambuf_iterator(is)), std::istreambuf_iterator()); + + assert(spirv.size() > 0); + } + + { + + VkShaderModuleCreateInfo moduleCreateInfo = {}; + moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + moduleCreateInfo.codeSize = spirv.size(); + moduleCreateInfo.pCode = (uint32_t*) spirv.data(); + + VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &module)); + } + + { + descriptor.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + descriptor.stage = stage; + descriptor.module = module; + descriptor.pName = "main"; + + assert(descriptor.module != VK_NULL_HANDLE); + } + // set up metadata + { + metadata["filename"] = filename; + metadata["type"] = ""; + } + // do reflection + { + spirv_cross::Compiler comp( (uint32_t*) &spirv[0], spirv.size() / 4 ); + spirv_cross::ShaderResources res = comp.get_shader_resources(); + + std::function parseMembers = [&]( spirv_cross::TypeID type_id ) { + auto parseMember = [&]( auto type_id ){ + uf::Serializer payload; + + auto type = comp.get_type(type_id); + + std::string name = ""; + size_t size = 1; + ext::json::Value value; + switch ( type.basetype ) { + case spirv_cross::SPIRType::BaseType::Boolean: name = "bool"; size = sizeof(bool); value = (bool) 0; break; + case spirv_cross::SPIRType::BaseType::SByte: name = "int8_t"; size = sizeof(int8_t); value = (int8_t) 0; break; + case spirv_cross::SPIRType::BaseType::UByte: name = "uint8_t"; size = sizeof(uint8_t); value = (uint8_t) 0; break; + case spirv_cross::SPIRType::BaseType::Short: name = "int16_t"; size = sizeof(int16_t); value = (int16_t) 0; break; + case spirv_cross::SPIRType::BaseType::UShort: name = "uint16_t"; size = sizeof(uint16_t); value = (uint16_t) 0; break; + case spirv_cross::SPIRType::BaseType::Int: name = "int32_t"; size = sizeof(int32_t); value = (int32_t) 0; break; + case spirv_cross::SPIRType::BaseType::UInt: name = "uint32_t"; size = sizeof(uint32_t); value = (uint32_t) 0; break; + case spirv_cross::SPIRType::BaseType::Int64: name = "int64_t"; size = sizeof(int64_t); value = (int64_t) 0; break; + case spirv_cross::SPIRType::BaseType::UInt64: name = "uint64_t"; size = sizeof(uint64_t); value = (uint64_t) 0; break; + case spirv_cross::SPIRType::BaseType::Half: name = "half"; size = sizeof(float)/2; value = (float) 0; break; + case spirv_cross::SPIRType::BaseType::Float: name = "float"; size = sizeof(float); value = (float) 0; break; + case spirv_cross::SPIRType::BaseType::Double: name = "double"; size = sizeof(double); value = (double) 0; break; + case spirv_cross::SPIRType::BaseType::Image: name = "image2D"; break; + case spirv_cross::SPIRType::BaseType::SampledImage: name = "sampler2D"; break; + case spirv_cross::SPIRType::BaseType::Sampler: name = "sampler"; break; + default: + name = comp.get_name(type_id); + size = comp.get_declared_struct_size(type); + break; + } + if ( name == "" ) name = comp.get_name(type.type_alias); + if ( name == "" ) name = comp.get_name(type.type_alias); + if ( name == "" ) name = comp.get_name(type.parent_type); + if ( name == "" ) name = comp.get_fallback_name(type_id); + if ( type.vecsize > 1 ) { + name = "<"+name+">"; + if ( type.columns > 1 ) { + name = "Matrix"+std::to_string(type.vecsize)+"x"+std::to_string(type.columns)+name; + } else { + name = "Vector"+std::to_string(type.vecsize)+name; + } + } + { + ext::json::Value source = value; + value = ext::json::array(); + for ( size_t i = 0; i < type.vecsize * type.columns; ++i ) { + value.emplace_back(source); + } + size *= type.columns * type.vecsize; + } + for ( auto arraySize : type.array ) { + if ( arraySize > 1 ) { + ext::json::Value source = value; + value = ext::json::array(); + for ( size_t i = 0; i < arraySize; ++i ) { + value.emplace_back(source); + } + name += "[" + std::to_string(arraySize) + "]"; + size *= arraySize; + } + } + if ( ext::json::isArray(value) && value.size() == 1 ) { + value = value[0]; + } + payload["name"] = name; + payload["size"] = size; + payload["value"] = value; + return payload; + }; + uf::Serializer payload = ext::json::array(); + const auto& type = comp.get_type(type_id); + for ( auto& member_type_id : type.member_types ) { + const auto& member_type = comp.get_type(member_type_id); + std::string name = comp.get_member_name(type.type_alias, payload.size()); + if ( name == "" ) name = comp.get_member_name(type.parent_type, payload.size()); + if ( name == "" ) name = comp.get_member_name(type_id, payload.size()); + + auto& entry = payload.emplace_back(); + auto parsed = parseMember(member_type_id); + std::string type_name = parsed["name"]; + entry["name"] = type_name + " " + name; + if ( member_type.basetype == spirv_cross::SPIRType::BaseType::Struct ) { + entry["struct"] = true; + auto parsed = parseMembers(member_type_id); + if ( !member_type.array.empty() && member_type.array[0] > 1 ) { + size_t size = comp.get_declared_struct_size(member_type); + for ( auto arraySize : member_type.array ) { + ext::json::Value source = parsed; + parsed = ext::json::array(); + for ( size_t i = 0; i < arraySize; ++i ) { + parsed.emplace_back(source); + } + size = size * arraySize; + } + entry["size"] = size; + entry["value"] = parsed; + } else { + entry["size"] = comp.get_declared_struct_size(member_type); + entry["members"] = parsed; + } + } else { + entry["size"] = parsed["size"]; + entry["value"] = parsed["value"]; + } + } + return payload; + }; + + auto parseResource = [&]( const spirv_cross::Resource& resource, VkDescriptorType descriptorType, size_t index ) { + const auto& type = comp.get_type(resource.type_id); + const auto& base_type = comp.get_type(resource.base_type_id); + std::string name = resource.name; + size_t arraySize = 1; + if ( !type.array.empty() ) { + arraySize = type.array[0]; + } + + switch ( descriptorType ) { + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + std::string tname = ""; + switch ( type.image.dim ) { + case spv::Dim::Dim1D: tname = "1D"; break; + case spv::Dim::Dim2D: tname = "2D"; break; + case spv::Dim::Dim3D: tname = "3D"; break; + case spv::Dim::DimCube: tname = "Cube"; break; + case spv::Dim::DimRect: tname = "Rect"; break; + case spv::Dim::DimBuffer: tname = "Buffer"; break; + case spv::Dim::DimSubpassData: tname = "SubpassData"; break; + + } + size_t binding = comp.get_decoration(resource.id, spv::DecorationBinding); + std::string key = std::to_string(binding); + metadata["definitions"]["textures"][key]["name"] = name; + metadata["definitions"]["textures"][key]["index"] = index; + metadata["definitions"]["textures"][key]["binding"] = binding; + metadata["definitions"]["textures"][key]["size"] = arraySize; + metadata["definitions"]["textures"][key]["type"] = tname; + } break; + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { + size_t bufferSize = comp.get_declared_struct_size(base_type); + if ( bufferSize <= 0 ) break; + if ( bufferSize > device.properties.limits.maxUniformBufferRange ) { + VK_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer length of " << bufferSize << " for shader " << filename); + bufferSize = device.properties.limits.maxUniformBufferRange; + } + size_t misalignment = bufferSize % device.properties.limits.minStorageBufferOffsetAlignment; + if ( misalignment != 0 ) { + VK_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer alignment of " << misalignment << " for shader " << filename << ", correcting..."); + bufferSize += misalignment; + } + { + VK_DEBUG_VALIDATION_MESSAGE("Uniform size of " << bufferSize << " for shader " << filename); + auto& uniform = uniforms.emplace_back(); + uniform.create( bufferSize ); + } + // generate definition to JSON + { + metadata["definitions"]["uniforms"][name]["name"] = name; + metadata["definitions"]["uniforms"][name]["index"] = index; + metadata["definitions"]["uniforms"][name]["size"] = bufferSize; + metadata["definitions"]["uniforms"][name]["members"] = parseMembers(resource.type_id); + } + } break; + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: { + // generate definition to JSON + { + metadata["definitions"]["storage"][name]["name"] = name; + metadata["definitions"]["storage"][name]["index"] = index; + metadata["definitions"]["storage"][name]["members"] = parseMembers(resource.type_id); + } + // test + { + // updateUniform(name, getUniform(name)); + } + } break; + } + descriptorSetLayoutBindings.push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, comp.get_decoration(resource.id, spv::DecorationBinding), arraySize ) ); + }; + + + //for ( const auto& resource : res.key ) { + #define LOOP_RESOURCES( key, type ) for ( size_t i = 0; i < res.key.size(); ++i ) {\ + const auto& resource = res.key[i];\ + VK_DEBUG_VALIDATION_MESSAGE("["< device.properties.limits.maxPushConstantsSize ) { + VK_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of " << size << " for shader " << filename); + size = device.properties.limits.maxPushConstantsSize; + } + VK_DEBUG_VALIDATION_MESSAGE("Push constant size of " << size << " for shader " << filename); + { + auto& pushConstant = pushConstants.emplace_back(); + pushConstant.create( size ); + } + // generate definition to JSON + { + metadata["definitions"]["pushConstants"][name]["name"] = name; + metadata["definitions"]["pushConstants"][name]["size"] = size; + metadata["definitions"]["pushConstants"][name]["index"] = pushConstants.size() - 1; + metadata["definitions"]["pushConstants"][name]["members"] = parseMembers(resource.type_id); + } + } + + size_t specializationSize = 0; + for ( const auto& constant : comp.get_specialization_constants() ) { + const auto& value = comp.get_constant(constant.id); + const auto& type = comp.get_type(value.constant_type); + size_t size = 4; //comp.get_declared_struct_size(type); + + VkSpecializationMapEntry specializationMapEntry; + specializationMapEntry.constantID = constant.constant_id; + specializationMapEntry.size = size; + specializationMapEntry.offset = specializationSize; + specializationMapEntries.push_back(specializationMapEntry); + specializationSize += size; + } + if ( specializationSize > 0 ) { + specializationConstants.create( specializationSize ); + VK_DEBUG_VALIDATION_MESSAGE("Specialization constants size of " << specializationSize << " for shader " << filename); + + uint8_t* s = (uint8_t*) (void*) specializationConstants; + size_t offset = 0; + + metadata["specializationConstants"] = ext::json::array(); + for ( const auto& constant : comp.get_specialization_constants() ) { + const auto& value = comp.get_constant(constant.id); + const auto& type = comp.get_type(value.constant_type); + std::string name = comp.get_name (constant.id); + + ext::json::Value member; + + size_t size = 4; + uint8_t buffer[size]; + switch ( type.basetype ) { + case spirv_cross::SPIRType::UInt: { + auto v = value.scalar(); + member["type"] = "uint32_t"; + member["value"] = v; + member["validate"] = true; + memcpy( &buffer[0], &v, sizeof(v) ); + } break; + case spirv_cross::SPIRType::Int: { + auto v = value.scalar_i32(); + member["type"] = "int32_t"; + member["value"] = v; + memcpy( &buffer[0], &v, sizeof(v) ); + } break; + case spirv_cross::SPIRType::Float: { + auto v = value.scalar_f32(); + member["type"] = "float"; + member["value"] = v; + memcpy( &buffer[0], &v, sizeof(v) ); + } break; + case spirv_cross::SPIRType::Boolean: { + auto v = value.scalar()!=0; + member["type"] = "bool"; + member["value"] = v; + memcpy( &buffer[0], &v, sizeof(v) ); + } break; + default: { + VK_DEBUG_VALIDATION_MESSAGE("Unregistered specialization constant type at offset " << offset << " for shader " << filename ); + } break; + } + member["name"] = name; + member["size"] = size; + member["default"] = member["value"]; + VK_DEBUG_VALIDATION_MESSAGE("Specialization constant: " << member["type"].as() << " " << name << " = " << member["value"].dump() << "; at offset " << offset << " for shader " << filename ); + metadata["specializationConstants"].emplace_back(member); + + memcpy( &s[offset], &buffer, size ); + offset += size; + } + /* + { + specializationInfo = {}; + specializationInfo.dataSize = specializationSize; + specializationInfo.mapEntryCount = specializationMapEntries.size(); + specializationInfo.pMapEntries = specializationMapEntries.data(); + specializationInfo.pData = (void*) specializationConstants; + descriptor.pSpecializationInfo = &specializationInfo; + } + */ + } + /* + */ + // LOOP_RESOURCES( stage_inputs, VkVertexInputAttributeDescription ); + // LOOP_RESOURCES( stage_outputs, VkPipelineColorBlendAttachmentState ); + } + + // organize layouts + { + std::sort( descriptorSetLayoutBindings.begin(), descriptorSetLayoutBindings.end(), [&]( const VkDescriptorSetLayoutBinding& l, const VkDescriptorSetLayoutBinding& r ){ + return l.binding < r.binding; + } ); + } + + // update uniform buffers + for ( auto& uniform : uniforms ) { + auto& userdata = uniform.data(); + initializeBuffer( + (void*) userdata.data, + userdata.len, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + ); + } +} + +void ext::vulkan::Shader::destroy() { + if ( !device ) return; + + ext::vulkan::Buffers::destroy(); + + if ( module != VK_NULL_HANDLE ) { + vkDestroyShaderModule( *device, module, nullptr ); + module = VK_NULL_HANDLE; + descriptor = {}; + } + for ( auto& userdata : uniforms ) userdata.destroy(); + for ( auto& userdata : pushConstants ) userdata.destroy(); + uniforms.clear(); + pushConstants.clear(); +} + +bool ext::vulkan::Shader::validate() { + // check if uniforms match buffer size + bool valid = true; + { + auto it = uniforms.begin(); + for ( auto& buffer : buffers ) { + if ( !(buffer.usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) ) continue; + if ( it == uniforms.end() ) break; + auto& uniform = *(it++); + if ( uniform.data().len != buffer.allocationInfo.size ) { + VK_DEBUG_VALIDATION_MESSAGE("Uniform size mismatch: Expected " << buffer.allocationInfo.size << ", got " << uniform.data().len << "; fixing..."); + uniform.destroy(); + uniform.create(buffer.allocationInfo.size); + valid = false; + } + } + } + return valid; +} +bool ext::vulkan::Shader::hasUniform( const std::string& name ) { + return !ext::json::isNull(metadata["definitions"]["uniforms"][name]); +} +ext::vulkan::Buffer* ext::vulkan::Shader::getUniformBuffer( const std::string& name ) { + if ( !hasUniform(name) ) return NULL; + size_t uniformIndex = metadata["definitions"]["uniforms"][name]["index"].as(); + for ( size_t bufferIndex = 0, uniformCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { + if ( !(buffers[bufferIndex].usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) ) continue; + if ( uniformCounter++ != uniformIndex ) continue; + return &buffers[bufferIndex]; + } + return NULL; +} +ext::vulkan::userdata_t& ext::vulkan::Shader::getUniform( const std::string& name ) { + if ( !hasUniform(name) ) { + static ext::vulkan::userdata_t null; + return null; + } + auto& definition = metadata["definitions"]["uniforms"][name]; + size_t uniformSize = definition["size"].as(); + size_t uniformIndex = definition["index"].as(); + auto& userdata = uniforms[uniformIndex]; + return userdata; +} +bool ext::vulkan::Shader::updateUniform( const std::string& name ) { + if ( !hasUniform(name) ) return false; + auto& uniform = getUniform(name); + return updateUniform(name, uniform); +} +bool ext::vulkan::Shader::updateUniform( const std::string& name, const ext::vulkan::userdata_t& userdata ) { + if ( !hasUniform(name) ) return false; + auto* bufferObject = getUniformBuffer(name); + if ( !bufferObject ) return false; + size_t size = std::max(metadata["definitions"]["uniforms"][name]["size"].as(), bufferObject->allocationInfo.size); + updateBuffer( (void*) userdata, size, *bufferObject ); + return true; +} + +uf::Serializer ext::vulkan::Shader::getUniformJson( const std::string& name, bool cache ) { + if ( !hasUniform(name) ) return ext::json::null(); + if ( cache && !ext::json::isNull(metadata["uniforms"][name]) ) return metadata["uniforms"][name]; + auto& definition = metadata["definitions"]["uniforms"][name]; + if ( cache ) return metadata["uniforms"][name] = definitionToJson(definition); + return definitionToJson(definition); +} +ext::vulkan::userdata_t ext::vulkan::Shader::getUniformUserdata( const std::string& name, const ext::json::Value& payload ) { + if ( !hasUniform(name) ) return false; + return jsonToUserdata(payload, metadata["definitions"]["uniforms"][name]); +} +bool ext::vulkan::Shader::updateUniform( const std::string& name, const ext::json::Value& payload ) { + if ( !hasUniform(name) ) return false; + + auto* bufferObject = getUniformBuffer(name); + if ( !bufferObject ) return false; + + auto uniform = getUniformUserdata( name, payload ); + updateBuffer( (void*) uniform, uniform.data().len, *bufferObject ); + return true; +} + +bool ext::vulkan::Shader::hasStorage( const std::string& name ) { + return !ext::json::isNull(metadata["definitions"]["storage"][name]); +} + +ext::vulkan::Buffer* ext::vulkan::Shader::getStorageBuffer( const std::string& name ) { + if ( !hasStorage(name) ) return NULL; + size_t storageIndex = metadata["definitions"]["storage"][name]["index"].as(); + for ( size_t bufferIndex = 0, storageCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { + if ( !(buffers[bufferIndex].usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) ) continue; + if ( storageCounter++ != storageIndex ) continue; + return &buffers[bufferIndex]; + } + return NULL; +} +uf::Serializer ext::vulkan::Shader::getStorageJson( const std::string& name, bool cache ) { + if ( !hasStorage(name) ) return ext::json::null(); + if ( cache && !ext::json::isNull(metadata["storage"][name]) ) return metadata["storage"][name]; + auto& definition = metadata["definitions"]["storage"][name]; + if ( cache ) return metadata["storage"][name] = definitionToJson(definition); + return definitionToJson(definition); +} +ext::vulkan::userdata_t ext::vulkan::Shader::getStorageUserdata( const std::string& name, const ext::json::Value& payload ) { + if ( !hasStorage(name) ) return false; + return jsonToUserdata(payload, metadata["definitions"]["storage"][name]); +} + +#endif \ No newline at end of file diff --git a/engine/src/ext/vulkan/texture.cpp b/engine/src/ext/vulkan/texture.cpp index 3e898d66..1553718c 100644 --- a/engine/src/ext/vulkan/texture.cpp +++ b/engine/src/ext/vulkan/texture.cpp @@ -9,6 +9,32 @@ ext::vulkan::Texture2D ext::vulkan::Texture2D::empty; ext::vulkan::Texture3D ext::vulkan::Texture3D::empty; ext::vulkan::TextureCube ext::vulkan::TextureCube::empty; +std::vector ext::vulkan::Sampler::samplers; + +ext::vulkan::Sampler ext::vulkan::Sampler::retrieve( const ext::vulkan::Sampler::Descriptor& info ) { + ext::vulkan::Sampler sampler; + for ( auto& s : samplers ) { + if ( memcmp( &info, &s.descriptor, sizeof(info) - sizeof(VkDescriptorImageInfo) ) != 0 ) continue; + sampler = s; + goto RETRIEVE_RETURN; + /* + auto& d = s.descriptor; + if ( d.filter.min != info.filter.min || d.filter.mag != info.filter.mag || d.filter.borderColor != info.filter.borderColor ) continue; + if ( d.addressMode.unnormalizedCoordinates != info.addressMode.unnormalizedCoordinates || d.addressMode.u != info.addressMode.u || d.addressMode.v != info.addressMode.v || d.addressMode.w != info.addressMode.w ) continue; + if ( d.mip.compareEnable != info.mip.compareEnable || d.mip.compareOp != info.mip.compareOp || d.mip.mode != info.mip.mode || d.mip.lodBias != info.mip.lodBias || d.mip.min != info.mip.min || d.mip.max != info.mip.max ) continue; + */ + } + { + auto& s = samplers.emplace_back(); + s.descriptor = info; + s.initialize( ext::vulkan::device ); + sampler = s; + } +RETRIEVE_RETURN: + sampler.device = NULL; + return sampler; +} + void ext::vulkan::Sampler::initialize( Device& device ) { this->device = &device; if ( device.enabledFeatures.samplerAnisotropy == VK_FALSE ) { @@ -41,6 +67,8 @@ void ext::vulkan::Sampler::initialize( Device& device ) { } } void ext::vulkan::Sampler::destroy() { + if ( !device ) return; + if ( sampler != VK_NULL_HANDLE ) { vkDestroySampler(device->logicalDevice, sampler, nullptr); sampler = VK_NULL_HANDLE; @@ -112,7 +140,7 @@ void ext::vulkan::Texture::destroy() { // vkFreeMemory(device->logicalDevice, deviceMemory, nullptr); deviceMemory = VK_NULL_HANDLE; } - sampler.destroy(); // should be above + if ( sampler.device ) sampler.destroy(); } void ext::vulkan::Texture::setImageLayout( VkCommandBuffer cmdbuffer, @@ -417,7 +445,8 @@ void ext::vulkan::Texture::fromBuffers( // Create sampler sampler.descriptor.mip.min = 0; sampler.descriptor.mip.max = static_cast(this->mips); - sampler.initialize( device ); + // sampler.initialize( device ); + sampler = ext::vulkan::Sampler::retrieve( sampler.descriptor ); // Create image view VkImageViewCreateInfo viewCreateInfo = {}; @@ -511,7 +540,8 @@ void ext::vulkan::Texture::asRenderTarget( Device& device, uint32_t width, uint3 device.flushCommandBuffer(layoutCmd, true); // Create sampler - sampler.initialize( device ); + // sampler.initialize( device ); + sampler = ext::vulkan::Sampler::retrieve( sampler.descriptor ); // Create image view VkImageViewCreateInfo viewCreateInfo = ext::vulkan::initializers::imageViewCreateInfo(); @@ -547,7 +577,10 @@ void ext::vulkan::Texture::aliasAttachment( const RenderTarget::Attachment& atta deviceMemory = attachment.mem; // Create sampler - if ( createSampler ) sampler.initialize( ext::vulkan::device ); + if ( createSampler ) { + // sampler.initialize( ext::vulkan::device ); + sampler = ext::vulkan::Sampler::retrieve( sampler.descriptor ); + } this->updateDescriptors(); } diff --git a/engine/src/ext/vulkan/vulkan.cpp b/engine/src/ext/vulkan/vulkan.cpp index 7aa01a65..dec96c11 100644 --- a/engine/src/ext/vulkan/vulkan.cpp +++ b/engine/src/ext/vulkan/vulkan.cpp @@ -378,23 +378,14 @@ void ext::vulkan::destroy() { Texture2D::empty.destroy(); Texture3D::empty.destroy(); TextureCube::empty.destroy(); -if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); for ( auto entity : graph ) { if ( !entity->hasComponent() ) continue; uf::Graphic& graphic = entity->getComponent(); graphic.destroy(); } -} else { - for ( uf::Scene* scene : uf::scene::scenes ) { - if ( !scene ) continue; - scene->process([&]( uf::Entity* entity ) { - if ( !entity->hasComponent() ) return; - uf::Graphic& graphic = entity->getComponent(); - graphic.destroy(); - }); - } -} + for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; renderMode->destroy(); @@ -402,6 +393,10 @@ if ( uf::scene::useGraph ) { renderMode = NULL; } + for ( auto& s : ext::vulkan::Sampler::samplers ) { + s.destroy(); + } + swapchain.destroy(); device.destroy(); ext::vulkan::mutex.unlock(); diff --git a/engine/src/spec/controller/windows.cpp b/engine/src/spec/controller/windows.cpp index bb835d69..4cdc578a 100644 --- a/engine/src/spec/controller/windows.cpp +++ b/engine/src/spec/controller/windows.cpp @@ -11,7 +11,7 @@ void spec::win32::controller::tick() {} void spec::win32::controller::terminate() {} bool spec::win32::controller::connected( size_t i ) { #if UF_USE_OPENVR - if ( ext::openvr::controllerActive( i ) ) return true; + if ( ext::openvr::controllerActive( i == 0 ? vr::Controller_Hand::Hand_Left : vr::Controller_Hand::Hand_Right ) ) return true; #endif return false; } @@ -50,12 +50,13 @@ bool spec::win32::controller::pressed( const std::string& _name, size_t i ) { else if ( name == "A" && i == vr::Controller_Hand::Hand_Left ) key = "a"; else if ( name == "B" && i == vr::Controller_Hand::Hand_Left ) key = "b"; - if ( name != "" ) return ext::openvr::controllerState( i, key )["state"].as(); + if ( name != "" ) return ext::openvr::controllerState( i == 0 ? vr::Controller_Hand::Hand_Left : vr::Controller_Hand::Hand_Right, key )["state"].as(); } #endif return false; } -float spec::win32::controller::analog( const std::string&, size_t i ) { +float spec::win32::controller::analog( const std::string& _name, size_t i ) { + std::string name = uf::string::uppercase(_name); #if UF_USE_OPENVR if ( ext::openvr::context ) { size_t offset = 0; @@ -70,7 +71,7 @@ float spec::win32::controller::analog( const std::string&, size_t i ) { else if ( name == "L_JOYSTICK_Y" ) { i = vr::Controller_Hand::Hand_Left; key = "thumbstick"; offset = 1; } else if ( name == "JOYSTICK_Y" && i == vr::Controller_Hand::Hand_Left ) { key = "thumbstick"; offset = 1; } - if ( name != "" ) return ext::openvr::controllerState( i, key )["analog"]["position"][offset].as(); + if ( name != "" ) return ext::openvr::controllerState( i == 0 ? vr::Controller_Hand::Hand_Left : vr::Controller_Hand::Hand_Right, key )["analog"]["position"][offset].as(); } #endif return 0; diff --git a/engine/src/spec/window/windows.cpp b/engine/src/spec/window/windows.cpp index cbcc8eab..e2f6a6b4 100644 --- a/engine/src/spec/window/windows.cpp +++ b/engine/src/spec/window/windows.cpp @@ -992,8 +992,9 @@ void UF_API_CALL spec::win32::Window::processEvent(UINT message, WPARAM wParam, { json["type"] = event.type; json["invoker"] = event.invoker; - json["window"]["size"]["x"] = event.window.size.x; - json["window"]["size"]["y"] = event.window.size.y; + json["window"]["size"] = uf::vector::encode(event.window.size); + // json["window"]["size"]["x"] = event.window.size.x; + // json["window"]["size"]["y"] = event.window.size.y; this->pushEvent(event.type, json); } @@ -1028,8 +1029,9 @@ void UF_API_CALL spec::win32::Window::processEvent(UINT message, WPARAM wParam, { json["type"] = event.type; json["invoker"] = event.invoker; - json["window"]["size"]["x"] = event.window.size.x; - json["window"]["size"]["y"] = event.window.size.y; + json["window"]["size"] = uf::vector::encode(event.window.size); + // json["window"]["size"]["x"] = event.window.size.x; + // json["window"]["size"]["y"] = event.window.size.y; this->pushEvent(event.type, json); } } else { @@ -1255,8 +1257,9 @@ void UF_API_CALL spec::win32::Window::processEvent(UINT message, WPARAM wParam, json["type"] = event.type; json["invoker"] = event.invoker; - json["mouse"]["position"]["x"] = event.mouse.position.x; - json["mouse"]["position"]["y"] = event.mouse.position.y; + json["mouse"]["position"] = uf::vector::encode(event.mouse.position); + // json["mouse"]["position"]["x"] = event.mouse.position.x; + // json["mouse"]["position"]["y"] = event.mouse.position.y; json["mouse"]["delta"] = event.mouse.delta; this->pushEvent(event.type, json); @@ -1322,13 +1325,15 @@ void UF_API_CALL spec::win32::Window::processEvent(UINT message, WPARAM wParam, #if USE_OPTIMAL this->pushEvent(event.type, uf::Userdata(uf::userdata::create(event))); #endif - json["type"] = event.type; + json["type"] = event.type; json["invoker"] = event.invoker; - json["mouse"]["position"]["x"] = event.mouse.position.x; - json["mouse"]["position"]["y"] = event.mouse.position.y; - json["mouse"]["delta"]["x"] = event.mouse.delta.x; - json["mouse"]["delta"]["y"] = event.mouse.delta.y; + json["mouse"]["position"] = uf::vector::encode(event.mouse.position); + json["mouse"]["delta"] = uf::vector::encode(event.mouse.delta); + // json["mouse"]["position"]["x"] = event.mouse.position.x; + // json["mouse"]["position"]["y"] = event.mouse.position.y; + // json["mouse"]["delta"]["x"] = event.mouse.delta.x; + // json["mouse"]["delta"]["y"] = event.mouse.delta.y; json["mouse"]["button"] = event.mouse.button; switch (event.mouse.state) { case 1: @@ -1441,12 +1446,15 @@ void UF_API_CALL spec::win32::Window::processEvent(UINT message, WPARAM wParam, json["type"] = event.type; json["invoker"] = event.invoker; - json["mouse"]["position"]["x"] = event.mouse.position.x; - json["mouse"]["position"]["y"] = event.mouse.position.y; - json["mouse"]["delta"]["x"] = event.mouse.delta.x; - json["mouse"]["delta"]["y"] = event.mouse.delta.y; - json["mouse"]["size"]["x"] = event.mouse.size.x; - json["mouse"]["size"]["y"] = event.mouse.size.y; + // json["mouse"]["position"]["x"] = event.mouse.position.x; + // json["mouse"]["position"]["y"] = event.mouse.position.y; + // json["mouse"]["delta"]["x"] = event.mouse.delta.x; + // json["mouse"]["delta"]["y"] = event.mouse.delta.y; + // json["mouse"]["size"]["x"] = event.mouse.size.x; + // json["mouse"]["size"]["y"] = event.mouse.size.y; + json["mouse"]["position"] = uf::vector::encode(event.mouse.position); + json["mouse"]["delta"] = uf::vector::encode(event.mouse.delta); + json["mouse"]["size"] = uf::vector::encode(event.mouse.size); switch (event.mouse.state) { case 1: json["mouse"]["state"] = "Entered"; diff --git a/engine/src/utils/io/file.cpp b/engine/src/utils/io/file.cpp index 7c8da37f..a32e2652 100644 --- a/engine/src/utils/io/file.cpp +++ b/engine/src/utils/io/file.cpp @@ -116,6 +116,16 @@ std::vector UF_API uf::io::readAsBuffer( const std::string& filename, c } return buffer; } + +size_t UF_API uf::io::write( const std::string& filename, const void* buffer, size_t size ) { + std::ofstream output; + output.open( uf::io::sanitize( filename ), std::ios::binary); + output.write( (const char*) buffer, size ); + output.close(); + + return size; +} + std::string UF_API uf::io::hash( const std::string& filename ) { return uf::string::sha256( uf::io::readAsBuffer( filename ) ); } diff --git a/engine/src/utils/window/window.cpp b/engine/src/utils/window/window.cpp index 867be923..1135524d 100644 --- a/engine/src/utils/window/window.cpp +++ b/engine/src/utils/window/window.cpp @@ -55,42 +55,59 @@ size_t UF_API_CALL uf::Window::getRefreshRate() const { } // Attribute modifiers void UF_API_CALL uf::Window::setPosition( const spec::uni::Window::vector_t& position ) { - if ( this->m_window ) this->m_window->setPosition(position); + if ( !this->m_window ) return; + this->m_window->setPosition(position); } void UF_API_CALL uf::Window::centerWindow() { - if ( this->m_window ) this->m_window->centerWindow(); + if ( !this->m_window ) return; + this->m_window->centerWindow(); } void UF_API_CALL uf::Window::setMousePosition( const spec::uni::Window::vector_t& position ) { - if ( this->m_window ) this->m_window->setMousePosition(position); + if ( !this->m_window ) return; + this->m_window->setMousePosition(position); } spec::uni::Window::vector_t UF_API_CALL uf::Window::getMousePosition() { - if ( this->m_window ) return this->m_window->getMousePosition(); - return { 0, 0 }; + return this->m_window ? this->m_window->getMousePosition() : spec::uni::Window::vector_t{ 0, 0 }; } void UF_API_CALL uf::Window::setSize( const spec::uni::Window::vector_t& size ) { - if ( this->m_window ) this->m_window->setSize(size); + if ( !this->m_window ) return; + this->m_window->setSize(size); } void UF_API_CALL uf::Window::setTitle( const spec::uni::Window::title_t& title ) { - if ( this->m_window ) this->m_window->setTitle(title); + if ( !this->m_window ) return; + this->m_window->setTitle(title); + + uf::Serializer json; + std::string hook = "window:Title.Changed"; + json["type"] = hook; + json["invoker"] = "os"; + json["window"]["title"] = std::string(title); + uf::hooks.call( hook, json ); } void UF_API_CALL uf::Window::setIcon( const spec::uni::Window::vector_t& size, uint8_t* pixels ) { - if ( this->m_window ) this->m_window->setIcon(size, pixels); + if ( !this->m_window ) return; + this->m_window->setIcon(size, pixels); } void UF_API_CALL uf::Window::setVisible( bool visibility ) { - if ( this->m_window ) this->m_window->setVisible(visibility); + if ( !this->m_window ) return; + this->m_window->setVisible(visibility); } void UF_API_CALL uf::Window::setCursorVisible( bool visibility ) { - if ( this->m_window ) this->m_window->setCursorVisible(visibility); + if ( !this->m_window ) return; + this->m_window->setCursorVisible(visibility); } void UF_API_CALL uf::Window::setKeyRepeatEnabled( bool state ) { - if ( this->m_window ) this->m_window->setKeyRepeatEnabled(state); + if ( !this->m_window ) return; + this->m_window->setKeyRepeatEnabled(state); } void UF_API_CALL uf::Window::setMouseGrabbed( bool state ) { - if ( this->m_window ) this->m_window->setMouseGrabbed(state); + if ( !this->m_window ) return; + this->m_window->setMouseGrabbed(state); } void UF_API_CALL uf::Window::requestFocus() { - if ( this->m_window ) this->m_window->requestFocus(); + if ( !this->m_window ) return; + this->m_window->requestFocus(); } bool UF_API_CALL uf::Window::hasFocus() const { return uf::Window::focused = (this->m_window ? this->m_window->hasFocus() : false); @@ -99,11 +116,13 @@ pod::Vector2ui UF_API_CALL uf::Window::getResolution() { return uf::Window::window_t::getResolution(); } void UF_API_CALL uf::Window::switchToFullscreen( bool borderless ) { - if ( this->m_window ) this->m_window->switchToFullscreen( borderless ); + if ( !this->m_window ) return; + this->m_window->switchToFullscreen( borderless ); } // Update void UF_API_CALL uf::Window::processEvents() { - if ( this->m_window ) this->m_window->processEvents(); + if ( !this->m_window ) return; + this->m_window->processEvents(); } bool UF_API_CALL uf::Window::pollEvents( bool block ) { return this->m_window ? this->m_window->pollEvents(block) : false; @@ -113,8 +132,8 @@ bool UF_API_CALL uf::Window::isKeyPressed( const std::string& key ) { } bool UF_API_CALL uf::Window::setActive(bool active) { #if UF_USE_OPENGL && UF_OPENGL_CONTEXT_IN_WINDOW - if (this->m_context) { - if (this->m_context->setActive(active)) return true; + if ( this->m_context ) { + if ( this->m_context->setActive(active) ) return true; uf::iostream << "[" << uf::IoStream::Color()("Red") << "ERROR" << "]" << "Failed to activate the window's context" << "\n"; return false; } @@ -144,21 +163,8 @@ void UF_API_CALL uf::Window::createSurface( VkInstance instance, VkSurfaceKHR& s #include #include void UF_API_CALL uf::Window::display() { - // Display the backbuffer on screen #if UF_USE_OPENGL && UF_OPENGL_CONTEXT_IN_WINDOW - if (this->m_context && this->setActive()) this->m_context->display(); -#endif -#if 0 - /* FPS */ if ( false ) { - static double limit = 1.0 / 60; - static uf::Timer timer(false); - if ( !timer.running() ) timer.start(); - double delta = limit - timer.elapsed().asDouble(); - if ( delta > 0 ) { - std::this_thread::sleep_for( std::chrono::milliseconds( (int) delta * 1000 ) ); - timer.reset(); - } - } + if ( this->m_context && this->setActive() ) this->m_context->display(); #endif } diff --git a/ext/behaviors/hands/behavior.cpp b/ext/behaviors/hands/behavior.cpp index 64816f40..824db1a5 100644 --- a/ext/behaviors/hands/behavior.cpp +++ b/ext/behaviors/hands/behavior.cpp @@ -69,8 +69,8 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { graphic.process = true; graphic.descriptor.frontFace = uf::renderer::enums::Face::CCW; - graphic.material.attachShader(uf::io::root+"/shaders/base/vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader(uf::io::root+"/shaders/base/frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root+"/shaders/base/base.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root+"/shaders/base/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); uf::instantiator::bind( "EntityBehavior", hand ); uf::instantiator::bind( "ObjectBehavior", hand ); @@ -104,8 +104,8 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { graphic.initialize(); graphic.initializeMesh(mesh); - graphic.material.attachShader(uf::io::root+"/shaders/line/vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader(uf::io::root+"/shaders/line/frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root+"/shaders/line/base.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root+"/shaders/line/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_STRIP; graphic.descriptor.fill = uf::renderer::enums::PolygonMode::LINE; graphic.descriptor.lineWidth = metadata["hands"][side]["pointer"]["width"].as(); @@ -166,10 +166,12 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { uf::Serializer payload; payload["type"] = "window:Mouse.Click"; payload["invoker"] = "vr"; - payload["mouse"]["position"]["x"] = metadata["hands"][side]["cursor"]["position"][0].as(); - payload["mouse"]["position"]["y"] = metadata["hands"][side]["cursor"]["position"][1].as(); - payload["mouse"]["delta"]["x"] = 0; - payload["mouse"]["delta"]["y"] = 0; + // payload["mouse"]["position"]["x"] = metadata["hands"][side]["cursor"]["position"][0].as(); + // payload["mouse"]["position"]["y"] = metadata["hands"][side]["cursor"]["position"][1].as(); + // payload["mouse"]["delta"]["x"] = 0; + // payload["mouse"]["delta"]["y"] = 0; + payload["mouse"]["position"] = metadata["hands"][side]["cursor"]["position"]; + payload["mouse"]["delta"] = uf::vector::encode( pod::Vector2i{0,0} ); payload["mouse"]["button"] = side == "left" ? "Right" : "Left"; payload["mouse"]["state"] = json["state"].as() ? "Down": "Up"; diff --git a/ext/behaviors/light/behavior.cpp b/ext/behaviors/light/behavior.cpp index 7ca4add6..9e18386c 100644 --- a/ext/behaviors/light/behavior.cpp +++ b/ext/behaviors/light/behavior.cpp @@ -244,31 +244,32 @@ void ext::LightBehavior::tick( uf::Object& self ) { camera.updateView(); } } - bool execute = true; + auto& renderMode = this->getComponent(); // enable renderer every X seconds if ( metadata.renderer.limiter > 0 ) { if ( metadata.renderer.timer > metadata.renderer.limiter ) { metadata.renderer.timer = 0; - execute = true; + renderMode.execute = true; } else { metadata.renderer.timer = metadata.renderer.timer + uf::physics::time::delta; - execute = false; + renderMode.execute = false; } } else { // round robin, enable if it's the light's current turn if ( metadata.renderer.mode == "round robin" ) { - if ( ::roundRobin.current < ::roundRobin.lights.size() ) execute = ::roundRobin.lights[::roundRobin.current] == this; + if ( ::roundRobin.current < ::roundRobin.lights.size() ) + renderMode.execute = ::roundRobin.lights[::roundRobin.current] == this; // render only if the light is used } else if ( metadata.renderer.mode == "occlusion" ) { - execute = metadata.renderer.rendered; + renderMode.execute = metadata.renderer.rendered; // light baking, but sadly re-bakes every time the command buffer is recorded } else if ( metadata.renderer.mode == "once" ) { - execute = !metadata.renderer.rendered; + renderMode.execute = !metadata.renderer.rendered; metadata.renderer.rendered = true; + } else if ( metadata.renderer.mode == "in-range" ) { + metadata.renderer.rendered = false; } } - auto& renderMode = this->getComponent(); - renderMode.execute = execute; } #if UF_ENTITY_METADATA_USE_JSON metadata.serialize(); diff --git a/ext/behaviors/noise/behavior.cpp b/ext/behaviors/noise/behavior.cpp index d946b915..5668fb6a 100644 --- a/ext/behaviors/noise/behavior.cpp +++ b/ext/behaviors/noise/behavior.cpp @@ -80,8 +80,8 @@ void ext::NoiseBehavior::initialize( uf::Object& self ) { this->callHook("entity:TextureUpdate.%UID%"); - graphic.material.attachShader(uf::io::root+"/shaders/base/vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader(uf::io::root+"/shaders/noise/frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root+"/shaders/base/base.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root+"/shaders/noise/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); } void ext::NoiseBehavior::tick( uf::Object& self ) { auto& metadata = this->getComponent(); diff --git a/ext/behaviors/player/behavior.cpp b/ext/behaviors/player/behavior.cpp index b785449f..28c2b8fe 100644 --- a/ext/behaviors/player/behavior.cpp +++ b/ext/behaviors/player/behavior.cpp @@ -40,8 +40,23 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { uf::Camera& camera = this->getComponent(); settings.mode = metadataJson["camera"]["ortho"].as() ? -1 : 1; - settings.perspective.size.x = metadataJson["camera"]["settings"]["size"]["x"].as(); - settings.perspective.size.y = metadataJson["camera"]["settings"]["size"]["y"].as(); + + settings.perspective.size = uf::vector::decode( metadataJson["camera"]["settings"]["size"], pod::Vector3f{} ); + // Update viewport + if ( settings.perspective.size.x <= 0 || settings.perspective.size.y <= 0 ) { + settings.perspective.size = uf::vector::decode( ext::config["window"]["size"], pod::Vector2ui{} ); + this->addHook( "window:Resized", [&](ext::json::Value& json){ + // Update persistent window sized (size stored to JSON file) + pod::Vector2ui size = uf::vector::decode( json["window"]["size"], pod::Vector2ui{} ); { + // size.x = json["window"]["size"]["x"].as(); + // size.y = json["window"]["size"]["y"].as(); + } + /* Update camera's viewport */ { + uf::Camera& camera = this->getComponent(); + camera.setSize({(pod::Math::num_t)size.x, (pod::Math::num_t)size.y}); + } + } ); + } camera.setSize(settings.perspective.size); if ( settings.mode < 0 ) { settings.ortho.lr.x = metadataJson["camera"]["settings"]["left"].as(); @@ -76,24 +91,8 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { transform.scale.y = metadataJson["camera"]["scale"][1].as(); transform.scale.z = metadataJson["camera"]["scale"][2].as(); } - camera.setOffset(settings.offset); camera.update(true); - - // Update viewport - if ( metadataJson["camera"]["settings"]["size"]["auto"].as() ) { - this->addHook( "window:Resized", [&](ext::json::Value& json){ - // Update persistent window sized (size stored to JSON file) - pod::Vector2ui size; { - size.x = json["window"]["size"]["x"].as(); - size.y = json["window"]["size"]["y"].as(); - } - /* Update camera's viewport */ { - uf::Camera& camera = this->getComponent(); - camera.setSize({(pod::Math::num_t)size.x, (pod::Math::num_t)size.y}); - } - } ); - } } metadataJson["system"]["control"] = true; this->addHook( "window:Mouse.CursorVisibility", [&](ext::json::Value& json){ @@ -106,8 +105,10 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { if ( !ext::json::isObject(json) ) return; if ( json["invoker"] != "client" ) return; - pod::Vector2i delta = { json["mouse"]["delta"]["x"].as(), json["mouse"]["delta"]["y"].as() }; - pod::Vector2i size = { json["mouse"]["size"]["x"].as(), json["mouse"]["size"]["y"].as() }; + // pod::Vector2i delta = { json["mouse"]["delta"]["x"].as(), json["mouse"]["delta"]["y"].as() }; + // pod::Vector2i size = { json["mouse"]["size"]["x"].as(), json["mouse"]["size"]["y"].as() }; + pod::Vector2i delta = uf::vector::decode( json["mouse"]["delta"], pod::Vector2i{} ); + pod::Vector2i size = uf::vector::decode( json["mouse"]["size"], pod::Vector2i{} ); pod::Vector2 relta = { (float) delta.x / size.x, (float) delta.y / size.y }; relta *= 2; if ( delta.x == 0 && delta.y == 0 ) return; @@ -379,10 +380,10 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { #if UF_ENTITY_METADATA_USE_JSON metadata.deserialize(); #endif - stats.floored = fabs(physics.linear.velocity.y) < 0.01f; stats.menu = metadata.system.menu; stats.impulse = metadata.system.physics.impulse; stats.noclipped = metadata.system.noclipped; + stats.floored = fabs(physics.linear.velocity.y) < 0.01f || stats.noclipped; struct { float move = 4; float walk = 1; @@ -394,6 +395,11 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { speed.move = metadata.system.physics.move; speed.run = metadata.system.physics.run / speed.move; speed.walk = metadata.system.physics.walk / speed.move; + + if ( stats.noclipped ) { + speed.move *= 4.0; + speed.run *= 2.0; + } } if ( !metadata.system.physics.collision ) { stats.impulse = true; @@ -449,23 +455,31 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( stats.floored ) { pod::Transform<> translator = transform; + #if UF_USE_OPENVR if ( ext::openvr::context ) { bool useController = true; translator.orientation = uf::quaternion::multiply( transform.orientation * pod::Vector4f{1,1,1,1}, useController ? (ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Right ) * pod::Vector4f{1,1,1,1}) : ext::openvr::hmdQuaternion() ); translator = uf::transform::reorient( translator ); - translator.forward *= { 1, 0, 1 }; - translator.right *= { 1, 0, 1 }; - + if ( !stats.noclipped ) { + translator.forward *= { 1, 0, 1 }; + translator.right *= { 1, 0, 1 }; + } + translator.forward = uf::vector::normalize( translator.forward ); translator.right = uf::vector::normalize( translator.right ); - } + } else #endif + if ( stats.noclipped ){ + auto& cameraTransform = camera.getTransform(); + // translator = uf::transform::flatten( cameraTransform ); + translator.forward.y += cameraTransform.forward.y; + } pod::Vector3f queued = {}; if ( keys.forward || keys.backwards ) { int polarity = keys.forward ? 1 : -1; - float mag = uf::vector::magnitude(physics.linear.velocity * pod::Vector3{1, 0, 1}); + float mag = uf::vector::magnitude(physics.linear.velocity); // * pod::Vector3{1, 0, 1}); if ( mag < speed.limitSquared ) { mag = uf::vector::magnitude(physics.linear.velocity + translator.forward * speed.move * polarity); } else mag = speed.limitSquared; @@ -477,17 +491,21 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( stats.impulse && stats.noclipped ) { physics.linear.velocity.x = correction.x; physics.linear.velocity.z = correction.z; + + if ( stats.noclipped ) physics.linear.velocity.y = correction.y; } else { correction *= uf::physics::time::delta; transform.position.x += correction.x; transform.position.z += correction.z; + + if ( stats.noclipped ) transform.position.y += correction.y; } } stats.updateCamera = (stats.walking = true); } if ( keys.left || keys.right ) { int polarity = keys.right ? 1 : -1; - float mag = uf::vector::magnitude(physics.linear.velocity * pod::Vector3{1, 0, 1}); + float mag = uf::vector::magnitude(physics.linear.velocity); // * pod::Vector3{1, 0, 1}); if ( mag < speed.limitSquared ) { mag = uf::vector::magnitude(physics.linear.velocity + translator.right * speed.move * polarity); } else mag = speed.limitSquared; @@ -511,6 +529,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( collider.body && !collider.shared ) { physics.linear.velocity.x = queued.x; physics.linear.velocity.z = queued.z; + + if ( stats.noclipped ) physics.linear.velocity.y = queued.y; #if UF_USE_BULLET ext::bullet::move( collider, physics.linear.velocity ); #endif @@ -520,6 +540,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( collider.body && !collider.shared ) { physics.linear.velocity.x = 0; physics.linear.velocity.z = 0; + + if ( stats.noclipped ) physics.linear.velocity.y = 0; #if UF_USE_BULLET ext::bullet::move( collider, physics.linear.velocity ); #endif diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index b096f63a..ce726e0c 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -108,9 +108,9 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { }); /* store viewport size */ this->addHook( "window:Resized", [&](ext::json::Value& json){ - pod::Vector2ui size; { - size.x = json["window"]["size"]["x"].as(); - size.y = json["window"]["size"]["y"].as(); + pod::Vector2ui size = uf::vector::decode( json["window"]["size"], pod::Vector2i{} ); { + // size.x = json["window"]["size"]["x"].as(); + // size.y = json["window"]["size"]["y"].as(); } metadataJson["system"]["window"] = json["system"]["window"]; @@ -140,7 +140,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { float high = std::numeric_limits::min(); float low = std::numeric_limits::max(); float amplitude = metadataJson["noise"]["amplitude"].is() ? metadataJson["noise"]["amplitude"].as() : 1.5; - pod::Vector3ui size = uf::vector::decode(metadataJson["noise"]["size"], pod::Vector3ui{256, 256, 256}); + pod::Vector3ui size = uf::vector::decode(metadataJson["noise"]["size"], pod::Vector3ui{64, 64, 64}); pod::Vector3d coefficients = uf::vector::decode(metadataJson["noise"]["coefficients"], pod::Vector3d{3.0, 3.0, 3.0}); std::vector pixels(size.x * size.y * size.z); @@ -169,8 +169,6 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { } texture.fromBuffers( (void*) pixels.data(), pixels.size(), uf::renderer::enums::Format::R8_UNORM, size.x, size.y, size.z, 1 ); } - // initialize voxel map - // initialize cubemap { std::vector filenames = { @@ -525,7 +523,10 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re auto& metadata = entity->getComponent(); if ( entity->hasComponent() ) { auto& renderMode = entity->getComponent(); - if ( metadata.renderer.mode == "in-range" ) renderMode.execute = false; + if ( metadata.renderer.mode == "in-range" ) { + // UF_DEBUG_MSG( renderModeName << "\t" << entity->getName() << "\t" << renderMode.execute ); + renderMode.execute = false; + } } if ( metadata.power <= 0 ) continue; LightInfo& info = entities.emplace_back(); @@ -548,12 +549,14 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re int shadowThreshold = metadata.light.shadowThreshold; if ( shadowSamples < 0 ) shadowSamples = 0; if ( shadowThreshold <= 0 ) shadowThreshold = std::numeric_limits::max(); + { std::vector scratch; scratch.reserve(entities.size()); for ( size_t i = 0; i < entities.size(); ++i ) { auto& info = entities[i]; if ( info.shadows && --shadowThreshold <= 0 ) info.shadows = false; + if ( renderModeName != "" ) info.shadows = false; scratch.emplace_back(info); } entities = scratch; @@ -610,16 +613,24 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re graphic.material.textures.clear(); if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { - for ( auto& t : sceneTextures.voxels.id ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.uv ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.normal ) graphic.material.textures.emplace_back().aliasTexture(t); - for ( auto& t : sceneTextures.voxels.radiance ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.id ) { + graphic.material.textures.emplace_back().aliasTexture(t); + } + for ( auto& t : sceneTextures.voxels.uv ) { + graphic.material.textures.emplace_back().aliasTexture(t); + } + for ( auto& t : sceneTextures.voxels.normal ) { + graphic.material.textures.emplace_back().aliasTexture(t); + } + for ( auto& t : sceneTextures.voxels.radiance ) { + graphic.material.textures.emplace_back().aliasTexture(t); + } } - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.noise); //this->getComponent()); - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.skybox); //this->getComponent()); + graphic.material.textures.emplace_back().aliasTexture(sceneTextures.noise); + graphic.material.textures.emplace_back().aliasTexture(sceneTextures.skybox); - size_t updateThreshold = metadata.light.updateThreshold; + int32_t updateThreshold = metadata.light.updateThreshold; size_t textureSlot = 0; std::vector lights; @@ -686,6 +697,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re auto& renderMode = entity->getComponent(); if ( metadata.renderer.mode == "in-range" && --updateThreshold > 0 ) { renderMode.execute = true; + // UF_DEBUG_MSG( renderModeName << "\t" << entity->getName() << "\t" << renderMode.execute ); } size_t view = 0; for ( auto& attachment : renderMode.renderTarget.attachments ) { @@ -706,6 +718,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re lights.emplace_back(light); } } + { uniforms->lengths.lights = std::min( lights.size(), metadata.max.lights ); bool shouldUpdate = graphic.material.textures.size() != previousTextures.size(); diff --git a/ext/behaviors/sprite/behavior.cpp b/ext/behaviors/sprite/behavior.cpp index 2343ffc0..1ff44412 100644 --- a/ext/behaviors/sprite/behavior.cpp +++ b/ext/behaviors/sprite/behavior.cpp @@ -82,8 +82,8 @@ void ext::HousamoSpriteBehavior::initialize( uf::Object& self ) { auto& texture = graphic.material.textures.emplace_back(); texture.loadFromImage( image ); - graphic.material.attachShader(uf::io::root+"/shaders/base/vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader(uf::io::root+"/shaders/base/frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root+"/shaders/base/base.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root+"/shaders/base/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); metadata["system"]["control"] = true; metadata["system"]["loaded"] = true; diff --git a/ext/behaviors/voxelizer/behavior.cpp b/ext/behaviors/voxelizer/behavior.cpp index a47acd80..8b57f40d 100644 --- a/ext/behaviors/voxelizer/behavior.cpp +++ b/ext/behaviors/voxelizer/behavior.cpp @@ -50,11 +50,13 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { std::vector empty(metadata.voxelSize.x * metadata.voxelSize.y * metadata.voxelSize.z * sizeof(uint8_t) * 4); + const bool HDR = false; for ( size_t i = 0; i < metadata.cascades; ++i ) { auto& id = sceneTextures.voxels.id.emplace_back(); auto& uv = sceneTextures.voxels.uv.emplace_back(); auto& normal = sceneTextures.voxels.normal.emplace_back(); auto& radiance = sceneTextures.voxels.radiance.emplace_back(); + // auto& depth = sceneTextures.voxels.depth.emplace_back(); id.sampler.descriptor.filter.min = VK_FILTER_NEAREST; id.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; @@ -62,7 +64,8 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { id.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_UINT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); uv.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); normal.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16G16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); - radiance.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); + radiance.fromBuffers( (void*) empty.data(), empty.size(), HDR ? uf::renderer::enums::Format::R16G16B16A16_SFLOAT : uf::renderer::enums::Format::R8G8B8A8_UNORM, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); + // depth.fromBuffers( (void*) empty.data(), empty.size(), uf::renderer::enums::Format::R16_SFLOAT, metadata.voxelSize.x, metadata.voxelSize.y, metadata.voxelSize.z, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); } } // initialize render mode @@ -74,7 +77,7 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { metadata.renderModeName = "VXGI:" + std::to_string((int) this->getUid()); uf::renderer::addRenderMode( &renderMode, metadata.renderModeName ); renderMode.metadata["type"] = "vxgi"; - renderMode.metadata["samples"] = 2; + renderMode.metadata["samples"] = 1; renderMode.metadata["subpasses"] = metadata.cascades; renderMode.blitter.device = &ext::vulkan::device; @@ -108,41 +111,7 @@ 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 ); - - #if 0 - 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; - } - } - #endif + // for ( auto& t : sceneTextures.voxels.depth ) vkCmdClearColorImage( commandBuffer, t.image, t.imageLayout, &clearColor, 1, &subresourceRange ); }); renderMode.bindCallback( renderMode.CALLBACK_END, [&]( VkCommandBuffer commandBuffer ){ // parse voxel lighting @@ -176,42 +145,6 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { subresourceRange ); } - - #if 0 - // 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 }); } #endif @@ -242,7 +175,12 @@ void ext::VoxelizerBehavior::tick( uf::Object& self ) { } } if ( renderMode.execute ) { - pod::Vector3f controllerPosition = controllerTransform.position; + pod::Vector3f controllerPosition = controllerTransform.position - metadata.extents.min; + controllerPosition.x = floor(controllerPosition.x); + controllerPosition.y = floor(controllerPosition.y); + controllerPosition.z = floor(controllerPosition.z); + controllerPosition += metadata.extents.min; + controllerPosition.x = floor(controllerPosition.x); controllerPosition.y = floor(controllerPosition.y); controllerPosition.z = -floor(controllerPosition.z); diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index 0d4c5073..f30ef514 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -508,9 +508,9 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { bool down = json["mouse"]["state"].as() == "Down"; bool clicked = false; if ( down ) { - pod::Vector2ui position; { - position.x = json["mouse"]["position"]["x"].as() > 0 ? json["mouse"]["position"]["x"].as() : 0; - position.y = json["mouse"]["position"]["y"].as() > 0 ? json["mouse"]["position"]["y"].as() : 0; + pod::Vector2ui position = uf::vector::decode( json["mouse"]["position"], pod::Vector2ui{} ); { + // position.x = json["mouse"]["position"]["x"].as() > 0 ? json["mouse"]["position"]["x"].as() : 0; + // position.y = json["mouse"]["position"]["y"].as() > 0 ? json["mouse"]["position"]["y"].as() : 0; } pod::Vector2f click; { click.x = (float) position.x / (float) ext::gui::size.current.x; @@ -524,8 +524,11 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { if (json["invoker"] == "vr" ) { - x = json["mouse"]["position"]["x"].as(); - y = json["mouse"]["position"]["y"].as(); + pod::Vector3f xy = uf::vector::decode( json["mouse"]["position"], pod::Vector2i{} ); + x = xy.x; + y = xy.y; + // x = json["mouse"]["position"]["x"].as(); + // y = json["mouse"]["position"]["y"].as(); } clicked = ( metadata.box.min.x <= x && metadata.box.min.y <= y && metadata.box.max.x >= x && metadata.box.max.y >= y ); } @@ -570,9 +573,9 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { bool down = json["mouse"]["state"].as() == "Down"; bool clicked = false; - pod::Vector2ui position; { - position.x = json["mouse"]["position"]["x"].as() > 0 ? json["mouse"]["position"]["x"].as() : 0; - position.y = json["mouse"]["position"]["y"].as() > 0 ? json["mouse"]["position"]["y"].as() : 0; + pod::Vector2ui position = uf::vector::decode( json["mouse"]["position"], pod::Vector2ui{} ); { + // position.x = json["mouse"]["position"]["x"].as() > 0 ? json["mouse"]["position"]["x"].as() : 0; + // position.y = json["mouse"]["position"]["y"].as() > 0 ? json["mouse"]["position"]["y"].as() : 0; } pod::Vector2f click; { click.x = (float) position.x / (float) ext::gui::size.current.x; diff --git a/ext/gui/html/behavior.cpp b/ext/gui/html/behavior.cpp index d7aca942..5ffe4cc4 100644 --- a/ext/gui/html/behavior.cpp +++ b/ext/gui/html/behavior.cpp @@ -48,8 +48,9 @@ void ext::GuiHtmlBehavior::initialize( uf::Object& self ) { size = ext::gui::size.current; } if ( size.x <= 0 && size.y <= 0 ) { - size.x = ext::config["window"]["size"]["x"].as(); - size.y = ext::config["window"]["size"]["y"].as(); + // size.x = ext::config["window"]["size"]["x"].as(); + // size.y = ext::config["window"]["size"]["y"].as(); + size = uf::vector::decode( ext::config["window"]["size"], pod::Vector2ui{} ); } page = ext::ultralight::create( page, metadata["html"].as(), size); std::string onLoad = this->formatHookName("html:Load.%UID%"); @@ -67,9 +68,9 @@ void ext::GuiHtmlBehavior::initialize( uf::Object& self ) { this->addHook( "window:Resized", [&](ext::json::Value& json){ if ( !this->hasComponent() ) return; - pod::Vector2ui size; { - size.x = json["window"]["size"]["x"].as(); - size.y = json["window"]["size"]["y"].as(); + pod::Vector2ui size = uf::vector::decode( json["window"]["size"], pod::Vector2ui{} ); { + // size.x = json["window"]["size"]["x"].as(); + // size.y = json["window"]["size"]["y"].as(); }; metadata["size"][0] = size.x; diff --git a/ext/gui/manager/behavior.cpp b/ext/gui/manager/behavior.cpp index eb9846b9..a7bb0edf 100644 --- a/ext/gui/manager/behavior.cpp +++ b/ext/gui/manager/behavior.cpp @@ -60,9 +60,9 @@ void ext::GuiManagerBehavior::initialize( uf::Object& self ) { this->addHook( "window:Resized", [&](ext::json::Value& json){ - pod::Vector2ui size; { - size.x = json["window"]["size"]["x"].as(); - size.y = json["window"]["size"]["y"].as(); + pod::Vector2ui size = uf::vector::decode( json["window"]["size"], pod::Vector2ui{} ); { + // size.x = json["window"]["size"]["x"].as(); + // size.y = json["window"]["size"]["y"].as(); } ext::gui::size.current = size; // ext::gui::size.reference = size; @@ -71,9 +71,9 @@ void ext::GuiManagerBehavior::initialize( uf::Object& self ) { bool down = json["mouse"]["state"].as() == "Down"; bool clicked = false; - pod::Vector2ui position; { - position.x = json["mouse"]["position"]["x"].as() > 0 ? json["mouse"]["position"]["x"].as() : 0; - position.y = json["mouse"]["position"]["y"].as() > 0 ? json["mouse"]["position"]["y"].as() : 0; + pod::Vector2ui position = uf::vector::decode( json["mouse"]["position"], pod::Vector2ui{} ); { + // position.x = json["mouse"]["position"]["x"].as() > 0 ? json["mouse"]["position"]["x"].as() : 0; + // position.y = json["mouse"]["position"]["y"].as() > 0 ? json["mouse"]["position"]["y"].as() : 0; } pod::Vector2f click; { click.x = (float) position.x / (float) ext::gui::size.current.x; diff --git a/ext/inits/persistence.inl b/ext/inits/persistence.inl index ef9c7264..541c2c81 100644 --- a/ext/inits/persistence.inl +++ b/ext/inits/persistence.inl @@ -9,8 +9,9 @@ uf::Serializer file; } config; /* Read from file */ if (( file.exists = config.file.readFromFile(file.filename) )) { - persistent.window.size.x = config.file["window"]["size"]["x"].as(); - persistent.window.size.y = config.file["window"]["size"]["y"].as(); + persistent.window.size = uf::vector::decode( config.file["window"]["size"], pod::Vector2ui{} ); + // persistent.window.size.x = config.file["window"]["size"]["x"].as(); + // persistent.window.size.y = config.file["window"]["size"]["y"].as(); if ( config.file["window"]["title"] != "null" ) { persistent.window.title = config.file["window"]["title"].as(); } @@ -20,8 +21,9 @@ std::string hook = "window:Resized"; json["type"] = hook; json["invoker"] = "ext"; - json["window"]["size"]["x"] = persistent.window.size.x; - json["window"]["size"]["y"] = persistent.window.size.y; + json["window"]["size"] = uf::vector::encode( persistent.window.size ); + // json["window"]["size"]["x"] = persistent.window.size.x; + // json["window"]["size"]["y"] = persistent.window.size.y; if ( persistent.window.size.x != 0 && persistent.window.size.y != 0 ) uf::hooks.call(hook, json); } diff --git a/ext/scenes/worldscape/terrain/behavior.cpp b/ext/scenes/worldscape/terrain/behavior.cpp index 0d32f6af..315a1380 100644 --- a/ext/scenes/worldscape/terrain/behavior.cpp +++ b/ext/scenes/worldscape/terrain/behavior.cpp @@ -104,8 +104,8 @@ void ext::TerrainBehavior::initialize( uf::Object& self ) { if ( _ != "" ) suffix = _ + "."; } graphic.material.initializeShaders({ - {uf::io::root+"/shaders/terrain/vert.spv", uf::renderer::enums::Shader::VERTEX}, - {uf::io::root+"/shaders/terrain/frag.spv", uf::renderer::enums::Shader::FRAGMENT} + {uf::io::root+"/shaders/terrain/base.vert.spv", uf::renderer::enums::Shader::VERTEX}, + {uf::io::root+"/shaders/terrain/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT} }); // uf::renderer::rebuildOnTickStart = false; } diff --git a/ext/scenes/worldscape/terrain/region.cpp b/ext/scenes/worldscape/terrain/region.cpp index 3b99aa09..b22f3096 100644 --- a/ext/scenes/worldscape/terrain/region.cpp +++ b/ext/scenes/worldscape/terrain/region.cpp @@ -54,8 +54,8 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { } graphic.material.initializeShaders({ - {uf::io::root+"/shaders/terrain/vert.spv", uf::renderer::enums::Shader::VERTEX}, - {uf::io::root+"/shaders/terrain/frag.spv", uf::renderer::enums::Shader::FRAGMENT} + {uf::io::root+"/shaders/terrain/base.vert.spv", uf::renderer::enums::Shader::VERTEX}, + {uf::io::root+"/shaders/terrain/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT} }); }