diff --git a/Makefile b/Makefile index 9f017460..e34b0edf 100644 --- a/Makefile +++ b/Makefile @@ -31,8 +31,8 @@ EXT_LIB_NAME += ext #VULKAN_SDK_PATH += /c/VulkanSDK/1.2.162.0/ #VULKAN_SDK_PATH += /c/VulkanSDK/1.2.176.1/ #VULKAN_SDK_PATH += /c/VulkanSDK/1.2.182.0/ -#VULKAN_SDK_PATH += /c/VulkanSDK/1.2.198.1/ -VULKAN_SDK_PATH += /c/VulkanSDK/1.3.204.1/ +VULKAN_SDK_PATH += /c/VulkanSDK/1.2.198.1/ +#VULKAN_SDK_PATH += /c/VulkanSDK/1.3.204.1/ #GLSLC += $(VULKAN_SDK_PATH)/Bin/glslangValidator GLSLC += $(VULKAN_SDK_PATH)/Bin/glslc diff --git a/bin/data/config.json b/bin/data/config.json index f41b60a2..a115b6c9 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -1,7 +1,7 @@ { "engine": { "scenes": { - "start": "SS2", + "start": "SH2_McDonalds", "meshes": { "interleave": false }, "matrix": { "reverseInfinite": true }, "lights": { @@ -23,7 +23,7 @@ } }, "vxgi": { - "limiter": 0.5, + "limiter": 2, "size": 96, "dispatch": 8, "cascades": 4, @@ -62,8 +62,9 @@ "size": 1, // "size": [ 640, 480, "NEAREST" ], // "size": [ 1280, 720 ], - "size": [ 960, 540 ], - "msaa": 16 + // "size": [ 960, 540 ], + // "size": [ 640, 480 ], + "msaa": 0 }, "experimental": { "rebuild on tick begin": false, @@ -77,7 +78,7 @@ "vsync": true, "hdr": true, "vxgi": true, - "deferred sampling": false, + "deferred sampling": true, // broken for some scenes "culling": true, "bloom": false }, @@ -243,7 +244,7 @@ "cursor" : { "visible" : true, "center" : false, - "sensitivity": [ 0.8, 0.8 ] + "sensitivity": [ 1, 1 ] }, "mode" : "windowed", // fullscreen, borderless, windowed "icon" : "./data/textures/icon.png", diff --git a/bin/data/entities/model.json b/bin/data/entities/model.json index 79f122e0..bc4af565 100644 --- a/bin/data/entities/model.json +++ b/bin/data/entities/model.json @@ -32,9 +32,17 @@ "trigger": { "mode": "rendered" }, "output": "./lightmap.png" }, + "grid": { + "/^worldspawn/": { + "size": [3,3,3], + // "epsilon": 0.01, + "cleanup": true, + "print": true + } + }, // "lightmap": "./lightmap.min.png", // "lightmap": "./lightmap.png", - "filter": "NEAREST", + // "filter": "NEAREST", "flags": { "ATLAS": false, "INVERT": false, diff --git a/bin/data/entities/playerModel.json b/bin/data/entities/playerModel.json index 78066453..ea3a455d 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, "assets": [ "/player/bear.glb" // { "filename": "/player/bear/graph.json", "delay": 0, "single threaded": false, "category": "models" } diff --git a/bin/data/scenes/mcdonalds/mcdonalds.json b/bin/data/scenes/mcdonalds/mcdonalds.json index 0ddf8f4f..29d257cc 100644 --- a/bin/data/scenes/mcdonalds/mcdonalds.json +++ b/bin/data/scenes/mcdonalds/mcdonalds.json @@ -6,12 +6,13 @@ // { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false } // { "filename": "./models/mcdonalds/graph.json", "delay": 0, "single threaded": false, "category": "models" } { "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } - + // { "filename": "./models/mini_mcd.glb", "delay": 0, "single threaded": false } // { "filename": "./models/mini_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } ], "metadata": { "model": { + // "grid": { "/^worldspawn/": { "size": 1 } }, "cull mode": "none", "tags": { "worldspawn": { "physics": { "type": "mesh", "static": true } }, diff --git a/bin/data/scenes/ss2/medsci.json b/bin/data/scenes/ss2/medsci.json index ae747427..43cfa6cd 100644 --- a/bin/data/scenes/ss2/medsci.json +++ b/bin/data/scenes/ss2/medsci.json @@ -20,11 +20,6 @@ ], "metadata": { "model": { - "chunk": { - "enabled": true, - "size": 3, // [3,3,3], - "target": "worldspawn" - }, "exporter": { "enabled": false }, @@ -35,6 +30,7 @@ "trigger": { "mode": "rendered" }, "output": "./lightmap.png" }, + "filter": "NEAREST", "tags": { "worldspawn": { "physics": { "type": "mesh", "static": true } }, "worldspawn_20": { "physics": { "type": "mesh", "static": true } }, diff --git a/bin/data/shaders/base/base.frag.h b/bin/data/shaders/base/base.frag.h index 66841425..416cd1ad 100644 --- a/bin/data/shaders/base/base.frag.h +++ b/bin/data/shaders/base/base.frag.h @@ -21,7 +21,7 @@ layout (location = 1) out vec2 outNormals; #endif void main() { - float mip = mipLevel(inUv.xy); + float mip = mipLevel(dFdx(inUv), dFdy(inUv)); vec2 uv = inUv.xy; vec4 C = vec4(1, 1, 1, 1); vec3 P = inPosition; diff --git a/bin/data/shaders/common/functions.h b/bin/data/shaders/common/functions.h index b5284c7e..932c8719 100644 --- a/bin/data/shaders/common/functions.h +++ b/bin/data/shaders/common/functions.h @@ -53,27 +53,21 @@ bool validTextureIndex( uint start, int offset ) { uint textureIndex( uint start, int offset ) { return start + offset; } -#if TEXTURE_WORKAROUND -vec4 sampleTexture( uint id, vec2 uv ) { - const Texture t = textures[id]; - return texture( samplerTextures[nonuniformEXT(t.index - surface.instance.imageID)], mix( t.lerp.xy, t.lerp.zw, uv ) ); -} -vec4 sampleTexture( uint id, vec2 uv, float mip ) { - const Texture t = textures[id]; - return textureLod( samplerTextures[nonuniformEXT(t.index - surface.instance.imageID)], mix( t.lerp.xy, t.lerp.zw, uv ), mip ); -} -#else 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 ) { return sampleTexture( id, surface.uv ); } -vec4 sampleTexture( uint id, float mip ) { return sampleTexture( id, surface.uv, mip ); } +} +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; @@ -101,10 +95,12 @@ void whitenoise(inout vec3 color, const vec4 parameters) { const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); color = mix( color, vec3(whiteNoise), blend ); } -float mipLevel( in vec2 uv ) { - const vec2 dx_vtc = dFdx(uv); - const vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); +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))); } vec4 resolve( subpassInputMS t, const uint samples ) { vec4 resolved = vec4(0); diff --git a/bin/data/shaders/common/macros.h b/bin/data/shaders/common/macros.h index 42f6526b..a6c1c75e 100644 --- a/bin/data/shaders/common/macros.h +++ b/bin/data/shaders/common/macros.h @@ -6,6 +6,9 @@ #ifndef MULTISAMPLING #define MULTISAMPLING 1 #endif +#ifndef MAX_MSAA_SAMPLES + #define MAX_MSAA_SAMPLES 16 +#endif #ifndef DEFERRED_SAMPLING #define DEFERRED_SAMPLING 1 #endif diff --git a/bin/data/shaders/common/structs.h b/bin/data/shaders/common/structs.h index feb6af2a..fe377eed 100644 --- a/bin/data/shaders/common/structs.h +++ b/bin/data/shaders/common/structs.h @@ -148,8 +148,8 @@ struct SurfaceMaterial { struct Surface { uint pass; - vec2 uv; - vec2 st; + vec3 uv; + vec3 st; Space position; Space normal; @@ -161,6 +161,15 @@ struct Surface { 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 // VXGI stuff struct Vxgi { mat4 matrix; diff --git a/bin/data/shaders/display/renderTarget.h b/bin/data/shaders/display/renderTarget.h index ab1aca5f..10755885 100644 --- a/bin/data/shaders/display/renderTarget.h +++ b/bin/data/shaders/display/renderTarget.h @@ -9,7 +9,7 @@ #if DEFERRED_SAMPLING layout (binding = 3) uniform sampler2D samplerUvs; #else - layout (binding = 4) uniform sampler2D samplerAlbedo; + layout (binding = 3) uniform sampler2D samplerAlbedo; #endif #else layout (binding = 1) uniform usampler2DMS samplerId; @@ -17,7 +17,7 @@ #if DEFERRED_SAMPLING layout (binding = 3) uniform sampler2DMS samplerUvs; #else - layout (binding = 4) uniform sampler2DMS samplerAlbedo; + layout (binding = 3) uniform sampler2DMS samplerAlbedo; #endif #endif diff --git a/bin/data/shaders/display/subpass.deferredSampling.frag.glsl b/bin/data/shaders/display/subpass.deferredSampling.frag.glsl index 5e30835c..d3ff5ebf 100644 --- a/bin/data/shaders/display/subpass.deferredSampling.frag.glsl +++ b/bin/data/shaders/display/subpass.deferredSampling.frag.glsl @@ -1,8 +1,8 @@ #version 450 #pragma shader_stage(fragment) -#define MULTISAMPLING 1 #define DEFERRED_SAMPLING 1 +#define MULTISAMPLING 0 #include "./subpass.h" diff --git a/bin/data/shaders/display/subpass.frag.glsl b/bin/data/shaders/display/subpass.frag.glsl index 4bbcd7aa..2f374f9e 100644 --- a/bin/data/shaders/display/subpass.frag.glsl +++ b/bin/data/shaders/display/subpass.frag.glsl @@ -2,7 +2,7 @@ #pragma shader_stage(fragment) #define DEFERRED_SAMPLING 0 -#define MULTISAMPLING 1 +#define MULTISAMPLING 0 #include "./subpass.h" void main() { diff --git a/bin/data/shaders/display/subpass.h b/bin/data/shaders/display/subpass.h index 0e54f3c7..3ccff55b 100644 --- a/bin/data/shaders/display/subpass.h +++ b/bin/data/shaders/display/subpass.h @@ -3,6 +3,8 @@ #define DEFERRED 1 #define MAX_TEXTURES TEXTURES +//#define TEXTURE_WORKAROUND 0 + #include "../common/macros.h" layout (constant_id = 0) const uint TEXTURES = 512; @@ -20,6 +22,9 @@ layout (constant_id = 1) const uint CUBEMAPS = 128; layout (input_attachment_index = 2, binding = 2) uniform subpassInput samplerAlbedo; #endif layout (input_attachment_index = 3, binding = 3) uniform subpassInput samplerDepth; + #if DEFERRED_SAMPLING + layout (input_attachment_index = 4, binding = 4) uniform subpassInput samplerMips; + #endif #else layout (input_attachment_index = 0, binding = 0) uniform usubpassInputMS samplerId; layout (input_attachment_index = 1, binding = 1) uniform subpassInputMS samplerNormal; @@ -29,6 +34,9 @@ layout (constant_id = 1) const uint CUBEMAPS = 128; layout (input_attachment_index = 2, binding = 2) uniform subpassInputMS samplerAlbedo; #endif layout (input_attachment_index = 3, binding = 3) uniform subpassInputMS samplerDepth; + #if DEFERRED_SAMPLING + layout (input_attachment_index = 4, binding = 4) uniform subpassInputMS samplerMips; + #endif #endif #include "../common/structs.h" @@ -120,12 +128,14 @@ void postProcess() { } void populateSurface() { + surface.fragment = vec4(0); surface.pass = inPushConstantPass.x; + { #if !MULTISAMPLING const float depth = subpassLoad(samplerDepth).r; #else - const float depth = resolve(samplerDepth, ubo.msaa).r; + const float depth = subpassLoad(samplerDepth, msaa.currentID).r; // resolve(samplerDepth, ubo.msaa).r; #endif vec4 positionEye = ubo.eyes[surface.pass].iProjection * vec4(inUv * 2.0 - 1.0, depth, 1.0); @@ -165,12 +175,13 @@ void populateSurface() { surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz; } #endif + #if !MULTISAMPLING surface.normal.world = decodeNormals( subpassLoad(samplerNormal).xy ); const uvec2 ID = subpassLoad(samplerId).xy; #else - surface.normal.world = decodeNormals( resolve(samplerNormal, ubo.msaa).xy ); - const uvec2 ID = subpassLoad(samplerId, 0).xy; //resolve(samplerId, ubo.msaa).xy; + surface.normal.world = decodeNormals( subpassLoad(samplerNormal, msaa.currentID).xy ); // decodeNormals( resolve(samplerNormal, ubo.msaa).xy ); + const uvec2 ID = msaa.IDs[msaa.currentID]; // subpassLoad(samplerId, msaa.currentID).xy; //resolve(samplerId, ubo.msaa).xy; #endif surface.normal.eye = vec3( ubo.eyes[surface.pass].view * vec4(surface.normal.world, 0.0) ); @@ -198,16 +209,20 @@ void populateSurface() { #if DEFERRED_SAMPLING { #if !MULTISAMPLING - vec4 uv = subpassLoad(samplerUv); + const vec4 uv = subpassLoad(samplerUv); + const vec2 mips = vec2(0); // subpassLoad(samplerMips).xy; #else - vec4 uv = resolve(samplerUv, ubo.msaa); + const vec4 uv = subpassLoad(samplerUv, msaa.currentID); // resolve(samplerUv, ubo.msaa); + const vec2 mips = vec2(0); // subpassLoad(samplerMips, msaa.currentID).xy; // resolve(samplerUv, ubo.msaa); #endif - surface.uv = uv.xy; - surface.st = uv.zw; + surface.uv.xy = uv.xy; + surface.uv.z = mips.x; + surface.st.xy = uv.zw; + surface.st.z = mips.y; } - const float mip = mipLevel(inUv.xy); + if ( validTextureIndex( material.indexAlbedo ) ) { - surface.material.albedo = sampleTexture( material.indexAlbedo, mip ); + surface.material.albedo = sampleTexture( material.indexAlbedo ); } // OPAQUE if ( material.modeAlpha == 0 ) { @@ -225,15 +240,15 @@ void populateSurface() { } // Emissive textures if ( validTextureIndex( material.indexEmissive ) ) { - surface.material.albedo += sampleTexture( material.indexEmissive, mip ); + surface.material.albedo += sampleTexture( material.indexEmissive ); } // Occlusion map if ( validTextureIndex( material.indexOcclusion ) ) { - surface.material.occlusion = sampleTexture( material.indexOcclusion, mip ).r; + surface.material.occlusion = sampleTexture( material.indexOcclusion ).r; } // Metallic/Roughness map if ( validTextureIndex( material.indexMetallicRoughness ) ) { - vec4 samp = sampleTexture( material.indexMetallicRoughness, mip ); + vec4 samp = sampleTexture( material.indexMetallicRoughness ); surface.material.metallic = samp.r; surface.material.roughness = samp.g; } @@ -241,7 +256,7 @@ void populateSurface() { #if !MULTISAMPLING surface.material.albedo = subpassLoad(samplerAlbedo); #else - surface.material.albedo = resolve(samplerAlbedo, ubo.msaa); + surface.material.albedo = subpassLoad(samplerAlbedo, msaa.currentID); // resolve(samplerAlbedo, ubo.msaa); #endif #endif } @@ -263,4 +278,36 @@ void directLighting() { #elif PHONG phong(); #endif -} \ No newline at end of file +} + +#if MULTISAMPLING +void resolveSurfaceFragment() { + for ( int i = 0; i < ubo.msaa; ++i ) { + msaa.currentID = i; + msaa.IDs[i] = subpassLoad(samplerId, msaa.currentID).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.msaa; +} +#endif \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.msaa.deferredSampling.frag.glsl b/bin/data/shaders/display/subpass.msaa.deferredSampling.frag.glsl index ee4f73a9..cba6fb80 100644 --- a/bin/data/shaders/display/subpass.msaa.deferredSampling.frag.glsl +++ b/bin/data/shaders/display/subpass.msaa.deferredSampling.frag.glsl @@ -2,10 +2,10 @@ #pragma shader_stage(fragment) #define DEFERRED_SAMPLING 1 +#define MULTISAMPLING 1 #include "./subpass.h" void main() { - populateSurface(); - directLighting(); + resolveSurfaceFragment(); postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.msaa.frag.glsl b/bin/data/shaders/display/subpass.msaa.frag.glsl index fa456578..77fd6a82 100644 --- a/bin/data/shaders/display/subpass.msaa.frag.glsl +++ b/bin/data/shaders/display/subpass.msaa.frag.glsl @@ -2,10 +2,11 @@ #pragma shader_stage(fragment) #define DEFERRED_SAMPLING 0 +#define MULTISAMPLING 1 #include "./subpass.h" void main() { - populateSurface(); - directLighting(); + resolveSurfaceFragment(); + postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.vxgi.msaa.deferredSampling.frag.glsl b/bin/data/shaders/display/subpass.vxgi.msaa.deferredSampling.frag.glsl index 534b454d..21bae0bd 100644 --- a/bin/data/shaders/display/subpass.vxgi.msaa.deferredSampling.frag.glsl +++ b/bin/data/shaders/display/subpass.vxgi.msaa.deferredSampling.frag.glsl @@ -3,11 +3,10 @@ #define VXGI 1 #define DEFERRED_SAMPLING 1 +#define MULTISAMPLING 1 #include "./subpass.h" void main() { - populateSurface(); - indirectLighting(); - directLighting(); + resolveSurfaceFragment(); postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.vxgi.msaa.frag.glsl b/bin/data/shaders/display/subpass.vxgi.msaa.frag.glsl index a3d327fb..beda7f27 100644 --- a/bin/data/shaders/display/subpass.vxgi.msaa.frag.glsl +++ b/bin/data/shaders/display/subpass.vxgi.msaa.frag.glsl @@ -3,11 +3,10 @@ #define VXGI 1 #define DEFERRED_SAMPLING 0 +#define MULTISAMPLING 1 #include "./subpass.h" void main() { - populateSurface(); - indirectLighting(); - directLighting(); + resolveSurfaceFragment(); postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/vxgi.comp.h b/bin/data/shaders/display/vxgi.comp.h index 5b2507c2..d3db68e6 100644 --- a/bin/data/shaders/display/vxgi.comp.h +++ b/bin/data/shaders/display/vxgi.comp.h @@ -99,8 +99,8 @@ void main() { #if DEFERRED_SAMPLING { vec4 uv = imageLoad(voxelUv[CASCADE], ivec3(tUvw) ); - surface.uv = uv.xy; - surface.st = uv.zw; + surface.uv.xy = uv.xy; + surface.st.xy = uv.zw; } if ( validTextureIndex( material.indexAlbedo ) ) { surface.material.albedo = sampleTexture( material.indexAlbedo ); diff --git a/bin/data/shaders/graph/baking/bake.frag.glsl b/bin/data/shaders/graph/baking/bake.frag.glsl index 645cb1c5..ed68abff 100644 --- a/bin/data/shaders/graph/baking/bake.frag.glsl +++ b/bin/data/shaders/graph/baking/bake.frag.glsl @@ -48,14 +48,14 @@ layout (location = 8) flat in uvec4 inId; layout (location = 0) out vec4 outAlbedo; void main() { - const float mip = mipLevel(inUv.xy); const uint drawID = uint(inId.x); const uint instanceID = uint(inId.y); const uint materialID = uint(inId.z); vec4 A = vec4(1, 1, 1, 1); surface.normal.world = normalize( inNormal ); - surface.uv = wrap(inUv.xy); + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); surface.position.world = inPosition; const Material material = materials[materialID]; diff --git a/bin/data/shaders/graph/base.frag.glsl b/bin/data/shaders/graph/base.frag.glsl index 20b659ac..ea71e7d0 100644 --- a/bin/data/shaders/graph/base.frag.glsl +++ b/bin/data/shaders/graph/base.frag.glsl @@ -2,4 +2,5 @@ #pragma shader_stage(fragment) #define DEFERRED_SAMPLING 0 +#define QUERY_MIPMAP 1 #include "./base.frag.h" diff --git a/bin/data/shaders/graph/base.frag.h b/bin/data/shaders/graph/base.frag.h index e6f192ce..2e8782ad 100644 --- a/bin/data/shaders/graph/base.frag.h +++ b/bin/data/shaders/graph/base.frag.h @@ -1,5 +1,4 @@ //#extension GL_EXT_nonuniform_qualifier : enable - #define CUBEMAPS 1 #define FRAGMENT 1 // #define MAX_TEXTURES TEXTURES @@ -34,6 +33,7 @@ layout (location = 0) out uvec2 outId; layout (location = 1) out vec2 outNormals; #if DEFERRED_SAMPLING layout (location = 2) out vec4 outUvs; + layout (location = 3) out vec2 outMips; #else layout (location = 2) out vec4 outAlbedo; #endif @@ -42,12 +42,13 @@ void main() { const uint drawID = uint(inId.x); const uint instanceID = uint(inId.y); const uint materialID = uint(inId.z); - const float mip = mipLevel(inUv.xy); const vec2 uv = wrap(inUv.xy); const vec3 P = inPosition; - surface.uv = uv; - surface.st = inSt; + surface.uv.xy = uv; + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + surface.st.xy = inSt; + surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt)); vec3 N = inNormal; vec4 A = vec4(0, 0, 0, 0); @@ -64,7 +65,7 @@ void main() { // sample albedo if ( !validTextureIndex( material.indexAlbedo ) ) discard; { - A = sampleTexture( material.indexAlbedo, mip ); + A = sampleTexture( material.indexAlbedo ); // alpha mode OPAQUE if ( material.modeAlpha == 0 ) { A.a = 1; @@ -80,7 +81,7 @@ void main() { } #if USE_LIGHTMAP && !DEFERRED_SAMPLING if ( validTextureIndex( instance.lightmapID ) ) { - A.rgb *= sampleTexture( instance.lightmapID, inSt, mip ).rgb; + A.rgb *= sampleTexture( instance.lightmapID, surface.st ).rgb; } #endif #endif @@ -88,13 +89,13 @@ void main() { // sample normal if ( validTextureIndex( material.indexNormal ) ) { Texture t = textures[material.indexNormal]; - N = inTBN * normalize( sampleTexture( material.indexNormal, mip ).xyz * 2.0 - vec3(1.0)); + N = inTBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - vec3(1.0)); } #if 0 // sample metallic/roughness if ( validTextureIndex( material.indexMetallicRoughness ) ) { Texture t = textures[material.indexMetallicRoughness]; - const vec4 sampled = textureLod( samplerTextures[nonuniformEXT((useAtlas)?textureAtlas.index:t.index)], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mip ); + const vec4 sampled = textureLod( samplerTextures[nonuniformEXT((useAtlas)?textureAtlas.index:t.index)], ( useAtlas ) ? mix( t.lerp.xy, t.lerp.zw, uv ) : uv, mipUv ); M = sampled.b; R = sampled.g; } @@ -107,8 +108,11 @@ void main() { #endif outAlbedo = A * inColor; #else - outUvs.xy = surface.uv; - outUvs.zw = surface.st; + outUvs.xy = surface.uv.xy; + outUvs.zw = surface.st.xy; + + outMips.x = surface.uv.z; + outMips.y = surface.st.z; #endif outNormals = encodeNormals( N ); outId = uvec2(drawID + 1, instanceID + 1); diff --git a/bin/data/shaders/graph/depth.frag.glsl b/bin/data/shaders/graph/depth.frag.glsl index 19e33ca6..5fcd9e00 100644 --- a/bin/data/shaders/graph/depth.frag.glsl +++ b/bin/data/shaders/graph/depth.frag.glsl @@ -35,17 +35,17 @@ void main() { const uint drawID = uint(inId.x); const uint instanceID = uint(inId.y); const uint materialID = uint(inId.z); - const float mip = mipLevel(inUv.xy); const vec2 uv = wrap(inUv.xy); vec4 A = vec4(0, 0, 0, 0); - surface.uv = uv; + surface.uv.xy = uv; + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); const Material material = materials[materialID]; // sample albedo if ( !validTextureIndex( material.indexAlbedo ) ) discard; { // const Texture t = textures[material.indexAlbedo]; // A = textureLod( samplerTextures[nonuniformEXT(t.index)], mix( t.lerp.xy, t.lerp.zw, uv ), mip ); - A = sampleTexture( material.indexAlbedo, mip ); + A = sampleTexture( material.indexAlbedo ); // alpha mode OPAQUE if ( material.modeAlpha == 0 ) { A.a = 1; diff --git a/bin/data/shaders/graph/voxelize.frag.h b/bin/data/shaders/graph/voxelize.frag.h index f2835688..2e70581a 100644 --- a/bin/data/shaders/graph/voxelize.frag.h +++ b/bin/data/shaders/graph/voxelize.frag.h @@ -61,11 +61,13 @@ void main() { const uint drawID = uint(inId.x); const uint instanceID = uint(inId.y); const uint materialID = uint(inId.z); - const float mip = mipLevel(inUv.xy); const vec2 uv = wrap(inUv.xy); - surface.uv = uv; - surface.st = inSt; + surface.uv.xy = uv; + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + surface.st.xy = inSt; + surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt)); + vec3 N = inNormal; vec4 A = vec4(0, 0, 0, 0); @@ -80,7 +82,7 @@ void main() { // sample albedo if ( !validTextureIndex( material.indexAlbedo ) ) discard; { if ( surface.instance.imageID <= 0 ) { - A = sampleTexture( material.indexAlbedo, mip ); + A = sampleTexture( material.indexAlbedo ); } else { const Texture t = textures[material.indexAlbedo]; A = texture( samplerTextures[nonuniformEXT(t.index - surface.instance.imageID)], mix( t.lerp.xy, t.lerp.zw, uv ) ); @@ -100,7 +102,7 @@ void main() { } #if USE_LIGHTMAP && !DEFERRED_SAMPLING if ( validTextureIndex( instance.lightmapID ) ) { - // A.rgb *= sampleTexture( instance.lightmapID, inSt, mip ).rgb; + A.rgb *= sampleTexture( instance.lightmapID, inSt ).rgb; } #endif diff --git a/bin/data/shaders/gui/gui.frag.h b/bin/data/shaders/gui/gui.frag.h index 96033206..e09221dd 100644 --- a/bin/data/shaders/gui/gui.frag.h +++ b/bin/data/shaders/gui/gui.frag.h @@ -24,8 +24,8 @@ layout (location = 1) out vec2 outNormals; 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 float mip = mipLevel(inUv.xy); const vec2 uv = inUv.xy; + const float mip = mipLevel(dFdx(inUv), dFdy(inUv)); vec4 C = inGui.color; #if GLYPH if ( enabled(inGui.mode, 1) ) { diff --git a/engine/inc/uf/engine/graph/graph.h b/engine/inc/uf/engine/graph/graph.h index f9fac1d0..73f6f619 100644 --- a/engine/inc/uf/engine/graph/graph.h +++ b/engine/inc/uf/engine/graph/graph.h @@ -65,14 +65,19 @@ namespace pod { public: uf::stl::vector keys; uf::stl::unordered_map map; + uf::stl::unordered_map indices; T& operator[]( const Key& key ) { - if ( map.count( key ) == 0 ) keys.emplace_back( key ); + if ( map.count( key ) == 0 ) { + indices[key] = keys.size(); + keys.emplace_back( key ); + } return map[key]; } void reserve( size_t i ) { keys.reserve(i); + indices.reserve(i); map.reserve(i); } }; diff --git a/engine/inc/uf/engine/graph/pod.inl b/engine/inc/uf/engine/graph/pod.inl index 3a0876af..10a5c073 100644 --- a/engine/inc/uf/engine/graph/pod.inl +++ b/engine/inc/uf/engine/graph/pod.inl @@ -1,42 +1,10 @@ namespace pod { - struct UF_API DrawCommand { - uint32_t indices = 0; // triangle count - uint32_t instances = 0; // instance count - uint32_t indexID = 0; // starting triangle position - int32_t vertexID = 0; // starting vertex position - uint32_t instanceID = 0; // starting instance position - // extra data - uint32_t padding1 = 0; // - uint32_t padding2 = 0; // - uint32_t vertices = 0; // - }; + template + struct UF_API Meshlet_T { + uf::stl::vector vertices; + uf::stl::vector indices; - - struct UF_API Instance { - pod::Matrix4f model; - pod::Vector4f color = {1,1,1,1}; - - alignas(4) uint32_t materialID = 0; - alignas(4) uint32_t primitiveID = 0; - alignas(4) uint32_t meshID = 0; - alignas(4) uint32_t objectID = 0; - - alignas(4) int32_t jointID = -1; - alignas(4) int32_t lightmapID = -1; - alignas(4) uint32_t imageID = 0; - alignas(4) uint32_t padding3 = 0; - - struct Bounds { - pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; - alignas(4) float padding1 = 0; - pod::Vector3f max = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; - alignas(4) float padding2 = 0; - } bounds; - }; - - struct Primitive { - pod::DrawCommand drawCommand; - pod::Instance instance; + pod::Primitive primitive; }; struct UF_API Material { diff --git a/engine/inc/uf/utils/math/rayt.h b/engine/inc/uf/utils/math/rayt.h index eb1bc536..70e79bdb 100644 --- a/engine/inc/uf/utils/math/rayt.h +++ b/engine/inc/uf/utils/math/rayt.h @@ -1,10 +1,10 @@ #pragma once - +#if 0 #include #include namespace pod { - struct UF_API Primitive { + struct UF_API RTPrimitive { static const uint32_t EMPTY = (uint32_t) -1; static const uint32_t CUBE = 1; static const uint32_t LEAF = 2; @@ -27,9 +27,10 @@ namespace pod { namespace uf { namespace primitive { - uf::stl::vector UF_API populate( const uf::stl::vector& cubes ); - uf::stl::vector UF_API populateEntirely( const uf::stl::vector& cubes ); + uf::stl::vector UF_API populate( const uf::stl::vector& cubes ); + uf::stl::vector UF_API populateEntirely( const uf::stl::vector& cubes ); uf::stl::vector UF_API populateEntirely( const uf::stl::vector& trees, bool = false ); - void UF_API test( const uf::stl::vector& cubes, const uf::stl::vector& trees ); + void UF_API test( const uf::stl::vector& cubes, const uf::stl::vector& trees ); } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/inc/uf/utils/math/vector.h b/engine/inc/uf/utils/math/vector.h index 4df12e88..6ca74a56 100644 --- a/engine/inc/uf/utils/math/vector.h +++ b/engine/inc/uf/utils/math/vector.h @@ -528,4 +528,15 @@ namespace pod { }; } +namespace std { + template + struct hash> { + size_t operator()(const pod::Vector& v) const { + size_t hash = 0; + for ( size_t i = 0; i < N; ++i ) hash ^= v[i]; + return hash; + } + }; +} + #include "vector/vector.inl" \ No newline at end of file diff --git a/engine/inc/uf/utils/mesh/grid.h b/engine/inc/uf/utils/mesh/grid.h index c0f4bfaa..dc40d7a1 100644 --- a/engine/inc/uf/utils/mesh/grid.h +++ b/engine/inc/uf/utils/mesh/grid.h @@ -2,22 +2,28 @@ #include #include +#include #include namespace uf { namespace meshgrid { - struct UF_API Node { + struct Node { struct { pod::Vector3f min = {}; pod::Vector3f max = {}; } extents; + struct { + pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; + pod::Vector3f max = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; + } effectiveExtents; pod::Vector3ui id = {}; - uf::stl::vector indices; + uf::stl::unordered_map> meshlets; }; struct Grid { - int divisions = 1; + pod::Vector3ui divisions = {1,1,1}; + int indices = 0; struct { pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; @@ -30,25 +36,81 @@ namespace uf { pod::Vector3f piece = {}; } extents; - uf::stl::vector nodes; + // uf::stl::vector nodes; + uf::stl::unordered_map nodes; }; - void UF_API print( const Grid&, size_t indices ); - Grid UF_API generate( int divisions, void* pPointer, size_t pStride, size_t pFirst, size_t pCount, void* iPointer, size_t iStride, size_t iFirst, size_t iCount ); - Grid UF_API partition( uf::Mesh&, int ); + void UF_API print( const Grid& ); + void UF_API cleanup( Grid& ); + + void UF_API calculate( uf::meshgrid::Grid&, float = std::numeric_limits::epsilon() ); + void UF_API calculate( uf::meshgrid::Grid&, int, float = std::numeric_limits::epsilon() ); + void UF_API calculate( uf::meshgrid::Grid&, const pod::Vector3ui&, float = std::numeric_limits::epsilon() ); + + void UF_API partition( uf::meshgrid::Grid&, const void*, size_t, const void*, size_t, const pod::Primitive& ); + void UF_API partition( uf::meshgrid::Grid&, uf::Mesh&, const pod::Primitive& ); template - Grid UF_API partition( uf::stl::vector& vertices, uf::stl::vector& indices, int divisions ) { + void UF_API partition( uf::meshgrid::Grid& grid, const uf::stl::vector& vertices, const uf::stl::vector& indices, const pod::Primitive& primitive ) { auto vertexDescriptor = T::descriptor.front(); for ( auto& descriptor : T::descriptor ) if ( descriptor.name == "position" ) { vertexDescriptor = descriptor; break; } UF_ASSERT( vertexDescriptor.name == "position" ); - return generate( divisions, - vertices.data(), sizeof(T), 0, vertices.size(), - indices.data(), sizeof(U), 0, indices.size() + return partition( grid, + vertices.data(), sizeof(T), + indices.data(), sizeof(U), + primitive ); } + + template + uf::stl::vector> UF_API partition( uf::meshgrid::Grid& grid, const uf::stl::vector>& meshlets, float eps = std::numeric_limits::epsilon() ) { + uf::stl::vector> partitioned; + for ( auto& meshlet : meshlets ) { + grid.extents.min = uf::vector::min( grid.extents.min, meshlet.primitive.instance.bounds.min ); + grid.extents.max = uf::vector::max( grid.extents.max, meshlet.primitive.instance.bounds.max ); + } + + uf::meshgrid::calculate( grid, eps ); + + for ( auto& meshlet : meshlets ) { + uf::meshgrid::partition( grid, meshlet.vertices, meshlet.indices, meshlet.primitive ); + } + + uf::meshgrid::cleanup( grid ); + + for ( auto& pair : grid.nodes ) { auto& node = pair.second; + for ( auto& pair2 : node.meshlets ) { auto& mlet = pair2.second; + if ( mlet.indices.empty() ) continue; + + auto& meshlet = meshlets[mlet.primitive.instance.primitiveID]; + auto& slice = partitioned.emplace_back(); + slice.vertices.reserve( mlet.indices.size() ); + slice.indices.reserve( mlet.indices.size() ); + for ( auto idx : mlet.indices ) { + slice.vertices.emplace_back( meshlet.vertices[idx] ); + slice.indices.emplace_back( slice.indices.size() ); + } + + slice.primitive.instance.materialID = meshlet.primitive.instance.materialID; + slice.primitive.instance.primitiveID = partitioned.size() - 1; + slice.primitive.instance.meshID = meshlet.primitive.instance.meshID; + slice.primitive.instance.objectID = 0; + slice.primitive.instance.bounds.min = node.effectiveExtents.min; + slice.primitive.instance.bounds.max = node.effectiveExtents.max; + + slice.primitive.drawCommand.indices = slice.indices.size(); + slice.primitive.drawCommand.instances = 1; + slice.primitive.drawCommand.indexID = 0; + slice.primitive.drawCommand.vertexID = 0; + slice.primitive.drawCommand.instanceID = 0; + slice.primitive.drawCommand.vertices = slice.vertices.size(); + } + } + + return partitioned; + } } } diff --git a/engine/inc/uf/utils/mesh/mesh.h b/engine/inc/uf/utils/mesh/mesh.h index 18ecc2d8..9614069b 100644 --- a/engine/inc/uf/utils/mesh/mesh.h +++ b/engine/inc/uf/utils/mesh/mesh.h @@ -46,6 +46,48 @@ namespace ext { } } +namespace pod { + struct UF_API DrawCommand { + uint32_t indices = 0; // triangle count + uint32_t instances = 0; // instance count + uint32_t indexID = 0; // starting triangle position + int32_t vertexID = 0; // starting vertex position + uint32_t instanceID = 0; // starting instance position + // extra data + uint32_t padding1 = 0; // + uint32_t padding2 = 0; // + uint32_t vertices = 0; // + }; + + + struct UF_API Instance { + pod::Matrix4f model; + pod::Vector4f color = {1,1,1,1}; + + alignas(4) uint32_t materialID = 0; + alignas(4) uint32_t primitiveID = 0; + alignas(4) uint32_t meshID = 0; + alignas(4) uint32_t objectID = 0; + + alignas(4) int32_t jointID = -1; + alignas(4) int32_t lightmapID = -1; + alignas(4) uint32_t imageID = 0; + alignas(4) uint32_t padding3 = 0; + + struct Bounds { + pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; + alignas(4) float padding1 = 0; + pod::Vector3f max = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; + alignas(4) float padding2 = 0; + } bounds; + }; + + struct Primitive { + pod::DrawCommand drawCommand; + pod::Instance instance; + }; +} + namespace uf { struct UF_API Mesh { public: @@ -210,15 +252,6 @@ namespace uf { _bind( interleave ); } }; - - template - struct UF_API Mesh_T { - typedef T vertex_t; - typedef U index_t; - - uf::stl::vector vertices; - uf::stl::vector indices; - }; } namespace ext { @@ -350,4 +383,26 @@ namespace pod { static UF_API uf::stl::vector descriptor; }; +} + +namespace uf { + template + struct UF_API Mesh_T { + typedef T vertex_t; + typedef U index_t; + + uf::stl::vector vertices; + uf::stl::vector indices; + uf::stl::vector primitives; + }; + + template + struct UF_API Meshlet_T { + typedef T vertex_t; + typedef U index_t; + + uf::stl::vector vertices; + uf::stl::vector indices; + pod::Primitive primitive; + }; } \ No newline at end of file diff --git a/engine/inc/uf/utils/string/ext.h b/engine/inc/uf/utils/string/ext.h index d71f29ec..6919a7fa 100644 --- a/engine/inc/uf/utils/string/ext.h +++ b/engine/inc/uf/utils/string/ext.h @@ -9,6 +9,9 @@ namespace uf { namespace string { + // bool match( const uf::stl::string& str, const uf::stl::string& r ); + bool UF_API isRegex( const uf::stl::string& str ); + uf::stl::vector UF_API matches( const uf::stl::string& str, const uf::stl::string& r ); uf::stl::string UF_API replace( const uf::stl::string&, const uf::stl::string&, const uf::stl::string& ); uf::stl::string UF_API lowercase( const uf::stl::string& ); diff --git a/engine/src/engine/graph/convert.cpp b/engine/src/engine/graph/convert.cpp index 6b7626ca..359c7324 100644 --- a/engine/src/engine/graph/convert.cpp +++ b/engine/src/engine/graph/convert.cpp @@ -11,7 +11,7 @@ namespace { - size_t UF_API process( uf::Object& object, pod::Graph& graph, pod::Node& parent ) { + size_t process( uf::Object& object, pod::Graph& graph, pod::Node& parent ) { // grab relevant IDs size_t nodeID = graph.nodes.size(); size_t instanceID = uf::graph::storage.instances.keys.size(); // graph.instances.size(); diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 1e767619..55afe00d 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #if UF_ENV_DREAMCAST @@ -84,11 +85,21 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity ) { else if ( mode == "both" ) graphic.descriptor.cullMode = uf::renderer::enums::CullMode::BOTH; } { - for ( auto& i : graph.images ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[i] ); - for ( auto& s : graph.samplers ) graphic.material.samplers.emplace_back( uf::graph::storage.samplers.map[s] ); - - // for ( auto pair : uf::graph::storage.texture2Ds.map ) graphic.material.textures.emplace_back().aliasTexture( pair.second ); + // for ( auto& s : graph.samplers ) graphic.material.samplers.emplace_back( uf::graph::storage.samplers.map[s] ); // for ( auto pair : uf::graph::storage.samplers.map ) graphic.material.samplers.emplace_back( pair.second ); + // for ( auto& key : uf::graph::storage.samplers.keys ) graphic.material.samplers.emplace_back( uf::graph::storage.samplers.map[key] ); + + // for ( auto& i : graph.images ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[i] ); + // for ( auto pair : uf::graph::storage.texture2Ds.map ) graphic.material.textures.emplace_back().aliasTexture( pair.second ); + #if 1 + for ( auto& key : uf::graph::storage.texture2Ds.keys ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[key] ); + #else + uf::stl::map texture2DOrderedMap; // texture2DOrderedMap.reserve( uf::graph::storage.texture2Ds.keys.size() ); + for ( auto key : uf::graph::storage.texture2Ds.keys ) { + texture2DOrderedMap[uf::graph::storage.texture2Ds.indices[key]] = key; + } + for ( auto pair : texture2DOrderedMap ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[pair.second] ); + #endif // bind scene's voxel texture if ( uf::renderer::settings::experimental::vxgi ) { @@ -395,9 +406,15 @@ void uf::graph::process( pod::Graph& graph ) { // setup textures uf::graph::storage.texture2Ds.reserve( uf::graph::storage.images.map.size() ); + // not having this block will cause our images and texture2Ds to be ordered out of sync + for ( auto& key : graph.images ) { + uf::graph::storage.images[key]; + uf::graph::storage.texture2Ds[key]; + } + // figure out what texture is what exactly - for ( auto& keyName : graph.materials ) { - auto& material = uf::graph::storage.materials[keyName]; + for ( auto& key : graph.materials ) { + auto& material = uf::graph::storage.materials[key]; auto ID = material.indexAlbedo; if ( !(0 <= ID && ID < graph.textures.size()) ) continue; @@ -407,11 +424,11 @@ void uf::graph::process( pod::Graph& graph ) { texture.srgb = true; } - for ( auto& keyName : graph.images ) { - auto& image = uf::graph::storage.images[keyName]; - auto& texture = uf::graph::storage.texture2Ds[keyName]; + for ( auto& key : graph.images ) { + auto& image = uf::graph::storage.images[key]; + auto& texture = uf::graph::storage.texture2Ds[key]; if ( !texture.generated() ) { - bool isLightmap = graph.metadata["lightmapped"].as() == keyName; + bool isLightmap = graph.metadata["lightmapped"].as() == key; auto filter = graph.metadata["filter"].as() == "NEAREST" && !isLightmap ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR; texture.sampler.descriptor.filter.min = filter; texture.sampler.descriptor.filter.mag = filter; @@ -427,28 +444,54 @@ void uf::graph::process( pod::Graph& graph ) { // process nodes for ( auto index : graph.root.children ) process( graph, index, *graph.root.entity ); - // remap materials->texture IDs - for ( auto& name : graph.materials ) { - auto& material = uf::graph::storage.materials[name]; - auto& keys = uf::graph::storage.textures.keys; - int32_t* IDs[] = { &material.indexAlbedo, &material.indexNormal, &material.indexEmissive, &material.indexOcclusion, &material.indexMetallicRoughness }; - for ( auto* pointer : IDs ) { - auto& ID = *pointer; - if ( !(0 <= ID && ID < graph.materials.size()) ) continue; - auto it = std::find( keys.begin(), keys.end(), graph.textures[ID] ); - UF_ASSERT( it != keys.end() ); - ID = it - keys.begin(); - } - } // remap textures->images IDs for ( auto& name : graph.textures ) { auto& texture = uf::graph::storage.textures[name]; auto& keys = uf::graph::storage.images.keys; - - if ( !(0 <= texture.index && texture.index < graph.textures.size()) ) continue; - auto it = std::find( keys.begin(), keys.end(), graph.images[texture.index] ); + auto& indices = uf::graph::storage.images.indices; + + if ( !(0 <= texture.index && texture.index < graph.images.size()) ) continue; + + auto& needle = graph.images[texture.index]; + #if 1 + texture.index = indices[needle]; + #elif 1 + for ( size_t i = 0; i < keys.size(); ++i ) { + if ( keys[i] != needle ) continue; + texture.index = i; + break; + } + #else + auto it = std::find( keys.begin(), keys.end(), needle ); UF_ASSERT( it != keys.end() ); texture.index = it - keys.begin(); + #endif + } + // remap materials->texture IDs + for ( auto& name : graph.materials ) { + auto& material = uf::graph::storage.materials[name]; + auto& keys = uf::graph::storage.textures.keys; + auto& indices = uf::graph::storage.textures.indices; + int32_t* IDs[] = { &material.indexAlbedo, &material.indexNormal, &material.indexEmissive, &material.indexOcclusion, &material.indexMetallicRoughness }; + for ( auto* pointer : IDs ) { + auto& ID = *pointer; + if ( !(0 <= ID && ID < graph.textures.size()) ) continue; + auto& needle = graph.textures[ID]; + #if 1 + ID = indices[needle]; + #elif 1 + for ( size_t i = 0; i < keys.size(); ++i ) { + if ( keys[i] != needle ) continue; + ID = i; + break; + } + #else + if ( !(0 <= ID && ID < graph.textures.size()) ) continue; + auto it = std::find( keys.begin(), keys.end(), needle ); + UF_ASSERT( it != keys.end() ); + ID = it - keys.begin(); + #endif + } } // remap instance variables for ( auto& name : graph.instances ) { @@ -456,16 +499,56 @@ void uf::graph::process( pod::Graph& graph ) { if ( 0 <= instance.materialID && instance.materialID < graph.materials.size() ) { auto& keys = /*graph.storage*/uf::graph::storage.materials.keys; - auto it = std::find( keys.begin(), keys.end(), graph.materials[instance.materialID] ); + auto& indices = /*graph.storage*/uf::graph::storage.materials.indices; + + if ( !(0 <= instance.materialID && instance.materialID < graph.materials.size()) ) continue; + + auto& needle = graph.materials[instance.materialID]; + #if 1 + instance.materialID = indices[needle]; + #elif 1 + for ( size_t i = 0; i < keys.size(); ++i ) { + if ( keys[i] != needle ) continue; + instance.materialID = i; + break; + } + #else + auto it = std::find( keys.begin(), keys.end(), needle ); UF_ASSERT( it != keys.end() ); instance.materialID = it - keys.begin(); + #endif } + if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) { + auto& keys = /*graph.storage*/uf::graph::storage.textures.keys; + auto& indices = /*graph.storage*/uf::graph::storage.textures.indices; + + if ( !(0 <= instance.lightmapID && instance.lightmapID < graph.textures.size()) ) continue; + + auto& needle = graph.textures[instance.lightmapID]; + #if 1 + instance.lightmapID = indices[needle]; + #elif 1 + for ( size_t i = 0; i < keys.size(); ++i ) { + if ( keys[i] != needle ) continue; + instance.lightmapID = i; + break; + } + #else + auto it = std::find( keys.begin(), keys.end(), needle ); + UF_ASSERT( it != keys.end() ); + instance.lightmapID = it - keys.begin(); + #endif + } + #if 0 + // i genuinely dont remember what this is used for + if ( 0 <= instance.imageID && instance.imageID < graph.images.size() ) { auto& keys = /*graph.storage*/uf::graph::storage.images.keys; auto it = std::find( keys.begin(), keys.end(), graph.images[instance.imageID] ); UF_ASSERT( it != keys.end() ); instance.imageID = it - keys.begin(); } + #endif // remap a skinID as an actual jointID if ( 0 <= instance.jointID && instance.jointID < graph.skins.size() ) { auto& name = graph.skins[instance.jointID]; @@ -476,12 +559,6 @@ void uf::graph::process( pod::Graph& graph ) { instance.jointID += joints.size(); } } - if ( 0 <= instance.lightmapID && instance.lightmapID < graph.textures.size() ) { - auto& keys = /*graph.storage*/uf::graph::storage.textures.keys; - auto it = std::find( keys.begin(), keys.end(), graph.textures[instance.lightmapID] ); - UF_ASSERT( it != keys.end() ); - instance.lightmapID = it - keys.begin(); - } } uf::graph::reload(); @@ -814,7 +891,7 @@ void uf::graph::initialize( pod::Graph& graph ) { } void uf::graph::animate( pod::Graph& graph, const uf::stl::string& _name, float speed, bool immediate ) { if ( !(graph.metadata["flags"]["SKINNED"].as()) ) return; - const uf::stl::string name = graph.name + "/" + _name; + const uf::stl::string name = /*graph.name + "/" +*/ _name; // UF_MSG_DEBUG( graph.name << " " << name ); // if ( graph.animations.count( name ) > 0 ) { if ( uf::graph::storage.animations.map.count( name ) > 0 ) { @@ -980,9 +1057,22 @@ void uf::graph::tick() { uf::stl::vector textures; textures.reserve(uf::graph::storage.textures.map.size()); for ( auto key : uf::graph::storage.drawCommands.keys ) drawCommands.insert( drawCommands.end(), uf::graph::storage.drawCommands.map[key].begin(), uf::graph::storage.drawCommands.map[key].end() ); + #if 1 for ( auto key : uf::graph::storage.materials.keys ) materials.emplace_back( uf::graph::storage.materials.map[key] ); for ( auto key : uf::graph::storage.textures.keys ) textures.emplace_back( uf::graph::storage.textures.map[key] ); + #else + uf::stl::map materialOrderedMap; // materialOrderedMap.reserve( uf::graph::storage.materials.keys.size() ); + for ( auto key : uf::graph::storage.materials.keys ) { + materialOrderedMap[uf::graph::storage.materials.indices[key]] = key; + } + for ( auto pair : materialOrderedMap ) materials.emplace_back( uf::graph::storage.materials.map[pair.second] ); + uf::stl::map textureOrderedMap; // textureOrderedMap.reserve( uf::graph::storage.textures.keys.size() ); + for ( auto key : uf::graph::storage.textures.keys ) { + textureOrderedMap[uf::graph::storage.textures.indices[key]] = key; + } + for ( auto pair : textureOrderedMap ) textures.emplace_back( uf::graph::storage.textures.map[pair.second] ); + #endif // uf::graph::storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) ); uf::graph::storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) ); uf::graph::storage.buffers.texture.update( (const void*) textures.data(), textures.size() * sizeof(pod::Texture) ); diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index 284738e1..0726ee0e 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -108,14 +108,6 @@ namespace { } return nodeIndex; } - - template - struct Primitive { - uf::stl::vector vertices; - uf::stl::vector indices; - - pod::Primitive primitive; - }; } pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serializer& metadata ) { @@ -147,7 +139,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize for ( auto& i : model.images ) { auto imageID = graph.images.size(); - auto keyName = graph.images.emplace_back(filename + "/" + i.name); + auto keyName = graph.images.emplace_back(/*filename + "/" +*/ i.name); auto& image = /*graph.storage*/uf::graph::storage.images[keyName]; image.loadFromBuffer( &i.image[0], {i.width, i.height}, 8, i.component, graph.metadata["flip textures"].as(true) ); } @@ -157,7 +149,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize /*graph.storage*/uf::graph::storage.samplers.reserve(model.samplers.size()); for ( auto& s : model.samplers ) { auto samplerID = graph.samplers.size(); - auto keyName = graph.samplers.emplace_back(filename + "/" + s.name); + auto keyName = graph.samplers.emplace_back(/*filename + "/" +*/ s.name); auto& sampler = /*graph.storage*/uf::graph::storage.samplers[keyName]; sampler.descriptor.filter.min = getFilterMode( s.minFilter ); @@ -174,7 +166,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize for ( auto& t : model.textures ) { auto textureID = graph.textures.size(); - auto keyName = graph.textures.emplace_back((t.name == "" ? graph.images[t.source] : (filename + "/" + t.name))); + auto keyName = graph.textures.emplace_back((t.name == "" ? graph.images[t.source] : (/*filename + "/" +*/ t.name))); auto& texture = /*graph.storage*/uf::graph::storage.textures[keyName]; texture.index = t.source; @@ -188,7 +180,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize for ( auto& m : model.materials ) { auto materialID = graph.materials.size(); - auto keyName = graph.materials.emplace_back(filename + "/" + m.name); + auto keyName = graph.materials.emplace_back(/*filename + "/" +*/ m.name); auto& material = /*graph.storage*/uf::graph::storage.materials[keyName]; material.indexAlbedo = m.pbrMetallicRoughness.baseColorTexture.index; @@ -232,7 +224,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize for ( auto& m : model.meshes ) { auto meshID = graph.meshes.size(); - auto keyName = graph.meshes.emplace_back(filename + "/" + m.name); + auto keyName = graph.meshes.emplace_back(/*filename + "/" +*/ m.name); graph.primitives.emplace_back(keyName); graph.drawCommands.emplace_back(keyName); @@ -241,9 +233,38 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize auto& primitives = /*graph.storage*/uf::graph::storage.primitives[keyName]; auto& mesh = /*graph.storage*/uf::graph::storage.meshes[keyName]; - mesh.bindIndirect(); - - size_t divisions = m.name == "worldspawn_20" ? 2 : 1; + struct { + uf::meshgrid::Grid grid; + ext::json::Value metadata; + float eps = std::numeric_limits::epsilon(); + bool print = false; + bool cleanup = true; + } meshgrid; + + if ( ext::json::isObject( graph.metadata["grid"][m.name] ) ) { + meshgrid.metadata = graph.metadata["grid"][m.name]; + } else { + ext::json::forEach( graph.metadata["grid"], [&]( const uf::stl::string& key, ext::json::Value& value ) { + if ( !ext::json::isNull( meshgrid.metadata["size"] ) ) return; + if ( !uf::string::isRegex( key ) ) return; + if ( uf::string::matches( m.name, key ).empty() ) return; + meshgrid.metadata = value; + }); + } + + if ( ext::json::isObject( meshgrid.metadata ) ) { + if ( meshgrid.metadata["size"].is() ) { + size_t d = meshgrid.metadata["size"].as(); + meshgrid.grid.divisions = {d, d, d}; + } else { + meshgrid.grid.divisions = uf::vector::decode( meshgrid.metadata["size"], meshgrid.grid.divisions ); + } + + meshgrid.eps = meshgrid.metadata["epsilon"].as(meshgrid.eps); + meshgrid.print = meshgrid.metadata["print"].as(meshgrid.print); + meshgrid.cleanup = meshgrid.metadata["cleanup"].as(meshgrid.cleanup); + } + if ( graph.metadata["flags"]["SKINNED"].as() ) { #define UF_GRAPH_MESH_FORMAT uf::graph::mesh::Skinned, uint32_t #define UF_GRAPH_PROCESS_PRIMITIVES_FULL 1 @@ -259,9 +280,6 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize #undef UF_GRAPH_MESH_FORMAT } - mesh.insertIndirects(drawCommands); - mesh.updateDescriptor(); - #if 0 if ( m.name == "worldspawn_20" ) { uf::stl::vector<::Primitive<>> objs; @@ -339,7 +357,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize for ( auto& s : model.skins ) { auto skinID = graph.skins.size(); - auto keyName = graph.skins.emplace_back(filename + "/" + s.name); + auto keyName = graph.skins.emplace_back(/*filename + "/" +*/ s.name); auto& skin = /*graph.storage*/uf::graph::storage.skins[keyName]; skin.name = s.name; @@ -373,7 +391,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize for ( auto& a : model.animations ) { auto animationID = graph.animations.size(); - auto keyName = graph.animations.emplace_back(filename + "/" + a.name); + auto keyName = graph.animations.emplace_back(/*filename + "/" +*/ a.name); auto& animation = /*graph.storage*/uf::graph::storage.animations[keyName]; animation.name = a.name; diff --git a/engine/src/ext/gltf/processPrimitives2.inl b/engine/src/ext/gltf/processPrimitives2.inl index 7c009cdc..bcbd60fd 100644 --- a/engine/src/ext/gltf/processPrimitives2.inl +++ b/engine/src/ext/gltf/processPrimitives2.inl @@ -1,10 +1,7 @@ -uf::stl::vector<::Primitive> objs; -uf::stl::vector<::Primitive> slices; - -mesh.bind(); +uf::stl::vector> meshlets; for ( auto& p : m.primitives ) { - auto& obj = objs.emplace_back(); + auto& meshlet = meshlets.emplace_back(); struct Attribute { uf::stl::string name = ""; @@ -41,13 +38,13 @@ for ( auto& p : m.primitives ) { auto& view = model.bufferViews[accessor.bufferView]; if ( attribute.name == "POSITION" ) { - obj.vertices.resize(accessor.count); - obj.primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] }; - obj.primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] }; + meshlet.vertices.resize(accessor.count); + meshlet.primitive.instance.bounds.min = pod::Vector3f{ accessor.minValues[0], accessor.minValues[1], accessor.minValues[2] }; + meshlet.primitive.instance.bounds.max = pod::Vector3f{ accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2] }; if ( !(graph.metadata["flags"]["INVERT"].as()) ){ - obj.primitive.instance.bounds.min.x = -obj.primitive.instance.bounds.min.x; - obj.primitive.instance.bounds.max.x = -obj.primitive.instance.bounds.max.x; + meshlet.primitive.instance.bounds.min.x = -meshlet.primitive.instance.bounds.min.x; + meshlet.primitive.instance.bounds.max.x = -meshlet.primitive.instance.bounds.max.x; } } @@ -83,7 +80,7 @@ for ( auto& p : m.primitives ) { } } - for ( size_t i = 0; i < obj.vertices.size(); ++i ) { + for ( size_t i = 0; i < meshlet.vertices.size(); ++i ) { #if 0 #define ITERATE_ATTRIBUTE( name, member )\ memcpy( &vertex.member[0], &attributes[name].buffer[i * attributes[name].components], attributes[name].stride ); @@ -104,7 +101,7 @@ for ( auto& p : m.primitives ) { } #endif - auto& vertex = obj.vertices[i]; + auto& vertex = meshlet.vertices[i]; ITERATE_ATTRIBUTE("POSITION", position, 1); ITERATE_ATTRIBUTE("TEXCOORD_0", uv, 1); ITERATE_ATTRIBUTE("COLOR_0", color, 255.0f); @@ -133,9 +130,9 @@ for ( auto& p : m.primitives ) { auto& view = model.bufferViews[accessor.bufferView]; auto& buffer = model.buffers[view.buffer]; - obj.indices.reserve( static_cast(accessor.count) ); + meshlet.indices.reserve( static_cast(accessor.count) ); - #define COPY_INDICES() for (size_t index = 0; index < accessor.count; index++) obj.indices.emplace_back(buf[index]); + #define COPY_INDICES() for (size_t index = 0; index < accessor.count; index++) meshlet.indices.emplace_back(buf[index]); const void* pointer = &(buffer.data[accessor.byteOffset + view.byteOffset]); switch (accessor.componentType) { @@ -158,72 +155,54 @@ for ( auto& p : m.primitives ) { #undef COPY_INDICES } - obj.primitive.instance.materialID = p.material; - obj.primitive.instance.primitiveID = objs.size() - 1; - obj.primitive.instance.meshID = meshID; - obj.primitive.instance.objectID = 0; + meshlet.primitive.instance.materialID = p.material; + meshlet.primitive.instance.primitiveID = meshlets.size() - 1; + meshlet.primitive.instance.meshID = meshID; + meshlet.primitive.instance.objectID = 0; - obj.primitive.drawCommand.indices = obj.indices.size(); - obj.primitive.drawCommand.instances = 1; - obj.primitive.drawCommand.indexID = 0; - obj.primitive.drawCommand.vertexID = 0; - obj.primitive.drawCommand.instanceID = 0; - obj.primitive.drawCommand.vertices = obj.vertices.size(); + meshlet.primitive.drawCommand.indices = meshlet.indices.size(); + meshlet.primitive.drawCommand.instances = 1; + meshlet.primitive.drawCommand.indexID = 0; + meshlet.primitive.drawCommand.vertexID = 0; + meshlet.primitive.drawCommand.instanceID = 0; + meshlet.primitive.drawCommand.vertices = meshlet.vertices.size(); } -if ( divisions > 1 ) { - for ( auto& obj : objs ) { - auto grid = uf::meshgrid::partition( obj.vertices, obj.indices, divisions ); - // uf::meshgrid::print( grid, obj.indices.size() ); - for ( auto& node : grid.nodes ) { - auto& slice = slices.emplace_back(); - slice.vertices.reserve( node.indices.size() ); - slice.indices.reserve( node.indices.size() ); - for ( auto& index : node.indices ) { - slice.vertices.emplace_back( obj.vertices[index] ); - slice.indices.emplace_back( slice.indices.size() ); - } +if ( meshgrid.grid.divisions.x > 1 && meshgrid.grid.divisions.y > 1 && meshgrid.grid.divisions.z > 1 ) { + auto partitioned = uf::meshgrid::partition( meshgrid.grid, meshlets, meshgrid.eps ); + if ( meshgrid.print ) UF_MSG_DEBUG( "Draw commands: " << m.name << ": " << meshlets.size() << " -> " << partitioned.size() ); + meshlets = std::move( partitioned ); +} - slice.primitive.instance.materialID = obj.primitive.instance.materialID; - slice.primitive.instance.primitiveID = slices.size() - 1; - slice.primitive.instance.meshID = meshID; - slice.primitive.instance.objectID = 0; +{ + size_t indexID = 0; + size_t vertexID = 0; - slice.primitive.drawCommand.indices = slice.indices.size(); - slice.primitive.drawCommand.instances = 1; - slice.primitive.drawCommand.indexID = 0; - slice.primitive.drawCommand.vertexID = 0; - slice.primitive.drawCommand.instanceID = 0; - slice.primitive.drawCommand.vertices = slice.vertices.size(); - } + mesh.bindIndirect(); + mesh.bind(); + + for ( auto& meshlet : meshlets ) { + drawCommands.emplace_back(pod::DrawCommand{ + .indices = meshlet.indices.size(), + .instances = 1, + .indexID = indexID, + .vertexID = vertexID, + .instanceID = 0, + + + .vertices = meshlet.vertices.size(), + }); + + primitives.emplace_back( meshlet.primitive ); + + indexID += meshlet.indices.size(); + vertexID += meshlet.vertices.size(); + + mesh.insertVertices(meshlet.vertices); + mesh.insertIndices(meshlet.indices); } - UF_MSG_DEBUG( "Draw commands: " << m.name << ": " << objs.size() << " -> " << slices.size() ); -} else { - slices = std::move( objs ); -} - - -size_t indexID = 0; -size_t vertexID = 0; -for ( auto& obj : slices ) { - drawCommands.emplace_back(pod::DrawCommand{ - .indices = obj.indices.size(), - .instances = 1, - .indexID = indexID, - .vertexID = vertexID, - .instanceID = 0, - - - .vertices = obj.vertices.size(), - }); - - primitives.emplace_back( obj.primitive ); - - indexID += obj.indices.size(); - vertexID += obj.vertices.size(); - - mesh.insertVertices(obj.vertices); - mesh.insertIndices(obj.indices); + mesh.insertIndirects(drawCommands); + mesh.updateDescriptor(); } \ No newline at end of file diff --git a/engine/src/ext/reactphysics/reactphysics.cpp b/engine/src/ext/reactphysics/reactphysics.cpp index fe605061..6161ada0 100644 --- a/engine/src/ext/reactphysics/reactphysics.cpp +++ b/engine/src/ext/reactphysics/reactphysics.cpp @@ -94,7 +94,7 @@ namespace { pod::Vector3f position; pod::Vector3f color; - static UF_API uf::stl::vector descriptor; + static uf::stl::vector descriptor; }; UF_VERTEX_DESCRIPTOR(VertexLine, @@ -323,11 +323,11 @@ pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const uf::Mesh rMesh->addSubpart(new rp3d::TriangleVertexArray( vertexInput.count, - (const uint8_t*) (vertexAttribute.pointer + vertexAttribute.stride * vertexInput.first), + (const uint8_t*) (vertexAttribute.pointer) + vertexAttribute.stride * vertexInput.first, vertexAttribute.stride, indexInput.count / 3, - (const uint8_t*) (indexAttribute.pointer + indexAttribute.stride * indexInput.first), + (const uint8_t*) (indexAttribute.pointer) + indexAttribute.stride * indexInput.first, indexAttribute.stride * 3, vertexType, @@ -337,11 +337,11 @@ pod::PhysicsState& ext::reactphysics::create( uf::Object& object, const uf::Mesh } else { rMesh->addSubpart(new rp3d::TriangleVertexArray( vertexInput.count, - (const uint8_t*) (vertexAttribute.pointer + vertexAttribute.stride * vertexInput.first), + (const uint8_t*) (vertexAttribute.pointer) + vertexAttribute.stride * vertexInput.first, vertexAttribute.stride, indexInput.count / 3, - (const uint8_t*) (indexAttribute.pointer + indexAttribute.stride * indexInput.first), + (const uint8_t*) (indexAttribute.pointer) + indexAttribute.stride * indexInput.first, indexAttribute.stride * 3, vertexType, diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 03262108..c9dfc4b4 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -49,7 +49,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { size_t msaa = ext::vulkan::settings::msaa; struct { - size_t id, normals, uvs, albedo, depth, color, bright, scratch, output; + size_t id, normals, uvs, mips, albedo, depth, color, bright, scratch, output; } attachments = {}; bool blend = true; // !ext::vulkan::settings::experimental::deferredSampling; @@ -71,7 +71,15 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { if ( ext::vulkan::settings::experimental::deferredSampling ) { attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ // /*.format = */VK_FORMAT_R32G32B32A32_SFLOAT, - /*.format = */VK_FORMAT_R16G16B16A16_UNORM, + /*.format = */VK_FORMAT_R16G16B16A16_SFLOAT, + /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + /*.blend = */false, + /*.samples = */msaa, + }); + attachments.mips = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + // /*.format = */VK_FORMAT_R32G32B32A32_SFLOAT, + /*.format = */VK_FORMAT_R16G16_SFLOAT, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, /*.blend = */false, @@ -158,7 +166,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { { renderTarget.addPass( /*.*/ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - /*.colors =*/ { attachments.id, attachments.normals, attachments.uvs }, + /*.colors =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.mips }, /*.inputs =*/ {}, /*.resolve =*/{}, /*.depth = */ attachments.depth, @@ -171,7 +179,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { renderTarget.addPass( /*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, /*.colors =*/ { attachments.color, attachments.bright }, - /*.inputs =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.depth }, + /*.inputs =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.depth, attachments.mips }, /*.resolve =*/{}, /*.depth = */attachments.depth, /*.layer = */eye, diff --git a/engine/src/ext/xatlas/xatlas.cpp b/engine/src/ext/xatlas/xatlas.cpp index 0f325470..1f807f1d 100644 --- a/engine/src/ext/xatlas/xatlas.cpp +++ b/engine/src/ext/xatlas/xatlas.cpp @@ -70,16 +70,16 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { auto& decl = entry.decl; - decl.vertexPositionData = positionAttribute.pointer + positionAttribute.stride * vertexInput.first; + decl.vertexPositionData = static_cast(positionAttribute.pointer) + positionAttribute.stride * vertexInput.first; decl.vertexPositionStride = positionAttribute.stride; - decl.vertexUvData = uvAttribute.pointer + uvAttribute.stride * vertexInput.first; + decl.vertexUvData = static_cast(uvAttribute.pointer) + uvAttribute.stride * vertexInput.first; decl.vertexUvStride = uvAttribute.stride; decl.vertexCount = vertexInput.count; decl.indexCount = indexInput.count; - decl.indexData = indexAttribute.pointer + indexAttribute.stride * indexInput.first; + decl.indexData = static_cast(indexAttribute.pointer) + indexAttribute.stride * indexInput.first; decl.indexFormat = indexType; } } else { @@ -87,16 +87,16 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { entry.index = index; auto& decl = entry.decl; - decl.vertexPositionData = positionAttribute.pointer + positionAttribute.stride * vertexInput.first; + decl.vertexPositionData = static_cast(positionAttribute.pointer) + positionAttribute.stride * vertexInput.first; decl.vertexPositionStride = positionAttribute.stride; - decl.vertexUvData = uvAttribute.pointer + uvAttribute.stride * vertexInput.first; + decl.vertexUvData = static_cast(uvAttribute.pointer) + uvAttribute.stride * vertexInput.first; decl.vertexUvStride = uvAttribute.stride; decl.vertexCount = vertexInput.count; decl.indexCount = indexInput.count; - decl.indexData = indexAttribute.pointer + indexAttribute.stride * indexInput.first; + decl.indexData = static_cast(indexAttribute.pointer) + indexAttribute.stride * indexInput.first; decl.indexFormat = indexType; } } else UF_EXCEPTION("to-do: not require indices for meshes"); @@ -181,10 +181,10 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { auto dstAttribute = mesh.vertex.attributes[k]; if ( dstAttribute.descriptor.name == "st" ) { - pod::Vector2f& st = *(pod::Vector2f*) ( dstAttribute.pointer + dstAttribute.stride * (j + dstInput.first) ); + pod::Vector2f& st = *(pod::Vector2f*) ( static_cast(dstAttribute.pointer) + dstAttribute.stride * (j + dstInput.first) ); st = pod::Vector2f{ vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; } else { - memcpy( dstAttribute.pointer + dstAttribute.stride * (j + dstInput.first), srcAttribute.pointer + srcAttribute.stride * (ref + srcInput.first), srcAttribute.stride ); + memcpy( static_cast(dstAttribute.pointer) + dstAttribute.stride * (j + dstInput.first), static_cast(srcAttribute.pointer) + srcAttribute.stride * (ref + srcInput.first), srcAttribute.stride ); } } } @@ -193,7 +193,7 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { uf::Mesh::Input indexInput = mesh.remapIndexInput( entry.command ); uf::Mesh::Attribute indexAttribute = mesh.index.attributes.front(); // uf::Mesh::Attribute indexAttribute = mesh.remapIndexAttribute( mesh.index.attributes.front(), entry.command ); - uint8_t* pointer = (uint8_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first; + uint8_t* pointer = (uint8_t*) static_cast(indexAttribute.pointer) + indexAttribute.stride * indexInput.first; for ( auto index = 0; index < xmesh.indexCount; ++index ) { switch ( mesh.index.size ) { case 1: (( uint8_t*) pointer)[index] = xmesh.indexArray[index]; break; @@ -220,7 +220,7 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { pod::Vector2f& st = *(pod::Vector2f*) ( ((uint8_t*) dstAttribute.pointer) + dstAttribute.stride * j); st = pod::Vector2f{ vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; } else { - memcpy( dstAttribute.pointer + dstAttribute.stride * j, srcAttribute.pointer + srcAttribute.stride * ref, srcAttribute.stride ); + memcpy( static_cast(dstAttribute.pointer) + dstAttribute.stride * j, static_cast(srcAttribute.pointer) + srcAttribute.stride * ref, srcAttribute.stride ); } } /* @@ -304,10 +304,10 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { auto& srcAttribute = source.vertex.attributes[_]; auto& dstAttribute = mesh.vertex.attributes[_]; - memcpy( dstAttribute.pointer + dstAttribute.stride * (vertexInput.first + v), srcAttribute.pointer + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride ); + memcpy( static_cast(dstAttribute.pointer) + dstAttribute.stride * (vertexInput.first + v), static_cast(srcAttribute.pointer) + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride ); } - pod::Vector2f& st = *(pod::Vector2f*) (stAttribute.pointer + stAttribute.stride * (vertexInput.first + v)); + pod::Vector2f& st = *(pod::Vector2f*) (static_cast(stAttribute.pointer) + stAttribute.stride * (vertexInput.first + v)); st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; } // indices @@ -315,9 +315,9 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { indexInput = mesh.remapIndexInput( entry.command ); for ( auto index = 0; index < xmesh.indexCount; ++index ) { switch ( mesh.index.size ) { - case 1: (( uint8_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; - case 2: ((uint16_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; - case 4: ((uint32_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 1: (( uint8_t*) static_cast(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 2: ((uint16_t*) static_cast(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 4: ((uint32_t*) static_cast(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; } } } else { @@ -329,18 +329,18 @@ pod::Vector2ui UF_API ext::xatlas::unwrap( pod::Graph& graph ) { auto& srcAttribute = source.vertex.attributes[_]; auto& dstAttribute = mesh.vertex.attributes[_]; - memcpy( dstAttribute.pointer + dstAttribute.stride * (vertexInput.first + v), srcAttribute.pointer + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride ); + memcpy( static_cast(dstAttribute.pointer) + dstAttribute.stride * (vertexInput.first + v), static_cast(srcAttribute.pointer) + srcAttribute.stride * (vertexInput.first + ref), srcAttribute.stride ); } - pod::Vector2f& st = *(pod::Vector2f*) (stAttribute.pointer + stAttribute.stride * (vertexInput.first + v)); + pod::Vector2f& st = *(pod::Vector2f*) (static_cast(stAttribute.pointer) + stAttribute.stride * (vertexInput.first + v)); st = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height }; } for ( auto index = 0; index < xmesh.indexCount; ++index ) { switch ( mesh.index.size ) { - case 1: (( uint8_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; - case 2: ((uint16_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; - case 4: ((uint32_t*) indexAttribute.pointer + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 1: (( uint8_t*) static_cast(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 2: ((uint16_t*) static_cast(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; + case 4: ((uint32_t*) static_cast(indexAttribute.pointer) + indexAttribute.stride * indexInput.first)[index] = xmesh.indexArray[index]; break; } } } diff --git a/engine/src/utils/math/rayt.cpp b/engine/src/utils/math/rayt.cpp index e083e8f7..1b285968 100644 --- a/engine/src/utils/math/rayt.cpp +++ b/engine/src/utils/math/rayt.cpp @@ -1,3 +1,4 @@ +#if 0 #include #include #include @@ -333,4 +334,5 @@ void uf::primitive::test( const uf::stl::vector& cubes, const uf } } std::cout << "ID: " << id << std::endl; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/utils/mesh/grid.cpp b/engine/src/utils/mesh/grid.cpp index e5c80a64..40c7fb1c 100644 --- a/engine/src/utils/mesh/grid.cpp +++ b/engine/src/utils/mesh/grid.cpp @@ -8,17 +8,21 @@ namespace { } -void UF_API uf::meshgrid::print( const uf::meshgrid::Grid& grid, size_t indices ) { +void UF_API uf::meshgrid::print( const uf::meshgrid::Grid& grid ) { UF_MSG_DEBUG( "== == == =="); float total = 0.0f; - for ( auto& node : grid.nodes ) { - float percentage = 100.0f * node.indices.size() / indices; + for ( auto& pair : grid.nodes ) { auto& node = pair.second; + size_t indices = 0; + for ( auto& pair2 : node.meshlets ) indices += pair2.second.indices.size(); + float percentage = 100.0f * indices / grid.indices; total += percentage; UF_MSG_DEBUG( "[" << node.id.x << "," << node.id.y << "," << node.id.z << "] " "[" << percentage << "%|" << total << "%] " "Min: " << uf::vector::toString( node.extents.min ) << " | " - "Max: " << uf::vector::toString( node.extents.max ) + "Max: " << uf::vector::toString( node.extents.max ) << " | " + "Meshlets: " << node.meshlets.size() << " | " + "Indices: " << indices ); } @@ -29,92 +33,228 @@ void UF_API uf::meshgrid::print( const uf::meshgrid::Grid& grid, size_t indices UF_MSG_DEBUG( "Corner: " << uf::vector::toString( grid.extents.corner ) ); UF_MSG_DEBUG( "Size: " << uf::vector::toString( grid.extents.size ) ); UF_MSG_DEBUG( "Piece: " << uf::vector::toString( grid.extents.piece ) ); + UF_MSG_DEBUG( "Divisions: " << uf::vector::toString( grid.divisions ) ); + UF_MSG_DEBUG( "Nodes: " << grid.nodes.size() ); + UF_MSG_DEBUG( "Indices: " << grid.indices ); UF_MSG_DEBUG( "== == == =="); } +void UF_API uf::meshgrid::cleanup( uf::meshgrid::Grid& grid ) { + uf::stl::vector eraseNodes; -uf::meshgrid::Grid uf::meshgrid::generate( int divisions, - void* pPointer, size_t pStride, size_t pFirst, size_t pCount, - void* iPointer, size_t iStride, size_t iFirst, size_t iCount -) { - uf::meshgrid::Grid grid; - grid.divisions = divisions; - - // calculate extents - for ( size_t i = 0; i < pCount; ++i ) { - pod::Vector3f& position = *(pod::Vector3f*) (pPointer + pStride * (pFirst + i)); - grid.extents.min = uf::vector::min( position, grid.extents.min ); - grid.extents.max = uf::vector::max( position, grid.extents.max ); + for ( auto& pair : grid.nodes ) { auto& node = pair.second; + + uf::stl::vector eraseMeshlets; + for ( auto& pair2 : node.meshlets ) { auto& meshlet = pair2.second; + if ( !meshlet.indices.empty() ) continue; + eraseMeshlets.emplace_back(pair2.first); + } + for ( auto& e : eraseMeshlets ) node.meshlets.erase(e); + + if ( !node.meshlets.empty() ) continue; + eraseNodes.emplace_back(pair.first); } + + for ( auto& e : eraseNodes ) grid.nodes.erase(e); + +/* + for ( auto it = grid.nodes.begin(); it != grid.nodes.end(); ++it ) { + auto& node = it->second; + + uf::stl::vector eraseMeshlets; + for ( auto it2 = node.meshlets.begin(); it2 != node.meshlets.end(); ++it2 ) { + auto& meshlet = it2->second; + + if ( !meshlet.indices.empty() ) continue; + UF_MSG_DEBUG("Erase: " << it2->first); + it2 = node.meshlets.erase(it2); + } + + if ( !node.meshlets.empty() ) continue; + UF_MSG_DEBUG("Erase: " << uf::vector::toString(it->first)); + it = grid.nodes.erase(it); + } +*/ +/* + for ( auto& pair : grid.nodes ) { auto& node = pair.second; + for ( auto& pair2 : node.meshlets ) { auto& meshlet = pair2.second; + if ( !meshlet.indices.empty() ) continue; + // node.meshlets.erase(pair2.first); + // UF_MSG_DEBUG("Erase: " << pair2.first); + } + if ( !node.meshlets.empty() ) continue; + UF_MSG_DEBUG("Erase: " << uf::vector::toString(pair.first)); + grid.nodes.erase(pair.first); + } +*/ +} + +void uf::meshgrid::calculate( uf::meshgrid::Grid& grid, int divisions, float eps ){ + grid.divisions = {divisions, divisions, divisions}; + return calculate( grid, eps ); +} +void uf::meshgrid::calculate( uf::meshgrid::Grid& grid, const pod::Vector3ui& divisions, float eps ){ + grid.divisions = divisions; + return calculate( grid, eps ); +} +void uf::meshgrid::calculate( uf::meshgrid::Grid& grid, float eps ){ + // calculate extents constexpr float epsilon = std::numeric_limits::epsilon(); grid.extents.min -= pod::Vector3f{ epsilon, epsilon, epsilon }; // dilate grid.extents.max += pod::Vector3f{ epsilon, epsilon, epsilon }; // dilate grid.extents.size = uf::vector::abs(grid.extents.max - grid.extents.min); - grid.extents.piece = grid.extents.size / divisions; + grid.extents.piece = grid.extents.size / grid.divisions; grid.extents.center = (grid.extents.max + grid.extents.min) * 0.5f; grid.extents.corner = grid.extents.size * 0.5f; - // initialize - grid.nodes.reserve( divisions * divisions * divisions ); - for ( int z = 0; z < divisions; ++z ) { - for ( int y = 0; y < divisions; ++y ) { - for ( int x = 0; x < divisions; ++x ) { - grid.nodes.emplace_back(uf::meshgrid::Node{ +// initialize + grid.nodes.reserve( grid.divisions.x * grid.divisions.y * grid.divisions.z ); + for ( int z = 0; z < grid.divisions.z; ++z ) { + for ( int y = 0; y < grid.divisions.y; ++y ) { + for ( int x = 0; x < grid.divisions.x; ++x ) { + auto id = pod::Vector3ui{ x, y, z }; + grid.nodes[id] = { .extents = { .min = grid.extents.min + grid.extents.piece * pod::Vector3f{ x, y, z }, .max = grid.extents.min + grid.extents.piece * pod::Vector3f{ x+1, y+1, z+1 }, }, - .id = pod::Vector3ui{ x, y, z }, - }); + .id = id + }; } } } +} +void uf::meshgrid::partition( uf::meshgrid::Grid& grid, + const void* pPointer, size_t pStride, + const void* iPointer, size_t iStride, + const pod::Primitive& primitive +) { + size_t pFirst = primitive.drawCommand.vertexID; + size_t pCount = primitive.drawCommand.vertices; + size_t iFirst = primitive.drawCommand.indexID; + size_t iCount = primitive.drawCommand.indices; + const float oneOverThree = 1.0f / 3.0f; + + struct Triangle { + pod::Vector3ui indices; + pod::Vector3f center; + pod::Vector3f vertices[3]; + }; + uf::stl::vector rejects; + + for ( auto& pair : grid.nodes ) { auto& node = pair.second; + auto& meshlet = node.meshlets[primitive.instance.primitiveID]; + meshlet.primitive = primitive; + meshlet.primitive.instance.bounds.min = node.extents.min; + meshlet.primitive.instance.bounds.max = node.extents.max; + } + // iterate for ( size_t i = 0; i < iCount; i+=3 ) { - size_t indexA = 0; - size_t indexB = 0; - size_t indexC = 0; - - uint8_t* indexPointerA = (uint8_t*) (iPointer + iStride * (iFirst + i + 0)); - uint8_t* indexPointerB = (uint8_t*) (iPointer + iStride * (iFirst + i + 1)); - uint8_t* indexPointerC = (uint8_t*) (iPointer + iStride * (iFirst + i + 2)); + Triangle tri{}; + const uint8_t* indexPointers[3] = { + (static_cast(iPointer) + iStride * (iFirst + i + 0)), + (static_cast(iPointer) + iStride * (iFirst + i + 1)), + (static_cast(iPointer) + iStride * (iFirst + i + 2)), + }; switch ( iStride ) { case sizeof(uint8_t): { - indexA = *( uint8_t*) indexPointerA; - indexB = *( uint8_t*) indexPointerB; - indexC = *( uint8_t*) indexPointerC; + tri.indices[0] = *( const uint8_t*) indexPointers[0]; + tri.indices[1] = *( const uint8_t*) indexPointers[1]; + tri.indices[2] = *( const uint8_t*) indexPointers[2]; } break; case sizeof(uint16_t): { - indexA = *(uint16_t*) indexPointerA; - indexB = *(uint16_t*) indexPointerB; - indexC = *(uint16_t*) indexPointerC; + tri.indices[0] = *(const uint16_t*) indexPointers[0]; + tri.indices[1] = *(const uint16_t*) indexPointers[1]; + tri.indices[2] = *(const uint16_t*) indexPointers[2]; } break; case sizeof(uint32_t): { - indexA = *(uint32_t*) indexPointerA; - indexB = *(uint32_t*) indexPointerB; - indexC = *(uint32_t*) indexPointerC; + tri.indices[0] = *(const uint32_t*) indexPointers[0]; + tri.indices[1] = *(const uint32_t*) indexPointers[1]; + tri.indices[2] = *(const uint32_t*) indexPointers[2]; } break; } - pod::Vector3f& positionA = *(pod::Vector3f*) (pPointer + pStride * (pFirst + indexA)); - pod::Vector3f& positionB = *(pod::Vector3f*) (pPointer + pStride * (pFirst + indexB)); - pod::Vector3f& positionC = *(pod::Vector3f*) (pPointer + pStride * (pFirst + indexC)); + tri.vertices[0] = *(const pod::Vector3f*) (static_cast(pPointer) + pStride * (pFirst + tri.indices[0])); + tri.vertices[1] = *(const pod::Vector3f*) (static_cast(pPointer) + pStride * (pFirst + tri.indices[1])); + tri.vertices[2] = *(const pod::Vector3f*) (static_cast(pPointer) + pStride * (pFirst + tri.indices[2])); + + tri.center = (tri.vertices[0] + tri.vertices[1] + tri.vertices[2]) * oneOverThree; - for ( auto& node : grid.nodes ) { - // if ( isInside( positionA, node.extents.min, node.extents.max ) || isInside( positionB, node.extents.min, node.extents.max ) || isInside( positionC, node.extents.min, node.extents.max ) ) { - if ( isInside( (positionA + positionB + positionC) / 3.0f, node.extents.min, node.extents.max ) ) { - node.indices.emplace_back( indexA ); - node.indices.emplace_back( indexB ); - node.indices.emplace_back( indexC ); + bool found = false; + for ( auto& pair : grid.nodes ) { auto& node = pair.second; + auto& meshlet = node.meshlets[primitive.instance.primitiveID]; + + // if ( isInside( tri.vertices[0], node.extents.min, node.extents.max ) || isInside( tri.vertices[1], node.extents.min, node.extents.max ) || isInside( tri.vertices[2], node.extents.min, node.extents.max ) ) { + if ( isInside( tri.center, node.extents.min, node.extents.max ) ) { + meshlet.indices.emplace_back( tri.indices[0] ); + meshlet.indices.emplace_back( tri.indices[1] ); + meshlet.indices.emplace_back( tri.indices[2] ); + + #pragma unroll // GCC unroll N + for ( uint_fast8_t _ = 0; _ < 3; ++_ ) { + node.effectiveExtents.min = uf::vector::min( node.effectiveExtents.min, tri.vertices[_] ); + node.effectiveExtents.max = uf::vector::max( node.effectiveExtents.max, tri.vertices[_] ); + } + + found = true; + break; } + if ( isInside( tri.vertices[0], node.extents.min, node.extents.max ) || isInside( tri.vertices[1], node.extents.min, node.extents.max ) || isInside( tri.vertices[2], node.extents.min, node.extents.max ) ) { + // if ( isInside( tri.center, node.extents.min, node.extents.max ) ) { + meshlet.indices.emplace_back( tri.indices[0] ); + meshlet.indices.emplace_back( tri.indices[1] ); + meshlet.indices.emplace_back( tri.indices[2] ); + + #pragma unroll // GCC unroll N + for ( uint_fast8_t _ = 0; _ < 3; ++_ ) { + node.effectiveExtents.min = uf::vector::min( node.effectiveExtents.min, tri.vertices[_] ); + node.effectiveExtents.max = uf::vector::max( node.effectiveExtents.max, tri.vertices[_] ); + } + + found = true; + break; + } + } + if ( found ) continue; + rejects.emplace_back(tri); + } + + for ( auto& tri : rejects ) { + uf::meshgrid::Node* closest = NULL; + float closestDistance = std::numeric_limits::max(); + + for ( auto& pair : grid.nodes ) { auto& node = pair.second; + auto nodeCenter = (node.extents.max + node.extents.min) * 0.5f; + float curDistance = uf::vector::distanceSquared( nodeCenter, tri.center ); + if ( curDistance < closestDistance ) { + closestDistance = curDistance; + closest = &node; + } + } + if ( closest ) { + auto& meshlet = closest->meshlets[primitive.instance.primitiveID]; + meshlet.indices.emplace_back( tri.indices[0] ); + meshlet.indices.emplace_back( tri.indices[1] ); + meshlet.indices.emplace_back( tri.indices[2] ); + + #pragma unroll // GCC unroll N + for ( uint_fast8_t _ = 0; _ < 3; ++_ ) { + closest->effectiveExtents.min = uf::vector::min( closest->effectiveExtents.min, tri.vertices[_] ); + closest->effectiveExtents.max = uf::vector::max( closest->effectiveExtents.max, tri.vertices[_] ); + } + + // UF_MSG_DEBUG("REASSIGNED TRI: " << uf::vector::toString(tri.center) << " -> " << uf::vector::toString(closest->id) << " (" << closestDistance << ")"); + } else { + // UF_MSG_DEBUG("REJECT TRI: " << tri.center.x << " " << tri.center.y << " " << tri.center.z); } } - return grid; + grid.indices += iCount; } -uf::meshgrid::Grid UF_API uf::meshgrid::partition( uf::Mesh& mesh, int divisions ) { +void UF_API uf::meshgrid::partition( uf::meshgrid::Grid& grid, uf::Mesh& mesh, const pod::Primitive& primitive ) { uf::Mesh::Input vertexInput = mesh.vertex; uf::Mesh::Input indexInput = mesh.index; @@ -124,83 +264,11 @@ uf::meshgrid::Grid UF_API uf::meshgrid::partition( uf::Mesh& mesh, int divisions for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "position" ) { vertexAttribute = attribute; break; } UF_ASSERT( vertexAttribute.descriptor.name == "position" ); - return generate( divisions, - vertexAttribute.pointer + vertexAttribute.offset, vertexAttribute.stride, vertexInput.first, mesh.vertex.count, - indexAttribute.pointer + indexAttribute.offset, indexAttribute.stride, indexInput.first, mesh.index.count + return partition( grid, + static_cast(vertexAttribute.pointer) + vertexAttribute.offset, vertexAttribute.stride, + static_cast(indexAttribute.pointer) + indexAttribute.offset, indexAttribute.stride, + primitive ); -/* - for ( size_t i = 0; i < mesh.vertex.count; ++i ) { - pod::Vector3f& position = *(pod::Vector3f*) (vertexAttribute.pointer + vertexAttribute.stride * (vertexInput.first + i)); - grid.extents.min = uf::vector::min( position, grid.extents.min ); - grid.extents.max = uf::vector::max( position, grid.extents.max ); - } - constexpr float epsilon = std::numeric_limits::epsilon(); - grid.extents.min -= pod::Vector3f{ epsilon, epsilon, epsilon }; // dilate - grid.extents.max += pod::Vector3f{ epsilon, epsilon, epsilon }; // dilate - grid.extents.size = uf::vector::abs(grid.extents.max - grid.extents.min); - grid.extents.piece = grid.extents.size / divisions; - - grid.extents.center = (grid.extents.max + grid.extents.min) * 0.5f; - grid.extents.corner = grid.extents.size * 0.5f; - - grid.nodes.reserve( divisions * divisions * divisions ); - - for ( int z = 0; z < divisions; ++z ) { - for ( int y = 0; y < divisions; ++y ) { - for ( int x = 0; x < divisions; ++x ) { - grid.nodes.emplace_back(uf::meshgrid::Node{ - .extents = { - .min = grid.extents.min + grid.extents.piece * pod::Vector3f{ x, y, z }, - .max = grid.extents.min + grid.extents.piece * pod::Vector3f{ x+1, y+1, z+1 }, - }, - .id = pod::Vector3ui{ x, y, z }, - }); - } - } - } - - for ( size_t i = 0; i < indexInput.count; i+=3 ) { - size_t indexA = 0; - size_t indexB = 0; - size_t indexC = 0; - - uint8_t* indexPointerA = (uint8_t*) (indexAttribute.pointer + indexAttribute.stride * (indexInput.first + i + 0)); - uint8_t* indexPointerB = (uint8_t*) (indexAttribute.pointer + indexAttribute.stride * (indexInput.first + i + 1)); - uint8_t* indexPointerC = (uint8_t*) (indexAttribute.pointer + indexAttribute.stride * (indexInput.first + i + 2)); - - switch ( indexInput.size ) { - case sizeof(uint8_t): { - indexA = *( uint8_t*) indexPointerA; - indexB = *( uint8_t*) indexPointerB; - indexC = *( uint8_t*) indexPointerC; - } break; - case sizeof(uint16_t): { - indexA = *(uint16_t*) indexPointerA; - indexB = *(uint16_t*) indexPointerB; - indexC = *(uint16_t*) indexPointerC; - } break; - case sizeof(uint32_t): { - indexA = *(uint32_t*) indexPointerA; - indexB = *(uint32_t*) indexPointerB; - indexC = *(uint32_t*) indexPointerC; - } break; - } - - pod::Vector3f& positionA = *(pod::Vector3f*) (vertexAttribute.pointer + vertexAttribute.stride * (vertexInput.first + indexA)); - pod::Vector3f& positionB = *(pod::Vector3f*) (vertexAttribute.pointer + vertexAttribute.stride * (vertexInput.first + indexB)); - pod::Vector3f& positionC = *(pod::Vector3f*) (vertexAttribute.pointer + vertexAttribute.stride * (vertexInput.first + indexC)); - - for ( auto& node : grid.nodes ) { - // if ( isInside( positionA, node.extents.min, node.extents.max ) || isInside( positionB, node.extents.min, node.extents.max ) || isInside( positionC, node.extents.min, node.extents.max ) ) { - if ( isInside( (positionA + positionB + positionC) / 3.0f, node.extents.min, node.extents.max ) ) { - node.indices.emplace_back( indexA ); - node.indices.emplace_back( indexB ); - node.indices.emplace_back( indexC ); - } - } - } - return grid; -*/ } #if 0 diff --git a/engine/src/utils/mesh/mesh.cpp b/engine/src/utils/mesh/mesh.cpp index ca641cb5..5400f6ab 100644 --- a/engine/src/utils/mesh/mesh.cpp +++ b/engine/src/utils/mesh/mesh.cpp @@ -132,8 +132,8 @@ uf::Mesh uf::Mesh::expand( bool interleaved ) { auto& dstIndex = res.index.attributes.front(); #define GET_INDEX(T) {\ - index = *(const T*) (srcIndex.pointer + idx * srcIndex.stride);\ - *((T*) (dstIndex.pointer + idx * dstIndex.stride)) = idx;\ + index = *(const T*) (static_cast(srcIndex.pointer) + idx * srcIndex.stride);\ + *((T*) (static_cast(dstIndex.pointer) + idx * dstIndex.stride)) = idx;\ } for ( size_t idx = 0; idx < index.count; ++idx ) { @@ -148,8 +148,8 @@ uf::Mesh uf::Mesh::expand( bool interleaved ) { auto& srcInput = vertex.attributes[_]; auto& dstInput = res.vertex.attributes[_]; - memcpy( dstInput.pointer, srcInput.pointer + index * srcInput.stride, srcInput.descriptor.size ); - dstInput.pointer += dstInput.stride; + memcpy( dstInput.pointer, static_cast(srcInput.pointer) + index * srcInput.stride, srcInput.descriptor.size ); + dstInput.pointer = static_cast(dstInput.pointer) + dstInput.stride; } } @@ -362,7 +362,9 @@ void uf::Mesh::_updateDescriptor( uf::Mesh::Input& input ) { attribute.length = buffer.size(); attribute.pointer = buffer.data() + attribute.offset; input.size += attribute.descriptor.size; - if ( interleaved ) attribute.pointer += attribute.descriptor.offset; + if ( interleaved ) { + attribute.pointer = static_cast(attribute.pointer) + attribute.descriptor.offset; + } } for ( auto& attribute : input.attributes ) { attribute.stride = isInterleaved(input.interleaved) ? input.size : attribute.descriptor.size; @@ -377,10 +379,10 @@ uf::Mesh::Attribute uf::Mesh::_remapAttribute( const uf::Mesh::Input& input, con auto& drawCommand = ((const pod::DrawCommand*) getBuffer(indirect).data())[i]; if ( &input == &vertex ) { - res.pointer += drawCommand.vertexID * res.stride; + res.pointer = static_cast(res.pointer) + drawCommand.vertexID * res.stride; res.length = drawCommand.vertices * res.stride; } else if ( &input == &index ) { - res.pointer += drawCommand.indexID * res.stride; + res.pointer = static_cast(res.pointer) + drawCommand.indexID * res.stride; res.length = drawCommand.indices * res.stride; } return res; @@ -426,7 +428,7 @@ void uf::Mesh::_insertVs( uf::Mesh::Input& dstInput, const uf::Mesh& mesh, const while ( _++ < _srcInput.count ) { for ( auto& srcAttribute : _srcInput.attributes ) { dst.insert( dst.end(), (uint8_t*) srcAttribute.pointer, (uint8_t*) srcAttribute.pointer + srcAttribute.descriptor.size ); - srcAttribute.pointer += srcAttribute.descriptor.size; + srcAttribute.pointer = static_cast(srcAttribute.pointer) + srcAttribute.descriptor.size; } } } else if ( !isInterleaved(dstInput.interleaved) && isInterleaved(srcInput.interleaved) ) { @@ -476,7 +478,7 @@ void uf::Mesh::_insertIs( uf::Mesh::Input& dstInput, const uf::Mesh& mesh, const while ( _++ < _srcInput.count ) { for ( auto& srcAttribute : _srcInput.attributes ) { dst.insert( dst.end(), (uint8_t*) srcAttribute.pointer, (uint8_t*) srcAttribute.pointer + srcAttribute.descriptor.size ); - srcAttribute.pointer += srcAttribute.descriptor.size; + srcAttribute.pointer = static_cast(srcAttribute.pointer) + srcAttribute.descriptor.size; } } } else if ( !isInterleaved(dstInput.interleaved) && isInterleaved(srcInput.interleaved) ) { diff --git a/engine/src/utils/string/ext.cpp b/engine/src/utils/string/ext.cpp index 1bec5baf..771d72b4 100644 --- a/engine/src/utils/string/ext.cpp +++ b/engine/src/utils/string/ext.cpp @@ -6,6 +6,33 @@ #include #include +#include + +/* +bool UF_API uf::string::match( const uf::stl::string& str, const uf::stl::string& r ) { + std::regex regex(r); + std::smatch match; + return std::regex_search( str, match, regex ); +} +*/ +bool UF_API uf::string::isRegex( const uf::stl::string& str ) { + return str.front() == '/' && str.back() == '/'; +} +uf::stl::vector UF_API uf::string::matches( const uf::stl::string& str, const uf::stl::string& r ) { + + std::regex regex(r.substr(1,r.length()-2)); + std::smatch match; + uf::stl::vector matches; + if ( std::regex_search( str, match, regex ) ) { + for ( auto& m : match ) { + UF_MSG_DEBUG(m); + matches.emplace_back(m.str()); + } + } + + return matches; +} + uf::stl::string UF_API uf::string::lowercase( const uf::stl::string& str ) { uf::stl::string lower = str; std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index a2938332..09068186 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -91,7 +91,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { */ }); this->addHook( "world:Entity.LoadAsset", [&](pod::payloads::assetLoad& payload){ - assetLoader.load("asset:Load." + payload.uid, payload); + assetLoader.load("asset:Load." + std::to_string(payload.uid), payload); }); this->addHook( "shader:Update.%UID%", [&](ext::json::Value& json){ metadata.shader.mode = json["mode"].as(); diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index fa2c5ac6..bddd7c0c 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -908,7 +908,7 @@ void ext::GuiBehavior::tick( uf::Object& self ) { UF_ASSERT( vertexAttribute.descriptor.name == "position" ); for ( auto i = 0; i < mesh.vertex.count; ++i ) { - float* p = (float*) (vertexAttribute.pointer + i * vertexAttribute.stride ); + float* p = (float*) (static_cast(vertexAttribute.pointer) + i * vertexAttribute.stride ); pod::Vector4f position = { p[0], p[1], 0, 1 }; pod::Vector4f translated = uf::matrix::multiply( model, position ); min.x = std::min( min.x, translated.x );