diff --git a/Makefile b/Makefile index 0c507da1..5c27623d 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ VULKAN_SDK_PATH += /c/VulkanSDK/1.3.224.1/ GLSLC += $(VULKAN_SDK_PATH)/Bin/glslc SPV_OPTIMIZER += $(VULKAN_SDK_PATH)/Bin/spirv-opt +SPV_LINTER += $(VULKAN_SDK_PATH)/Bin/spirv-lint # Base Engine's DLL INC_DIR += $(ENGINE_INC_DIR) LIB_DIR += $(ENGINE_LIB_DIR) @@ -343,6 +344,7 @@ endif %.spv: %.glsl $(GLSLC) --target-env=vulkan1.2 -o $@ $< + $(SPV_LINTER) $@ $(SPV_OPTIMIZER) --preserve-bindings --preserve-spec-constants -O $@ -o $@ shaders: $(TARGET_SHADERS) diff --git a/belly/bin/data/config.json b/belly/bin/data/config.json new file mode 100644 index 00000000..300234d0 --- /dev/null +++ b/belly/bin/data/config.json @@ -0,0 +1,383 @@ +{ + "engine": { + "scenes": { + "start": "SourceEngine", + "matrix": { "reverseInfinite": true }, + "meshes": { "interleaved": false }, + "lights": { "enabled": true, + "useLightmaps": false, + "max": 16, + "shadows": { + "enabled": true, + "update": 2, + "max": 4, + "samples": 1 + }, + "bloom": { + "scale": 1.0, + "strength": 0.125, + "sigma": 0.8, + "samples": 5, + "threshold": 1.0 + } + }, + "textures": { + "max": { + "2D": 1024, + "cube": 1024, + "3D": 128 + } + }, + "vxgi": { + "limiter": 0.5, + // "limiter": 0.125, + "size": 192, + "dispatch": 8, + "cascades": 3, + "cascadePower": 1.5, + "granularity": 12, + "voxelizeScale": 1, + "occlusionFalloff": 2, + "traceStartOffsetFactor": 1, + "shadows": 0, + "extents": { + "min": [ -16, -4, -16 ], + "max": [ 16, 4, 16 ] + } + }, + "rt": { + // "size": [ 1280, 720 ], + "full": false, + "filter": "nearest", + "defaultRayBounds": [ 0.5, 256.0 ], + "alphaTestOffset": 0.01, + "samples": 1, + "paths": 2, + "frameAccumulationMinimum": 0 + } + }, + "graph": { + "initial buffer elements": 131072 + }, + "ext": { + "vulkan": { + "version": 1.3, + "validation": { "enabled": true, + "filters": [ + // "0x4dae5635" // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout + + "0x609a13b" // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls) + ,"0x141cb623" // UNASSIGNED-Threading-MultipleThreads ("false-positive" multithreading) + ,"0xe5d1743c" // VUID-vkCmdDispatch-None-02699 (problem when using VXGI) + ,"0x71500fba" // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) + ,"0x35d7ea98" // VUID-vkUpdateDescriptorSets-None-03047 (bitches without VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT or VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT) + ,"0x8e1000ad" // VUID-vkCmdDrawIndexedIndirect-None-04008 (bitches without nullDescriptor) + ,"0x9dd97212" // VUID-vkCmdDrawIndexedIndirect-None-02721 (bitches without nullDescriptor) + ,"0x36481fcb" // VUID-vkCmdBindVertexBuffers-pBuffers-04001 (bitches without nullDescriptor) + ] + }, + "framebuffer": { + "msaa": 1, + "size": 1 + // "size": [ 640, 480, "NEAREST" ] + // "size": [ 1280, 720 ] + // "size": [ 960, 540 ] + // "size": [ 640, 480 ] + }, + "gpu": 1, + "experimental": { + "rebuild on tick begin": false, + "batch queue submissions": true, + "dedicated thread": false, + "memory budget": false + }, + "invariant": { + "default stage buffers": true + }, + "pipelines": { + "deferred": true, + "vsync": true, + "hdr": false, + "vxgi": false, + "culling": false, + "bloom": false, + "rt": false, + "postProcess": false, + "fsr": false + }, + "formats": { + "depth": "D32_SFLOAT", + "color": "R16G16B16A16_SFLOAT", // "R32G32B32A32_SFLOAT", + "normal": "R16G16B16A16_SFLOAT", + "position": "R16G16B16A16_SFLOAT" + }, + "versions": { + "1.0": { + "extensions": { + "instance": [], + "device": [ + "VK_KHR_swapchain" + ] + }, + "features": [ + "shaderDrawParameters", + "multiDrawIndirect", + "fillModeNonSolid", + "wideLines", + "independentBlend", + "deviceCoherentMemory", + "robustBufferAccess", + "samplerAnisotropy", + "sampleRateShading" + ], + "featureChain": [] + }, + "1.1": { + "extensions": { + "instance": [ + "VK_KHR_get_physical_device_properties2" + ,"VK_KHR_get_surface_capabilities2" + ], + "device": [ + "VK_EXT_memory_budget" + ,"VK_EXT_descriptor_indexing" + ,"VK_KHR_buffer_device_address" + ] + }, + "features": [ + "nullDescriptor" + ,"fragmentStoresAndAtomics" + ,"geometryShader" + ,"multiViewport" + ,"shaderInt16" + ,"shaderFloat16" + ,"shaderInt64" + ,"shaderFloat64" + ,"shaderSubgroupClock" + ,"shaderSampledImageArrayDynamicIndexing" + ,"shaderStorageImageArrayDynamicIndexing" + ,"shaderStorageImageMultisample" + + ,"shaderSampledImageArrayNonUniformIndexing" + ,"shaderStorageImageArrayNonUniformIndexing" + + ,"descriptorIndexing" + ,"bufferDeviceAddress" + ], + "featureChain": [ + "physicalDevice2" + ,"shaderDrawParameters" + ,"robustness" + ,"shaderClock" + + ,"descriptorIndexing" + ,"bufferDeviceAddress" + ] + }, + "1.2": { + "extensions": { + "instance": [ + "VK_KHR_get_physical_device_properties2", + "VK_KHR_get_surface_capabilities2" + ], + "device": [ + "VK_KHR_deferred_host_operations" + ,"VK_EXT_shader_viewport_index_layer" + ,"VK_KHR_spirv_1_4" + ,"VK_KHR_shader_float_controls" + ,"VK_KHR_shader_clock" + ,"VK_EXT_subgroup_size_control" + ,"VK_KHR_acceleration_structure" + ,"VK_KHR_ray_tracing_pipeline" + ,"VK_KHR_ray_query" + + // ,"VK_AMD_shader_explicit_vertex_parameter" + // ,"VK_KHR_fragment_shader_barycentric" + ] + }, + "features": [ + "hostQueryReset", + + "runtimeDescriptorArray", + "descriptorBindingVariableDescriptorCount", + + "shaderOutputViewportIndex", + "shaderOutputLayer" + ], + "featureChain": [ + "physicalDeviceVulkan12" + // for ray-tracing + ,"fragmentShaderBarycentric" + ,"rayTracingPipeline" + ,"rayQuery" + ,"accelerationStructure" + ,"subgroupSizeControl" + ] + }, + "1.3": { + "extensions": { + "instance": [], + "device": [] + }, + "features": [], + "featureChain": [] + } + } + }, + "opengl": { + "validation": { "enabled": false }, + "framebuffer": { "size": 1, "msaa": 1 }, + "experimental": { + "rebuild on tick begin": true + }, + "pipelines": { + "culling": true + }, + "experimental": { + "rebuild on tick begin": true + }, + "invariant": { + "multithreaded recording": false + }, + "formats": { + "depth": "D32_SFLOAT", + "color": "R8G8B8A8_UNORM", // "R32G32B32A32_SFLOAT", + "normal": "R16G16B16A16_SFLOAT", + "position": "R16G16B16A16_SFLOAT" + }, + "features": [], + "extensions": { "instance": [], "device": [] } + }, + "lua": { + "enabled": true, + "main": "/main.lua", + "modules": { + "json": "/json.lua" + } + }, + "json": { + "encoding": "msgpack", + "compression": "gz" + }, + "imgui": { + "enabled": false + }, + "fsr": { + "enabled": true, + "sharpness": 1, + "jitter scale": 0.0625, + "preset": "ultra" // native (1x), quality (1.5x), balanced (1.7x), performance (2.0x), ultra (3.0x) + }, + "reactphysics": { + "timescale": 0.01666666666, + "interpolate": true, + "gravity": { + "mode": "universal", + "constant": 6.67408e-11 + }, + "debug draw": { + "enabled": false, + "line width": 8, + // "layer": "Gui", + "rate": 0.0125 + } + }, + "vr" : { + "enable" : false, + "manifest": "./data/openvr_manifest.json", + "swap eyes": false, + "dominant eye": 0, + "scale": 1.0 + }, + "ultralight": { "enabled": true, "scale": 1.5 }, + "discord": { "enabled": false } + }, + "audio": { + "mute": false, + "buffers": { + "size": 32768, + "count": 4 + }, + "volumes": { + "sfx": 0.35, + "bgm": 0.15, + "voice": 1.0 + }, + "streams by default": true + }, + "memory pool": { + "enabled": true, + "subPools": true, + "alignment": 64, + "override": false, + "size": "512 MiB", + "pools": { + "entity": "128 MiB", + "userdata": "128 MiB", + "component": "128 MiB" + } + }, + "render modes": { "gui": true, "deferred": true }, + "limiters": { + "deltaTime": 5, + "framerate": 0 // "auto" + }, + "threads": { + "workers" : "auto", + "frame limiter": 0 // "auto" + }, + "debug": { + "framerate": { + "print": true, + "every": 2 + }, + "garbage collection": { + "enabled": true, + "mode": 1, + "rate": 4, + "announce": true + }, + "entity": { + "delete children on destroy": false, + "delete components on destroy": false + }, + "userdata": { + "auto destruct": true, + "auto validate": false + }, + "loader": { + "assert": true + }, + "hooks": { + "defer lazy calls": true + }, + "scene": { + "print task calls": false + } + } + }, + "window" : { + "terminal" : { + "ncurses" : false, + "visible" : true + }, + "keyboard" : { + "repeat" : false + }, + "cursor" : { + "visible" : true, + "center" : false, + "sensitivity": [ 0.75, 0.75 ], + "smoothing": [ 4, 4 ] + }, + "mode" : "windowed", // fullscreen, borderless, windowed + "icon" : "./data/textures/icon.png", + // "size" : [ 1920, 1080 ], + // "size" : [ 1280, 720 ], + "size" : [ 960, 540 ], + // "size" : [ 640, 480 ], + // "size" : [ 256, 224 ], + "title" : "Grimgram", + "visible" : true + } +} \ No newline at end of file diff --git a/belly/bin/data/shaders/base/line/frag.glsl b/belly/bin/data/shaders/base/line/frag.glsl new file mode 100644 index 00000000..935d731a --- /dev/null +++ b/belly/bin/data/shaders/base/line/frag.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(fragment) + +layout (location = 0) in vec3 inPosition; +layout (location = 1) in vec3 inColor; + +layout (location = 0) out uvec2 outId; +layout (location = 1) out vec2 outNormals; +layout (location = 2) out vec4 outAlbedo; + +void main() { + outAlbedo = vec4(inColor, 1); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/base/line/vert.glsl b/belly/bin/data/shaders/base/line/vert.glsl new file mode 100644 index 00000000..32b9484c --- /dev/null +++ b/belly/bin/data/shaders/base/line/vert.glsl @@ -0,0 +1,29 @@ +#version 450 +#pragma shader_stage(vertex) + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (constant_id = 0) const uint PASSES = 6; + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inColor; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; + +layout (location = 0) out vec3 outPosition; +layout (location = 1) out vec3 outColor; + +void main() { + outPosition = vec3(camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0)); + outColor = inColor; + + gl_Position = camera.viewport[PushConstant.pass].projection * camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/common/fog.h b/belly/bin/data/shaders/common/fog.h new file mode 100644 index 00000000..7c62eff2 --- /dev/null +++ b/belly/bin/data/shaders/common/fog.h @@ -0,0 +1,56 @@ +// Perlin Fog +void fog( in Ray ray, inout vec3 i, float scale ) { + if ( ubo.settings.fog.stepScale <= 0 || ubo.settings.fog.range.x == 0 || ubo.settings.fog.range.y == 0 ) return; +#if FOG_RAY_MARCH + const float range = ubo.settings.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.settings.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 = 0; // 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.settings.fog.densityScale * 0.001 + ubo.settings.fog.offset * 0.01; + density = max(0, textureLod(samplerNoise, uvw, level).r - ubo.settings.fog.densityThreshold) * ubo.settings.fog.densityMultiplier; + if ( density > 0 ) { + density = exp(-density * stepSize * ubo.settings.fog.absorbtion); + transmittance *= density; + lightFactor *= density; + if ( transmittance < 0.1 ) break; + } + } + i.rgb = mix(ubo.settings.fog.color.rgb, i.rgb, transmittance ); + } +#endif +#if FOG_BASIC + const vec3 color = ubo.settings.fog.color.rgb; + const float inner = ubo.settings.fog.range.x; + const float outer = ubo.settings.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/belly/bin/data/shaders/common/functions.h b/belly/bin/data/shaders/common/functions.h new file mode 100644 index 00000000..45b85f9f --- /dev/null +++ b/belly/bin/data/shaders/common/functions.h @@ -0,0 +1,419 @@ +// 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 mipLevel( in vec2 dx_vtc, in vec2 dy_vtc ) { + const float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)); + return 0.5 * log2(delta_max_sqr); +// return max(0.0, 0.5 * log2(delta_max_sqr) - 1.0); + +// return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); +} +float mipLevels( vec2 size ) { + return floor(log2(max(size.x, size.y))); +} +float mipLevels( ivec2 size ) { + return floor(log2(max(size.x, size.y))); +} +// +void toneMap( inout vec3 color, float exposure ) { + color.rgb = vec3(1.0) - exp(-color.rgb * exposure); +} +void gammaCorrect( inout vec3 color, float gamma ) { + color.rgb = pow(color.rgb, vec3(1.0 / gamma)); +} +void toneMap( inout vec4 color, float exposure ) { toneMap(color.rgb, exposure); } +void gammaCorrect( inout vec4 color, float gamma ) { gammaCorrect(color.rgb, gamma); } +// +uint tea(uint val0, uint val1) { + uint v0 = val0; + uint v1 = val1; + uint s0 = 0; + + #pragma unroll 16 + for(uint n = 0; n < 16; n++) { + s0 += 0x9e3779b9; + v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); + v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); + } + return v0; +} +uint lcg(inout uint prev) { + uint LCG_A = 1664525u; + uint LCG_C = 1013904223u; + prev = (LCG_A * prev + LCG_C); + return prev & 0x00FFFFFF; +} +float rnd(inout uint prev) { return (float(lcg(prev)) / float(0x01000000)); } + +uint prngSeed; +float rnd() { return rnd(prngSeed); } +// +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 tangentBitangent(in vec3 N, out vec3 Nt, out vec3 Nb) { + if(abs(N.x) > abs(N.y)) Nt = vec3(N.z, 0, -N.x) / sqrt(N.x * N.x + N.z * N.z); + else Nt = vec3(0, -N.z, N.y) / sqrt(N.y * N.y + N.z * N.z); + Nb = cross(N, Nt); +} +vec3 samplingHemisphere(inout uint seed, in vec3 x, in vec3 y, in vec3 z) { + float r1 = rnd(seed); + float r2 = rnd(seed); + float sq = sqrt(1.0 - r2); + vec3 direction = vec3(cos(2 * PI * r1) * sq, sin(2 * PI * r1) * sq, sqrt(r2)); + direction = direction.x * x + direction.y * y + direction.z * z; + return direction; +} +vec3 samplingHemisphere(inout uint seed, in vec3 z) { + vec3 x; + vec3 y; + tangentBitangent( z, x, y ); + + float r1 = rnd(seed); + float r2 = rnd(seed); + float sq = sqrt(1.0 - r2); + vec3 direction = vec3(cos(2 * PI * r1) * sq, sin(2 * PI * r1) * sq, sqrt(r2)); + direction = direction.x * x + direction.y * y + direction.z * z; + return direction; +} +// +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); +} +vec4 blend( vec4 source, vec4 dest, float a ) { + return source * a + dest * (1.0 - a); +} +float gauss( float x, float sigma ) { + return (1.0 / (2.0 * 3.14157 * sigma) * exp(-(x*x) / (2.0 * sigma))); +} +bool enabled( uint flag, uint bit ) { + return (flag & (1 << bit)) != 0; +} +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; +} +vec3 encodeSrgb(vec3 rgb) { + const vec3 a = 12.92 * rgb; + const vec3 b = 1.055 * pow(rgb, vec3(1.0 / 2.4)) - 0.055; + const vec3 c = step(vec3(0.0031308), rgb); + return mix(a, b, c); +} + +vec3 decodeSrgb(vec3 rgb) { + const vec3 a = rgb / 12.92; + const vec3 b = pow((rgb + 0.055) / 1.055, vec3(2.4)); + const vec3 c = step(vec3(0.04045), rgb); + return mix(a, b, c); +} +bool validTextureIndex( int textureIndex ) { + return 0 <= textureIndex && textureIndex < MAX_TEXTURES; +} +#if MAX_CUBEMAPS +bool validCubemapIndex( int textureIndex ) { + return 0 <= textureIndex && textureIndex < MAX_CUBEMAPS; +} +#endif +#if !BLOOM && (DEFERRED || FRAGMENT || COMPUTE || RT) +bool validTextureIndex( uint id ) { + return 0 <= id && id < MAX_TEXTURES; +} +bool validTextureIndex( uint start, int offset ) { + return 0 <= offset && start + offset < MAX_TEXTURES; +} +uint textureIndex( uint start, int offset ) { + return start + offset; +} +vec4 sampleTexture( uint id, vec2 uv ) { + const Texture t = textures[id]; + return texture( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ) ); +} +vec4 sampleTexture( uint id, vec2 uv, float mip ) { +#if QUERY_MIPMAP + return sampleTexture( id, uv ); +#else + const Texture t = textures[id]; + return textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip ); +#endif +} +vec4 sampleTexture( uint id, vec3 uvm ) { return sampleTexture( id, uvm.xy, uvm.z ); } +vec4 sampleTexture( uint id ) { return sampleTexture( id, surface.uv.xy, surface.uv.z ); } +vec4 sampleTexture( uint id, float mip ) { return sampleTexture( id, surface.uv.xy, mip ); } +#endif +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); +} +#if VXGI +float cascadePower( uint x ) { + return pow(1 + x, ubo.settings.vxgi.cascadePower); +// return max( 1, x * ubo.settings.vxgi.cascadePower ); +} +#endif +#if FRAGMENT +void whitenoise(inout vec3 color, const vec4 parameters) { + const float flicker = parameters.x; + 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 ); +} +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; +} +#endif +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; +} +// + +vec2 encodeBarycentrics( vec3 barycentric ) { + return barycentric.yz; +} +vec3 decodeBarycentrics( vec2 attributes ) { + return vec3( + 1.0 - attributes.x - attributes.y, + attributes.x, + attributes.y + ); +} +#if DEFERRED_SAMPLING +void populateSurfaceMaterial() { + const Material material = materials[surface.instance.materialID]; + surface.material.albedo = material.colorBase; + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; + surface.light = material.colorEmissive; + + if ( validTextureIndex( material.indexAlbedo ) ) { + surface.material.albedo *= sampleTexture( material.indexAlbedo ); + } + // OPAQUE + if ( material.modeAlpha == 0 ) { + surface.material.albedo.a = 1; + // BLEND + } else if ( material.modeAlpha == 1 ) { + + // MASK + } else if ( material.modeAlpha == 2 ) { + + } + // Lightmap + if ( (/*surface.subID++ > 0 ||*/ bool(ubo.settings.lighting.useLightmaps)) && validTextureIndex( surface.instance.lightmapID ) ) { + vec4 light = sampleTexture( surface.instance.lightmapID, surface.st ); + /*surface.material.lightmapped = light.a > 0.000000001; + if ( surface.material.lightmapped )*/ surface.light += surface.material.albedo * light; + } else { + surface.material.lightmapped = false; + } + // Emissive textures + if ( validTextureIndex( material.indexEmissive ) ) { + surface.light += sampleTexture( material.indexEmissive ); + } + // Occlusion map + if ( validTextureIndex( material.indexOcclusion ) ) { + surface.material.occlusion = sampleTexture( material.indexOcclusion ).r; + } + // Metallic/Roughness map + if ( validTextureIndex( material.indexMetallicRoughness ) ) { + vec4 samp = sampleTexture( material.indexMetallicRoughness ); + surface.material.metallic = samp.r; + surface.material.roughness = samp.g; + } + // Normals + if ( validTextureIndex( material.indexNormal ) && surface.tangent.world != vec3(0) ) { + surface.normal.world = surface.tbn * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - vec3(1.0)); + } + { + surface.normal.eye = normalize(vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) )); + } + + surface.light *= surface.material.albedo; +} + +bool isValidAddress( uint64_t address ) { +#if UINT64_ENABLED + return bool(address); +#else + return bool(address.x) && bool(address.y); +#endif +} + +#if BUFFER_REFERENCE +void populateSurface( InstanceAddresses instanceAddresses, uvec3 indices ) { + Triangle triangle; + Vertex points[3]; + + if ( isValidAddress(instanceAddresses.vertex) ) { + Vertices vertices = Vertices(nonuniformEXT(instanceAddresses.vertex)); + + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_] = vertices.v[/*triangle.*/indices[_]]; + } else { + if ( isValidAddress(instanceAddresses.position) ) { + VPos buf = VPos(nonuniformEXT(instanceAddresses.position)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].position = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.uv) ) { + VUv buf = VUv(nonuniformEXT(instanceAddresses.uv)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].uv = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.st) ) { + VSt buf = VSt(nonuniformEXT(instanceAddresses.st)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].st = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.normal) ) { + VNormal buf = VNormal(nonuniformEXT(instanceAddresses.normal)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].normal = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.tangent) ) { + VTangent buf = VTangent(nonuniformEXT(instanceAddresses.tangent)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].tangent = buf.v[/*triangle.*/indices[_]]; + } + } + +#if BARYCENTRIC_CALCULATE + { + const vec3 p = vec3(inverse( surface.instance.model ) * vec4(surface.position.world, 1)); + + const vec3 a = points[0].position; + const vec3 b = points[1].position; + const vec3 c = points[2].position; + + const vec3 v0 = b - a; + const vec3 v1 = c - a; + const vec3 v2 = p - a; + const float d00 = dot(v0, v0); + const float d01 = dot(v0, v1); + const float d11 = dot(v1, v1); + const float d20 = dot(v2, v0); + const float d21 = dot(v2, v1); + const float denom = d00 * d11 - d01 * d01; + + const float v = (d11 * d20 - d01 * d21) / denom; + const float w = (d00 * d21 - d01 * d20) / denom; + const float u = 1.0f - v - w; + + surface.barycentric = vec3( u, v, w ); + } +#endif + + triangle.geomNormal = normalize(cross(points[1].position - points[0].position, points[2].position - points[0].position)); + triangle.point.normal = /*triangle.*/points[0].normal * surface.barycentric[0] + /*triangle.*/points[1].normal * surface.barycentric[1] + /*triangle.*/points[2].normal * surface.barycentric[2]; + + triangle.point.position = /*triangle.*/points[0].position * surface.barycentric[0] + /*triangle.*/points[1].position * surface.barycentric[1] + /*triangle.*/points[2].position * surface.barycentric[2]; + triangle.point.uv = /*triangle.*/points[0].uv * surface.barycentric[0] + /*triangle.*/points[1].uv * surface.barycentric[1] + /*triangle.*/points[2].uv * surface.barycentric[2]; + triangle.point.st = /*triangle.*/points[0].st * surface.barycentric[0] + /*triangle.*/points[1].st * surface.barycentric[1] + /*triangle.*/points[2].st * surface.barycentric[2]; + triangle.point.tangent = /*triangle.*/points[0].tangent * surface.barycentric[0] + /*triangle.*/points[1].tangent * surface.barycentric[1] + /*triangle.*/points[2].tangent * surface.barycentric[2]; + + + if ( triangle.point.tangent != vec3(0) ) { + surface.tangent.world = normalize(vec3( surface.instance.model * vec4(triangle.point.tangent, 0.0) )); + vec3 bitangent = normalize(vec3( surface.instance.model * vec4(cross( triangle.point.normal, triangle.point.tangent ), 0.0) )); + surface.tbn = mat3(surface.tangent.world, bitangent, triangle.point.normal); + } + + // bind position +#if 1 || BARYCENTRIC_CALCULATE + { + surface.position.world = vec3( surface.instance.model * vec4(triangle.point.position, 1.0 ) ); + surface.position.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.position.world, 1.0) ); + } +#endif + // bind normals + { + surface.normal.world = normalize(vec3( surface.instance.model * vec4(triangle.point.normal, 0.0 ) )); + // surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) ); + } + // bind UVs + { + surface.uv.xy = triangle.point.uv; + surface.uv.z = 0; + surface.st.xy = triangle.point.st; + surface.st.z = 0; + } + + populateSurfaceMaterial(); +} +void populateSurface( uint instanceID, uint primitiveID ) { + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.instance = instances[instanceID]; + + const InstanceAddresses instanceAddresses = instanceAddresses[instanceID]; + if ( !isValidAddress(instanceAddresses.index) ) return; + const DrawCommand drawCommand = Indirects(nonuniformEXT(instanceAddresses.indirect)).dc[instanceAddresses.drawID]; + const uint triangleID = primitiveID + (drawCommand.indexID / 3); + uvec3 indices = Indices(nonuniformEXT(instanceAddresses.index)).i[triangleID]; + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/indices[_] += drawCommand.vertexID; + + populateSurface( instanceAddresses, indices ); +} +void populateSurface( RayTracePayload payload ) { + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.instance = instances[payload.instanceID]; + + if ( !payload.hit ) return; + surface.barycentric = decodeBarycentrics(payload.attributes); + populateSurface( payload.instanceID, payload.primitiveID ); +} +#endif +#endif \ No newline at end of file diff --git a/belly/bin/data/shaders/common/lambert.h b/belly/bin/data/shaders/common/lambert.h new file mode 100644 index 00000000..eed6391e --- /dev/null +++ b/belly/bin/data/shaders/common/lambert.h @@ -0,0 +1,66 @@ +float shadowFactor( const Light light, float def ); +void lambert() { + // outcoming light from surface to eye + const vec3 Lo = normalize( -surface.position.eye ); + // angle of outcoming light + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); + + for ( uint i = 0, shadows = 0; i < MAX_LIGHTS; ++i ) { + #if BAKING + // skip if surface is a dynamic light, we aren't baking dynamic lights + if ( lights[i].type < 0 ) continue; + #else + // skip if surface is already baked, and this isn't a dynamic light + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + #endif + if ( lights[i].power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + + vec3 Li = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + // magnitude of incoming light vector (for inverse-square attenuation) + const float Lmagnitude = dot(Li, Li); + // distance incoming light travels (reuse from above) + const float Ldistance = sqrt(Lmagnitude); + // "free" normalization, since we need to compute the above values anyways + Li = Li / Ldistance; + // attenuation factor + // const float Lattenuation = 1.0 / (1 + (PI * Lmagnitude)); + const float Lattenuation = 1.0 / (1 + Lmagnitude); + // skip if attenuation factor is too low + // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; + // ray cast if our surface is occluded from the light + const float Lshadow = 1; // ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // skip if our shadow factor is too low + if ( Lshadow <= LIGHT_POWER_CUTOFF ) continue; + // light radiance + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // skip if our radiance is too low + // if ( Lr <= LIGHT_POWER_CUTOFF ) continue; + // halfway vector + const vec3 Lh = normalize(Li + Lo); + // angle of incoming light + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + // angle of halfway light vector + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); +/* + const vec3 Liu = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + const vec3 Li = normalize(Liu); + // const float Lattenuation = 1.0 / (PI * pow(length(Liu), 2.0)); + // const float Lattenuation = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + const float Lattenuation = 1.0 / (1 + pow(length(Liu), 2.0)); + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + if ( lights[i].power * Lattenuation * Lshadow <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // const vec3 Lh = normalize(Li + Lo); + // const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); +*/ + + const vec3 diffuse = surface.material.albedo.rgb; + const vec3 specular = vec3(0); + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += lights[i].power * Lattenuation * Lshadow; + } +} \ No newline at end of file diff --git a/belly/bin/data/shaders/common/light.h b/belly/bin/data/shaders/common/light.h new file mode 100644 index 00000000..0dbfe75c --- /dev/null +++ b/belly/bin/data/shaders/common/light.h @@ -0,0 +1,11 @@ +float shadowFactor( const Light light, float def ); + +#if PBR + #include "../common/pbr.h" +#endif +#if LAMBERT + #include "../common/lambert.h" +#endif +#if PHONG + #include "../common/phong.h" +#endif \ No newline at end of file diff --git a/belly/bin/data/shaders/common/macros.h b/belly/bin/data/shaders/common/macros.h new file mode 100644 index 00000000..03e97e50 --- /dev/null +++ b/belly/bin/data/shaders/common/macros.h @@ -0,0 +1,104 @@ +#ifndef NO_NONUNIFORM_EXT + #define NO_NONUNIFORM_EXT 0 + // enable if shaderNonUniform is not supported + // Nvidia hardware does not require nonuniformEXT, but AMD does +#endif + +// implicit variables +#ifndef MULTISAMPLING + #define MULTISAMPLING 1 +#endif +#ifndef MAX_MSAA_SAMPLES + #define MAX_MSAA_SAMPLES 16 +#endif +#ifndef MAX_TEXTURES + #define MAX_TEXTURES TEXTURES +#endif +#ifndef MAX_LIGHTS + #define MAX_LIGHTS ubo.settings.lengths.lights +#endif +#ifndef MAX_SHADOWS + #define MAX_SHADOWS ubo.settings.lighting.maxShadows +#endif +#ifndef VIEW_MATRIX + #define VIEW_MATRIX ubo.eyes[surface.pass].view +#endif + +// implicit shader settings +#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 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 PHONG + #define PHONG 0 +#endif +#ifndef LAMBERT + #define LAMBERT 0 +#endif +#ifndef PBR + #define PBR 1 +#endif +*/ + +#if NO_NONUNIFORM_EXT + #define nonuniformEXT(X) X +#else + #extension GL_EXT_nonuniform_qualifier : enable +#endif + +#if !UINT64_ENABLED + #define uint64_t uvec2 +#endif + +// easy and accessible in one place +#ifndef BARYCENTRIC + #define BARYCENTRIC 0 +#endif +#if BARYCENTRIC + #ifndef BARYCENTRIC_CALCULATE + #define BARYCENTRIC_CALCULATE 0 + #endif +#endif + +#if BUFFER_REFERENCE + #extension GL_EXT_scalar_block_layout : enable + #extension GL_EXT_buffer_reference : enable + #extension GL_EXT_buffer_reference2 : enable + #if UINT64_ENABLED + #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable + #else + #extension GL_EXT_buffer_reference_uvec2 : enable + #endif +#endif + +const float PI = 3.14159265359; +const float EPSILON = 0.00001; +const float SQRT2 = 1.41421356237; + +const float LIGHT_POWER_CUTOFF = 0.0005; +const float LIGHTMAP_GAMMA = 1.0; + +#define SETTINGS_TYPE_FULLBRIGHT 0x10 \ No newline at end of file diff --git a/belly/bin/data/shaders/common/pbr.h b/belly/bin/data/shaders/common/pbr.h new file mode 100644 index 00000000..a9896c54 --- /dev/null +++ b/belly/bin/data/shaders/common/pbr.h @@ -0,0 +1,121 @@ +// PBR +void pbr() { + // per-surface, not per-light, compute once + + // Freslen reflectance for a dieletric + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + // outcoming light from surface to eye + const vec3 Lo = normalize( -surface.position.eye ); + // angle of outcoming light + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); + + const float Rs = 4.0; + + for ( uint i = 0, shadows = 0; i < MAX_LIGHTS; ++i ) { + #if BAKING + // skip if surface is a dynamic light, we aren't baking dynamic lights + if ( lights[i].type < 0 ) continue; + #else + // skip if surface is already baked, and this isn't a dynamic light + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + #endif + /* + // skip if light power is too low + if ( lights[i].power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + + const vec3 Liu = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + const vec3 Li = normalize(Liu); + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // const float Lattenuation = 1.0 / (PI * pow(length(Liu), 2.0)); + // const float Lattenuation = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + const float Lattenuation = 1.0 / (1 + pow(length(Liu), 2.0)); + if ( lights[i].power * Lattenuation * Lshadow <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); + */ + // incoming light to surface (non-const to normalize it later) + // vec3 Li = lights[i].position - surface.position.world; + vec3 Li = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + // magnitude of incoming light vector (for inverse-square attenuation) + const float Lmagnitude = dot(Li, Li); + // distance incoming light travels (reuse from above) + const float Ldistance = sqrt(Lmagnitude); + // "free" normalization, since we need to compute the above values anyways + Li = Li / Ldistance; + // attenuation factor + // const float Lattenuation = 1.0 / (1 + (PI * Lmagnitude)); + const float Lattenuation = 1.0 / (1 + Lmagnitude); + // skip if attenuation factor is too low + // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; + // ray cast if our surface is occluded from the light + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // skip if our shadow factor is too low + if ( Lshadow <= LIGHT_POWER_CUTOFF ) continue; + // light radiance + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // skip if our radiance is too low + // if ( Lr <= LIGHT_POWER_CUTOFF ) continue; + // halfway vector + const vec3 Lh = normalize(Li + Lo); + // angle of incoming light + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + // angle of halfway light vector + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); + + // Fresnel term for direct lighting + const vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, Lo))); + // Distribution for specular lighting + const float D = ndfGGX( cosLh, surface.material.roughness * Rs); + // Geometric attenuation for specular lighting + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness * Rs); + + // final lighting + const vec3 diffuse = mix(vec3(1.0) - F, vec3(0), surface.material.metallic) * surface.material.albedo.rgb; + const vec3 specular = ( shadows < MAX_SHADOWS ) ? ((F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo)) : vec3(0); + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += lights[i].power * Lattenuation * Lshadow; + } +#if 0 + const float Rs = 4.0; // specular lighting looks gross without this + uint shadows = 0; + for ( uint i = 0; i < ubo.settings.lengths.lights; ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && light.type >= 0 ) continue; + + const vec3 Liu = vec3(ubo.eyes[surface.pass].view * vec4(light.position, 1)) - surface.position.eye; + const float Ld = length(Liu); + const float La = 1.0 / (1 + (PI * pow(Ld, 2.0))); + if ( La <= LIGHT_POWER_CUTOFF ) continue; + + const vec3 Li = normalize(Liu); + const float Ls = ( shadows++ < ubo.settings.lighting.maxShadows ) ? shadowFactor( light, 0.0 ) : 1; + 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; + 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); + /* + // lightmapped, compute only specular + if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.light.rgb += (specular) * Lr * cosLi; + // point light, compute only diffuse + // else if ( abs(light.type) == 1 ) surface.light.rgb += (diffuse) * Lr * cosLi; + else surface.light.rgb += (diffuse + specular) * Lr * cosLi; + */ + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } +#endif +} \ No newline at end of file diff --git a/belly/bin/data/shaders/common/shadows.h b/belly/bin/data/shaders/common/shadows.h new file mode 100644 index 00000000..20100334 --- /dev/null +++ b/belly/bin/data/shaders/common/shadows.h @@ -0,0 +1,171 @@ +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.settings.lighting.shadowSamples +#endif +#if VXGI + float voxelShadowFactor( const Light, float def ); +#endif + +#if CUBEMAPS +float omniShadowMap( const Light light, float def ) { + return 1.0; +} +#else +float omniShadowMap( const Light light, float def ) { + float factor = 1.0; + + const mat4 views[6] = { + mat4( 0, 0, 1, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 1 ), + mat4( 0, 0,-1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ), + mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 1 ), + }; + + const vec3 D = normalize(surface.position.world - light.position); + const vec3 N = abs(D); + uint A = N.y > N.x ? 1 : 0; + A = N.z > N[A] ? 2 : A; + uint index = A * 2; + if ( D[A] < 0.0 ) ++index; + + vec4 positionClip = light.projection * views[index] * vec4(surface.position.world - light.position, 1.0); + positionClip.xy /= 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 < -1 || positionClip.z >= 1 ) return 0.0; + + const float eyeDepthScale = 1.0; + const float sampledDepthScale = light.view[1][1]; // light view matricies will incorporate scaling factors for some retarded reason, so we need to rescale it by grabbing from here, hopefully it remains coherent between all light matrices to ever exist in engine + + const float bias = light.depthBias; + const float eyeDepth = abs(positionClip.z / positionClip.w) * eyeDepthScale; + + const vec3 sampleOffsetDirections[20] = { + vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), + vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), + vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), + vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), + vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) + }; + + float sampled = 0; + const int samples = int(SHADOW_SAMPLES); + // cubemap point light + if ( light.typeMap == 1 ) { + if ( samples < 1 ) { + sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D).r * sampledDepthScale; + } else { + for ( int i = 0; i < samples; ++i ) { + const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; + vec2 poisson = poissonDisk[idx] / 700.0; + vec3 P = vec3( poisson.xy, (poisson.x + poisson.y) * 0.5 ); + sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D + P ).r * sampledDepthScale; + if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples; + } + return factor; + } + // separated point lights + } else if ( light.typeMap == 2 ) { + const vec2 uv = positionClip.xy * 0.5 + 0.5; + if ( samples < 1 ) { + sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv).r * sampledDepthScale; + } else { + for ( int i = 0; i < samples; ++i ) { + const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; + sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv + poissonDisk[idx] / 700.0 ).r * sampledDepthScale; + if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples; + } + return factor; + } + } + return eyeDepth < sampled - bias ? 0.0 : factor; +} +#endif +#if RT +float shadowFactorRT( const Light light, float def ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = light.position - ray.origin; + + float tMin = ubo.settings.rt.defaultRayBounds.x; + float tMax = length(ray.direction) - ubo.settings.rt.defaultRayBounds.x; + + ray.direction = normalize(ray.direction); + + uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT; + uint cullMask = 0xFF; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, tlas, rayFlags, cullMask, ray.origin, tMin, ray.direction, tMax); + + while(rayQueryProceedEXT(rayQuery)); + + return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT ? 1.0 : 0.0; +} +#endif +float shadowFactor( const Light light, float def ) { +#if RT + return shadowFactorRT( light, def ); +#endif + if ( light.typeMap != 0 ) return omniShadowMap( light, def ); + + if ( !validTextureIndex(light.indexMap) ) + #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.indexMap)], 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.indexMap)], 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/belly/bin/data/shaders/common/structs.h b/belly/bin/data/shaders/common/structs.h new file mode 100644 index 00000000..c8e35fb5 --- /dev/null +++ b/belly/bin/data/shaders/common/structs.h @@ -0,0 +1,308 @@ +struct EyeMatrices { + mat4 view; + mat4 projection; + + mat4 model; + mat4 previous; + + mat4 iView; + mat4 iProjection; + + vec4 eyePos; +}; + +struct Viewport { + mat4 view; + mat4 projection; +}; + +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 Light { + mat4 view; + mat4 projection; + + vec3 position; + float radius; + + vec3 color; + float power; + + int type; + int typeMap; + int indexMap; + float depthBias; +}; + +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 padding1; + int padding2; + int modeAlpha; +}; + +struct Texture { + int index; + int samp; + int remap; + float blend; + + vec4 lerp; +}; + +struct DrawCommand { + uint indices; // triangle count + uint instances; // instance count + uint indexID; // starting triangle position + int vertexID; // starting vertex position + + uint instanceID; // starting instance position + float padding1; // + float padding2; // material to use for this draw call + uint vertices; // number of vertices used +}; + +struct Bounds { + vec3 min; + float padding1; + vec3 max; + float padding2; +}; + +struct Instance { + mat4 model; + mat4 previous; + + vec4 color; + + uint materialID; + uint primitiveID; + uint meshID; + uint objectID; + + int jointID; + int lightmapID; + uint imageID; + uint auxID; + + Bounds bounds; +// InstanceAddresses addresses; +}; + +struct InstanceAddresses { + uint64_t vertex; + uint64_t index; + + uint64_t indirect; + uint drawID; + uint padding0; + + uint64_t position; + uint64_t uv; + + uint64_t color; + uint64_t st; + + uint64_t normal; + uint64_t tangent; + + uint64_t joints; + uint64_t weights; + + uint64_t id; + uint64_t padding1; +}; + +struct SurfaceMaterial { + vec4 albedo; + vec4 indirect; + + float metallic; + float roughness; + float occlusion; + bool lightmapped; +}; + +struct Surface { + uint pass; + uint subID; + + vec3 uv; + vec3 st; + Space position; + Space normal; + Space tangent; + mat3 tbn; + vec3 barycentric; + vec2 motion; + + Ray ray; + + SurfaceMaterial material; + Instance instance; + + vec4 light; + vec4 fragment; +} surface; + +// MSAA info +#if MULTISAMPLING +struct MSAA { + int currentID; + uvec2 IDs[MAX_MSAA_SAMPLES]; + vec4 fragment; + vec4 fragments[MAX_MSAA_SAMPLES]; +} msaa; +#endif +// UBO settings +struct SettingsLengths { + uint lights; + uint materials; + uint textures; + uint drawCommands; +}; +struct SettingsMode { + vec4 parameters; + uint type; + uint scalar; + uint msaa; + uint frameNumber; +}; +struct SettingsLighting { + vec3 ambient; + uint indexSkybox; + + uint maxShadows; + uint shadowSamples; + uint useLightmaps; +}; +struct SettingsFog { + vec3 color; + float stepScale; + + vec3 offset; + float densityScale; + + vec2 range; + float densityThreshold; + float densityMultiplier; + + float absorbtion; + float padding1; + float padding2; + float padding3; +}; +struct SettingsBloom { + float exposure; + float gamma; + float threshold; + uint padding; +}; +struct SettingsVxgi { + mat4 matrix; + + float cascadePower; + float granularity; + float voxelizeScale; + float occlusionFalloff; + + float traceStartOffsetFactor; + uint shadows; + uint padding2; + uint padding3; +}; +struct SettingsRayTrace { + vec2 defaultRayBounds; + float alphaTestOffset; + float padding1; + + uint samples; + uint paths; + uint frameAccumulationMinimum; + uint padding2; +}; + +struct Settings { + SettingsLengths lengths; + SettingsMode mode; + SettingsLighting lighting; + SettingsFog fog; + SettingsBloom bloom; + SettingsVxgi vxgi; + SettingsRayTrace rt; +}; +struct Voxel { + uvec2 id; + vec3 position; + vec3 normal; + vec2 uv; + vec4 color; +}; +struct VoxelInfo { + vec3 min; + vec3 max; + + float mipmapLevels; + float radianceSize; + float radianceSizeRecip; +} voxelInfo; + +// Raytrace stuff + +struct Vertex { + vec3 position; + vec2 uv; + uint color; + vec2 st; + vec3 normal; + vec3 tangent; + uvec2 joints; + vec4 weights; + uint id; +}; + +struct Triangle { + Vertex point; + + vec3 geomNormal; + + uint instanceID; +}; + +struct RayTracePayload { + bool hit; + uint instanceID; + uint primitiveID; + vec2 attributes; +// Triangle triangle; +}; \ No newline at end of file diff --git a/belly/bin/data/shaders/common/vxgi.h b/belly/bin/data/shaders/common/vxgi.h new file mode 100644 index 00000000..83621d1b --- /dev/null +++ b/belly/bin/data/shaders/common/vxgi.h @@ -0,0 +1,189 @@ +// GI +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.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) ); + ray.direction = vec3( ubo.settings.vxgi.matrix * vec4( ray.direction, 0.0 ) ); + uint cascade = cascadeIndex(ray.origin); +#else + uint cascade = cascadeIndex( vec3( ubo.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) ) ); +#endif + const float granularityRecip = ubo.settings.vxgi.granularity; //2.0; // 0.25f * (CASCADES - cascade); + const float granularity = 1.0f / granularityRecip; + const float occlusionFalloff = ubo.settings.vxgi.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 + tDelta * ubo.settings.vxgi.traceStartOffsetFactor; + 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.settings.vxgi.matrix * 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 ( ubo.settings.vxgi.shadows < ++voxelShadowsCount ) 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.settings.vxgi.matrix ); + 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 = 0; // 1.0f / float(CONES_COUNT) * 0.125f; + + 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.25; // 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; + } + // indirectDiffuse.rgb *= surface.material.albedo.rgb; + 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 ); + // indirectSpecular.rgb *= surface.material.albedo.rgb; + // outFragColor.rgb = indirectSpecular.rgb; return; + } + +/* + if ( true ) { + gammaCorrect(indirectDiffuse.rgb, 1.0 / ubo.settings.bloom.gamma); + } +*/ + indirectDiffuse *= DIFFUSE_INDIRECT_FACTOR; + indirectSpecular *= SPECULAR_INDIRECT_FACTOR; + + + surface.material.indirect = indirectDiffuse + indirectSpecular; +// outFragColor.rgb = surface.material.indirect.rgb; return; + + // 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 * 0.5 ); + surface.fragment.rgb += (1.0 - surface.material.albedo.a) * radiance.rgb; + } +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/bloom/comp.glsl b/belly/bin/data/shaders/display/bloom/comp.glsl new file mode 100644 index 00000000..639cc811 --- /dev/null +++ b/belly/bin/data/shaders/display/bloom/comp.glsl @@ -0,0 +1,67 @@ +#version 450 +#pragma shader_stage(compute) + +#define COMPUTE 1 +#define TEXTURES 0 +#define CUBEMAPS 0 +#define BLOOM 1 + +layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; + +layout( push_constant ) uniform PushBlock { + uint eye; + uint mode; +} PushConstant; + +layout (binding = 0) uniform UBO { + float scale; + float strength; + float threshold; + float sigma; + + float gamma; + float exposure; + uint samples; + uint padding; +} ubo; + +layout (binding = 1, rgba16f) uniform volatile coherent image2D imageColor; +layout (binding = 2, rgba16f) uniform volatile coherent image2D imageBloom; +layout (binding = 3, rgba16f) uniform volatile coherent image2D imagePingPong; + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" + +void main() { + const uint mode = PushConstant.mode; + const ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + const ivec2 size = imageSize( imageColor ); + if ( texel.x >= size.x || texel.y >= size.y ) return; + + if ( mode == 0 ) { // fill bloom + vec3 result = imageLoad( imageColor, texel ).rgb; + float brightness = dot(result, vec3(0.2126, 0.7152, 0.0722)); + if ( brightness < ubo.threshold ) result = vec3(0, 0, 0); + imageStore( imageBloom, texel, vec4( result, 1.0 ) ); + } else if ( mode == 1 ) { // bloom horizontal + vec3 result = imageLoad( imageBloom, texel ).rgb * gauss( 0, ubo.sigma ) * ubo.strength; + for( int i = 1; i < ubo.samples; ++i ) { + result += imageLoad( imageBloom, texel + ivec2(i * ubo.scale, 0.0)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + result += imageLoad( imageBloom, texel - ivec2(i * ubo.scale, 0.0)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + } + // write to PingPong + imageStore( imagePingPong, texel, vec4( result, 1.0 ) ); + } else if ( mode == 2 ) { // bloom vertical + vec3 result = imageLoad( imagePingPong, texel ).rgb * gauss( 0, ubo.sigma ) * ubo.strength; + for( int i = 1; i < ubo.samples; ++i ) { + result += imageLoad( imagePingPong, texel + ivec2(0.0, i * ubo.scale)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + result += imageLoad( imagePingPong, texel - ivec2(0.0, i * ubo.scale)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + } + // write to Bloom + imageStore( imageBloom, texel, vec4( result, 1.0 ) ); + } else if ( mode == 3 ) { // combine + vec3 result = imageLoad( imageColor, texel ).rgb + imageLoad( imageBloom, texel ).rgb; + imageStore( imageColor, texel, vec4( result, 1.0 ) ); + } +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/deferred/comp/comp.glsl b/belly/bin/data/shaders/display/deferred/comp/comp.glsl new file mode 100644 index 00000000..cb7c6384 --- /dev/null +++ b/belly/bin/data/shaders/display/deferred/comp/comp.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 0 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/deferred/comp/comp.h b/belly/bin/data/shaders/display/deferred/comp/comp.h new file mode 100644 index 00000000..835e84ef --- /dev/null +++ b/belly/bin/data/shaders/display/deferred/comp/comp.h @@ -0,0 +1,287 @@ +#extension GL_EXT_samplerless_texture_functions : require +#extension GL_EXT_nonuniform_qualifier : enable + +#if RT + #extension GL_EXT_ray_tracing : enable + #extension GL_EXT_ray_query : enable +#endif + +layout (local_size_x = 4, local_size_y = 4, local_size_z = 1) in; + +#define COMPUTE 1 +#define DEFERRED 1 +#define DEFERRED_SAMPLING 1 + +#define PBR 1 +#define LAMBERT 0 +#if RT || BARYCENTRIC + #define BUFFER_REFERENCE 0 + #define UINT64_ENABLED 0 +#endif +#define FOG 1 +#define FOG_RAY_MARCH 1 + +#include "../../../common/macros.h" + +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +#if VXGI + layout (constant_id = 2) const uint CASCADES = 16; +#endif + +#if !MULTISAMPLING + layout(binding = 0) uniform utexture2D samplerId; + #if BARYCENTRIC + #if !BARYCENTRIC_CALCULATE + layout(binding = 1) uniform texture2D samplerBary; + #endif + #else + layout(binding = 1) uniform texture2D samplerUv; + layout(binding = 2) uniform texture2D samplerNormal; + #endif + layout(binding = 3) uniform texture2D samplerDepth; +#else + layout(binding = 0) uniform utexture2DMS samplerId; + #if BARYCENTRIC + #if !BARYCENTRIC_CALCULATE + layout(binding = 1) uniform texture2DMS samplerBary; + #endif + #else + layout(binding = 1) uniform texture2DMS samplerUv; + layout(binding = 2) uniform texture2DMS samplerNormal; + #endif + layout(binding = 3) uniform texture2DMS samplerDepth; +#endif + + +layout(binding = 7, rgba16f) uniform volatile coherent image2D imageColor; +layout(binding = 8, rgba16f) uniform volatile coherent image2D imageBright; +layout(binding = 9, rg16f) uniform volatile coherent image2D imageMotion; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +#include "../../../common/structs.h" + +layout (binding = 10) uniform UBO { + EyeMatrices eyes[2]; + + Settings settings; +} ubo; +/* +*/ +layout (std140, binding = 11) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 12) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 13) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 14) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 15) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 16) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 17) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 18) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 19) uniform sampler3D samplerNoise; +#if VXGI + layout (binding = 20) uniform usampler3D voxelId[CASCADES]; + layout (binding = 21) uniform sampler3D voxelNormal[CASCADES]; + layout (binding = 22) uniform sampler3D voxelRadiance[CASCADES]; +#endif +#if RT + layout (binding = 23) uniform accelerationStructureEXT tlas; +#endif + +#if BUFFER_REFERENCE + layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; + layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; + layout(buffer_reference, scalar) buffer Indirects { DrawCommand dc[]; }; + + layout(buffer_reference, scalar) buffer VPos { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VUv { vec2 v[]; }; + layout(buffer_reference, scalar) buffer VColor { uint v[]; }; + layout(buffer_reference, scalar) buffer VSt { vec2 v[]; }; + layout(buffer_reference, scalar) buffer VNormal { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VTangent { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VID { uint v[]; }; +#endif + +#include "../../../common/functions.h" +#include "../../../common/fog.h" +#include "../../../common/light.h" +#include "../../../common/shadows.h" +#if VXGI + #include "../../../common/vxgi.h" +#endif + +#if MULTISAMPLING + #define IMAGE_LOAD(X) texelFetch( X, ivec2(gl_GlobalInvocationID.xy), msaa.currentID ) +#else + #define IMAGE_LOAD(X) texelFetch( X, ivec2(gl_GlobalInvocationID.xy), 0 ) +#endif + +#define IMAGE_STORE(X, Y) imageStore( X, ivec2(gl_GlobalInvocationID.xy), Y ) + +void postProcess() { +#if FOG + fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); +#endif + float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); + bool bloom = brightness > ubo.settings.bloom.threshold; +//if ( bloom ) toneMap( surface.fragment.rgb, brightness ); + vec4 outFragColor = vec4(surface.fragment.rgb, 1.0); + vec4 outFragBright = bloom ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); + vec2 outFragMotion = surface.motion; + + if ( ubo.settings.mode.type == 0x0001 ) { + outFragColor = vec4(surface.material.albedo.rgb, 1); + } else if ( ubo.settings.mode.type == 0x0002 ) { + outFragColor = vec4(surface.normal.eye.rgb, 1); + } else if ( ubo.settings.mode.type == 0x0003 ) { + outFragColor = vec4(surface.uv.xy, 0, 1); + } else if ( ubo.settings.mode.type == 0x0004 ) { + outFragColor = vec4(surface.st.xy, 0, 1); + } + + IMAGE_STORE( imageColor, outFragColor ); + IMAGE_STORE( imageBright, outFragBright ); + IMAGE_STORE( imageMotion, vec4(outFragMotion, 0, 0) ); +} + +void populateSurface() { + uvec2 renderSize = imageSize(imageColor); + if ( gl_GlobalInvocationID.x >= renderSize.x || gl_GlobalInvocationID.y >= renderSize.y || gl_GlobalInvocationID.z > PushConstant.pass ) return; + + surface.fragment = vec4(0); + surface.pass = PushConstant.pass; + + { + vec2 inUv = (vec2(gl_GlobalInvocationID.xy) / vec2(renderSize)) * 2.0f - 1.0f; + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + const vec4 near4 = iProjectionView * (vec4(inUv, -1.0, 1.0)); + const vec4 far4 = iProjectionView * (vec4(inUv, 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 = /*near3.xyz;*/ ubo.eyes[surface.pass].eyePos.xyz; + + const float depth = IMAGE_LOAD(samplerDepth).r; + + vec4 eye = ubo.eyes[surface.pass].iProjection * vec4(inUv, depth, 1.0); + eye /= eye.w; + + surface.position.eye = eye.xyz; + surface.position.world = vec3( ubo.eyes[surface.pass].iView * eye ); + } + +#if !MULTISAMPLING + const uvec2 ID = uvec2(IMAGE_LOAD(samplerId).xy); +#else + const uvec2 ID = msaa.IDs[msaa.currentID]; +#endif + surface.motion = vec2(0); + + if ( ID.x == 0 || ID.y == 0 ) { + if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment.rgb = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], surface.ray.direction ).rgb; + } + surface.fragment.a = 0.0; + return; + } + { + const uint triangleID = ID.x - 1; + const uint instanceID = ID.y - 1; + surface.subID = 1; + + #if BARYCENTRIC + #if !BARYCENTRIC_CALCULATE + surface.barycentric = decodeBarycentrics(IMAGE_LOAD(samplerBary).xy).xyz; + #endif + populateSurface( instanceID, triangleID ); + #else + vec4 uvst = IMAGE_LOAD(samplerUv); + vec4 normaltangent = IMAGE_LOAD(samplerNormal); + + surface.uv.xy = uvst.xy; + surface.uv.z = 0; + surface.st.xy = uvst.zw; + surface.st.z = 0; + + surface.normal.world = decodeNormals(normaltangent.xy); + // surface.tangent.world = decodeNormals(normaltangent.zw); + + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.instance = instances[instanceID]; + + populateSurfaceMaterial(); + #endif + } + + { + vec4 pNDC = ubo.eyes[surface.pass].previous * surface.instance.previous * vec4(surface.position.world, 1); + vec4 cNDC = ubo.eyes[surface.pass].model * surface.instance.model * vec4(surface.position.world, 1); + pNDC /= pNDC.w; + cNDC /= cNDC.w; + + surface.motion = cNDC.xy - pNDC.xy; + } +} + +void directLighting() { + surface.light.rgb += surface.material.albedo.rgb * ubo.settings.lighting.ambient.rgb * surface.material.occlusion; // add ambient lighting + surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting +#if PBR + pbr(); +#elif LAMBERT + lambert(); +#elif PHONG + phong(); +#endif + + surface.fragment.rgb += surface.light.rgb; +} + +#if MULTISAMPLING +void resolveSurfaceFragment() { + for ( int i = 0; i < ubo.settings.mode.msaa; ++i ) { + msaa.currentID = i; + msaa.IDs[i] = uvec3(IMAGE_LOAD(samplerId)).xy; + + // check if ID is already used + bool unique = true; + for ( int j = msaa.currentID - 1; j >= 0; --j ) { + if ( msaa.IDs[j] == msaa.IDs[i] ) { + surface.fragment = msaa.fragments[j]; + unique = false; + break; + } + } + + if ( unique ) { + populateSurface(); + #if VXGI + indirectLighting(); + #endif + directLighting(); + } + + msaa.fragment += surface.fragment; + msaa.fragments[msaa.currentID] = surface.fragment; + } + + surface.fragment = msaa.fragment / ubo.settings.mode.msaa; +} +#endif \ No newline at end of file diff --git a/belly/bin/data/shaders/display/deferred/comp/msaa.comp.glsl b/belly/bin/data/shaders/display/deferred/comp/msaa.comp.glsl new file mode 100644 index 00000000..00628645 --- /dev/null +++ b/belly/bin/data/shaders/display/deferred/comp/msaa.comp.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 0 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + resolveSurfaceFragment(); + + postProcess(); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/deferred/comp/rt.comp.glsl b/belly/bin/data/shaders/display/deferred/comp/rt.comp.glsl new file mode 100644 index 00000000..bdc07694 --- /dev/null +++ b/belly/bin/data/shaders/display/deferred/comp/rt.comp.glsl @@ -0,0 +1,13 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 0 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/deferred/comp/rt.msaa.comp.glsl b/belly/bin/data/shaders/display/deferred/comp/rt.msaa.comp.glsl new file mode 100644 index 00000000..1388e20b --- /dev/null +++ b/belly/bin/data/shaders/display/deferred/comp/rt.msaa.comp.glsl @@ -0,0 +1,13 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 0 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/deferred/comp/rt.vxgi.comp.glsl b/belly/bin/data/shaders/display/deferred/comp/rt.vxgi.comp.glsl new file mode 100644 index 00000000..18e067a1 --- /dev/null +++ b/belly/bin/data/shaders/display/deferred/comp/rt.vxgi.comp.glsl @@ -0,0 +1,14 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 1 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + indirectLighting(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/deferred/comp/rt.vxgi.msaa.comp.glsl b/belly/bin/data/shaders/display/deferred/comp/rt.vxgi.msaa.comp.glsl new file mode 100644 index 00000000..87394afc --- /dev/null +++ b/belly/bin/data/shaders/display/deferred/comp/rt.vxgi.msaa.comp.glsl @@ -0,0 +1,13 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 1 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/deferred/comp/vxgi.comp.glsl b/belly/bin/data/shaders/display/deferred/comp/vxgi.comp.glsl new file mode 100644 index 00000000..f29ee254 --- /dev/null +++ b/belly/bin/data/shaders/display/deferred/comp/vxgi.comp.glsl @@ -0,0 +1,14 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 1 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + indirectLighting(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/deferred/comp/vxgi.msaa.comp.glsl b/belly/bin/data/shaders/display/deferred/comp/vxgi.msaa.comp.glsl new file mode 100644 index 00000000..6829be37 --- /dev/null +++ b/belly/bin/data/shaders/display/deferred/comp/vxgi.msaa.comp.glsl @@ -0,0 +1,12 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 1 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + resolveSurfaceFragment(); + postProcess(); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/depth-pyramid/comp.glsl b/belly/bin/data/shaders/display/depth-pyramid/comp.glsl new file mode 100644 index 00000000..d58feb89 --- /dev/null +++ b/belly/bin/data/shaders/display/depth-pyramid/comp.glsl @@ -0,0 +1,30 @@ +#version 450 +#pragma shader_stage(compute) + +//#extension GL_EXT_nonuniform_qualifier : enable + +layout (constant_id = 0) const uint MIPS = 6; +layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#define COMPUTE 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout( push_constant ) uniform PushBlock { + uint _; + uint pass; +} PushConstant; + +layout (binding = 3) uniform sampler2D inImage[MIPS]; +layout (binding = 4, r32f) uniform volatile coherent image2D outImage[MIPS]; + +void main() { + vec2 imageSize = imageSize(outImage[PushConstant.pass]); + uvec2 pos = gl_GlobalInvocationID.xy; + if ( pos.x >= imageSize.x || pos.y >= imageSize.y ) return; + + float depth = texture(inImage[PushConstant.pass], (vec2(pos) + vec2(0.5)) / imageSize).x; + + imageStore(outImage[PushConstant.pass], ivec2(pos), vec4(depth)); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/renderTarget/frag.glsl b/belly/bin/data/shaders/display/renderTarget/frag.glsl new file mode 100644 index 00000000..8758b85d --- /dev/null +++ b/belly/bin/data/shaders/display/renderTarget/frag.glsl @@ -0,0 +1,35 @@ +#version 450 +#pragma shader_stage(fragment) +#extension GL_EXT_samplerless_texture_functions : require + +layout (location = 0) in vec2 inUv; +layout (location = 1) flat in uint inPass; + +layout (location = 0) out vec4 outColor; + +layout (binding = 0) uniform sampler2D samplerColor; + +layout (binding = 1) uniform UBO { + float curTime; + float gamma; + float exposure; + uint padding; +} ubo; + +#define TONE_MAP 1 +#define GAMMA_CORRECT 1 +#define TEXTURES 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" + +void main() { + outColor = texture( samplerColor, inUv ); +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/renderTarget/postProcess.frag.glsl b/belly/bin/data/shaders/display/renderTarget/postProcess.frag.glsl new file mode 100644 index 00000000..5e1ae123 --- /dev/null +++ b/belly/bin/data/shaders/display/renderTarget/postProcess.frag.glsl @@ -0,0 +1,392 @@ +#version 450 +#pragma shader_stage(fragment) +#extension GL_EXT_samplerless_texture_functions : require + +layout (location = 0) in vec2 inUv; +layout (location = 1) flat in uint inPass; + +layout (location = 0) out vec4 outColor; + +layout (binding = 0) uniform sampler2D samplerColor; + +layout (binding = 1) uniform UBO { + float curTime; + float gamma; + float exposure; + uint padding; +} ubo; + +#define TONE_MAP 1 +#define GAMMA_CORRECT 1 +#define TEXTURES 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" + +#define M_PI 3.1415926535897932384626433832795 + +const float u_imgx = 0; +const float u_imgy = 0; +const float u_imgw = 1; +const float u_imgh = 1; +const float u_img_gain = 2; +const float u_img_bias = 0; +const float u_beam_bias = 0.185; +const float u_beam_gain = 0.25; +const float u_corner = 0.05; +const float u_zoom = 1.0; +const float u_shape = 2; +const float u_round = -0.02; +const float u_grain = 0.4; +const float u_vpitch = 936.1; +const float u_hpitch = 1024.6; +const float u_top = 1; +const float u_bot = 1; + +void main() { + const vec2 screenResolution = textureSize( samplerColor, 0 ); + const float u_lines = screenResolution.y * 0.75; + + vec2 uv_orig = (inUv.xy * 2.0 - 1.0); + vec2 uv_mod = uv_orig * pow(1.0-abs(uv_orig),vec2(u_round)) * (u_zoom + u_corner * pow( abs(uv_orig.yx), vec2(u_shape)) ); + vec2 uv = uv_mod / 2.0 + 0.5; + + if ( abs(uv_mod).x > 1.0 || abs(uv_mod.y) > 1.0 ) { + outColor = vec4(0.0, 0.0, 0.0, 1.0); + return; + } + + float spacing = 1.0/u_lines; + uv+=spacing*0.5; + + float line_top = ( ceil(uv.y*u_lines)) / u_lines; + float line_bot = line_top - spacing; + + vec2 scale = vec2(u_imgw, u_imgh); + vec2 offset = vec2(u_imgx, u_imgy); + + vec2 uv_top = (vec2(uv.x, line_top)+offset) * scale - (scale-1.0)*0.5 ; + vec2 uv_bot = (vec2(uv.x, line_bot)+offset) * scale - (scale-1.0)*0.5 ; + + uv_top -= spacing * 0.5; + uv_bot -= spacing * 0.5; + + vec4 sampled_top = texture(samplerColor, uv_top); + vec4 sampled_bot = texture(samplerColor, uv_bot); + + vec3 color_top = sampled_top.xyz * u_img_gain + u_img_bias; + vec3 color_bot = sampled_bot.xyz * u_img_gain + u_img_bias; + + float dist_top = pow(abs(uv.y - line_top), 1.0); + float dist_bot = pow(abs(uv.y - line_bot), 1.0); + + vec3 beam_top = 1.0 - (dist_top / (spacing * (color_top * u_beam_gain + u_beam_bias))); + vec3 beam_bot = 1.0 - (dist_bot / (spacing * (color_bot * u_beam_gain + u_beam_bias))); + + beam_top = clamp(beam_top, 0.0, 1.0) ; + beam_bot = clamp(beam_bot, 0.0, 1.0) ; + + vec3 color = (color_top*beam_top)*u_top + (color_bot*beam_bot)*u_bot; + + vec2 dot; + dot.y = floor(uv.y * u_vpitch) ; + dot.x = uv.x; + + if (mod(dot.y, 2.0) > 0.5) + dot.x += (4.5/3.0) / u_hpitch; + + dot.x = (floor(dot.x*u_hpitch)) ; + + int fil = int(mod(dot.x, 3.0)); + + vec3 out_color = color * (1.0-u_grain); + + vec3 passthru = vec3( + float(fil == 0), + float(fil == 1), + float(fil == 2) + ) * (u_grain); + + out_color += color * passthru; + + outColor = vec4(out_color, (sampled_top.a + sampled_bot.a) * 0.5 ); + +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} + +#if 0 +float iTime = 0; +float noise(vec2 p) { + float s = (fract(sin(dot(p * sin( iTime * 0.5 ), vec2(12.9898,78.233)*2.0)) * 43758.5453)); // texture(iChannel1,vec2(1.,2.*cos(iTime))*iTime*8. + p*1.).x; + s *= s; + return s; +} + +float onOff(float a, float b, float c) { + return step(c, sin(iTime + a*cos(iTime*b))); +} + +float ramp(float y, float start, float end) { + float inside = step(start,y) - step(end,y); + float fact = (y-start)/(end-start)*inside; + return (1.-fact) * inside; + +} + +float stripes(vec2 uv) { + float noi = noise(uv*vec2(0.5,1.) + vec2(1.,3.)); + return ramp(mod(uv.y*4. + iTime/2.+sin(iTime + sin(iTime*0.63)),1.),0.5,0.6)*noi; +} + +vec4 getVideo(vec2 uv) { + vec2 look = uv; + float window = 1./(1.+20.*(look.y-mod(iTime/4.,1.))*(look.y-mod(iTime/4.,1.))); + look.x = look.x + sin(look.y*10. + iTime)/50.*onOff(4.,4.,.3)*(1.+cos(iTime*80.))*window; + float vShift = 0.4*onOff(2.,3.,.9)*(sin(iTime)*sin(iTime*20.) + + (0.5 + 0.1*sin(iTime*200.)*cos(iTime))); + look.y = mod(look.y + vShift, 1.); + return texture(samplerColor,look); +} + +vec2 screenDistort(vec2 uv) { + uv -= vec2(.5,.5); + uv = uv*1.2*(1./1.2+2.*uv.x*uv.x*uv.y*uv.y); + uv += vec2(.5,.5); + return uv; +} + +void main() { + vec2 uv = inUv.xy; // fragCoord.xy / iResolution.xy; + iTime = ubo.curTime; + + uv = screenDistort(uv); + vec4 video = getVideo(uv); + float vigAmt = 3.+.3*sin(iTime + 5.*cos(iTime*5.)); + float vignette = (1.-vigAmt*(uv.y-.5)*(uv.y-.5))*(1.-vigAmt*(uv.x-.5)*(uv.x-.5)); + + video.rgb += stripes(uv); + video.rgb += noise(uv*2.)/4.; + video.rgb *= vignette; + video.rgb *= (12.+mod(uv.y*30.+iTime,1.))/13.; + + outColor = video; +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} +#endif +#if 0 +vec2 curveRemapUV(vec2 uv, vec2 curvature) { + uv = uv * 2.0 - 1.0; + vec2 offset = abs(uv.yx) / vec2(curvature.x, curvature.y); + uv = uv + uv * offset * offset; + uv = uv * 0.5 + 0.5; + return uv; +} + +vec4 scanLineIntensity(float uv, float resolution, float opacity) { + float intensity = sin(uv * resolution * PI * 2.0); + intensity = ((0.5 * intensity) + 0.5) * 0.9 + 0.1; + return vec4(vec3(pow(intensity, opacity)), 1.0); +} + +vec4 vignetteIntensity(vec2 uv, vec2 resolution, float opacity, float roundness) { + float intensity = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y); + return vec4(vec3(clamp(pow((resolution.x / roundness) * intensity, opacity), 0.0, 1.0)), 1.0); +} + +void main(void) { + const vec2 screenResolution = textureSize( samplerColor, 0 ); + const vec2 scanLineOpacity = vec2(0.5); + const float brightness = 2; + const float vignetteOpacity = 0.5; + const float vignetteRoundness = 0.5; + const vec2 curvature = vec2(8); + + const vec2 remappedUV = curveRemapUV(vec2(inUv.x, inUv.y), curvature); + vec4 baseColor = texture(samplerColor, remappedUV); + + baseColor *= vignetteIntensity(remappedUV, screenResolution, vignetteOpacity, vignetteRoundness); + + baseColor *= scanLineIntensity(remappedUV.x, screenResolution.y, scanLineOpacity.x); + baseColor *= scanLineIntensity(remappedUV.y, screenResolution.x, scanLineOpacity.y); + + baseColor *= vec4(vec3(brightness), 1.0); + + if (remappedUV.x < 0.0 || remappedUV.y < 0.0 || remappedUV.x > 1.0 || remappedUV.y > 1.0){ + outColor = vec4(0.0, 0.0, 0.0, 1.0); + } else { + outColor = baseColor; + } + +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} +#endif +#if 0 +vec2 fragCoord = vec2(0,0); +vec2 iResolution = vec2(640,480); + +// Emulated input resolution. +#if 0 + // Fix resolution to set amount. + #define res (vec2(320.0/1.0,160.0/1.0)) +#else + // Optimize for resize. + #define res (iResolution.xy/6.0) +#endif + +// Hardness of scanline. +// -8.0 = soft +// -16.0 = medium +float hardScan=-8.0; + +// Hardness of pixels in scanline. +// -2.0 = soft +// -4.0 = hard +float hardPix=-3.0; + +// Display warp. +// 0.0 = none +// 1.0/8.0 = extreme +vec2 warp=vec2(1.0/32.0,1.0/24.0); + +// Amount of shadow mask. +float maskDark=0.5; +float maskLight=1.5; + +//------------------------------------------------------------------------ + +// sRGB to Linear. +// Assuing using sRGB typed textures this should not be needed. +float ToLinear1(float c){return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4);} +vec3 ToLinear(vec3 c){return vec3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b));} + +// Linear to sRGB. +// Assuing using sRGB typed textures this should not be needed. +float ToSrgb1(float c){return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055);} +vec3 ToSrgb(vec3 c){return vec3(ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b));} + +// Nearest emulated sample given floating point position and texel offset. +// Also zero's off screen. +vec3 Fetch(vec2 pos,vec2 off){ + pos=floor(pos*res+off)/res; + if(max(abs(pos.x-0.5),abs(pos.y-0.5))>0.5)return vec3(0.0,0.0,0.0); + return ToLinear(texture(samplerColor,pos.xy,-16.0).rgb);} + +// Distance in emulated pixels to nearest texel. +vec2 Dist(vec2 pos){pos=pos*res;return -((pos-floor(pos))-vec2(0.5));} + +// 1D Gaussian. +float Gaus(float pos,float scale){return exp2(scale*pos*pos);} + +// 3-tap Gaussian filter along horz line. +vec3 Horz3(vec2 pos,float off){ + vec3 b=Fetch(pos,vec2(-1.0,off)); + vec3 c=Fetch(pos,vec2( 0.0,off)); + vec3 d=Fetch(pos,vec2( 1.0,off)); + float dst=Dist(pos).x; + // Convert distance to weight. + float scale=hardPix; + float wb=Gaus(dst-1.0,scale); + float wc=Gaus(dst+0.0,scale); + float wd=Gaus(dst+1.0,scale); + // Return filtered sample. + return (b*wb+c*wc+d*wd)/(wb+wc+wd);} + +// 5-tap Gaussian filter along horz line. +vec3 Horz5(vec2 pos,float off){ + vec3 a=Fetch(pos,vec2(-2.0,off)); + vec3 b=Fetch(pos,vec2(-1.0,off)); + vec3 c=Fetch(pos,vec2( 0.0,off)); + vec3 d=Fetch(pos,vec2( 1.0,off)); + vec3 e=Fetch(pos,vec2( 2.0,off)); + float dst=Dist(pos).x; + // Convert distance to weight. + float scale=hardPix; + float wa=Gaus(dst-2.0,scale); + float wb=Gaus(dst-1.0,scale); + float wc=Gaus(dst+0.0,scale); + float wd=Gaus(dst+1.0,scale); + float we=Gaus(dst+2.0,scale); + // Return filtered sample. + return (a*wa+b*wb+c*wc+d*wd+e*we)/(wa+wb+wc+wd+we);} + +// Return scanline weight. +float Scan(vec2 pos,float off){ + float dst=Dist(pos).y; + return Gaus(dst+off,hardScan);} + +// Allow nearest three lines to effect pixel. +vec3 Tri(vec2 pos){ + vec3 a=Horz3(pos,-1.0); + vec3 b=Horz5(pos, 0.0); + vec3 c=Horz3(pos, 1.0); + float wa=Scan(pos,-1.0); + float wb=Scan(pos, 0.0); + float wc=Scan(pos, 1.0); + return a*wa+b*wb+c*wc;} + +// Distortion of scanlines, and end of screen alpha. +vec2 Warp(vec2 pos){ + pos=pos*2.0-1.0; + pos*=vec2(1.0+(pos.y*pos.y)*warp.x,1.0+(pos.x*pos.x)*warp.y); + return pos*0.5+0.5;} + +// Shadow mask. +vec3 Mask(vec2 pos){ + pos.x+=pos.y*3.0; + vec3 mask=vec3(maskDark,maskDark,maskDark); + pos.x=fract(pos.x/6.0); + if(pos.x<0.333)mask.r=maskLight; + else if(pos.x<0.666)mask.g=maskLight; + else mask.b=maskLight; + return mask;} + +void main() { + iResolution = textureSize( samplerColor, 0 ); + fragCoord = inUv * iResolution; + + vec2 pos = Warp(fragCoord.xy / iResolution.xy); + + hardScan = -12.0; + maskDark = maskLight = 1.0; + + outColor.rgb = Tri(pos) * Mask(fragCoord.xy); + outColor.rgb = ToSrgb(outColor.rgb); + outColor.a = 1.0; + +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} +#endif +#if 0 +void main() { + const vec2 uv = 0.025 * sin( ubo.curTime ) * inUv.xy; + const float mdf = 0.5; + const float noise = (fract(sin(dot(uv, vec2(12.9898,78.233)*2.0)) * 43758.5453)); + const vec4 sampled = texture( samplerColor, inUv ); + + outColor = sampled - noise * mdf; + + toneMap(outColor, ubo.exposure); + gammaCorrect(outColor, ubo.gamma); +} +#endif \ No newline at end of file diff --git a/belly/bin/data/shaders/display/renderTarget/vert.glsl b/belly/bin/data/shaders/display/renderTarget/vert.glsl new file mode 100644 index 00000000..95fd44b3 --- /dev/null +++ b/belly/bin/data/shaders/display/renderTarget/vert.glsl @@ -0,0 +1,16 @@ +#version 450 +#pragma shader_stage(vertex) + +layout (location = 0) out vec2 outUv; +layout (location = 1) out flat uint outPass; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +void main() { + outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + outPass = PushConstant.pass; + gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/vxgi/comp.glsl b/belly/bin/data/shaders/display/vxgi/comp.glsl new file mode 100644 index 00000000..9d44d570 --- /dev/null +++ b/belly/bin/data/shaders/display/vxgi/comp.glsl @@ -0,0 +1,148 @@ +#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 COMPUTE 1 + +#define VXGI 1 +#define MAX_CUBEMAPS CUBEMAPS +#define GAMMA_CORRECT 1 +#define PBR 1 + +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +layout (constant_id = 2) const uint CASCADES = 16; + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 0) uniform UBO { + EyeMatrices eyes[2]; + + Settings settings; +} ubo; +layout (std140, binding = 1) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 2) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 3) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 4) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 5) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 6) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 7) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 8) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 9) uniform sampler3D samplerNoise; + +layout (binding = 10, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; +layout (binding = 11, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; +#if VXGI_HDR + layout (binding = 12, rgba32f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#else + layout (binding = 12, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#endif + +#include "../../common/functions.h" +#include "../../common/light.h" +#undef VXGI // +#include "../../common/shadows.h" +void main() { + const vec3 tUvw = gl_GlobalInvocationID.xzy; + for ( uint CASCADE = 0; CASCADE < CASCADES; ++CASCADE ) { + surface.normal.world = decodeNormals( vec2(imageLoad(voxelNormal[CASCADE], ivec3(tUvw) ).xy) ); + surface.normal.eye = vec3( ubo.settings.vxgi.matrix * vec4( surface.normal.world, 0.0f ) ); + + surface.position.eye = (vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelRadiance[CASCADE])) * 2.0f - 1.0f) * cascadePower(CASCADE); + surface.position.world = vec3( inverse(ubo.settings.vxgi.matrix) * vec4( surface.position.eye, 1.0f ) ); + + const uvec2 ID = uvec2(imageLoad(voxelId[CASCADE], ivec3(tUvw) ).xy); + const uint drawID = ID.x - 1; + const uint instanceID = ID.y - 1; + if ( ID.x == 0 || ID.y == 0 ) { + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(0)); + continue; + } + const DrawCommand drawCommand = drawCommands[drawID]; + surface.instance = instances[instanceID]; + const Material material = materials[surface.instance.materialID]; + surface.material.albedo = material.colorBase; + surface.fragment = material.colorEmissive; + + surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) ); + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; + + const vec3 ambient = ubo.settings.lighting.ambient.rgb * surface.material.occlusion; + if ( validTextureIndex( surface.instance.lightmapID ) ) { + surface.fragment.rgb += surface.material.albedo.rgb; + } else { + surface.fragment.rgb += surface.material.albedo.rgb * ambient; + // corrections + surface.position.eye = vec3( ubo.eyes[surface.pass].view * vec4( surface.position.world, 1 ) ); + surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0) ); + pbr(); + /* + surface.material.roughness *= 4.0; + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize( surface.position.world ); + const float cosLo = max(0.0, dot(surface.normal.world, Lo)); + for ( uint i = 0; i < ubo.settings.lengths.lights; ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - surface.position.world; + const vec3 Li = normalize(Liu); + const float Ls = shadowFactor( light, 0.0 ); + const float La = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.world, Li)); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + #if LAMBERT + const vec3 diffuse = surface.material.albedo.rgb; + const vec3 specular = vec3(0); + #elif PBR + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.world, Lh)); + + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, surface.material.roughness ); + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); + const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; + const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + #endif + // lightmapped, compute only specular + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } + */ + } + + surface.fragment.rgb += surface.light.rgb; + + #if TONE_MAP + toneMap(surface.fragment.rgb, ubo.settings.bloom.exposure); + #endif + #if GAMMA_CORRECT + gammaCorrect(surface.fragment.rgb, 1.0 / ubo.settings.bloom.gamma); + #endif + + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, surface.material.albedo.a)); + } +} \ No newline at end of file diff --git a/belly/bin/data/shaders/display/vxgi/mip.gaussian.comp.glsl b/belly/bin/data/shaders/display/vxgi/mip.gaussian.comp.glsl new file mode 100644 index 00000000..dae6f972 --- /dev/null +++ b/belly/bin/data/shaders/display/vxgi/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/belly/bin/data/shaders/graph/baking/frag.glsl b/belly/bin/data/shaders/graph/baking/frag.glsl new file mode 100644 index 00000000..076049f2 --- /dev/null +++ b/belly/bin/data/shaders/graph/baking/frag.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(fragment) + +#define RT 0 +#include "./frag.h" diff --git a/belly/bin/data/shaders/graph/baking/frag.h b/belly/bin/data/shaders/graph/baking/frag.h new file mode 100644 index 00000000..0abc2c25 --- /dev/null +++ b/belly/bin/data/shaders/graph/baking/frag.h @@ -0,0 +1,204 @@ +//#extension GL_EXT_nonuniform_qualifier : enable +#if RT + #extension GL_EXT_ray_tracing : enable + #extension GL_EXT_ray_query : enable +#endif + +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +layout (constant_id = 2) const uint LAYERS = 32; + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 6) uniform samplerCube samplerCubemaps[CUBEMAPS]; + +#define SHADOW_SAMPLES 16 +#define FRAGMENT 1 +#define BAKING 1 +#define PBR 1 +#define MAX_LIGHTS min(ubo.lights, lights.length()) +#define MAX_SHADOWS MAX_LIGHTS +#define VIEW_MATRIX camera.viewport[0].view + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 7) uniform Camera { + Viewport viewport[6]; +} camera; + +layout (binding = 8) uniform UBO { + uint lights; + uint currentID; + uint padding1; + uint padding2; +} ubo; + +layout (std140, binding = 9) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 10) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 11) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 12) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 13) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 14) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 15, rgba8) uniform volatile coherent image3D outAlbedos; + +#if RT + layout (binding = 16) uniform accelerationStructureEXT tlas; +#endif + +#include "../../common/functions.h" +#if RT +float shadowFactor( const Light light, float def ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = light.position - ray.origin; + + float tMin = 0.001; + float tMax = length(ray.direction) + tMin; + + ray.direction = normalize(ray.direction); + + uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT; + uint cullMask = 0xFF; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, tlas, rayFlags, cullMask, ray.origin, tMin, ray.direction, tMax); + + while(rayQueryProceedEXT(rayQuery)) {} + + return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT ? 1.0 : 0.0; +} +#else + #include "../../common/shadows.h" +#endif + +#include "../../common/light.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +layout (location = 0) out vec4 outAlbedo; + +void main() { + const uint triangleID = uint(inId.x); // gl_PrimitiveID + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + + if ( instanceID != ubo.currentID ) discard; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + surface.position.world = inPosition; + surface.normal.world = inNormal; + + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + const uint mapID = instance.auxID; + + vec4 A = material.colorBase; + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = 1.0f - material.factorOcclusion; + +#if 0 + vec3 N = inNormal; + vec3 T = inTangent; + T = normalize(T - dot(T, N) * N); + vec3 B = cross(T, N); + mat3 TBN = mat3(T, B, N); +// mat3 TBN = mat3(N, B, T); + if ( T != vec3(0) && validTextureIndex( material.indexNormal ) ) { + surface.normal.world = TBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - 1.0 ); + } else { + surface.normal.world = N; + } +#endif + + surface.light = material.colorEmissive; + surface.material.albedo = vec4(1); + { + surface.normal.eye = surface.normal.eye; + surface.position.eye = surface.position.eye; + // pbr(); + + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + for ( uint i = 0; i < min(ubo.lights, lights.length()); ++i ) { + const Light light = lights[i]; + + if ( light.type <= 0 ) continue; + + const mat4 mat = light.view; // inverse(light.view); + const vec3 position = surface.position.world; + // const vec3 position = vec3( mat * vec4(surface.position.world, 1.0) ); + const vec3 normal = surface.normal.world; + // const vec3 normal = vec3( mat * vec4(surface.normal.world, 0.0) ); + + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - surface.position.world; + const float La = 1.0 / (1 + PI * pow(length(Liu), 2.0)); + const float Ls = shadowFactor( light, 0.0 ); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + + const vec3 Lo = normalize( -position ); + const float cosLo = max(0.0, abs(dot(normal, Lo))); + + const vec3 Li = normalize(Liu); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + // const float cosLi = max(0.0, dot(normal, Li)); + const float cosLi = abs(dot(normal, Li)); + #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(normal, Lh)); + const float cosLh = abs(dot(normal, Lh)); + + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = 1; // 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 + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } + } +#define EXPOSURE 0 +#define GAMMA 0 + +// surface.light.rgb = vec3(1.0) - exp(-surface.light.rgb * EXPOSURE); +// surface.light.rgb = pow(surface.light.rgb, vec3(1.0 / GAMMA)); + + outAlbedo = vec4(surface.light.rgb, 1); + + { + const vec2 st = inSt.xy * imageSize(outAlbedos).xy; + const ivec3 uvw = ivec3(int(st.x), int(st.y), int(mapID)); + imageStore(outAlbedos, uvw, vec4(surface.light.rgb, 1) ); + } +} \ No newline at end of file diff --git a/belly/bin/data/shaders/graph/baking/rt.frag.glsl b/belly/bin/data/shaders/graph/baking/rt.frag.glsl new file mode 100644 index 00000000..a7eca538 --- /dev/null +++ b/belly/bin/data/shaders/graph/baking/rt.frag.glsl @@ -0,0 +1,5 @@ +#version 460 +#pragma shader_stage(fragment) + +#define RT 1 +#include "./frag.h" diff --git a/belly/bin/data/shaders/graph/baking/vert.glsl b/belly/bin/data/shaders/graph/baking/vert.glsl new file mode 100644 index 00000000..1f20a625 --- /dev/null +++ b/belly/bin/data/shaders/graph/baking/vert.glsl @@ -0,0 +1,8 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 0 +#define BAKING 1 + +#include "../base/vert.h" diff --git a/belly/bin/data/shaders/graph/base/frag.glsl b/belly/bin/data/shaders/graph/base/frag.glsl new file mode 100644 index 00000000..22289e3b --- /dev/null +++ b/belly/bin/data/shaders/graph/base/frag.glsl @@ -0,0 +1,126 @@ +#version 450 +#pragma shader_stage(fragment) + +//#extension GL_EXT_nonuniform_qualifier : enable + +#define FRAGMENT 1 +#define CAN_DISCARD 1 + +#define MAX_TEXTURES textures.length() + +layout (constant_id = 0) const uint TEXTURES = 1; + + +#include "../../common/macros.h" +#include "../../common/structs.h" + +#if BARYCENTRIC && !BARYCENTRIC_CALCULATE + #define BARYCENTRIC_STABILIZE 1 +// #define BARY_COORD gl_BaryCoordEXT +// #extension GL_EXT_fragment_shader_barycentric : enable + #define BARY_COORD gl_BaryCoordSmoothAMD + #extension GL_AMD_shader_explicit_vertex_parameter : enable +#endif + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 6) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 7) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 8) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 9) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 10) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 11) readonly buffer Lights { + Light lights[]; +}; + +#include "../../common/functions.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +#if BARYCENTRIC_STABILIZE + layout (location = 2) __explicitInterpAMD in vec4 inPOS1; +#else + layout (location = 2) in vec4 inPOS1; +#endif +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +layout (location = 0) out uvec2 outId; +#if BARYCENTRIC + layout (location = 1) out vec2 outBary; +#else + layout (location = 1) out vec4 outUv; + layout (location = 2) out vec4 outNormal; +#endif + +void main() { + const uint triangleID = gl_PrimitiveID; // uint(inId.x); + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + +#if CAN_DISCARD + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + surface.st.xy = wrap(inSt.xy); + surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt)); + + vec4 A = inColor * material.colorBase; + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + // alpha mode OPAQUE + if ( material.modeAlpha == 0 ) { + A.a = 1; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + if ( A.a < 0.0001 ) discard; + +#if !BARYCENTRIC + outUv = vec4(surface.uv, surface.st); + outNormal = vec4( encodeNormals(inNormal), encodeNormals(inTangent) ); +#endif + +#endif + + outId = uvec2(triangleID + 1, instanceID + 1); + +#if BARYCENTRIC && !BARYCENTRIC_CALCULATE + vec3 bary = vec3(gl_BaryCoordSmoothAMD.xy, 1 - gl_BaryCoordSmoothAMD.x - gl_BaryCoordSmoothAMD.y); + bary = bary.yzx; + #if BARYCENTRIC_STABILIZE + vec4 v0 = interpolateAtVertexAMD(inPOS1, 0); + vec4 v1 = interpolateAtVertexAMD(inPOS1, 1); + vec4 v2 = interpolateAtVertexAMD(inPOS1, 2); + if (v0 == inPOS0) outBary = encodeBarycentrics(bary.yzx); + else if (v1 == inPOS0) outBary = encodeBarycentrics(bary.zxy); + else if (v2 == inPOS0) outBary = encodeBarycentrics(bary.xyz); + #else + outBary = encodeBarycentrics(bary.xyz); + #endif +#endif +} \ No newline at end of file diff --git a/belly/bin/data/shaders/graph/base/instanced.vert.glsl b/belly/bin/data/shaders/graph/base/instanced.vert.glsl new file mode 100644 index 00000000..92cae145 --- /dev/null +++ b/belly/bin/data/shaders/graph/base/instanced.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 0 +#include "./vert.h" diff --git a/belly/bin/data/shaders/graph/base/skinned.instanced.vert.glsl b/belly/bin/data/shaders/graph/base/skinned.instanced.vert.glsl new file mode 100644 index 00000000..2bc9b86a --- /dev/null +++ b/belly/bin/data/shaders/graph/base/skinned.instanced.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 1 +#include "./vert.h" diff --git a/belly/bin/data/shaders/graph/base/skinned.vert.glsl b/belly/bin/data/shaders/graph/base/skinned.vert.glsl new file mode 100644 index 00000000..96b6ba5a --- /dev/null +++ b/belly/bin/data/shaders/graph/base/skinned.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 0 +#define SKINNED 1 +#include "./vert.h" diff --git a/belly/bin/data/shaders/graph/base/vert.glsl b/belly/bin/data/shaders/graph/base/vert.glsl new file mode 100644 index 00000000..701eee8d --- /dev/null +++ b/belly/bin/data/shaders/graph/base/vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 0 +#define SKINNED 0 +#include "./vert.h" diff --git a/belly/bin/data/shaders/graph/base/vert.h b/belly/bin/data/shaders/graph/base/vert.h new file mode 100644 index 00000000..5aad74bf --- /dev/null +++ b/belly/bin/data/shaders/graph/base/vert.h @@ -0,0 +1,100 @@ +layout (constant_id = 0) const uint PASSES = 6; +#extension GL_ARB_shader_draw_parameters : enable + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec2 inUv; +layout (location = 2) in vec4 inColor; +layout (location = 3) in vec2 inSt; +layout (location = 4) in vec3 inNormal; +layout (location = 5) in vec4 inTangent; +layout (location = 6) in uvec2 inId; +#if SKINNED + layout (location = 7) in uvec4 inJoints; + layout (location = 8) in vec4 inWeights; +#endif + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +#if !BAKING +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; +#endif +layout (std140, binding = 1) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 2) readonly buffer Instances { + Instance instances[]; +}; + +#if SKINNED + layout (std140, binding = 3) readonly buffer Joints { + mat4 joints[]; + }; +#endif + +layout (location = 0) out uvec4 outId; +layout (location = 1) flat out vec4 outPOS0; +layout (location = 2) out vec4 outPOS1; +layout (location = 3) out vec3 outPosition; +layout (location = 4) out vec2 outUv; +layout (location = 5) out vec4 outColor; +layout (location = 6) out vec2 outSt; +layout (location = 7) out vec3 outNormal; +layout (location = 8) out vec3 outTangent; + +vec4 snap(vec4 vertex, vec2 resolution) { + vec4 snappedPos = vertex; + snappedPos.xyz = vertex.xyz / vertex.w; + snappedPos.xy = floor(resolution * snappedPos.xy) / resolution; + snappedPos.xyz *= vertex.w; + return snappedPos; +} + +void main() { + const uint drawID = gl_DrawIDARB; + const uint triangleID = gl_VertexIndex / 3; + const DrawCommand drawCommand = drawCommands[drawID]; + const uint instanceID = drawCommand.instanceID; // gl_InstanceIndex; + const Instance instance = instances[instanceID]; + const uint jointID = instance.jointID; + +#if BAKING + const mat4 view = mat4(1); + const mat4 projection = mat4(1); +#else + const mat4 view = camera.viewport[PushConstant.pass].view; + const mat4 projection = camera.viewport[PushConstant.pass].projection; +#endif +#if SKINNED + const mat4 skinned = joints.length() <= 0 || jointID < 0 ? mat4(1.0) : inWeights.x * joints[jointID + int(inJoints.x)] + inWeights.y * joints[jointID + int(inJoints.y)] + inWeights.z * joints[jointID + int(inJoints.z)] + inWeights.w * joints[jointID + int(inJoints.w)]; +#else + const mat4 skinned = mat4(1.0); +#endif +// const mat4 model = instances.length() <= 0 ? skinned : (instance.model * skinned); + const mat4 model = instance.model * skinned; + + +#if BAKING + gl_Position = vec4(inSt * 2.0 - 1.0, 0.0, 1.0); +#else + gl_Position = projection * view * model * vec4(inPos.xyz, 1.0); +#endif + outPOS0 = gl_Position; + outPOS1 = gl_Position; + + outId = uvec4(triangleID, drawID, instanceID, PushConstant.pass); + + outPosition = vec3(model * vec4(inPos.xyz, 1.0)); + outUv = inUv; + outSt = inSt; + outColor = inColor * instance.color; + outNormal = normalize(vec3(model * vec4(inNormal.xyz, 0.0))); + outTangent = normalize(vec3(view * model * vec4(inTangent.xyz, 0.0))); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/graph/cull/comp.glsl b/belly/bin/data/shaders/graph/cull/comp.glsl new file mode 100644 index 00000000..0b174a2b --- /dev/null +++ b/belly/bin/data/shaders/graph/cull/comp.glsl @@ -0,0 +1,369 @@ +#version 450 +#pragma shader_stage(compute) + +//#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_EXT_samplerless_texture_functions : enable + +layout (constant_id = 0) const uint PASSES = 6; +layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +#define COMPUTE 1 +#define QUERY_MIPMAPS 1 +#define DEPTH_BIAS 0.00005 + +#include "../../common/macros.h" +#include "../../common/structs.h" + +float mipLevels( vec2 size ) { + return floor(log2(max(size.x, size.y))); +} +float mipLevels( ivec2 size ) { + return floor(log2(max(size.x, size.y))); +} + +vec4 aabbToSphere( Bounds bounds ) { + vec4 sphere; + sphere.xyz = (bounds.max + bounds.min) * 0.5; + sphere.w = length((bounds.max - bounds.min) * 0.5); + return sphere; +} + +// 2D Polyhedral Bounds of a Clipped, Perspective-Projected 3D Sphere. Michael Mara, Morgan McGuire. 2013 +bool projectSphere(vec3 C, float r, float znear, float P00, float P11, out vec4 aabb) +{ + if (C.z < r + znear) + return false; + + vec2 cx = -C.xz; + vec2 vx = vec2(sqrt(dot(cx, cx) - r * r), r); + vec2 minx = mat2(vx.x, vx.y, -vx.y, vx.x) * cx; + vec2 maxx = mat2(vx.x, -vx.y, vx.y, vx.x) * cx; + + vec2 cy = -C.yz; + vec2 vy = vec2(sqrt(dot(cy, cy) - r * r), r); + vec2 miny = mat2(vy.x, vy.y, -vy.y, vy.x) * cy; + vec2 maxy = mat2(vy.x, -vy.y, vy.y, vy.x) * cy; + + aabb = vec4(minx.x / minx.y * P00, miny.x / miny.y * P11, maxx.x / maxx.y * P00, maxy.x / maxy.y * P11); + aabb = aabb.xwzy * vec4(0.5f, -0.5f, 0.5f, -0.5f) + vec4(0.5f); // clip space -> uv space + + return true; +} + +layout( push_constant ) uniform PushBlock { + uint pass; + uint passes; +} PushConstant; + +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; + +layout (std140, binding = 1) buffer DrawCommands { + DrawCommand drawCommands[]; +}; + +layout (std140, binding = 2) buffer Instances { + Instance instances[]; +}; + +layout (binding = 3) uniform sampler2D samplerDepth; + +struct Frustum { + vec4 planes[6]; +}; + +vec4 normalizePlane( vec4 p ) { + return p / length(p.xyz); +} + +bool frustumCull( uint id ) { + if ( PushConstant.passes == 0 ) return true; + + const DrawCommand drawCommand = drawCommands[id]; + const Instance instance = instances[drawCommand.instanceID]; + + bool visible = false; + for ( uint pass = 0; pass < PushConstant.passes; ++pass ) { +#if 0 + vec4 sphere = aabbToSphere( instance.bounds ); + vec3 center = vec3( camera.viewport[pass].view * instance.model * vec4( ) ); +#else + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + #if 1 + vec4 planes[6]; { + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + planes[i*2+j] = normalizePlane( planes[i*2+j] ); + } + } + for ( uint p = 0; p < 6; ++p ) { + float d = max(instance.bounds.min.x * planes[p].x, instance.bounds.max.x * planes[p].x) + + max(instance.bounds.min.y * planes[p].y, instance.bounds.max.y * planes[p].y) + + max(instance.bounds.min.z * planes[p].z, instance.bounds.max.z * planes[p].z); + if ( d > -planes[p].w ) return true; + } + #else + vec4 corners[8] = { + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + }; + vec4 planes[6]; { + #pragma unroll 3 + for (int i = 0; i < 3; ++i) + #pragma unroll 2 + for (int j = 0; j < 2; ++j) { + planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + planes[i*2+j] = normalizePlane( planes[i*2+j] ); + } + } + #pragma unroll 8 + for ( uint p = 0; p < 8; ++p ) corners[p] = mat * corners[p]; + #pragma unroll 6 + for ( uint p = 0; p < 6; ++p ) { + #pragma unroll 8 + for ( uint q = 0; q < 8; ++q ) { + if ( dot( corners[q], planes[p] ) > 0 ) return true; + } + return false; + } + #endif +#endif + } + return visible; +} + +bool occlusionCull( uint id ) { + if ( PushConstant.passes == 0 ) return true; + + const DrawCommand drawCommand = drawCommands[id]; + const Instance instance = instances[drawCommand.instanceID]; + + bool visible = true; + for ( uint pass = 0; pass < PushConstant.passes; ++pass ) { +#if 1 + vec4 aabb; + vec4 sphere = aabbToSphere( instance.bounds ); + vec3 center = (camera.viewport[pass].view * instance.model * vec4(sphere.xyz, 1)).xyz; + float radius = (instance.model * vec4(sphere.w, 0, 0, 0)).x; + // center.y *= -1; + mat4 proj = camera.viewport[pass].projection; + float znear = proj[3][2]; + float P00 = proj[0][0]; + float P11 = proj[1][1]; + if (projectSphere(center, radius, znear, P00, P11, aabb)) { + ivec2 pyramidSize = textureSize( samplerDepth, 0 ); + float mips = mipLevels( pyramidSize ); + + float width = (aabb.z - aabb.x) * pyramidSize.x; + float height = (aabb.w - aabb.y) * pyramidSize.y; + + //find the mipmap level that will match the screen size of the sphere + float level = floor(log2(max(width, height))); + // if ( level == mips ) + --level; + level = clamp( level, 0, mips ); + + //sample the depth pyramid at that specific level + float depth = textureLod(samplerDepth, (aabb.xy + aabb.zw) * 0.5, level).x; + + float depthSphere = znear / (center.z - radius); + + instances[drawCommand.instanceID].bounds.padding1 = depth; + instances[drawCommand.instanceID].bounds.padding2 = proj[3][2]; + + //if the depth of the sphere is in front of the depth pyramid value, then the object is visible + visible = visible && depthSphere >= depth - DEPTH_BIAS; + } + +#else + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + vec3 boundsSize = instance.bounds.max - instance.bounds.min; + vec3 points[8] = { + instance.bounds.min.xyz, + instance.bounds.min.xyz + vec3(boundsSize.x,0,0), + instance.bounds.min.xyz + vec3(0, boundsSize.y,0), + instance.bounds.min.xyz + vec3(0, 0, boundsSize.z), + instance.bounds.min.xyz + vec3(boundsSize.xy,0), + instance.bounds.min.xyz + vec3(0, boundsSize.yz), + instance.bounds.min.xyz + vec3(boundsSize.x, 0, boundsSize.z), + instance.bounds.min.xyz + boundsSize.xyz, + }; + vec2 minXY = vec2(1); + vec2 maxXY = vec2(0); + + float minZ = 1; + float maxZ = 0; + + #pragma unroll 8 + for ( uint i = 0; i < 8; ++i ) { + vec4 clip = mat * vec4( points[i], 1 ); + clip.xyz /= clip.w; + clip.xy = clip.xy * 0.5 + 0.5; + + minXY.x = min(minXY.x, clip.x); + minXY.y = min(minXY.y, clip.y); + + maxXY.x = max(maxXY.x, clip.x); + maxXY.y = max(maxXY.y, clip.y); + + #if INVERSE + clip.z = 1.0 - clip.z; + maxZ = max(maxZ, clip.z); + #else + minZ = min(minZ, clip.z); + #endif + } + + if ( maxXY.x <= 0 || maxXY.y <= 0 ) return false; + if ( minXY.x >= 1 || minXY.y >= 1 ) return false; + + ivec2 depthSize = textureSize( samplerDepth, 0 ); + float mips = mipLevels( depthSize ); + + vec4 uv = vec4(minXY, maxXY); + + ivec2 clipSize = ivec2(maxXY - minXY) * depthSize; + float mip = mipLevels( clipSize ); + mip = clamp( mip, 0, mips ); + if ( mip == 0 ) { + mip = 1; + } else { + float lower = max(mip - 1, 0); + float scale = exp2(-lower); + vec2 a = floor(uv.xy * scale); + vec2 b = ceil(uv.zw * scale); + vec2 dims = b - a; + + // Use the lower level if we only touch <= 2 texels in both dimensions + if (dims.x <= 2 && dims.y <= 2) mip = lower; + } + + float depths[4] = { + textureLod( samplerDepth, uv.xy, mip ).r, + textureLod( samplerDepth, uv.zy, mip ).r, + textureLod( samplerDepth, uv.xw, mip ).r, + textureLod( samplerDepth, uv.zw, mip ).r, + }; + #if INVERSE + float minDepth = 1.0 - min(min(min(depths[0], depths[1]), depths[2]), depths[3]); + #else + float maxDepth = max(max(max(depths[0], depths[1]), depths[2]), depths[3]); + #endif + + instances[drawCommand.instanceID].bounds.padding1 = minZ; + instances[drawCommand.instanceID].bounds.padding2 = maxDepth; + + return minZ <= maxDepth; +#endif + } + return visible; +} + +void main() { + const uint gID = gl_GlobalInvocationID.x; + if ( !(0 <= gID && gID < drawCommands.length()) ) return; + + bool visible = frustumCull( gID ); +// if ( visible ) visible = occlusionCull( gID ); +// bool visible = occlusionCull( gID ); + drawCommands[gID].instances = visible ? 1 : 0; +} + + +/* + Frustum frustum; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + frustum.planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + frustum.planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + frustum.planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + frustum.planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + frustum.planes[i*2+j]*= length(frustum.planes[i*2+j].xyz); + } + for ( uint i = 0; i < 6; ++i ) { + vec4 plane = frustum.planes[i]; + float d = dot(instance.bounds.center, plane.xyz); + float r = dot(instance.bounds.extent, abs(plane.xyz)); + bool inside = d + r > -plane.w; + if ( !inside ) return 0; + } + return true; +*/ +/* + vec4 plane; + vec4 center = vec4( (max + min) * 0.5, 1 ); + vec4 extent = vec4( (max - min) * 0.5, 1 ); + center = mat * center; + extent = mat * extent; + center.xyz /= center.w; + extent.xyz /= extent.w; + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][0]; // left + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][0]; // right + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][1]; // bottom + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][1]; // top + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][2]; // near + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][2]; // far + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + +*/ +/* + for ( uint p = 0; p < 8; ++p ) { + vec4 t = corners[p]; + float w = abs(t.w); + visible = -w <= t.x && t.x <= w && -w <= t.y && t.y <= w && 0 <= t.z && t.z <= w; // && -w <= t.z && t.z <= w; + } +*/ +/* +mat4 convert( mat4 proj ) { + float f = -proj[1][1]; + float raidou = f / proj[0][0]; + float zNear = proj[3][2]; + float zFar = 32; + + float range = zNear - zFar; + + float Sx = f * raidou; + float Sy = f; + float Sz = (-zNear - zFar) / range; + float Pz = 2 * zFar * zNear / range; + + mat4 new = mat4(1.0); + new[0][0] = Sx; + new[1][1] = -Sy; + new[2][2] = Sz; + new[3][2] = Pz; + new[2][3] = 1; + return new; +} +*/ \ No newline at end of file diff --git a/belly/bin/data/shaders/graph/depth/frag.glsl b/belly/bin/data/shaders/graph/depth/frag.glsl new file mode 100644 index 00000000..79ed3c71 --- /dev/null +++ b/belly/bin/data/shaders/graph/depth/frag.glsl @@ -0,0 +1,73 @@ +#version 450 +#pragma shader_stage(fragment) + +#define FRAGMENT 1 +#define MAX_TEXTURES textures.length() + +layout (constant_id = 0) const uint TEXTURES = 1; + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 6) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 7) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 8) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 9) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 10) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 11) readonly buffer Lights { + Light lights[]; +}; + +#include "../../common/functions.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +void main() { + const uint triangleID = uint(inId.x); // gl_PrimitiveID + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + vec4 A = inColor * material.colorBase; + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + // alpha mode OPAQUE + if ( material.modeAlpha == 0 ) { + A.a = 1; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + if ( A.a < 1 ) discard; +} \ No newline at end of file diff --git a/belly/bin/data/shaders/graph/voxelize/frag.glsl b/belly/bin/data/shaders/graph/voxelize/frag.glsl new file mode 100644 index 00000000..3095eaec --- /dev/null +++ b/belly/bin/data/shaders/graph/voxelize/frag.glsl @@ -0,0 +1,142 @@ +#version 450 +#pragma shader_stage(fragment) + +// to-do: convert to use functions.h surface population functions + +#define FRAGMENT 1 +#define DEFERRED_SAMPLING 0 +#define CUBEMAPS 1 + +#define BLEND 1 +#define DEPTH_TEST 0 +#define USE_LIGHTMAP 1 +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CASCADES = 16; + +#define MAX_TEXTURES textures.length() +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 6) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 7) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 8) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; + +layout (std140, binding = 9) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 10) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 11) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 12, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; +layout (binding = 13, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; +#if VXGI_HDR + layout (binding = 14, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#else + layout (binding = 14, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#endif +#if DEPTH_TEST + layout (binding = 15, r16f) uniform volatile coherent image3D voxelDepth[CASCADES]; +#endif + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +#include "../../common/functions.h" + +void main() { + const uint CASCADE = inId.w; + if ( CASCADES <= CASCADE ) discard; + const vec3 P = inPosition.xzy * 0.5 + 0.5; + if ( abs(P.x) > 1 || abs(P.y) > 1 || abs(P.z) > 1 ) discard; + + const uint triangleID = uint(inId.x); // gl_PrimitiveID + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + surface.st.xy = inSt; + surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt)); + + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + surface.instance = instance; + + vec4 A = material.colorBase; + float M = material.factorMetallic; + float R = material.factorRoughness; + float AO = material.factorOcclusion; + + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + // alpha mode OPAQUE + if ( material.modeAlpha == 0 ) { + A.a = 1; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + if ( A.a == 0 ) discard; + +#if USE_LIGHTMAP + if ( validTextureIndex( instance.lightmapID ) ) { + A.rgb *= sampleTexture( instance.lightmapID, inSt ).rgb; + } +#endif + + // sample normal + vec3 N = inNormal; + vec3 T = inTangent; + T = normalize(T - dot(T, N) * N); + vec3 B = cross(T, N); + mat3 TBN = mat3(T, B, N); +// mat3 TBN = mat3(N, B, T); + if ( T != vec3(0) && validTextureIndex( material.indexNormal ) ) { + N = TBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - 1.0 ); + } + + const ivec3 uvw = ivec3(P * imageSize(voxelRadiance[CASCADE])); + +#if DEPTH_TEST + const float outDepth = length(inPosition.xzy); + const float inDepth = imageLoad(voxelDepth[CASCADE], uvw).r; + if ( inDepth != 0 && inDepth < outDepth ) discard; + imageStore(voxelDepth[CASCADE], uvw, vec4(inDepth, 0, 0, 0)); +#endif + + imageStore(voxelId[CASCADE], uvw, uvec4(uvec2(drawID + 1, instanceID + 1), 0, 0)); + imageStore(voxelNormal[CASCADE], uvw, vec4(encodeNormals( normalize( N ) ), 0, 0)); +#if BLEND + // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA + const vec4 src = A * inColor; + const vec4 dst = imageLoad(voxelRadiance[CASCADE], uvw); + imageStore(voxelRadiance[CASCADE], uvw, blend( src, dst, src.a ) ); +#else + imageStore(voxelRadiance[CASCADE], uvw, A ); +#endif +} diff --git a/belly/bin/data/shaders/graph/voxelize/geom.glsl b/belly/bin/data/shaders/graph/voxelize/geom.glsl new file mode 100644 index 00000000..65259479 --- /dev/null +++ b/belly/bin/data/shaders/graph/voxelize/geom.glsl @@ -0,0 +1,93 @@ +#version 450 +#pragma shader_stage(geometry) + +layout(triangles) in; +layout(triangle_strip, max_vertices = 3) out; + +layout (location = 0) flat in uvec4 inId[]; +layout (location = 1) flat in vec4 inPOS0[]; +layout (location = 2) in vec4 inPOS1[]; +layout (location = 3) in vec3 inPosition[]; +layout (location = 4) in vec2 inUv[]; +layout (location = 5) in vec4 inColor[]; +layout (location = 6) in vec2 inSt[]; +layout (location = 7) in vec3 inNormal[]; +layout (location = 8) in vec3 inTangent[]; + +layout (location = 0) flat out uvec4 outId; +layout (location = 1) flat out vec4 outPOS0; +layout (location = 2) out vec4 outPOS1; +layout (location = 3) out vec3 outPosition; +layout (location = 4) out vec2 outUv; +layout (location = 5) out vec4 outColor; +layout (location = 6) out vec2 outSt; +layout (location = 7) out vec3 outNormal; +layout (location = 8) out vec3 outTangent; + +layout (binding = 4) uniform UBO { + mat4 voxel; + + float cascadePower; + float granularity; + float voxelizeScale; + float occlusionFalloff; + + uint shadows; + uint padding1; + uint padding2; + uint padding3; +} ubo; + +float cascadePower( uint x ) { + return pow(1 + x, ubo.cascadePower); +// return max( 1, x * ubo.cascadePower ); +} + +#define USE_CROSS 0 +void main(){ + const float HALF_PIXEL = ubo.voxelizeScale; + const vec3 C = ( inPosition[0] + inPosition[1] + inPosition[2] ) / 3.0; + +#if USE_CROSS + const vec3 N = abs(cross(inPosition[2] - inPosition[0], inPosition[1] - inPosition[0])); +#else + const vec3 N = abs(inNormal[0] + inNormal[1] + inNormal[2]); + uint A = N.y > N.x ? 1 : 0; + A = N.z > N[A] ? 2 : A; +#endif + + const uint CASCADE = inId[0].w; + vec3 P[3] = { + 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), + }; + + #pragma unroll 3 + for( uint i = 0; i < 3; ++i ){ + const vec3 D = normalize( inPosition[i] - C ) * HALF_PIXEL; + + outPosition = P[i] + D; + outPOS0 = inPOS0[i]; + outPOS1 = inPOS1[i]; + outUv = inUv[i]; + outSt = inSt[i]; + outColor = inColor[i]; + outNormal = inNormal[i]; + outTangent = inTangent[i]; + outId = inId[i]; + + const vec3 P = outPosition; // + D; + #if USE_CROSS + if ( N.z > N.x && N.z > N.y ) gl_Position = vec4(P.x, P.y, 0, 1); + else if ( N.x > N.y && N.x > N.z ) gl_Position = vec4(P.y, P.z, 0, 1); + else gl_Position = vec4(P.x, P.z, 0, 1); + #else + if ( A == 0 ) gl_Position = vec4(P.zy, 0, 1 ); + else if ( A == 1 ) gl_Position = vec4(P.xz, 0, 1 ); + else if ( A == 2 ) gl_Position = vec4(P.xy, 0, 1 ); + #endif + EmitVertex(); + } + EndPrimitive(); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/gui/base/frag.glsl b/belly/bin/data/shaders/gui/base/frag.glsl new file mode 100644 index 00000000..05f07fa7 --- /dev/null +++ b/belly/bin/data/shaders/gui/base/frag.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(fragment) + +#define GLYPH 0 +#include "../gui/frag.h" diff --git a/belly/bin/data/shaders/gui/base/vert.glsl b/belly/bin/data/shaders/gui/base/vert.glsl new file mode 100644 index 00000000..c6455702 --- /dev/null +++ b/belly/bin/data/shaders/gui/base/vert.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(vertex) + +#define GLYPH 0 +#include "../gui/vert.h" diff --git a/belly/bin/data/shaders/gui/gui/frag.h b/belly/bin/data/shaders/gui/gui/frag.h new file mode 100644 index 00000000..6343874d --- /dev/null +++ b/belly/bin/data/shaders/gui/gui/frag.h @@ -0,0 +1,45 @@ +#define TEXTURES 1 +#define CUBEMAPS 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" +#include "./gui.h" + +layout (binding = 1) uniform sampler2D samplerTexture; + +layout (location = 0) in vec2 inUv; +layout (location = 1) in flat Gui inGui; +layout (location = 7) in flat Glyph inGlyph; + +layout (location = 0) out vec4 outAlbedo; + +void main() { + if ( inUv.x < inGui.offset.x || inUv.y < inGui.offset.y || inUv.x > inGui.offset.z || inUv.y > inGui.offset.w ) discard; + + const vec2 uv = inUv.xy; + const float mip = mipLevel(dFdx(inUv), dFdy(inUv)); + vec4 C = inGui.color; +#if GLYPH + if ( enabled(inGui.mode, 1) ) { + outAlbedo = inGui.color; + return; + } + const float sampled = texture(samplerTexture, inUv).r; + if ( enabled(inGui.mode, 2) ) { + const float smoothing = ( inGlyph.spread > 0 && inGlyph.scale > 0 ) ? 0.25 / (inGlyph.spread * inGlyph.scale) : 0.25 / (4 * 1.5); + const float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, sampled); + const float alpha = smoothstep(inGlyph.weight - smoothing, inGlyph.weight + smoothing, sampled); + if ( alpha < 0.001 || alpha > 1 ) discard; + C = mix(inGlyph.stroke, inGui.color, outlining); + C.a = inGui.color.a * alpha; + } else { + if ( sampled < 0.001 || sampled > 1 ) discard; + C *= sampled; + } +#else + if ( enabled(inGui.mode, 0) ) C = inGui.color; + else C *= textureLod( samplerTexture, uv, mip ); +#endif + outAlbedo = C; +} \ No newline at end of file diff --git a/belly/bin/data/shaders/gui/gui/gui.h b/belly/bin/data/shaders/gui/gui/gui.h new file mode 100644 index 00000000..6a06ac56 --- /dev/null +++ b/belly/bin/data/shaders/gui/gui/gui.h @@ -0,0 +1,18 @@ +struct Gui { + vec4 offset; + vec4 color; + + int mode; + float depth; + float padding1; + float padding2; +}; + +struct Glyph { + vec4 stroke; + + int spread; + float weight; + float scale; + float padding; +}; \ No newline at end of file diff --git a/belly/bin/data/shaders/gui/gui/vert.h b/belly/bin/data/shaders/gui/gui/vert.h new file mode 100644 index 00000000..63ac1c3b --- /dev/null +++ b/belly/bin/data/shaders/gui/gui/vert.h @@ -0,0 +1,37 @@ +layout (constant_id = 0) const uint PASSES = 6; +layout (location = 0) in vec2 inPos; +layout (location = 1) in vec2 inUv; + +#include "./gui.h" + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +struct Matrices { + mat4 model[PASSES]; +}; +layout (binding = 0) uniform UBO { + Matrices matrices; + Gui gui; +#if GLYPH + Glyph glyph; +#endif +} ubo; + +layout (location = 0) out vec2 outUv; +layout (location = 1) out flat Gui outGui; +#if GLYPH + layout (location = 7) out flat Glyph outGlyph; +#endif + +void main() { + outUv = inUv; + outGui = ubo.gui; +#if GLYPH + outGlyph = ubo.glyph; +#endif + + gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, ubo.gui.depth, 1.0); +} \ No newline at end of file diff --git a/belly/bin/data/shaders/gui/text/frag.glsl b/belly/bin/data/shaders/gui/text/frag.glsl new file mode 100644 index 00000000..506229e8 --- /dev/null +++ b/belly/bin/data/shaders/gui/text/frag.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(fragment) + +#define GLYPH 1 +#include "../gui/frag.h" diff --git a/belly/bin/data/shaders/gui/text/vert.glsl b/belly/bin/data/shaders/gui/text/vert.glsl new file mode 100644 index 00000000..60465aaa --- /dev/null +++ b/belly/bin/data/shaders/gui/text/vert.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(vertex) + +#define GLYPH 1 +#include "../gui/vert.h" diff --git a/belly/bin/data/shaders/raytrace/shader.ray-gen.glsl b/belly/bin/data/shaders/raytrace/shader.ray-gen.glsl new file mode 100644 index 00000000..40eca388 --- /dev/null +++ b/belly/bin/data/shaders/raytrace/shader.ray-gen.glsl @@ -0,0 +1,401 @@ +#version 460 + +#extension GL_EXT_ray_tracing : enable +#extension GL_ARB_shader_clock : enable + +#pragma shader_stage(raygen) +layout (constant_id = 0) const uint PASSES = 2; +layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 2) const uint CUBEMAPS = 8; +layout (constant_id = 3) const uint CASCADES = 1; + +// shader type settings +#define RT 1 +#define DEFERRED_SAMPLING 1 +#define BUFFER_REFERENCE 1 +#define UINT64_ENABLED 1 +#define PBR 1 +// shader function settings +#define FOG 1 + +//force it off +#define BARYCENTRIC 0 +#define BARYCENTRIC_CALCULATE 0 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +layout (binding = 0) uniform accelerationStructureEXT tlas; + +layout (binding = 1, rgba32f) uniform volatile coherent image2D outImage; + +layout (binding = 2) uniform UBO { + EyeMatrices eyes[2]; + + Settings settings; +} ubo; + +layout (std140, binding = 3) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 4) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 5) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 6) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 7) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 8) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 9) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 10) uniform sampler3D samplerNoise; +#if VXGI + layout (binding = 11) uniform usampler3D voxelId[CASCADES]; + layout (binding = 12) uniform sampler3D voxelNormal[CASCADES]; + layout (binding = 13) uniform sampler3D voxelRadiance[CASCADES]; +#endif + +layout (location = 0) rayPayloadEXT RayTracePayload payload; + +layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; +layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; +layout(buffer_reference, scalar) buffer Indirects { DrawCommand dc[]; }; + +layout(buffer_reference, scalar) buffer VPos { vec3 v[]; }; +layout(buffer_reference, scalar) buffer VUv { vec2 v[]; }; +layout(buffer_reference, scalar) buffer VColor { uint v[]; }; +layout(buffer_reference, scalar) buffer VSt { vec2 v[]; }; +layout(buffer_reference, scalar) buffer VNormal { vec3 v[]; }; +layout(buffer_reference, scalar) buffer VTangent { vec3 v[]; }; +layout(buffer_reference, scalar) buffer VID { uint v[]; }; + +#include "../common/functions.h" +#include "../common/light.h" +#include "../common/fog.h" +#if VXGI + #include "../common/vxgi.h" +#endif + +void trace( Ray ray, float tMin, float tMax ) { + uint rayFlags = gl_RayFlagsOpaqueEXT; + uint cullMask = 0xFF; + + payload.hit = false; + surface.position.eye.z = tMax; + traceRayEXT(tlas, rayFlags, cullMask, 0, 0, 0, ray.origin, tMin, ray.direction, tMax, 0); +} +void trace( Ray ray, float tMin ) { + uint rayFlags = gl_RayFlagsOpaqueEXT; + uint cullMask = 0xFF; + + float tMax = ubo.settings.rt.defaultRayBounds.y; + + payload.hit = false; + surface.position.eye.z = tMax; + traceRayEXT(tlas, rayFlags, cullMask, 0, 0, 0, ray.origin, tMin, ray.direction, tMax, 0); +} + +void trace( Ray ray ) { + trace( ray, ubo.settings.rt.defaultRayBounds.x, ubo.settings.rt.defaultRayBounds.y ); +} + +float shadowFactor( const Light light, float def ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = light.position - ray.origin; + + float tMin = ubo.settings.rt.defaultRayBounds.x; + float tMax = length(ray.direction) - 0.0001; + + ray.direction = normalize(ray.direction); + + uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT; + uint cullMask = 0xFF; + + payload.hit = true; + traceRayEXT(tlas, rayFlags, cullMask, 0, 0, 0, ray.origin, tMin, ray.direction, tMax, 0); + + return payload.hit ? 0.0 : 1.0; +} + +void directLighting() { +#if VXGI + indirectLighting(); +#endif + + surface.light.rgb += surface.material.albedo.rgb * ubo.settings.lighting.ambient.rgb * surface.material.occlusion; // add ambient lighting + surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting +#if PBR + pbr(); +#elif LAMBERT + lambert(); +#elif PHONG + phong(); +#endif + surface.fragment.rgb += surface.light.rgb; + surface.fragment.a = surface.material.albedo.a; +} + +vec4 traceStep( Ray ray ) { + Ray fogRay = ray; + float eyeDepth = 0; + vec4 outFrag = vec4(0); + + // initial condition + { + trace( ray ); + + if ( payload.hit ) { + populateSurface( payload ); + directLighting(); + } else if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], ray.direction ); + surface.fragment.a = 4096; + surface.position.eye.z /= 8; + } else { + surface.fragment = vec4(ubo.settings.lighting.ambient.rgb, 0.5); + } + #if FOG + fog( ray, surface.fragment.rgb, surface.fragment.a ); + #endif + outFrag = surface.fragment; + eyeDepth = surface.position.eye.z; + } + + + // "transparency" + if ( payload.hit && surface.material.albedo.a < 0.999 ) { + const vec4 TRANSPARENCY_COLOR = vec4(1.0 - surface.material.albedo.a); + + if ( surface.material.albedo.a < 0.001 ) outFrag = vec4(0); + + RayTracePayload surfacePayload = payload; + Ray transparency; + transparency.direction = ray.direction; + transparency.origin = surface.position.world; + fogRay = transparency; + + trace( transparency, ubo.settings.rt.alphaTestOffset ); + if ( payload.hit ) { + populateSurface( payload ); + directLighting(); + } else if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], ray.direction ); + surface.fragment.a = 4096; + surface.position.eye.z /= 8; + } + #if FOG + fog( transparency, surface.fragment.rgb, surface.fragment.a ); + #endif + outFrag += TRANSPARENCY_COLOR * surface.fragment; + eyeDepth = surface.position.eye.z; + + payload = surfacePayload; + populateSurface( payload ); + } +#if FOG + { + // surface.position.eye.z = eyeDepth; + // fog( fogRay, outFrag.rgb, outFrag.a ); + // fog( ray, surface.fragment.rgb, surface.fragment.a ); + } +#endif + + // reflection + if ( payload.hit ) { + const float REFLECTIVITY = 1.0 - surface.material.roughness; + const vec4 REFLECTED_ALBEDO = surface.material.albedo * REFLECTIVITY; + + if ( REFLECTIVITY > 0.001 ) { + RayTracePayload surfacePayload = payload; + + Ray reflection; + reflection.origin = surface.position.world; + reflection.direction = reflect( ray.direction, surface.normal.world ); + + trace( reflection ); + + if ( payload.hit ) { + populateSurface( payload ); + directLighting(); + } else if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], reflection.direction ); + surface.fragment.a = 4096; + } + #if FOG + fog( reflection, surface.fragment.rgb, surface.fragment.a ); + #endif + outFrag += REFLECTED_ALBEDO * surface.fragment; + + payload = surfacePayload; + populateSurface( payload ); + } + } + + return outFrag; +} + +void main() { +// if ( ubo.settings.mode.frameNumber > 16 ) return; +// prngSeed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, ubo.settings.mode.frameNumber); + prngSeed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, int(clockARB())); + surface.pass = PushConstant.pass; + surface.subID = 0; + vec4 outFrag = vec4(0); + + const uint SAMPLES = min(ubo.settings.rt.samples, 4); + const uint NUM_PATHS = min(ubo.settings.rt.paths, 8); +#if 1 + const uint FRAME_ACCUMULATION_VALUE = ubo.settings.rt.frameAccumulationMinimum > 0 ? min(ubo.settings.rt.frameAccumulationMinimum, ubo.settings.mode.frameNumber + 1) : ubo.settings.mode.frameNumber + 1; +#else + const uint FRAME_ACCUMULATION_VALUE = min(32, ubo.settings.mode.frameNumber + 1); +#endif + const float BLEND_FACTOR = 1.0f / float(FRAME_ACCUMULATION_VALUE); + uint FRAME_NUMBER = ubo.settings.mode.frameNumber; + +#if 0 + for ( uint samp = 0; samp < SAMPLES; ++samp, ++FRAME_NUMBER ) { + { + const vec2 center = ( FRAME_NUMBER > 0 ) ? vec2( rnd(), rnd() ) : vec2(0.5); + const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + center) / vec2(gl_LaunchSizeEXT.xy); + #if 1 + vec4 target = ubo.eyes[surface.pass].iProjection * vec4(inUv.x * 2.0f - 1.0f, inUv.y * 2.0f - 1.0f, 1, 1); + vec4 direction = ubo.eyes[surface.pass].iView * vec4(normalize(target.xyz), 0); + + surface.ray.direction = vec3(direction); + surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; + #else + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + 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.eyes[surface.pass].eyePos.xyz; + #endif + } + + { + vec4 curValue = vec4(0); + vec4 curWeight = vec4(1); + for ( uint path = 0; path < NUM_PATHS; ++path ) { + vec4 stepValue = traceStep( surface.ray ); + curValue += stepValue * curWeight; + + if ( !payload.hit ) break; + + surface.ray.origin = surface.position.world; + surface.ray.direction = samplingHemisphere( prngSeed, surface.normal.world ); + curWeight *= surface.material.albedo * dot( surface.ray.direction, surface.normal.world ); + + if ( length(curWeight) < 0.01 ) break; + } + outFrag += curValue; + } + } + { + outFrag /= SAMPLES; + } +#elif 0 + { + const vec2 center = ( FRAME_NUMBER > 0 ) ? vec2( rnd(), rnd() ) : vec2(0.5); + const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + center) / vec2(gl_LaunchSizeEXT.xy); + #if 0 + vec4 target = ubo.eyes[surface.pass].iProjection * vec4(inUv.x * 2.0f - 1.0f, inUv.y * 2.0f - 1.0f, 1, 1); + vec4 direction = ubo.eyes[surface.pass].iView * vec4(normalize(target.xyz), 0); + + surface.ray.direction = vec3(direction); + surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; + #else + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + 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.eyes[surface.pass].eyePos.xyz; + #endif + } + + { + vec4 curValue = vec4(0); + vec4 curWeight = vec4(1); + for ( uint path = 0; path < NUM_PATHS; ++path ) { + vec4 stepValue = traceStep( surface.ray ); + curValue += stepValue * curWeight; + + if ( !payload.hit ) break; + + surface.ray.origin = surface.position.world; + surface.ray.direction = samplingHemisphere( prngSeed, surface.normal.world ); + curWeight *= surface.material.albedo * dot( surface.ray.direction, surface.normal.world ); + + if ( length(curWeight) < 0.01 ) break; + } + outFrag += curValue; + } + { + surface.fragment = outFrag; + } +#else + { + const vec2 center = ( FRAME_NUMBER > 0 ) ? vec2( rnd(), rnd() ) : vec2(0.5); + const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + center) / vec2(gl_LaunchSizeEXT.xy); + #if 0 + vec4 target = ubo.eyes[surface.pass].iProjection * vec4(inUv.x * 2.0f - 1.0f, inUv.y * 2.0f - 1.0f, 1, 1); + vec4 direction = ubo.eyes[surface.pass].iView * vec4(normalize(target.xyz), 0); + + surface.ray.direction = vec3(direction); + surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; + #else + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + 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.eyes[surface.pass].eyePos.xyz; + #endif + } + { + surface.fragment = traceStep( surface.ray ); + } +#endif + { + #if BLOOM + float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); + vec4 outFragBright = brightness > ubo.threshold ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); + // imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), outFragBright); + #endif + #if FOG + fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); + #endif + } + + { + outFrag = surface.fragment; + outFrag.a = 1; + } + + if ( ubo.settings.mode.frameNumber == 0 ) { + imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), outFrag); + } else { + // if ( length(outFrag.rgb) < 0.01f ) return; + vec4 blended = mix(imageLoad(outImage, ivec2(gl_LaunchIDEXT.xy)), outFrag, BLEND_FACTOR); + + imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), blended); + } +} \ No newline at end of file diff --git a/belly/bin/data/shaders/raytrace/shader.ray-hit-any.glsl b/belly/bin/data/shaders/raytrace/shader.ray-hit-any.glsl new file mode 100644 index 00000000..20cca3ed --- /dev/null +++ b/belly/bin/data/shaders/raytrace/shader.ray-hit-any.glsl @@ -0,0 +1,28 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_EXT_buffer_reference : enable +#extension GL_EXT_buffer_reference2 : enable +#extension GL_EXT_scalar_block_layout : enable +#pragma shader_stage(anyhit) +layout (constant_id = 0) const uint PASSES = 2; +layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 2) const uint CUBEMAPS = 128; + +#define RT 1 +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout(location = 0) rayPayloadInEXT RayTracePayload payload; + +hitAttributeEXT vec2 attribs; + +void main() { + payload.hit = true; + payload.instanceID = gl_InstanceCustomIndexEXT; + payload.primitiveID = gl_PrimitiveID; + payload.attributes = attribs; + +} \ No newline at end of file diff --git a/belly/bin/data/shaders/raytrace/shader.ray-hit-closest.glsl b/belly/bin/data/shaders/raytrace/shader.ray-hit-closest.glsl new file mode 100644 index 00000000..d8aec3a6 --- /dev/null +++ b/belly/bin/data/shaders/raytrace/shader.ray-hit-closest.glsl @@ -0,0 +1,25 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_nonuniform_qualifier : enable + +#pragma shader_stage(closest) +layout (constant_id = 0) const uint PASSES = 2; +layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 2) const uint CUBEMAPS = 128; + +#define RT 1 +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout(location = 0) rayPayloadInEXT RayTracePayload payload; + +hitAttributeEXT vec2 attribs; + +void main() { + payload.hit = true; + payload.instanceID = gl_InstanceCustomIndexEXT; + payload.primitiveID = gl_PrimitiveID; + payload.attributes = attribs; +} \ No newline at end of file diff --git a/belly/bin/data/shaders/raytrace/shader.ray-miss.glsl b/belly/bin/data/shaders/raytrace/shader.ray-miss.glsl new file mode 100644 index 00000000..49d0a1e5 --- /dev/null +++ b/belly/bin/data/shaders/raytrace/shader.ray-miss.glsl @@ -0,0 +1,15 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#pragma shader_stage(miss) + +#define RT 1 +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout(location = 0) rayPayloadInEXT RayTracePayload payload; + +void main() { + payload.hit = false; +} \ No newline at end of file diff --git a/bin/data/config.json b/bin/data/config.json index 8f2b07f5..0adc5388 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -1,7 +1,7 @@ { "engine": { "scenes": { - "start": "StartMenu", + "start": "SourceEngine", "matrix": { "reverseInfinite": true }, "meshes": { "interleaved": false }, "lights": { "enabled": true, @@ -31,10 +31,10 @@ "vxgi": { "limiter": 0.5, // "limiter": 0.125, - "size": 128, + "size": 192, "dispatch": 8, "cascades": 3, - "cascadePower": 3, + "cascadePower": 1.5, "granularity": 12, "voxelizeScale": 1, "occlusionFalloff": 2, @@ -57,37 +57,23 @@ } }, "graph": { - "initial buffer elements": 131072 + "initial buffer elements": 1024 }, "ext": { "vulkan": { + "version": 1.3, "validation": { "enabled": false, "filters": [ - "0x35d7ea98", // VUID-vkUpdateDescriptorSets-None-03047 () + // "0x4dae5635" // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout - "0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps) - "0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls) - "0x23e43bb7", // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls) - - "0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) - "0x7d560045", // VUID-vkCmdPipelineBarrier-dstStageMask-06462 (false positive, pipeline barrier for BLAS) - - "0xde55a405", // VUID-VkDescriptorImageInfo-imageLayout-00344 (bitches because ) - "0x9410d614", // VUID-vkCmdDrawIndexedIndirect-None-02699 (same as above) - - "0x97c889fd", // VUID-VkBufferDeviceAddressInfo-buffer-02601 (false positive, lies about not setting flags when I explicitly set flags for scratch) - "0xea5edaf3" // VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03674 (same as above) - - // "0x9cacd67a" // UNASSIGNED-CoreValidation-DrawState-QueryNotReset (false positive) - - // "0xe91b58a0" // VUID-vkCmdDrawIndexed-None-02686 (?) - - // "0x124ffb34", // VUID-VkImageMemoryBarrier-oldLayout-01197 (hacky bloom-shit) - // "0x8ab1932c", // VUID-VkImageViewCreateInfo-imageViewType-04973 (hacky bloom-shit) - - // "0x8e1000ad", // VUID-vkCmdDrawIndexedIndirect-None-04008 (bitches without nullDescriptor) - // "0x9dd97212", // VUID-vkCmdDrawIndexedIndirect-None-02721 (bitches without nullDescriptor) - // "0x36481fcb", // VUID-vkCmdBindVertexBuffers-pBuffers-04001 (bitches without nullDescriptor) + "0x609a13b" // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls) + ,"0x141cb623" // UNASSIGNED-Threading-MultipleThreads ("false-positive" multithreading) + ,"0xe5d1743c" // VUID-vkCmdDispatch-None-02699 (problem when using VXGI) + ,"0x71500fba" // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) + ,"0x35d7ea98" // VUID-vkUpdateDescriptorSets-None-03047 (bitches without VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT or VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT) + ,"0x8e1000ad" // VUID-vkCmdDrawIndexedIndirect-None-04008 (bitches without nullDescriptor) + ,"0x9dd97212" // VUID-vkCmdDrawIndexedIndirect-None-02721 (bitches without nullDescriptor) + ,"0x36481fcb" // VUID-vkCmdBindVertexBuffers-pBuffers-04001 (bitches without nullDescriptor) ] }, "framebuffer": { @@ -98,20 +84,23 @@ // "size": [ 960, 540 ] // "size": [ 640, 480 ] }, - "gpu": 1, + "gpu": 7817, "experimental": { "rebuild on tick begin": false, "batch queue submissions": true, - "dedicated thread": true + "dedicated thread": false, + "memory budget": false + }, + "invariant": { + "default stage buffers": true }, - "invariant": {}, "pipelines": { "deferred": true, - "vsync": false, - "hdr": false, + "vsync": true, + "hdr": true, "vxgi": false, - "culling": false, - "bloom": false, + "culling": true, + "bloom": true, "rt": false, "postProcess": false, "fsr": false @@ -122,62 +111,117 @@ "normal": "R16G16B16A16_SFLOAT", "position": "R16G16B16A16_SFLOAT" }, - "features": [ - "shaderDrawParameters", - "multiDrawIndirect", - "fillModeNonSolid", - "wideLines", - "independentBlend", - "deviceCoherentMemory", - "robustBufferAccess", - "samplerAnisotropy", - "sampleRateShading", - "nullDescriptor", - "fragmentStoresAndAtomics", - "geometryShader", - "multiViewport", - "shaderInt16", - "shaderFloat16", - "shaderInt64", - "shaderFloat64", - "shaderSubgroupClock", - "shaderSampledImageArrayDynamicIndexing", - "shaderStorageImageArrayDynamicIndexing", - "shaderStorageImageMultisample", - // 1.2 features - "descriptorIndexing", + "versions": { + "1.0": { + "extensions": { + "instance": [], + "device": [ + "VK_KHR_swapchain" + ] + }, + "features": [ + "shaderDrawParameters", + "multiDrawIndirect", + "fillModeNonSolid", + "wideLines", + "independentBlend", + "deviceCoherentMemory", + "robustBufferAccess", + "samplerAnisotropy", + "sampleRateShading" + ], + "featureChain": [] + }, + "1.1": { + "extensions": { + "instance": [ + "VK_KHR_get_physical_device_properties2" + ,"VK_KHR_get_surface_capabilities2" + ], + "device": [ + "VK_EXT_memory_budget" + ,"VK_EXT_descriptor_indexing" + ,"VK_KHR_buffer_device_address" + ] + }, + "features": [ + "nullDescriptor" + ,"fragmentStoresAndAtomics" + ,"geometryShader" + ,"multiViewport" + ,"shaderInt16" + ,"shaderFloat16" + ,"shaderInt64" + ,"shaderFloat64" + ,"shaderSubgroupClock" + ,"shaderSampledImageArrayDynamicIndexing" + ,"shaderStorageImageArrayDynamicIndexing" + ,"shaderStorageImageMultisample" + + ,"shaderSampledImageArrayNonUniformIndexing" + ,"shaderStorageImageArrayNonUniformIndexing" - "shaderOutputViewportIndex", - "shaderOutputLayer", + ,"descriptorIndexing" + ,"bufferDeviceAddress" + ], + "featureChain": [ + "physicalDevice2" + ,"shaderDrawParameters" + ,"robustness" + ,"shaderClock" - "shaderSampledImageArrayNonUniformIndexing", - "shaderStorageImageArrayNonUniformIndexing", - "runtimeDescriptorArray", - "descriptorBindingVariableDescriptorCount", + ,"descriptorIndexing" + ,"bufferDeviceAddress" + ] + }, + "1.2": { + "extensions": { + "instance": [ + "VK_KHR_get_physical_device_properties2", + "VK_KHR_get_surface_capabilities2" + ], + "device": [ + "VK_KHR_deferred_host_operations" + ,"VK_EXT_shader_viewport_index_layer" + ,"VK_KHR_spirv_1_4" + ,"VK_KHR_shader_float_controls" + ,"VK_KHR_shader_clock" + ,"VK_EXT_subgroup_size_control" + ,"VK_KHR_acceleration_structure" + ,"VK_KHR_ray_tracing_pipeline" + ,"VK_KHR_ray_query" - "hostQueryReset", - "bufferDeviceAddress" - ], - "extensions": { - "instance": [ - "VK_KHR_get_physical_device_properties2", - "VK_KHR_get_surface_capabilities2" - ], - "device": [ - "VK_KHR_swapchain", - "VK_EXT_shader_viewport_index_layer", - "VK_KHR_acceleration_structure", - "VK_KHR_ray_tracing_pipeline", - "VK_KHR_buffer_device_address", - "VK_KHR_deferred_host_operations", - "VK_EXT_descriptor_indexing", - "VK_KHR_spirv_1_4", - "VK_KHR_shader_float_controls", - "VK_KHR_shader_clock", - "VK_KHR_ray_query", - "VK_EXT_subgroup_size_control", - "VK_AMD_shader_explicit_vertex_parameter" // "VK_KHR_fragment_shader_barycentric" - ] + // ,"VK_AMD_shader_explicit_vertex_parameter" + // ,"VK_KHR_fragment_shader_barycentric" + ] + }, + "features": [ + "hostQueryReset", + + "runtimeDescriptorArray", + "descriptorBindingVariableDescriptorCount", + + "shaderOutputViewportIndex", + "shaderOutputLayer" + ], + "featureChain": [ + "physicalDeviceVulkan12" + // for ray-tracing + ,"fragmentShaderBarycentric" + ,"rayTracingPipeline" + ,"rayQuery" + ,"accelerationStructure" + ,"subgroupSizeControl" + ] + }, + "1.3": { + "extensions": { + "instance": [], + "device": [] + }, + "features": [], + "featureChain": [] + } } }, "opengl": { @@ -226,7 +270,7 @@ }, "reactphysics": { "timescale": 0.01666666666, - "interpolate": false, + "interpolate": true, "gravity": { "mode": "universal", "constant": 6.67408e-11 @@ -276,7 +320,7 @@ "render modes": { "gui": true, "deferred": true }, "limiters": { "deltaTime": 5, - "framerate": "auto" + "framerate": 0 // "auto" }, "threads": { "workers" : "auto", @@ -306,18 +350,21 @@ }, "hooks": { "defer lazy calls": true + }, + "scene": { + "print task calls": false } } }, "window" : { "terminal" : { "ncurses" : false, - "visible" : false + "visible" : true }, "keyboard" : { "repeat" : false }, - "cursor" : { + "mouse" : { "visible" : true, "center" : false, "sensitivity": [ 0.75, 0.75 ], diff --git a/bin/data/entities/burger.json b/bin/data/entities/burger.json index df96f577..5fe475e9 100644 --- a/bin/data/entities/burger.json +++ b/bin/data/entities/burger.json @@ -1,7 +1,7 @@ { "type": "Object", "name": "Burger", - "ignore": true, + "ignore": false, "import": "/model.json", "assets": [ // "/burger/burger.glb" diff --git a/bin/data/entities/gui/mainmenu/scripts/menu.lua b/bin/data/entities/gui/mainmenu/scripts/menu.lua index 7d6ec234..23c11482 100644 --- a/bin/data/entities/gui/mainmenu/scripts/menu.lua +++ b/bin/data/entities/gui/mainmenu/scripts/menu.lua @@ -28,8 +28,8 @@ if not timer:running() then timer:start() end local playSound = function( key ) local url = "/ui/" .. key .. ".ogg" - local assetLoader = scene:getComponent("Asset") - assetLoader:cache(ent:formatHookName("asset:Load.%UID%"), string.resolveURI(url)) +-- local assetLoader = scene:getComponent("Asset") +-- assetLoader:cache(ent:formatHookName("asset:Load.%UID%"), string.resolveURI(url)) end local destination = function( obj, x, y, z ) local static = Static.get(obj) diff --git a/bin/data/entities/gui/pause/scripts/menu.lua b/bin/data/entities/gui/pause/scripts/menu.lua index f5373f66..23599258 100644 --- a/bin/data/entities/gui/pause/scripts/menu.lua +++ b/bin/data/entities/gui/pause/scripts/menu.lua @@ -48,8 +48,8 @@ destination(children.quit, -1.5, nil, 0) local playSound = function( key ) local url = "/ui/" .. key .. ".ogg" - local assetLoader = scene:getComponent("Asset") - assetLoader:cache(soundEmitter:formatHookName("asset:Load.%UID%"), string.resolveURI(url), "") +-- local assetLoader = scene:getComponent("Asset") +-- assetLoader:cache(soundEmitter:formatHookName("asset:Load.%UID%"), string.resolveURI(url), "") end ent:addHook("menu:Close.%UID%", function( json ) diff --git a/bin/data/entities/light.json b/bin/data/entities/light.json index 4b07bfa5..1ec312c7 100644 --- a/bin/data/entities/light.json +++ b/bin/data/entities/light.json @@ -24,12 +24,12 @@ "power": 100, "fov": 90, "bias": { - "constant": 1.25, - "slope": 1.75, - "shader": 0.00000005 // 0.000005 //0.000000005 + "constant": 1, + "slope": 1, + "shader": 0.00005 // 0.000005 //0.000000005 }, - "radius": [0.25, 0], - "resolution": 256, + "radius": [0.5, 0], + "resolution": 1024, "shadows": true, "dynamic": true } diff --git a/bin/data/entities/playerModel.json b/bin/data/entities/playerModel.json index c8f1796e..4a340d63 100644 --- a/bin/data/entities/playerModel.json +++ b/bin/data/entities/playerModel.json @@ -1,7 +1,7 @@ { "type": "Object", "name": "Player: Model", - "ignore": true, + "ignore": false, "import": "/model.json", "assets": [ "/player/bear.glb" diff --git a/bin/data/scenes/scene.json b/bin/data/scenes/scene.json index 708fc6af..5a3c92cd 100644 --- a/bin/data/scenes/scene.json +++ b/bin/data/scenes/scene.json @@ -16,7 +16,7 @@ [ 0, 0, 0, 0 ] ], "shader": { - "mode": 1, + "mode": 0, "scalar": 16, "parameters": [ 0, 0, 0, "time" ] } diff --git a/bin/data/scenes/sourceengine/base_sourceengine.json b/bin/data/scenes/sourceengine/base_sourceengine.json index c1f787d5..e6a70f91 100644 --- a/bin/data/scenes/sourceengine/base_sourceengine.json +++ b/bin/data/scenes/sourceengine/base_sourceengine.json @@ -3,7 +3,7 @@ "metadata": { "graph": { // "renderer": { "separate": true }, - "baking": { "enabled": false }, + "baking": { "enabled": true }, "tags": { // exact matches "worldspawn": { @@ -19,6 +19,7 @@ }, "info_player_spawn": { "action": "attach", "filename": "./player.json", "transform": { "orientation": [ 0, 1, 0, 0 ] } }, "light_environment": { "transform": { "orientation": [0,0,0,1] }, "light": { + "color": [0.1, 0.1, 0.1], "power": 100000, "global": true, "bias": { diff --git a/bin/data/scenes/sourceengine/mds_mcdonalds.json b/bin/data/scenes/sourceengine/mds_mcdonalds.json index 844787ad..525f3a4d 100644 --- a/bin/data/scenes/sourceengine/mds_mcdonalds.json +++ b/bin/data/scenes/sourceengine/mds_mcdonalds.json @@ -2,8 +2,8 @@ "import": "./base_sourceengine.json", "assets": [ // { "filename": "./models/mds_mcdonalds.glb" } - { "filename": "./models/mds_mcdonalds/graph.json" } - // { "filename": "/burger.json", "delay": 1 } + { "filename": "./models/mds_mcdonalds/graph.json" }, + { "filename": "/burger.json", "delay": 1 } ], "metadata": { "graph": { diff --git a/bin/data/scenes/sourceengine/scene.json b/bin/data/scenes/sourceengine/scene.json index 45d67ac3..7acd2711 100644 --- a/bin/data/scenes/sourceengine/scene.json +++ b/bin/data/scenes/sourceengine/scene.json @@ -2,16 +2,16 @@ "import": "/scene.json", "assets": [ "./sourceengine.json" - // "./loading.json" + // { "filename": "./loading.json", "delay": 0.5 } ], "metadata": { "light": { - "ambient": [ 0, 0, 0 ], + // "ambient": [ 0, 0, 0 ], // "ambient": [ 0.05, 0.05, 0.05 ], // "ambient": [ 0.15, 0.15, 0.15 ], // "ambient": [ 0.5, 0.5, 0.5 ], // "ambient": [ 0.8, 0.8, 0.8 ], - // "ambient": [ 0.1, 0.1, 0.2 ], + "ambient": [ 0.1, 0.1, 0.2 ], "exposure": 0.125, "gamma": 2.2, // 2.2, diff --git a/bin/data/scenes/ss2/medsci.json b/bin/data/scenes/ss2/medsci.json index 4b9a5e9f..6c038f5f 100644 --- a/bin/data/scenes/ss2/medsci.json +++ b/bin/data/scenes/ss2/medsci.json @@ -8,10 +8,10 @@ // { "filename": "./models/tiny_msci/graph.json" } // { "filename": "./models/micro_sci.glb" } - { "filename": "./models/micro_sci/graph.json" } + // { "filename": "./models/micro_sci/graph.json" } // { "filename": "./models/msci.glb" } - // { "filename": "./models/msci/graph.json" } + { "filename": "./models/msci/graph.json" } // { "filename": "./models/medsci.glb" } // { "filename": "./models/medsci/graph.json" } diff --git a/bin/data/shaders - 1.1/base/line/frag.glsl b/bin/data/shaders - 1.1/base/line/frag.glsl new file mode 100644 index 00000000..935d731a --- /dev/null +++ b/bin/data/shaders - 1.1/base/line/frag.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(fragment) + +layout (location = 0) in vec3 inPosition; +layout (location = 1) in vec3 inColor; + +layout (location = 0) out uvec2 outId; +layout (location = 1) out vec2 outNormals; +layout (location = 2) out vec4 outAlbedo; + +void main() { + outAlbedo = vec4(inColor, 1); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/base/line/vert.glsl b/bin/data/shaders - 1.1/base/line/vert.glsl new file mode 100644 index 00000000..32b9484c --- /dev/null +++ b/bin/data/shaders - 1.1/base/line/vert.glsl @@ -0,0 +1,29 @@ +#version 450 +#pragma shader_stage(vertex) + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (constant_id = 0) const uint PASSES = 6; + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inColor; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; + +layout (location = 0) out vec3 outPosition; +layout (location = 1) out vec3 outColor; + +void main() { + outPosition = vec3(camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0)); + outColor = inColor; + + gl_Position = camera.viewport[PushConstant.pass].projection * camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/common/fog.h b/bin/data/shaders - 1.1/common/fog.h new file mode 100644 index 00000000..7c62eff2 --- /dev/null +++ b/bin/data/shaders - 1.1/common/fog.h @@ -0,0 +1,56 @@ +// Perlin Fog +void fog( in Ray ray, inout vec3 i, float scale ) { + if ( ubo.settings.fog.stepScale <= 0 || ubo.settings.fog.range.x == 0 || ubo.settings.fog.range.y == 0 ) return; +#if FOG_RAY_MARCH + const float range = ubo.settings.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.settings.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 = 0; // 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.settings.fog.densityScale * 0.001 + ubo.settings.fog.offset * 0.01; + density = max(0, textureLod(samplerNoise, uvw, level).r - ubo.settings.fog.densityThreshold) * ubo.settings.fog.densityMultiplier; + if ( density > 0 ) { + density = exp(-density * stepSize * ubo.settings.fog.absorbtion); + transmittance *= density; + lightFactor *= density; + if ( transmittance < 0.1 ) break; + } + } + i.rgb = mix(ubo.settings.fog.color.rgb, i.rgb, transmittance ); + } +#endif +#if FOG_BASIC + const vec3 color = ubo.settings.fog.color.rgb; + const float inner = ubo.settings.fog.range.x; + const float outer = ubo.settings.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 - 1.1/common/functions.h b/bin/data/shaders - 1.1/common/functions.h new file mode 100644 index 00000000..45b85f9f --- /dev/null +++ b/bin/data/shaders - 1.1/common/functions.h @@ -0,0 +1,419 @@ +// 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 mipLevel( in vec2 dx_vtc, in vec2 dy_vtc ) { + const float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)); + return 0.5 * log2(delta_max_sqr); +// return max(0.0, 0.5 * log2(delta_max_sqr) - 1.0); + +// return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); +} +float mipLevels( vec2 size ) { + return floor(log2(max(size.x, size.y))); +} +float mipLevels( ivec2 size ) { + return floor(log2(max(size.x, size.y))); +} +// +void toneMap( inout vec3 color, float exposure ) { + color.rgb = vec3(1.0) - exp(-color.rgb * exposure); +} +void gammaCorrect( inout vec3 color, float gamma ) { + color.rgb = pow(color.rgb, vec3(1.0 / gamma)); +} +void toneMap( inout vec4 color, float exposure ) { toneMap(color.rgb, exposure); } +void gammaCorrect( inout vec4 color, float gamma ) { gammaCorrect(color.rgb, gamma); } +// +uint tea(uint val0, uint val1) { + uint v0 = val0; + uint v1 = val1; + uint s0 = 0; + + #pragma unroll 16 + for(uint n = 0; n < 16; n++) { + s0 += 0x9e3779b9; + v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); + v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); + } + return v0; +} +uint lcg(inout uint prev) { + uint LCG_A = 1664525u; + uint LCG_C = 1013904223u; + prev = (LCG_A * prev + LCG_C); + return prev & 0x00FFFFFF; +} +float rnd(inout uint prev) { return (float(lcg(prev)) / float(0x01000000)); } + +uint prngSeed; +float rnd() { return rnd(prngSeed); } +// +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 tangentBitangent(in vec3 N, out vec3 Nt, out vec3 Nb) { + if(abs(N.x) > abs(N.y)) Nt = vec3(N.z, 0, -N.x) / sqrt(N.x * N.x + N.z * N.z); + else Nt = vec3(0, -N.z, N.y) / sqrt(N.y * N.y + N.z * N.z); + Nb = cross(N, Nt); +} +vec3 samplingHemisphere(inout uint seed, in vec3 x, in vec3 y, in vec3 z) { + float r1 = rnd(seed); + float r2 = rnd(seed); + float sq = sqrt(1.0 - r2); + vec3 direction = vec3(cos(2 * PI * r1) * sq, sin(2 * PI * r1) * sq, sqrt(r2)); + direction = direction.x * x + direction.y * y + direction.z * z; + return direction; +} +vec3 samplingHemisphere(inout uint seed, in vec3 z) { + vec3 x; + vec3 y; + tangentBitangent( z, x, y ); + + float r1 = rnd(seed); + float r2 = rnd(seed); + float sq = sqrt(1.0 - r2); + vec3 direction = vec3(cos(2 * PI * r1) * sq, sin(2 * PI * r1) * sq, sqrt(r2)); + direction = direction.x * x + direction.y * y + direction.z * z; + return direction; +} +// +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); +} +vec4 blend( vec4 source, vec4 dest, float a ) { + return source * a + dest * (1.0 - a); +} +float gauss( float x, float sigma ) { + return (1.0 / (2.0 * 3.14157 * sigma) * exp(-(x*x) / (2.0 * sigma))); +} +bool enabled( uint flag, uint bit ) { + return (flag & (1 << bit)) != 0; +} +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; +} +vec3 encodeSrgb(vec3 rgb) { + const vec3 a = 12.92 * rgb; + const vec3 b = 1.055 * pow(rgb, vec3(1.0 / 2.4)) - 0.055; + const vec3 c = step(vec3(0.0031308), rgb); + return mix(a, b, c); +} + +vec3 decodeSrgb(vec3 rgb) { + const vec3 a = rgb / 12.92; + const vec3 b = pow((rgb + 0.055) / 1.055, vec3(2.4)); + const vec3 c = step(vec3(0.04045), rgb); + return mix(a, b, c); +} +bool validTextureIndex( int textureIndex ) { + return 0 <= textureIndex && textureIndex < MAX_TEXTURES; +} +#if MAX_CUBEMAPS +bool validCubemapIndex( int textureIndex ) { + return 0 <= textureIndex && textureIndex < MAX_CUBEMAPS; +} +#endif +#if !BLOOM && (DEFERRED || FRAGMENT || COMPUTE || RT) +bool validTextureIndex( uint id ) { + return 0 <= id && id < MAX_TEXTURES; +} +bool validTextureIndex( uint start, int offset ) { + return 0 <= offset && start + offset < MAX_TEXTURES; +} +uint textureIndex( uint start, int offset ) { + return start + offset; +} +vec4 sampleTexture( uint id, vec2 uv ) { + const Texture t = textures[id]; + return texture( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ) ); +} +vec4 sampleTexture( uint id, vec2 uv, float mip ) { +#if QUERY_MIPMAP + return sampleTexture( id, uv ); +#else + const Texture t = textures[id]; + return textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip ); +#endif +} +vec4 sampleTexture( uint id, vec3 uvm ) { return sampleTexture( id, uvm.xy, uvm.z ); } +vec4 sampleTexture( uint id ) { return sampleTexture( id, surface.uv.xy, surface.uv.z ); } +vec4 sampleTexture( uint id, float mip ) { return sampleTexture( id, surface.uv.xy, mip ); } +#endif +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); +} +#if VXGI +float cascadePower( uint x ) { + return pow(1 + x, ubo.settings.vxgi.cascadePower); +// return max( 1, x * ubo.settings.vxgi.cascadePower ); +} +#endif +#if FRAGMENT +void whitenoise(inout vec3 color, const vec4 parameters) { + const float flicker = parameters.x; + 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 ); +} +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; +} +#endif +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; +} +// + +vec2 encodeBarycentrics( vec3 barycentric ) { + return barycentric.yz; +} +vec3 decodeBarycentrics( vec2 attributes ) { + return vec3( + 1.0 - attributes.x - attributes.y, + attributes.x, + attributes.y + ); +} +#if DEFERRED_SAMPLING +void populateSurfaceMaterial() { + const Material material = materials[surface.instance.materialID]; + surface.material.albedo = material.colorBase; + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; + surface.light = material.colorEmissive; + + if ( validTextureIndex( material.indexAlbedo ) ) { + surface.material.albedo *= sampleTexture( material.indexAlbedo ); + } + // OPAQUE + if ( material.modeAlpha == 0 ) { + surface.material.albedo.a = 1; + // BLEND + } else if ( material.modeAlpha == 1 ) { + + // MASK + } else if ( material.modeAlpha == 2 ) { + + } + // Lightmap + if ( (/*surface.subID++ > 0 ||*/ bool(ubo.settings.lighting.useLightmaps)) && validTextureIndex( surface.instance.lightmapID ) ) { + vec4 light = sampleTexture( surface.instance.lightmapID, surface.st ); + /*surface.material.lightmapped = light.a > 0.000000001; + if ( surface.material.lightmapped )*/ surface.light += surface.material.albedo * light; + } else { + surface.material.lightmapped = false; + } + // Emissive textures + if ( validTextureIndex( material.indexEmissive ) ) { + surface.light += sampleTexture( material.indexEmissive ); + } + // Occlusion map + if ( validTextureIndex( material.indexOcclusion ) ) { + surface.material.occlusion = sampleTexture( material.indexOcclusion ).r; + } + // Metallic/Roughness map + if ( validTextureIndex( material.indexMetallicRoughness ) ) { + vec4 samp = sampleTexture( material.indexMetallicRoughness ); + surface.material.metallic = samp.r; + surface.material.roughness = samp.g; + } + // Normals + if ( validTextureIndex( material.indexNormal ) && surface.tangent.world != vec3(0) ) { + surface.normal.world = surface.tbn * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - vec3(1.0)); + } + { + surface.normal.eye = normalize(vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) )); + } + + surface.light *= surface.material.albedo; +} + +bool isValidAddress( uint64_t address ) { +#if UINT64_ENABLED + return bool(address); +#else + return bool(address.x) && bool(address.y); +#endif +} + +#if BUFFER_REFERENCE +void populateSurface( InstanceAddresses instanceAddresses, uvec3 indices ) { + Triangle triangle; + Vertex points[3]; + + if ( isValidAddress(instanceAddresses.vertex) ) { + Vertices vertices = Vertices(nonuniformEXT(instanceAddresses.vertex)); + + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_] = vertices.v[/*triangle.*/indices[_]]; + } else { + if ( isValidAddress(instanceAddresses.position) ) { + VPos buf = VPos(nonuniformEXT(instanceAddresses.position)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].position = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.uv) ) { + VUv buf = VUv(nonuniformEXT(instanceAddresses.uv)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].uv = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.st) ) { + VSt buf = VSt(nonuniformEXT(instanceAddresses.st)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].st = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.normal) ) { + VNormal buf = VNormal(nonuniformEXT(instanceAddresses.normal)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].normal = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.tangent) ) { + VTangent buf = VTangent(nonuniformEXT(instanceAddresses.tangent)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].tangent = buf.v[/*triangle.*/indices[_]]; + } + } + +#if BARYCENTRIC_CALCULATE + { + const vec3 p = vec3(inverse( surface.instance.model ) * vec4(surface.position.world, 1)); + + const vec3 a = points[0].position; + const vec3 b = points[1].position; + const vec3 c = points[2].position; + + const vec3 v0 = b - a; + const vec3 v1 = c - a; + const vec3 v2 = p - a; + const float d00 = dot(v0, v0); + const float d01 = dot(v0, v1); + const float d11 = dot(v1, v1); + const float d20 = dot(v2, v0); + const float d21 = dot(v2, v1); + const float denom = d00 * d11 - d01 * d01; + + const float v = (d11 * d20 - d01 * d21) / denom; + const float w = (d00 * d21 - d01 * d20) / denom; + const float u = 1.0f - v - w; + + surface.barycentric = vec3( u, v, w ); + } +#endif + + triangle.geomNormal = normalize(cross(points[1].position - points[0].position, points[2].position - points[0].position)); + triangle.point.normal = /*triangle.*/points[0].normal * surface.barycentric[0] + /*triangle.*/points[1].normal * surface.barycentric[1] + /*triangle.*/points[2].normal * surface.barycentric[2]; + + triangle.point.position = /*triangle.*/points[0].position * surface.barycentric[0] + /*triangle.*/points[1].position * surface.barycentric[1] + /*triangle.*/points[2].position * surface.barycentric[2]; + triangle.point.uv = /*triangle.*/points[0].uv * surface.barycentric[0] + /*triangle.*/points[1].uv * surface.barycentric[1] + /*triangle.*/points[2].uv * surface.barycentric[2]; + triangle.point.st = /*triangle.*/points[0].st * surface.barycentric[0] + /*triangle.*/points[1].st * surface.barycentric[1] + /*triangle.*/points[2].st * surface.barycentric[2]; + triangle.point.tangent = /*triangle.*/points[0].tangent * surface.barycentric[0] + /*triangle.*/points[1].tangent * surface.barycentric[1] + /*triangle.*/points[2].tangent * surface.barycentric[2]; + + + if ( triangle.point.tangent != vec3(0) ) { + surface.tangent.world = normalize(vec3( surface.instance.model * vec4(triangle.point.tangent, 0.0) )); + vec3 bitangent = normalize(vec3( surface.instance.model * vec4(cross( triangle.point.normal, triangle.point.tangent ), 0.0) )); + surface.tbn = mat3(surface.tangent.world, bitangent, triangle.point.normal); + } + + // bind position +#if 1 || BARYCENTRIC_CALCULATE + { + surface.position.world = vec3( surface.instance.model * vec4(triangle.point.position, 1.0 ) ); + surface.position.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.position.world, 1.0) ); + } +#endif + // bind normals + { + surface.normal.world = normalize(vec3( surface.instance.model * vec4(triangle.point.normal, 0.0 ) )); + // surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) ); + } + // bind UVs + { + surface.uv.xy = triangle.point.uv; + surface.uv.z = 0; + surface.st.xy = triangle.point.st; + surface.st.z = 0; + } + + populateSurfaceMaterial(); +} +void populateSurface( uint instanceID, uint primitiveID ) { + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.instance = instances[instanceID]; + + const InstanceAddresses instanceAddresses = instanceAddresses[instanceID]; + if ( !isValidAddress(instanceAddresses.index) ) return; + const DrawCommand drawCommand = Indirects(nonuniformEXT(instanceAddresses.indirect)).dc[instanceAddresses.drawID]; + const uint triangleID = primitiveID + (drawCommand.indexID / 3); + uvec3 indices = Indices(nonuniformEXT(instanceAddresses.index)).i[triangleID]; + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/indices[_] += drawCommand.vertexID; + + populateSurface( instanceAddresses, indices ); +} +void populateSurface( RayTracePayload payload ) { + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.instance = instances[payload.instanceID]; + + if ( !payload.hit ) return; + surface.barycentric = decodeBarycentrics(payload.attributes); + populateSurface( payload.instanceID, payload.primitiveID ); +} +#endif +#endif \ No newline at end of file diff --git a/bin/data/shaders - 1.1/common/lambert.h b/bin/data/shaders - 1.1/common/lambert.h new file mode 100644 index 00000000..eed6391e --- /dev/null +++ b/bin/data/shaders - 1.1/common/lambert.h @@ -0,0 +1,66 @@ +float shadowFactor( const Light light, float def ); +void lambert() { + // outcoming light from surface to eye + const vec3 Lo = normalize( -surface.position.eye ); + // angle of outcoming light + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); + + for ( uint i = 0, shadows = 0; i < MAX_LIGHTS; ++i ) { + #if BAKING + // skip if surface is a dynamic light, we aren't baking dynamic lights + if ( lights[i].type < 0 ) continue; + #else + // skip if surface is already baked, and this isn't a dynamic light + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + #endif + if ( lights[i].power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + + vec3 Li = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + // magnitude of incoming light vector (for inverse-square attenuation) + const float Lmagnitude = dot(Li, Li); + // distance incoming light travels (reuse from above) + const float Ldistance = sqrt(Lmagnitude); + // "free" normalization, since we need to compute the above values anyways + Li = Li / Ldistance; + // attenuation factor + // const float Lattenuation = 1.0 / (1 + (PI * Lmagnitude)); + const float Lattenuation = 1.0 / (1 + Lmagnitude); + // skip if attenuation factor is too low + // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; + // ray cast if our surface is occluded from the light + const float Lshadow = 1; // ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // skip if our shadow factor is too low + if ( Lshadow <= LIGHT_POWER_CUTOFF ) continue; + // light radiance + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // skip if our radiance is too low + // if ( Lr <= LIGHT_POWER_CUTOFF ) continue; + // halfway vector + const vec3 Lh = normalize(Li + Lo); + // angle of incoming light + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + // angle of halfway light vector + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); +/* + const vec3 Liu = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + const vec3 Li = normalize(Liu); + // const float Lattenuation = 1.0 / (PI * pow(length(Liu), 2.0)); + // const float Lattenuation = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + const float Lattenuation = 1.0 / (1 + pow(length(Liu), 2.0)); + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + if ( lights[i].power * Lattenuation * Lshadow <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // const vec3 Lh = normalize(Li + Lo); + // const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); +*/ + + const vec3 diffuse = surface.material.albedo.rgb; + const vec3 specular = vec3(0); + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += lights[i].power * Lattenuation * Lshadow; + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/common/light.h b/bin/data/shaders - 1.1/common/light.h new file mode 100644 index 00000000..0dbfe75c --- /dev/null +++ b/bin/data/shaders - 1.1/common/light.h @@ -0,0 +1,11 @@ +float shadowFactor( const Light light, float def ); + +#if PBR + #include "../common/pbr.h" +#endif +#if LAMBERT + #include "../common/lambert.h" +#endif +#if PHONG + #include "../common/phong.h" +#endif \ No newline at end of file diff --git a/bin/data/shaders - 1.1/common/macros.h b/bin/data/shaders - 1.1/common/macros.h new file mode 100644 index 00000000..909ca56b --- /dev/null +++ b/bin/data/shaders - 1.1/common/macros.h @@ -0,0 +1,102 @@ +#ifndef NO_NONUNIFORM_EXT + #define NO_NONUNIFORM_EXT 0 + // enable if shaderNonUniform is not supported + // Nvidia hardware does not require nonuniformEXT, but AMD does +#endif + +// implicit variables +#ifndef MULTISAMPLING + #define MULTISAMPLING 1 +#endif +#ifndef MAX_MSAA_SAMPLES + #define MAX_MSAA_SAMPLES 16 +#endif +#ifndef MAX_TEXTURES + #define MAX_TEXTURES TEXTURES +#endif +#ifndef MAX_LIGHTS + #define MAX_LIGHTS ubo.settings.lengths.lights +#endif +#ifndef MAX_SHADOWS + #define MAX_SHADOWS ubo.settings.lighting.maxShadows +#endif +#ifndef VIEW_MATRIX + #define VIEW_MATRIX ubo.eyes[surface.pass].view +#endif + +// implicit shader settings +#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 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 PHONG + #define PHONG 0 +#endif +#ifndef LAMBERT + #define LAMBERT 0 +#endif +#ifndef PBR + #define PBR 1 +#endif +*/ + +#if NO_NONUNIFORM_EXT + #define nonuniformEXT(X) X +#else + #extension GL_EXT_nonuniform_qualifier : enable +#endif + +#if !UINT64_ENABLED + #define uint64_t uvec2 +#endif + +// easy and accessible in one place +#ifndef BARYCENTRIC + #define BARYCENTRIC 0 +#endif +#if BARYCENTRIC + #ifndef BARYCENTRIC_CALCULATE + #define BARYCENTRIC_CALCULATE 0 + #endif +#endif + +#if BUFFER_REFERENCE + #extension GL_EXT_scalar_block_layout : enable + #extension GL_EXT_buffer_reference : enable + #extension GL_EXT_buffer_reference2 : enable + #if UINT64_ENABLED + #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable + #else + #extension GL_EXT_buffer_reference_uvec2 : enable + #endif +#endif + +const float PI = 3.14159265359; +const float EPSILON = 0.00001; +const float SQRT2 = 1.41421356237; + +const float LIGHT_POWER_CUTOFF = 0.0005; +const float LIGHTMAP_GAMMA = 1.0; \ No newline at end of file diff --git a/bin/data/shaders - 1.1/common/pbr.h b/bin/data/shaders - 1.1/common/pbr.h new file mode 100644 index 00000000..a9896c54 --- /dev/null +++ b/bin/data/shaders - 1.1/common/pbr.h @@ -0,0 +1,121 @@ +// PBR +void pbr() { + // per-surface, not per-light, compute once + + // Freslen reflectance for a dieletric + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + // outcoming light from surface to eye + const vec3 Lo = normalize( -surface.position.eye ); + // angle of outcoming light + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); + + const float Rs = 4.0; + + for ( uint i = 0, shadows = 0; i < MAX_LIGHTS; ++i ) { + #if BAKING + // skip if surface is a dynamic light, we aren't baking dynamic lights + if ( lights[i].type < 0 ) continue; + #else + // skip if surface is already baked, and this isn't a dynamic light + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + #endif + /* + // skip if light power is too low + if ( lights[i].power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + + const vec3 Liu = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + const vec3 Li = normalize(Liu); + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // const float Lattenuation = 1.0 / (PI * pow(length(Liu), 2.0)); + // const float Lattenuation = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + const float Lattenuation = 1.0 / (1 + pow(length(Liu), 2.0)); + if ( lights[i].power * Lattenuation * Lshadow <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); + */ + // incoming light to surface (non-const to normalize it later) + // vec3 Li = lights[i].position - surface.position.world; + vec3 Li = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + // magnitude of incoming light vector (for inverse-square attenuation) + const float Lmagnitude = dot(Li, Li); + // distance incoming light travels (reuse from above) + const float Ldistance = sqrt(Lmagnitude); + // "free" normalization, since we need to compute the above values anyways + Li = Li / Ldistance; + // attenuation factor + // const float Lattenuation = 1.0 / (1 + (PI * Lmagnitude)); + const float Lattenuation = 1.0 / (1 + Lmagnitude); + // skip if attenuation factor is too low + // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; + // ray cast if our surface is occluded from the light + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // skip if our shadow factor is too low + if ( Lshadow <= LIGHT_POWER_CUTOFF ) continue; + // light radiance + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // skip if our radiance is too low + // if ( Lr <= LIGHT_POWER_CUTOFF ) continue; + // halfway vector + const vec3 Lh = normalize(Li + Lo); + // angle of incoming light + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + // angle of halfway light vector + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); + + // Fresnel term for direct lighting + const vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, Lo))); + // Distribution for specular lighting + const float D = ndfGGX( cosLh, surface.material.roughness * Rs); + // Geometric attenuation for specular lighting + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness * Rs); + + // final lighting + const vec3 diffuse = mix(vec3(1.0) - F, vec3(0), surface.material.metallic) * surface.material.albedo.rgb; + const vec3 specular = ( shadows < MAX_SHADOWS ) ? ((F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo)) : vec3(0); + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += lights[i].power * Lattenuation * Lshadow; + } +#if 0 + const float Rs = 4.0; // specular lighting looks gross without this + uint shadows = 0; + for ( uint i = 0; i < ubo.settings.lengths.lights; ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && light.type >= 0 ) continue; + + const vec3 Liu = vec3(ubo.eyes[surface.pass].view * vec4(light.position, 1)) - surface.position.eye; + const float Ld = length(Liu); + const float La = 1.0 / (1 + (PI * pow(Ld, 2.0))); + if ( La <= LIGHT_POWER_CUTOFF ) continue; + + const vec3 Li = normalize(Liu); + const float Ls = ( shadows++ < ubo.settings.lighting.maxShadows ) ? shadowFactor( light, 0.0 ) : 1; + 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; + 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); + /* + // lightmapped, compute only specular + if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.light.rgb += (specular) * Lr * cosLi; + // point light, compute only diffuse + // else if ( abs(light.type) == 1 ) surface.light.rgb += (diffuse) * Lr * cosLi; + else surface.light.rgb += (diffuse + specular) * Lr * cosLi; + */ + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } +#endif +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/common/shadows.h b/bin/data/shaders - 1.1/common/shadows.h new file mode 100644 index 00000000..20100334 --- /dev/null +++ b/bin/data/shaders - 1.1/common/shadows.h @@ -0,0 +1,171 @@ +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.settings.lighting.shadowSamples +#endif +#if VXGI + float voxelShadowFactor( const Light, float def ); +#endif + +#if CUBEMAPS +float omniShadowMap( const Light light, float def ) { + return 1.0; +} +#else +float omniShadowMap( const Light light, float def ) { + float factor = 1.0; + + const mat4 views[6] = { + mat4( 0, 0, 1, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 1 ), + mat4( 0, 0,-1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ), + mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 1 ), + }; + + const vec3 D = normalize(surface.position.world - light.position); + const vec3 N = abs(D); + uint A = N.y > N.x ? 1 : 0; + A = N.z > N[A] ? 2 : A; + uint index = A * 2; + if ( D[A] < 0.0 ) ++index; + + vec4 positionClip = light.projection * views[index] * vec4(surface.position.world - light.position, 1.0); + positionClip.xy /= 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 < -1 || positionClip.z >= 1 ) return 0.0; + + const float eyeDepthScale = 1.0; + const float sampledDepthScale = light.view[1][1]; // light view matricies will incorporate scaling factors for some retarded reason, so we need to rescale it by grabbing from here, hopefully it remains coherent between all light matrices to ever exist in engine + + const float bias = light.depthBias; + const float eyeDepth = abs(positionClip.z / positionClip.w) * eyeDepthScale; + + const vec3 sampleOffsetDirections[20] = { + vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), + vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), + vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), + vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), + vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) + }; + + float sampled = 0; + const int samples = int(SHADOW_SAMPLES); + // cubemap point light + if ( light.typeMap == 1 ) { + if ( samples < 1 ) { + sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D).r * sampledDepthScale; + } else { + for ( int i = 0; i < samples; ++i ) { + const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; + vec2 poisson = poissonDisk[idx] / 700.0; + vec3 P = vec3( poisson.xy, (poisson.x + poisson.y) * 0.5 ); + sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D + P ).r * sampledDepthScale; + if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples; + } + return factor; + } + // separated point lights + } else if ( light.typeMap == 2 ) { + const vec2 uv = positionClip.xy * 0.5 + 0.5; + if ( samples < 1 ) { + sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv).r * sampledDepthScale; + } else { + for ( int i = 0; i < samples; ++i ) { + const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; + sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv + poissonDisk[idx] / 700.0 ).r * sampledDepthScale; + if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples; + } + return factor; + } + } + return eyeDepth < sampled - bias ? 0.0 : factor; +} +#endif +#if RT +float shadowFactorRT( const Light light, float def ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = light.position - ray.origin; + + float tMin = ubo.settings.rt.defaultRayBounds.x; + float tMax = length(ray.direction) - ubo.settings.rt.defaultRayBounds.x; + + ray.direction = normalize(ray.direction); + + uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT; + uint cullMask = 0xFF; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, tlas, rayFlags, cullMask, ray.origin, tMin, ray.direction, tMax); + + while(rayQueryProceedEXT(rayQuery)); + + return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT ? 1.0 : 0.0; +} +#endif +float shadowFactor( const Light light, float def ) { +#if RT + return shadowFactorRT( light, def ); +#endif + if ( light.typeMap != 0 ) return omniShadowMap( light, def ); + + if ( !validTextureIndex(light.indexMap) ) + #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.indexMap)], 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.indexMap)], 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 - 1.1/common/structs.h b/bin/data/shaders - 1.1/common/structs.h new file mode 100644 index 00000000..c8e35fb5 --- /dev/null +++ b/bin/data/shaders - 1.1/common/structs.h @@ -0,0 +1,308 @@ +struct EyeMatrices { + mat4 view; + mat4 projection; + + mat4 model; + mat4 previous; + + mat4 iView; + mat4 iProjection; + + vec4 eyePos; +}; + +struct Viewport { + mat4 view; + mat4 projection; +}; + +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 Light { + mat4 view; + mat4 projection; + + vec3 position; + float radius; + + vec3 color; + float power; + + int type; + int typeMap; + int indexMap; + float depthBias; +}; + +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 padding1; + int padding2; + int modeAlpha; +}; + +struct Texture { + int index; + int samp; + int remap; + float blend; + + vec4 lerp; +}; + +struct DrawCommand { + uint indices; // triangle count + uint instances; // instance count + uint indexID; // starting triangle position + int vertexID; // starting vertex position + + uint instanceID; // starting instance position + float padding1; // + float padding2; // material to use for this draw call + uint vertices; // number of vertices used +}; + +struct Bounds { + vec3 min; + float padding1; + vec3 max; + float padding2; +}; + +struct Instance { + mat4 model; + mat4 previous; + + vec4 color; + + uint materialID; + uint primitiveID; + uint meshID; + uint objectID; + + int jointID; + int lightmapID; + uint imageID; + uint auxID; + + Bounds bounds; +// InstanceAddresses addresses; +}; + +struct InstanceAddresses { + uint64_t vertex; + uint64_t index; + + uint64_t indirect; + uint drawID; + uint padding0; + + uint64_t position; + uint64_t uv; + + uint64_t color; + uint64_t st; + + uint64_t normal; + uint64_t tangent; + + uint64_t joints; + uint64_t weights; + + uint64_t id; + uint64_t padding1; +}; + +struct SurfaceMaterial { + vec4 albedo; + vec4 indirect; + + float metallic; + float roughness; + float occlusion; + bool lightmapped; +}; + +struct Surface { + uint pass; + uint subID; + + vec3 uv; + vec3 st; + Space position; + Space normal; + Space tangent; + mat3 tbn; + vec3 barycentric; + vec2 motion; + + Ray ray; + + SurfaceMaterial material; + Instance instance; + + vec4 light; + vec4 fragment; +} surface; + +// MSAA info +#if MULTISAMPLING +struct MSAA { + int currentID; + uvec2 IDs[MAX_MSAA_SAMPLES]; + vec4 fragment; + vec4 fragments[MAX_MSAA_SAMPLES]; +} msaa; +#endif +// UBO settings +struct SettingsLengths { + uint lights; + uint materials; + uint textures; + uint drawCommands; +}; +struct SettingsMode { + vec4 parameters; + uint type; + uint scalar; + uint msaa; + uint frameNumber; +}; +struct SettingsLighting { + vec3 ambient; + uint indexSkybox; + + uint maxShadows; + uint shadowSamples; + uint useLightmaps; +}; +struct SettingsFog { + vec3 color; + float stepScale; + + vec3 offset; + float densityScale; + + vec2 range; + float densityThreshold; + float densityMultiplier; + + float absorbtion; + float padding1; + float padding2; + float padding3; +}; +struct SettingsBloom { + float exposure; + float gamma; + float threshold; + uint padding; +}; +struct SettingsVxgi { + mat4 matrix; + + float cascadePower; + float granularity; + float voxelizeScale; + float occlusionFalloff; + + float traceStartOffsetFactor; + uint shadows; + uint padding2; + uint padding3; +}; +struct SettingsRayTrace { + vec2 defaultRayBounds; + float alphaTestOffset; + float padding1; + + uint samples; + uint paths; + uint frameAccumulationMinimum; + uint padding2; +}; + +struct Settings { + SettingsLengths lengths; + SettingsMode mode; + SettingsLighting lighting; + SettingsFog fog; + SettingsBloom bloom; + SettingsVxgi vxgi; + SettingsRayTrace rt; +}; +struct Voxel { + uvec2 id; + vec3 position; + vec3 normal; + vec2 uv; + vec4 color; +}; +struct VoxelInfo { + vec3 min; + vec3 max; + + float mipmapLevels; + float radianceSize; + float radianceSizeRecip; +} voxelInfo; + +// Raytrace stuff + +struct Vertex { + vec3 position; + vec2 uv; + uint color; + vec2 st; + vec3 normal; + vec3 tangent; + uvec2 joints; + vec4 weights; + uint id; +}; + +struct Triangle { + Vertex point; + + vec3 geomNormal; + + uint instanceID; +}; + +struct RayTracePayload { + bool hit; + uint instanceID; + uint primitiveID; + vec2 attributes; +// Triangle triangle; +}; \ No newline at end of file diff --git a/bin/data/shaders - 1.1/common/vxgi.h b/bin/data/shaders - 1.1/common/vxgi.h new file mode 100644 index 00000000..83621d1b --- /dev/null +++ b/bin/data/shaders - 1.1/common/vxgi.h @@ -0,0 +1,189 @@ +// GI +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.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) ); + ray.direction = vec3( ubo.settings.vxgi.matrix * vec4( ray.direction, 0.0 ) ); + uint cascade = cascadeIndex(ray.origin); +#else + uint cascade = cascadeIndex( vec3( ubo.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) ) ); +#endif + const float granularityRecip = ubo.settings.vxgi.granularity; //2.0; // 0.25f * (CASCADES - cascade); + const float granularity = 1.0f / granularityRecip; + const float occlusionFalloff = ubo.settings.vxgi.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 + tDelta * ubo.settings.vxgi.traceStartOffsetFactor; + 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.settings.vxgi.matrix * 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 ( ubo.settings.vxgi.shadows < ++voxelShadowsCount ) 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.settings.vxgi.matrix ); + 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 = 0; // 1.0f / float(CONES_COUNT) * 0.125f; + + 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.25; // 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; + } + // indirectDiffuse.rgb *= surface.material.albedo.rgb; + 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 ); + // indirectSpecular.rgb *= surface.material.albedo.rgb; + // outFragColor.rgb = indirectSpecular.rgb; return; + } + +/* + if ( true ) { + gammaCorrect(indirectDiffuse.rgb, 1.0 / ubo.settings.bloom.gamma); + } +*/ + indirectDiffuse *= DIFFUSE_INDIRECT_FACTOR; + indirectSpecular *= SPECULAR_INDIRECT_FACTOR; + + + surface.material.indirect = indirectDiffuse + indirectSpecular; +// outFragColor.rgb = surface.material.indirect.rgb; return; + + // 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 * 0.5 ); + surface.fragment.rgb += (1.0 - surface.material.albedo.a) * radiance.rgb; + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/bloom/comp.glsl b/bin/data/shaders - 1.1/display/bloom/comp.glsl new file mode 100644 index 00000000..639cc811 --- /dev/null +++ b/bin/data/shaders - 1.1/display/bloom/comp.glsl @@ -0,0 +1,67 @@ +#version 450 +#pragma shader_stage(compute) + +#define COMPUTE 1 +#define TEXTURES 0 +#define CUBEMAPS 0 +#define BLOOM 1 + +layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; + +layout( push_constant ) uniform PushBlock { + uint eye; + uint mode; +} PushConstant; + +layout (binding = 0) uniform UBO { + float scale; + float strength; + float threshold; + float sigma; + + float gamma; + float exposure; + uint samples; + uint padding; +} ubo; + +layout (binding = 1, rgba16f) uniform volatile coherent image2D imageColor; +layout (binding = 2, rgba16f) uniform volatile coherent image2D imageBloom; +layout (binding = 3, rgba16f) uniform volatile coherent image2D imagePingPong; + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" + +void main() { + const uint mode = PushConstant.mode; + const ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + const ivec2 size = imageSize( imageColor ); + if ( texel.x >= size.x || texel.y >= size.y ) return; + + if ( mode == 0 ) { // fill bloom + vec3 result = imageLoad( imageColor, texel ).rgb; + float brightness = dot(result, vec3(0.2126, 0.7152, 0.0722)); + if ( brightness < ubo.threshold ) result = vec3(0, 0, 0); + imageStore( imageBloom, texel, vec4( result, 1.0 ) ); + } else if ( mode == 1 ) { // bloom horizontal + vec3 result = imageLoad( imageBloom, texel ).rgb * gauss( 0, ubo.sigma ) * ubo.strength; + for( int i = 1; i < ubo.samples; ++i ) { + result += imageLoad( imageBloom, texel + ivec2(i * ubo.scale, 0.0)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + result += imageLoad( imageBloom, texel - ivec2(i * ubo.scale, 0.0)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + } + // write to PingPong + imageStore( imagePingPong, texel, vec4( result, 1.0 ) ); + } else if ( mode == 2 ) { // bloom vertical + vec3 result = imageLoad( imagePingPong, texel ).rgb * gauss( 0, ubo.sigma ) * ubo.strength; + for( int i = 1; i < ubo.samples; ++i ) { + result += imageLoad( imagePingPong, texel + ivec2(0.0, i * ubo.scale)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + result += imageLoad( imagePingPong, texel - ivec2(0.0, i * ubo.scale)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + } + // write to Bloom + imageStore( imageBloom, texel, vec4( result, 1.0 ) ); + } else if ( mode == 3 ) { // combine + vec3 result = imageLoad( imageColor, texel ).rgb + imageLoad( imageBloom, texel ).rgb; + imageStore( imageColor, texel, vec4( result, 1.0 ) ); + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/deferred/comp/comp.glsl b/bin/data/shaders - 1.1/display/deferred/comp/comp.glsl new file mode 100644 index 00000000..cb7c6384 --- /dev/null +++ b/bin/data/shaders - 1.1/display/deferred/comp/comp.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 0 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/deferred/comp/comp.h b/bin/data/shaders - 1.1/display/deferred/comp/comp.h new file mode 100644 index 00000000..d791fa1e --- /dev/null +++ b/bin/data/shaders - 1.1/display/deferred/comp/comp.h @@ -0,0 +1,278 @@ +#extension GL_EXT_samplerless_texture_functions : require +#extension GL_EXT_nonuniform_qualifier : enable + +#if RT + #extension GL_EXT_ray_tracing : enable + #extension GL_EXT_ray_query : enable +#endif + +layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#define COMPUTE 1 +#define DEFERRED 1 +#define DEFERRED_SAMPLING 1 + +#define PBR 1 +#define LAMBERT 0 +#if RT || BARYCENTRIC + #define BUFFER_REFERENCE 0 + #define UINT64_ENABLED 0 +#endif +#define FOG 1 +#define FOG_RAY_MARCH 1 + +#include "../../../common/macros.h" + +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +#if VXGI + layout (constant_id = 2) const uint CASCADES = 16; +#endif + +#if !MULTISAMPLING + layout(binding = 0) uniform utexture2D samplerId; + #if BARYCENTRIC + #if !BARYCENTRIC_CALCULATE + layout(binding = 1) uniform texture2D samplerBary; + #endif + #else + layout(binding = 1) uniform texture2D samplerUv; + layout(binding = 2) uniform texture2D samplerNormal; + #endif + layout(binding = 3) uniform texture2D samplerDepth; +#else + layout(binding = 0) uniform utexture2DMS samplerId; + #if BARYCENTRIC + #if !BARYCENTRIC_CALCULATE + layout(binding = 1) uniform texture2DMS samplerBary; + #endif + #else + layout(binding = 1) uniform texture2DMS samplerUv; + layout(binding = 2) uniform texture2DMS samplerNormal; + #endif + layout(binding = 3) uniform texture2DMS samplerDepth; +#endif + + +layout(binding = 7, rgba16f) uniform volatile coherent image2D imageColor; +layout(binding = 8, rgba16f) uniform volatile coherent image2D imageBright; +layout(binding = 9, rg16f) uniform volatile coherent image2D imageMotion; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +#include "../../../common/structs.h" + +layout (binding = 10) uniform UBO { + EyeMatrices eyes[2]; + + Settings settings; +} ubo; +/* +*/ +layout (std140, binding = 11) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 12) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 13) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 14) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 15) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 16) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 17) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 18) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 19) uniform sampler3D samplerNoise; +#if VXGI + layout (binding = 20) uniform usampler3D voxelId[CASCADES]; + layout (binding = 21) uniform sampler3D voxelNormal[CASCADES]; + layout (binding = 22) uniform sampler3D voxelRadiance[CASCADES]; +#endif +#if RT + layout (binding = 23) uniform accelerationStructureEXT tlas; +#endif + +#if BUFFER_REFERENCE + layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; + layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; + layout(buffer_reference, scalar) buffer Indirects { DrawCommand dc[]; }; + + layout(buffer_reference, scalar) buffer VPos { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VUv { vec2 v[]; }; + layout(buffer_reference, scalar) buffer VColor { uint v[]; }; + layout(buffer_reference, scalar) buffer VSt { vec2 v[]; }; + layout(buffer_reference, scalar) buffer VNormal { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VTangent { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VID { uint v[]; }; +#endif + +#include "../../../common/functions.h" +#include "../../../common/fog.h" +#include "../../../common/light.h" +#include "../../../common/shadows.h" +#if VXGI + #include "../../../common/vxgi.h" +#endif + +#if MULTISAMPLING + #define IMAGE_LOAD(X) texelFetch( X, ivec2(gl_GlobalInvocationID.xy), msaa.currentID ) +#else + #define IMAGE_LOAD(X) texelFetch( X, ivec2(gl_GlobalInvocationID.xy), 0 ) +#endif + +#define IMAGE_STORE(X, Y) imageStore( X, ivec2(gl_GlobalInvocationID.xy), Y ) + +void postProcess() { +#if FOG + fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); +#endif + float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); + bool bloom = brightness > ubo.settings.bloom.threshold; +//if ( bloom ) toneMap( surface.fragment.rgb, brightness ); + vec4 outFragColor = vec4(surface.fragment.rgb, 1.0); + vec4 outFragBright = bloom ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); + vec2 outFragMotion = surface.motion; + + IMAGE_STORE( imageColor, outFragColor ); + IMAGE_STORE( imageBright, outFragBright ); + IMAGE_STORE( imageMotion, vec4(outFragMotion, 0, 0) ); +} + +void populateSurface() { + uvec2 renderSize = imageSize(imageColor); + if ( gl_GlobalInvocationID.x >= renderSize.x || gl_GlobalInvocationID.y >= renderSize.y || gl_GlobalInvocationID.z > PushConstant.pass ) return; + + surface.fragment = vec4(0); + surface.pass = PushConstant.pass; + + { + vec2 inUv = (vec2(gl_GlobalInvocationID.xy) / vec2(renderSize)) * 2.0f - 1.0f; + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + const vec4 near4 = iProjectionView * (vec4(inUv, -1.0, 1.0)); + const vec4 far4 = iProjectionView * (vec4(inUv, 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 = /*near3.xyz;*/ ubo.eyes[surface.pass].eyePos.xyz; + + const float depth = IMAGE_LOAD(samplerDepth).r; + + vec4 eye = ubo.eyes[surface.pass].iProjection * vec4(inUv, depth, 1.0); + eye /= eye.w; + + surface.position.eye = eye.xyz; + surface.position.world = vec3( ubo.eyes[surface.pass].iView * eye ); + } + +#if !MULTISAMPLING + const uvec2 ID = uvec2(IMAGE_LOAD(samplerId).xy); +#else + const uvec2 ID = msaa.IDs[msaa.currentID]; +#endif + surface.motion = vec2(0); + + if ( ID.x == 0 || ID.y == 0 ) { + if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment.rgb = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], surface.ray.direction ).rgb; + } + surface.fragment.a = 0.0; + return; + } + { + const uint triangleID = ID.x - 1; + const uint instanceID = ID.y - 1; + surface.subID = 1; + + #if BARYCENTRIC + #if !BARYCENTRIC_CALCULATE + surface.barycentric = decodeBarycentrics(IMAGE_LOAD(samplerBary).xy).xyz; + #endif + populateSurface( instanceID, triangleID ); + #else + vec4 uvst = IMAGE_LOAD(samplerUv); + vec4 normaltangent = IMAGE_LOAD(samplerNormal); + + surface.uv.xy = uvst.xy; + surface.uv.z = 0; + surface.st.xy = uvst.zw; + surface.st.z = 0; + + surface.normal.world = decodeNormals(normaltangent.xy); + // surface.tangent.world = decodeNormals(normaltangent.zw); + + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.instance = instances[instanceID]; + + populateSurfaceMaterial(); + #endif + } + + { + vec4 pNDC = ubo.eyes[surface.pass].previous * surface.instance.previous * vec4(surface.position.world, 1); + vec4 cNDC = ubo.eyes[surface.pass].model * surface.instance.model * vec4(surface.position.world, 1); + pNDC /= pNDC.w; + cNDC /= cNDC.w; + + surface.motion = cNDC.xy - pNDC.xy; + } +} + +void directLighting() { + surface.light.rgb += surface.material.albedo.rgb * ubo.settings.lighting.ambient.rgb * surface.material.occlusion; // add ambient lighting + surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting +#if PBR + pbr(); +#elif LAMBERT + lambert(); +#elif PHONG + phong(); +#endif + + surface.fragment.rgb += surface.light.rgb; + +} + +#if MULTISAMPLING +void resolveSurfaceFragment() { + for ( int i = 0; i < ubo.settings.mode.msaa; ++i ) { + msaa.currentID = i; + msaa.IDs[i] = uvec3(IMAGE_LOAD(samplerId)).xy; + + // check if ID is already used + bool unique = true; + for ( int j = msaa.currentID - 1; j >= 0; --j ) { + if ( msaa.IDs[j] == msaa.IDs[i] ) { + surface.fragment = msaa.fragments[j]; + unique = false; + break; + } + } + + if ( unique ) { + populateSurface(); + #if VXGI + indirectLighting(); + #endif + directLighting(); + } + + msaa.fragment += surface.fragment; + msaa.fragments[msaa.currentID] = surface.fragment; + } + + surface.fragment = msaa.fragment / ubo.settings.mode.msaa; +} +#endif \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/deferred/comp/msaa.comp.glsl b/bin/data/shaders - 1.1/display/deferred/comp/msaa.comp.glsl new file mode 100644 index 00000000..00628645 --- /dev/null +++ b/bin/data/shaders - 1.1/display/deferred/comp/msaa.comp.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 0 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + resolveSurfaceFragment(); + + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/deferred/comp/rt.comp.glsl b/bin/data/shaders - 1.1/display/deferred/comp/rt.comp.glsl new file mode 100644 index 00000000..bdc07694 --- /dev/null +++ b/bin/data/shaders - 1.1/display/deferred/comp/rt.comp.glsl @@ -0,0 +1,13 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 0 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/deferred/comp/rt.msaa.comp.glsl b/bin/data/shaders - 1.1/display/deferred/comp/rt.msaa.comp.glsl new file mode 100644 index 00000000..1388e20b --- /dev/null +++ b/bin/data/shaders - 1.1/display/deferred/comp/rt.msaa.comp.glsl @@ -0,0 +1,13 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 0 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/deferred/comp/rt.vxgi.comp.glsl b/bin/data/shaders - 1.1/display/deferred/comp/rt.vxgi.comp.glsl new file mode 100644 index 00000000..18e067a1 --- /dev/null +++ b/bin/data/shaders - 1.1/display/deferred/comp/rt.vxgi.comp.glsl @@ -0,0 +1,14 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 1 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + indirectLighting(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/deferred/comp/rt.vxgi.msaa.comp.glsl b/bin/data/shaders - 1.1/display/deferred/comp/rt.vxgi.msaa.comp.glsl new file mode 100644 index 00000000..87394afc --- /dev/null +++ b/bin/data/shaders - 1.1/display/deferred/comp/rt.vxgi.msaa.comp.glsl @@ -0,0 +1,13 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 1 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/deferred/comp/vxgi.comp.glsl b/bin/data/shaders - 1.1/display/deferred/comp/vxgi.comp.glsl new file mode 100644 index 00000000..f29ee254 --- /dev/null +++ b/bin/data/shaders - 1.1/display/deferred/comp/vxgi.comp.glsl @@ -0,0 +1,14 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 1 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + indirectLighting(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/deferred/comp/vxgi.msaa.comp.glsl b/bin/data/shaders - 1.1/display/deferred/comp/vxgi.msaa.comp.glsl new file mode 100644 index 00000000..6829be37 --- /dev/null +++ b/bin/data/shaders - 1.1/display/deferred/comp/vxgi.msaa.comp.glsl @@ -0,0 +1,12 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 1 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + resolveSurfaceFragment(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/depth-pyramid/comp.glsl b/bin/data/shaders - 1.1/display/depth-pyramid/comp.glsl new file mode 100644 index 00000000..d58feb89 --- /dev/null +++ b/bin/data/shaders - 1.1/display/depth-pyramid/comp.glsl @@ -0,0 +1,30 @@ +#version 450 +#pragma shader_stage(compute) + +//#extension GL_EXT_nonuniform_qualifier : enable + +layout (constant_id = 0) const uint MIPS = 6; +layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#define COMPUTE 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout( push_constant ) uniform PushBlock { + uint _; + uint pass; +} PushConstant; + +layout (binding = 3) uniform sampler2D inImage[MIPS]; +layout (binding = 4, r32f) uniform volatile coherent image2D outImage[MIPS]; + +void main() { + vec2 imageSize = imageSize(outImage[PushConstant.pass]); + uvec2 pos = gl_GlobalInvocationID.xy; + if ( pos.x >= imageSize.x || pos.y >= imageSize.y ) return; + + float depth = texture(inImage[PushConstant.pass], (vec2(pos) + vec2(0.5)) / imageSize).x; + + imageStore(outImage[PushConstant.pass], ivec2(pos), vec4(depth)); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/renderTarget/frag.glsl b/bin/data/shaders - 1.1/display/renderTarget/frag.glsl new file mode 100644 index 00000000..8758b85d --- /dev/null +++ b/bin/data/shaders - 1.1/display/renderTarget/frag.glsl @@ -0,0 +1,35 @@ +#version 450 +#pragma shader_stage(fragment) +#extension GL_EXT_samplerless_texture_functions : require + +layout (location = 0) in vec2 inUv; +layout (location = 1) flat in uint inPass; + +layout (location = 0) out vec4 outColor; + +layout (binding = 0) uniform sampler2D samplerColor; + +layout (binding = 1) uniform UBO { + float curTime; + float gamma; + float exposure; + uint padding; +} ubo; + +#define TONE_MAP 1 +#define GAMMA_CORRECT 1 +#define TEXTURES 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" + +void main() { + outColor = texture( samplerColor, inUv ); +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/renderTarget/postProcess.frag.glsl b/bin/data/shaders - 1.1/display/renderTarget/postProcess.frag.glsl new file mode 100644 index 00000000..5e1ae123 --- /dev/null +++ b/bin/data/shaders - 1.1/display/renderTarget/postProcess.frag.glsl @@ -0,0 +1,392 @@ +#version 450 +#pragma shader_stage(fragment) +#extension GL_EXT_samplerless_texture_functions : require + +layout (location = 0) in vec2 inUv; +layout (location = 1) flat in uint inPass; + +layout (location = 0) out vec4 outColor; + +layout (binding = 0) uniform sampler2D samplerColor; + +layout (binding = 1) uniform UBO { + float curTime; + float gamma; + float exposure; + uint padding; +} ubo; + +#define TONE_MAP 1 +#define GAMMA_CORRECT 1 +#define TEXTURES 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" + +#define M_PI 3.1415926535897932384626433832795 + +const float u_imgx = 0; +const float u_imgy = 0; +const float u_imgw = 1; +const float u_imgh = 1; +const float u_img_gain = 2; +const float u_img_bias = 0; +const float u_beam_bias = 0.185; +const float u_beam_gain = 0.25; +const float u_corner = 0.05; +const float u_zoom = 1.0; +const float u_shape = 2; +const float u_round = -0.02; +const float u_grain = 0.4; +const float u_vpitch = 936.1; +const float u_hpitch = 1024.6; +const float u_top = 1; +const float u_bot = 1; + +void main() { + const vec2 screenResolution = textureSize( samplerColor, 0 ); + const float u_lines = screenResolution.y * 0.75; + + vec2 uv_orig = (inUv.xy * 2.0 - 1.0); + vec2 uv_mod = uv_orig * pow(1.0-abs(uv_orig),vec2(u_round)) * (u_zoom + u_corner * pow( abs(uv_orig.yx), vec2(u_shape)) ); + vec2 uv = uv_mod / 2.0 + 0.5; + + if ( abs(uv_mod).x > 1.0 || abs(uv_mod.y) > 1.0 ) { + outColor = vec4(0.0, 0.0, 0.0, 1.0); + return; + } + + float spacing = 1.0/u_lines; + uv+=spacing*0.5; + + float line_top = ( ceil(uv.y*u_lines)) / u_lines; + float line_bot = line_top - spacing; + + vec2 scale = vec2(u_imgw, u_imgh); + vec2 offset = vec2(u_imgx, u_imgy); + + vec2 uv_top = (vec2(uv.x, line_top)+offset) * scale - (scale-1.0)*0.5 ; + vec2 uv_bot = (vec2(uv.x, line_bot)+offset) * scale - (scale-1.0)*0.5 ; + + uv_top -= spacing * 0.5; + uv_bot -= spacing * 0.5; + + vec4 sampled_top = texture(samplerColor, uv_top); + vec4 sampled_bot = texture(samplerColor, uv_bot); + + vec3 color_top = sampled_top.xyz * u_img_gain + u_img_bias; + vec3 color_bot = sampled_bot.xyz * u_img_gain + u_img_bias; + + float dist_top = pow(abs(uv.y - line_top), 1.0); + float dist_bot = pow(abs(uv.y - line_bot), 1.0); + + vec3 beam_top = 1.0 - (dist_top / (spacing * (color_top * u_beam_gain + u_beam_bias))); + vec3 beam_bot = 1.0 - (dist_bot / (spacing * (color_bot * u_beam_gain + u_beam_bias))); + + beam_top = clamp(beam_top, 0.0, 1.0) ; + beam_bot = clamp(beam_bot, 0.0, 1.0) ; + + vec3 color = (color_top*beam_top)*u_top + (color_bot*beam_bot)*u_bot; + + vec2 dot; + dot.y = floor(uv.y * u_vpitch) ; + dot.x = uv.x; + + if (mod(dot.y, 2.0) > 0.5) + dot.x += (4.5/3.0) / u_hpitch; + + dot.x = (floor(dot.x*u_hpitch)) ; + + int fil = int(mod(dot.x, 3.0)); + + vec3 out_color = color * (1.0-u_grain); + + vec3 passthru = vec3( + float(fil == 0), + float(fil == 1), + float(fil == 2) + ) * (u_grain); + + out_color += color * passthru; + + outColor = vec4(out_color, (sampled_top.a + sampled_bot.a) * 0.5 ); + +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} + +#if 0 +float iTime = 0; +float noise(vec2 p) { + float s = (fract(sin(dot(p * sin( iTime * 0.5 ), vec2(12.9898,78.233)*2.0)) * 43758.5453)); // texture(iChannel1,vec2(1.,2.*cos(iTime))*iTime*8. + p*1.).x; + s *= s; + return s; +} + +float onOff(float a, float b, float c) { + return step(c, sin(iTime + a*cos(iTime*b))); +} + +float ramp(float y, float start, float end) { + float inside = step(start,y) - step(end,y); + float fact = (y-start)/(end-start)*inside; + return (1.-fact) * inside; + +} + +float stripes(vec2 uv) { + float noi = noise(uv*vec2(0.5,1.) + vec2(1.,3.)); + return ramp(mod(uv.y*4. + iTime/2.+sin(iTime + sin(iTime*0.63)),1.),0.5,0.6)*noi; +} + +vec4 getVideo(vec2 uv) { + vec2 look = uv; + float window = 1./(1.+20.*(look.y-mod(iTime/4.,1.))*(look.y-mod(iTime/4.,1.))); + look.x = look.x + sin(look.y*10. + iTime)/50.*onOff(4.,4.,.3)*(1.+cos(iTime*80.))*window; + float vShift = 0.4*onOff(2.,3.,.9)*(sin(iTime)*sin(iTime*20.) + + (0.5 + 0.1*sin(iTime*200.)*cos(iTime))); + look.y = mod(look.y + vShift, 1.); + return texture(samplerColor,look); +} + +vec2 screenDistort(vec2 uv) { + uv -= vec2(.5,.5); + uv = uv*1.2*(1./1.2+2.*uv.x*uv.x*uv.y*uv.y); + uv += vec2(.5,.5); + return uv; +} + +void main() { + vec2 uv = inUv.xy; // fragCoord.xy / iResolution.xy; + iTime = ubo.curTime; + + uv = screenDistort(uv); + vec4 video = getVideo(uv); + float vigAmt = 3.+.3*sin(iTime + 5.*cos(iTime*5.)); + float vignette = (1.-vigAmt*(uv.y-.5)*(uv.y-.5))*(1.-vigAmt*(uv.x-.5)*(uv.x-.5)); + + video.rgb += stripes(uv); + video.rgb += noise(uv*2.)/4.; + video.rgb *= vignette; + video.rgb *= (12.+mod(uv.y*30.+iTime,1.))/13.; + + outColor = video; +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} +#endif +#if 0 +vec2 curveRemapUV(vec2 uv, vec2 curvature) { + uv = uv * 2.0 - 1.0; + vec2 offset = abs(uv.yx) / vec2(curvature.x, curvature.y); + uv = uv + uv * offset * offset; + uv = uv * 0.5 + 0.5; + return uv; +} + +vec4 scanLineIntensity(float uv, float resolution, float opacity) { + float intensity = sin(uv * resolution * PI * 2.0); + intensity = ((0.5 * intensity) + 0.5) * 0.9 + 0.1; + return vec4(vec3(pow(intensity, opacity)), 1.0); +} + +vec4 vignetteIntensity(vec2 uv, vec2 resolution, float opacity, float roundness) { + float intensity = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y); + return vec4(vec3(clamp(pow((resolution.x / roundness) * intensity, opacity), 0.0, 1.0)), 1.0); +} + +void main(void) { + const vec2 screenResolution = textureSize( samplerColor, 0 ); + const vec2 scanLineOpacity = vec2(0.5); + const float brightness = 2; + const float vignetteOpacity = 0.5; + const float vignetteRoundness = 0.5; + const vec2 curvature = vec2(8); + + const vec2 remappedUV = curveRemapUV(vec2(inUv.x, inUv.y), curvature); + vec4 baseColor = texture(samplerColor, remappedUV); + + baseColor *= vignetteIntensity(remappedUV, screenResolution, vignetteOpacity, vignetteRoundness); + + baseColor *= scanLineIntensity(remappedUV.x, screenResolution.y, scanLineOpacity.x); + baseColor *= scanLineIntensity(remappedUV.y, screenResolution.x, scanLineOpacity.y); + + baseColor *= vec4(vec3(brightness), 1.0); + + if (remappedUV.x < 0.0 || remappedUV.y < 0.0 || remappedUV.x > 1.0 || remappedUV.y > 1.0){ + outColor = vec4(0.0, 0.0, 0.0, 1.0); + } else { + outColor = baseColor; + } + +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} +#endif +#if 0 +vec2 fragCoord = vec2(0,0); +vec2 iResolution = vec2(640,480); + +// Emulated input resolution. +#if 0 + // Fix resolution to set amount. + #define res (vec2(320.0/1.0,160.0/1.0)) +#else + // Optimize for resize. + #define res (iResolution.xy/6.0) +#endif + +// Hardness of scanline. +// -8.0 = soft +// -16.0 = medium +float hardScan=-8.0; + +// Hardness of pixels in scanline. +// -2.0 = soft +// -4.0 = hard +float hardPix=-3.0; + +// Display warp. +// 0.0 = none +// 1.0/8.0 = extreme +vec2 warp=vec2(1.0/32.0,1.0/24.0); + +// Amount of shadow mask. +float maskDark=0.5; +float maskLight=1.5; + +//------------------------------------------------------------------------ + +// sRGB to Linear. +// Assuing using sRGB typed textures this should not be needed. +float ToLinear1(float c){return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4);} +vec3 ToLinear(vec3 c){return vec3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b));} + +// Linear to sRGB. +// Assuing using sRGB typed textures this should not be needed. +float ToSrgb1(float c){return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055);} +vec3 ToSrgb(vec3 c){return vec3(ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b));} + +// Nearest emulated sample given floating point position and texel offset. +// Also zero's off screen. +vec3 Fetch(vec2 pos,vec2 off){ + pos=floor(pos*res+off)/res; + if(max(abs(pos.x-0.5),abs(pos.y-0.5))>0.5)return vec3(0.0,0.0,0.0); + return ToLinear(texture(samplerColor,pos.xy,-16.0).rgb);} + +// Distance in emulated pixels to nearest texel. +vec2 Dist(vec2 pos){pos=pos*res;return -((pos-floor(pos))-vec2(0.5));} + +// 1D Gaussian. +float Gaus(float pos,float scale){return exp2(scale*pos*pos);} + +// 3-tap Gaussian filter along horz line. +vec3 Horz3(vec2 pos,float off){ + vec3 b=Fetch(pos,vec2(-1.0,off)); + vec3 c=Fetch(pos,vec2( 0.0,off)); + vec3 d=Fetch(pos,vec2( 1.0,off)); + float dst=Dist(pos).x; + // Convert distance to weight. + float scale=hardPix; + float wb=Gaus(dst-1.0,scale); + float wc=Gaus(dst+0.0,scale); + float wd=Gaus(dst+1.0,scale); + // Return filtered sample. + return (b*wb+c*wc+d*wd)/(wb+wc+wd);} + +// 5-tap Gaussian filter along horz line. +vec3 Horz5(vec2 pos,float off){ + vec3 a=Fetch(pos,vec2(-2.0,off)); + vec3 b=Fetch(pos,vec2(-1.0,off)); + vec3 c=Fetch(pos,vec2( 0.0,off)); + vec3 d=Fetch(pos,vec2( 1.0,off)); + vec3 e=Fetch(pos,vec2( 2.0,off)); + float dst=Dist(pos).x; + // Convert distance to weight. + float scale=hardPix; + float wa=Gaus(dst-2.0,scale); + float wb=Gaus(dst-1.0,scale); + float wc=Gaus(dst+0.0,scale); + float wd=Gaus(dst+1.0,scale); + float we=Gaus(dst+2.0,scale); + // Return filtered sample. + return (a*wa+b*wb+c*wc+d*wd+e*we)/(wa+wb+wc+wd+we);} + +// Return scanline weight. +float Scan(vec2 pos,float off){ + float dst=Dist(pos).y; + return Gaus(dst+off,hardScan);} + +// Allow nearest three lines to effect pixel. +vec3 Tri(vec2 pos){ + vec3 a=Horz3(pos,-1.0); + vec3 b=Horz5(pos, 0.0); + vec3 c=Horz3(pos, 1.0); + float wa=Scan(pos,-1.0); + float wb=Scan(pos, 0.0); + float wc=Scan(pos, 1.0); + return a*wa+b*wb+c*wc;} + +// Distortion of scanlines, and end of screen alpha. +vec2 Warp(vec2 pos){ + pos=pos*2.0-1.0; + pos*=vec2(1.0+(pos.y*pos.y)*warp.x,1.0+(pos.x*pos.x)*warp.y); + return pos*0.5+0.5;} + +// Shadow mask. +vec3 Mask(vec2 pos){ + pos.x+=pos.y*3.0; + vec3 mask=vec3(maskDark,maskDark,maskDark); + pos.x=fract(pos.x/6.0); + if(pos.x<0.333)mask.r=maskLight; + else if(pos.x<0.666)mask.g=maskLight; + else mask.b=maskLight; + return mask;} + +void main() { + iResolution = textureSize( samplerColor, 0 ); + fragCoord = inUv * iResolution; + + vec2 pos = Warp(fragCoord.xy / iResolution.xy); + + hardScan = -12.0; + maskDark = maskLight = 1.0; + + outColor.rgb = Tri(pos) * Mask(fragCoord.xy); + outColor.rgb = ToSrgb(outColor.rgb); + outColor.a = 1.0; + +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} +#endif +#if 0 +void main() { + const vec2 uv = 0.025 * sin( ubo.curTime ) * inUv.xy; + const float mdf = 0.5; + const float noise = (fract(sin(dot(uv, vec2(12.9898,78.233)*2.0)) * 43758.5453)); + const vec4 sampled = texture( samplerColor, inUv ); + + outColor = sampled - noise * mdf; + + toneMap(outColor, ubo.exposure); + gammaCorrect(outColor, ubo.gamma); +} +#endif \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/renderTarget/vert.glsl b/bin/data/shaders - 1.1/display/renderTarget/vert.glsl new file mode 100644 index 00000000..95fd44b3 --- /dev/null +++ b/bin/data/shaders - 1.1/display/renderTarget/vert.glsl @@ -0,0 +1,16 @@ +#version 450 +#pragma shader_stage(vertex) + +layout (location = 0) out vec2 outUv; +layout (location = 1) out flat uint outPass; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +void main() { + outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + outPass = PushConstant.pass; + gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/vxgi/comp.glsl b/bin/data/shaders - 1.1/display/vxgi/comp.glsl new file mode 100644 index 00000000..9d44d570 --- /dev/null +++ b/bin/data/shaders - 1.1/display/vxgi/comp.glsl @@ -0,0 +1,148 @@ +#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 COMPUTE 1 + +#define VXGI 1 +#define MAX_CUBEMAPS CUBEMAPS +#define GAMMA_CORRECT 1 +#define PBR 1 + +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +layout (constant_id = 2) const uint CASCADES = 16; + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 0) uniform UBO { + EyeMatrices eyes[2]; + + Settings settings; +} ubo; +layout (std140, binding = 1) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 2) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 3) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 4) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 5) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 6) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 7) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 8) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 9) uniform sampler3D samplerNoise; + +layout (binding = 10, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; +layout (binding = 11, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; +#if VXGI_HDR + layout (binding = 12, rgba32f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#else + layout (binding = 12, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#endif + +#include "../../common/functions.h" +#include "../../common/light.h" +#undef VXGI // +#include "../../common/shadows.h" +void main() { + const vec3 tUvw = gl_GlobalInvocationID.xzy; + for ( uint CASCADE = 0; CASCADE < CASCADES; ++CASCADE ) { + surface.normal.world = decodeNormals( vec2(imageLoad(voxelNormal[CASCADE], ivec3(tUvw) ).xy) ); + surface.normal.eye = vec3( ubo.settings.vxgi.matrix * vec4( surface.normal.world, 0.0f ) ); + + surface.position.eye = (vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelRadiance[CASCADE])) * 2.0f - 1.0f) * cascadePower(CASCADE); + surface.position.world = vec3( inverse(ubo.settings.vxgi.matrix) * vec4( surface.position.eye, 1.0f ) ); + + const uvec2 ID = uvec2(imageLoad(voxelId[CASCADE], ivec3(tUvw) ).xy); + const uint drawID = ID.x - 1; + const uint instanceID = ID.y - 1; + if ( ID.x == 0 || ID.y == 0 ) { + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(0)); + continue; + } + const DrawCommand drawCommand = drawCommands[drawID]; + surface.instance = instances[instanceID]; + const Material material = materials[surface.instance.materialID]; + surface.material.albedo = material.colorBase; + surface.fragment = material.colorEmissive; + + surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) ); + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; + + const vec3 ambient = ubo.settings.lighting.ambient.rgb * surface.material.occlusion; + if ( validTextureIndex( surface.instance.lightmapID ) ) { + surface.fragment.rgb += surface.material.albedo.rgb; + } else { + surface.fragment.rgb += surface.material.albedo.rgb * ambient; + // corrections + surface.position.eye = vec3( ubo.eyes[surface.pass].view * vec4( surface.position.world, 1 ) ); + surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0) ); + pbr(); + /* + surface.material.roughness *= 4.0; + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize( surface.position.world ); + const float cosLo = max(0.0, dot(surface.normal.world, Lo)); + for ( uint i = 0; i < ubo.settings.lengths.lights; ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - surface.position.world; + const vec3 Li = normalize(Liu); + const float Ls = shadowFactor( light, 0.0 ); + const float La = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.world, Li)); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + #if LAMBERT + const vec3 diffuse = surface.material.albedo.rgb; + const vec3 specular = vec3(0); + #elif PBR + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.world, Lh)); + + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, surface.material.roughness ); + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); + const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; + const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + #endif + // lightmapped, compute only specular + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } + */ + } + + surface.fragment.rgb += surface.light.rgb; + + #if TONE_MAP + toneMap(surface.fragment.rgb, ubo.settings.bloom.exposure); + #endif + #if GAMMA_CORRECT + gammaCorrect(surface.fragment.rgb, 1.0 / ubo.settings.bloom.gamma); + #endif + + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, surface.material.albedo.a)); + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/display/vxgi/mip.gaussian.comp.glsl b/bin/data/shaders - 1.1/display/vxgi/mip.gaussian.comp.glsl new file mode 100644 index 00000000..dae6f972 --- /dev/null +++ b/bin/data/shaders - 1.1/display/vxgi/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 - 1.1/graph/baking/frag.glsl b/bin/data/shaders - 1.1/graph/baking/frag.glsl new file mode 100644 index 00000000..076049f2 --- /dev/null +++ b/bin/data/shaders - 1.1/graph/baking/frag.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(fragment) + +#define RT 0 +#include "./frag.h" diff --git a/bin/data/shaders - 1.1/graph/baking/frag.h b/bin/data/shaders - 1.1/graph/baking/frag.h new file mode 100644 index 00000000..0abc2c25 --- /dev/null +++ b/bin/data/shaders - 1.1/graph/baking/frag.h @@ -0,0 +1,204 @@ +//#extension GL_EXT_nonuniform_qualifier : enable +#if RT + #extension GL_EXT_ray_tracing : enable + #extension GL_EXT_ray_query : enable +#endif + +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +layout (constant_id = 2) const uint LAYERS = 32; + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 6) uniform samplerCube samplerCubemaps[CUBEMAPS]; + +#define SHADOW_SAMPLES 16 +#define FRAGMENT 1 +#define BAKING 1 +#define PBR 1 +#define MAX_LIGHTS min(ubo.lights, lights.length()) +#define MAX_SHADOWS MAX_LIGHTS +#define VIEW_MATRIX camera.viewport[0].view + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 7) uniform Camera { + Viewport viewport[6]; +} camera; + +layout (binding = 8) uniform UBO { + uint lights; + uint currentID; + uint padding1; + uint padding2; +} ubo; + +layout (std140, binding = 9) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 10) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 11) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 12) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 13) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 14) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 15, rgba8) uniform volatile coherent image3D outAlbedos; + +#if RT + layout (binding = 16) uniform accelerationStructureEXT tlas; +#endif + +#include "../../common/functions.h" +#if RT +float shadowFactor( const Light light, float def ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = light.position - ray.origin; + + float tMin = 0.001; + float tMax = length(ray.direction) + tMin; + + ray.direction = normalize(ray.direction); + + uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT; + uint cullMask = 0xFF; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, tlas, rayFlags, cullMask, ray.origin, tMin, ray.direction, tMax); + + while(rayQueryProceedEXT(rayQuery)) {} + + return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT ? 1.0 : 0.0; +} +#else + #include "../../common/shadows.h" +#endif + +#include "../../common/light.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +layout (location = 0) out vec4 outAlbedo; + +void main() { + const uint triangleID = uint(inId.x); // gl_PrimitiveID + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + + if ( instanceID != ubo.currentID ) discard; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + surface.position.world = inPosition; + surface.normal.world = inNormal; + + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + const uint mapID = instance.auxID; + + vec4 A = material.colorBase; + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = 1.0f - material.factorOcclusion; + +#if 0 + vec3 N = inNormal; + vec3 T = inTangent; + T = normalize(T - dot(T, N) * N); + vec3 B = cross(T, N); + mat3 TBN = mat3(T, B, N); +// mat3 TBN = mat3(N, B, T); + if ( T != vec3(0) && validTextureIndex( material.indexNormal ) ) { + surface.normal.world = TBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - 1.0 ); + } else { + surface.normal.world = N; + } +#endif + + surface.light = material.colorEmissive; + surface.material.albedo = vec4(1); + { + surface.normal.eye = surface.normal.eye; + surface.position.eye = surface.position.eye; + // pbr(); + + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + for ( uint i = 0; i < min(ubo.lights, lights.length()); ++i ) { + const Light light = lights[i]; + + if ( light.type <= 0 ) continue; + + const mat4 mat = light.view; // inverse(light.view); + const vec3 position = surface.position.world; + // const vec3 position = vec3( mat * vec4(surface.position.world, 1.0) ); + const vec3 normal = surface.normal.world; + // const vec3 normal = vec3( mat * vec4(surface.normal.world, 0.0) ); + + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - surface.position.world; + const float La = 1.0 / (1 + PI * pow(length(Liu), 2.0)); + const float Ls = shadowFactor( light, 0.0 ); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + + const vec3 Lo = normalize( -position ); + const float cosLo = max(0.0, abs(dot(normal, Lo))); + + const vec3 Li = normalize(Liu); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + // const float cosLi = max(0.0, dot(normal, Li)); + const float cosLi = abs(dot(normal, Li)); + #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(normal, Lh)); + const float cosLh = abs(dot(normal, Lh)); + + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = 1; // 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 + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } + } +#define EXPOSURE 0 +#define GAMMA 0 + +// surface.light.rgb = vec3(1.0) - exp(-surface.light.rgb * EXPOSURE); +// surface.light.rgb = pow(surface.light.rgb, vec3(1.0 / GAMMA)); + + outAlbedo = vec4(surface.light.rgb, 1); + + { + const vec2 st = inSt.xy * imageSize(outAlbedos).xy; + const ivec3 uvw = ivec3(int(st.x), int(st.y), int(mapID)); + imageStore(outAlbedos, uvw, vec4(surface.light.rgb, 1) ); + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/graph/baking/rt.frag.glsl b/bin/data/shaders - 1.1/graph/baking/rt.frag.glsl new file mode 100644 index 00000000..a7eca538 --- /dev/null +++ b/bin/data/shaders - 1.1/graph/baking/rt.frag.glsl @@ -0,0 +1,5 @@ +#version 460 +#pragma shader_stage(fragment) + +#define RT 1 +#include "./frag.h" diff --git a/bin/data/shaders - 1.1/graph/baking/vert.glsl b/bin/data/shaders - 1.1/graph/baking/vert.glsl new file mode 100644 index 00000000..1f20a625 --- /dev/null +++ b/bin/data/shaders - 1.1/graph/baking/vert.glsl @@ -0,0 +1,8 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 0 +#define BAKING 1 + +#include "../base/vert.h" diff --git a/bin/data/shaders - 1.1/graph/base/frag.glsl b/bin/data/shaders - 1.1/graph/base/frag.glsl new file mode 100644 index 00000000..22289e3b --- /dev/null +++ b/bin/data/shaders - 1.1/graph/base/frag.glsl @@ -0,0 +1,126 @@ +#version 450 +#pragma shader_stage(fragment) + +//#extension GL_EXT_nonuniform_qualifier : enable + +#define FRAGMENT 1 +#define CAN_DISCARD 1 + +#define MAX_TEXTURES textures.length() + +layout (constant_id = 0) const uint TEXTURES = 1; + + +#include "../../common/macros.h" +#include "../../common/structs.h" + +#if BARYCENTRIC && !BARYCENTRIC_CALCULATE + #define BARYCENTRIC_STABILIZE 1 +// #define BARY_COORD gl_BaryCoordEXT +// #extension GL_EXT_fragment_shader_barycentric : enable + #define BARY_COORD gl_BaryCoordSmoothAMD + #extension GL_AMD_shader_explicit_vertex_parameter : enable +#endif + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 6) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 7) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 8) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 9) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 10) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 11) readonly buffer Lights { + Light lights[]; +}; + +#include "../../common/functions.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +#if BARYCENTRIC_STABILIZE + layout (location = 2) __explicitInterpAMD in vec4 inPOS1; +#else + layout (location = 2) in vec4 inPOS1; +#endif +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +layout (location = 0) out uvec2 outId; +#if BARYCENTRIC + layout (location = 1) out vec2 outBary; +#else + layout (location = 1) out vec4 outUv; + layout (location = 2) out vec4 outNormal; +#endif + +void main() { + const uint triangleID = gl_PrimitiveID; // uint(inId.x); + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + +#if CAN_DISCARD + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + surface.st.xy = wrap(inSt.xy); + surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt)); + + vec4 A = inColor * material.colorBase; + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + // alpha mode OPAQUE + if ( material.modeAlpha == 0 ) { + A.a = 1; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + if ( A.a < 0.0001 ) discard; + +#if !BARYCENTRIC + outUv = vec4(surface.uv, surface.st); + outNormal = vec4( encodeNormals(inNormal), encodeNormals(inTangent) ); +#endif + +#endif + + outId = uvec2(triangleID + 1, instanceID + 1); + +#if BARYCENTRIC && !BARYCENTRIC_CALCULATE + vec3 bary = vec3(gl_BaryCoordSmoothAMD.xy, 1 - gl_BaryCoordSmoothAMD.x - gl_BaryCoordSmoothAMD.y); + bary = bary.yzx; + #if BARYCENTRIC_STABILIZE + vec4 v0 = interpolateAtVertexAMD(inPOS1, 0); + vec4 v1 = interpolateAtVertexAMD(inPOS1, 1); + vec4 v2 = interpolateAtVertexAMD(inPOS1, 2); + if (v0 == inPOS0) outBary = encodeBarycentrics(bary.yzx); + else if (v1 == inPOS0) outBary = encodeBarycentrics(bary.zxy); + else if (v2 == inPOS0) outBary = encodeBarycentrics(bary.xyz); + #else + outBary = encodeBarycentrics(bary.xyz); + #endif +#endif +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/graph/base/instanced.vert.glsl b/bin/data/shaders - 1.1/graph/base/instanced.vert.glsl new file mode 100644 index 00000000..92cae145 --- /dev/null +++ b/bin/data/shaders - 1.1/graph/base/instanced.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 0 +#include "./vert.h" diff --git a/bin/data/shaders - 1.1/graph/base/skinned.instanced.vert.glsl b/bin/data/shaders - 1.1/graph/base/skinned.instanced.vert.glsl new file mode 100644 index 00000000..2bc9b86a --- /dev/null +++ b/bin/data/shaders - 1.1/graph/base/skinned.instanced.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 1 +#include "./vert.h" diff --git a/bin/data/shaders - 1.1/graph/base/skinned.vert.glsl b/bin/data/shaders - 1.1/graph/base/skinned.vert.glsl new file mode 100644 index 00000000..96b6ba5a --- /dev/null +++ b/bin/data/shaders - 1.1/graph/base/skinned.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 0 +#define SKINNED 1 +#include "./vert.h" diff --git a/bin/data/shaders - 1.1/graph/base/vert.glsl b/bin/data/shaders - 1.1/graph/base/vert.glsl new file mode 100644 index 00000000..701eee8d --- /dev/null +++ b/bin/data/shaders - 1.1/graph/base/vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 0 +#define SKINNED 0 +#include "./vert.h" diff --git a/bin/data/shaders - 1.1/graph/base/vert.h b/bin/data/shaders - 1.1/graph/base/vert.h new file mode 100644 index 00000000..5aad74bf --- /dev/null +++ b/bin/data/shaders - 1.1/graph/base/vert.h @@ -0,0 +1,100 @@ +layout (constant_id = 0) const uint PASSES = 6; +#extension GL_ARB_shader_draw_parameters : enable + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec2 inUv; +layout (location = 2) in vec4 inColor; +layout (location = 3) in vec2 inSt; +layout (location = 4) in vec3 inNormal; +layout (location = 5) in vec4 inTangent; +layout (location = 6) in uvec2 inId; +#if SKINNED + layout (location = 7) in uvec4 inJoints; + layout (location = 8) in vec4 inWeights; +#endif + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +#if !BAKING +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; +#endif +layout (std140, binding = 1) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 2) readonly buffer Instances { + Instance instances[]; +}; + +#if SKINNED + layout (std140, binding = 3) readonly buffer Joints { + mat4 joints[]; + }; +#endif + +layout (location = 0) out uvec4 outId; +layout (location = 1) flat out vec4 outPOS0; +layout (location = 2) out vec4 outPOS1; +layout (location = 3) out vec3 outPosition; +layout (location = 4) out vec2 outUv; +layout (location = 5) out vec4 outColor; +layout (location = 6) out vec2 outSt; +layout (location = 7) out vec3 outNormal; +layout (location = 8) out vec3 outTangent; + +vec4 snap(vec4 vertex, vec2 resolution) { + vec4 snappedPos = vertex; + snappedPos.xyz = vertex.xyz / vertex.w; + snappedPos.xy = floor(resolution * snappedPos.xy) / resolution; + snappedPos.xyz *= vertex.w; + return snappedPos; +} + +void main() { + const uint drawID = gl_DrawIDARB; + const uint triangleID = gl_VertexIndex / 3; + const DrawCommand drawCommand = drawCommands[drawID]; + const uint instanceID = drawCommand.instanceID; // gl_InstanceIndex; + const Instance instance = instances[instanceID]; + const uint jointID = instance.jointID; + +#if BAKING + const mat4 view = mat4(1); + const mat4 projection = mat4(1); +#else + const mat4 view = camera.viewport[PushConstant.pass].view; + const mat4 projection = camera.viewport[PushConstant.pass].projection; +#endif +#if SKINNED + const mat4 skinned = joints.length() <= 0 || jointID < 0 ? mat4(1.0) : inWeights.x * joints[jointID + int(inJoints.x)] + inWeights.y * joints[jointID + int(inJoints.y)] + inWeights.z * joints[jointID + int(inJoints.z)] + inWeights.w * joints[jointID + int(inJoints.w)]; +#else + const mat4 skinned = mat4(1.0); +#endif +// const mat4 model = instances.length() <= 0 ? skinned : (instance.model * skinned); + const mat4 model = instance.model * skinned; + + +#if BAKING + gl_Position = vec4(inSt * 2.0 - 1.0, 0.0, 1.0); +#else + gl_Position = projection * view * model * vec4(inPos.xyz, 1.0); +#endif + outPOS0 = gl_Position; + outPOS1 = gl_Position; + + outId = uvec4(triangleID, drawID, instanceID, PushConstant.pass); + + outPosition = vec3(model * vec4(inPos.xyz, 1.0)); + outUv = inUv; + outSt = inSt; + outColor = inColor * instance.color; + outNormal = normalize(vec3(model * vec4(inNormal.xyz, 0.0))); + outTangent = normalize(vec3(view * model * vec4(inTangent.xyz, 0.0))); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/graph/cull/comp.glsl b/bin/data/shaders - 1.1/graph/cull/comp.glsl new file mode 100644 index 00000000..0b174a2b --- /dev/null +++ b/bin/data/shaders - 1.1/graph/cull/comp.glsl @@ -0,0 +1,369 @@ +#version 450 +#pragma shader_stage(compute) + +//#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_EXT_samplerless_texture_functions : enable + +layout (constant_id = 0) const uint PASSES = 6; +layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +#define COMPUTE 1 +#define QUERY_MIPMAPS 1 +#define DEPTH_BIAS 0.00005 + +#include "../../common/macros.h" +#include "../../common/structs.h" + +float mipLevels( vec2 size ) { + return floor(log2(max(size.x, size.y))); +} +float mipLevels( ivec2 size ) { + return floor(log2(max(size.x, size.y))); +} + +vec4 aabbToSphere( Bounds bounds ) { + vec4 sphere; + sphere.xyz = (bounds.max + bounds.min) * 0.5; + sphere.w = length((bounds.max - bounds.min) * 0.5); + return sphere; +} + +// 2D Polyhedral Bounds of a Clipped, Perspective-Projected 3D Sphere. Michael Mara, Morgan McGuire. 2013 +bool projectSphere(vec3 C, float r, float znear, float P00, float P11, out vec4 aabb) +{ + if (C.z < r + znear) + return false; + + vec2 cx = -C.xz; + vec2 vx = vec2(sqrt(dot(cx, cx) - r * r), r); + vec2 minx = mat2(vx.x, vx.y, -vx.y, vx.x) * cx; + vec2 maxx = mat2(vx.x, -vx.y, vx.y, vx.x) * cx; + + vec2 cy = -C.yz; + vec2 vy = vec2(sqrt(dot(cy, cy) - r * r), r); + vec2 miny = mat2(vy.x, vy.y, -vy.y, vy.x) * cy; + vec2 maxy = mat2(vy.x, -vy.y, vy.y, vy.x) * cy; + + aabb = vec4(minx.x / minx.y * P00, miny.x / miny.y * P11, maxx.x / maxx.y * P00, maxy.x / maxy.y * P11); + aabb = aabb.xwzy * vec4(0.5f, -0.5f, 0.5f, -0.5f) + vec4(0.5f); // clip space -> uv space + + return true; +} + +layout( push_constant ) uniform PushBlock { + uint pass; + uint passes; +} PushConstant; + +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; + +layout (std140, binding = 1) buffer DrawCommands { + DrawCommand drawCommands[]; +}; + +layout (std140, binding = 2) buffer Instances { + Instance instances[]; +}; + +layout (binding = 3) uniform sampler2D samplerDepth; + +struct Frustum { + vec4 planes[6]; +}; + +vec4 normalizePlane( vec4 p ) { + return p / length(p.xyz); +} + +bool frustumCull( uint id ) { + if ( PushConstant.passes == 0 ) return true; + + const DrawCommand drawCommand = drawCommands[id]; + const Instance instance = instances[drawCommand.instanceID]; + + bool visible = false; + for ( uint pass = 0; pass < PushConstant.passes; ++pass ) { +#if 0 + vec4 sphere = aabbToSphere( instance.bounds ); + vec3 center = vec3( camera.viewport[pass].view * instance.model * vec4( ) ); +#else + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + #if 1 + vec4 planes[6]; { + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + planes[i*2+j] = normalizePlane( planes[i*2+j] ); + } + } + for ( uint p = 0; p < 6; ++p ) { + float d = max(instance.bounds.min.x * planes[p].x, instance.bounds.max.x * planes[p].x) + + max(instance.bounds.min.y * planes[p].y, instance.bounds.max.y * planes[p].y) + + max(instance.bounds.min.z * planes[p].z, instance.bounds.max.z * planes[p].z); + if ( d > -planes[p].w ) return true; + } + #else + vec4 corners[8] = { + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + }; + vec4 planes[6]; { + #pragma unroll 3 + for (int i = 0; i < 3; ++i) + #pragma unroll 2 + for (int j = 0; j < 2; ++j) { + planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + planes[i*2+j] = normalizePlane( planes[i*2+j] ); + } + } + #pragma unroll 8 + for ( uint p = 0; p < 8; ++p ) corners[p] = mat * corners[p]; + #pragma unroll 6 + for ( uint p = 0; p < 6; ++p ) { + #pragma unroll 8 + for ( uint q = 0; q < 8; ++q ) { + if ( dot( corners[q], planes[p] ) > 0 ) return true; + } + return false; + } + #endif +#endif + } + return visible; +} + +bool occlusionCull( uint id ) { + if ( PushConstant.passes == 0 ) return true; + + const DrawCommand drawCommand = drawCommands[id]; + const Instance instance = instances[drawCommand.instanceID]; + + bool visible = true; + for ( uint pass = 0; pass < PushConstant.passes; ++pass ) { +#if 1 + vec4 aabb; + vec4 sphere = aabbToSphere( instance.bounds ); + vec3 center = (camera.viewport[pass].view * instance.model * vec4(sphere.xyz, 1)).xyz; + float radius = (instance.model * vec4(sphere.w, 0, 0, 0)).x; + // center.y *= -1; + mat4 proj = camera.viewport[pass].projection; + float znear = proj[3][2]; + float P00 = proj[0][0]; + float P11 = proj[1][1]; + if (projectSphere(center, radius, znear, P00, P11, aabb)) { + ivec2 pyramidSize = textureSize( samplerDepth, 0 ); + float mips = mipLevels( pyramidSize ); + + float width = (aabb.z - aabb.x) * pyramidSize.x; + float height = (aabb.w - aabb.y) * pyramidSize.y; + + //find the mipmap level that will match the screen size of the sphere + float level = floor(log2(max(width, height))); + // if ( level == mips ) + --level; + level = clamp( level, 0, mips ); + + //sample the depth pyramid at that specific level + float depth = textureLod(samplerDepth, (aabb.xy + aabb.zw) * 0.5, level).x; + + float depthSphere = znear / (center.z - radius); + + instances[drawCommand.instanceID].bounds.padding1 = depth; + instances[drawCommand.instanceID].bounds.padding2 = proj[3][2]; + + //if the depth of the sphere is in front of the depth pyramid value, then the object is visible + visible = visible && depthSphere >= depth - DEPTH_BIAS; + } + +#else + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + vec3 boundsSize = instance.bounds.max - instance.bounds.min; + vec3 points[8] = { + instance.bounds.min.xyz, + instance.bounds.min.xyz + vec3(boundsSize.x,0,0), + instance.bounds.min.xyz + vec3(0, boundsSize.y,0), + instance.bounds.min.xyz + vec3(0, 0, boundsSize.z), + instance.bounds.min.xyz + vec3(boundsSize.xy,0), + instance.bounds.min.xyz + vec3(0, boundsSize.yz), + instance.bounds.min.xyz + vec3(boundsSize.x, 0, boundsSize.z), + instance.bounds.min.xyz + boundsSize.xyz, + }; + vec2 minXY = vec2(1); + vec2 maxXY = vec2(0); + + float minZ = 1; + float maxZ = 0; + + #pragma unroll 8 + for ( uint i = 0; i < 8; ++i ) { + vec4 clip = mat * vec4( points[i], 1 ); + clip.xyz /= clip.w; + clip.xy = clip.xy * 0.5 + 0.5; + + minXY.x = min(minXY.x, clip.x); + minXY.y = min(minXY.y, clip.y); + + maxXY.x = max(maxXY.x, clip.x); + maxXY.y = max(maxXY.y, clip.y); + + #if INVERSE + clip.z = 1.0 - clip.z; + maxZ = max(maxZ, clip.z); + #else + minZ = min(minZ, clip.z); + #endif + } + + if ( maxXY.x <= 0 || maxXY.y <= 0 ) return false; + if ( minXY.x >= 1 || minXY.y >= 1 ) return false; + + ivec2 depthSize = textureSize( samplerDepth, 0 ); + float mips = mipLevels( depthSize ); + + vec4 uv = vec4(minXY, maxXY); + + ivec2 clipSize = ivec2(maxXY - minXY) * depthSize; + float mip = mipLevels( clipSize ); + mip = clamp( mip, 0, mips ); + if ( mip == 0 ) { + mip = 1; + } else { + float lower = max(mip - 1, 0); + float scale = exp2(-lower); + vec2 a = floor(uv.xy * scale); + vec2 b = ceil(uv.zw * scale); + vec2 dims = b - a; + + // Use the lower level if we only touch <= 2 texels in both dimensions + if (dims.x <= 2 && dims.y <= 2) mip = lower; + } + + float depths[4] = { + textureLod( samplerDepth, uv.xy, mip ).r, + textureLod( samplerDepth, uv.zy, mip ).r, + textureLod( samplerDepth, uv.xw, mip ).r, + textureLod( samplerDepth, uv.zw, mip ).r, + }; + #if INVERSE + float minDepth = 1.0 - min(min(min(depths[0], depths[1]), depths[2]), depths[3]); + #else + float maxDepth = max(max(max(depths[0], depths[1]), depths[2]), depths[3]); + #endif + + instances[drawCommand.instanceID].bounds.padding1 = minZ; + instances[drawCommand.instanceID].bounds.padding2 = maxDepth; + + return minZ <= maxDepth; +#endif + } + return visible; +} + +void main() { + const uint gID = gl_GlobalInvocationID.x; + if ( !(0 <= gID && gID < drawCommands.length()) ) return; + + bool visible = frustumCull( gID ); +// if ( visible ) visible = occlusionCull( gID ); +// bool visible = occlusionCull( gID ); + drawCommands[gID].instances = visible ? 1 : 0; +} + + +/* + Frustum frustum; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + frustum.planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + frustum.planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + frustum.planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + frustum.planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + frustum.planes[i*2+j]*= length(frustum.planes[i*2+j].xyz); + } + for ( uint i = 0; i < 6; ++i ) { + vec4 plane = frustum.planes[i]; + float d = dot(instance.bounds.center, plane.xyz); + float r = dot(instance.bounds.extent, abs(plane.xyz)); + bool inside = d + r > -plane.w; + if ( !inside ) return 0; + } + return true; +*/ +/* + vec4 plane; + vec4 center = vec4( (max + min) * 0.5, 1 ); + vec4 extent = vec4( (max - min) * 0.5, 1 ); + center = mat * center; + extent = mat * extent; + center.xyz /= center.w; + extent.xyz /= extent.w; + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][0]; // left + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][0]; // right + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][1]; // bottom + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][1]; // top + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][2]; // near + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][2]; // far + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + +*/ +/* + for ( uint p = 0; p < 8; ++p ) { + vec4 t = corners[p]; + float w = abs(t.w); + visible = -w <= t.x && t.x <= w && -w <= t.y && t.y <= w && 0 <= t.z && t.z <= w; // && -w <= t.z && t.z <= w; + } +*/ +/* +mat4 convert( mat4 proj ) { + float f = -proj[1][1]; + float raidou = f / proj[0][0]; + float zNear = proj[3][2]; + float zFar = 32; + + float range = zNear - zFar; + + float Sx = f * raidou; + float Sy = f; + float Sz = (-zNear - zFar) / range; + float Pz = 2 * zFar * zNear / range; + + mat4 new = mat4(1.0); + new[0][0] = Sx; + new[1][1] = -Sy; + new[2][2] = Sz; + new[3][2] = Pz; + new[2][3] = 1; + return new; +} +*/ \ No newline at end of file diff --git a/bin/data/shaders - 1.1/graph/depth/frag.glsl b/bin/data/shaders - 1.1/graph/depth/frag.glsl new file mode 100644 index 00000000..79ed3c71 --- /dev/null +++ b/bin/data/shaders - 1.1/graph/depth/frag.glsl @@ -0,0 +1,73 @@ +#version 450 +#pragma shader_stage(fragment) + +#define FRAGMENT 1 +#define MAX_TEXTURES textures.length() + +layout (constant_id = 0) const uint TEXTURES = 1; + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 6) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 7) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 8) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 9) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 10) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 11) readonly buffer Lights { + Light lights[]; +}; + +#include "../../common/functions.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +void main() { + const uint triangleID = uint(inId.x); // gl_PrimitiveID + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + vec4 A = inColor * material.colorBase; + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + // alpha mode OPAQUE + if ( material.modeAlpha == 0 ) { + A.a = 1; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + if ( A.a < 1 ) discard; +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/graph/voxelize/frag.glsl b/bin/data/shaders - 1.1/graph/voxelize/frag.glsl new file mode 100644 index 00000000..3095eaec --- /dev/null +++ b/bin/data/shaders - 1.1/graph/voxelize/frag.glsl @@ -0,0 +1,142 @@ +#version 450 +#pragma shader_stage(fragment) + +// to-do: convert to use functions.h surface population functions + +#define FRAGMENT 1 +#define DEFERRED_SAMPLING 0 +#define CUBEMAPS 1 + +#define BLEND 1 +#define DEPTH_TEST 0 +#define USE_LIGHTMAP 1 +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CASCADES = 16; + +#define MAX_TEXTURES textures.length() +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 6) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 7) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 8) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; + +layout (std140, binding = 9) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 10) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 11) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 12, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; +layout (binding = 13, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; +#if VXGI_HDR + layout (binding = 14, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#else + layout (binding = 14, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#endif +#if DEPTH_TEST + layout (binding = 15, r16f) uniform volatile coherent image3D voxelDepth[CASCADES]; +#endif + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +#include "../../common/functions.h" + +void main() { + const uint CASCADE = inId.w; + if ( CASCADES <= CASCADE ) discard; + const vec3 P = inPosition.xzy * 0.5 + 0.5; + if ( abs(P.x) > 1 || abs(P.y) > 1 || abs(P.z) > 1 ) discard; + + const uint triangleID = uint(inId.x); // gl_PrimitiveID + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + surface.st.xy = inSt; + surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt)); + + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + surface.instance = instance; + + vec4 A = material.colorBase; + float M = material.factorMetallic; + float R = material.factorRoughness; + float AO = material.factorOcclusion; + + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + // alpha mode OPAQUE + if ( material.modeAlpha == 0 ) { + A.a = 1; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + if ( A.a == 0 ) discard; + +#if USE_LIGHTMAP + if ( validTextureIndex( instance.lightmapID ) ) { + A.rgb *= sampleTexture( instance.lightmapID, inSt ).rgb; + } +#endif + + // sample normal + vec3 N = inNormal; + vec3 T = inTangent; + T = normalize(T - dot(T, N) * N); + vec3 B = cross(T, N); + mat3 TBN = mat3(T, B, N); +// mat3 TBN = mat3(N, B, T); + if ( T != vec3(0) && validTextureIndex( material.indexNormal ) ) { + N = TBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - 1.0 ); + } + + const ivec3 uvw = ivec3(P * imageSize(voxelRadiance[CASCADE])); + +#if DEPTH_TEST + const float outDepth = length(inPosition.xzy); + const float inDepth = imageLoad(voxelDepth[CASCADE], uvw).r; + if ( inDepth != 0 && inDepth < outDepth ) discard; + imageStore(voxelDepth[CASCADE], uvw, vec4(inDepth, 0, 0, 0)); +#endif + + imageStore(voxelId[CASCADE], uvw, uvec4(uvec2(drawID + 1, instanceID + 1), 0, 0)); + imageStore(voxelNormal[CASCADE], uvw, vec4(encodeNormals( normalize( N ) ), 0, 0)); +#if BLEND + // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA + const vec4 src = A * inColor; + const vec4 dst = imageLoad(voxelRadiance[CASCADE], uvw); + imageStore(voxelRadiance[CASCADE], uvw, blend( src, dst, src.a ) ); +#else + imageStore(voxelRadiance[CASCADE], uvw, A ); +#endif +} diff --git a/bin/data/shaders - 1.1/graph/voxelize/geom.glsl b/bin/data/shaders - 1.1/graph/voxelize/geom.glsl new file mode 100644 index 00000000..65259479 --- /dev/null +++ b/bin/data/shaders - 1.1/graph/voxelize/geom.glsl @@ -0,0 +1,93 @@ +#version 450 +#pragma shader_stage(geometry) + +layout(triangles) in; +layout(triangle_strip, max_vertices = 3) out; + +layout (location = 0) flat in uvec4 inId[]; +layout (location = 1) flat in vec4 inPOS0[]; +layout (location = 2) in vec4 inPOS1[]; +layout (location = 3) in vec3 inPosition[]; +layout (location = 4) in vec2 inUv[]; +layout (location = 5) in vec4 inColor[]; +layout (location = 6) in vec2 inSt[]; +layout (location = 7) in vec3 inNormal[]; +layout (location = 8) in vec3 inTangent[]; + +layout (location = 0) flat out uvec4 outId; +layout (location = 1) flat out vec4 outPOS0; +layout (location = 2) out vec4 outPOS1; +layout (location = 3) out vec3 outPosition; +layout (location = 4) out vec2 outUv; +layout (location = 5) out vec4 outColor; +layout (location = 6) out vec2 outSt; +layout (location = 7) out vec3 outNormal; +layout (location = 8) out vec3 outTangent; + +layout (binding = 4) uniform UBO { + mat4 voxel; + + float cascadePower; + float granularity; + float voxelizeScale; + float occlusionFalloff; + + uint shadows; + uint padding1; + uint padding2; + uint padding3; +} ubo; + +float cascadePower( uint x ) { + return pow(1 + x, ubo.cascadePower); +// return max( 1, x * ubo.cascadePower ); +} + +#define USE_CROSS 0 +void main(){ + const float HALF_PIXEL = ubo.voxelizeScale; + const vec3 C = ( inPosition[0] + inPosition[1] + inPosition[2] ) / 3.0; + +#if USE_CROSS + const vec3 N = abs(cross(inPosition[2] - inPosition[0], inPosition[1] - inPosition[0])); +#else + const vec3 N = abs(inNormal[0] + inNormal[1] + inNormal[2]); + uint A = N.y > N.x ? 1 : 0; + A = N.z > N[A] ? 2 : A; +#endif + + const uint CASCADE = inId[0].w; + vec3 P[3] = { + 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), + }; + + #pragma unroll 3 + for( uint i = 0; i < 3; ++i ){ + const vec3 D = normalize( inPosition[i] - C ) * HALF_PIXEL; + + outPosition = P[i] + D; + outPOS0 = inPOS0[i]; + outPOS1 = inPOS1[i]; + outUv = inUv[i]; + outSt = inSt[i]; + outColor = inColor[i]; + outNormal = inNormal[i]; + outTangent = inTangent[i]; + outId = inId[i]; + + const vec3 P = outPosition; // + D; + #if USE_CROSS + if ( N.z > N.x && N.z > N.y ) gl_Position = vec4(P.x, P.y, 0, 1); + else if ( N.x > N.y && N.x > N.z ) gl_Position = vec4(P.y, P.z, 0, 1); + else gl_Position = vec4(P.x, P.z, 0, 1); + #else + if ( A == 0 ) gl_Position = vec4(P.zy, 0, 1 ); + else if ( A == 1 ) gl_Position = vec4(P.xz, 0, 1 ); + else if ( A == 2 ) gl_Position = vec4(P.xy, 0, 1 ); + #endif + EmitVertex(); + } + EndPrimitive(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/gui/base/frag.glsl b/bin/data/shaders - 1.1/gui/base/frag.glsl new file mode 100644 index 00000000..05f07fa7 --- /dev/null +++ b/bin/data/shaders - 1.1/gui/base/frag.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(fragment) + +#define GLYPH 0 +#include "../gui/frag.h" diff --git a/bin/data/shaders - 1.1/gui/base/vert.glsl b/bin/data/shaders - 1.1/gui/base/vert.glsl new file mode 100644 index 00000000..c6455702 --- /dev/null +++ b/bin/data/shaders - 1.1/gui/base/vert.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(vertex) + +#define GLYPH 0 +#include "../gui/vert.h" diff --git a/bin/data/shaders - 1.1/gui/gui/frag.h b/bin/data/shaders - 1.1/gui/gui/frag.h new file mode 100644 index 00000000..6343874d --- /dev/null +++ b/bin/data/shaders - 1.1/gui/gui/frag.h @@ -0,0 +1,45 @@ +#define TEXTURES 1 +#define CUBEMAPS 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" +#include "./gui.h" + +layout (binding = 1) uniform sampler2D samplerTexture; + +layout (location = 0) in vec2 inUv; +layout (location = 1) in flat Gui inGui; +layout (location = 7) in flat Glyph inGlyph; + +layout (location = 0) out vec4 outAlbedo; + +void main() { + if ( inUv.x < inGui.offset.x || inUv.y < inGui.offset.y || inUv.x > inGui.offset.z || inUv.y > inGui.offset.w ) discard; + + const vec2 uv = inUv.xy; + const float mip = mipLevel(dFdx(inUv), dFdy(inUv)); + vec4 C = inGui.color; +#if GLYPH + if ( enabled(inGui.mode, 1) ) { + outAlbedo = inGui.color; + return; + } + const float sampled = texture(samplerTexture, inUv).r; + if ( enabled(inGui.mode, 2) ) { + const float smoothing = ( inGlyph.spread > 0 && inGlyph.scale > 0 ) ? 0.25 / (inGlyph.spread * inGlyph.scale) : 0.25 / (4 * 1.5); + const float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, sampled); + const float alpha = smoothstep(inGlyph.weight - smoothing, inGlyph.weight + smoothing, sampled); + if ( alpha < 0.001 || alpha > 1 ) discard; + C = mix(inGlyph.stroke, inGui.color, outlining); + C.a = inGui.color.a * alpha; + } else { + if ( sampled < 0.001 || sampled > 1 ) discard; + C *= sampled; + } +#else + if ( enabled(inGui.mode, 0) ) C = inGui.color; + else C *= textureLod( samplerTexture, uv, mip ); +#endif + outAlbedo = C; +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/gui/gui/gui.h b/bin/data/shaders - 1.1/gui/gui/gui.h new file mode 100644 index 00000000..6a06ac56 --- /dev/null +++ b/bin/data/shaders - 1.1/gui/gui/gui.h @@ -0,0 +1,18 @@ +struct Gui { + vec4 offset; + vec4 color; + + int mode; + float depth; + float padding1; + float padding2; +}; + +struct Glyph { + vec4 stroke; + + int spread; + float weight; + float scale; + float padding; +}; \ No newline at end of file diff --git a/bin/data/shaders - 1.1/gui/gui/vert.h b/bin/data/shaders - 1.1/gui/gui/vert.h new file mode 100644 index 00000000..63ac1c3b --- /dev/null +++ b/bin/data/shaders - 1.1/gui/gui/vert.h @@ -0,0 +1,37 @@ +layout (constant_id = 0) const uint PASSES = 6; +layout (location = 0) in vec2 inPos; +layout (location = 1) in vec2 inUv; + +#include "./gui.h" + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +struct Matrices { + mat4 model[PASSES]; +}; +layout (binding = 0) uniform UBO { + Matrices matrices; + Gui gui; +#if GLYPH + Glyph glyph; +#endif +} ubo; + +layout (location = 0) out vec2 outUv; +layout (location = 1) out flat Gui outGui; +#if GLYPH + layout (location = 7) out flat Glyph outGlyph; +#endif + +void main() { + outUv = inUv; + outGui = ubo.gui; +#if GLYPH + outGlyph = ubo.glyph; +#endif + + gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, ubo.gui.depth, 1.0); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/gui/text/frag.glsl b/bin/data/shaders - 1.1/gui/text/frag.glsl new file mode 100644 index 00000000..506229e8 --- /dev/null +++ b/bin/data/shaders - 1.1/gui/text/frag.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(fragment) + +#define GLYPH 1 +#include "../gui/frag.h" diff --git a/bin/data/shaders - 1.1/gui/text/vert.glsl b/bin/data/shaders - 1.1/gui/text/vert.glsl new file mode 100644 index 00000000..60465aaa --- /dev/null +++ b/bin/data/shaders - 1.1/gui/text/vert.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(vertex) + +#define GLYPH 1 +#include "../gui/vert.h" diff --git a/bin/data/shaders - 1.1/raytrace/shader.ray-gen.glsl b/bin/data/shaders - 1.1/raytrace/shader.ray-gen.glsl new file mode 100644 index 00000000..40eca388 --- /dev/null +++ b/bin/data/shaders - 1.1/raytrace/shader.ray-gen.glsl @@ -0,0 +1,401 @@ +#version 460 + +#extension GL_EXT_ray_tracing : enable +#extension GL_ARB_shader_clock : enable + +#pragma shader_stage(raygen) +layout (constant_id = 0) const uint PASSES = 2; +layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 2) const uint CUBEMAPS = 8; +layout (constant_id = 3) const uint CASCADES = 1; + +// shader type settings +#define RT 1 +#define DEFERRED_SAMPLING 1 +#define BUFFER_REFERENCE 1 +#define UINT64_ENABLED 1 +#define PBR 1 +// shader function settings +#define FOG 1 + +//force it off +#define BARYCENTRIC 0 +#define BARYCENTRIC_CALCULATE 0 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +layout (binding = 0) uniform accelerationStructureEXT tlas; + +layout (binding = 1, rgba32f) uniform volatile coherent image2D outImage; + +layout (binding = 2) uniform UBO { + EyeMatrices eyes[2]; + + Settings settings; +} ubo; + +layout (std140, binding = 3) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 4) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 5) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 6) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 7) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 8) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 9) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 10) uniform sampler3D samplerNoise; +#if VXGI + layout (binding = 11) uniform usampler3D voxelId[CASCADES]; + layout (binding = 12) uniform sampler3D voxelNormal[CASCADES]; + layout (binding = 13) uniform sampler3D voxelRadiance[CASCADES]; +#endif + +layout (location = 0) rayPayloadEXT RayTracePayload payload; + +layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; +layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; +layout(buffer_reference, scalar) buffer Indirects { DrawCommand dc[]; }; + +layout(buffer_reference, scalar) buffer VPos { vec3 v[]; }; +layout(buffer_reference, scalar) buffer VUv { vec2 v[]; }; +layout(buffer_reference, scalar) buffer VColor { uint v[]; }; +layout(buffer_reference, scalar) buffer VSt { vec2 v[]; }; +layout(buffer_reference, scalar) buffer VNormal { vec3 v[]; }; +layout(buffer_reference, scalar) buffer VTangent { vec3 v[]; }; +layout(buffer_reference, scalar) buffer VID { uint v[]; }; + +#include "../common/functions.h" +#include "../common/light.h" +#include "../common/fog.h" +#if VXGI + #include "../common/vxgi.h" +#endif + +void trace( Ray ray, float tMin, float tMax ) { + uint rayFlags = gl_RayFlagsOpaqueEXT; + uint cullMask = 0xFF; + + payload.hit = false; + surface.position.eye.z = tMax; + traceRayEXT(tlas, rayFlags, cullMask, 0, 0, 0, ray.origin, tMin, ray.direction, tMax, 0); +} +void trace( Ray ray, float tMin ) { + uint rayFlags = gl_RayFlagsOpaqueEXT; + uint cullMask = 0xFF; + + float tMax = ubo.settings.rt.defaultRayBounds.y; + + payload.hit = false; + surface.position.eye.z = tMax; + traceRayEXT(tlas, rayFlags, cullMask, 0, 0, 0, ray.origin, tMin, ray.direction, tMax, 0); +} + +void trace( Ray ray ) { + trace( ray, ubo.settings.rt.defaultRayBounds.x, ubo.settings.rt.defaultRayBounds.y ); +} + +float shadowFactor( const Light light, float def ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = light.position - ray.origin; + + float tMin = ubo.settings.rt.defaultRayBounds.x; + float tMax = length(ray.direction) - 0.0001; + + ray.direction = normalize(ray.direction); + + uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT; + uint cullMask = 0xFF; + + payload.hit = true; + traceRayEXT(tlas, rayFlags, cullMask, 0, 0, 0, ray.origin, tMin, ray.direction, tMax, 0); + + return payload.hit ? 0.0 : 1.0; +} + +void directLighting() { +#if VXGI + indirectLighting(); +#endif + + surface.light.rgb += surface.material.albedo.rgb * ubo.settings.lighting.ambient.rgb * surface.material.occlusion; // add ambient lighting + surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting +#if PBR + pbr(); +#elif LAMBERT + lambert(); +#elif PHONG + phong(); +#endif + surface.fragment.rgb += surface.light.rgb; + surface.fragment.a = surface.material.albedo.a; +} + +vec4 traceStep( Ray ray ) { + Ray fogRay = ray; + float eyeDepth = 0; + vec4 outFrag = vec4(0); + + // initial condition + { + trace( ray ); + + if ( payload.hit ) { + populateSurface( payload ); + directLighting(); + } else if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], ray.direction ); + surface.fragment.a = 4096; + surface.position.eye.z /= 8; + } else { + surface.fragment = vec4(ubo.settings.lighting.ambient.rgb, 0.5); + } + #if FOG + fog( ray, surface.fragment.rgb, surface.fragment.a ); + #endif + outFrag = surface.fragment; + eyeDepth = surface.position.eye.z; + } + + + // "transparency" + if ( payload.hit && surface.material.albedo.a < 0.999 ) { + const vec4 TRANSPARENCY_COLOR = vec4(1.0 - surface.material.albedo.a); + + if ( surface.material.albedo.a < 0.001 ) outFrag = vec4(0); + + RayTracePayload surfacePayload = payload; + Ray transparency; + transparency.direction = ray.direction; + transparency.origin = surface.position.world; + fogRay = transparency; + + trace( transparency, ubo.settings.rt.alphaTestOffset ); + if ( payload.hit ) { + populateSurface( payload ); + directLighting(); + } else if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], ray.direction ); + surface.fragment.a = 4096; + surface.position.eye.z /= 8; + } + #if FOG + fog( transparency, surface.fragment.rgb, surface.fragment.a ); + #endif + outFrag += TRANSPARENCY_COLOR * surface.fragment; + eyeDepth = surface.position.eye.z; + + payload = surfacePayload; + populateSurface( payload ); + } +#if FOG + { + // surface.position.eye.z = eyeDepth; + // fog( fogRay, outFrag.rgb, outFrag.a ); + // fog( ray, surface.fragment.rgb, surface.fragment.a ); + } +#endif + + // reflection + if ( payload.hit ) { + const float REFLECTIVITY = 1.0 - surface.material.roughness; + const vec4 REFLECTED_ALBEDO = surface.material.albedo * REFLECTIVITY; + + if ( REFLECTIVITY > 0.001 ) { + RayTracePayload surfacePayload = payload; + + Ray reflection; + reflection.origin = surface.position.world; + reflection.direction = reflect( ray.direction, surface.normal.world ); + + trace( reflection ); + + if ( payload.hit ) { + populateSurface( payload ); + directLighting(); + } else if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], reflection.direction ); + surface.fragment.a = 4096; + } + #if FOG + fog( reflection, surface.fragment.rgb, surface.fragment.a ); + #endif + outFrag += REFLECTED_ALBEDO * surface.fragment; + + payload = surfacePayload; + populateSurface( payload ); + } + } + + return outFrag; +} + +void main() { +// if ( ubo.settings.mode.frameNumber > 16 ) return; +// prngSeed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, ubo.settings.mode.frameNumber); + prngSeed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, int(clockARB())); + surface.pass = PushConstant.pass; + surface.subID = 0; + vec4 outFrag = vec4(0); + + const uint SAMPLES = min(ubo.settings.rt.samples, 4); + const uint NUM_PATHS = min(ubo.settings.rt.paths, 8); +#if 1 + const uint FRAME_ACCUMULATION_VALUE = ubo.settings.rt.frameAccumulationMinimum > 0 ? min(ubo.settings.rt.frameAccumulationMinimum, ubo.settings.mode.frameNumber + 1) : ubo.settings.mode.frameNumber + 1; +#else + const uint FRAME_ACCUMULATION_VALUE = min(32, ubo.settings.mode.frameNumber + 1); +#endif + const float BLEND_FACTOR = 1.0f / float(FRAME_ACCUMULATION_VALUE); + uint FRAME_NUMBER = ubo.settings.mode.frameNumber; + +#if 0 + for ( uint samp = 0; samp < SAMPLES; ++samp, ++FRAME_NUMBER ) { + { + const vec2 center = ( FRAME_NUMBER > 0 ) ? vec2( rnd(), rnd() ) : vec2(0.5); + const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + center) / vec2(gl_LaunchSizeEXT.xy); + #if 1 + vec4 target = ubo.eyes[surface.pass].iProjection * vec4(inUv.x * 2.0f - 1.0f, inUv.y * 2.0f - 1.0f, 1, 1); + vec4 direction = ubo.eyes[surface.pass].iView * vec4(normalize(target.xyz), 0); + + surface.ray.direction = vec3(direction); + surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; + #else + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + 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.eyes[surface.pass].eyePos.xyz; + #endif + } + + { + vec4 curValue = vec4(0); + vec4 curWeight = vec4(1); + for ( uint path = 0; path < NUM_PATHS; ++path ) { + vec4 stepValue = traceStep( surface.ray ); + curValue += stepValue * curWeight; + + if ( !payload.hit ) break; + + surface.ray.origin = surface.position.world; + surface.ray.direction = samplingHemisphere( prngSeed, surface.normal.world ); + curWeight *= surface.material.albedo * dot( surface.ray.direction, surface.normal.world ); + + if ( length(curWeight) < 0.01 ) break; + } + outFrag += curValue; + } + } + { + outFrag /= SAMPLES; + } +#elif 0 + { + const vec2 center = ( FRAME_NUMBER > 0 ) ? vec2( rnd(), rnd() ) : vec2(0.5); + const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + center) / vec2(gl_LaunchSizeEXT.xy); + #if 0 + vec4 target = ubo.eyes[surface.pass].iProjection * vec4(inUv.x * 2.0f - 1.0f, inUv.y * 2.0f - 1.0f, 1, 1); + vec4 direction = ubo.eyes[surface.pass].iView * vec4(normalize(target.xyz), 0); + + surface.ray.direction = vec3(direction); + surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; + #else + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + 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.eyes[surface.pass].eyePos.xyz; + #endif + } + + { + vec4 curValue = vec4(0); + vec4 curWeight = vec4(1); + for ( uint path = 0; path < NUM_PATHS; ++path ) { + vec4 stepValue = traceStep( surface.ray ); + curValue += stepValue * curWeight; + + if ( !payload.hit ) break; + + surface.ray.origin = surface.position.world; + surface.ray.direction = samplingHemisphere( prngSeed, surface.normal.world ); + curWeight *= surface.material.albedo * dot( surface.ray.direction, surface.normal.world ); + + if ( length(curWeight) < 0.01 ) break; + } + outFrag += curValue; + } + { + surface.fragment = outFrag; + } +#else + { + const vec2 center = ( FRAME_NUMBER > 0 ) ? vec2( rnd(), rnd() ) : vec2(0.5); + const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + center) / vec2(gl_LaunchSizeEXT.xy); + #if 0 + vec4 target = ubo.eyes[surface.pass].iProjection * vec4(inUv.x * 2.0f - 1.0f, inUv.y * 2.0f - 1.0f, 1, 1); + vec4 direction = ubo.eyes[surface.pass].iView * vec4(normalize(target.xyz), 0); + + surface.ray.direction = vec3(direction); + surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; + #else + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + 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.eyes[surface.pass].eyePos.xyz; + #endif + } + { + surface.fragment = traceStep( surface.ray ); + } +#endif + { + #if BLOOM + float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); + vec4 outFragBright = brightness > ubo.threshold ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); + // imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), outFragBright); + #endif + #if FOG + fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); + #endif + } + + { + outFrag = surface.fragment; + outFrag.a = 1; + } + + if ( ubo.settings.mode.frameNumber == 0 ) { + imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), outFrag); + } else { + // if ( length(outFrag.rgb) < 0.01f ) return; + vec4 blended = mix(imageLoad(outImage, ivec2(gl_LaunchIDEXT.xy)), outFrag, BLEND_FACTOR); + + imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), blended); + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/raytrace/shader.ray-hit-any.glsl b/bin/data/shaders - 1.1/raytrace/shader.ray-hit-any.glsl new file mode 100644 index 00000000..20cca3ed --- /dev/null +++ b/bin/data/shaders - 1.1/raytrace/shader.ray-hit-any.glsl @@ -0,0 +1,28 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_EXT_buffer_reference : enable +#extension GL_EXT_buffer_reference2 : enable +#extension GL_EXT_scalar_block_layout : enable +#pragma shader_stage(anyhit) +layout (constant_id = 0) const uint PASSES = 2; +layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 2) const uint CUBEMAPS = 128; + +#define RT 1 +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout(location = 0) rayPayloadInEXT RayTracePayload payload; + +hitAttributeEXT vec2 attribs; + +void main() { + payload.hit = true; + payload.instanceID = gl_InstanceCustomIndexEXT; + payload.primitiveID = gl_PrimitiveID; + payload.attributes = attribs; + +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/raytrace/shader.ray-hit-closest.glsl b/bin/data/shaders - 1.1/raytrace/shader.ray-hit-closest.glsl new file mode 100644 index 00000000..d8aec3a6 --- /dev/null +++ b/bin/data/shaders - 1.1/raytrace/shader.ray-hit-closest.glsl @@ -0,0 +1,25 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_nonuniform_qualifier : enable + +#pragma shader_stage(closest) +layout (constant_id = 0) const uint PASSES = 2; +layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 2) const uint CUBEMAPS = 128; + +#define RT 1 +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout(location = 0) rayPayloadInEXT RayTracePayload payload; + +hitAttributeEXT vec2 attribs; + +void main() { + payload.hit = true; + payload.instanceID = gl_InstanceCustomIndexEXT; + payload.primitiveID = gl_PrimitiveID; + payload.attributes = attribs; +} \ No newline at end of file diff --git a/bin/data/shaders - 1.1/raytrace/shader.ray-miss.glsl b/bin/data/shaders - 1.1/raytrace/shader.ray-miss.glsl new file mode 100644 index 00000000..49d0a1e5 --- /dev/null +++ b/bin/data/shaders - 1.1/raytrace/shader.ray-miss.glsl @@ -0,0 +1,15 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#pragma shader_stage(miss) + +#define RT 1 +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout(location = 0) rayPayloadInEXT RayTracePayload payload; + +void main() { + payload.hit = false; +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/base/line/frag.glsl b/bin/data/shaders - 1.2/base/line/frag.glsl new file mode 100644 index 00000000..935d731a --- /dev/null +++ b/bin/data/shaders - 1.2/base/line/frag.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(fragment) + +layout (location = 0) in vec3 inPosition; +layout (location = 1) in vec3 inColor; + +layout (location = 0) out uvec2 outId; +layout (location = 1) out vec2 outNormals; +layout (location = 2) out vec4 outAlbedo; + +void main() { + outAlbedo = vec4(inColor, 1); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/base/line/vert.glsl b/bin/data/shaders - 1.2/base/line/vert.glsl new file mode 100644 index 00000000..32b9484c --- /dev/null +++ b/bin/data/shaders - 1.2/base/line/vert.glsl @@ -0,0 +1,29 @@ +#version 450 +#pragma shader_stage(vertex) + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (constant_id = 0) const uint PASSES = 6; + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inColor; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; + +layout (location = 0) out vec3 outPosition; +layout (location = 1) out vec3 outColor; + +void main() { + outPosition = vec3(camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0)); + outColor = inColor; + + gl_Position = camera.viewport[PushConstant.pass].projection * camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/common/fog.h b/bin/data/shaders - 1.2/common/fog.h new file mode 100644 index 00000000..7c62eff2 --- /dev/null +++ b/bin/data/shaders - 1.2/common/fog.h @@ -0,0 +1,56 @@ +// Perlin Fog +void fog( in Ray ray, inout vec3 i, float scale ) { + if ( ubo.settings.fog.stepScale <= 0 || ubo.settings.fog.range.x == 0 || ubo.settings.fog.range.y == 0 ) return; +#if FOG_RAY_MARCH + const float range = ubo.settings.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.settings.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 = 0; // 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.settings.fog.densityScale * 0.001 + ubo.settings.fog.offset * 0.01; + density = max(0, textureLod(samplerNoise, uvw, level).r - ubo.settings.fog.densityThreshold) * ubo.settings.fog.densityMultiplier; + if ( density > 0 ) { + density = exp(-density * stepSize * ubo.settings.fog.absorbtion); + transmittance *= density; + lightFactor *= density; + if ( transmittance < 0.1 ) break; + } + } + i.rgb = mix(ubo.settings.fog.color.rgb, i.rgb, transmittance ); + } +#endif +#if FOG_BASIC + const vec3 color = ubo.settings.fog.color.rgb; + const float inner = ubo.settings.fog.range.x; + const float outer = ubo.settings.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 - 1.2/common/functions.h b/bin/data/shaders - 1.2/common/functions.h new file mode 100644 index 00000000..45b85f9f --- /dev/null +++ b/bin/data/shaders - 1.2/common/functions.h @@ -0,0 +1,419 @@ +// 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 mipLevel( in vec2 dx_vtc, in vec2 dy_vtc ) { + const float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)); + return 0.5 * log2(delta_max_sqr); +// return max(0.0, 0.5 * log2(delta_max_sqr) - 1.0); + +// return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); +} +float mipLevels( vec2 size ) { + return floor(log2(max(size.x, size.y))); +} +float mipLevels( ivec2 size ) { + return floor(log2(max(size.x, size.y))); +} +// +void toneMap( inout vec3 color, float exposure ) { + color.rgb = vec3(1.0) - exp(-color.rgb * exposure); +} +void gammaCorrect( inout vec3 color, float gamma ) { + color.rgb = pow(color.rgb, vec3(1.0 / gamma)); +} +void toneMap( inout vec4 color, float exposure ) { toneMap(color.rgb, exposure); } +void gammaCorrect( inout vec4 color, float gamma ) { gammaCorrect(color.rgb, gamma); } +// +uint tea(uint val0, uint val1) { + uint v0 = val0; + uint v1 = val1; + uint s0 = 0; + + #pragma unroll 16 + for(uint n = 0; n < 16; n++) { + s0 += 0x9e3779b9; + v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); + v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); + } + return v0; +} +uint lcg(inout uint prev) { + uint LCG_A = 1664525u; + uint LCG_C = 1013904223u; + prev = (LCG_A * prev + LCG_C); + return prev & 0x00FFFFFF; +} +float rnd(inout uint prev) { return (float(lcg(prev)) / float(0x01000000)); } + +uint prngSeed; +float rnd() { return rnd(prngSeed); } +// +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 tangentBitangent(in vec3 N, out vec3 Nt, out vec3 Nb) { + if(abs(N.x) > abs(N.y)) Nt = vec3(N.z, 0, -N.x) / sqrt(N.x * N.x + N.z * N.z); + else Nt = vec3(0, -N.z, N.y) / sqrt(N.y * N.y + N.z * N.z); + Nb = cross(N, Nt); +} +vec3 samplingHemisphere(inout uint seed, in vec3 x, in vec3 y, in vec3 z) { + float r1 = rnd(seed); + float r2 = rnd(seed); + float sq = sqrt(1.0 - r2); + vec3 direction = vec3(cos(2 * PI * r1) * sq, sin(2 * PI * r1) * sq, sqrt(r2)); + direction = direction.x * x + direction.y * y + direction.z * z; + return direction; +} +vec3 samplingHemisphere(inout uint seed, in vec3 z) { + vec3 x; + vec3 y; + tangentBitangent( z, x, y ); + + float r1 = rnd(seed); + float r2 = rnd(seed); + float sq = sqrt(1.0 - r2); + vec3 direction = vec3(cos(2 * PI * r1) * sq, sin(2 * PI * r1) * sq, sqrt(r2)); + direction = direction.x * x + direction.y * y + direction.z * z; + return direction; +} +// +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); +} +vec4 blend( vec4 source, vec4 dest, float a ) { + return source * a + dest * (1.0 - a); +} +float gauss( float x, float sigma ) { + return (1.0 / (2.0 * 3.14157 * sigma) * exp(-(x*x) / (2.0 * sigma))); +} +bool enabled( uint flag, uint bit ) { + return (flag & (1 << bit)) != 0; +} +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; +} +vec3 encodeSrgb(vec3 rgb) { + const vec3 a = 12.92 * rgb; + const vec3 b = 1.055 * pow(rgb, vec3(1.0 / 2.4)) - 0.055; + const vec3 c = step(vec3(0.0031308), rgb); + return mix(a, b, c); +} + +vec3 decodeSrgb(vec3 rgb) { + const vec3 a = rgb / 12.92; + const vec3 b = pow((rgb + 0.055) / 1.055, vec3(2.4)); + const vec3 c = step(vec3(0.04045), rgb); + return mix(a, b, c); +} +bool validTextureIndex( int textureIndex ) { + return 0 <= textureIndex && textureIndex < MAX_TEXTURES; +} +#if MAX_CUBEMAPS +bool validCubemapIndex( int textureIndex ) { + return 0 <= textureIndex && textureIndex < MAX_CUBEMAPS; +} +#endif +#if !BLOOM && (DEFERRED || FRAGMENT || COMPUTE || RT) +bool validTextureIndex( uint id ) { + return 0 <= id && id < MAX_TEXTURES; +} +bool validTextureIndex( uint start, int offset ) { + return 0 <= offset && start + offset < MAX_TEXTURES; +} +uint textureIndex( uint start, int offset ) { + return start + offset; +} +vec4 sampleTexture( uint id, vec2 uv ) { + const Texture t = textures[id]; + return texture( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ) ); +} +vec4 sampleTexture( uint id, vec2 uv, float mip ) { +#if QUERY_MIPMAP + return sampleTexture( id, uv ); +#else + const Texture t = textures[id]; + return textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip ); +#endif +} +vec4 sampleTexture( uint id, vec3 uvm ) { return sampleTexture( id, uvm.xy, uvm.z ); } +vec4 sampleTexture( uint id ) { return sampleTexture( id, surface.uv.xy, surface.uv.z ); } +vec4 sampleTexture( uint id, float mip ) { return sampleTexture( id, surface.uv.xy, mip ); } +#endif +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); +} +#if VXGI +float cascadePower( uint x ) { + return pow(1 + x, ubo.settings.vxgi.cascadePower); +// return max( 1, x * ubo.settings.vxgi.cascadePower ); +} +#endif +#if FRAGMENT +void whitenoise(inout vec3 color, const vec4 parameters) { + const float flicker = parameters.x; + 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 ); +} +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; +} +#endif +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; +} +// + +vec2 encodeBarycentrics( vec3 barycentric ) { + return barycentric.yz; +} +vec3 decodeBarycentrics( vec2 attributes ) { + return vec3( + 1.0 - attributes.x - attributes.y, + attributes.x, + attributes.y + ); +} +#if DEFERRED_SAMPLING +void populateSurfaceMaterial() { + const Material material = materials[surface.instance.materialID]; + surface.material.albedo = material.colorBase; + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; + surface.light = material.colorEmissive; + + if ( validTextureIndex( material.indexAlbedo ) ) { + surface.material.albedo *= sampleTexture( material.indexAlbedo ); + } + // OPAQUE + if ( material.modeAlpha == 0 ) { + surface.material.albedo.a = 1; + // BLEND + } else if ( material.modeAlpha == 1 ) { + + // MASK + } else if ( material.modeAlpha == 2 ) { + + } + // Lightmap + if ( (/*surface.subID++ > 0 ||*/ bool(ubo.settings.lighting.useLightmaps)) && validTextureIndex( surface.instance.lightmapID ) ) { + vec4 light = sampleTexture( surface.instance.lightmapID, surface.st ); + /*surface.material.lightmapped = light.a > 0.000000001; + if ( surface.material.lightmapped )*/ surface.light += surface.material.albedo * light; + } else { + surface.material.lightmapped = false; + } + // Emissive textures + if ( validTextureIndex( material.indexEmissive ) ) { + surface.light += sampleTexture( material.indexEmissive ); + } + // Occlusion map + if ( validTextureIndex( material.indexOcclusion ) ) { + surface.material.occlusion = sampleTexture( material.indexOcclusion ).r; + } + // Metallic/Roughness map + if ( validTextureIndex( material.indexMetallicRoughness ) ) { + vec4 samp = sampleTexture( material.indexMetallicRoughness ); + surface.material.metallic = samp.r; + surface.material.roughness = samp.g; + } + // Normals + if ( validTextureIndex( material.indexNormal ) && surface.tangent.world != vec3(0) ) { + surface.normal.world = surface.tbn * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - vec3(1.0)); + } + { + surface.normal.eye = normalize(vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) )); + } + + surface.light *= surface.material.albedo; +} + +bool isValidAddress( uint64_t address ) { +#if UINT64_ENABLED + return bool(address); +#else + return bool(address.x) && bool(address.y); +#endif +} + +#if BUFFER_REFERENCE +void populateSurface( InstanceAddresses instanceAddresses, uvec3 indices ) { + Triangle triangle; + Vertex points[3]; + + if ( isValidAddress(instanceAddresses.vertex) ) { + Vertices vertices = Vertices(nonuniformEXT(instanceAddresses.vertex)); + + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_] = vertices.v[/*triangle.*/indices[_]]; + } else { + if ( isValidAddress(instanceAddresses.position) ) { + VPos buf = VPos(nonuniformEXT(instanceAddresses.position)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].position = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.uv) ) { + VUv buf = VUv(nonuniformEXT(instanceAddresses.uv)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].uv = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.st) ) { + VSt buf = VSt(nonuniformEXT(instanceAddresses.st)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].st = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.normal) ) { + VNormal buf = VNormal(nonuniformEXT(instanceAddresses.normal)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].normal = buf.v[/*triangle.*/indices[_]]; + } + if ( isValidAddress(instanceAddresses.tangent) ) { + VTangent buf = VTangent(nonuniformEXT(instanceAddresses.tangent)); + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/points[_].tangent = buf.v[/*triangle.*/indices[_]]; + } + } + +#if BARYCENTRIC_CALCULATE + { + const vec3 p = vec3(inverse( surface.instance.model ) * vec4(surface.position.world, 1)); + + const vec3 a = points[0].position; + const vec3 b = points[1].position; + const vec3 c = points[2].position; + + const vec3 v0 = b - a; + const vec3 v1 = c - a; + const vec3 v2 = p - a; + const float d00 = dot(v0, v0); + const float d01 = dot(v0, v1); + const float d11 = dot(v1, v1); + const float d20 = dot(v2, v0); + const float d21 = dot(v2, v1); + const float denom = d00 * d11 - d01 * d01; + + const float v = (d11 * d20 - d01 * d21) / denom; + const float w = (d00 * d21 - d01 * d20) / denom; + const float u = 1.0f - v - w; + + surface.barycentric = vec3( u, v, w ); + } +#endif + + triangle.geomNormal = normalize(cross(points[1].position - points[0].position, points[2].position - points[0].position)); + triangle.point.normal = /*triangle.*/points[0].normal * surface.barycentric[0] + /*triangle.*/points[1].normal * surface.barycentric[1] + /*triangle.*/points[2].normal * surface.barycentric[2]; + + triangle.point.position = /*triangle.*/points[0].position * surface.barycentric[0] + /*triangle.*/points[1].position * surface.barycentric[1] + /*triangle.*/points[2].position * surface.barycentric[2]; + triangle.point.uv = /*triangle.*/points[0].uv * surface.barycentric[0] + /*triangle.*/points[1].uv * surface.barycentric[1] + /*triangle.*/points[2].uv * surface.barycentric[2]; + triangle.point.st = /*triangle.*/points[0].st * surface.barycentric[0] + /*triangle.*/points[1].st * surface.barycentric[1] + /*triangle.*/points[2].st * surface.barycentric[2]; + triangle.point.tangent = /*triangle.*/points[0].tangent * surface.barycentric[0] + /*triangle.*/points[1].tangent * surface.barycentric[1] + /*triangle.*/points[2].tangent * surface.barycentric[2]; + + + if ( triangle.point.tangent != vec3(0) ) { + surface.tangent.world = normalize(vec3( surface.instance.model * vec4(triangle.point.tangent, 0.0) )); + vec3 bitangent = normalize(vec3( surface.instance.model * vec4(cross( triangle.point.normal, triangle.point.tangent ), 0.0) )); + surface.tbn = mat3(surface.tangent.world, bitangent, triangle.point.normal); + } + + // bind position +#if 1 || BARYCENTRIC_CALCULATE + { + surface.position.world = vec3( surface.instance.model * vec4(triangle.point.position, 1.0 ) ); + surface.position.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.position.world, 1.0) ); + } +#endif + // bind normals + { + surface.normal.world = normalize(vec3( surface.instance.model * vec4(triangle.point.normal, 0.0 ) )); + // surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) ); + } + // bind UVs + { + surface.uv.xy = triangle.point.uv; + surface.uv.z = 0; + surface.st.xy = triangle.point.st; + surface.st.z = 0; + } + + populateSurfaceMaterial(); +} +void populateSurface( uint instanceID, uint primitiveID ) { + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.instance = instances[instanceID]; + + const InstanceAddresses instanceAddresses = instanceAddresses[instanceID]; + if ( !isValidAddress(instanceAddresses.index) ) return; + const DrawCommand drawCommand = Indirects(nonuniformEXT(instanceAddresses.indirect)).dc[instanceAddresses.drawID]; + const uint triangleID = primitiveID + (drawCommand.indexID / 3); + uvec3 indices = Indices(nonuniformEXT(instanceAddresses.index)).i[triangleID]; + #pragma unroll 3 + for ( uint _ = 0; _ < 3; ++_ ) /*triangle.*/indices[_] += drawCommand.vertexID; + + populateSurface( instanceAddresses, indices ); +} +void populateSurface( RayTracePayload payload ) { + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.instance = instances[payload.instanceID]; + + if ( !payload.hit ) return; + surface.barycentric = decodeBarycentrics(payload.attributes); + populateSurface( payload.instanceID, payload.primitiveID ); +} +#endif +#endif \ No newline at end of file diff --git a/bin/data/shaders - 1.2/common/lambert.h b/bin/data/shaders - 1.2/common/lambert.h new file mode 100644 index 00000000..eed6391e --- /dev/null +++ b/bin/data/shaders - 1.2/common/lambert.h @@ -0,0 +1,66 @@ +float shadowFactor( const Light light, float def ); +void lambert() { + // outcoming light from surface to eye + const vec3 Lo = normalize( -surface.position.eye ); + // angle of outcoming light + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); + + for ( uint i = 0, shadows = 0; i < MAX_LIGHTS; ++i ) { + #if BAKING + // skip if surface is a dynamic light, we aren't baking dynamic lights + if ( lights[i].type < 0 ) continue; + #else + // skip if surface is already baked, and this isn't a dynamic light + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + #endif + if ( lights[i].power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + + vec3 Li = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + // magnitude of incoming light vector (for inverse-square attenuation) + const float Lmagnitude = dot(Li, Li); + // distance incoming light travels (reuse from above) + const float Ldistance = sqrt(Lmagnitude); + // "free" normalization, since we need to compute the above values anyways + Li = Li / Ldistance; + // attenuation factor + // const float Lattenuation = 1.0 / (1 + (PI * Lmagnitude)); + const float Lattenuation = 1.0 / (1 + Lmagnitude); + // skip if attenuation factor is too low + // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; + // ray cast if our surface is occluded from the light + const float Lshadow = 1; // ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // skip if our shadow factor is too low + if ( Lshadow <= LIGHT_POWER_CUTOFF ) continue; + // light radiance + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // skip if our radiance is too low + // if ( Lr <= LIGHT_POWER_CUTOFF ) continue; + // halfway vector + const vec3 Lh = normalize(Li + Lo); + // angle of incoming light + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + // angle of halfway light vector + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); +/* + const vec3 Liu = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + const vec3 Li = normalize(Liu); + // const float Lattenuation = 1.0 / (PI * pow(length(Liu), 2.0)); + // const float Lattenuation = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + const float Lattenuation = 1.0 / (1 + pow(length(Liu), 2.0)); + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + if ( lights[i].power * Lattenuation * Lshadow <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // const vec3 Lh = normalize(Li + Lo); + // const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); +*/ + + const vec3 diffuse = surface.material.albedo.rgb; + const vec3 specular = vec3(0); + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += lights[i].power * Lattenuation * Lshadow; + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/common/light.h b/bin/data/shaders - 1.2/common/light.h new file mode 100644 index 00000000..0dbfe75c --- /dev/null +++ b/bin/data/shaders - 1.2/common/light.h @@ -0,0 +1,11 @@ +float shadowFactor( const Light light, float def ); + +#if PBR + #include "../common/pbr.h" +#endif +#if LAMBERT + #include "../common/lambert.h" +#endif +#if PHONG + #include "../common/phong.h" +#endif \ No newline at end of file diff --git a/bin/data/shaders - 1.2/common/macros.h b/bin/data/shaders - 1.2/common/macros.h new file mode 100644 index 00000000..909ca56b --- /dev/null +++ b/bin/data/shaders - 1.2/common/macros.h @@ -0,0 +1,102 @@ +#ifndef NO_NONUNIFORM_EXT + #define NO_NONUNIFORM_EXT 0 + // enable if shaderNonUniform is not supported + // Nvidia hardware does not require nonuniformEXT, but AMD does +#endif + +// implicit variables +#ifndef MULTISAMPLING + #define MULTISAMPLING 1 +#endif +#ifndef MAX_MSAA_SAMPLES + #define MAX_MSAA_SAMPLES 16 +#endif +#ifndef MAX_TEXTURES + #define MAX_TEXTURES TEXTURES +#endif +#ifndef MAX_LIGHTS + #define MAX_LIGHTS ubo.settings.lengths.lights +#endif +#ifndef MAX_SHADOWS + #define MAX_SHADOWS ubo.settings.lighting.maxShadows +#endif +#ifndef VIEW_MATRIX + #define VIEW_MATRIX ubo.eyes[surface.pass].view +#endif + +// implicit shader settings +#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 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 PHONG + #define PHONG 0 +#endif +#ifndef LAMBERT + #define LAMBERT 0 +#endif +#ifndef PBR + #define PBR 1 +#endif +*/ + +#if NO_NONUNIFORM_EXT + #define nonuniformEXT(X) X +#else + #extension GL_EXT_nonuniform_qualifier : enable +#endif + +#if !UINT64_ENABLED + #define uint64_t uvec2 +#endif + +// easy and accessible in one place +#ifndef BARYCENTRIC + #define BARYCENTRIC 0 +#endif +#if BARYCENTRIC + #ifndef BARYCENTRIC_CALCULATE + #define BARYCENTRIC_CALCULATE 0 + #endif +#endif + +#if BUFFER_REFERENCE + #extension GL_EXT_scalar_block_layout : enable + #extension GL_EXT_buffer_reference : enable + #extension GL_EXT_buffer_reference2 : enable + #if UINT64_ENABLED + #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable + #else + #extension GL_EXT_buffer_reference_uvec2 : enable + #endif +#endif + +const float PI = 3.14159265359; +const float EPSILON = 0.00001; +const float SQRT2 = 1.41421356237; + +const float LIGHT_POWER_CUTOFF = 0.0005; +const float LIGHTMAP_GAMMA = 1.0; \ No newline at end of file diff --git a/bin/data/shaders - 1.2/common/pbr.h b/bin/data/shaders - 1.2/common/pbr.h new file mode 100644 index 00000000..a9896c54 --- /dev/null +++ b/bin/data/shaders - 1.2/common/pbr.h @@ -0,0 +1,121 @@ +// PBR +void pbr() { + // per-surface, not per-light, compute once + + // Freslen reflectance for a dieletric + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + // outcoming light from surface to eye + const vec3 Lo = normalize( -surface.position.eye ); + // angle of outcoming light + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); + + const float Rs = 4.0; + + for ( uint i = 0, shadows = 0; i < MAX_LIGHTS; ++i ) { + #if BAKING + // skip if surface is a dynamic light, we aren't baking dynamic lights + if ( lights[i].type < 0 ) continue; + #else + // skip if surface is already baked, and this isn't a dynamic light + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + #endif + /* + // skip if light power is too low + if ( lights[i].power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + + const vec3 Liu = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + const vec3 Li = normalize(Liu); + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // const float Lattenuation = 1.0 / (PI * pow(length(Liu), 2.0)); + // const float Lattenuation = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + const float Lattenuation = 1.0 / (1 + pow(length(Liu), 2.0)); + if ( lights[i].power * Lattenuation * Lshadow <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); + */ + // incoming light to surface (non-const to normalize it later) + // vec3 Li = lights[i].position - surface.position.world; + vec3 Li = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + // magnitude of incoming light vector (for inverse-square attenuation) + const float Lmagnitude = dot(Li, Li); + // distance incoming light travels (reuse from above) + const float Ldistance = sqrt(Lmagnitude); + // "free" normalization, since we need to compute the above values anyways + Li = Li / Ldistance; + // attenuation factor + // const float Lattenuation = 1.0 / (1 + (PI * Lmagnitude)); + const float Lattenuation = 1.0 / (1 + Lmagnitude); + // skip if attenuation factor is too low + // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; + // ray cast if our surface is occluded from the light + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // skip if our shadow factor is too low + if ( Lshadow <= LIGHT_POWER_CUTOFF ) continue; + // light radiance + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // skip if our radiance is too low + // if ( Lr <= LIGHT_POWER_CUTOFF ) continue; + // halfway vector + const vec3 Lh = normalize(Li + Lo); + // angle of incoming light + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + // angle of halfway light vector + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); + + // Fresnel term for direct lighting + const vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, Lo))); + // Distribution for specular lighting + const float D = ndfGGX( cosLh, surface.material.roughness * Rs); + // Geometric attenuation for specular lighting + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness * Rs); + + // final lighting + const vec3 diffuse = mix(vec3(1.0) - F, vec3(0), surface.material.metallic) * surface.material.albedo.rgb; + const vec3 specular = ( shadows < MAX_SHADOWS ) ? ((F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo)) : vec3(0); + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += lights[i].power * Lattenuation * Lshadow; + } +#if 0 + const float Rs = 4.0; // specular lighting looks gross without this + uint shadows = 0; + for ( uint i = 0; i < ubo.settings.lengths.lights; ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && light.type >= 0 ) continue; + + const vec3 Liu = vec3(ubo.eyes[surface.pass].view * vec4(light.position, 1)) - surface.position.eye; + const float Ld = length(Liu); + const float La = 1.0 / (1 + (PI * pow(Ld, 2.0))); + if ( La <= LIGHT_POWER_CUTOFF ) continue; + + const vec3 Li = normalize(Liu); + const float Ls = ( shadows++ < ubo.settings.lighting.maxShadows ) ? shadowFactor( light, 0.0 ) : 1; + 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; + 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); + /* + // lightmapped, compute only specular + if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.light.rgb += (specular) * Lr * cosLi; + // point light, compute only diffuse + // else if ( abs(light.type) == 1 ) surface.light.rgb += (diffuse) * Lr * cosLi; + else surface.light.rgb += (diffuse + specular) * Lr * cosLi; + */ + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } +#endif +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/common/shadows.h b/bin/data/shaders - 1.2/common/shadows.h new file mode 100644 index 00000000..20100334 --- /dev/null +++ b/bin/data/shaders - 1.2/common/shadows.h @@ -0,0 +1,171 @@ +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.settings.lighting.shadowSamples +#endif +#if VXGI + float voxelShadowFactor( const Light, float def ); +#endif + +#if CUBEMAPS +float omniShadowMap( const Light light, float def ) { + return 1.0; +} +#else +float omniShadowMap( const Light light, float def ) { + float factor = 1.0; + + const mat4 views[6] = { + mat4( 0, 0, 1, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 1 ), + mat4( 0, 0,-1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ), + mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 1 ), + }; + + const vec3 D = normalize(surface.position.world - light.position); + const vec3 N = abs(D); + uint A = N.y > N.x ? 1 : 0; + A = N.z > N[A] ? 2 : A; + uint index = A * 2; + if ( D[A] < 0.0 ) ++index; + + vec4 positionClip = light.projection * views[index] * vec4(surface.position.world - light.position, 1.0); + positionClip.xy /= 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 < -1 || positionClip.z >= 1 ) return 0.0; + + const float eyeDepthScale = 1.0; + const float sampledDepthScale = light.view[1][1]; // light view matricies will incorporate scaling factors for some retarded reason, so we need to rescale it by grabbing from here, hopefully it remains coherent between all light matrices to ever exist in engine + + const float bias = light.depthBias; + const float eyeDepth = abs(positionClip.z / positionClip.w) * eyeDepthScale; + + const vec3 sampleOffsetDirections[20] = { + vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), + vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), + vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), + vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), + vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) + }; + + float sampled = 0; + const int samples = int(SHADOW_SAMPLES); + // cubemap point light + if ( light.typeMap == 1 ) { + if ( samples < 1 ) { + sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D).r * sampledDepthScale; + } else { + for ( int i = 0; i < samples; ++i ) { + const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; + vec2 poisson = poissonDisk[idx] / 700.0; + vec3 P = vec3( poisson.xy, (poisson.x + poisson.y) * 0.5 ); + sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D + P ).r * sampledDepthScale; + if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples; + } + return factor; + } + // separated point lights + } else if ( light.typeMap == 2 ) { + const vec2 uv = positionClip.xy * 0.5 + 0.5; + if ( samples < 1 ) { + sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv).r * sampledDepthScale; + } else { + for ( int i = 0; i < samples; ++i ) { + const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; + sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv + poissonDisk[idx] / 700.0 ).r * sampledDepthScale; + if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples; + } + return factor; + } + } + return eyeDepth < sampled - bias ? 0.0 : factor; +} +#endif +#if RT +float shadowFactorRT( const Light light, float def ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = light.position - ray.origin; + + float tMin = ubo.settings.rt.defaultRayBounds.x; + float tMax = length(ray.direction) - ubo.settings.rt.defaultRayBounds.x; + + ray.direction = normalize(ray.direction); + + uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT; + uint cullMask = 0xFF; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, tlas, rayFlags, cullMask, ray.origin, tMin, ray.direction, tMax); + + while(rayQueryProceedEXT(rayQuery)); + + return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT ? 1.0 : 0.0; +} +#endif +float shadowFactor( const Light light, float def ) { +#if RT + return shadowFactorRT( light, def ); +#endif + if ( light.typeMap != 0 ) return omniShadowMap( light, def ); + + if ( !validTextureIndex(light.indexMap) ) + #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.indexMap)], 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.indexMap)], 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 - 1.2/common/structs.h b/bin/data/shaders - 1.2/common/structs.h new file mode 100644 index 00000000..c8e35fb5 --- /dev/null +++ b/bin/data/shaders - 1.2/common/structs.h @@ -0,0 +1,308 @@ +struct EyeMatrices { + mat4 view; + mat4 projection; + + mat4 model; + mat4 previous; + + mat4 iView; + mat4 iProjection; + + vec4 eyePos; +}; + +struct Viewport { + mat4 view; + mat4 projection; +}; + +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 Light { + mat4 view; + mat4 projection; + + vec3 position; + float radius; + + vec3 color; + float power; + + int type; + int typeMap; + int indexMap; + float depthBias; +}; + +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 padding1; + int padding2; + int modeAlpha; +}; + +struct Texture { + int index; + int samp; + int remap; + float blend; + + vec4 lerp; +}; + +struct DrawCommand { + uint indices; // triangle count + uint instances; // instance count + uint indexID; // starting triangle position + int vertexID; // starting vertex position + + uint instanceID; // starting instance position + float padding1; // + float padding2; // material to use for this draw call + uint vertices; // number of vertices used +}; + +struct Bounds { + vec3 min; + float padding1; + vec3 max; + float padding2; +}; + +struct Instance { + mat4 model; + mat4 previous; + + vec4 color; + + uint materialID; + uint primitiveID; + uint meshID; + uint objectID; + + int jointID; + int lightmapID; + uint imageID; + uint auxID; + + Bounds bounds; +// InstanceAddresses addresses; +}; + +struct InstanceAddresses { + uint64_t vertex; + uint64_t index; + + uint64_t indirect; + uint drawID; + uint padding0; + + uint64_t position; + uint64_t uv; + + uint64_t color; + uint64_t st; + + uint64_t normal; + uint64_t tangent; + + uint64_t joints; + uint64_t weights; + + uint64_t id; + uint64_t padding1; +}; + +struct SurfaceMaterial { + vec4 albedo; + vec4 indirect; + + float metallic; + float roughness; + float occlusion; + bool lightmapped; +}; + +struct Surface { + uint pass; + uint subID; + + vec3 uv; + vec3 st; + Space position; + Space normal; + Space tangent; + mat3 tbn; + vec3 barycentric; + vec2 motion; + + Ray ray; + + SurfaceMaterial material; + Instance instance; + + vec4 light; + vec4 fragment; +} surface; + +// MSAA info +#if MULTISAMPLING +struct MSAA { + int currentID; + uvec2 IDs[MAX_MSAA_SAMPLES]; + vec4 fragment; + vec4 fragments[MAX_MSAA_SAMPLES]; +} msaa; +#endif +// UBO settings +struct SettingsLengths { + uint lights; + uint materials; + uint textures; + uint drawCommands; +}; +struct SettingsMode { + vec4 parameters; + uint type; + uint scalar; + uint msaa; + uint frameNumber; +}; +struct SettingsLighting { + vec3 ambient; + uint indexSkybox; + + uint maxShadows; + uint shadowSamples; + uint useLightmaps; +}; +struct SettingsFog { + vec3 color; + float stepScale; + + vec3 offset; + float densityScale; + + vec2 range; + float densityThreshold; + float densityMultiplier; + + float absorbtion; + float padding1; + float padding2; + float padding3; +}; +struct SettingsBloom { + float exposure; + float gamma; + float threshold; + uint padding; +}; +struct SettingsVxgi { + mat4 matrix; + + float cascadePower; + float granularity; + float voxelizeScale; + float occlusionFalloff; + + float traceStartOffsetFactor; + uint shadows; + uint padding2; + uint padding3; +}; +struct SettingsRayTrace { + vec2 defaultRayBounds; + float alphaTestOffset; + float padding1; + + uint samples; + uint paths; + uint frameAccumulationMinimum; + uint padding2; +}; + +struct Settings { + SettingsLengths lengths; + SettingsMode mode; + SettingsLighting lighting; + SettingsFog fog; + SettingsBloom bloom; + SettingsVxgi vxgi; + SettingsRayTrace rt; +}; +struct Voxel { + uvec2 id; + vec3 position; + vec3 normal; + vec2 uv; + vec4 color; +}; +struct VoxelInfo { + vec3 min; + vec3 max; + + float mipmapLevels; + float radianceSize; + float radianceSizeRecip; +} voxelInfo; + +// Raytrace stuff + +struct Vertex { + vec3 position; + vec2 uv; + uint color; + vec2 st; + vec3 normal; + vec3 tangent; + uvec2 joints; + vec4 weights; + uint id; +}; + +struct Triangle { + Vertex point; + + vec3 geomNormal; + + uint instanceID; +}; + +struct RayTracePayload { + bool hit; + uint instanceID; + uint primitiveID; + vec2 attributes; +// Triangle triangle; +}; \ No newline at end of file diff --git a/bin/data/shaders - 1.2/common/vxgi.h b/bin/data/shaders - 1.2/common/vxgi.h new file mode 100644 index 00000000..83621d1b --- /dev/null +++ b/bin/data/shaders - 1.2/common/vxgi.h @@ -0,0 +1,189 @@ +// GI +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.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) ); + ray.direction = vec3( ubo.settings.vxgi.matrix * vec4( ray.direction, 0.0 ) ); + uint cascade = cascadeIndex(ray.origin); +#else + uint cascade = cascadeIndex( vec3( ubo.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) ) ); +#endif + const float granularityRecip = ubo.settings.vxgi.granularity; //2.0; // 0.25f * (CASCADES - cascade); + const float granularity = 1.0f / granularityRecip; + const float occlusionFalloff = ubo.settings.vxgi.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 + tDelta * ubo.settings.vxgi.traceStartOffsetFactor; + 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.settings.vxgi.matrix * 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 ( ubo.settings.vxgi.shadows < ++voxelShadowsCount ) 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.settings.vxgi.matrix ); + 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 = 0; // 1.0f / float(CONES_COUNT) * 0.125f; + + 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.25; // 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; + } + // indirectDiffuse.rgb *= surface.material.albedo.rgb; + 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 ); + // indirectSpecular.rgb *= surface.material.albedo.rgb; + // outFragColor.rgb = indirectSpecular.rgb; return; + } + +/* + if ( true ) { + gammaCorrect(indirectDiffuse.rgb, 1.0 / ubo.settings.bloom.gamma); + } +*/ + indirectDiffuse *= DIFFUSE_INDIRECT_FACTOR; + indirectSpecular *= SPECULAR_INDIRECT_FACTOR; + + + surface.material.indirect = indirectDiffuse + indirectSpecular; +// outFragColor.rgb = surface.material.indirect.rgb; return; + + // 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 * 0.5 ); + surface.fragment.rgb += (1.0 - surface.material.albedo.a) * radiance.rgb; + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/bloom/comp.glsl b/bin/data/shaders - 1.2/display/bloom/comp.glsl new file mode 100644 index 00000000..639cc811 --- /dev/null +++ b/bin/data/shaders - 1.2/display/bloom/comp.glsl @@ -0,0 +1,67 @@ +#version 450 +#pragma shader_stage(compute) + +#define COMPUTE 1 +#define TEXTURES 0 +#define CUBEMAPS 0 +#define BLOOM 1 + +layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; + +layout( push_constant ) uniform PushBlock { + uint eye; + uint mode; +} PushConstant; + +layout (binding = 0) uniform UBO { + float scale; + float strength; + float threshold; + float sigma; + + float gamma; + float exposure; + uint samples; + uint padding; +} ubo; + +layout (binding = 1, rgba16f) uniform volatile coherent image2D imageColor; +layout (binding = 2, rgba16f) uniform volatile coherent image2D imageBloom; +layout (binding = 3, rgba16f) uniform volatile coherent image2D imagePingPong; + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" + +void main() { + const uint mode = PushConstant.mode; + const ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + const ivec2 size = imageSize( imageColor ); + if ( texel.x >= size.x || texel.y >= size.y ) return; + + if ( mode == 0 ) { // fill bloom + vec3 result = imageLoad( imageColor, texel ).rgb; + float brightness = dot(result, vec3(0.2126, 0.7152, 0.0722)); + if ( brightness < ubo.threshold ) result = vec3(0, 0, 0); + imageStore( imageBloom, texel, vec4( result, 1.0 ) ); + } else if ( mode == 1 ) { // bloom horizontal + vec3 result = imageLoad( imageBloom, texel ).rgb * gauss( 0, ubo.sigma ) * ubo.strength; + for( int i = 1; i < ubo.samples; ++i ) { + result += imageLoad( imageBloom, texel + ivec2(i * ubo.scale, 0.0)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + result += imageLoad( imageBloom, texel - ivec2(i * ubo.scale, 0.0)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + } + // write to PingPong + imageStore( imagePingPong, texel, vec4( result, 1.0 ) ); + } else if ( mode == 2 ) { // bloom vertical + vec3 result = imageLoad( imagePingPong, texel ).rgb * gauss( 0, ubo.sigma ) * ubo.strength; + for( int i = 1; i < ubo.samples; ++i ) { + result += imageLoad( imagePingPong, texel + ivec2(0.0, i * ubo.scale)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + result += imageLoad( imagePingPong, texel - ivec2(0.0, i * ubo.scale)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + } + // write to Bloom + imageStore( imageBloom, texel, vec4( result, 1.0 ) ); + } else if ( mode == 3 ) { // combine + vec3 result = imageLoad( imageColor, texel ).rgb + imageLoad( imageBloom, texel ).rgb; + imageStore( imageColor, texel, vec4( result, 1.0 ) ); + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/deferred/comp/comp.glsl b/bin/data/shaders - 1.2/display/deferred/comp/comp.glsl new file mode 100644 index 00000000..cb7c6384 --- /dev/null +++ b/bin/data/shaders - 1.2/display/deferred/comp/comp.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 0 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/deferred/comp/comp.h b/bin/data/shaders - 1.2/display/deferred/comp/comp.h new file mode 100644 index 00000000..d791fa1e --- /dev/null +++ b/bin/data/shaders - 1.2/display/deferred/comp/comp.h @@ -0,0 +1,278 @@ +#extension GL_EXT_samplerless_texture_functions : require +#extension GL_EXT_nonuniform_qualifier : enable + +#if RT + #extension GL_EXT_ray_tracing : enable + #extension GL_EXT_ray_query : enable +#endif + +layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#define COMPUTE 1 +#define DEFERRED 1 +#define DEFERRED_SAMPLING 1 + +#define PBR 1 +#define LAMBERT 0 +#if RT || BARYCENTRIC + #define BUFFER_REFERENCE 0 + #define UINT64_ENABLED 0 +#endif +#define FOG 1 +#define FOG_RAY_MARCH 1 + +#include "../../../common/macros.h" + +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +#if VXGI + layout (constant_id = 2) const uint CASCADES = 16; +#endif + +#if !MULTISAMPLING + layout(binding = 0) uniform utexture2D samplerId; + #if BARYCENTRIC + #if !BARYCENTRIC_CALCULATE + layout(binding = 1) uniform texture2D samplerBary; + #endif + #else + layout(binding = 1) uniform texture2D samplerUv; + layout(binding = 2) uniform texture2D samplerNormal; + #endif + layout(binding = 3) uniform texture2D samplerDepth; +#else + layout(binding = 0) uniform utexture2DMS samplerId; + #if BARYCENTRIC + #if !BARYCENTRIC_CALCULATE + layout(binding = 1) uniform texture2DMS samplerBary; + #endif + #else + layout(binding = 1) uniform texture2DMS samplerUv; + layout(binding = 2) uniform texture2DMS samplerNormal; + #endif + layout(binding = 3) uniform texture2DMS samplerDepth; +#endif + + +layout(binding = 7, rgba16f) uniform volatile coherent image2D imageColor; +layout(binding = 8, rgba16f) uniform volatile coherent image2D imageBright; +layout(binding = 9, rg16f) uniform volatile coherent image2D imageMotion; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +#include "../../../common/structs.h" + +layout (binding = 10) uniform UBO { + EyeMatrices eyes[2]; + + Settings settings; +} ubo; +/* +*/ +layout (std140, binding = 11) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 12) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 13) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 14) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 15) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 16) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 17) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 18) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 19) uniform sampler3D samplerNoise; +#if VXGI + layout (binding = 20) uniform usampler3D voxelId[CASCADES]; + layout (binding = 21) uniform sampler3D voxelNormal[CASCADES]; + layout (binding = 22) uniform sampler3D voxelRadiance[CASCADES]; +#endif +#if RT + layout (binding = 23) uniform accelerationStructureEXT tlas; +#endif + +#if BUFFER_REFERENCE + layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; + layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; + layout(buffer_reference, scalar) buffer Indirects { DrawCommand dc[]; }; + + layout(buffer_reference, scalar) buffer VPos { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VUv { vec2 v[]; }; + layout(buffer_reference, scalar) buffer VColor { uint v[]; }; + layout(buffer_reference, scalar) buffer VSt { vec2 v[]; }; + layout(buffer_reference, scalar) buffer VNormal { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VTangent { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VID { uint v[]; }; +#endif + +#include "../../../common/functions.h" +#include "../../../common/fog.h" +#include "../../../common/light.h" +#include "../../../common/shadows.h" +#if VXGI + #include "../../../common/vxgi.h" +#endif + +#if MULTISAMPLING + #define IMAGE_LOAD(X) texelFetch( X, ivec2(gl_GlobalInvocationID.xy), msaa.currentID ) +#else + #define IMAGE_LOAD(X) texelFetch( X, ivec2(gl_GlobalInvocationID.xy), 0 ) +#endif + +#define IMAGE_STORE(X, Y) imageStore( X, ivec2(gl_GlobalInvocationID.xy), Y ) + +void postProcess() { +#if FOG + fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); +#endif + float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); + bool bloom = brightness > ubo.settings.bloom.threshold; +//if ( bloom ) toneMap( surface.fragment.rgb, brightness ); + vec4 outFragColor = vec4(surface.fragment.rgb, 1.0); + vec4 outFragBright = bloom ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); + vec2 outFragMotion = surface.motion; + + IMAGE_STORE( imageColor, outFragColor ); + IMAGE_STORE( imageBright, outFragBright ); + IMAGE_STORE( imageMotion, vec4(outFragMotion, 0, 0) ); +} + +void populateSurface() { + uvec2 renderSize = imageSize(imageColor); + if ( gl_GlobalInvocationID.x >= renderSize.x || gl_GlobalInvocationID.y >= renderSize.y || gl_GlobalInvocationID.z > PushConstant.pass ) return; + + surface.fragment = vec4(0); + surface.pass = PushConstant.pass; + + { + vec2 inUv = (vec2(gl_GlobalInvocationID.xy) / vec2(renderSize)) * 2.0f - 1.0f; + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + const vec4 near4 = iProjectionView * (vec4(inUv, -1.0, 1.0)); + const vec4 far4 = iProjectionView * (vec4(inUv, 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 = /*near3.xyz;*/ ubo.eyes[surface.pass].eyePos.xyz; + + const float depth = IMAGE_LOAD(samplerDepth).r; + + vec4 eye = ubo.eyes[surface.pass].iProjection * vec4(inUv, depth, 1.0); + eye /= eye.w; + + surface.position.eye = eye.xyz; + surface.position.world = vec3( ubo.eyes[surface.pass].iView * eye ); + } + +#if !MULTISAMPLING + const uvec2 ID = uvec2(IMAGE_LOAD(samplerId).xy); +#else + const uvec2 ID = msaa.IDs[msaa.currentID]; +#endif + surface.motion = vec2(0); + + if ( ID.x == 0 || ID.y == 0 ) { + if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment.rgb = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], surface.ray.direction ).rgb; + } + surface.fragment.a = 0.0; + return; + } + { + const uint triangleID = ID.x - 1; + const uint instanceID = ID.y - 1; + surface.subID = 1; + + #if BARYCENTRIC + #if !BARYCENTRIC_CALCULATE + surface.barycentric = decodeBarycentrics(IMAGE_LOAD(samplerBary).xy).xyz; + #endif + populateSurface( instanceID, triangleID ); + #else + vec4 uvst = IMAGE_LOAD(samplerUv); + vec4 normaltangent = IMAGE_LOAD(samplerNormal); + + surface.uv.xy = uvst.xy; + surface.uv.z = 0; + surface.st.xy = uvst.zw; + surface.st.z = 0; + + surface.normal.world = decodeNormals(normaltangent.xy); + // surface.tangent.world = decodeNormals(normaltangent.zw); + + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.instance = instances[instanceID]; + + populateSurfaceMaterial(); + #endif + } + + { + vec4 pNDC = ubo.eyes[surface.pass].previous * surface.instance.previous * vec4(surface.position.world, 1); + vec4 cNDC = ubo.eyes[surface.pass].model * surface.instance.model * vec4(surface.position.world, 1); + pNDC /= pNDC.w; + cNDC /= cNDC.w; + + surface.motion = cNDC.xy - pNDC.xy; + } +} + +void directLighting() { + surface.light.rgb += surface.material.albedo.rgb * ubo.settings.lighting.ambient.rgb * surface.material.occlusion; // add ambient lighting + surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting +#if PBR + pbr(); +#elif LAMBERT + lambert(); +#elif PHONG + phong(); +#endif + + surface.fragment.rgb += surface.light.rgb; + +} + +#if MULTISAMPLING +void resolveSurfaceFragment() { + for ( int i = 0; i < ubo.settings.mode.msaa; ++i ) { + msaa.currentID = i; + msaa.IDs[i] = uvec3(IMAGE_LOAD(samplerId)).xy; + + // check if ID is already used + bool unique = true; + for ( int j = msaa.currentID - 1; j >= 0; --j ) { + if ( msaa.IDs[j] == msaa.IDs[i] ) { + surface.fragment = msaa.fragments[j]; + unique = false; + break; + } + } + + if ( unique ) { + populateSurface(); + #if VXGI + indirectLighting(); + #endif + directLighting(); + } + + msaa.fragment += surface.fragment; + msaa.fragments[msaa.currentID] = surface.fragment; + } + + surface.fragment = msaa.fragment / ubo.settings.mode.msaa; +} +#endif \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/deferred/comp/msaa.comp.glsl b/bin/data/shaders - 1.2/display/deferred/comp/msaa.comp.glsl new file mode 100644 index 00000000..00628645 --- /dev/null +++ b/bin/data/shaders - 1.2/display/deferred/comp/msaa.comp.glsl @@ -0,0 +1,13 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 0 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + resolveSurfaceFragment(); + + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/deferred/comp/rt.comp.glsl b/bin/data/shaders - 1.2/display/deferred/comp/rt.comp.glsl new file mode 100644 index 00000000..bdc07694 --- /dev/null +++ b/bin/data/shaders - 1.2/display/deferred/comp/rt.comp.glsl @@ -0,0 +1,13 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 0 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/deferred/comp/rt.msaa.comp.glsl b/bin/data/shaders - 1.2/display/deferred/comp/rt.msaa.comp.glsl new file mode 100644 index 00000000..1388e20b --- /dev/null +++ b/bin/data/shaders - 1.2/display/deferred/comp/rt.msaa.comp.glsl @@ -0,0 +1,13 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 0 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/deferred/comp/rt.vxgi.comp.glsl b/bin/data/shaders - 1.2/display/deferred/comp/rt.vxgi.comp.glsl new file mode 100644 index 00000000..18e067a1 --- /dev/null +++ b/bin/data/shaders - 1.2/display/deferred/comp/rt.vxgi.comp.glsl @@ -0,0 +1,14 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 1 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + indirectLighting(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/deferred/comp/rt.vxgi.msaa.comp.glsl b/bin/data/shaders - 1.2/display/deferred/comp/rt.vxgi.msaa.comp.glsl new file mode 100644 index 00000000..87394afc --- /dev/null +++ b/bin/data/shaders - 1.2/display/deferred/comp/rt.vxgi.msaa.comp.glsl @@ -0,0 +1,13 @@ +#version 460 +#pragma shader_stage(compute) + +#define RT 1 +#define VXGI 1 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + populateSurface(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/deferred/comp/vxgi.comp.glsl b/bin/data/shaders - 1.2/display/deferred/comp/vxgi.comp.glsl new file mode 100644 index 00000000..f29ee254 --- /dev/null +++ b/bin/data/shaders - 1.2/display/deferred/comp/vxgi.comp.glsl @@ -0,0 +1,14 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 1 +#define MULTISAMPLING 0 +#include "./comp.h" + +void main() { + populateSurface(); + indirectLighting(); + directLighting(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/deferred/comp/vxgi.msaa.comp.glsl b/bin/data/shaders - 1.2/display/deferred/comp/vxgi.msaa.comp.glsl new file mode 100644 index 00000000..6829be37 --- /dev/null +++ b/bin/data/shaders - 1.2/display/deferred/comp/vxgi.msaa.comp.glsl @@ -0,0 +1,12 @@ +#version 450 +#pragma shader_stage(compute) + +#define RT 0 +#define VXGI 1 +#define MULTISAMPLING 1 +#include "./comp.h" + +void main() { + resolveSurfaceFragment(); + postProcess(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/depth-pyramid/comp.glsl b/bin/data/shaders - 1.2/display/depth-pyramid/comp.glsl new file mode 100644 index 00000000..d58feb89 --- /dev/null +++ b/bin/data/shaders - 1.2/display/depth-pyramid/comp.glsl @@ -0,0 +1,30 @@ +#version 450 +#pragma shader_stage(compute) + +//#extension GL_EXT_nonuniform_qualifier : enable + +layout (constant_id = 0) const uint MIPS = 6; +layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +#define COMPUTE 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout( push_constant ) uniform PushBlock { + uint _; + uint pass; +} PushConstant; + +layout (binding = 3) uniform sampler2D inImage[MIPS]; +layout (binding = 4, r32f) uniform volatile coherent image2D outImage[MIPS]; + +void main() { + vec2 imageSize = imageSize(outImage[PushConstant.pass]); + uvec2 pos = gl_GlobalInvocationID.xy; + if ( pos.x >= imageSize.x || pos.y >= imageSize.y ) return; + + float depth = texture(inImage[PushConstant.pass], (vec2(pos) + vec2(0.5)) / imageSize).x; + + imageStore(outImage[PushConstant.pass], ivec2(pos), vec4(depth)); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/renderTarget/frag.glsl b/bin/data/shaders - 1.2/display/renderTarget/frag.glsl new file mode 100644 index 00000000..8758b85d --- /dev/null +++ b/bin/data/shaders - 1.2/display/renderTarget/frag.glsl @@ -0,0 +1,35 @@ +#version 450 +#pragma shader_stage(fragment) +#extension GL_EXT_samplerless_texture_functions : require + +layout (location = 0) in vec2 inUv; +layout (location = 1) flat in uint inPass; + +layout (location = 0) out vec4 outColor; + +layout (binding = 0) uniform sampler2D samplerColor; + +layout (binding = 1) uniform UBO { + float curTime; + float gamma; + float exposure; + uint padding; +} ubo; + +#define TONE_MAP 1 +#define GAMMA_CORRECT 1 +#define TEXTURES 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" + +void main() { + outColor = texture( samplerColor, inUv ); +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/renderTarget/postProcess.frag.glsl b/bin/data/shaders - 1.2/display/renderTarget/postProcess.frag.glsl new file mode 100644 index 00000000..5e1ae123 --- /dev/null +++ b/bin/data/shaders - 1.2/display/renderTarget/postProcess.frag.glsl @@ -0,0 +1,392 @@ +#version 450 +#pragma shader_stage(fragment) +#extension GL_EXT_samplerless_texture_functions : require + +layout (location = 0) in vec2 inUv; +layout (location = 1) flat in uint inPass; + +layout (location = 0) out vec4 outColor; + +layout (binding = 0) uniform sampler2D samplerColor; + +layout (binding = 1) uniform UBO { + float curTime; + float gamma; + float exposure; + uint padding; +} ubo; + +#define TONE_MAP 1 +#define GAMMA_CORRECT 1 +#define TEXTURES 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" + +#define M_PI 3.1415926535897932384626433832795 + +const float u_imgx = 0; +const float u_imgy = 0; +const float u_imgw = 1; +const float u_imgh = 1; +const float u_img_gain = 2; +const float u_img_bias = 0; +const float u_beam_bias = 0.185; +const float u_beam_gain = 0.25; +const float u_corner = 0.05; +const float u_zoom = 1.0; +const float u_shape = 2; +const float u_round = -0.02; +const float u_grain = 0.4; +const float u_vpitch = 936.1; +const float u_hpitch = 1024.6; +const float u_top = 1; +const float u_bot = 1; + +void main() { + const vec2 screenResolution = textureSize( samplerColor, 0 ); + const float u_lines = screenResolution.y * 0.75; + + vec2 uv_orig = (inUv.xy * 2.0 - 1.0); + vec2 uv_mod = uv_orig * pow(1.0-abs(uv_orig),vec2(u_round)) * (u_zoom + u_corner * pow( abs(uv_orig.yx), vec2(u_shape)) ); + vec2 uv = uv_mod / 2.0 + 0.5; + + if ( abs(uv_mod).x > 1.0 || abs(uv_mod.y) > 1.0 ) { + outColor = vec4(0.0, 0.0, 0.0, 1.0); + return; + } + + float spacing = 1.0/u_lines; + uv+=spacing*0.5; + + float line_top = ( ceil(uv.y*u_lines)) / u_lines; + float line_bot = line_top - spacing; + + vec2 scale = vec2(u_imgw, u_imgh); + vec2 offset = vec2(u_imgx, u_imgy); + + vec2 uv_top = (vec2(uv.x, line_top)+offset) * scale - (scale-1.0)*0.5 ; + vec2 uv_bot = (vec2(uv.x, line_bot)+offset) * scale - (scale-1.0)*0.5 ; + + uv_top -= spacing * 0.5; + uv_bot -= spacing * 0.5; + + vec4 sampled_top = texture(samplerColor, uv_top); + vec4 sampled_bot = texture(samplerColor, uv_bot); + + vec3 color_top = sampled_top.xyz * u_img_gain + u_img_bias; + vec3 color_bot = sampled_bot.xyz * u_img_gain + u_img_bias; + + float dist_top = pow(abs(uv.y - line_top), 1.0); + float dist_bot = pow(abs(uv.y - line_bot), 1.0); + + vec3 beam_top = 1.0 - (dist_top / (spacing * (color_top * u_beam_gain + u_beam_bias))); + vec3 beam_bot = 1.0 - (dist_bot / (spacing * (color_bot * u_beam_gain + u_beam_bias))); + + beam_top = clamp(beam_top, 0.0, 1.0) ; + beam_bot = clamp(beam_bot, 0.0, 1.0) ; + + vec3 color = (color_top*beam_top)*u_top + (color_bot*beam_bot)*u_bot; + + vec2 dot; + dot.y = floor(uv.y * u_vpitch) ; + dot.x = uv.x; + + if (mod(dot.y, 2.0) > 0.5) + dot.x += (4.5/3.0) / u_hpitch; + + dot.x = (floor(dot.x*u_hpitch)) ; + + int fil = int(mod(dot.x, 3.0)); + + vec3 out_color = color * (1.0-u_grain); + + vec3 passthru = vec3( + float(fil == 0), + float(fil == 1), + float(fil == 2) + ) * (u_grain); + + out_color += color * passthru; + + outColor = vec4(out_color, (sampled_top.a + sampled_bot.a) * 0.5 ); + +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} + +#if 0 +float iTime = 0; +float noise(vec2 p) { + float s = (fract(sin(dot(p * sin( iTime * 0.5 ), vec2(12.9898,78.233)*2.0)) * 43758.5453)); // texture(iChannel1,vec2(1.,2.*cos(iTime))*iTime*8. + p*1.).x; + s *= s; + return s; +} + +float onOff(float a, float b, float c) { + return step(c, sin(iTime + a*cos(iTime*b))); +} + +float ramp(float y, float start, float end) { + float inside = step(start,y) - step(end,y); + float fact = (y-start)/(end-start)*inside; + return (1.-fact) * inside; + +} + +float stripes(vec2 uv) { + float noi = noise(uv*vec2(0.5,1.) + vec2(1.,3.)); + return ramp(mod(uv.y*4. + iTime/2.+sin(iTime + sin(iTime*0.63)),1.),0.5,0.6)*noi; +} + +vec4 getVideo(vec2 uv) { + vec2 look = uv; + float window = 1./(1.+20.*(look.y-mod(iTime/4.,1.))*(look.y-mod(iTime/4.,1.))); + look.x = look.x + sin(look.y*10. + iTime)/50.*onOff(4.,4.,.3)*(1.+cos(iTime*80.))*window; + float vShift = 0.4*onOff(2.,3.,.9)*(sin(iTime)*sin(iTime*20.) + + (0.5 + 0.1*sin(iTime*200.)*cos(iTime))); + look.y = mod(look.y + vShift, 1.); + return texture(samplerColor,look); +} + +vec2 screenDistort(vec2 uv) { + uv -= vec2(.5,.5); + uv = uv*1.2*(1./1.2+2.*uv.x*uv.x*uv.y*uv.y); + uv += vec2(.5,.5); + return uv; +} + +void main() { + vec2 uv = inUv.xy; // fragCoord.xy / iResolution.xy; + iTime = ubo.curTime; + + uv = screenDistort(uv); + vec4 video = getVideo(uv); + float vigAmt = 3.+.3*sin(iTime + 5.*cos(iTime*5.)); + float vignette = (1.-vigAmt*(uv.y-.5)*(uv.y-.5))*(1.-vigAmt*(uv.x-.5)*(uv.x-.5)); + + video.rgb += stripes(uv); + video.rgb += noise(uv*2.)/4.; + video.rgb *= vignette; + video.rgb *= (12.+mod(uv.y*30.+iTime,1.))/13.; + + outColor = video; +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} +#endif +#if 0 +vec2 curveRemapUV(vec2 uv, vec2 curvature) { + uv = uv * 2.0 - 1.0; + vec2 offset = abs(uv.yx) / vec2(curvature.x, curvature.y); + uv = uv + uv * offset * offset; + uv = uv * 0.5 + 0.5; + return uv; +} + +vec4 scanLineIntensity(float uv, float resolution, float opacity) { + float intensity = sin(uv * resolution * PI * 2.0); + intensity = ((0.5 * intensity) + 0.5) * 0.9 + 0.1; + return vec4(vec3(pow(intensity, opacity)), 1.0); +} + +vec4 vignetteIntensity(vec2 uv, vec2 resolution, float opacity, float roundness) { + float intensity = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y); + return vec4(vec3(clamp(pow((resolution.x / roundness) * intensity, opacity), 0.0, 1.0)), 1.0); +} + +void main(void) { + const vec2 screenResolution = textureSize( samplerColor, 0 ); + const vec2 scanLineOpacity = vec2(0.5); + const float brightness = 2; + const float vignetteOpacity = 0.5; + const float vignetteRoundness = 0.5; + const vec2 curvature = vec2(8); + + const vec2 remappedUV = curveRemapUV(vec2(inUv.x, inUv.y), curvature); + vec4 baseColor = texture(samplerColor, remappedUV); + + baseColor *= vignetteIntensity(remappedUV, screenResolution, vignetteOpacity, vignetteRoundness); + + baseColor *= scanLineIntensity(remappedUV.x, screenResolution.y, scanLineOpacity.x); + baseColor *= scanLineIntensity(remappedUV.y, screenResolution.x, scanLineOpacity.y); + + baseColor *= vec4(vec3(brightness), 1.0); + + if (remappedUV.x < 0.0 || remappedUV.y < 0.0 || remappedUV.x > 1.0 || remappedUV.y > 1.0){ + outColor = vec4(0.0, 0.0, 0.0, 1.0); + } else { + outColor = baseColor; + } + +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} +#endif +#if 0 +vec2 fragCoord = vec2(0,0); +vec2 iResolution = vec2(640,480); + +// Emulated input resolution. +#if 0 + // Fix resolution to set amount. + #define res (vec2(320.0/1.0,160.0/1.0)) +#else + // Optimize for resize. + #define res (iResolution.xy/6.0) +#endif + +// Hardness of scanline. +// -8.0 = soft +// -16.0 = medium +float hardScan=-8.0; + +// Hardness of pixels in scanline. +// -2.0 = soft +// -4.0 = hard +float hardPix=-3.0; + +// Display warp. +// 0.0 = none +// 1.0/8.0 = extreme +vec2 warp=vec2(1.0/32.0,1.0/24.0); + +// Amount of shadow mask. +float maskDark=0.5; +float maskLight=1.5; + +//------------------------------------------------------------------------ + +// sRGB to Linear. +// Assuing using sRGB typed textures this should not be needed. +float ToLinear1(float c){return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4);} +vec3 ToLinear(vec3 c){return vec3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b));} + +// Linear to sRGB. +// Assuing using sRGB typed textures this should not be needed. +float ToSrgb1(float c){return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055);} +vec3 ToSrgb(vec3 c){return vec3(ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b));} + +// Nearest emulated sample given floating point position and texel offset. +// Also zero's off screen. +vec3 Fetch(vec2 pos,vec2 off){ + pos=floor(pos*res+off)/res; + if(max(abs(pos.x-0.5),abs(pos.y-0.5))>0.5)return vec3(0.0,0.0,0.0); + return ToLinear(texture(samplerColor,pos.xy,-16.0).rgb);} + +// Distance in emulated pixels to nearest texel. +vec2 Dist(vec2 pos){pos=pos*res;return -((pos-floor(pos))-vec2(0.5));} + +// 1D Gaussian. +float Gaus(float pos,float scale){return exp2(scale*pos*pos);} + +// 3-tap Gaussian filter along horz line. +vec3 Horz3(vec2 pos,float off){ + vec3 b=Fetch(pos,vec2(-1.0,off)); + vec3 c=Fetch(pos,vec2( 0.0,off)); + vec3 d=Fetch(pos,vec2( 1.0,off)); + float dst=Dist(pos).x; + // Convert distance to weight. + float scale=hardPix; + float wb=Gaus(dst-1.0,scale); + float wc=Gaus(dst+0.0,scale); + float wd=Gaus(dst+1.0,scale); + // Return filtered sample. + return (b*wb+c*wc+d*wd)/(wb+wc+wd);} + +// 5-tap Gaussian filter along horz line. +vec3 Horz5(vec2 pos,float off){ + vec3 a=Fetch(pos,vec2(-2.0,off)); + vec3 b=Fetch(pos,vec2(-1.0,off)); + vec3 c=Fetch(pos,vec2( 0.0,off)); + vec3 d=Fetch(pos,vec2( 1.0,off)); + vec3 e=Fetch(pos,vec2( 2.0,off)); + float dst=Dist(pos).x; + // Convert distance to weight. + float scale=hardPix; + float wa=Gaus(dst-2.0,scale); + float wb=Gaus(dst-1.0,scale); + float wc=Gaus(dst+0.0,scale); + float wd=Gaus(dst+1.0,scale); + float we=Gaus(dst+2.0,scale); + // Return filtered sample. + return (a*wa+b*wb+c*wc+d*wd+e*we)/(wa+wb+wc+wd+we);} + +// Return scanline weight. +float Scan(vec2 pos,float off){ + float dst=Dist(pos).y; + return Gaus(dst+off,hardScan);} + +// Allow nearest three lines to effect pixel. +vec3 Tri(vec2 pos){ + vec3 a=Horz3(pos,-1.0); + vec3 b=Horz5(pos, 0.0); + vec3 c=Horz3(pos, 1.0); + float wa=Scan(pos,-1.0); + float wb=Scan(pos, 0.0); + float wc=Scan(pos, 1.0); + return a*wa+b*wb+c*wc;} + +// Distortion of scanlines, and end of screen alpha. +vec2 Warp(vec2 pos){ + pos=pos*2.0-1.0; + pos*=vec2(1.0+(pos.y*pos.y)*warp.x,1.0+(pos.x*pos.x)*warp.y); + return pos*0.5+0.5;} + +// Shadow mask. +vec3 Mask(vec2 pos){ + pos.x+=pos.y*3.0; + vec3 mask=vec3(maskDark,maskDark,maskDark); + pos.x=fract(pos.x/6.0); + if(pos.x<0.333)mask.r=maskLight; + else if(pos.x<0.666)mask.g=maskLight; + else mask.b=maskLight; + return mask;} + +void main() { + iResolution = textureSize( samplerColor, 0 ); + fragCoord = inUv * iResolution; + + vec2 pos = Warp(fragCoord.xy / iResolution.xy); + + hardScan = -12.0; + maskDark = maskLight = 1.0; + + outColor.rgb = Tri(pos) * Mask(fragCoord.xy); + outColor.rgb = ToSrgb(outColor.rgb); + outColor.a = 1.0; + +#if TONE_MAP + toneMap(outColor, ubo.exposure); +#endif +#if GAMMA_CORRECT + gammaCorrect(outColor, ubo.gamma); +#endif +} +#endif +#if 0 +void main() { + const vec2 uv = 0.025 * sin( ubo.curTime ) * inUv.xy; + const float mdf = 0.5; + const float noise = (fract(sin(dot(uv, vec2(12.9898,78.233)*2.0)) * 43758.5453)); + const vec4 sampled = texture( samplerColor, inUv ); + + outColor = sampled - noise * mdf; + + toneMap(outColor, ubo.exposure); + gammaCorrect(outColor, ubo.gamma); +} +#endif \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/renderTarget/vert.glsl b/bin/data/shaders - 1.2/display/renderTarget/vert.glsl new file mode 100644 index 00000000..95fd44b3 --- /dev/null +++ b/bin/data/shaders - 1.2/display/renderTarget/vert.glsl @@ -0,0 +1,16 @@ +#version 450 +#pragma shader_stage(vertex) + +layout (location = 0) out vec2 outUv; +layout (location = 1) out flat uint outPass; + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +void main() { + outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + outPass = PushConstant.pass; + gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/vxgi/comp.glsl b/bin/data/shaders - 1.2/display/vxgi/comp.glsl new file mode 100644 index 00000000..9d44d570 --- /dev/null +++ b/bin/data/shaders - 1.2/display/vxgi/comp.glsl @@ -0,0 +1,148 @@ +#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 COMPUTE 1 + +#define VXGI 1 +#define MAX_CUBEMAPS CUBEMAPS +#define GAMMA_CORRECT 1 +#define PBR 1 + +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +layout (constant_id = 2) const uint CASCADES = 16; + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 0) uniform UBO { + EyeMatrices eyes[2]; + + Settings settings; +} ubo; +layout (std140, binding = 1) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 2) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 3) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 4) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 5) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 6) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 7) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 8) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 9) uniform sampler3D samplerNoise; + +layout (binding = 10, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; +layout (binding = 11, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; +#if VXGI_HDR + layout (binding = 12, rgba32f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#else + layout (binding = 12, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#endif + +#include "../../common/functions.h" +#include "../../common/light.h" +#undef VXGI // +#include "../../common/shadows.h" +void main() { + const vec3 tUvw = gl_GlobalInvocationID.xzy; + for ( uint CASCADE = 0; CASCADE < CASCADES; ++CASCADE ) { + surface.normal.world = decodeNormals( vec2(imageLoad(voxelNormal[CASCADE], ivec3(tUvw) ).xy) ); + surface.normal.eye = vec3( ubo.settings.vxgi.matrix * vec4( surface.normal.world, 0.0f ) ); + + surface.position.eye = (vec3(gl_GlobalInvocationID.xyz) / vec3(imageSize(voxelRadiance[CASCADE])) * 2.0f - 1.0f) * cascadePower(CASCADE); + surface.position.world = vec3( inverse(ubo.settings.vxgi.matrix) * vec4( surface.position.eye, 1.0f ) ); + + const uvec2 ID = uvec2(imageLoad(voxelId[CASCADE], ivec3(tUvw) ).xy); + const uint drawID = ID.x - 1; + const uint instanceID = ID.y - 1; + if ( ID.x == 0 || ID.y == 0 ) { + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(0)); + continue; + } + const DrawCommand drawCommand = drawCommands[drawID]; + surface.instance = instances[instanceID]; + const Material material = materials[surface.instance.materialID]; + surface.material.albedo = material.colorBase; + surface.fragment = material.colorEmissive; + + surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) ); + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; + + const vec3 ambient = ubo.settings.lighting.ambient.rgb * surface.material.occlusion; + if ( validTextureIndex( surface.instance.lightmapID ) ) { + surface.fragment.rgb += surface.material.albedo.rgb; + } else { + surface.fragment.rgb += surface.material.albedo.rgb * ambient; + // corrections + surface.position.eye = vec3( ubo.eyes[surface.pass].view * vec4( surface.position.world, 1 ) ); + surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0) ); + pbr(); + /* + surface.material.roughness *= 4.0; + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize( surface.position.world ); + const float cosLo = max(0.0, dot(surface.normal.world, Lo)); + for ( uint i = 0; i < ubo.settings.lengths.lights; ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - surface.position.world; + const vec3 Li = normalize(Liu); + const float Ls = shadowFactor( light, 0.0 ); + const float La = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.world, Li)); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + #if LAMBERT + const vec3 diffuse = surface.material.albedo.rgb; + const vec3 specular = vec3(0); + #elif PBR + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.world, Lh)); + + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, surface.material.roughness ); + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); + const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; + const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + #endif + // lightmapped, compute only specular + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } + */ + } + + surface.fragment.rgb += surface.light.rgb; + + #if TONE_MAP + toneMap(surface.fragment.rgb, ubo.settings.bloom.exposure); + #endif + #if GAMMA_CORRECT + gammaCorrect(surface.fragment.rgb, 1.0 / ubo.settings.bloom.gamma); + #endif + + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, surface.material.albedo.a)); + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/display/vxgi/mip.gaussian.comp.glsl b/bin/data/shaders - 1.2/display/vxgi/mip.gaussian.comp.glsl new file mode 100644 index 00000000..dae6f972 --- /dev/null +++ b/bin/data/shaders - 1.2/display/vxgi/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 - 1.2/graph/baking/frag.glsl b/bin/data/shaders - 1.2/graph/baking/frag.glsl new file mode 100644 index 00000000..076049f2 --- /dev/null +++ b/bin/data/shaders - 1.2/graph/baking/frag.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(fragment) + +#define RT 0 +#include "./frag.h" diff --git a/bin/data/shaders - 1.2/graph/baking/frag.h b/bin/data/shaders - 1.2/graph/baking/frag.h new file mode 100644 index 00000000..0abc2c25 --- /dev/null +++ b/bin/data/shaders - 1.2/graph/baking/frag.h @@ -0,0 +1,204 @@ +//#extension GL_EXT_nonuniform_qualifier : enable +#if RT + #extension GL_EXT_ray_tracing : enable + #extension GL_EXT_ray_query : enable +#endif + +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +layout (constant_id = 2) const uint LAYERS = 32; + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 6) uniform samplerCube samplerCubemaps[CUBEMAPS]; + +#define SHADOW_SAMPLES 16 +#define FRAGMENT 1 +#define BAKING 1 +#define PBR 1 +#define MAX_LIGHTS min(ubo.lights, lights.length()) +#define MAX_SHADOWS MAX_LIGHTS +#define VIEW_MATRIX camera.viewport[0].view + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 7) uniform Camera { + Viewport viewport[6]; +} camera; + +layout (binding = 8) uniform UBO { + uint lights; + uint currentID; + uint padding1; + uint padding2; +} ubo; + +layout (std140, binding = 9) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 10) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 11) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 12) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 13) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 14) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 15, rgba8) uniform volatile coherent image3D outAlbedos; + +#if RT + layout (binding = 16) uniform accelerationStructureEXT tlas; +#endif + +#include "../../common/functions.h" +#if RT +float shadowFactor( const Light light, float def ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = light.position - ray.origin; + + float tMin = 0.001; + float tMax = length(ray.direction) + tMin; + + ray.direction = normalize(ray.direction); + + uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT; + uint cullMask = 0xFF; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, tlas, rayFlags, cullMask, ray.origin, tMin, ray.direction, tMax); + + while(rayQueryProceedEXT(rayQuery)) {} + + return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT ? 1.0 : 0.0; +} +#else + #include "../../common/shadows.h" +#endif + +#include "../../common/light.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +layout (location = 0) out vec4 outAlbedo; + +void main() { + const uint triangleID = uint(inId.x); // gl_PrimitiveID + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + + if ( instanceID != ubo.currentID ) discard; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + surface.position.world = inPosition; + surface.normal.world = inNormal; + + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + const uint mapID = instance.auxID; + + vec4 A = material.colorBase; + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = 1.0f - material.factorOcclusion; + +#if 0 + vec3 N = inNormal; + vec3 T = inTangent; + T = normalize(T - dot(T, N) * N); + vec3 B = cross(T, N); + mat3 TBN = mat3(T, B, N); +// mat3 TBN = mat3(N, B, T); + if ( T != vec3(0) && validTextureIndex( material.indexNormal ) ) { + surface.normal.world = TBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - 1.0 ); + } else { + surface.normal.world = N; + } +#endif + + surface.light = material.colorEmissive; + surface.material.albedo = vec4(1); + { + surface.normal.eye = surface.normal.eye; + surface.position.eye = surface.position.eye; + // pbr(); + + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + for ( uint i = 0; i < min(ubo.lights, lights.length()); ++i ) { + const Light light = lights[i]; + + if ( light.type <= 0 ) continue; + + const mat4 mat = light.view; // inverse(light.view); + const vec3 position = surface.position.world; + // const vec3 position = vec3( mat * vec4(surface.position.world, 1.0) ); + const vec3 normal = surface.normal.world; + // const vec3 normal = vec3( mat * vec4(surface.normal.world, 0.0) ); + + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - surface.position.world; + const float La = 1.0 / (1 + PI * pow(length(Liu), 2.0)); + const float Ls = shadowFactor( light, 0.0 ); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + + const vec3 Lo = normalize( -position ); + const float cosLo = max(0.0, abs(dot(normal, Lo))); + + const vec3 Li = normalize(Liu); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + // const float cosLi = max(0.0, dot(normal, Li)); + const float cosLi = abs(dot(normal, Li)); + #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(normal, Lh)); + const float cosLh = abs(dot(normal, Lh)); + + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = 1; // 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 + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } + } +#define EXPOSURE 0 +#define GAMMA 0 + +// surface.light.rgb = vec3(1.0) - exp(-surface.light.rgb * EXPOSURE); +// surface.light.rgb = pow(surface.light.rgb, vec3(1.0 / GAMMA)); + + outAlbedo = vec4(surface.light.rgb, 1); + + { + const vec2 st = inSt.xy * imageSize(outAlbedos).xy; + const ivec3 uvw = ivec3(int(st.x), int(st.y), int(mapID)); + imageStore(outAlbedos, uvw, vec4(surface.light.rgb, 1) ); + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/graph/baking/rt.frag.glsl b/bin/data/shaders - 1.2/graph/baking/rt.frag.glsl new file mode 100644 index 00000000..a7eca538 --- /dev/null +++ b/bin/data/shaders - 1.2/graph/baking/rt.frag.glsl @@ -0,0 +1,5 @@ +#version 460 +#pragma shader_stage(fragment) + +#define RT 1 +#include "./frag.h" diff --git a/bin/data/shaders - 1.2/graph/baking/vert.glsl b/bin/data/shaders - 1.2/graph/baking/vert.glsl new file mode 100644 index 00000000..1f20a625 --- /dev/null +++ b/bin/data/shaders - 1.2/graph/baking/vert.glsl @@ -0,0 +1,8 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 0 +#define BAKING 1 + +#include "../base/vert.h" diff --git a/bin/data/shaders - 1.2/graph/base/frag.glsl b/bin/data/shaders - 1.2/graph/base/frag.glsl new file mode 100644 index 00000000..22289e3b --- /dev/null +++ b/bin/data/shaders - 1.2/graph/base/frag.glsl @@ -0,0 +1,126 @@ +#version 450 +#pragma shader_stage(fragment) + +//#extension GL_EXT_nonuniform_qualifier : enable + +#define FRAGMENT 1 +#define CAN_DISCARD 1 + +#define MAX_TEXTURES textures.length() + +layout (constant_id = 0) const uint TEXTURES = 1; + + +#include "../../common/macros.h" +#include "../../common/structs.h" + +#if BARYCENTRIC && !BARYCENTRIC_CALCULATE + #define BARYCENTRIC_STABILIZE 1 +// #define BARY_COORD gl_BaryCoordEXT +// #extension GL_EXT_fragment_shader_barycentric : enable + #define BARY_COORD gl_BaryCoordSmoothAMD + #extension GL_AMD_shader_explicit_vertex_parameter : enable +#endif + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 6) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 7) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 8) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 9) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 10) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 11) readonly buffer Lights { + Light lights[]; +}; + +#include "../../common/functions.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +#if BARYCENTRIC_STABILIZE + layout (location = 2) __explicitInterpAMD in vec4 inPOS1; +#else + layout (location = 2) in vec4 inPOS1; +#endif +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +layout (location = 0) out uvec2 outId; +#if BARYCENTRIC + layout (location = 1) out vec2 outBary; +#else + layout (location = 1) out vec4 outUv; + layout (location = 2) out vec4 outNormal; +#endif + +void main() { + const uint triangleID = gl_PrimitiveID; // uint(inId.x); + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + +#if CAN_DISCARD + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + surface.st.xy = wrap(inSt.xy); + surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt)); + + vec4 A = inColor * material.colorBase; + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + // alpha mode OPAQUE + if ( material.modeAlpha == 0 ) { + A.a = 1; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + if ( A.a < 0.0001 ) discard; + +#if !BARYCENTRIC + outUv = vec4(surface.uv, surface.st); + outNormal = vec4( encodeNormals(inNormal), encodeNormals(inTangent) ); +#endif + +#endif + + outId = uvec2(triangleID + 1, instanceID + 1); + +#if BARYCENTRIC && !BARYCENTRIC_CALCULATE + vec3 bary = vec3(gl_BaryCoordSmoothAMD.xy, 1 - gl_BaryCoordSmoothAMD.x - gl_BaryCoordSmoothAMD.y); + bary = bary.yzx; + #if BARYCENTRIC_STABILIZE + vec4 v0 = interpolateAtVertexAMD(inPOS1, 0); + vec4 v1 = interpolateAtVertexAMD(inPOS1, 1); + vec4 v2 = interpolateAtVertexAMD(inPOS1, 2); + if (v0 == inPOS0) outBary = encodeBarycentrics(bary.yzx); + else if (v1 == inPOS0) outBary = encodeBarycentrics(bary.zxy); + else if (v2 == inPOS0) outBary = encodeBarycentrics(bary.xyz); + #else + outBary = encodeBarycentrics(bary.xyz); + #endif +#endif +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/graph/base/instanced.vert.glsl b/bin/data/shaders - 1.2/graph/base/instanced.vert.glsl new file mode 100644 index 00000000..92cae145 --- /dev/null +++ b/bin/data/shaders - 1.2/graph/base/instanced.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 0 +#include "./vert.h" diff --git a/bin/data/shaders - 1.2/graph/base/skinned.instanced.vert.glsl b/bin/data/shaders - 1.2/graph/base/skinned.instanced.vert.glsl new file mode 100644 index 00000000..2bc9b86a --- /dev/null +++ b/bin/data/shaders - 1.2/graph/base/skinned.instanced.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 1 +#define SKINNED 1 +#include "./vert.h" diff --git a/bin/data/shaders - 1.2/graph/base/skinned.vert.glsl b/bin/data/shaders - 1.2/graph/base/skinned.vert.glsl new file mode 100644 index 00000000..96b6ba5a --- /dev/null +++ b/bin/data/shaders - 1.2/graph/base/skinned.vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 0 +#define SKINNED 1 +#include "./vert.h" diff --git a/bin/data/shaders - 1.2/graph/base/vert.glsl b/bin/data/shaders - 1.2/graph/base/vert.glsl new file mode 100644 index 00000000..701eee8d --- /dev/null +++ b/bin/data/shaders - 1.2/graph/base/vert.glsl @@ -0,0 +1,6 @@ +#version 450 +#pragma shader_stage(vertex) + +#define INSTANCED 0 +#define SKINNED 0 +#include "./vert.h" diff --git a/bin/data/shaders - 1.2/graph/base/vert.h b/bin/data/shaders - 1.2/graph/base/vert.h new file mode 100644 index 00000000..5aad74bf --- /dev/null +++ b/bin/data/shaders - 1.2/graph/base/vert.h @@ -0,0 +1,100 @@ +layout (constant_id = 0) const uint PASSES = 6; +#extension GL_ARB_shader_draw_parameters : enable + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec2 inUv; +layout (location = 2) in vec4 inColor; +layout (location = 3) in vec2 inSt; +layout (location = 4) in vec3 inNormal; +layout (location = 5) in vec4 inTangent; +layout (location = 6) in uvec2 inId; +#if SKINNED + layout (location = 7) in uvec4 inJoints; + layout (location = 8) in vec4 inWeights; +#endif + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +#if !BAKING +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; +#endif +layout (std140, binding = 1) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 2) readonly buffer Instances { + Instance instances[]; +}; + +#if SKINNED + layout (std140, binding = 3) readonly buffer Joints { + mat4 joints[]; + }; +#endif + +layout (location = 0) out uvec4 outId; +layout (location = 1) flat out vec4 outPOS0; +layout (location = 2) out vec4 outPOS1; +layout (location = 3) out vec3 outPosition; +layout (location = 4) out vec2 outUv; +layout (location = 5) out vec4 outColor; +layout (location = 6) out vec2 outSt; +layout (location = 7) out vec3 outNormal; +layout (location = 8) out vec3 outTangent; + +vec4 snap(vec4 vertex, vec2 resolution) { + vec4 snappedPos = vertex; + snappedPos.xyz = vertex.xyz / vertex.w; + snappedPos.xy = floor(resolution * snappedPos.xy) / resolution; + snappedPos.xyz *= vertex.w; + return snappedPos; +} + +void main() { + const uint drawID = gl_DrawIDARB; + const uint triangleID = gl_VertexIndex / 3; + const DrawCommand drawCommand = drawCommands[drawID]; + const uint instanceID = drawCommand.instanceID; // gl_InstanceIndex; + const Instance instance = instances[instanceID]; + const uint jointID = instance.jointID; + +#if BAKING + const mat4 view = mat4(1); + const mat4 projection = mat4(1); +#else + const mat4 view = camera.viewport[PushConstant.pass].view; + const mat4 projection = camera.viewport[PushConstant.pass].projection; +#endif +#if SKINNED + const mat4 skinned = joints.length() <= 0 || jointID < 0 ? mat4(1.0) : inWeights.x * joints[jointID + int(inJoints.x)] + inWeights.y * joints[jointID + int(inJoints.y)] + inWeights.z * joints[jointID + int(inJoints.z)] + inWeights.w * joints[jointID + int(inJoints.w)]; +#else + const mat4 skinned = mat4(1.0); +#endif +// const mat4 model = instances.length() <= 0 ? skinned : (instance.model * skinned); + const mat4 model = instance.model * skinned; + + +#if BAKING + gl_Position = vec4(inSt * 2.0 - 1.0, 0.0, 1.0); +#else + gl_Position = projection * view * model * vec4(inPos.xyz, 1.0); +#endif + outPOS0 = gl_Position; + outPOS1 = gl_Position; + + outId = uvec4(triangleID, drawID, instanceID, PushConstant.pass); + + outPosition = vec3(model * vec4(inPos.xyz, 1.0)); + outUv = inUv; + outSt = inSt; + outColor = inColor * instance.color; + outNormal = normalize(vec3(model * vec4(inNormal.xyz, 0.0))); + outTangent = normalize(vec3(view * model * vec4(inTangent.xyz, 0.0))); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/graph/cull/comp.glsl b/bin/data/shaders - 1.2/graph/cull/comp.glsl new file mode 100644 index 00000000..0b174a2b --- /dev/null +++ b/bin/data/shaders - 1.2/graph/cull/comp.glsl @@ -0,0 +1,369 @@ +#version 450 +#pragma shader_stage(compute) + +//#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_EXT_samplerless_texture_functions : enable + +layout (constant_id = 0) const uint PASSES = 6; +layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +#define COMPUTE 1 +#define QUERY_MIPMAPS 1 +#define DEPTH_BIAS 0.00005 + +#include "../../common/macros.h" +#include "../../common/structs.h" + +float mipLevels( vec2 size ) { + return floor(log2(max(size.x, size.y))); +} +float mipLevels( ivec2 size ) { + return floor(log2(max(size.x, size.y))); +} + +vec4 aabbToSphere( Bounds bounds ) { + vec4 sphere; + sphere.xyz = (bounds.max + bounds.min) * 0.5; + sphere.w = length((bounds.max - bounds.min) * 0.5); + return sphere; +} + +// 2D Polyhedral Bounds of a Clipped, Perspective-Projected 3D Sphere. Michael Mara, Morgan McGuire. 2013 +bool projectSphere(vec3 C, float r, float znear, float P00, float P11, out vec4 aabb) +{ + if (C.z < r + znear) + return false; + + vec2 cx = -C.xz; + vec2 vx = vec2(sqrt(dot(cx, cx) - r * r), r); + vec2 minx = mat2(vx.x, vx.y, -vx.y, vx.x) * cx; + vec2 maxx = mat2(vx.x, -vx.y, vx.y, vx.x) * cx; + + vec2 cy = -C.yz; + vec2 vy = vec2(sqrt(dot(cy, cy) - r * r), r); + vec2 miny = mat2(vy.x, vy.y, -vy.y, vy.x) * cy; + vec2 maxy = mat2(vy.x, -vy.y, vy.y, vy.x) * cy; + + aabb = vec4(minx.x / minx.y * P00, miny.x / miny.y * P11, maxx.x / maxx.y * P00, maxy.x / maxy.y * P11); + aabb = aabb.xwzy * vec4(0.5f, -0.5f, 0.5f, -0.5f) + vec4(0.5f); // clip space -> uv space + + return true; +} + +layout( push_constant ) uniform PushBlock { + uint pass; + uint passes; +} PushConstant; + +layout (binding = 0) uniform Camera { + Viewport viewport[PASSES]; +} camera; + +layout (std140, binding = 1) buffer DrawCommands { + DrawCommand drawCommands[]; +}; + +layout (std140, binding = 2) buffer Instances { + Instance instances[]; +}; + +layout (binding = 3) uniform sampler2D samplerDepth; + +struct Frustum { + vec4 planes[6]; +}; + +vec4 normalizePlane( vec4 p ) { + return p / length(p.xyz); +} + +bool frustumCull( uint id ) { + if ( PushConstant.passes == 0 ) return true; + + const DrawCommand drawCommand = drawCommands[id]; + const Instance instance = instances[drawCommand.instanceID]; + + bool visible = false; + for ( uint pass = 0; pass < PushConstant.passes; ++pass ) { +#if 0 + vec4 sphere = aabbToSphere( instance.bounds ); + vec3 center = vec3( camera.viewport[pass].view * instance.model * vec4( ) ); +#else + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + #if 1 + vec4 planes[6]; { + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + planes[i*2+j] = normalizePlane( planes[i*2+j] ); + } + } + for ( uint p = 0; p < 6; ++p ) { + float d = max(instance.bounds.min.x * planes[p].x, instance.bounds.max.x * planes[p].x) + + max(instance.bounds.min.y * planes[p].y, instance.bounds.max.y * planes[p].y) + + max(instance.bounds.min.z * planes[p].z, instance.bounds.max.z * planes[p].z); + if ( d > -planes[p].w ) return true; + } + #else + vec4 corners[8] = { + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ), + + vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ), + }; + vec4 planes[6]; { + #pragma unroll 3 + for (int i = 0; i < 3; ++i) + #pragma unroll 2 + for (int j = 0; j < 2; ++j) { + planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + planes[i*2+j] = normalizePlane( planes[i*2+j] ); + } + } + #pragma unroll 8 + for ( uint p = 0; p < 8; ++p ) corners[p] = mat * corners[p]; + #pragma unroll 6 + for ( uint p = 0; p < 6; ++p ) { + #pragma unroll 8 + for ( uint q = 0; q < 8; ++q ) { + if ( dot( corners[q], planes[p] ) > 0 ) return true; + } + return false; + } + #endif +#endif + } + return visible; +} + +bool occlusionCull( uint id ) { + if ( PushConstant.passes == 0 ) return true; + + const DrawCommand drawCommand = drawCommands[id]; + const Instance instance = instances[drawCommand.instanceID]; + + bool visible = true; + for ( uint pass = 0; pass < PushConstant.passes; ++pass ) { +#if 1 + vec4 aabb; + vec4 sphere = aabbToSphere( instance.bounds ); + vec3 center = (camera.viewport[pass].view * instance.model * vec4(sphere.xyz, 1)).xyz; + float radius = (instance.model * vec4(sphere.w, 0, 0, 0)).x; + // center.y *= -1; + mat4 proj = camera.viewport[pass].projection; + float znear = proj[3][2]; + float P00 = proj[0][0]; + float P11 = proj[1][1]; + if (projectSphere(center, radius, znear, P00, P11, aabb)) { + ivec2 pyramidSize = textureSize( samplerDepth, 0 ); + float mips = mipLevels( pyramidSize ); + + float width = (aabb.z - aabb.x) * pyramidSize.x; + float height = (aabb.w - aabb.y) * pyramidSize.y; + + //find the mipmap level that will match the screen size of the sphere + float level = floor(log2(max(width, height))); + // if ( level == mips ) + --level; + level = clamp( level, 0, mips ); + + //sample the depth pyramid at that specific level + float depth = textureLod(samplerDepth, (aabb.xy + aabb.zw) * 0.5, level).x; + + float depthSphere = znear / (center.z - radius); + + instances[drawCommand.instanceID].bounds.padding1 = depth; + instances[drawCommand.instanceID].bounds.padding2 = proj[3][2]; + + //if the depth of the sphere is in front of the depth pyramid value, then the object is visible + visible = visible && depthSphere >= depth - DEPTH_BIAS; + } + +#else + mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model; + vec3 boundsSize = instance.bounds.max - instance.bounds.min; + vec3 points[8] = { + instance.bounds.min.xyz, + instance.bounds.min.xyz + vec3(boundsSize.x,0,0), + instance.bounds.min.xyz + vec3(0, boundsSize.y,0), + instance.bounds.min.xyz + vec3(0, 0, boundsSize.z), + instance.bounds.min.xyz + vec3(boundsSize.xy,0), + instance.bounds.min.xyz + vec3(0, boundsSize.yz), + instance.bounds.min.xyz + vec3(boundsSize.x, 0, boundsSize.z), + instance.bounds.min.xyz + boundsSize.xyz, + }; + vec2 minXY = vec2(1); + vec2 maxXY = vec2(0); + + float minZ = 1; + float maxZ = 0; + + #pragma unroll 8 + for ( uint i = 0; i < 8; ++i ) { + vec4 clip = mat * vec4( points[i], 1 ); + clip.xyz /= clip.w; + clip.xy = clip.xy * 0.5 + 0.5; + + minXY.x = min(minXY.x, clip.x); + minXY.y = min(minXY.y, clip.y); + + maxXY.x = max(maxXY.x, clip.x); + maxXY.y = max(maxXY.y, clip.y); + + #if INVERSE + clip.z = 1.0 - clip.z; + maxZ = max(maxZ, clip.z); + #else + minZ = min(minZ, clip.z); + #endif + } + + if ( maxXY.x <= 0 || maxXY.y <= 0 ) return false; + if ( minXY.x >= 1 || minXY.y >= 1 ) return false; + + ivec2 depthSize = textureSize( samplerDepth, 0 ); + float mips = mipLevels( depthSize ); + + vec4 uv = vec4(minXY, maxXY); + + ivec2 clipSize = ivec2(maxXY - minXY) * depthSize; + float mip = mipLevels( clipSize ); + mip = clamp( mip, 0, mips ); + if ( mip == 0 ) { + mip = 1; + } else { + float lower = max(mip - 1, 0); + float scale = exp2(-lower); + vec2 a = floor(uv.xy * scale); + vec2 b = ceil(uv.zw * scale); + vec2 dims = b - a; + + // Use the lower level if we only touch <= 2 texels in both dimensions + if (dims.x <= 2 && dims.y <= 2) mip = lower; + } + + float depths[4] = { + textureLod( samplerDepth, uv.xy, mip ).r, + textureLod( samplerDepth, uv.zy, mip ).r, + textureLod( samplerDepth, uv.xw, mip ).r, + textureLod( samplerDepth, uv.zw, mip ).r, + }; + #if INVERSE + float minDepth = 1.0 - min(min(min(depths[0], depths[1]), depths[2]), depths[3]); + #else + float maxDepth = max(max(max(depths[0], depths[1]), depths[2]), depths[3]); + #endif + + instances[drawCommand.instanceID].bounds.padding1 = minZ; + instances[drawCommand.instanceID].bounds.padding2 = maxDepth; + + return minZ <= maxDepth; +#endif + } + return visible; +} + +void main() { + const uint gID = gl_GlobalInvocationID.x; + if ( !(0 <= gID && gID < drawCommands.length()) ) return; + + bool visible = frustumCull( gID ); +// if ( visible ) visible = occlusionCull( gID ); +// bool visible = occlusionCull( gID ); + drawCommands[gID].instances = visible ? 1 : 0; +} + + +/* + Frustum frustum; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 2; ++j) { + frustum.planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]); + frustum.planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]); + frustum.planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]); + frustum.planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]); + frustum.planes[i*2+j]*= length(frustum.planes[i*2+j].xyz); + } + for ( uint i = 0; i < 6; ++i ) { + vec4 plane = frustum.planes[i]; + float d = dot(instance.bounds.center, plane.xyz); + float r = dot(instance.bounds.extent, abs(plane.xyz)); + bool inside = d + r > -plane.w; + if ( !inside ) return 0; + } + return true; +*/ +/* + vec4 plane; + vec4 center = vec4( (max + min) * 0.5, 1 ); + vec4 extent = vec4( (max - min) * 0.5, 1 ); + center = mat * center; + extent = mat * extent; + center.xyz /= center.w; + extent.xyz /= extent.w; + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][0]; // left + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][0]; // right + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][1]; // bottom + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][1]; // top + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][2]; // near + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + + for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][2]; // far + visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w; + if ( visible ) return true; + +*/ +/* + for ( uint p = 0; p < 8; ++p ) { + vec4 t = corners[p]; + float w = abs(t.w); + visible = -w <= t.x && t.x <= w && -w <= t.y && t.y <= w && 0 <= t.z && t.z <= w; // && -w <= t.z && t.z <= w; + } +*/ +/* +mat4 convert( mat4 proj ) { + float f = -proj[1][1]; + float raidou = f / proj[0][0]; + float zNear = proj[3][2]; + float zFar = 32; + + float range = zNear - zFar; + + float Sx = f * raidou; + float Sy = f; + float Sz = (-zNear - zFar) / range; + float Pz = 2 * zFar * zNear / range; + + mat4 new = mat4(1.0); + new[0][0] = Sx; + new[1][1] = -Sy; + new[2][2] = Sz; + new[3][2] = Pz; + new[2][3] = 1; + return new; +} +*/ \ No newline at end of file diff --git a/bin/data/shaders - 1.2/graph/depth/frag.glsl b/bin/data/shaders - 1.2/graph/depth/frag.glsl new file mode 100644 index 00000000..79ed3c71 --- /dev/null +++ b/bin/data/shaders - 1.2/graph/depth/frag.glsl @@ -0,0 +1,73 @@ +#version 450 +#pragma shader_stage(fragment) + +#define FRAGMENT 1 +#define MAX_TEXTURES textures.length() + +layout (constant_id = 0) const uint TEXTURES = 1; + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 6) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 7) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 8) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 9) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 10) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 11) readonly buffer Lights { + Light lights[]; +}; + +#include "../../common/functions.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +void main() { + const uint triangleID = uint(inId.x); // gl_PrimitiveID + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + vec4 A = inColor * material.colorBase; + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + // alpha mode OPAQUE + if ( material.modeAlpha == 0 ) { + A.a = 1; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + if ( A.a < 1 ) discard; +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/graph/voxelize/frag.glsl b/bin/data/shaders - 1.2/graph/voxelize/frag.glsl new file mode 100644 index 00000000..3095eaec --- /dev/null +++ b/bin/data/shaders - 1.2/graph/voxelize/frag.glsl @@ -0,0 +1,142 @@ +#version 450 +#pragma shader_stage(fragment) + +// to-do: convert to use functions.h surface population functions + +#define FRAGMENT 1 +#define DEFERRED_SAMPLING 0 +#define CUBEMAPS 1 + +#define BLEND 1 +#define DEPTH_TEST 0 +#define USE_LIGHTMAP 1 +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CASCADES = 16; + +#define MAX_TEXTURES textures.length() +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES]; +layout (std140, binding = 6) readonly buffer DrawCommands { + DrawCommand drawCommands[]; +}; +layout (std140, binding = 7) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 8) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; + +layout (std140, binding = 9) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 10) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 11) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 12, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; +layout (binding = 13, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; +#if VXGI_HDR + layout (binding = 14, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#else + layout (binding = 14, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; +#endif +#if DEPTH_TEST + layout (binding = 15, r16f) uniform volatile coherent image3D voxelDepth[CASCADES]; +#endif + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +#include "../../common/functions.h" + +void main() { + const uint CASCADE = inId.w; + if ( CASCADES <= CASCADE ) discard; + const vec3 P = inPosition.xzy * 0.5 + 0.5; + if ( abs(P.x) > 1 || abs(P.y) > 1 || abs(P.z) > 1 ) discard; + + const uint triangleID = uint(inId.x); // gl_PrimitiveID + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + surface.st.xy = inSt; + surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt)); + + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + surface.instance = instance; + + vec4 A = material.colorBase; + float M = material.factorMetallic; + float R = material.factorRoughness; + float AO = material.factorOcclusion; + + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + // alpha mode OPAQUE + if ( material.modeAlpha == 0 ) { + A.a = 1; + // alpha mode BLEND + } else if ( material.modeAlpha == 1 ) { + + // alpha mode MASK + } else if ( material.modeAlpha == 2 ) { + if ( A.a < abs(material.factorAlphaCutoff) ) discard; + A.a = 1; + } + if ( A.a == 0 ) discard; + +#if USE_LIGHTMAP + if ( validTextureIndex( instance.lightmapID ) ) { + A.rgb *= sampleTexture( instance.lightmapID, inSt ).rgb; + } +#endif + + // sample normal + vec3 N = inNormal; + vec3 T = inTangent; + T = normalize(T - dot(T, N) * N); + vec3 B = cross(T, N); + mat3 TBN = mat3(T, B, N); +// mat3 TBN = mat3(N, B, T); + if ( T != vec3(0) && validTextureIndex( material.indexNormal ) ) { + N = TBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - 1.0 ); + } + + const ivec3 uvw = ivec3(P * imageSize(voxelRadiance[CASCADE])); + +#if DEPTH_TEST + const float outDepth = length(inPosition.xzy); + const float inDepth = imageLoad(voxelDepth[CASCADE], uvw).r; + if ( inDepth != 0 && inDepth < outDepth ) discard; + imageStore(voxelDepth[CASCADE], uvw, vec4(inDepth, 0, 0, 0)); +#endif + + imageStore(voxelId[CASCADE], uvw, uvec4(uvec2(drawID + 1, instanceID + 1), 0, 0)); + imageStore(voxelNormal[CASCADE], uvw, vec4(encodeNormals( normalize( N ) ), 0, 0)); +#if BLEND + // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA + const vec4 src = A * inColor; + const vec4 dst = imageLoad(voxelRadiance[CASCADE], uvw); + imageStore(voxelRadiance[CASCADE], uvw, blend( src, dst, src.a ) ); +#else + imageStore(voxelRadiance[CASCADE], uvw, A ); +#endif +} diff --git a/bin/data/shaders - 1.2/graph/voxelize/geom.glsl b/bin/data/shaders - 1.2/graph/voxelize/geom.glsl new file mode 100644 index 00000000..65259479 --- /dev/null +++ b/bin/data/shaders - 1.2/graph/voxelize/geom.glsl @@ -0,0 +1,93 @@ +#version 450 +#pragma shader_stage(geometry) + +layout(triangles) in; +layout(triangle_strip, max_vertices = 3) out; + +layout (location = 0) flat in uvec4 inId[]; +layout (location = 1) flat in vec4 inPOS0[]; +layout (location = 2) in vec4 inPOS1[]; +layout (location = 3) in vec3 inPosition[]; +layout (location = 4) in vec2 inUv[]; +layout (location = 5) in vec4 inColor[]; +layout (location = 6) in vec2 inSt[]; +layout (location = 7) in vec3 inNormal[]; +layout (location = 8) in vec3 inTangent[]; + +layout (location = 0) flat out uvec4 outId; +layout (location = 1) flat out vec4 outPOS0; +layout (location = 2) out vec4 outPOS1; +layout (location = 3) out vec3 outPosition; +layout (location = 4) out vec2 outUv; +layout (location = 5) out vec4 outColor; +layout (location = 6) out vec2 outSt; +layout (location = 7) out vec3 outNormal; +layout (location = 8) out vec3 outTangent; + +layout (binding = 4) uniform UBO { + mat4 voxel; + + float cascadePower; + float granularity; + float voxelizeScale; + float occlusionFalloff; + + uint shadows; + uint padding1; + uint padding2; + uint padding3; +} ubo; + +float cascadePower( uint x ) { + return pow(1 + x, ubo.cascadePower); +// return max( 1, x * ubo.cascadePower ); +} + +#define USE_CROSS 0 +void main(){ + const float HALF_PIXEL = ubo.voxelizeScale; + const vec3 C = ( inPosition[0] + inPosition[1] + inPosition[2] ) / 3.0; + +#if USE_CROSS + const vec3 N = abs(cross(inPosition[2] - inPosition[0], inPosition[1] - inPosition[0])); +#else + const vec3 N = abs(inNormal[0] + inNormal[1] + inNormal[2]); + uint A = N.y > N.x ? 1 : 0; + A = N.z > N[A] ? 2 : A; +#endif + + const uint CASCADE = inId[0].w; + vec3 P[3] = { + 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), + }; + + #pragma unroll 3 + for( uint i = 0; i < 3; ++i ){ + const vec3 D = normalize( inPosition[i] - C ) * HALF_PIXEL; + + outPosition = P[i] + D; + outPOS0 = inPOS0[i]; + outPOS1 = inPOS1[i]; + outUv = inUv[i]; + outSt = inSt[i]; + outColor = inColor[i]; + outNormal = inNormal[i]; + outTangent = inTangent[i]; + outId = inId[i]; + + const vec3 P = outPosition; // + D; + #if USE_CROSS + if ( N.z > N.x && N.z > N.y ) gl_Position = vec4(P.x, P.y, 0, 1); + else if ( N.x > N.y && N.x > N.z ) gl_Position = vec4(P.y, P.z, 0, 1); + else gl_Position = vec4(P.x, P.z, 0, 1); + #else + if ( A == 0 ) gl_Position = vec4(P.zy, 0, 1 ); + else if ( A == 1 ) gl_Position = vec4(P.xz, 0, 1 ); + else if ( A == 2 ) gl_Position = vec4(P.xy, 0, 1 ); + #endif + EmitVertex(); + } + EndPrimitive(); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/gui/base/frag.glsl b/bin/data/shaders - 1.2/gui/base/frag.glsl new file mode 100644 index 00000000..05f07fa7 --- /dev/null +++ b/bin/data/shaders - 1.2/gui/base/frag.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(fragment) + +#define GLYPH 0 +#include "../gui/frag.h" diff --git a/bin/data/shaders - 1.2/gui/base/vert.glsl b/bin/data/shaders - 1.2/gui/base/vert.glsl new file mode 100644 index 00000000..c6455702 --- /dev/null +++ b/bin/data/shaders - 1.2/gui/base/vert.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(vertex) + +#define GLYPH 0 +#include "../gui/vert.h" diff --git a/bin/data/shaders - 1.2/gui/gui/frag.h b/bin/data/shaders - 1.2/gui/gui/frag.h new file mode 100644 index 00000000..6343874d --- /dev/null +++ b/bin/data/shaders - 1.2/gui/gui/frag.h @@ -0,0 +1,45 @@ +#define TEXTURES 1 +#define CUBEMAPS 1 + +#include "../../common/macros.h" +#include "../../common/structs.h" +#include "../../common/functions.h" +#include "./gui.h" + +layout (binding = 1) uniform sampler2D samplerTexture; + +layout (location = 0) in vec2 inUv; +layout (location = 1) in flat Gui inGui; +layout (location = 7) in flat Glyph inGlyph; + +layout (location = 0) out vec4 outAlbedo; + +void main() { + if ( inUv.x < inGui.offset.x || inUv.y < inGui.offset.y || inUv.x > inGui.offset.z || inUv.y > inGui.offset.w ) discard; + + const vec2 uv = inUv.xy; + const float mip = mipLevel(dFdx(inUv), dFdy(inUv)); + vec4 C = inGui.color; +#if GLYPH + if ( enabled(inGui.mode, 1) ) { + outAlbedo = inGui.color; + return; + } + const float sampled = texture(samplerTexture, inUv).r; + if ( enabled(inGui.mode, 2) ) { + const float smoothing = ( inGlyph.spread > 0 && inGlyph.scale > 0 ) ? 0.25 / (inGlyph.spread * inGlyph.scale) : 0.25 / (4 * 1.5); + const float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, sampled); + const float alpha = smoothstep(inGlyph.weight - smoothing, inGlyph.weight + smoothing, sampled); + if ( alpha < 0.001 || alpha > 1 ) discard; + C = mix(inGlyph.stroke, inGui.color, outlining); + C.a = inGui.color.a * alpha; + } else { + if ( sampled < 0.001 || sampled > 1 ) discard; + C *= sampled; + } +#else + if ( enabled(inGui.mode, 0) ) C = inGui.color; + else C *= textureLod( samplerTexture, uv, mip ); +#endif + outAlbedo = C; +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/gui/gui/gui.h b/bin/data/shaders - 1.2/gui/gui/gui.h new file mode 100644 index 00000000..6a06ac56 --- /dev/null +++ b/bin/data/shaders - 1.2/gui/gui/gui.h @@ -0,0 +1,18 @@ +struct Gui { + vec4 offset; + vec4 color; + + int mode; + float depth; + float padding1; + float padding2; +}; + +struct Glyph { + vec4 stroke; + + int spread; + float weight; + float scale; + float padding; +}; \ No newline at end of file diff --git a/bin/data/shaders - 1.2/gui/gui/vert.h b/bin/data/shaders - 1.2/gui/gui/vert.h new file mode 100644 index 00000000..63ac1c3b --- /dev/null +++ b/bin/data/shaders - 1.2/gui/gui/vert.h @@ -0,0 +1,37 @@ +layout (constant_id = 0) const uint PASSES = 6; +layout (location = 0) in vec2 inPos; +layout (location = 1) in vec2 inUv; + +#include "./gui.h" + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +struct Matrices { + mat4 model[PASSES]; +}; +layout (binding = 0) uniform UBO { + Matrices matrices; + Gui gui; +#if GLYPH + Glyph glyph; +#endif +} ubo; + +layout (location = 0) out vec2 outUv; +layout (location = 1) out flat Gui outGui; +#if GLYPH + layout (location = 7) out flat Glyph outGlyph; +#endif + +void main() { + outUv = inUv; + outGui = ubo.gui; +#if GLYPH + outGlyph = ubo.glyph; +#endif + + gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, ubo.gui.depth, 1.0); +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/gui/text/frag.glsl b/bin/data/shaders - 1.2/gui/text/frag.glsl new file mode 100644 index 00000000..506229e8 --- /dev/null +++ b/bin/data/shaders - 1.2/gui/text/frag.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(fragment) + +#define GLYPH 1 +#include "../gui/frag.h" diff --git a/bin/data/shaders - 1.2/gui/text/vert.glsl b/bin/data/shaders - 1.2/gui/text/vert.glsl new file mode 100644 index 00000000..60465aaa --- /dev/null +++ b/bin/data/shaders - 1.2/gui/text/vert.glsl @@ -0,0 +1,5 @@ +#version 450 +#pragma shader_stage(vertex) + +#define GLYPH 1 +#include "../gui/vert.h" diff --git a/bin/data/shaders - 1.2/raytrace/shader.ray-gen.glsl b/bin/data/shaders - 1.2/raytrace/shader.ray-gen.glsl new file mode 100644 index 00000000..40eca388 --- /dev/null +++ b/bin/data/shaders - 1.2/raytrace/shader.ray-gen.glsl @@ -0,0 +1,401 @@ +#version 460 + +#extension GL_EXT_ray_tracing : enable +#extension GL_ARB_shader_clock : enable + +#pragma shader_stage(raygen) +layout (constant_id = 0) const uint PASSES = 2; +layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 2) const uint CUBEMAPS = 8; +layout (constant_id = 3) const uint CASCADES = 1; + +// shader type settings +#define RT 1 +#define DEFERRED_SAMPLING 1 +#define BUFFER_REFERENCE 1 +#define UINT64_ENABLED 1 +#define PBR 1 +// shader function settings +#define FOG 1 + +//force it off +#define BARYCENTRIC 0 +#define BARYCENTRIC_CALCULATE 0 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout( push_constant ) uniform PushBlock { + uint pass; + uint draw; +} PushConstant; + +layout (binding = 0) uniform accelerationStructureEXT tlas; + +layout (binding = 1, rgba32f) uniform volatile coherent image2D outImage; + +layout (binding = 2) uniform UBO { + EyeMatrices eyes[2]; + + Settings settings; +} ubo; + +layout (std140, binding = 3) readonly buffer Instances { + Instance instances[]; +}; +layout (std140, binding = 4) readonly buffer InstanceAddresseses { + InstanceAddresses instanceAddresses[]; +}; +layout (std140, binding = 5) readonly buffer Materials { + Material materials[]; +}; +layout (std140, binding = 6) readonly buffer Textures { + Texture textures[]; +}; +layout (std140, binding = 7) readonly buffer Lights { + Light lights[]; +}; + +layout (binding = 8) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 9) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 10) uniform sampler3D samplerNoise; +#if VXGI + layout (binding = 11) uniform usampler3D voxelId[CASCADES]; + layout (binding = 12) uniform sampler3D voxelNormal[CASCADES]; + layout (binding = 13) uniform sampler3D voxelRadiance[CASCADES]; +#endif + +layout (location = 0) rayPayloadEXT RayTracePayload payload; + +layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; +layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; +layout(buffer_reference, scalar) buffer Indirects { DrawCommand dc[]; }; + +layout(buffer_reference, scalar) buffer VPos { vec3 v[]; }; +layout(buffer_reference, scalar) buffer VUv { vec2 v[]; }; +layout(buffer_reference, scalar) buffer VColor { uint v[]; }; +layout(buffer_reference, scalar) buffer VSt { vec2 v[]; }; +layout(buffer_reference, scalar) buffer VNormal { vec3 v[]; }; +layout(buffer_reference, scalar) buffer VTangent { vec3 v[]; }; +layout(buffer_reference, scalar) buffer VID { uint v[]; }; + +#include "../common/functions.h" +#include "../common/light.h" +#include "../common/fog.h" +#if VXGI + #include "../common/vxgi.h" +#endif + +void trace( Ray ray, float tMin, float tMax ) { + uint rayFlags = gl_RayFlagsOpaqueEXT; + uint cullMask = 0xFF; + + payload.hit = false; + surface.position.eye.z = tMax; + traceRayEXT(tlas, rayFlags, cullMask, 0, 0, 0, ray.origin, tMin, ray.direction, tMax, 0); +} +void trace( Ray ray, float tMin ) { + uint rayFlags = gl_RayFlagsOpaqueEXT; + uint cullMask = 0xFF; + + float tMax = ubo.settings.rt.defaultRayBounds.y; + + payload.hit = false; + surface.position.eye.z = tMax; + traceRayEXT(tlas, rayFlags, cullMask, 0, 0, 0, ray.origin, tMin, ray.direction, tMax, 0); +} + +void trace( Ray ray ) { + trace( ray, ubo.settings.rt.defaultRayBounds.x, ubo.settings.rt.defaultRayBounds.y ); +} + +float shadowFactor( const Light light, float def ) { + Ray ray; + ray.origin = surface.position.world; + ray.direction = light.position - ray.origin; + + float tMin = ubo.settings.rt.defaultRayBounds.x; + float tMax = length(ray.direction) - 0.0001; + + ray.direction = normalize(ray.direction); + + uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT; + uint cullMask = 0xFF; + + payload.hit = true; + traceRayEXT(tlas, rayFlags, cullMask, 0, 0, 0, ray.origin, tMin, ray.direction, tMax, 0); + + return payload.hit ? 0.0 : 1.0; +} + +void directLighting() { +#if VXGI + indirectLighting(); +#endif + + surface.light.rgb += surface.material.albedo.rgb * ubo.settings.lighting.ambient.rgb * surface.material.occlusion; // add ambient lighting + surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting +#if PBR + pbr(); +#elif LAMBERT + lambert(); +#elif PHONG + phong(); +#endif + surface.fragment.rgb += surface.light.rgb; + surface.fragment.a = surface.material.albedo.a; +} + +vec4 traceStep( Ray ray ) { + Ray fogRay = ray; + float eyeDepth = 0; + vec4 outFrag = vec4(0); + + // initial condition + { + trace( ray ); + + if ( payload.hit ) { + populateSurface( payload ); + directLighting(); + } else if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], ray.direction ); + surface.fragment.a = 4096; + surface.position.eye.z /= 8; + } else { + surface.fragment = vec4(ubo.settings.lighting.ambient.rgb, 0.5); + } + #if FOG + fog( ray, surface.fragment.rgb, surface.fragment.a ); + #endif + outFrag = surface.fragment; + eyeDepth = surface.position.eye.z; + } + + + // "transparency" + if ( payload.hit && surface.material.albedo.a < 0.999 ) { + const vec4 TRANSPARENCY_COLOR = vec4(1.0 - surface.material.albedo.a); + + if ( surface.material.albedo.a < 0.001 ) outFrag = vec4(0); + + RayTracePayload surfacePayload = payload; + Ray transparency; + transparency.direction = ray.direction; + transparency.origin = surface.position.world; + fogRay = transparency; + + trace( transparency, ubo.settings.rt.alphaTestOffset ); + if ( payload.hit ) { + populateSurface( payload ); + directLighting(); + } else if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], ray.direction ); + surface.fragment.a = 4096; + surface.position.eye.z /= 8; + } + #if FOG + fog( transparency, surface.fragment.rgb, surface.fragment.a ); + #endif + outFrag += TRANSPARENCY_COLOR * surface.fragment; + eyeDepth = surface.position.eye.z; + + payload = surfacePayload; + populateSurface( payload ); + } +#if FOG + { + // surface.position.eye.z = eyeDepth; + // fog( fogRay, outFrag.rgb, outFrag.a ); + // fog( ray, surface.fragment.rgb, surface.fragment.a ); + } +#endif + + // reflection + if ( payload.hit ) { + const float REFLECTIVITY = 1.0 - surface.material.roughness; + const vec4 REFLECTED_ALBEDO = surface.material.albedo * REFLECTIVITY; + + if ( REFLECTIVITY > 0.001 ) { + RayTracePayload surfacePayload = payload; + + Ray reflection; + reflection.origin = surface.position.world; + reflection.direction = reflect( ray.direction, surface.normal.world ); + + trace( reflection ); + + if ( payload.hit ) { + populateSurface( payload ); + directLighting(); + } else if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], reflection.direction ); + surface.fragment.a = 4096; + } + #if FOG + fog( reflection, surface.fragment.rgb, surface.fragment.a ); + #endif + outFrag += REFLECTED_ALBEDO * surface.fragment; + + payload = surfacePayload; + populateSurface( payload ); + } + } + + return outFrag; +} + +void main() { +// if ( ubo.settings.mode.frameNumber > 16 ) return; +// prngSeed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, ubo.settings.mode.frameNumber); + prngSeed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, int(clockARB())); + surface.pass = PushConstant.pass; + surface.subID = 0; + vec4 outFrag = vec4(0); + + const uint SAMPLES = min(ubo.settings.rt.samples, 4); + const uint NUM_PATHS = min(ubo.settings.rt.paths, 8); +#if 1 + const uint FRAME_ACCUMULATION_VALUE = ubo.settings.rt.frameAccumulationMinimum > 0 ? min(ubo.settings.rt.frameAccumulationMinimum, ubo.settings.mode.frameNumber + 1) : ubo.settings.mode.frameNumber + 1; +#else + const uint FRAME_ACCUMULATION_VALUE = min(32, ubo.settings.mode.frameNumber + 1); +#endif + const float BLEND_FACTOR = 1.0f / float(FRAME_ACCUMULATION_VALUE); + uint FRAME_NUMBER = ubo.settings.mode.frameNumber; + +#if 0 + for ( uint samp = 0; samp < SAMPLES; ++samp, ++FRAME_NUMBER ) { + { + const vec2 center = ( FRAME_NUMBER > 0 ) ? vec2( rnd(), rnd() ) : vec2(0.5); + const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + center) / vec2(gl_LaunchSizeEXT.xy); + #if 1 + vec4 target = ubo.eyes[surface.pass].iProjection * vec4(inUv.x * 2.0f - 1.0f, inUv.y * 2.0f - 1.0f, 1, 1); + vec4 direction = ubo.eyes[surface.pass].iView * vec4(normalize(target.xyz), 0); + + surface.ray.direction = vec3(direction); + surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; + #else + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + 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.eyes[surface.pass].eyePos.xyz; + #endif + } + + { + vec4 curValue = vec4(0); + vec4 curWeight = vec4(1); + for ( uint path = 0; path < NUM_PATHS; ++path ) { + vec4 stepValue = traceStep( surface.ray ); + curValue += stepValue * curWeight; + + if ( !payload.hit ) break; + + surface.ray.origin = surface.position.world; + surface.ray.direction = samplingHemisphere( prngSeed, surface.normal.world ); + curWeight *= surface.material.albedo * dot( surface.ray.direction, surface.normal.world ); + + if ( length(curWeight) < 0.01 ) break; + } + outFrag += curValue; + } + } + { + outFrag /= SAMPLES; + } +#elif 0 + { + const vec2 center = ( FRAME_NUMBER > 0 ) ? vec2( rnd(), rnd() ) : vec2(0.5); + const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + center) / vec2(gl_LaunchSizeEXT.xy); + #if 0 + vec4 target = ubo.eyes[surface.pass].iProjection * vec4(inUv.x * 2.0f - 1.0f, inUv.y * 2.0f - 1.0f, 1, 1); + vec4 direction = ubo.eyes[surface.pass].iView * vec4(normalize(target.xyz), 0); + + surface.ray.direction = vec3(direction); + surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; + #else + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + 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.eyes[surface.pass].eyePos.xyz; + #endif + } + + { + vec4 curValue = vec4(0); + vec4 curWeight = vec4(1); + for ( uint path = 0; path < NUM_PATHS; ++path ) { + vec4 stepValue = traceStep( surface.ray ); + curValue += stepValue * curWeight; + + if ( !payload.hit ) break; + + surface.ray.origin = surface.position.world; + surface.ray.direction = samplingHemisphere( prngSeed, surface.normal.world ); + curWeight *= surface.material.albedo * dot( surface.ray.direction, surface.normal.world ); + + if ( length(curWeight) < 0.01 ) break; + } + outFrag += curValue; + } + { + surface.fragment = outFrag; + } +#else + { + const vec2 center = ( FRAME_NUMBER > 0 ) ? vec2( rnd(), rnd() ) : vec2(0.5); + const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + center) / vec2(gl_LaunchSizeEXT.xy); + #if 0 + vec4 target = ubo.eyes[surface.pass].iProjection * vec4(inUv.x * 2.0f - 1.0f, inUv.y * 2.0f - 1.0f, 1, 1); + vec4 direction = ubo.eyes[surface.pass].iView * vec4(normalize(target.xyz), 0); + + surface.ray.direction = vec3(direction); + surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; + #else + const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); + 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.eyes[surface.pass].eyePos.xyz; + #endif + } + { + surface.fragment = traceStep( surface.ray ); + } +#endif + { + #if BLOOM + float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); + vec4 outFragBright = brightness > ubo.threshold ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); + // imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), outFragBright); + #endif + #if FOG + fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); + #endif + } + + { + outFrag = surface.fragment; + outFrag.a = 1; + } + + if ( ubo.settings.mode.frameNumber == 0 ) { + imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), outFrag); + } else { + // if ( length(outFrag.rgb) < 0.01f ) return; + vec4 blended = mix(imageLoad(outImage, ivec2(gl_LaunchIDEXT.xy)), outFrag, BLEND_FACTOR); + + imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), blended); + } +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/raytrace/shader.ray-hit-any.glsl b/bin/data/shaders - 1.2/raytrace/shader.ray-hit-any.glsl new file mode 100644 index 00000000..20cca3ed --- /dev/null +++ b/bin/data/shaders - 1.2/raytrace/shader.ray-hit-any.glsl @@ -0,0 +1,28 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_EXT_buffer_reference : enable +#extension GL_EXT_buffer_reference2 : enable +#extension GL_EXT_scalar_block_layout : enable +#pragma shader_stage(anyhit) +layout (constant_id = 0) const uint PASSES = 2; +layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 2) const uint CUBEMAPS = 128; + +#define RT 1 +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout(location = 0) rayPayloadInEXT RayTracePayload payload; + +hitAttributeEXT vec2 attribs; + +void main() { + payload.hit = true; + payload.instanceID = gl_InstanceCustomIndexEXT; + payload.primitiveID = gl_PrimitiveID; + payload.attributes = attribs; + +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/raytrace/shader.ray-hit-closest.glsl b/bin/data/shaders - 1.2/raytrace/shader.ray-hit-closest.glsl new file mode 100644 index 00000000..d8aec3a6 --- /dev/null +++ b/bin/data/shaders - 1.2/raytrace/shader.ray-hit-closest.glsl @@ -0,0 +1,25 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_nonuniform_qualifier : enable + +#pragma shader_stage(closest) +layout (constant_id = 0) const uint PASSES = 2; +layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 2) const uint CUBEMAPS = 128; + +#define RT 1 +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout(location = 0) rayPayloadInEXT RayTracePayload payload; + +hitAttributeEXT vec2 attribs; + +void main() { + payload.hit = true; + payload.instanceID = gl_InstanceCustomIndexEXT; + payload.primitiveID = gl_PrimitiveID; + payload.attributes = attribs; +} \ No newline at end of file diff --git a/bin/data/shaders - 1.2/raytrace/shader.ray-miss.glsl b/bin/data/shaders - 1.2/raytrace/shader.ray-miss.glsl new file mode 100644 index 00000000..49d0a1e5 --- /dev/null +++ b/bin/data/shaders - 1.2/raytrace/shader.ray-miss.glsl @@ -0,0 +1,15 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#pragma shader_stage(miss) + +#define RT 1 +#define COMPUTE 1 + +#include "../common/macros.h" +#include "../common/structs.h" + +layout(location = 0) rayPayloadInEXT RayTracePayload payload; + +void main() { + payload.hit = false; +} \ No newline at end of file diff --git a/bin/data/shaders/common/functions.h b/bin/data/shaders/common/functions.h index 0253f128..45b85f9f 100644 --- a/bin/data/shaders/common/functions.h +++ b/bin/data/shaders/common/functions.h @@ -250,10 +250,10 @@ void populateSurfaceMaterial() { } // Lightmap - if ( (surface.subID++ > 0 || bool(ubo.settings.lighting.useLightmaps)) && validTextureIndex( surface.instance.lightmapID ) ) { + if ( (/*surface.subID++ > 0 ||*/ bool(ubo.settings.lighting.useLightmaps)) && validTextureIndex( surface.instance.lightmapID ) ) { vec4 light = sampleTexture( surface.instance.lightmapID, surface.st ); - surface.material.lightmapped = light.a > 0.001; - if ( surface.material.lightmapped ) surface.light += surface.material.albedo * light; + /*surface.material.lightmapped = light.a > 0.000000001; + if ( surface.material.lightmapped )*/ surface.light += surface.material.albedo * light; } else { surface.material.lightmapped = false; } @@ -290,6 +290,7 @@ bool isValidAddress( uint64_t address ) { #endif } +#if BUFFER_REFERENCE void populateSurface( InstanceAddresses instanceAddresses, uvec3 indices ) { Triangle triangle; Vertex points[3]; @@ -414,4 +415,5 @@ void populateSurface( RayTracePayload payload ) { surface.barycentric = decodeBarycentrics(payload.attributes); populateSurface( payload.instanceID, payload.primitiveID ); } +#endif #endif \ No newline at end of file diff --git a/bin/data/shaders/common/lambert.h b/bin/data/shaders/common/lambert.h index a70a2920..eed6391e 100644 --- a/bin/data/shaders/common/lambert.h +++ b/bin/data/shaders/common/lambert.h @@ -1,27 +1,66 @@ float shadowFactor( const Light light, float def ); void lambert() { - const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); - const vec3 Lo = normalize( -surface.position.world ); - const float cosLo = max(0.0, dot(surface.normal.world, Lo)); - for ( uint i = 0; i < lights.length(); ++i ) { - const Light light = lights[i]; - if ( light.power <= LIGHT_POWER_CUTOFF ) continue; - const vec3 Lp = light.position; - // const vec3 Liu = light.position - surface.position.world; - const vec3 Liu = vec3(ubo.eyes[surface.pass].view * vec4(light.position, 1)) - surface.position.eye; - const float La = 1.0 / (PI * pow(length(Liu), 2.0)); - const float Ls = shadowFactor( light, 0.0 ); - if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; + // outcoming light from surface to eye + const vec3 Lo = normalize( -surface.position.eye ); + // angle of outcoming light + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); - const vec3 Li = normalize(Liu); - const vec3 Lr = light.color.rgb * light.power * La * Ls; - // const float cosLi = abs(dot(surface.normal.world, Li)); + for ( uint i = 0, shadows = 0; i < MAX_LIGHTS; ++i ) { + #if BAKING + // skip if surface is a dynamic light, we aren't baking dynamic lights + if ( lights[i].type < 0 ) continue; + #else + // skip if surface is already baked, and this isn't a dynamic light + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + #endif + if ( lights[i].power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + + vec3 Li = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + // magnitude of incoming light vector (for inverse-square attenuation) + const float Lmagnitude = dot(Li, Li); + // distance incoming light travels (reuse from above) + const float Ldistance = sqrt(Lmagnitude); + // "free" normalization, since we need to compute the above values anyways + Li = Li / Ldistance; + // attenuation factor + // const float Lattenuation = 1.0 / (1 + (PI * Lmagnitude)); + const float Lattenuation = 1.0 / (1 + Lmagnitude); + // skip if attenuation factor is too low + // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; + // ray cast if our surface is occluded from the light + const float Lshadow = 1; // ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // skip if our shadow factor is too low + if ( Lshadow <= LIGHT_POWER_CUTOFF ) continue; + // light radiance + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // skip if our radiance is too low + // if ( Lr <= LIGHT_POWER_CUTOFF ) continue; + // halfway vector + const vec3 Lh = normalize(Li + Lo); + // angle of incoming light const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + // angle of halfway light vector + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); +/* + const vec3 Liu = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + const vec3 Li = normalize(Liu); + // const float Lattenuation = 1.0 / (PI * pow(length(Liu), 2.0)); + // const float Lattenuation = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + const float Lattenuation = 1.0 / (1 + pow(length(Liu), 2.0)); + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + if ( lights[i].power * Lattenuation * Lshadow <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + // const vec3 Lh = normalize(Li + Lo); + // const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); +*/ const vec3 diffuse = surface.material.albedo.rgb; const vec3 specular = vec3(0); surface.light.rgb += (diffuse + specular) * Lr * cosLi; - surface.light.a += light.power * La * Ls; + surface.light.a += lights[i].power * Lattenuation * Lshadow; } } \ No newline at end of file diff --git a/bin/data/shaders/common/macros.h b/bin/data/shaders/common/macros.h index 909ca56b..03e97e50 100644 --- a/bin/data/shaders/common/macros.h +++ b/bin/data/shaders/common/macros.h @@ -99,4 +99,6 @@ const float EPSILON = 0.00001; const float SQRT2 = 1.41421356237; const float LIGHT_POWER_CUTOFF = 0.0005; -const float LIGHTMAP_GAMMA = 1.0; \ No newline at end of file +const float LIGHTMAP_GAMMA = 1.0; + +#define SETTINGS_TYPE_FULLBRIGHT 0x10 \ No newline at end of file diff --git a/bin/data/shaders/common/pbr.h b/bin/data/shaders/common/pbr.h index 7e22f3c8..a9896c54 100644 --- a/bin/data/shaders/common/pbr.h +++ b/bin/data/shaders/common/pbr.h @@ -19,8 +19,24 @@ void pbr() { // skip if surface is already baked, and this isn't a dynamic light if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; #endif + /* // skip if light power is too low if ( lights[i].power <= LIGHT_POWER_CUTOFF ) continue; + if ( surface.material.lightmapped && lights[i].type >= 0 ) continue; + + const vec3 Liu = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; + const vec3 Li = normalize(Liu); + const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + // const float Lattenuation = 1.0 / (PI * pow(length(Liu), 2.0)); + // const float Lattenuation = 1.0 / (1 + (PI * pow(length(Liu), 2.0))); + const float Lattenuation = 1.0 / (1 + pow(length(Liu), 2.0)); + if ( lights[i].power * Lattenuation * Lshadow <= LIGHT_POWER_CUTOFF ) continue; + + const float cosLi = max(0.0, dot(surface.normal.eye, Li)); + const vec3 Lr = lights[i].color.rgb * lights[i].power * Lattenuation * Lshadow; + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); + */ // incoming light to surface (non-const to normalize it later) // vec3 Li = lights[i].position - surface.position.world; vec3 Li = vec3(VIEW_MATRIX * vec4(lights[i].position, 1)) - surface.position.eye; @@ -34,7 +50,7 @@ void pbr() { // const float Lattenuation = 1.0 / (1 + (PI * Lmagnitude)); const float Lattenuation = 1.0 / (1 + Lmagnitude); // skip if attenuation factor is too low - if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; + // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; // ray cast if our surface is occluded from the light const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; // skip if our shadow factor is too low @@ -49,6 +65,7 @@ void pbr() { const float cosLi = max(0.0, dot(surface.normal.eye, Li)); // angle of halfway light vector const float cosLh = max(0.0, dot(surface.normal.eye, Lh)); + // Fresnel term for direct lighting const vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, Lo))); // Distribution for specular lighting diff --git a/bin/data/shaders/display/deferred/comp/comp.h b/bin/data/shaders/display/deferred/comp/comp.h index c9ab5189..6a275e18 100644 --- a/bin/data/shaders/display/deferred/comp/comp.h +++ b/bin/data/shaders/display/deferred/comp/comp.h @@ -6,15 +6,18 @@ #extension GL_EXT_ray_query : enable #endif -layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; #define COMPUTE 1 #define DEFERRED 1 #define DEFERRED_SAMPLING 1 #define PBR 1 -#define BUFFER_REFERENCE 1 -#define UINT64_ENABLED 1 +#define LAMBERT 0 +#if RT || BARYCENTRIC + #define BUFFER_REFERENCE 0 + #define UINT64_ENABLED 0 +#endif #define FOG 1 #define FOG_RAY_MARCH 1 @@ -100,17 +103,19 @@ layout (binding = 19) uniform sampler3D samplerNoise; layout (binding = 23) uniform accelerationStructureEXT tlas; #endif -layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; -layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; -layout(buffer_reference, scalar) buffer Indirects { DrawCommand dc[]; }; +#if BUFFER_REFERENCE + layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; }; + layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; }; + layout(buffer_reference, scalar) buffer Indirects { DrawCommand dc[]; }; -layout(buffer_reference, scalar) buffer VPos { vec3 v[]; }; -layout(buffer_reference, scalar) buffer VUv { vec2 v[]; }; -layout(buffer_reference, scalar) buffer VColor { uint v[]; }; -layout(buffer_reference, scalar) buffer VSt { vec2 v[]; }; -layout(buffer_reference, scalar) buffer VNormal { vec3 v[]; }; -layout(buffer_reference, scalar) buffer VTangent { vec3 v[]; }; -layout(buffer_reference, scalar) buffer VID { uint v[]; }; + layout(buffer_reference, scalar) buffer VPos { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VUv { vec2 v[]; }; + layout(buffer_reference, scalar) buffer VColor { uint v[]; }; + layout(buffer_reference, scalar) buffer VSt { vec2 v[]; }; + layout(buffer_reference, scalar) buffer VNormal { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VTangent { vec3 v[]; }; + layout(buffer_reference, scalar) buffer VID { uint v[]; }; +#endif #include "../../../common/functions.h" #include "../../../common/fog.h" @@ -128,7 +133,14 @@ layout(buffer_reference, scalar) buffer VID { uint v[]; }; #define IMAGE_STORE(X, Y) imageStore( X, ivec2(gl_GlobalInvocationID.xy), Y ) +bool USE_SKYBOX_ON_DIVERGENCE = false; + void postProcess() { + if ( USE_SKYBOX_ON_DIVERGENCE ) { + if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { + surface.fragment.rgb = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], surface.ray.direction ).rgb; + } + } #if FOG fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); #endif @@ -138,6 +150,26 @@ void postProcess() { vec4 outFragColor = vec4(surface.fragment.rgb, 1.0); vec4 outFragBright = bloom ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); vec2 outFragMotion = surface.motion; + + if ( ubo.settings.mode.type > 0x0000 ) { + uvec2 renderSize = imageSize(imageColor); + vec2 inUv = (vec2(gl_GlobalInvocationID.xy) / vec2(renderSize)) * 2.0f - 1.0f; + if ( inUv.x < 0 ) { + if ( ubo.settings.mode.type == 0x0001 ) { + outFragColor = vec4(surface.material.albedo.rgb, 1); + } else if ( ubo.settings.mode.type == 0x0002 ) { + outFragColor = vec4(surface.light.rgb, 1); + } else if ( ubo.settings.mode.type == 0x0003 ) { + outFragColor = vec4(surface.light.a, surface.light.a, surface.light.a, 1); + } else if ( ubo.settings.mode.type == 0x0004 ) { + outFragColor = vec4(surface.normal.eye.rgb, 1); + } else if ( ubo.settings.mode.type == 0x0005 ) { + outFragColor = vec4(surface.uv.xy, 0, 1); + } else if ( ubo.settings.mode.type == 0x0006 ) { + outFragColor = vec4(surface.st.xy, 0, 1); + } + } + } IMAGE_STORE( imageColor, outFragColor ); IMAGE_STORE( imageBright, outFragBright ); @@ -145,12 +177,16 @@ void postProcess() { } void populateSurface() { - uvec2 renderSize = imageSize(imageColor); + const uvec2 renderSize = imageSize(imageColor); if ( gl_GlobalInvocationID.x >= renderSize.x || gl_GlobalInvocationID.y >= renderSize.y || gl_GlobalInvocationID.z > PushConstant.pass ) return; - surface.fragment = vec4(0); surface.pass = PushConstant.pass; + surface.fragment = vec4(0); + surface.light = vec4(0); + surface.motion = vec2(0); + surface.material.indirect = vec4(0); + float depth = 0.0; { vec2 inUv = (vec2(gl_GlobalInvocationID.xy) / vec2(renderSize)) * 2.0f - 1.0f; const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) ); @@ -162,7 +198,7 @@ void populateSurface() { surface.ray.direction = normalize( far3 - near3 ); surface.ray.origin = /*near3.xyz;*/ ubo.eyes[surface.pass].eyePos.xyz; - const float depth = IMAGE_LOAD(samplerDepth).r; + depth = IMAGE_LOAD(samplerDepth).r; vec4 eye = ubo.eyes[surface.pass].iProjection * vec4(inUv, depth, 1.0); eye /= eye.w; @@ -171,23 +207,27 @@ void populateSurface() { surface.position.world = vec3( ubo.eyes[surface.pass].iView * eye ); } + #if !MULTISAMPLING const uvec2 ID = uvec2(IMAGE_LOAD(samplerId).xy); #else const uvec2 ID = msaa.IDs[msaa.currentID]; #endif - surface.motion = vec2(0); - if ( ID.x == 0 || ID.y == 0 ) { + if ( ID.x == 0 || ID.y == 0 || depth <= 0.0 ) { + USE_SKYBOX_ON_DIVERGENCE = true; + } +/* + if ( ID.x == 0 || ID.y == 0 || depth <= 0.0 ) { if ( 0 <= ubo.settings.lighting.indexSkybox && ubo.settings.lighting.indexSkybox < CUBEMAPS ) { surface.fragment.rgb = texture( samplerCubemaps[ubo.settings.lighting.indexSkybox], surface.ray.direction ).rgb; } - surface.fragment.a = 0.0; return; } +*/ { - const uint triangleID = ID.x - 1; - const uint instanceID = ID.y - 1; + const uint triangleID = ID.x == 0 ? 0 : ID.x - 1; + const uint instanceID = ID.y == 0 ? 0 : ID.y - 1; surface.subID = 1; #if BARYCENTRIC @@ -206,9 +246,7 @@ void populateSurface() { surface.normal.world = decodeNormals(normaltangent.xy); // surface.tangent.world = decodeNormals(normaltangent.zw); - - surface.fragment = vec4(0); - surface.light = vec4(0); + surface.instance = instances[instanceID]; populateSurfaceMaterial(); @@ -235,6 +273,7 @@ void directLighting() { #elif PHONG phong(); #endif + surface.fragment.rgb += surface.light.rgb; } diff --git a/bin/data/shaders/display/vxgi/comp.glsl b/bin/data/shaders/display/vxgi/comp.glsl index 9d44d570..571d2812 100644 --- a/bin/data/shaders/display/vxgi/comp.glsl +++ b/bin/data/shaders/display/vxgi/comp.glsl @@ -70,12 +70,17 @@ void main() { surface.position.world = vec3( inverse(ubo.settings.vxgi.matrix) * vec4( surface.position.eye, 1.0f ) ); const uvec2 ID = uvec2(imageLoad(voxelId[CASCADE], ivec3(tUvw) ).xy); - const uint drawID = ID.x - 1; - const uint instanceID = ID.y - 1; + const bool DISCARD_DUE_TO_DIVERGENCE = ID.x == 0 || ID.y == 0; + + const uint drawID = ID.x == 0 ? 0 : ID.x - 1; + const uint instanceID = ID.y == 0 ? 0 : ID.y - 1; + + /* if ( ID.x == 0 || ID.y == 0 ) { imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(0)); continue; } + */ const DrawCommand drawCommand = drawCommands[drawID]; surface.instance = instances[instanceID]; const Material material = materials[surface.instance.materialID]; @@ -143,6 +148,10 @@ void main() { gammaCorrect(surface.fragment.rgb, 1.0 / ubo.settings.bloom.gamma); #endif - imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, surface.material.albedo.a)); + if ( DISCARD_DUE_TO_DIVERGENCE ) { + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(0)); + } else { + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, surface.material.albedo.a)); + } } } \ No newline at end of file diff --git a/client/client/ext.cpp b/client/client/ext.cpp index e1ff9aae..1113d373 100644 --- a/client/client/ext.cpp +++ b/client/client/ext.cpp @@ -49,7 +49,7 @@ void client::initialize() { ext::config["window"]["refresh rate"] = client::window.getRefreshRate(); // Miscellaneous client::window.setVisible(client::config["window"]["visible"].as()); - client::window.setCursorVisible(client::config["window"]["cursor"]["visible"].as()); + client::window.setCursorVisible(client::config["window"]["mouse"]["visible"].as()); if ( client::config["engine"]["ext"]["imgui"]["enabled"].as() ) { client::window.setCursorVisible(false); } @@ -138,7 +138,7 @@ void client::tick() { } // mouse move uf::inputs::kbm::states::Mouse = {}; - if ( client::config["window"]["mouse"]["center"].as() ) { + if ( client::config["window"]["mouse"]["center"].as(false) ) { auto size = client::window.getSize(); auto current = client::window.getMousePosition(); auto center = client::window.getSize() / 2.0f; @@ -159,6 +159,10 @@ void client::tick() { { center, current - center, 0 } }); #endif + } else { + #if UF_INPUT_USE_ENUM_MOUSE + // uf::inputs::kbm::states::Mouse = { 0, 0 }; + #endif } } } diff --git a/engine/inc/uf/engine/asset/asset.h b/engine/inc/uf/engine/asset/asset.h index b79b2091..bfa559e9 100644 --- a/engine/inc/uf/engine/asset/asset.h +++ b/engine/inc/uf/engine/asset/asset.h @@ -8,10 +8,7 @@ #include namespace uf { - class UF_API Asset : public uf::Component { - protected: - static uf::Asset masterAssetLoader; - public: + namespace asset { enum Type { UNKNOWN, IMAGE, @@ -21,115 +18,105 @@ namespace uf { GRAPH, }; - struct Payload { - uf::Asset::Type type = {}; + struct UF_API Payload { + uf::asset::Type type = {}; uf::stl::string filename = ""; uf::stl::string mime = ""; uf::stl::string hash = ""; bool initialize = true; bool monoThreaded = false; - size_t uid = 0; + bool asComponent = false; + + uf::Serializer metadata; + + pod::Resolvable object; }; - static uf::Asset::Payload resolveToPayload( const uf::stl::string&, const uf::stl::string& = "" ); - static bool isExpected( const uf::Asset::Payload&, uf::Asset::Type expected ); + struct UF_API Job { + typedef uf::stl::vector container_t; - static bool assertionLoad; + uf::stl::string callback = ""; + uf::stl::string type = ""; + uf::asset::Payload payload = {}; + }; + + #if UF_COMPONENT_POINTERED_USERDATA + typedef pod::PointeredUserdata userdata_t; + #else + typedef pod::Userdata* userdata_t; + #endif + + extern UF_API bool assertionLoad; + extern UF_API uf::stl::unordered_map map; + extern UF_API Job::container_t jobs; + extern UF_API uf::Serializer metadata; + + // extern UF_API uf::Serializer map; + + uf::asset::Payload UF_API resolveToPayload( const uf::stl::string&, const uf::stl::string& = "" ); + bool UF_API isExpected( const uf::asset::Payload&, uf::asset::Type expected ); // URL or file path - void processQueue(); + void UF_API processQueue(); - void cache( const uf::stl::string&, const uf::Asset::Payload& ); - void load( const uf::stl::string&, const uf::Asset::Payload& ); + void UF_API cache( const uf::stl::string&, const uf::asset::Payload& ); + void UF_API load( const uf::stl::string&, const uf::asset::Payload& ); - uf::stl::string cache( const uf::Asset::Payload& ); - uf::stl::string load( const uf::Asset::Payload& ); + uf::stl::string UF_API cache( uf::asset::Payload& ); + uf::stl::string UF_API load( uf::asset::Payload& ); - uf::stl::string getOriginal( const uf::stl::string& ); + bool has( const uf::stl::string& url ); + bool has( const uf::asset::Payload& payload ); - template - uf::stl::vector& getContainer() { - return this->getComponent>(); - } + uf::asset::userdata_t& get( const uf::stl::string& url ); + void remove( const uf::stl::string& url ); - template - bool has( std::size_t i = 0 ) { - auto& container = this->getContainer(); - return container.size() > i; - } - template - bool has( const uf::stl::string& url ) { - auto& container = this->getContainer(); - if ( container.empty() ) return false; - uf::stl::string extension = uf::io::extension( url, -1 ); - uf::Serializer& map = this->getComponent(); - if ( ext::json::isNull( map[extension] ) ) return false; - if ( ext::json::isNull( map[extension][url] ) ) return false; - if ( ext::json::isNull( map[extension][url]["index"] ) ) return false; - return true; - } - template - T& get( std::size_t i = 0 ) { - auto& container = this->getContainer(); - return container.at(i); - } template T& get( const uf::stl::string& url ) { - uf::stl::string extension = uf::io::extension( url, -1 ); - uf::Serializer& map = this->getComponent(); - size_t index = map[extension][url]["index"].as(0); - return this->get(index); + if ( !uf::asset::has( url ) ) { + #if UF_COMPONENT_POINTERED_USERDATA + uf::asset::map[url] = uf::pointeredUserdata::create(); + #else + uf::asset::map[url] = uf::userdata::create(); + #endif + } + + #if UF_COMPONENT_POINTERED_USERDATA + return uf::pointeredUserdata::get( uf::asset::map[url] ); + #else + return uf::userdata::get( uf::asset::map[url] ); + #endif + } + template + T& get( uf::asset::Payload& payload ) { + return payload.asComponent && payload.object ? uf::Entity::resolve( payload.object ).getComponent() : uf::asset::get( payload.filename ); } + template + T& add( const uf::stl::string& url ) { + #if UF_COMPONENT_POINTERED_USERDATA + uf::asset::map[url] = uf::pointeredUserdata::create(); + #else + uf::asset::map[url] = uf::userdata::create(); + #endif + return uf::asset::get( url ); + } template T& add( const uf::stl::string& url, const T& copy ) { - uf::stl::string extension = uf::io::extension( url, -1 ); - uf::Serializer& map = this->getComponent(); - auto& container = this->getContainer(); - if ( !ext::json::isNull( map[extension][url]["index"] ) ) return this->get(url); - - container.push_back( copy ); - return container.back(); - } - template - T& add( const uf::stl::string& url, T&& move ) { - uf::stl::string extension = uf::io::extension( url, -1 ); - uf::Serializer& map = this->getComponent(); - auto& container = this->getContainer(); - - if ( !ext::json::isNull( map[extension][url]["index"] ) ) return this->get(url); - - container.push_back( move ); - return container.back(); + #if UF_COMPONENT_POINTERED_USERDATA + uf::asset::map[url] = uf::pointeredUserdata::create( copy ); + #else + uf::asset::map[url] = uf::userdata::create( copy ); + #endif + return uf::asset::get( url ); } - template - void remove( const uf::stl::string& url ) { - if ( !this->has( url ) ) return; - auto& container = this->getContainer(); - - uf::stl::string extension = uf::io::extension( url, -1 ); - uf::Serializer& map = this->getComponent(); - std::size_t index = map[extension][url]["index"].as(); - // container.erase( container.begin() + index ); - // map[extension][url] = ext::json::null(); - // map[extension][url]["erased"] = true; - - uf::stl::string key = ""; - ext::json::forEach( map[extension], [&]( const uf::stl::string& k, ext::json::Value& v ) { - std::size_t i = v["index"].as(); - if ( index == i && key != url ) key = k; - }); - if ( key != "" ) map[extension][key] = ext::json::null(); - map[extension][url] = ext::json::null(); - return; - } - }; + } } namespace pod { namespace payloads { - typedef uf::Asset::Payload assetLoad; + typedef uf::asset::Payload assetLoad; } } \ No newline at end of file diff --git a/engine/inc/uf/engine/asset/masterdata.h b/engine/inc/uf/engine/asset/masterdata.h index cd063013..83672ebe 100644 --- a/engine/inc/uf/engine/asset/masterdata.h +++ b/engine/inc/uf/engine/asset/masterdata.h @@ -2,6 +2,7 @@ #include +/* namespace uf { class UF_API MasterData { protected: @@ -18,4 +19,5 @@ namespace uf { const uf::stl::string& tableName() const; const uf::stl::string& keyName() const; }; -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/engine/inc/uf/engine/entity/entity.h b/engine/inc/uf/engine/entity/entity.h index 7c33808c..ebb5b90d 100644 --- a/engine/inc/uf/engine/entity/entity.h +++ b/engine/inc/uf/engine/entity/entity.h @@ -4,10 +4,12 @@ #include #include #include -#include +#include #include +#include + namespace uf { class UF_API Entity : public uf::Behaviors { public: @@ -26,6 +28,7 @@ namespace uf { public: static uf::MemoryPool memoryPool; + Entity(); ~Entity(); // identifiers @@ -43,6 +46,8 @@ namespace uf { template const T& getParent() const; template const T& getRootParent() const; + template pod::Resolvable resolvable(); + void setUid(); void unsetUid(); @@ -70,6 +75,7 @@ namespace uf { static uf::Entity* globalFindByUid( size_t id ); static uf::Entity* globalFindByName( const uf::stl::string& name ); + template static T& resolve( const pod::Resolvable& ); }; } diff --git a/engine/inc/uf/engine/entity/entity.inl b/engine/inc/uf/engine/entity/entity.inl index 8da02a4e..d1c31fa3 100644 --- a/engine/inc/uf/engine/entity/entity.inl +++ b/engine/inc/uf/engine/entity/entity.inl @@ -36,6 +36,21 @@ template const T& uf::Entity::getRootParent() const { } return *(const T*) last; } + +template pod::Resolvable uf::Entity::resolvable() { + return pod::Resolvable{ + .uid = this->m_uid, + .pointer = (T*) this, + }; +} +template T& uf::Entity::resolve( const pod::Resolvable& resolvable ) { + if ( resolvable.uid ) { + uf::Entity* entity = uf::Entity::globalFindByUid( resolvable.uid ); + if ( entity ) return entity->as(); + } + if ( resolvable.pointer ) return ((uf::Entity*) resolvable.pointer)->as(); + return uf::Entity::null.as(); +} /* template void uf::Entity::initialize() { static_cast(this)->initialize(); diff --git a/engine/inc/uf/engine/scene/scene.h b/engine/inc/uf/engine/scene/scene.h index 13d3fa4b..78957ba2 100644 --- a/engine/inc/uf/engine/scene/scene.h +++ b/engine/inc/uf/engine/scene/scene.h @@ -26,6 +26,7 @@ namespace uf { namespace scene { extern UF_API uf::stl::vector scenes; + extern UF_API bool printTaskCalls; // extern UF_API uf::stl::vector graph; // extern UF_API bool queuedInvalidation; // extern UF_API bool useGraph; diff --git a/engine/inc/uf/ext/lua/lua.h b/engine/inc/uf/ext/lua/lua.h index c52b670d..fee682c9 100644 --- a/engine/inc/uf/ext/lua/lua.h +++ b/engine/inc/uf/ext/lua/lua.h @@ -42,6 +42,8 @@ namespace ext { bool UF_API run( const uf::stl::string&, bool = true ); pod::LuaScript UF_API script( const uf::stl::string& ); + void UF_API script( const uf::stl::string&, pod::LuaScript& ); + bool UF_API run( const pod::LuaScript&, bool = true ); sol::table createTable(); diff --git a/engine/inc/uf/ext/toml/toml.h b/engine/inc/uf/ext/toml/toml.h index 7227c71f..e53df767 100644 --- a/engine/inc/uf/ext/toml/toml.h +++ b/engine/inc/uf/ext/toml/toml.h @@ -7,11 +7,11 @@ namespace ext { namespace toml { - uf::stl::string toJson( const uf::stl::string& ); - uf::stl::vector toJson( const uf::stl::vector& ); + uf::stl::string UF_API toJson( const uf::stl::string& ); + uf::stl::vector UF_API toJson( const uf::stl::vector& ); - uf::stl::string fromJson( const uf::stl::string& ); - uf::stl::vector fromJson( const uf::stl::vector& ); + uf::stl::string UF_API fromJson( const uf::stl::string& ); + uf::stl::vector UF_API fromJson( const uf::stl::vector& ); } } #endif \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/vulkan.h b/engine/inc/uf/ext/vulkan/vulkan.h index cd1e7262..a69c37e6 100644 --- a/engine/inc/uf/ext/vulkan/vulkan.h +++ b/engine/inc/uf/ext/vulkan/vulkan.h @@ -51,6 +51,7 @@ namespace ext { namespace settings { constexpr size_t maxViews = 6; + extern UF_API float version; extern UF_API uint32_t width; extern UF_API uint32_t height; extern UF_API uint8_t msaa; @@ -65,6 +66,7 @@ namespace ext { extern UF_API uf::stl::vector requestedDeviceFeatures; extern UF_API uf::stl::vector requestedDeviceExtensions; extern UF_API uf::stl::vector requestedInstanceExtensions; + extern UF_API uf::Serializer requestedFeatureChain; extern UF_API VkFilter swapchainUpscaleFilter; @@ -73,9 +75,12 @@ namespace ext { extern UF_API bool rebuildOnTickBegin; extern UF_API bool batchQueueSubmissions; extern UF_API bool enableMultiGPU; + extern UF_API bool memoryBudgetBit; } namespace invariant { + extern UF_API bool deviceAddressing; + extern UF_API bool waitOnRenderEnd; extern UF_API bool individualPipelines; extern UF_API bool multithreadedRecording; diff --git a/engine/inc/uf/utils/component/component.h b/engine/inc/uf/utils/component/component.h index f7430dcd..977cec11 100644 --- a/engine/inc/uf/utils/component/component.h +++ b/engine/inc/uf/utils/component/component.h @@ -13,14 +13,15 @@ namespace pod { struct UF_API Component { typedef TYPE_HASH_T id_t; typedef uf::stl::unordered_map container_t; - // typedef uf::stl::unordered_map alias_t; + + #if UF_COMPONENT_POINTERED_USERDATA + typedef pod::PointeredUserdata userdata_t; + #else + typedef pod::Userdata* userdata_t; + #endif pod::Component::id_t id; - #if UF_COMPONENT_POINTERED_USERDATA - pod::PointeredUserdata userdata; - #else - pod::Userdata* userdata; - #endif + pod::Component::userdata_t userdata; }; } namespace uf { @@ -56,6 +57,24 @@ namespace uf { template T& addComponent( const T& = T() ); template void deleteComponent(); + #if UF_COMPONENT_POINTERED_USERDATA + pod::PointeredUserdata addComponent( pod::PointeredUserdata& userdata ); + pod::PointeredUserdata moveComponent( pod::PointeredUserdata& userdata ); + + template T& moveComponent( pod::PointeredUserdata& userdata ) { + this->moveComponent( userdata ); + return this->getComponent(); + } + #else + pod::Userdata* addComponent( pod::Userdata* userdata ); + pod::Userdata* moveComponent( pod::Userdata*& userdata ); + + template T& moveComponent( pod::Userdata*& userdata ) { + this->moveComponent( userdata ); + return this->getComponent(); + } + #endif + void destroyComponents(); }; } diff --git a/engine/inc/uf/utils/io/iostream.h b/engine/inc/uf/utils/io/iostream.h index 77700387..58ce835b 100644 --- a/engine/inc/uf/utils/io/iostream.h +++ b/engine/inc/uf/utils/io/iostream.h @@ -60,6 +60,7 @@ namespace uf { void UF_API_CALL back(); uf::stl::string getBuffer(); uf::stl::vector getHistory(); + void pushHistory( const uf::stl::string& str ); char UF_API_CALL readChar(const bool& = true); uf::stl::string UF_API_CALL readString(const bool& = true); diff --git a/engine/inc/uf/utils/resolvable/resolvable.h b/engine/inc/uf/utils/resolvable/resolvable.h new file mode 100644 index 00000000..29ab7cb7 --- /dev/null +++ b/engine/inc/uf/utils/resolvable/resolvable.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace pod { + template + struct UF_API Resolvable { + size_t uid = 0; + T* pointer = NULL; + + pod::Resolvable& operator=( const T& t ) { + this->pointer = &t; + return *this; + } + operator bool() const { + return uid || pointer; + } + }; +} \ No newline at end of file diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index e32c57d1..d5d6c70f 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -44,16 +44,19 @@ namespace { uf::stl::string callback; uf::stl::string type; - uf::Asset::Payload payload; + uf::asset::Payload payload; }; } -uf::Asset uf::Asset::masterAssetLoader; -bool uf::Asset::assertionLoad = true; +// uf::asset uf::asset::masterAssetLoader; +bool uf::asset::assertionLoad = true; +uf::asset::Job::container_t uf::asset::jobs; +uf::stl::unordered_map uf::asset::map; +uf::Serializer uf::asset::metadata; #define UF_ASSET_MULTITHREAD 1 -void uf::Asset::processQueue() { +void uf::asset::processQueue() { #if UF_ASSET_MULTITHREAD auto tasks = uf::thread::schedule(true, false); #else @@ -61,97 +64,100 @@ void uf::Asset::processQueue() { #endif mutex.lock(); - auto jobs = std::move(this->getComponent()); + auto jobs = std::move(uf::asset::jobs); mutex.unlock(); - for ( auto& job : jobs ) tasks.queue([=, this]{ // C++20 retardation + for ( auto& job : jobs ) tasks.queue([=]{ uf::stl::string callback = job.callback; uf::stl::string type = job.type; - uf::Asset::Payload payload = job.payload; + uf::asset::Payload payload = job.payload; if ( payload.filename == "" || callback == "" ) return; - uf::stl::string filename = type == "cache" ? this->cache(payload) : this->load(payload); - - if ( callback != "" && filename != "" ) uf::hooks.call(callback, payload); + uf::stl::string filename = type == "cache" ? uf::asset::cache(payload) : uf::asset::load(payload); + + if ( callback != "" && filename != "" ) { + uf::hooks.call(callback, payload); + } }); -// bool bitch = !tasks.container.empty(); -// if ( bitch ) UF_MSG_DEBUG("Batching Jobs: {}", tasks.container.size()); uf::thread::execute( tasks ); -// if ( bitch ) UF_MSG_DEBUG("Finished Jobs: {}", tasks.container.size()); } -void uf::Asset::cache( const uf::stl::string& callback, const uf::Asset::Payload& payload ) { +void uf::asset::cache( const uf::stl::string& callback, const uf::asset::Payload& payload ) { mutex.lock(); - auto& jobs = this->getComponent(); + auto& jobs = uf::asset::jobs; jobs.emplace_back(Job{ callback, "cache", payload }); mutex.unlock(); } -void uf::Asset::load( const uf::stl::string& callback, const uf::Asset::Payload& payload ) { +void uf::asset::load( const uf::stl::string& callback, const uf::asset::Payload& payload ) { mutex.lock(); - auto& jobs = this->getComponent(); + auto& jobs = uf::asset::jobs; jobs.emplace_back(Job{ callback, "load", payload }); mutex.unlock(); } -uf::Asset::Payload uf::Asset::resolveToPayload( const uf::stl::string& uri, const uf::stl::string& mime ) { +uf::asset::Payload uf::asset::resolveToPayload( const uf::stl::string& uri, const uf::stl::string& mime ) { uf::stl::string extension = uf::string::lowercase( uf::io::extension( uri, -1 ) ); uf::stl::string basename = uf::string::lowercase( uf::string::replace( uf::io::filename( uri ), "/.(?:gz|lz4?)$/", "" ) ); - uf::Asset::Payload payload; + uf::asset::Payload payload; - static uf::stl::unordered_map typemap = { - { "jpg", uf::Asset::Type::IMAGE }, - { "jpeg", uf::Asset::Type::IMAGE }, - { "png", uf::Asset::Type::IMAGE }, + static uf::stl::unordered_map typemap = { + { "jpg", uf::asset::Type::IMAGE }, + { "jpeg", uf::asset::Type::IMAGE }, + { "png", uf::asset::Type::IMAGE }, - { "ogg", uf::Asset::Type::AUDIO }, + { "ogg", uf::asset::Type::AUDIO }, - { "json", uf::Asset::Type::JSON }, - { "bson", uf::Asset::Type::JSON }, - { "cbor", uf::Asset::Type::JSON }, - { "msgpack",uf::Asset::Type::JSON }, - { "ubjson", uf::Asset::Type::JSON }, - { "bjdata", uf::Asset::Type::JSON }, - { "toml", uf::Asset::Type::JSON }, + { "json", uf::asset::Type::JSON }, + { "bson", uf::asset::Type::JSON }, + { "cbor", uf::asset::Type::JSON }, + { "msgpack",uf::asset::Type::JSON }, + { "ubjson", uf::asset::Type::JSON }, + { "bjdata", uf::asset::Type::JSON }, + { "toml", uf::asset::Type::JSON }, - { "lua", uf::Asset::Type::LUA }, + { "lua", uf::asset::Type::LUA }, - { "glb", uf::Asset::Type::GRAPH }, + { "glb", uf::asset::Type::GRAPH }, #if !UF_USE_OPENGL - { "gltf", uf::Asset::Type::GRAPH }, - { "mdl", uf::Asset::Type::GRAPH }, + { "gltf", uf::asset::Type::GRAPH }, + { "mdl", uf::asset::Type::GRAPH }, #endif }; payload.filename = uri; payload.mime = mime; + if ( payload.filename.substr(0,5) != "https" && extension == "json" ) { + payload.filename = uf::Serializer::resolveFilename( payload.filename ); + } + if ( typemap.count( extension ) == 1 ) payload.type = typemap[extension]; - if ( basename == "graph.json" ) payload.type = uf::Asset::Type::GRAPH; - else if ( basename == "graph.bson" ) payload.type = uf::Asset::Type::GRAPH; - else if ( basename == "graph.cbor" ) payload.type = uf::Asset::Type::GRAPH; - else if ( basename == "graph.msgpack" ) payload.type = uf::Asset::Type::GRAPH; - else if ( basename == "graph.ubjson" ) payload.type = uf::Asset::Type::GRAPH; - else if ( basename == "graph.bjdata" ) payload.type = uf::Asset::Type::GRAPH; - else if ( basename == "graph.toml" ) payload.type = uf::Asset::Type::GRAPH; + if ( basename == "graph.json" ) payload.type = uf::asset::Type::GRAPH; + else if ( basename == "graph.bson" ) payload.type = uf::asset::Type::GRAPH; + else if ( basename == "graph.cbor" ) payload.type = uf::asset::Type::GRAPH; + else if ( basename == "graph.msgpack" ) payload.type = uf::asset::Type::GRAPH; + else if ( basename == "graph.ubjson" ) payload.type = uf::asset::Type::GRAPH; + else if ( basename == "graph.bjdata" ) payload.type = uf::asset::Type::GRAPH; + else if ( basename == "graph.toml" ) payload.type = uf::asset::Type::GRAPH; return payload; } -bool uf::Asset::isExpected( const uf::Asset::Payload& payload, uf::Asset::Type expected ) { +bool uf::asset::isExpected( const uf::asset::Payload& payload, uf::asset::Type expected ) { if ( payload.filename == "" ) return false; if ( payload.type != expected ) return false; return true; } -uf::stl::string uf::Asset::cache( const uf::Asset::Payload& payload ) { +uf::stl::string uf::asset::cache( uf::asset::Payload& payload ) { uf::stl::string filename = payload.filename; uf::stl::string extension = uf::io::extension( filename ); if ( filename.substr(0,5) == "https" ) { uf::stl::string hash = uf::string::sha256( filename ); uf::stl::string cached = uf::io::root + "/cache/http/" + hash + "." + extension; if ( !uf::io::exists( cached ) && !retrieve( filename, cached, hash ) ) { - if ( !uf::Asset::assertionLoad ) { + if ( !uf::asset::assertionLoad ) { UF_MSG_ERROR("Failed to preload {} ({}): HTTP error", filename, cached); } else { UF_EXCEPTION("Failed to preload {} ({}): HTTP error", filename, cached); @@ -159,15 +165,9 @@ uf::stl::string uf::Asset::cache( const uf::Asset::Payload& payload ) { return ""; } filename = cached; - } else { - // do implicit loading of json files (could be encoded as bson, cbor, and compressed as gz, lz4) - if ( extension == "json" ) { - filename = uf::Serializer::resolveFilename( filename ); - extension = uf::io::extension( extension ); - } } if ( !uf::io::exists( filename ) ) { - if ( !uf::Asset::assertionLoad ) { + if ( !uf::asset::assertionLoad ) { UF_MSG_ERROR("Failed to preload {}, does not exist", filename); } else { UF_EXCEPTION("Failed to preload {}, does not exist", filename); @@ -176,7 +176,7 @@ uf::stl::string uf::Asset::cache( const uf::Asset::Payload& payload ) { } uf::stl::string actual = payload.hash; if ( payload.hash != "" && (actual = uf::io::hash( filename )) != payload.hash ) { - if ( !uf::Asset::assertionLoad ) { + if ( !uf::asset::assertionLoad ) { UF_MSG_ERROR("Failed to preload {}: Hash mismatch; expected {}, got {}", filename, payload.hash, actual); } else { UF_EXCEPTION("Failed to preload {}: Hash mismatch; expected {}, got {}", filename, payload.hash, actual); @@ -189,7 +189,7 @@ uf::stl::string uf::Asset::cache( const uf::Asset::Payload& payload ) { #endif return filename; } -uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) { +uf::stl::string uf::asset::load( uf::asset::Payload& payload ) { uf::stl::string filename = payload.filename; uf::stl::string extension = uf::string::lowercase(uf::io::extension( payload.filename, -1 )); uf::stl::string basename = uf::string::lowercase( uf::string::replace( uf::io::filename( payload.filename ), "/.(?:gz|lz4?)$/", "" ) ); @@ -197,7 +197,7 @@ uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) { uf::stl::string hash = uf::string::sha256( payload.filename ); uf::stl::string cached = uf::io::root + "/cache/http/" + hash + "." + extension; if ( !uf::io::exists( cached ) && !retrieve( payload.filename, cached, hash ) ) { - if ( !uf::Asset::assertionLoad ) { + if ( !uf::asset::assertionLoad ) { UF_MSG_ERROR("Failed to load {} ({}): HTTP error", payload.filename, cached); } else { UF_EXCEPTION("Failed to load {} ({}): HTTP error", payload.filename, cached); @@ -205,15 +205,9 @@ uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) { return ""; } filename = cached; - } else { - // do implicit loading of json files (could be encoded as bson, cbor, and compressed as gz, lz4) - if ( extension == "json" ) { - filename = uf::Serializer::resolveFilename( filename ); - extension = uf::io::extension( extension ); - } } if ( !uf::io::exists( filename ) ) { - if ( !uf::Asset::assertionLoad ) { + if ( !uf::asset::assertionLoad ) { UF_MSG_ERROR("Failed to load {}: does not exist", filename); } else { UF_EXCEPTION("Failed to load {}: does not exist", filename); @@ -222,7 +216,7 @@ uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) { } uf::stl::string actual = payload.hash; if ( payload.hash != "" && (actual = uf::io::hash( filename )) != payload.hash ) { - if ( !uf::Asset::assertionLoad ) { + if ( !uf::asset::assertionLoad ) { UF_MSG_ERROR("Failed to load {}: Hash mismatch; expected {}, got {}", filename, payload.hash, actual); } else { UF_EXCEPTION("Failed to load {}: Hash mismatch; expected {}, got {}", filename, payload.hash, actual); @@ -235,47 +229,37 @@ uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) { DC_STATS(); #endif - auto& map = this->getComponent(); #define UF_ASSET_REGISTER(type)\ - auto& container = this->getContainer();\ - if ( !ext::json::isNull( map[extension][payload.filename]["index"] ) ) return filename;\ - if ( !ext::json::isNull( map[extension][filename]["index"] ) ) return filename;\ - map[extension][payload.filename]["index"] = container.size();\ - map[extension][filename]["index"] = container.size();\ - type& asset = container.emplace_back(); + type& asset = uf::asset::get( payload ); + // if ( uf::asset::has( filename ) ) return filename; + // if ( uf::asset::has( payload.filename ) ) return filename; switch ( payload.type ) { - case uf::Asset::Type::IMAGE: { + case uf::asset::Type::IMAGE: { UF_ASSET_REGISTER(uf::Image) asset.open(filename); } break; - case uf::Asset::Type::AUDIO: { + case uf::asset::Type::AUDIO: { UF_ASSET_REGISTER(uf::Audio) asset.open(filename, true); } break; - case uf::Asset::Type::JSON: { + case uf::asset::Type::JSON: { UF_ASSET_REGISTER(uf::Serializer) asset.readFromFile(filename); } break; #if UF_USE_LUA - case uf::Asset::Type::LUA: { + case uf::asset::Type::LUA: { UF_ASSET_REGISTER(pod::LuaScript) asset = ext::lua::script( filename ); } break; #endif - case uf::Asset::Type::GRAPH: { + case uf::asset::Type::GRAPH: { UF_ASSET_REGISTER(pod::Graph) - auto& metadata = this->getComponent(); - #if UF_USE_OPENGL - // combining mesh is only really a (negligent) gain on Vulkan - // collision meshes still use separated meshes, so avoid having to duplicate a mesh for very little gains, if any - metadata[payload.filename]["renderer"]["atlas"] = false; - metadata[payload.filename]["renderer"]["separate"] = true; - #endif - asset = uf::graph::load( filename, metadata[payload.filename] ); + asset = uf::graph::load( filename, payload.metadata ); uf::graph::process( asset ); + #if !UF_ENV_DREAMCAST if ( asset.metadata["debug"]["print"]["stats"].as() ) UF_MSG_INFO("{}", uf::graph::stats( asset )); if ( asset.metadata["debug"]["print"]["tree"].as() ) UF_MSG_INFO("{}", uf::graph::print( asset )); @@ -294,9 +278,31 @@ uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) { return filename; } -uf::stl::string uf::Asset::getOriginal( const uf::stl::string& uri ) { +bool uf::asset::has( const uf::stl::string& url ) { + return uf::asset::map.count( url ) > 0; +} +bool uf::asset::has( const uf::asset::Payload& payload ) { + if ( payload.asComponent ) return true; + return uf::asset::has( payload.filename ); +} +void uf::asset::remove( const uf::stl::string& url ) { + if ( !uf::asset::has( url ) ) return; + auto& userdata = uf::asset::map[url]; +#if UF_COMPONENT_POINTERED_USERDATA + if ( userdata.data ) uf::pointeredUserdata::destroy( userdata ); +#else + if ( userdata ) uf::userdata::destroy( userdata ); +#endif + uf::asset::map.erase( url ); +} +uf::asset::userdata_t& uf::asset::get( const uf::stl::string& url ) { + return uf::asset::map[url]; +} +/* +uf::stl::string uf::asset::getOriginal( const uf::stl::string& uri ) { + return uri; uf::stl::string extension = uf::io::extension( uri ); - auto& map = this->getComponent(); + auto& map = uf::asset::map; //getComponent(); if ( ext::json::isNull( map[extension][uri]["index"] ) ) return uri; std::size_t index = map[extension][uri]["index"].as(); @@ -306,4 +312,5 @@ uf::stl::string uf::Asset::getOriginal( const uf::stl::string& uri ) { if ( index == i && key != uri ) key = k; }); return key; -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/engine/src/engine/asset/masterdata.cpp b/engine/src/engine/asset/masterdata.cpp index 5ca5aba0..6d334921 100644 --- a/engine/src/engine/asset/masterdata.cpp +++ b/engine/src/engine/asset/masterdata.cpp @@ -1,9 +1,10 @@ +/* #include #include //uf::stl::string uf::MasterData::root = "https://el..xyz/mastertable/get/%TABLE%/%KEY%?.json"; uf::stl::string uf::MasterData::root = uf::io::root + "/master/%TABLE%.json"; -uf::Asset uf::MasterData::assetLoader; +uf::asset uf::MasterData::assetLoader; uf::Serializer uf::MasterData::load( const uf::stl::string& table, size_t key ) { return this->load( table, std::to_string(key) ); @@ -13,8 +14,8 @@ uf::Serializer uf::MasterData::load( const uf::stl::string& table, const uf::stl this->m_key = key; uf::stl::string url = uf::string::replace( root, "%TABLE%", table ); - auto payload = uf::Asset::resolveToPayload( uf::string::replace( url, "%KEY%", key ) ); - uf::stl::string filename = assetLoader.cache(payload); + auto payload = uf::asset::resolveToPayload( uf::string::replace( url, "%KEY%", key ) ); + uf::stl::string filename = uf::asset::cache(payload); if ( filename != "" ) this->m_data.readFromFile(filename); return this->get(); } @@ -28,4 +29,5 @@ const uf::stl::string& uf::MasterData::tableName() const { } const uf::stl::string& uf::MasterData::keyName() const { return this->m_key; -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/engine/src/engine/graph/decode.cpp b/engine/src/engine/graph/decode.cpp index 9782a70a..3bb3eba8 100644 --- a/engine/src/engine/graph/decode.cpp +++ b/engine/src/engine/graph/decode.cpp @@ -12,10 +12,10 @@ #if UF_ENV_DREAMCAST #define UF_GRAPH_LOAD_MULTITHREAD 0 #else - #define UF_GRAPH_LOAD_MULTITHREAD 1 + #define UF_GRAPH_LOAD_MULTITHREAD 0 #endif -#if UF_ENV_DREAMCAST +#if 1 || UF_ENV_DREAMCAST #define UF_DEBUG_TIMER_MULTITRACE_START(...) UF_TIMER_MULTITRACE_START(__VA_ARGS__) #define UF_DEBUG_TIMER_MULTITRACE(...) UF_TIMER_MULTITRACE(__VA_ARGS__) #define UF_DEBUG_TIMER_MULTITRACE_END(...) UF_TIMER_MULTITRACE_END(__VA_ARGS__) @@ -366,6 +366,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize graph.instances.emplace_back(name); UF_MSG_DEBUG( "{}", name ); }); + UF_DEBUG_TIMER_MULTITRACE("Read instances"); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -379,6 +380,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize /*graph.storage*/uf::graph::storage.primitives[name] = decodePrimitives( value, graph ); graph.primitives.emplace_back(name); }); + UF_DEBUG_TIMER_MULTITRACE("Read primitives."); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -392,6 +394,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize /*graph.storage*/uf::graph::storage.drawCommands[name] = decodeDrawCommands( value, graph ); graph.drawCommands.emplace_back(name); }); + UF_DEBUG_TIMER_MULTITRACE("Read drawCommands"); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -405,6 +408,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize /*graph.storage*/uf::graph::storage.meshes[name] = decodeMesh( value, graph ); graph.meshes.emplace_back(name); }); + UF_DEBUG_TIMER_MULTITRACE("Read meshes"); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -418,6 +422,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize /*graph.storage*/uf::graph::storage.images[name] = decodeImage( value, graph ); graph.images.emplace_back(name); }); + UF_DEBUG_TIMER_MULTITRACE("Read images"); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -445,6 +450,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize /*graph.storage*/uf::graph::storage.textures[name] = decodeTexture( value, graph ); graph.textures.emplace_back(name); }); + UF_DEBUG_TIMER_MULTITRACE("Read texture information"); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -458,6 +464,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize /*graph.storage*/uf::graph::storage.samplers[name] = decodeSampler( value, graph ); graph.samplers.emplace_back(name); }); + UF_DEBUG_TIMER_MULTITRACE("Read sampler information"); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -471,6 +478,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize /*graph.storage*/uf::graph::storage.materials[name] = decodeMaterial( value, graph ); graph.materials.emplace_back(name); }); + UF_DEBUG_TIMER_MULTITRACE("Read material information"); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -483,6 +491,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize auto name = value["name"].as(); graph.lights[name] = decodeLight( value, graph ); }); + UF_DEBUG_TIMER_MULTITRACE("Read lighting information"); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -529,6 +538,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize graph.nodes.emplace_back(decodeNode( value, graph )); }); graph.root = decodeNode( serializer["root"], graph ); + UF_DEBUG_TIMER_MULTITRACE("Read nodes"); #if UF_ENV_DREAMCAST DC_STATS(); #endif diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 4f5918e8..93d43bf6 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -403,7 +403,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M } // grab addresses - if ( /*uf::renderer::settings::pipelines::rt*/ true ) { + if ( uf::renderer::settings::invariant::deviceAddressing ) { pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer( mesh.indirect ).data(); for ( size_t drawID = 0; drawID < mesh.indirect.count; ++drawID ) { auto& drawCommand = drawCommands[drawID]; diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 99f617cc..aea6d5c6 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -17,7 +17,7 @@ UF_BEHAVIOR_TRAITS_CPP(uf::ObjectBehavior, ticks = true, renders = false, multit #define this (&self) void uf::ObjectBehavior::initialize( uf::Object& self ) { auto& scene = uf::scene::getCurrentScene(); - auto& assetLoader = scene.getComponent(); +// auto& assetLoader = scene.getComponent(); auto& metadata = this->getComponent(); auto& metadataJson = this->getComponent(); auto& transform = this->getComponent>(); @@ -35,7 +35,7 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { auto& parent = this->getParent().as(); pod::payloads::assetLoad payload; - payload.uid = this->getUid(); + payload.object = this->resolvable<>(); parent.lazyCallHook("asset:Parsed.%UID%", payload); } } @@ -63,20 +63,46 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { }); this->addHook( "asset:QueueLoad.%UID%", [&](pod::payloads::assetLoad& payload){ uf::stl::string callback = this->formatHookName("asset:FinishedLoad.%UID%"); - if ( payload.monoThreaded ) { - // UF_MSG_DEBUG("Queued: {}", payload.filename); - if ( assetLoader.load( payload ) != "" ) this->queueHook( callback, payload ); - } else { - // UF_MSG_DEBUG("Immediate: {}", payload.filename); - assetLoader.load( callback, payload ); + /* + switch ( payload.type ) { + case uf::asset::Type::AUDIO: + case uf::asset::Type::IMAGE: + case uf::asset::Type::LUA: { + if ( payload.monoThreaded ) { + if ( uf::asset::cache( payload ) != "" ) this->queueHook( callback, payload ); + } else { + uf::asset::cache( callback, payload ); + } + } break; + + case uf::asset::Type::GRAPH: { + if ( payload.monoThreaded ) { + if ( uf::asset::load( payload ) != "" ) this->queueHook( callback, payload ); + } else { + uf::asset::load( callback, payload ); + } + } break; } + */ + if ( payload.monoThreaded ) { + if ( uf::asset::load( payload ) != "" ) this->queueHook( callback, payload ); + } else { + uf::asset::load( callback, payload ); + } + /* + if ( payload.monoThreaded ) { + if ( uf::asset::cache( payload ) != "" ) this->queueHook( callback, payload ); + } else { + uf::asset::cache( callback, payload ); + } + */ }); this->addHook( "asset:FinishedLoad.%UID%", [&](pod::payloads::assetLoad& payload){ this->queueHook("asset:Load.%UID%", payload); this->queueHook("asset:Parsed.%UID%", payload); }); this->addHook( "asset:Load.%UID%", [&](pod::payloads::assetLoad& payload){ - if ( !uf::Asset::isExpected( payload, uf::Asset::Type::JSON ) ) return; + if ( !uf::asset::isExpected( payload, uf::asset::Type::JSON ) ) return; uf::Serializer json; if ( !json.readFromFile(payload.filename) ) return; @@ -93,8 +119,7 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { metadata.system.load.progress += portion; if ( metadata.system.load.progress == metadata.system.load.total ) { auto& parent = this->getParent().as(); - - payload.uid = this->getUid(); + payload.object = this->resolvable<>(); parent.lazyCallHook("asset:Parsed.%UID%", payload); } }); diff --git a/engine/src/engine/object/behaviors/graph.cpp b/engine/src/engine/object/behaviors/graph.cpp index 61bda47d..7482c2da 100644 --- a/engine/src/engine/object/behaviors/graph.cpp +++ b/engine/src/engine/object/behaviors/graph.cpp @@ -26,13 +26,9 @@ void uf::GraphBehavior::initialize( uf::Object& self ) { uf::graph::animate( graph, name ); }); this->addHook( "asset:Load.%UID%", [&](pod::payloads::assetLoad& payload){ - if ( !uf::Asset::isExpected( payload, uf::Asset::Type::GRAPH ) ) return; - - auto& scene = uf::scene::getCurrentScene(); - auto& assetLoader = scene.getComponent(); - if ( !assetLoader.has(payload.filename) ) return; - auto& graph = (this->getComponent() = std::move( assetLoader.get(payload.filename) )); - assetLoader.remove(payload.filename); + if ( !uf::asset::isExpected( payload, uf::asset::Type::GRAPH ) ) return; + if ( !uf::asset::has( payload ) ) uf::asset::load( payload ); + auto& graph = uf::asset::get( payload ); // deferred shader loading auto& transform = this->getComponent>(); @@ -47,6 +43,10 @@ void uf::GraphBehavior::initialize( uf::Object& self ) { } this->addChild(graph.root.entity->as()); + + if ( !payload.asComponent ) { + this->moveComponent( uf::asset::get( payload.filename ) ); + } }); } void uf::GraphBehavior::destroy( uf::Object& self ) {} diff --git a/engine/src/engine/object/behaviors/lua.cpp b/engine/src/engine/object/behaviors/lua.cpp index e70c99ec..f30ff5bb 100644 --- a/engine/src/engine/object/behaviors/lua.cpp +++ b/engine/src/engine/object/behaviors/lua.cpp @@ -20,15 +20,15 @@ void uf::LuaBehavior::initialize( uf::Object& self ) { if ( !ext::lua::enabled ) return; this->addHook( "asset:Load.%UID%", [&](pod::payloads::assetLoad& payload){ - if ( !uf::Asset::isExpected( payload, uf::Asset::Type::LUA ) ) return; + if ( !uf::asset::isExpected( payload, uf::asset::Type::LUA ) ) return; + if ( !uf::asset::has( payload ) ) uf::asset::load( payload ); + auto& script = uf::asset::get( payload ); - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Asset& assetLoader = scene.getComponent(); - const pod::LuaScript* assetPointer = NULL; - if ( !assetLoader.has(payload.filename) ) return; - assetPointer = &assetLoader.get(payload.filename); - if ( !assetPointer ) return; - pod::LuaScript script = *assetPointer; + /* + if ( !uf::asset::has(payload.filename) ) uf::asset::load( payload ); + auto& script = uf::asset::get(payload.filename); + */ + // auto& script = this->getComponent(); script.env["ent"] = &this->as(); ext::lua::run( script ); }); diff --git a/engine/src/engine/object/object.cpp b/engine/src/engine/object/object.cpp index bd6a0e49..2fa232e8 100644 --- a/engine/src/engine/object/object.cpp +++ b/engine/src/engine/object/object.cpp @@ -167,12 +167,12 @@ void uf::Object::loadAssets( const uf::Serializer& _json ){ auto& metadata = this->getComponent(); auto& metadataJson = this->getComponent(); auto& scene = uf::scene::getCurrentScene(); - auto& assetLoader = scene.getComponent(); +// auto& assetLoader = scene.getComponent(); ext::json::Value json = _json; - #define ASSET_ENTRY(type) { uf::string::lowercase(#type), uf::Asset::Type::type } - const uf::stl::unordered_map assets = { + #define ASSET_ENTRY(type) { uf::string::lowercase(#type), uf::asset::Type::type } + const uf::stl::unordered_map assets = { ASSET_ENTRY(AUDIO), ASSET_ENTRY(IMAGE), ASSET_ENTRY(GRAPH), @@ -202,30 +202,38 @@ void uf::Object::loadAssets( const uf::Serializer& _json ){ uf::stl::string f = isObject ? target[i]["filename"].as() : target[i].as(); uf::stl::string filename = uf::io::resolveURI( f, metadata.system.root ); uf::stl::string mime = isObject ? target[i]["mime"].as("") : ""; - uf::Asset::Payload payload = uf::Asset::resolveToPayload( filename, mime ); - if ( !uf::Asset::isExpected( payload, assetType ) ) continue; - payload.hash = isObject ? target[i]["hash"].as("") : ""; - payload.monoThreaded = isObject ? !target[i]["multithreaded"].as(true) : !true; - this->queueHook( "asset:QueueLoad.%UID%", payload, isObject ? target[i]["delay"].as() : 0 ); bool bind = isObject ? target[i]["bind"].as(true) : true; + uf::asset::Payload payload = uf::asset::resolveToPayload( filename, mime ); + if ( !uf::asset::isExpected( payload, assetType ) ) continue; + + payload.hash = isObject ? target[i]["hash"].as("") : ""; + payload.object = this->resolvable<>(); + payload.monoThreaded = isObject ? !target[i]["multithreaded"].as(true) : !true; + payload.asComponent = isObject ? !target[i]["component"].as(false) : false; + payload.asComponent = true; + switch ( assetType ) { - case uf::Asset::Type::LUA: { + case uf::asset::Type::LUA: { + // payload.asComponent = true; if ( bind ) uf::instantiator::bind("LuaBehavior", *this); } break; - case uf::Asset::Type::GRAPH: { - auto graphMetadata = json["metadata"]["graph"]; - auto& aMetadata = assetLoader.getComponent(); - aMetadata[filename] = graphMetadata; - aMetadata[filename]["root"] = json["root"]; + case uf::asset::Type::GRAPH: { + // payload.asComponent = true; if ( bind ) uf::instantiator::bind("GraphBehavior", *this); + auto metadata = json["metadata"]["graph"]; + payload.metadata = metadata; + payload.metadata["root"] = json["root"]; + // nasty hack to get soundscapes/music to load while the rest of the graph loads - if ( ext::json::isObject(graphMetadata["assets"]) || ext::json::isArray(graphMetadata["assets"]) ) { - scene.loadAssets(graphMetadata["assets"]); + if ( ext::json::isObject(metadata["assets"]) || ext::json::isArray(metadata["assets"]) ) { + scene.loadAssets(metadata["assets"]); } } break; } + + this->queueHook( "asset:QueueLoad.%UID%", payload, isObject ? target[i]["delay"].as() : 0 ); } } } @@ -234,7 +242,7 @@ bool uf::Object::load( const uf::Serializer& _json ) { auto& metadata = this->getComponent(); auto& metadataJson = this->getComponent(); auto& scene = uf::scene::getCurrentScene(); - auto& assetLoader = scene.getComponent(); +// auto& assetLoader = scene.getComponent(); uf::Serializer json = _json; // setup root/source/mtime @@ -363,9 +371,9 @@ bool uf::Object::load( const uf::Serializer& _json ) { uf::stl::string mime = ext::json::isObject( target[i] ) ? target[i]["mime"].as() : ""; uf::stl::string hash = ext::json::isObject( target[i] ) ? target[i]["hash"].as() : ""; - uf::Asset::Payload payload = uf::Asset::resolveToPayload( filename, mime ); - if ( !uf::Asset::isExpected( payload, uf::Asset::Type::JSON ) ) continue; - if ( (filename = assetLoader.load( payload )) == "" ) continue; + uf::asset::Payload payload = uf::asset::resolveToPayload( filename, mime ); + if ( !uf::asset::isExpected( payload, uf::asset::Type::JSON ) ) continue; + if ( (filename = uf::asset::load( payload )) == "" ) continue; float delay = ext::json::isObject( target[i] ) ? target[i]["delay"].as() : -1; if ( delay > -1 ) { diff --git a/engine/src/engine/scene/scene.cpp b/engine/src/engine/scene/scene.cpp index 3c3d411d..6702e223 100644 --- a/engine/src/engine/scene/scene.cpp +++ b/engine/src/engine/scene/scene.cpp @@ -98,34 +98,36 @@ const uf::stl::vector& uf::Scene::getGraph() { #if UF_TICK_FROM_TASKS auto* self = (uf::Object*) entity; auto/*&*/ behaviorGraph = entity->getGraph(); -#if 1 - #if UF_TICK_MULTITHREAD_OVERRIDE - for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.parallel.queue([=]{ fun(*self); }); - #else - for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.serial.queue([=]{ fun(*self); }); - #endif + if ( uf::scene::printTaskCalls ) { + for ( auto& behavior : self->getBehaviors() ) { + if ( !behavior.traits.ticks ) continue; - for ( auto fun : behaviorGraph.tick.parallel ) metadata.tasks.parallel.queue([=]{ fun(*self); }); -#else - for ( auto& behavior : self->getBehaviors() ) { - if ( !behavior.traits.ticks ) continue; + auto name = behavior.type.name().str(); + #if UF_TICK_MULTITHREAD_OVERRIDE + if ( true ) + #else + if ( behavior.traits.multithread ) + #endif + metadata.tasks.parallel.queue([=]{ + UF_MSG_DEBUG("Parallel {} task executing: {}: {}", name, self->getName(), self->getUid()); + behavior.tick(*self); + UF_MSG_DEBUG("Parallel {} task exectued: {}: {}", name, self->getName(), self->getUid()); + }); else metadata.tasks.serial.queue([=]{ + UF_MSG_DEBUG("Serial {} task executing: {}: {}", name, self->getName(), self->getUid()); + behavior.tick(*self); + UF_MSG_DEBUG("Serial {} task exectued: {}: {}", name, self->getName(), self->getUid()); + }); + } + } else { + #if UF_TICK_MULTITHREAD_OVERRIDE + for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.parallel.queue([=]{ fun(*self); }); + #else + for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.serial.queue([=]{ fun(*self); }); + #endif - auto name = behavior.type.name().str(); - #if UF_TICK_MULTITHREAD_OVERRIDE - if ( true ) - #else - if ( behavior.traits.multithread ) - #endif - metadata.tasks.parallel.queue([=]{ - behavior.tick(*self); - UF_MSG_DEBUG("Parallel {} task exectued: {}: {}", name, self->getName(), self->getUid()); - }); else metadata.tasks.serial.queue([=]{ - behavior.tick(*self); - UF_MSG_DEBUG("Serial {} task exectued: {}: {}", name, self->getName(), self->getUid()); - }); - } + for ( auto fun : behaviorGraph.tick.parallel ) metadata.tasks.parallel.queue([=]{ fun(*self); }); + } #endif -#endif }); uf::renderer::states::rebuild = true; @@ -138,6 +140,8 @@ uf::stl::vector uf::Scene::getGraph( bool reverse ) { } uf::stl::vector uf::scene::scenes; +bool uf::scene::printTaskCalls = false; + uf::Scene& uf::scene::loadScene( const uf::stl::string& name, const uf::stl::string& _filename ) { uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene; uf::scene::scenes.emplace_back( scene ); @@ -197,6 +201,8 @@ void uf::scene::tick() { } #endif + if ( uf::scene::printTaskCalls ) UF_MSG_DEBUG("Scene tick start"); + auto& scene = uf::scene::getCurrentScene(); #if !UF_SCENE_GLOBAL_GRAPH auto& metadata = scene.getComponent(); @@ -212,6 +218,8 @@ void uf::scene::tick() { #else for ( auto entity : graph ) entity->tick(); #endif + + if ( uf::scene::printTaskCalls ) UF_MSG_DEBUG("Scene tick end"); } void uf::scene::render() { if ( scenes.empty() ) return; diff --git a/engine/src/ext/lua/lua.cpp b/engine/src/ext/lua/lua.cpp index 9cccc174..c579a355 100644 --- a/engine/src/ext/lua/lua.cpp +++ b/engine/src/ext/lua/lua.cpp @@ -297,11 +297,15 @@ bool ext::lua::run( const uf::stl::string& s, bool safe ) { pod::LuaScript ext::lua::script( const uf::stl::string& filename ) { pod::LuaScript script; if ( !ext::lua::enabled ) return script; - script.file = filename; script.env = sol::environment( ext::lua::state, sol::create, ext::lua::state.globals() ); return script; } +void ext::lua::script( const uf::stl::string& filename, pod::LuaScript& script ) { + if ( !ext::lua::enabled ) return; + script.file = filename; + script.env = sol::environment( ext::lua::state, sol::create, ext::lua::state.globals() ); +} bool ext::lua::run( const pod::LuaScript& s, bool safe ) { // is file if ( uf::io::extension(s.file) == "lua" ) { diff --git a/engine/src/ext/lua/usertypes/asset.cpp b/engine/src/ext/lua/usertypes/asset.cpp index dcfc7923..01c5db0d 100644 --- a/engine/src/ext/lua/usertypes/asset.cpp +++ b/engine/src/ext/lua/usertypes/asset.cpp @@ -1,9 +1,10 @@ +/* #include #if UF_USE_LUA #include namespace binds { - void load( uf::Asset& asset, sol::variadic_args va ) { + void load( uf::asset& asset, sol::variadic_args va ) { auto it = va.begin(); uf::stl::string callback = ""; uf::stl::string uri = ""; @@ -14,13 +15,13 @@ namespace binds { if ( it != va.end() ) hash = *(it++); if ( it != va.end() ) mime = *(it++); - auto payload = uf::Asset::resolveToPayload( uri, mime ); + auto payload = uf::asset::resolveToPayload( uri, mime ); payload.hash = hash; if ( callback == "" ) asset.load( payload ); else asset.load( callback, payload ); } - void cache( uf::Asset& asset, sol::variadic_args va ) { + void cache( uf::asset& asset, sol::variadic_args va ) { auto it = va.begin(); uf::stl::string callback = ""; uf::stl::string uri = ""; @@ -31,7 +32,7 @@ namespace binds { if ( it != va.end() ) hash = *(it++); if ( it != va.end() ) mime = *(it++); - auto payload = uf::Asset::resolveToPayload( uri, mime ); + auto payload = uf::asset::resolveToPayload( uri, mime ); payload.hash = hash; if ( callback == "" ) @@ -39,14 +40,15 @@ namespace binds { else asset.cache( callback, payload ); } - uf::stl::string getOriginal( uf::Asset& asset, const uf::stl::string& n ) { + uf::stl::string getOriginal( uf::asset& asset, const uf::stl::string& n ) { return asset.getOriginal( n ); } } -UF_LUA_REGISTER_USERTYPE(uf::Asset, +UF_LUA_REGISTER_USERTYPE(uf::asset, UF_LUA_REGISTER_USERTYPE_DEFINE( load, UF_LUA_C_FUN(::binds::load) ), UF_LUA_REGISTER_USERTYPE_DEFINE( cache, UF_LUA_C_FUN(::binds::cache) ), UF_LUA_REGISTER_USERTYPE_DEFINE( getOriginal, UF_LUA_C_FUN(::binds::getOriginal) ) ) -#endif \ No newline at end of file +#endif +*/ \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/object.cpp b/engine/src/ext/lua/usertypes/object.cpp index 7864876e..cd64f43d 100644 --- a/engine/src/ext/lua/usertypes/object.cpp +++ b/engine/src/ext/lua/usertypes/object.cpp @@ -14,7 +14,7 @@ namespace binds { Metadata, Transform, Audio, - Asset, + // Asset, Camera, Physics, PhysicsState, @@ -27,7 +27,7 @@ namespace binds { UF_LUA_REGISTER_ENUM(Metadata), UF_LUA_REGISTER_ENUM(Transform), UF_LUA_REGISTER_ENUM(Audio), - UF_LUA_REGISTER_ENUM(Asset), + // UF_LUA_REGISTER_ENUM(Asset), UF_LUA_REGISTER_ENUM(Camera), UF_LUA_REGISTER_ENUM(Physics), UF_LUA_REGISTER_ENUM(PhysicsState) @@ -56,7 +56,7 @@ namespace binds { } break; UF_LUA_RETRIEVE_COMPONENT_FROM_ENUM( Transform, pod::Transform<> ); UF_LUA_RETRIEVE_COMPONENT_FROM_ENUM( Audio, uf::Audio ); - UF_LUA_RETRIEVE_COMPONENT_FROM_ENUM( Asset, uf::Asset ); + // UF_LUA_RETRIEVE_COMPONENT_FROM_ENUM( Asset, uf::asset ); UF_LUA_RETRIEVE_COMPONENT_FROM_ENUM( Camera, uf::Camera ); UF_LUA_RETRIEVE_COMPONENT_FROM_ENUM( Physics, pod::Physics ); UF_LUA_RETRIEVE_COMPONENT_FROM_ENUM( PhysicsState, pod::PhysicsState ); @@ -81,7 +81,7 @@ namespace binds { } UF_LUA_RETRIEVE_COMPONENT_FROM_STRING(pod::Transform<>) UF_LUA_RETRIEVE_COMPONENT_FROM_STRING(uf::Audio) - UF_LUA_RETRIEVE_COMPONENT_FROM_STRING(uf::Asset) + // UF_LUA_RETRIEVE_COMPONENT_FROM_STRING(uf::asset) UF_LUA_RETRIEVE_COMPONENT_FROM_STRING(uf::Camera) UF_LUA_RETRIEVE_COMPONENT_FROM_STRING(pod::Physics) UF_LUA_RETRIEVE_COMPONENT_FROM_STRING(pod::PhysicsState) @@ -110,7 +110,7 @@ namespace binds { } UF_LUA_UPDATE_COMPONENT(pod::Transform<>) UF_LUA_UPDATE_COMPONENT(uf::Audio) - UF_LUA_UPDATE_COMPONENT(uf::Asset) + // UF_LUA_UPDATE_COMPONENT(uf::asset) UF_LUA_UPDATE_COMPONENT(uf::Camera) UF_LUA_UPDATE_COMPONENT(pod::Physics) UF_LUA_UPDATE_COMPONENT(pod::PhysicsState) diff --git a/engine/src/ext/opengl/commands.cpp b/engine/src/ext/opengl/commands.cpp index d99a44ad..4afa1427 100644 --- a/engine/src/ext/opengl/commands.cpp +++ b/engine/src/ext/opengl/commands.cpp @@ -131,7 +131,33 @@ void ext::opengl::CommandBuffer::submit() { } void ext::opengl::CommandBuffer::flush() { mutex->lock(); - for ( auto& userdata : infos ) userdata.destroy(); + for ( auto& info : infos ) { + CommandBuffer::Info* header = (CommandBuffer::Info*) (void*) info; + switch ( header->type ) { + case ext::opengl::enums::Command::CLEAR: { + InfoClear* info = (InfoClear*) header; + info->~InfoClear(); + } break; + case ext::opengl::enums::Command::VIEWPORT: { + InfoViewport* info = (InfoViewport*) header; + info->~InfoViewport(); + } break; + case ext::opengl::enums::Command::VARIANT: { + InfoVariant* info = (InfoVariant*) header; + info->~InfoVariant(); + } break; + case ext::opengl::enums::Command::DRAW: { + InfoDraw* info = (InfoDraw*) header; + info->~InfoDraw(); + } break; + default: { + } break; + } + } + for ( auto& userdata : infos ) { + userdata.autoDestruct = true; + userdata.destroy(); + } infos.clear(); state = 0; mutex->unlock(); @@ -300,10 +326,6 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glBindTexture(drawInfo.textures.primary.viewType, drawInfo.textures.primary.image)); GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.uv.stride, (static_cast(drawInfo.attributes.uv.pointer) + drawInfo.attributes.uv.stride * drawInfo.descriptor.inputs.vertex.first))); - if ( drawInfo.textures.secondary.image && drawInfo.attributes.st.pointer ) { - GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.st.stride, (static_cast(drawInfo.attributes.st.pointer) + drawInfo.attributes.st.stride * drawInfo.descriptor.inputs.vertex.first))); - } - /* if ( !(drawInfo.textures.secondary.image && drawInfo.attributes.st.pointer) ) { GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); } else { @@ -318,7 +340,6 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.st.stride, (static_cast(drawInfo.attributes.st.pointer) + drawInfo.attributes.st.stride * drawInfo.descriptor.inputs.vertex.first))); } - */ } if ( drawInfo.attributes.normal.pointer ) GL_ERROR_CHECK(glNormalPointer(GL_FLOAT, drawInfo.attributes.normal.stride, (static_cast(drawInfo.attributes.normal.pointer) + drawInfo.attributes.normal.stride * drawInfo.descriptor.inputs.vertex.first))); diff --git a/engine/src/ext/reactphysics/reactphysics.cpp b/engine/src/ext/reactphysics/reactphysics.cpp index de120cd8..dd9d82d7 100644 --- a/engine/src/ext/reactphysics/reactphysics.cpp +++ b/engine/src/ext/reactphysics/reactphysics.cpp @@ -235,7 +235,7 @@ void ext::reactphysics::tick( float delta ) { accumulator -= ext::reactphysics::timescale; } - TIMER(ext::reactphysics::debugDraw::rate, ext::reactphysics::debugDraw::enabled ) { + TIMER( ext::reactphysics::debugDraw::rate, ext::reactphysics::debugDraw::enabled ) { auto& scene = uf::scene::getCurrentScene(); ::debugDraw( scene ); } @@ -489,12 +489,14 @@ void ext::reactphysics::syncTo() { const auto& b1 = bodies[i1]; const auto& b2 = bodies[i2]; + const float T = uf::physics::time::delta / ext::reactphysics::timescale; + const auto direction = ::convert(uf::vector::normalize( b2.position - b1.position )); const float G = ext::reactphysics::gravity::constant; const float m1 = b1.mass; const float m2 = b2.mass; const float r2 = uf::vector::distanceSquared( b1.position, b2.position ); - const float F = G * m1 * m2 / r2; + const float F = T * G * m1 * m2 / r2; #if UF_ENV_DREAMCAST if ( b1.body ) b1.body->applyForceToCenterOfMass(direction * F); diff --git a/engine/src/ext/vulkan/buffer.cpp b/engine/src/ext/vulkan/buffer.cpp index 509dfb17..7cf9a42a 100644 --- a/engine/src/ext/vulkan/buffer.cpp +++ b/engine/src/ext/vulkan/buffer.cpp @@ -1,6 +1,7 @@ #if UF_USE_VULKAN #define VMA_VULKAN_VERSION 1002000 +#define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (200ull * 1024 * 1024) #define VMA_IMPLEMENTATION #include @@ -94,12 +95,18 @@ void ext::vulkan::Buffer::allocate( VkBufferCreateInfo bufferCreateInfo ) { } size_t ext::vulkan::Buffer::getAddress() { +// if ( !(usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) ) UF_MSG_DEBUG("CALLING GETADDRESS ON BUFFER WITHOUT ADDRESS BIT: {}", fmt::ptr(this->buffer)); + if ( this->address ) return this->address; + VkBufferDeviceAddressInfoKHR info{}; info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; info.buffer = buffer; return (this->address = vkGetBufferDeviceAddressKHR(this->device ? *this->device : ext::vulkan::device, &info)); } size_t ext::vulkan::Buffer::getAddress() const { +// if ( !(usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) ) UF_MSG_DEBUG("CALLING GETADDRESS ON BUFFER WITHOUT ADDRESS BIT: {}", fmt::ptr(this->buffer)); + if ( this->address ) return this->address; + VkBufferDeviceAddressInfoKHR info{}; info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; info.buffer = buffer; @@ -126,17 +133,20 @@ void ext::vulkan::Buffer::destroy(bool defer) { this->buffer = {}; this->memory = {}; this->descriptor = {}; - this->alignment = {}; +// this->alignment = {}; this->address = {}; this->mapped = {}; - this->usage = {}; - this->memoryProperties = {}; +// this->usage = {}; +// this->memoryProperties = {}; this->allocation = {}; this->allocationInfo = {}; } void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, bool stage ) { if ( !device ) device = &ext::vulkan::device; if ( stage ) usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; // implicitly set properties + +// if ( usage != VK_BUFFER_USAGE_TRANSFER_SRC_BIT ) usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + VK_CHECK_RESULT(device->createBuffer( nullptr, length, @@ -144,7 +154,31 @@ void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkB memoryProperties, *this )); + if ( data && length ) update( data, length, stage ); + +/* + { + uf::stl::string type; + + if ( usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT ) type += "transfer_src,"; + if ( usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT ) type += "transfer_dst,"; + if ( usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT ) type += "uniform_texel,"; + if ( usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT ) type += "storage_texel,"; + if ( usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) type += "uniform,"; + if ( usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) type += "storage,"; + if ( usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT ) type += "index,"; + if ( usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT ) type += "vertex,"; + if ( usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT ) type += "indirect,"; + if ( usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) type += "acceleration_structure,"; + if ( usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT ) type += "address,"; + if ( usage & VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR ) type += "binding_table,"; + + UF_MSG_DEBUG("CREATING BUFFER: {}: {}({})", fmt::ptr(this->buffer), type, usage); + } +*/ + + this->usage = usage; } bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool stage ) const { // if ( !data || !length ) return false; @@ -168,6 +202,7 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st } ext::vulkan::Device* device = this->device ? this->device : &ext::vulkan::device; + Buffer staging = device->fetchTransientBuffer( // Buffer staging = device->createBuffer( data, diff --git a/engine/src/ext/vulkan/device.cpp b/engine/src/ext/vulkan/device.cpp index 55dd7236..4f530213 100644 --- a/engine/src/ext/vulkan/device.cpp +++ b/engine/src/ext/vulkan/device.cpp @@ -857,11 +857,29 @@ void ext::vulkan::Device::initialize() { VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "Program"; - appInfo.applicationVersion = VK_MAKE_VERSION(1, 3, 0); appInfo.pEngineName = "Engine"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 3, 0); appInfo.engineVersion = VK_MAKE_VERSION(1, 3, 0); appInfo.apiVersion = VK_API_VERSION_1_3; + if ( uf::renderer::settings::version <= 1.0 ) { + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.apiVersion = VK_API_VERSION_1_0; + } else if ( uf::renderer::settings::version <= 1.1 ) { + appInfo.applicationVersion = VK_MAKE_VERSION(1, 1, 0); + appInfo.engineVersion = VK_MAKE_VERSION(1, 1, 0); + appInfo.apiVersion = VK_API_VERSION_1_1; + } else if ( uf::renderer::settings::version <= 1.2 ) { + appInfo.applicationVersion = VK_MAKE_VERSION(1, 2, 0); + appInfo.engineVersion = VK_MAKE_VERSION(1, 2, 0); + appInfo.apiVersion = VK_API_VERSION_1_2; + } else if ( uf::renderer::settings::version <= 1.3 ) { + appInfo.applicationVersion = VK_MAKE_VERSION(1, 3, 0); + appInfo.engineVersion = VK_MAKE_VERSION(1, 3, 0); + appInfo.apiVersion = VK_API_VERSION_1_3; + } + VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &appInfo; @@ -916,6 +934,7 @@ void ext::vulkan::Device::initialize() { size_t bestDeviceIndex = 0; for ( size_t i = 0; i < deviceCount; ++i ) { auto& deviceInfo = deviceInfos.emplace_back( rate(*this, physicalDevices[i]) ); + VK_VALIDATION_MESSAGE("[{}] Found device: {} (score: {} | device ID: {} | vendor ID: {} | API version: {} | driver version: {})", i, deviceInfo.properties.deviceName, deviceInfo.score, deviceInfo.properties.deviceID, deviceInfo.properties.vendorID, deviceInfo.properties.apiVersion, deviceInfo.properties.driverVersion ); /* VK_VALIDATION_MESSAGE("[" << i << "] " "Found device: " << deviceInfo.properties.deviceName << " (" @@ -926,6 +945,11 @@ void ext::vulkan::Device::initialize() { "driver version: " << deviceInfo.properties.driverVersion << ")" ); */ + if ( ext::vulkan::settings::gpuID == deviceInfo.properties.deviceID ) { + bestDeviceIndex = i; + break; + } + if ( settings::experimental::enableMultiGPU && deviceInfos[bestDeviceIndex].properties.vendorID != deviceInfo.properties.vendorID ) settings::experimental::enableMultiGPU = false; if ( deviceInfos[bestDeviceIndex].score >= deviceInfo.score ) continue; bestDeviceIndex = i; @@ -935,6 +959,7 @@ void ext::vulkan::Device::initialize() { } auto& deviceInfo = deviceInfos[bestDeviceIndex]; this->physicalDevice = deviceInfo.handle; + VK_VALIDATION_MESSAGE("Usind device #{}: (score: {} | device ID: {} | vendor ID: {} | API version: {} | driver version: {})", bestDeviceIndex, deviceInfo.properties.deviceName, deviceInfo.score, deviceInfo.properties.deviceID, deviceInfo.properties.vendorID, deviceInfo.properties.apiVersion, deviceInfo.properties.driverVersion ); /* VK_VALIDATION_MESSAGE("Using device #" << bestDeviceIndex << " (" "score: " << deviceInfo.score << " | " @@ -1095,10 +1120,16 @@ void ext::vulkan::Device::initialize() { deviceCreateInfo.ppEnabledExtensionNames = cDeviceExtensions.data(); } + struct BaseStructure { + VkStructureType sType; + void* pNext; + }; + std::queue chain = {}; + VkPhysicalDeviceFeatures2 physicalDeviceFeatures2{}; VkPhysicalDeviceVulkan12Features physicalDeviceVulkan12Features{}; - // VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures{}; - // VkPhysicalDeviceBufferDeviceAddressFeatures bufferDeviceAddresFeatures{}; + VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures{}; + VkPhysicalDeviceBufferDeviceAddressFeatures bufferDeviceAddressFeatures{}; VkPhysicalDeviceShaderDrawParametersFeatures shaderDrawParametersFeatures{}; VkPhysicalDeviceRobustness2FeaturesEXT robustnessFeatures{}; VkPhysicalDeviceRayTracingPipelineFeaturesKHR rayTracingPipelineFeatures{}; @@ -1118,75 +1149,97 @@ void ext::vulkan::Device::initialize() { vkGetPhysicalDeviceFeatures2(device.physicalDevice, &enabledDeviceFeatures2); } - { + if ( ext::vulkan::settings::requestedFeatureChain["physicalDevice2"].as(false) ) { physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; physicalDeviceFeatures2.features = enabledFeatures; + chain.push( &physicalDeviceFeatures2 ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "physicalDeviceFeatures2" ); } - { - + if ( ext::vulkan::settings::requestedFeatureChain["physicalDeviceVulkan12"].as(false) ) { physicalDeviceVulkan12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; enableRequestedDeviceFeatures12( enabledPhysicalDeviceVulkan12Features, physicalDeviceVulkan12Features ); + chain.push( &physicalDeviceVulkan12Features ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "physicalDeviceVulkan12Features" ); + } else { + if ( ext::vulkan::settings::requestedFeatureChain["descriptorIndexing"].as(false) ) { + // core for Vulkan 1.3+ + 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; + chain.push( &descriptorIndexingFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "descriptorIndexingFeatures" ); + } + // core for Vulkan 1.3+ + if ( ext::vulkan::settings::requestedFeatureChain["bufferDeviceAddress"].as(false) ) { + bufferDeviceAddressFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; + bufferDeviceAddressFeatures.bufferDeviceAddress = VK_TRUE; + chain.push( &bufferDeviceAddressFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "bufferDeviceAddressFeatures" ); + } } - /* - { - 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; - } - { - bufferDeviceAddresFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; - bufferDeviceAddresFeatures.bufferDeviceAddress = VK_TRUE; - } - */ - { + + // + if ( ext::vulkan::settings::requestedFeatureChain["shaderDrawParameters"].as(false) ) { shaderDrawParametersFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; shaderDrawParametersFeatures.shaderDrawParameters = VK_TRUE; + chain.push( &shaderDrawParametersFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "shaderDrawParametersFeatures" ); } - { + if ( ext::vulkan::settings::requestedFeatureChain["robustness"].as(false) ) { robustnessFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; robustnessFeatures.nullDescriptor = VK_TRUE; + chain.push( &robustnessFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "robustnessFeatures" ); } - { - rayTracingPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - rayTracingPipelineFeatures.rayTracingPipeline = VK_TRUE; - } - { - rayQueryFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; - rayQueryFeatures.rayQuery = VK_TRUE; - } - { - accelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - accelerationStructureFeatures.accelerationStructure = VK_TRUE; - // accelerationStructureFeatures.accelerationStructureHostCommands = VK_TRUE; - } - { + + if ( ext::vulkan::settings::requestedFeatureChain["shaderClock"].as(false) ) { shaderClockFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR; shaderClockFeatures.shaderSubgroupClock = VK_TRUE; shaderClockFeatures.shaderDeviceClock = VK_TRUE; + chain.push( &shaderClockFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "shaderClockFeatures" ); } - { + if ( ext::vulkan::settings::requestedFeatureChain["fragmentShaderBarycentric"].as(false) ) { fragmentShaderBarycentricFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR; fragmentShaderBarycentricFeatures.fragmentShaderBarycentric = VK_TRUE; + chain.push( &fragmentShaderBarycentricFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "fragmentShaderBarycentricFeatures" ); } - { + if ( ext::vulkan::settings::requestedFeatureChain["rayTracingPipeline"].as(false) ) { + rayTracingPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + rayTracingPipelineFeatures.rayTracingPipeline = VK_TRUE; + chain.push( &rayTracingPipelineFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "rayTracingPipelineFeatures" ); + } + if ( ext::vulkan::settings::requestedFeatureChain["rayQuery"].as(false) ) { + rayQueryFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; + rayQueryFeatures.rayQuery = VK_TRUE; + chain.push( &rayQueryFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "rayQueryFeatures" ); + } + if ( ext::vulkan::settings::requestedFeatureChain["accelerationStructure"].as(false) ) { + accelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + accelerationStructureFeatures.accelerationStructure = VK_TRUE; + // accelerationStructureFeatures.accelerationStructureHostCommands = VK_TRUE; + chain.push( &accelerationStructureFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "accelerationStructureFeatures" ); + } + if ( ext::vulkan::settings::requestedFeatureChain["subgroupSizeControl"].as(false) ) { subgroupSizeControlFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES; - subgroupSizeControlFeatures.subgroupSizeControl = true; + subgroupSizeControlFeatures.subgroupSizeControl = VK_TRUE; + chain.push( &subgroupSizeControlFeatures ); + VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "subgroupSizeControlFeatures" ); + } + + BaseStructure* next = (BaseStructure*) &deviceCreateInfo; + while ( !chain.empty() ) { + BaseStructure* front = (BaseStructure*) chain.front(); + next->pNext = front; + next = front; + chain.pop(); } - - deviceCreateInfo.pNext = &physicalDeviceFeatures2; - physicalDeviceFeatures2.pNext = &physicalDeviceVulkan12Features; - physicalDeviceVulkan12Features.pNext = &shaderDrawParametersFeatures; - // descriptorIndexingFeatures.pNext = &bufferDeviceAddresFeatures; - // bufferDeviceAddresFeatures.pNext = &shaderDrawParametersFeatures; - shaderDrawParametersFeatures.pNext = &robustnessFeatures; - robustnessFeatures.pNext = &rayTracingPipelineFeatures; - rayTracingPipelineFeatures.pNext = &rayQueryFeatures; - rayQueryFeatures.pNext = &accelerationStructureFeatures; - accelerationStructureFeatures.pNext = &shaderClockFeatures; - shaderClockFeatures.pNext = &fragmentShaderBarycentricFeatures; - fragmentShaderBarycentricFeatures.pNext = &subgroupSizeControlFeatures; if ( settings::experimental::enableMultiGPU ) { UF_MSG_DEBUG("Multiple devices supported, using {} devices...", groupDeviceCreateInfo.physicalDeviceCount); @@ -1207,6 +1260,13 @@ void ext::vulkan::Device::initialize() { VK_VALIDATION_MESSAGE("{}", payload.dump()); uf::hooks.call("vulkan:Device.FeaturesEnabled", payload); } + /* + { + ext::json::Value payload = retrieveDeviceFeatures12( *this ); + VK_VALIDATION_MESSAGE("{}", payload.dump()); + uf::hooks.call("vulkan:Device.FeaturesEnabled", payload); + } + */ } // Create command pool getCommandPool( QueueEnum::GRAPHICS ); @@ -1355,12 +1415,28 @@ void ext::vulkan::Device::initialize() { vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr; VmaAllocatorCreateInfo allocatorInfo = {}; - allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3; + allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2; allocatorInfo.physicalDevice = physicalDevice; allocatorInfo.instance = instance; allocatorInfo.device = logicalDevice; - allocatorInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; allocatorInfo.pVulkanFunctions = &vulkanFunctions; + + if ( uf::renderer::settings::version <= 1.0 ) allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0; + else if ( uf::renderer::settings::version <= 1.1 ) allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_1; + else if ( uf::renderer::settings::version <= 1.2 ) allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_2; + // else if ( uf::renderer::settings::version <= 1.3 ) allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3; + + if ( uf::renderer::settings::invariant::deviceAddressing ) { + allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; + } else { + allocatorInfo.flags = 0; + } + if ( uf::renderer::settings::experimental::memoryBudgetBit ) { + UF_MSG_DEBUG("MEMORY BUDGET BIT SET"); + allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; + } + + UF_MSG_DEBUG("Allocator flags: {}", allocatorInfo.flags); vmaCreateAllocator(&allocatorInfo, &allocator); } diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index b20252b2..4a2e1fd2 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -524,33 +524,33 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip if ( !buffer ) continue; if ( buffer->usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer->descriptor); - if ( buffer->usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer->descriptor); + if ( buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) infos.storage.emplace_back(buffer->descriptor); } #if 0 // add per-rendermode buffers for ( auto& buffer : renderMode.buffers ) { if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor); - if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor); - // if ( buffer.usage & uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE ) infos.accelerationStructure.emplace_back(buffer.descriptor); + if ( buffer.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) infos.storage.emplace_back(buffer.descriptor); + // if ( buffer.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) infos.accelerationStructure.emplace_back(buffer.descriptor); } #endif // add per-shader buffers for ( auto& buffer : shader->buffers ) { if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor); - if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor); - // if ( buffer.usage & uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE ) infos.accelerationStructure.emplace_back(buffer.descriptor); + if ( buffer.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) infos.storage.emplace_back(buffer.descriptor); + // if ( buffer.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) infos.accelerationStructure.emplace_back(buffer.descriptor); } // add per-pipeline buffers for ( auto& buffer : this->buffers ) { if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor); - if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor); - // if ( buffer.usage & uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE ) infos.accelerationStructure.emplace_back(buffer.descriptor); + if ( buffer.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) infos.storage.emplace_back(buffer.descriptor); + // if ( buffer.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) infos.accelerationStructure.emplace_back(buffer.descriptor); } // add per-graphics buffers for ( auto& buffer : graphic.buffers ) { if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor); - if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor); - // if ( buffer.usage & uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE ) infos.accelerationStructure.emplace_back(buffer.descriptor); + if ( buffer.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) infos.storage.emplace_back(buffer.descriptor); + // if ( buffer.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) infos.accelerationStructure.emplace_back(buffer.descriptor); } if ( descriptor.subpass < renderTarget.passes.size() ) { @@ -1093,7 +1093,8 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) { }; uf::stl::vector queue; descriptor.inputs.bufferOffset = buffers.size(); // buffers.empty() ? 0 : buffers.size() - 1; - VkBufferUsageFlags baseUsage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + VkBufferUsageFlags baseUsage = uf::renderer::settings::invariant::deviceAddressing ? VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0; + // VkBufferUsageFlags baseUsage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; #define PARSE_INPUT(name, usage){\ if ( mesh.isInterleaved( mesh.name.interleaved ) ) {\ @@ -1114,10 +1115,10 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) { // allocate buffers auto previousRequestedAlignment = this->requestedAlignment; this->requestedAlignment = 16; - PARSE_INPUT(vertex, uf::renderer::enums::Buffer::VERTEX) - PARSE_INPUT(index, uf::renderer::enums::Buffer::INDEX) - PARSE_INPUT(instance, uf::renderer::enums::Buffer::VERTEX) - PARSE_INPUT(indirect, uf::renderer::enums::Buffer::INDIRECT | uf::renderer::enums::Buffer::STORAGE) + PARSE_INPUT(vertex, uf::renderer::enums::Buffer::VERTEX ) + PARSE_INPUT(index, uf::renderer::enums::Buffer::INDEX ) + PARSE_INPUT(instance, uf::renderer::enums::Buffer::VERTEX ) + PARSE_INPUT(indirect, uf::renderer::enums::Buffer::INDIRECT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) this->requestedAlignment = previousRequestedAlignment; } @@ -1360,7 +1361,7 @@ void ext::vulkan::Graphic::generateBottomAccelerationStructures() { } // create BLAS buffer and handle - size_t blasBufferIndex = this->initializeBuffer( NULL, totalBlasBufferSize, uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE | uf::renderer::enums::Buffer::ADDRESS ); + size_t blasBufferIndex = this->initializeBuffer( NULL, totalBlasBufferSize, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT ); this->metadata.buffers["blasBuffer"] = blasBufferIndex; VkQueryPool queryPool{VK_NULL_HANDLE}; @@ -1445,7 +1446,7 @@ void ext::vulkan::Graphic::generateBottomAccelerationStructures() { ext::vulkan::Buffer oldBuffer; oldBuffer.alignment = acclerationStructureProperties.minAccelerationStructureScratchOffsetAlignment; - oldBuffer.initialize( NULL, totalBlasBufferSize, uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE | uf::renderer::enums::Buffer::ADDRESS ); + oldBuffer.initialize( NULL, totalBlasBufferSize, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT ); this->buffers[blasBufferIndex].swap(oldBuffer); size_t blasBufferOffset{}; @@ -1547,7 +1548,7 @@ void ext::vulkan::Graphic::generateTopAccelerationStructure( const uf::stl::vect // do not stage, because apparently vkQueueWaitIdle doesn't actually wait for the transfer to complete instanceIndex = this->initializeBuffer( (const void*) instancesVK.data(), instancesVK.size() * sizeof(VkAccelerationStructureInstanceKHR), - uf::renderer::enums::Buffer::ADDRESS | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, false + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, false ); this->metadata.buffers["tlasInstance"] = instanceIndex; } else { @@ -1601,7 +1602,7 @@ void ext::vulkan::Graphic::generateTopAccelerationStructure( const uf::stl::vect ); // create BLAS buffer and handle - auto tlasBufferUsageFlags = uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE | uf::renderer::enums::Buffer::ADDRESS; + auto tlasBufferUsageFlags = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; if ( !update ) { const size_t EXTRANEOUS_SIZE = 1024 * 1024; // oversize, to avoid having to constantly resize size_t bufferSize = MAX( sizeInfo.accelerationStructureSize, EXTRANEOUS_SIZE ); @@ -1711,7 +1712,7 @@ void ext::vulkan::Graphic::generateTopAccelerationStructure( const uf::stl::vect // UF_MSG_DEBUG("Reduced size to {}% ({} -> {} = {})", (float) (oldSize - compactedSize) / (float) (oldSize), oldSize, compactedSize, oldSize - compactedSize); ext::vulkan::Buffer oldBuffer; - oldBuffer.initialize( NULL, tlasBufferSize, uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE | uf::renderer::enums::Buffer::ADDRESS | uf::renderer::enums::Buffer::STORAGE ); + oldBuffer.initialize( NULL, tlasBufferSize, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ); this->buffers[tlasBufferIndex].swap(oldBuffer); tlas.buffer = this->buffers[tlasBufferIndex].alias(); diff --git a/engine/src/ext/vulkan/rendermodes/base.cpp b/engine/src/ext/vulkan/rendermodes/base.cpp index af88990b..d8c4f755 100644 --- a/engine/src/ext/vulkan/rendermodes/base.cpp +++ b/engine/src/ext/vulkan/rendermodes/base.cpp @@ -131,12 +131,14 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vectorpipelineBarrier( commands[i], 0 ); } */ + /* for ( auto _ : layers ) { RenderTargetRenderMode* layer = (RenderTargetRenderMode*) _; auto& blitter = layer->blitter; if ( !blitter.initialized || !blitter.process || blitter.descriptor.renderMode != this->getName() ) continue; layer->pipelineBarrier( commands[i], 0 ); } + */ // pre-renderpass commands if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commands[i], i ); @@ -154,7 +156,6 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vectorblitter; if ( !blitter.initialized || !blitter.process || blitter.descriptor.subpass != currentPass || blitter.descriptor.renderMode != this->getName() ) continue; - // UF_MSG_DEBUG("`{}`: {} | `{}` | {} | {} | {}", layer->getName(), layer->getType(), blitter.descriptor.renderMode, blitter.initialized, blitter.process, blitter.descriptor.subpass); ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; // bindGraphicDescriptor(blitter.descriptor, currentSubpass); blitter.record(commands[i], descriptor); } @@ -186,12 +187,14 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vectorblitter; if ( !blitter.initialized || !blitter.process || blitter.descriptor.renderMode != this->getName() ) continue; layer->pipelineBarrier( commands[i], 1 ); } + */ /* for ( auto layer : layers ) { layer->pipelineBarrier( commands[i], 1 ); @@ -300,7 +303,8 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) { VK_CHECK_RESULT(vkCreateImageView( device, &colorAttachmentView, nullptr, &renderTarget.attachments[i].view)); renderTarget.attachments[i].descriptor.format = ext::vulkan::settings::formats::color; - renderTarget.attachments[i].descriptor.layout = VK_IMAGE_LAYOUT_UNDEFINED; + // renderTarget.attachments[i].descriptor.layout = VK_IMAGE_LAYOUT_UNDEFINED; + renderTarget.attachments[i].descriptor.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; renderTarget.attachments[i].descriptor.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; renderTarget.attachments[i].descriptor.aliased = true; renderTarget.attachments[i].image = images[i]; @@ -330,6 +334,13 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) { VmaAllocationCreateInfo allocInfo = {}; allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; VK_CHECK_RESULT(vmaCreateImage(allocator, &imageCreateInfo, &allocInfo, &attachment.image, &attachment.allocation, &attachment.allocationInfo)); + + + attachment.descriptor.format = ext::vulkan::settings::formats::depth; + // attachment.descriptor.layout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.descriptor.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachment.descriptor.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + attachment.descriptor.aliased = true; attachment.mem = attachment.allocationInfo.deviceMemory; VkImageViewCreateInfo depthStencilView = {}; @@ -346,6 +357,39 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) { VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &attachment.view)); } + +#if 1 + auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS); + for ( auto& attachment : renderTarget.attachments ) { + bool isDepth = attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + if ( isDepth ) { + // transition attachments to general attachments for imageStore + VkImageSubresourceRange subresourceRange; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.baseArrayLayer = 0; + subresourceRange.layerCount = 1; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + subresourceRange.layerCount = 1; + + uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, subresourceRange ); + } else { + // transition attachments to general attachments for imageStore + VkImageSubresourceRange subresourceRange; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.baseArrayLayer = 0; + subresourceRange.layerCount = 1; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.layerCount = 1; + + uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, subresourceRange ); + } + } + device.flushCommandBuffer(commandBuffer, uf::renderer::QueueEnum::GRAPHICS); +#endif + // Create FSR dump /* if ( settings::pipelines::fsr ) { diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index c4491ebb..e29b5d7f 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -684,10 +684,30 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto size_t currentSubpass = 0; + /* // transition layers for read for ( auto layer : layers ) { layer->pipelineBarrier( commandBuffer, 0 ); } + */ + // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + + // VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL + // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL + + #if 1 + for ( auto& attachment : renderTarget.attachments ) { + // transition attachments to general attachments for imageStore + VkImageSubresourceRange subresourceRange; + subresourceRange.baseMipLevel = 0; + subresourceRange.baseArrayLayer = 0; + subresourceRange.levelCount = attachment.descriptor.mips; + subresourceRange.layerCount = renderTarget.views; + subresourceRange.aspectMask = attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, attachment.descriptor.layout, subresourceRange ); + } + #endif for ( auto& pipeline : metadata.pipelines ) { if ( pipeline == metadata.pipeline ) continue; @@ -743,6 +763,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto } vkCmdEndRenderPass(commandBuffer); + #if 1 if ( settings::pipelines::deferred && DEFERRED_MODE == "compute" && blitter.material.hasShader(DEFERRED_MODE, "deferred") ) { auto& shader = blitter.material.getShader(DEFERRED_MODE, "deferred"); ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; @@ -876,10 +897,13 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto #endif } #endif + #endif + /* for ( auto layer : layers ) { layer->pipelineBarrier( commandBuffer, 1 ); } + */ } VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer)); diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 34438b5e..91bcd08a 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -498,9 +498,32 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v size_t subpasses = renderTarget.passes.size(); size_t currentPass = 0; + + // + // this->pipelineBarrier( commands[i], 1 ); + + // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + + // VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL + // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL + + #if 1 + for ( auto& attachment : renderTarget.attachments ) { + // transition attachments to general attachments for imageStore + VkImageSubresourceRange subresourceRange; + subresourceRange.baseMipLevel = 0; + subresourceRange.baseArrayLayer = 0; + subresourceRange.levelCount = attachment.descriptor.mips; + subresourceRange.layerCount = renderTarget.views; + subresourceRange.aspectMask = attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, attachment.descriptor.layout, subresourceRange ); + } + #endif + // pre-renderpass commands if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commandBuffer, i ); - + if ( this->getName() == "Compute" ) { for ( auto graphic : graphics ) { if ( graphic->descriptor.renderMode != this->getTarget() ) continue; @@ -508,18 +531,6 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v graphic->record( commandBuffer ); } } else { - #if 0 - for ( auto& pipeline : metadata.pipelines ) { - if ( pipeline == metadata.pipeline ) continue; - for ( auto graphic : graphics ) { - if ( graphic->descriptor.renderMode != this->getTarget() ) continue; - ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentPass); - descriptor.pipeline = pipeline; - if ( pipeline == "rt" ) descriptor.bind.point = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; - graphic->record( commandBuffer, descriptor, 0, metadata.type == uf::renderer::settings::pipelines::names::vxgi ? 0 : MIN(subpasses,6) ); - } - } - #endif for ( auto& pipeline : metadata.pipelines ) { if ( pipeline == metadata.pipeline ) continue; for ( auto graphic : graphics ) { @@ -558,9 +569,12 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v } vkCmdEndRenderPass(commandBuffer); } + // post-renderpass commands if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commandBuffer, i ); + + // this->pipelineBarrier( commands[i], 1 ); } VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer)); diff --git a/engine/src/ext/vulkan/rendertarget.cpp b/engine/src/ext/vulkan/rendertarget.cpp index 6b392d6c..3e84051d 100644 --- a/engine/src/ext/vulkan/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendertarget.cpp @@ -68,6 +68,8 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript } attachment->views.resize(this->views * attachment->descriptor.mips); + bool isDepth = attachment->descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + VkImageCreateInfo imageCreateInfo = {}; imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; @@ -79,6 +81,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = attachment->descriptor.usage; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if ( this->views == 6 ) { imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; } @@ -93,7 +96,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript VkImageAspectFlags aspectMask = 0; // specialization: depth buffer - if ( attachment->descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) { + if ( isDepth ) { aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; // | VK_IMAGE_ASPECT_STENCIL_BIT; } else { aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -144,6 +147,32 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript attachment->blendState = blendAttachmentState; } + if ( false ) { + auto commandBuffer = device->fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS); + if ( isDepth ) { + // transition attachments to general attachments for imageStore + VkImageSubresourceRange subresourceRange; + subresourceRange.baseMipLevel = 0; + subresourceRange.baseArrayLayer = 0; + subresourceRange.levelCount = attachment->descriptor.mips; + subresourceRange.layerCount = this->views; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + uf::renderer::Texture::setImageLayout( commandBuffer, attachment->image, VK_IMAGE_LAYOUT_UNDEFINED, attachment->descriptor.layout, subresourceRange ); + } else { + // transition attachments to general attachments for imageStore + VkImageSubresourceRange subresourceRange; + subresourceRange.baseMipLevel = 0; + subresourceRange.baseArrayLayer = 0; + subresourceRange.levelCount = attachment->descriptor.mips; + subresourceRange.layerCount = this->views; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + uf::renderer::Texture::setImageLayout( commandBuffer, attachment->image, VK_IMAGE_LAYOUT_UNDEFINED, attachment->descriptor.layout, subresourceRange ); + } + device->flushCommandBuffer(commandBuffer, uf::renderer::QueueEnum::GRAPHICS); + } + return index; } void ext::vulkan::RenderTarget::initialize( Device& device ) { @@ -332,6 +361,41 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &framebuffers[i])); } } + +#if 0 + { + auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::TRANSFER); + for ( auto& attachment : attachments ) { + bool isDepth = attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + + if ( isDepth ) { + // transition attachments to general attachments for imageStore + VkImageSubresourceRange subresourceRange; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.baseArrayLayer = 0; + subresourceRange.layerCount = 1; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + subresourceRange.layerCount = 1; + + uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, subresourceRange ); + } else { + // transition attachments to general attachments for imageStore + VkImageSubresourceRange subresourceRange; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.baseArrayLayer = 0; + subresourceRange.layerCount = 1; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.layerCount = 1; + + uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_UNDEFINED, attachment.descriptor.layout, subresourceRange ); + } + } + device.flushCommandBuffer(commandBuffer); + } +#endif + initialized = true; } diff --git a/engine/src/ext/vulkan/texture.cpp b/engine/src/ext/vulkan/texture.cpp index 98c2c557..a4245375 100644 --- a/engine/src/ext/vulkan/texture.cpp +++ b/engine/src/ext/vulkan/texture.cpp @@ -494,6 +494,7 @@ void ext::vulkan::Texture::fromBuffers( VkImageLayout imageLayout ) { this->initialize(device, texWidth, texHeight, texDepth, layers); + this->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; if ( this->mips == 0 ) { this->mips = 1; @@ -515,6 +516,7 @@ void ext::vulkan::Texture::fromBuffers( if ( std::find( queueFamilyIndices.begin(), queueFamilyIndices.end(), device.queueFamilyIndices.compute ) == queueFamilyIndices.end() ) queueFamilyIndices.emplace_back(device.queueFamilyIndices.compute); if ( std::find( queueFamilyIndices.begin(), queueFamilyIndices.end(), device.queueFamilyIndices.transfer ) == queueFamilyIndices.end() ) queueFamilyIndices.emplace_back(device.queueFamilyIndices.transfer); + bool exclusive = device.queueFamilyIndices.graphics == 0 && device.queueFamilyIndices.present == 0 && device.queueFamilyIndices.compute == 0 && device.queueFamilyIndices.transfer == 0; // Create optimal tiled target image VkImageCreateInfo imageCreateInfo = ext::vulkan::initializers::imageCreateInfo(); @@ -528,7 +530,7 @@ void ext::vulkan::Texture::fromBuffers( imageCreateInfo.pQueueFamilyIndices = queueFamilyIndices.data(); // imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.sharingMode = exclusive ? VK_SHARING_MODE_EXCLUSIVE : VK_SHARING_MODE_CONCURRENT; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCreateInfo.initialLayout = this->imageLayout; imageCreateInfo.extent = { width, height, depth }; imageCreateInfo.usage = imageUsageFlags; // Ensure that the TRANSFER_SRC bit is set for mip creation @@ -570,6 +572,12 @@ void ext::vulkan::Texture::fromBuffers( viewCreateInfo.image = image; VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view)); + { + auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS); + uf::renderer::Texture::setImageLayout( commandBuffer, image, VK_IMAGE_LAYOUT_UNDEFINED, (this->imageLayout = imageLayout), viewCreateInfo.subresourceRange ); + device.flushCommandBuffer(commandBuffer, uf::renderer::QueueEnum::GRAPHICS, true); + } + if ( data && bufferSize ) { uint8_t* layerPointer = (uint8_t*) data; VkDeviceSize layerSize = bufferSize / this->layers; @@ -577,7 +585,9 @@ void ext::vulkan::Texture::fromBuffers( this->update( (void*) layerPointer, layerSize, imageLayout, layer ); layerPointer += layerSize; } - } else { + } +/* + else { // Create image view VkImageSubresourceRange subresourceRange = {}; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -594,10 +604,11 @@ void ext::vulkan::Texture::fromBuffers( imageLayout, subresourceRange ); - device.flushCommandBuffer(commandBuffer); + device.flushCommandBuffer(commandBuffer, QueueEnum::GRAPHICS, true); this->imageLayout = imageLayout; } +*/ this->updateDescriptors(); } diff --git a/engine/src/ext/vulkan/vulkan.cpp b/engine/src/ext/vulkan/vulkan.cpp index f7c9d54b..3529992e 100644 --- a/engine/src/ext/vulkan/vulkan.cpp +++ b/engine/src/ext/vulkan/vulkan.cpp @@ -21,6 +21,7 @@ namespace { } auxFences; } +float ext::vulkan::settings::version = 1.3; uint32_t ext::vulkan::settings::width = 1280; uint32_t ext::vulkan::settings::height = 720; uint8_t ext::vulkan::settings::msaa = 1; @@ -39,6 +40,7 @@ uf::stl::vector ext::vulkan::settings::validationFilters; uf::stl::vector ext::vulkan::settings::requestedDeviceFeatures; uf::stl::vector ext::vulkan::settings::requestedDeviceExtensions; uf::stl::vector ext::vulkan::settings::requestedInstanceExtensions; +uf::Serializer ext::vulkan::settings::requestedFeatureChain; VkFilter ext::vulkan::settings::swapchainUpscaleFilter = VK_FILTER_LINEAR; @@ -48,11 +50,13 @@ bool ext::vulkan::settings::experimental::batchQueueSubmissions = true; bool ext::vulkan::settings::experimental::rebuildOnTickBegin = false; bool ext::vulkan::settings::experimental::enableMultiGPU = false; +bool ext::vulkan::settings::experimental::memoryBudgetBit = true; // not so experimental bool ext::vulkan::settings::invariant::waitOnRenderEnd = false; bool ext::vulkan::settings::invariant::individualPipelines = true; bool ext::vulkan::settings::invariant::multithreadedRecording = true; +bool ext::vulkan::settings::invariant::deviceAddressing = false; uf::stl::string ext::vulkan::settings::invariant::deferredMode = ""; @@ -280,10 +284,12 @@ void ext::vulkan::initialize() { device.initialize(); swapchain.initialize( device ); - ext::vulkan::scratchBuffer.alignment = ext::vulkan::settings::scratchBufferAlignment; - ext::vulkan::scratchBuffer.initialize( NULL, ext::vulkan::settings::scratchBufferInitialSize, - uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE | uf::renderer::enums::Buffer::ADDRESS | uf::renderer::enums::Buffer::STORAGE - ); + if ( uf::renderer::settings::invariant::deviceAddressing ) { + ext::vulkan::scratchBuffer.alignment = ext::vulkan::settings::scratchBufferAlignment; + ext::vulkan::scratchBuffer.initialize( NULL, ext::vulkan::settings::scratchBufferInitialSize, + uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE | uf::renderer::enums::Buffer::ADDRESS | uf::renderer::enums::Buffer::STORAGE + ); + } if ( uf::io::exists(uf::io::root + "/textures/missing.png") ) { uf::Image image; diff --git a/engine/src/utils/component/component.cpp b/engine/src/utils/component/component.cpp index 96385c4d..9ddd72d4 100644 --- a/engine/src/utils/component/component.cpp +++ b/engine/src/utils/component/component.cpp @@ -5,6 +5,40 @@ uf::Component::~Component() { this->destroyComponents(); } +#if UF_COMPONENT_POINTERED_USERDATA +pod::PointeredUserdata uf::Component::addComponent( pod::PointeredUserdata& userdata ) { + pod::Component::id_t id = userdata.type; + pod::Component& component = this->m_container[id]; + component.id = id; + component.userdata = uf::pointeredUserdata::copy( userdata ); + return component.userdata; +} +pod::PointeredUserdata uf::Component::moveComponent( pod::PointeredUserdata& userdata ) { + pod::Component::id_t id = userdata.type; + pod::Component& component = this->m_container[id]; + component.id = id; + component.userdata = userdata; + userdata.data = NULL; + return component.userdata; +} +#else +pod::Userdata* uf::Component::addComponent( pod::Userdata* userdata ) { + pod::Component::id_t id = userdata->type; + pod::Component& component = this->m_container[id]; + component.id = id; + component.userdata = uf::userdata::copy( userdata ); + return component.userdata; +} +pod::Userdata* uf::Component::moveComponent( pod::Userdata*& userdata ) { + pod::Component::id_t id = userdata->type; + pod::Component& component = this->m_container[id]; + component.id = id; + component.userdata = userdata; + userdata = NULL; + return component.userdata; +} +#endif + void uf::Component::destroyComponents() { for ( auto& kv : this->m_container ) { pod::Component& component = kv.second; diff --git a/engine/src/utils/io/fmt.cpp b/engine/src/utils/io/fmt.cpp index 9c247296..11432460 100644 --- a/engine/src/utils/io/fmt.cpp +++ b/engine/src/utils/io/fmt.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #if UF_USE_IMGUI @@ -14,11 +15,13 @@ uf::stl::string uf::io::log( const uf::stl::string& category, const uf::stl::str #if UF_USE_FMT auto string = ::fmt::format("[{}] [{}:{}@{}]: {}", category, file, function, line, message); ::fmt::print("{}\n", string); + uf::iostream.pushHistory(string); #else std::stringstream ss; ss << "[" << category << "] [" << file << ":" << function << "@" << line << "]: " << message << "\n"; auto string = ss.str(); std::cout << string; + uf::iostream.pushHistory(string); #endif std::cout.flush(); diff --git a/engine/src/utils/io/iostream.cpp b/engine/src/utils/io/iostream.cpp index b42b2f7a..e2105d89 100644 --- a/engine/src/utils/io/iostream.cpp +++ b/engine/src/utils/io/iostream.cpp @@ -74,6 +74,9 @@ uf::stl::string uf::IoStream::getBuffer() { uf::stl::vector uf::IoStream::getHistory() { return ::info.output.history; } +void uf::IoStream::pushHistory( const uf::stl::string& str ) { + ::info.output.history.emplace_back(str); +} void uf::IoStream::back() { } char uf::IoStream::readChar(const bool& loop) { diff --git a/ext/behaviors/craeture/behavior.cpp b/ext/behaviors/craeture/behavior.cpp index a8ace88a..b6bb9531 100644 --- a/ext/behaviors/craeture/behavior.cpp +++ b/ext/behaviors/craeture/behavior.cpp @@ -23,7 +23,7 @@ UF_BEHAVIOR_REGISTER_CPP(ext::CraetureBehavior) UF_BEHAVIOR_TRAITS_CPP(ext::CraetureBehavior, ticks = false, renders = false, multithread = false) #define this (&self) namespace { - void load( uf::Object& self, uf::Image& image ) { + void load( uf::Object& self, const uf::Image& image ) { auto& graphic = self.getComponent(); auto& texture = graphic.material.textures.emplace_back(); texture.loadFromImage( image ); @@ -50,12 +50,10 @@ namespace { } void ext::CraetureBehavior::initialize( uf::Object& self ) { this->addHook( "asset:Load.%UID%", [&](pod::payloads::assetLoad& payload){ - if ( !uf::Asset::isExpected( payload, uf::Asset::Type::IMAGE ) ) return; + if ( !uf::asset::isExpected( payload, uf::asset::Type::IMAGE ) ) return; + if ( !uf::asset::has( payload ) ) uf::asset::load( payload ); + const auto& image = uf::asset::get( payload ); - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Asset& assetLoader = scene.getComponent(); - if ( !assetLoader.has(payload.filename) ) return; - auto& image = assetLoader.get(payload.filename); ::load( self, image ); }); diff --git a/ext/behaviors/player/behavior.cpp b/ext/behaviors/player/behavior.cpp index 160bc27e..87706dad 100644 --- a/ext/behaviors/player/behavior.cpp +++ b/ext/behaviors/player/behavior.cpp @@ -75,8 +75,8 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { } // sloppy - metadata.mouse.sensitivity = uf::vector::decode( ext::config["window"]["cursor"]["sensitivity"], metadata.mouse.sensitivity ); - metadata.mouse.smoothing = uf::vector::decode( ext::config["window"]["cursor"]["smoothing"], metadata.mouse.smoothing ); + metadata.mouse.sensitivity = uf::vector::decode( ext::config["window"]["mouse"]["sensitivity"], metadata.mouse.sensitivity ); + metadata.mouse.smoothing = uf::vector::decode( ext::config["window"]["mouse"]["smoothing"], metadata.mouse.smoothing ); this->addHook( "window:Mouse.CursorVisibility", [&](pod::payloads::windowMouseCursorVisibility& payload){ metadata.system.control = !payload.mouse.visible; @@ -512,7 +512,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { combinedDeltaOrientation = uf::quaternion::multiply( deltaOrientation, combinedDeltaOrientation );\ storedCameraOrientation = ORIENTATION;\ } - { + if ( false ) { pod::Quaternion<> combinedDeltaOrientation = {0,0,0,1}; pod::Vector3f combinedDeltaAngles = {}; TRACK_ORIENTATION(transform.orientation); diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index 040637cb..23ba46be 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -37,7 +37,7 @@ UF_BEHAVIOR_REGISTER_CPP(ext::ExtSceneBehavior) UF_BEHAVIOR_TRAITS_CPP(ext::ExtSceneBehavior, ticks = true, renders = false, multithread = false) // hangs on initialization #define this ((uf::Scene*) &self) void ext::ExtSceneBehavior::initialize( uf::Object& self ) { - auto& assetLoader = this->getComponent(); +// auto& assetLoader = this->getComponent(); auto& metadata = this->getComponent(); auto& metadataJson = this->getComponent(); @@ -47,15 +47,11 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { }); this->addHook( "asset:Load.%UID%", [&](pod::payloads::assetLoad& payload){ - if ( !uf::Asset::isExpected( payload, uf::Asset::Type::AUDIO ) ) return; - - if ( !assetLoader.has(payload.filename) ) return; - auto& asset = assetLoader.get(payload.filename); - auto& audio = this->getComponent(); - - audio.destroy(); - audio = std::move(asset); - assetLoader.remove(payload.filename); + if ( !uf::asset::isExpected( payload, uf::asset::Type::AUDIO ) ) return; + // if ( !uf::asset::has( payload ) ) uf::asset::load( payload ); + auto& audio = uf::asset::get( payload ); + // if ( !uf::asset::has(payload.filename) ) uf::asset::load( payload ); + // auto& audio = this->getComponent(); #if UF_AUDIO_MAPPED_VOLUMES audio.setVolume(uf::audio::volumes.count("bgm") > 0 ? uf::audio::volumes.at("bgm") : 1.0); @@ -64,6 +60,10 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { #endif audio.loop( true ); audio.play(); + + if ( !payload.asComponent ) { + this->moveComponent( uf::asset::get( payload.filename ) ); + } }); this->addHook( "menu:Open", [&](pod::payloads::menuOpen& payload){ @@ -78,7 +78,9 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { }; }); this->addHook( "world:Entity.LoadAsset", [&](pod::payloads::assetLoad& payload){ - assetLoader.load("asset:Load." + std::to_string(payload.uid), payload); + if ( !payload.object ) return; + + uf::asset::load("asset:Load." + std::to_string(payload.object.uid), payload); }); this->addHook( "shader:Update.%UID%", [&](ext::json::Value& json){ metadata.shader.mode = json["mode"].as(); @@ -208,8 +210,8 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { #endif } void ext::ExtSceneBehavior::tick( uf::Object& self ) { - auto& assetLoader = this->getComponent(); - assetLoader.processQueue(); +// auto& assetLoader = this->getComponent(); + uf::asset::processQueue(); auto& metadata = this->getComponent(); auto& metadataJson = this->getComponent(); @@ -242,7 +244,8 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { // uf::renderer::states::frameAccumulateReset = metadata.shader.frameAccumulateReset; /* Print World Tree */ { - TIMER(1, uf::inputs::kbm::states::U ) { + TIMER(1, uf::inputs::kbm::states::U || uf::scene::printTaskCalls ) + { std::function filter = []( uf::Entity* entity, int indent ) { for ( int i = 0; i < indent; ++i ) uf::iostream << "\t"; uf::iostream << uf::string::toString(entity->as()) << " "; @@ -345,9 +348,9 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { if ( (current + epsilon >= end || !bgm.playing()) && !bgm.loops() ) { // intro to main transition uf::stl::string filename = bgm.getFilename(); - filename = assetLoader.getOriginal(filename); + filename = uf::asset::getOriginal(filename); if ( filename.find("_intro") != uf::stl::string::npos ) { - assetLoader.load(uf::string::replace( filename, "_intro", "" ), this->formatHookName("asset:Load.%UID%")); + uf::asset::load(uf::string::replace( filename, "_intro", "" ), this->formatHookName("asset:Load.%UID%")); // loop } else { bgm.setTime(0); diff --git a/ext/behaviors/soundemitter/behavior.cpp b/ext/behaviors/soundemitter/behavior.cpp index 2e8c1f99..c079a281 100644 --- a/ext/behaviors/soundemitter/behavior.cpp +++ b/ext/behaviors/soundemitter/behavior.cpp @@ -17,7 +17,7 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { auto& sounds = emitter.get(); auto& scene = uf::scene::getCurrentScene(); - auto& assetLoader = scene.getComponent(); +// auto& assetLoader = scene.getComponent(); if ( !metadata["audio"]["epsilon"].is() ) metadata["audio"]["epsilon"] = 0.001f; @@ -49,12 +49,7 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { uf::Audio& audio = exists ? emitter.get( filename ) : emitter.add(); if ( !exists ) { - if ( assetLoader.has(filename) ) { - audio = std::move( assetLoader.get(filename) ); - assetLoader.remove(filename); - } else { - audio.open( filename, json["streamed"].as() ); - } + audio.open( filename, json["streamed"].as() ); } if ( json["pitch"].is() ) audio.setPitch(json["pitch"].as()); @@ -80,9 +75,9 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { audio.play(); }); this->addHook( "asset:Load.%UID%", [&](pod::payloads::assetLoad& payload){ - if ( !uf::Asset::isExpected( payload, uf::Asset::Type::AUDIO ) ) return; - - if ( !assetLoader.has(payload.filename) ) return; + if ( !uf::asset::isExpected( payload, uf::asset::Type::AUDIO ) ) return; + if ( !uf::asset::has( payload ) ) uf::asset::load( payload ); + const auto& audio = uf::asset::get( payload ); ext::json::Value json = metadata["audio"]; json["filename"] = payload.filename; diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index 143a89dd..954fc684 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -335,7 +335,7 @@ uf::stl::vector ext::Gui::generateGlyphs( const uf::stl::string& void ext::Gui::load( const uf::Image& image ) { auto& scene = uf::scene::getCurrentScene(); - auto& assetLoader = scene.getComponent(); +// auto& assetLoader = scene.getComponent(); /* image.open( payload.filename ); auto& image = this->getComponent(); @@ -490,12 +490,10 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { UF_BEHAVIOR_METADATA_BIND_SERIALIZER_HOOKS(metadata, metadataJson); this->addHook( "asset:Load.%UID%", [&](pod::payloads::assetLoad& payload){ - if ( !uf::Asset::isExpected( payload, uf::Asset::Type::IMAGE ) ) return; - - auto& scene = uf::scene::getCurrentScene(); - auto& assetLoader = scene.getComponent(); - if ( !assetLoader.has(payload.filename) ) return; - auto& image = assetLoader.get(payload.filename); + if ( !uf::asset::isExpected( payload, uf::asset::Type::IMAGE ) ) return; + if ( !uf::asset::has( payload ) ) uf::asset::load( payload ); + const auto& image = uf::asset::get( payload ); + this->as().load( image ); }); diff --git a/ext/main.cpp b/ext/main.cpp index ada1d432..8766394a 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -237,12 +237,13 @@ void EXT_API ext::initialize() { uf::Entity::deleteComponentsOnDestroy = ::json["engine"]["debug"]["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy ); uf::Object::assertionLoad = ::json["engine"]["debug"]["loader"]["assert"].as( uf::Object::assertionLoad ); - uf::Asset::assertionLoad = ::json["engine"]["debug"]["loader"]["assert"].as( uf::Asset::assertionLoad ); + uf::asset::assertionLoad = ::json["engine"]["debug"]["loader"]["assert"].as( uf::asset::assertionLoad ); uf::userdata::autoDestruct = ::json["engine"]["debug"]["userdata"]["auto destruct"].as( uf::userdata::autoDestruct ); uf::userdata::autoValidate = ::json["engine"]["debug"]["userdata"]["auto validate"].as( uf::userdata::autoValidate ); uf::Object::deferLazyCalls = ::json["engine"]["debug"]["hooks"]["defer lazy calls"].as( uf::Object::deferLazyCalls ); + uf::scene::printTaskCalls = ::json["engine"]["debug"]["scene"]["print task calls"].as( uf::scene::printTaskCalls ); } { @@ -379,6 +380,8 @@ void EXT_API ext::initialize() { } #if UF_USE_VULKAN + uf::renderer::settings::version = configRenderJson["version"].as(1.3); + if ( configRenderJson["gpu"].as() == "auto" ) { uf::renderer::settings::gpuID = -1; } else { @@ -387,26 +390,41 @@ void EXT_API ext::initialize() { for ( int i = 0; i < configRenderJson["validation"]["filters"].size(); ++i ) { uf::renderer::settings::validationFilters.emplace_back( configRenderJson["validation"]["filters"][i].as() ); } - for ( int i = 0; i < configRenderJson["extensions"]["device"].size(); ++i ) { - uf::renderer::settings::requestedDeviceExtensions.emplace_back( configRenderJson["extensions"]["device"][i].as() ); - } - for ( int i = 0; i < configRenderJson["extensions"]["instance"].size(); ++i ) { - uf::renderer::settings::requestedInstanceExtensions.emplace_back( configRenderJson["extensions"]["instance"][i].as() ); - } - for ( int i = 0; i < configRenderJson["features"].size(); ++i ) { - uf::renderer::settings::requestedDeviceFeatures.emplace_back( configRenderJson["features"][i].as() ); - } - #endif - #if UF_USE_VULKAN + #define VK_LOAD_VERSION_LEVEL(VERSION) if ( VERSION <= uf::renderer::settings::version ) {\ + auto& configVersionLevel = configRenderJson["versions"][#VERSION];\ + for ( int i = 0; i < configVersionLevel["extensions"]["device"].size(); ++i ) {\ + uf::renderer::settings::requestedDeviceExtensions.emplace_back( configVersionLevel["extensions"]["device"][i].as() );\ + }\ + for ( int i = 0; i < configVersionLevel["extensions"]["instance"].size(); ++i ) {\ + uf::renderer::settings::requestedInstanceExtensions.emplace_back( configVersionLevel["extensions"]["instance"][i].as() );\ + }\ + for ( int i = 0; i < configVersionLevel["features"].size(); ++i ) {\ + uf::renderer::settings::requestedDeviceFeatures.emplace_back( configVersionLevel["features"][i].as() );\ + }\ + for ( int i = 0; i < configVersionLevel["featureChain"].size(); ++i ) {\ + uf::stl::string key = configVersionLevel["featureChain"][i].as();\ + uf::renderer::settings::requestedFeatureChain[key] = true;\ + }\ + } + + VK_LOAD_VERSION_LEVEL(1.0); + VK_LOAD_VERSION_LEVEL(1.1); + VK_LOAD_VERSION_LEVEL(1.2); + VK_LOAD_VERSION_LEVEL(1.3); + + ext::vulkan::settings::defaultStageBuffers = configRenderInvariantJson["default stage buffers"].as( uf::renderer::settings::defaultStageBuffers ); + uf::renderer::settings::invariant::deviceAddressing = uf::renderer::settings::requestedFeatureChain["physicalDeviceVulkan12"].as(false) || uf::renderer::settings::requestedFeatureChain["bufferDeviceAddress"].as(false); + uf::renderer::settings::experimental::batchQueueSubmissions = configRenderExperimentalJson["batch queue submissions"].as( uf::renderer::settings::experimental::batchQueueSubmissions ); + uf::renderer::settings::experimental::memoryBudgetBit = configRenderExperimentalJson["memory budget"].as( uf::renderer::settings::experimental::memoryBudgetBit ); #if 1 uf::renderer::settings::experimental::dedicatedThread = false; ::requestDedicatedRenderThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread ); #else uf::renderer::settings::experimental::dedicatedThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread ); #endif - uf::renderer::settings::experimental::batchQueueSubmissions = configRenderExperimentalJson["batch queue submissions"].as( uf::renderer::settings::experimental::batchQueueSubmissions ); #endif + uf::renderer::settings::experimental::rebuildOnTickBegin = configRenderExperimentalJson["rebuild on tick begin"].as( uf::renderer::settings::experimental::rebuildOnTickBegin ); uf::renderer::settings::invariant::multithreadedRecording = configRenderInvariantJson["multithreaded recording"].as( uf::renderer::settings::invariant::multithreadedRecording ); @@ -687,9 +705,7 @@ void EXT_API ext::initialize() { /* uf::thread::add( uf::thread::fetchWorker(), [&]{ - auto& scene = uf::scene::getCurrentScene(); - auto& assetLoader = scene.getComponent(); - assetLoader.processQueue(); + uf::asset::processQueue(); }); */ @@ -802,13 +818,13 @@ void EXT_API ext::tick() { } } #if !UF_ENV_DREAMCAST - /* Frame limiter of sorts I guess */ if ( ::times.limiter > 0 ) { + if ( ::times.limiter > 0 ) { static uf::Timer timer(false); if ( !timer.running() ) timer.start(); auto elapsed = timer.elapsed().asMilliseconds(); long long sleep = (::times.limiter * 1000) - elapsed; if ( sleep > 0 ) { - // if ( ::config.engine.limiter.print ) UF_MSG_DEBUG("Frame limiting: " << elapsed << "ms exceeds limit, sleeping for " << elapsed << "ms"); + if ( ::config.engine.limiter.print ) UF_MSG_DEBUG("Frame limiting: sleeping for {}ms (from {})", elapsed, ::times.limiter * 1000); std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); } timer.reset();