From 595e9869036c57ddf7649fbcf194b0854cb01171 Mon Sep 17 00:00:00 2001 From: ecker Date: Thu, 11 Jun 2026 00:08:31 -0500 Subject: [PATCH] did not plan on actually implementing tr_polys with forward+ (it didn't even solve the issue of incadescent light panels not working right because they're baked into worldspawn) --- bin/data/config.json | 2 +- .../scenes/sourceengine/sourceengine.json | 4 +- bin/data/shaders/base/graph/frag.glsl | 191 ++++++++++++++++++ bin/data/shaders/common/functions.h | 9 +- bin/data/shaders/common/structs.h | 3 + bin/data/shaders/display/deferred/comp/comp.h | 39 ++-- bin/data/shaders/graph/base/frag.glsl | 3 + engine/inc/uf/engine/graph/graph.h | 2 +- engine/inc/uf/engine/graph/pod.inl | 16 ++ engine/inc/uf/utils/math/physics/common.h | 2 +- engine/inc/uf/utils/math/physics/structs.h | 14 -- engine/src/engine/graph/graph.cpp | 50 +++-- engine/src/ext/valve/bsp.cpp | 13 +- engine/src/ext/vulkan/graphic.cpp | 4 + .../src/ext/vulkan/rendermodes/deferred.cpp | 80 +++++--- .../src/ext/vulkan/rendermodes/transition.inl | 18 +- engine/src/utils/math/physics/common.cpp | 14 +- 17 files changed, 365 insertions(+), 99 deletions(-) create mode 100644 bin/data/shaders/base/graph/frag.glsl diff --git a/bin/data/config.json b/bin/data/config.json index 8090d3c5..4abfad31 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -87,7 +87,7 @@ ] }, "framebuffer": { - "msaa": 8, + "msaa": 2, "size": 1 // "size": [ 640, 480, "NEAREST" ] // "size": [ 1280, 720 ] diff --git a/bin/data/scenes/sourceengine/sourceengine.json b/bin/data/scenes/sourceengine/sourceengine.json index bdb37541..065d566b 100644 --- a/bin/data/scenes/sourceengine/sourceengine.json +++ b/bin/data/scenes/sourceengine/sourceengine.json @@ -1,7 +1,7 @@ { // "import": "./rp_downtown_v2.json" // "import": "./ss2_medsci1.json" - "import": "./mds_mcdonalds.json" -// "import": "./cs_office.json" +// "import": "./mds_mcdonalds.json" + "import": "./cs_office.json" // "import": "./gm_construct.json" } \ No newline at end of file diff --git a/bin/data/shaders/base/graph/frag.glsl b/bin/data/shaders/base/graph/frag.glsl new file mode 100644 index 00000000..c9ce3350 --- /dev/null +++ b/bin/data/shaders/base/graph/frag.glsl @@ -0,0 +1,191 @@ +#version 450 +#pragma shader_stage(fragment) + +#define FORWARD 0 +#define FRAGMENT 1 +#define PBR 1 + +layout (constant_id = 0) const uint TEXTURES = 1; +layout (constant_id = 1) const uint CUBEMAPS = 128; + +#include "../../common/macros.h" +#include "../../common/structs.h" + +layout (binding = 6, set = 1) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 7, set = 1) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 8, set = 0) uniform sampler3D samplerNoise; +#if VXGI + layout (binding = 9, set = 0) uniform sampler3D voxelOutput[CASCADES]; +#endif +#if RT + layout (binding = 10, set = 0) uniform accelerationStructureEXT tlas; +#endif +layout (std140, binding = 11, set = 0) readonly buffer DrawCommands { DrawCommand drawCommands[]; }; +layout (std140, binding = 12, set = 0) readonly buffer Instances { Instance instances[]; }; +layout (std140, binding = 13, set = 0) readonly buffer InstanceAddresseses { InstanceAddresses addresses[]; }; +layout (std140, binding = 14, set = 0) readonly buffer Materials { Material materials[]; }; +layout (std140, binding = 15, set = 0) readonly buffer Textures { Texture textures[]; }; +layout (std140, binding = 16, set = 0) readonly buffer Lights { Light lights[]; }; +layout (std140, binding = 17, set = 0) readonly buffer Objects { Object objects[]; }; + +layout (binding = 18) uniform Camera { Viewport viewport[2]; } camera; + +// to-do: bind UBO for settings? +/* +layout (binding = 19) uniform UBO { EyeMatrices eyes[2]; Settings settings; } ubo; +*/ + +#include "../../common/functions.h" +//#include "../../common/light.h" +//#include "../../common/shadows.h" + +layout (location = 0) flat in uvec4 inId; +layout (location = 1) flat in vec4 inPOS0; +layout (location = 2) in vec4 inPOS1; +layout (location = 3) in vec3 inPosition; +layout (location = 4) sample in vec2 inUv; +layout (location = 5) in vec4 inColor; +layout (location = 6) in vec2 inSt; +layout (location = 7) in vec3 inNormal; +layout (location = 8) in vec3 inTangent; + +layout (location = 0) out vec4 outFragColor; + +void main() { + const uint triangleID = gl_PrimitiveID; + const uint drawID = uint(inId.y); + const uint instanceID = uint(inId.z); + +#if 0 + +#if CAN_DISCARD + const DrawCommand drawCommand = drawCommands[drawID]; + const Instance instance = instances[instanceID]; + const Material material = materials[instance.materialID]; + + surface.uv.xy = wrap(inUv.xy); + surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv)); + + surface.st.xy = wrap(inSt.xy); + surface.st.z = mipLevel(dFdx(inSt), dFdy(inSt)); + + vec4 A = inColor * material.colorBase; + // sample albedo + if ( validTextureIndex( material.indexAlbedo ) ) { + A = sampleTexture( material.indexAlbedo ); + } + if ( A.a < 0.0001 ) discard; +#endif + + outFragColor.rgb = A.rgb; + outFragColor.a = A.a; +#else + const DrawCommand drawCommand = drawCommands[drawID]; + surface.instance = instances[instanceID]; + surface.object = objects[surface.instance.objectID]; + const Material material = materials[surface.instance.materialID]; + + surface.uv.xy = wrap(inUv.xy); + surface.st.xy = wrap(inSt.xy); + + surface.dUvDx = dFdx(inUv); + surface.dUvDy = dFdy(inUv); + + surface.dStDx = dFdx(inSt); + surface.dStDy = dFdy(inSt); + + surface.uv.z = mipLevel(surface.dUvDx, surface.dUvDy); + surface.st.z = mipLevel(surface.dStDx, surface.dStDy); + + surface.position.world = inPosition; + surface.position.eye = vec3( inverse( surface.object.model ) * vec4(surface.position.world, 1.0) ); + + surface.normal.world = normalize(inNormal); + surface.tangent.world = normalize(inTangent); + vec3 bitangent = cross(surface.normal.world, surface.tangent.world); + surface.tbn = mat3(surface.tangent.world, bitangent, surface.normal.world); + + // + surface.material.albedo = material.colorBase; + surface.material.metallic = material.factorMetallic; + surface.material.roughness = material.factorRoughness; + surface.material.occlusion = material.factorOcclusion; + surface.material.lightmapped = false; + surface.light = material.colorEmissive; + + if ( validTextureIndex( material.indexAlbedo ) ) { + surface.material.albedo *= sampleTexture( material.indexAlbedo ); + } + // OPAQUE + if ( material.modeAlpha == 0 ) { + surface.material.albedo.a = 1; + // BLEND + } else if ( material.modeAlpha == 1 ) { + + // MASK + } else if ( material.modeAlpha == 2 ) { + + // EMISSIVE + } else if ( material.modeAlpha == 3 ) { + surface.light.rgb *= surface.material.albedo.rgb * surface.material.albedo.a; + surface.material.albedo.a = 1.0; + } + + // Emissive mapping + if ( validTextureIndex( material.indexEmissive ) ) { + surface.light *= sampleTexture( material.indexEmissive ); + } + // (Occlusion/)Metallic/Roughness map + if ( validTextureIndex( material.indexMetallicRoughness ) ) { + vec4 samp = sampleTexture( material.indexMetallicRoughness ); + + surface.material.metallic *= samp.b; + surface.material.roughness *= samp.g; + + if ( material.indexOcclusion == material.indexMetallicRoughness ) { + surface.material.occlusion = mix(1.0, samp.r, material.factorOcclusion); + } + } + // Occlusion mapping + if ( validTextureIndex( material.indexOcclusion ) && material.indexOcclusion != material.indexMetallicRoughness ) { + float occ = sampleTexture( material.indexOcclusion ).r; + surface.material.occlusion = mix(1.0, occ, material.factorOcclusion); + } + // Normal mapping + if ( validTextureIndex( material.indexNormal ) && surface.tangent.world != vec3(0) ) { + surface.normal.world = surface.tbn * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - vec3(1.0)); + } + { + surface.normal.eye = normalize(vec3( inverse( surface.object.model ) * vec4(surface.normal.world, 0.0) )); + } + + // Light mapping + if ( /*( bool(ubo.settings.lighting.useLightmaps)) &&*/ validTextureIndex( surface.instance.lightmapID ) ) { + surface.material.lightmapped = true; // light.a > 0.001; + vec4 light = decodeRGBE( sampleTexture( surface.instance.lightmapID, surface.st.xy, 0.0 ) ); + + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize(-surface.position.eye); + const float cosLo = max(0.0, dot(surface.normal.eye, Lo)); + const vec3 F = F0 + (max(vec3(1.0 - surface.material.roughness), F0) - F0) * pow(clamp(1.0 - cosLo, 0.0, 1.0), 5.0); + const vec3 kD = (vec3(1.0) - F) * (1.0 - surface.material.metallic); + + surface.light.rgb += (kD * surface.material.albedo.rgb * light.rgb) * surface.material.occlusion; + } + + if ( surface.material.albedo.a < 0.0001 && dot(surface.light.rgb, vec3(1.0)) < 0.0001 ) discard; + + surface.fragment = vec4(0.0); + surface.light.rgb += surface.material.albedo.rgb /* ubo.settings.lighting.ambient.rgb*/ * surface.material.occlusion; + +/* +#if PBR + pbr(); +#elif LAMBERT + lambert(); +#endif +*/ + outFragColor.rgb = surface.fragment.rgb + surface.light.rgb; + outFragColor.a = surface.material.albedo.a; +#endif +} \ No newline at end of file diff --git a/bin/data/shaders/common/functions.h b/bin/data/shaders/common/functions.h index bd549aa6..46a7a0fa 100644 --- a/bin/data/shaders/common/functions.h +++ b/bin/data/shaders/common/functions.h @@ -174,7 +174,7 @@ vec3 decodeSrgb(vec3 rgb) { const vec3 c = step(vec3(0.04045), rgb); return mix(a, b, c); } -#if !SPD && (DEFERRED || FRAGMENT || COMPUTE || RT) +#if !SPD && (DEFERRED || FRAGMENT || COMPUTE || RT || FORWARD) bool validTextureIndex( int textureIndex ) { return 0 <= textureIndex && textureIndex < MAX_TEXTURES; } @@ -304,6 +304,10 @@ void populateSurfaceMaterial() { // MASK } else if ( material.modeAlpha == 2 ) { + // EMISSIVE + } else if ( material.modeAlpha == 3 ) { + surface.light.rgb *= surface.material.albedo.rgb * surface.material.albedo.a; + surface.material.albedo.a = 1.0; } // Emissive mapping @@ -348,7 +352,8 @@ void populateSurfaceMaterial() { surface.light.rgb += (kD * surface.material.albedo.rgb * light.rgb) * surface.material.occlusion; } } - +#endif +#if DEFERRED_SAMPLING bool isValidAddress( uint64_t address ) { #if UINT64_ENABLED return bool(address); diff --git a/bin/data/shaders/common/structs.h b/bin/data/shaders/common/structs.h index 8e89ad4a..4d002017 100644 --- a/bin/data/shaders/common/structs.h +++ b/bin/data/shaders/common/structs.h @@ -177,6 +177,8 @@ struct Surface { vec2 motion; vec2 dUvDx; vec2 dUvDy; + vec2 dStDx; + vec2 dStDy; Ray ray; @@ -192,6 +194,7 @@ struct Surface { #if MULTISAMPLING struct MSAA { int currentID; + float depth; uvec2 IDs[MAX_MSAA_SAMPLES]; vec4 fragment; vec4 fragments[MAX_MSAA_SAMPLES]; diff --git a/bin/data/shaders/display/deferred/comp/comp.h b/bin/data/shaders/display/deferred/comp/comp.h index bd726f6f..65bf6187 100644 --- a/bin/data/shaders/display/deferred/comp/comp.h +++ b/bin/data/shaders/display/deferred/comp/comp.h @@ -53,6 +53,9 @@ layout (constant_id = 1) const uint CUBEMAPS = 128; layout(binding = 7, set = 0, rgba16f) uniform writeonly image2DArray imageColor; layout(binding = 8, set = 0, rgba16f) uniform writeonly image2DArray imageBright; layout(binding = 9, set = 0, rg16f) uniform writeonly image2DArray imageMotion; +#if MULTISAMPLING +layout(binding = 10, set = 0, r32f) uniform writeonly image2DArray imageDepthResolved; +#endif layout( push_constant ) uniform PushBlock { uint pass; @@ -61,46 +64,46 @@ layout( push_constant ) uniform PushBlock { #include "../../../common/structs.h" -layout (binding = 10, set = 0) uniform Camera { +layout (binding = 11, set = 0) uniform Camera { Viewport viewport[2]; } camera; -layout (binding = 11, set = 0) uniform UBO { +layout (binding = 12, set = 0) uniform UBO { EyeMatrices eyes[2]; Settings settings; } ubo; -layout (std140, binding = 12, set = 0) readonly buffer DrawCommands { +layout (std140, binding = 13, set = 0) readonly buffer DrawCommands { DrawCommand drawCommands[]; }; -layout (std140, binding = 13, set = 0) readonly buffer Instances { +layout (std140, binding = 14, set = 0) readonly buffer Instances { Instance instances[]; }; -layout (std140, binding = 14, set = 0) readonly buffer InstanceAddresseses { +layout (std140, binding = 15, set = 0) readonly buffer InstanceAddresseses { InstanceAddresses addresses[]; }; -layout (std140, binding = 15, set = 0) readonly buffer Objects { +layout (std140, binding = 16, set = 0) readonly buffer Objects { Object objects[]; }; -layout (std140, binding = 16, set = 0) readonly buffer Materials { +layout (std140, binding = 17, set = 0) readonly buffer Materials { Material materials[]; }; -layout (std140, binding = 17, set = 0) readonly buffer Textures { +layout (std140, binding = 18, set = 0) readonly buffer Textures { Texture textures[]; }; -layout (std140, binding = 18, set = 0) readonly buffer Lights { +layout (std140, binding = 19, set = 0) readonly buffer Lights { Light lights[]; }; -layout (binding = 19, set = 1) uniform sampler2D samplerTextures[TEXTURES]; -layout (binding = 20, set = 1) uniform samplerCube samplerCubemaps[CUBEMAPS]; -layout (binding = 21, set = 0) uniform sampler3D samplerNoise; +layout (binding = 20, set = 1) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 21, set = 1) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 22, set = 0) uniform sampler3D samplerNoise; #if VXGI - layout (binding = 22, set = 0) uniform sampler3D voxelOutput[CASCADES]; + layout (binding = 23, set = 0) uniform sampler3D voxelOutput[CASCADES]; #endif #if RT - layout (binding = 23, set = 0) uniform accelerationStructureEXT tlas; + layout (binding = 24, set = 0) uniform accelerationStructureEXT tlas; #endif #if BUFFER_REFERENCE @@ -334,11 +337,17 @@ void indirectLighting() { #if MULTISAMPLING void resolveSurfaceFragment() { msaa.fragment = vec4(0.0); + msaa.depth = texelFetch(samplerDepth, ivec3(gl_GlobalInvocationID.xyz), 0).r; for ( int i = 0; i < ubo.settings.mode.msaa; ++i ) { msaa.currentID = i; msaa.IDs[i] = uvec3(IMAGE_LOAD(samplerId)).xy; + if ( i > 0 ) { + float depth = texelFetch(samplerDepth, ivec3(gl_GlobalInvocationID.xyz), i).r; + msaa.depth = max(msaa.depth, depth); + } + bool unique = true; for ( int j = msaa.currentID - 1; j >= 0; --j ) { if ( msaa.IDs[j] == msaa.IDs[i] ) { @@ -369,5 +378,7 @@ void resolveSurfaceFragment() { } surface.fragment = msaa.fragment / float(ubo.settings.mode.msaa); + + IMAGE_STORE( imageDepthResolved, vec4(msaa.depth, 0, 0, 0) ); } #endif \ No newline at end of file diff --git a/bin/data/shaders/graph/base/frag.glsl b/bin/data/shaders/graph/base/frag.glsl index 4f84325f..b3782e84 100644 --- a/bin/data/shaders/graph/base/frag.glsl +++ b/bin/data/shaders/graph/base/frag.glsl @@ -102,6 +102,9 @@ void main() { } else if ( material.modeAlpha == 2 ) { if ( A.a < abs(material.factorAlphaCutoff) ) discard; A.a = 1; + // alpha mode EMISSIVE + } else if ( material.modeAlpha == 3 ) { + A.a = 1; } if ( A.a < 0.0001 ) discard; diff --git a/engine/inc/uf/engine/graph/graph.h b/engine/inc/uf/engine/graph/graph.h index 5664d041..5da77ebe 100644 --- a/engine/inc/uf/engine/graph/graph.h +++ b/engine/inc/uf/engine/graph/graph.h @@ -72,7 +72,7 @@ namespace pod { uf::stl::string tag = "worldspawn"; uf::stl::string player = "info_player_spawn"; - uint64_t hash = 0; + size_t hash = 0; float lastUpdate = 0; } stream; } settings; diff --git a/engine/inc/uf/engine/graph/pod.inl b/engine/inc/uf/engine/graph/pod.inl index 3fe075ce..4e19f190 100644 --- a/engine/inc/uf/engine/graph/pod.inl +++ b/engine/inc/uf/engine/graph/pod.inl @@ -1,5 +1,21 @@ + +#undef OPAQUE + namespace pod { struct UF_API Material { + struct AlphaMode { + static constexpr int32_t NONE = -1; + static constexpr int32_t OPAQUE = 0; + static constexpr int32_t BLEND = 1; + static constexpr int32_t MASK = 2; + static constexpr int32_t EMISSIVE = 3; + }; + + struct CullMode { + static constexpr int32_t DEFAULT = -1; + static constexpr int32_t NONE = 0; + }; + pod::Vector4f colorBase = { 0, 0, 0, 0 }; pod::Vector4f colorEmissive = { 0, 0, 0, 0 }; diff --git a/engine/inc/uf/utils/math/physics/common.h b/engine/inc/uf/utils/math/physics/common.h index bb33e89b..b3382835 100644 --- a/engine/inc/uf/utils/math/physics/common.h +++ b/engine/inc/uf/utils/math/physics/common.h @@ -5,7 +5,7 @@ // to-do: organize this mess namespace impl { - uint64_t makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b ); + size_t makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b ); void wakeBody( pod::PhysicsBody& body ); void sleepBody( pod::PhysicsBody& body ); void updateActivity( pod::PhysicsBody& body, float dt ); diff --git a/engine/inc/uf/utils/math/physics/structs.h b/engine/inc/uf/utils/math/physics/structs.h index 484ecafb..629bac51 100644 --- a/engine/inc/uf/utils/math/physics/structs.h +++ b/engine/inc/uf/utils/math/physics/structs.h @@ -221,20 +221,6 @@ namespace pod { struct BVH { typedef uint32_t index_t; typedef std::pair pair_t; - - struct PairHash { - size_t operator()( const pair_t& p ) const noexcept { - uint64_t a = (uint64_t) std::min(p.first, p.second); - uint64_t b = (uint64_t) std::max(p.first, p.second); - return (a << 32) ^ b; - } - }; - struct PairEq { - bool operator()( const pair_t& a, const pair_t& b ) const noexcept { - return (a.first == b.first && a.second == b.second) || (a.first == b.second && a.second == b.first); - } - }; - typedef uf::stl::vector pairs_t; struct Node { diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 4caac42f..36da151e 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -98,7 +98,8 @@ namespace { // standard pipeline { - uf::stl::string vertexShaderFilename = graphMetadataJson["shaders"]["vertex"].as("/graph/base/vert.spv"); { + uf::stl::string dir = "/graph/base/"; + uf::stl::string vertexShaderFilename = graphMetadataJson["shaders"]["vertex"].as(::fmt::format("{}/{}", dir, "vert.spv" )); { std::pair settings[] = { { graphMetadataJson["renderer"]["skinned"].as(), "skinned.vert" }, { !graphMetadataJson["renderer"]["separate"].as(), "instanced.vert" }, @@ -109,7 +110,11 @@ namespace { uf::stl::string geometryShaderFilename = graphMetadataJson["shaders"]["geometry"].as(""); if ( geometryShaderFilename != "" ) { geometryShaderFilename = entity.resolveURI( geometryShaderFilename, root ); } - uf::stl::string fragmentShaderFilename = graphMetadataJson["shaders"]["fragment"].as("/graph/base/frag.spv"); { + + if ( graphic.descriptor.renderTarget == 1 ) { + dir = "/base/graph/"; + } + uf::stl::string fragmentShaderFilename = graphMetadataJson["shaders"]["fragment"].as(::fmt::format("{}/{}", dir, "frag.spv")); { fragmentShaderFilename = entity.resolveURI( fragmentShaderFilename, root ); } @@ -136,12 +141,20 @@ namespace { { auto& shader = graphic.material.getShader("fragment"); #if UF_USE_VULKAN - uint32_t maxTextures = storage.textures.map.size(); + size_t maxTextures = storage.textures.map.size(); + size_t maxCubemaps = uf::config["engine"]["scenes"]["textures"]["max"]["cube"].as(128); + size_t maxTextures3D = uf::config["engine"]["scenes"]["textures"]["max"]["3D"].as(128); + uint32_t maxCascades = sceneTextures.voxels.id.size(); + shader.setSpecializationConstants({ { "TEXTURES", maxTextures }, + { "CUBEMAPS", maxCubemaps }, + { "CASCADES", maxCascades }, }); shader.setDescriptorCounts({ { "samplerTextures", maxTextures }, + { "samplerCubemaps", maxCubemaps }, + { "voxelOutput", maxCascades }, }); #endif } @@ -385,6 +398,8 @@ namespace { shader.aliasBuffer( "material", storage.buffers.material ); shader.aliasBuffer( "texture", storage.buffers.texture ); shader.aliasBuffer( "light", storage.buffers.light ); + shader.aliasBuffer( "object", storage.buffers.object ); + shader.aliasBuffer( "camera", storage.buffers.camera ); } } @@ -718,14 +733,20 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M } // query materials if culling needs to be disabled - for ( auto& primitive : primitives ) { - auto materialID = primitive.instance.materialID; - if ( 0 <= materialID && materialID <= graph.materials.size() ) { - auto& materialName = graph.materials[materialID]; - auto& material = storage.materials[materialName]; - if ( material.modeCull == 0 ) { - tag["renderer"]["cull mode"] = "none"; - break; + if ( entity.getName() != "worldspawn" ) { + for ( auto& primitive : primitives ) { + auto materialID = primitive.instance.materialID; + if ( 0 <= materialID && materialID <= graph.materials.size() ) { + auto& materialName = graph.materials[materialID]; + auto& material = storage.materials[materialName]; + if ( material.modeCull == pod::Material::CullMode::NONE ) { + tag["renderer"]["cull mode"] = "none"; + } + #if UF_USE_VULKAN + if ( material.modeAlpha == pod::Material::AlphaMode::BLEND ) { + graphic.descriptor.renderTarget = 1; + } + #endif } } } @@ -1032,9 +1053,10 @@ void uf::graph::process( pod::Graph& graph ) { if ( tag["material"]["modeAlpha"].is() ) { const auto mode = uf::string::lowercase( tag["material"]["modeAlpha"].as() ); - if ( mode == "opaque" ) material.modeAlpha = 0; - else if ( mode == "blend" ) material.modeAlpha = 1; - else if ( mode == "mask" ) material.modeAlpha = 2; + if ( mode == "opaque" ) material.modeAlpha = pod::Material::AlphaMode::OPAQUE; + else if ( mode == "blend" ) material.modeAlpha = pod::Material::AlphaMode::BLEND; + else if ( mode == "mask" ) material.modeAlpha = pod::Material::AlphaMode::MASK; + else if ( mode == "emissive" ) material.modeAlpha = pod::Material::AlphaMode::EMISSIVE; else UF_MSG_WARNING("Invalid AlphaMode enum string specified: {}", mode); } else { material.modeAlpha = tag["material"]["modeAlpha"].as(material.modeAlpha); diff --git a/engine/src/ext/valve/bsp.cpp b/engine/src/ext/valve/bsp.cpp index 8c27ac9b..79604c9f 100644 --- a/engine/src/ext/valve/bsp.cpp +++ b/engine/src/ext/valve/bsp.cpp @@ -933,16 +933,17 @@ void ext::valve::loadBsp( pod::Graph& graph, const uf::stl::string& filename, co if ( vmt["$phong"].as(0) == 1 ) material.factorRoughness = std::min(material.factorRoughness, 0.5f); if ( vmt["$translucent"].as(0) == 1 ) { - material.modeAlpha = 1; // BLEND + material.modeAlpha = pod::Material::AlphaMode::BLEND; } else if ( vmt["$alphatest"].as(0) == 1 ) { - material.modeAlpha = 2; // MASK + material.modeAlpha = pod::Material::AlphaMode::MASK; material.factorAlphaCutoff = vmt["$alphatestreference"].as(0.5f); } - if ( vmt["$nocull"].as(0) == 1 ) material.modeCull = 0; + if ( vmt["$nocull"].as(0) == 1 ) material.modeCull = pod::Material::CullMode::NONE; - // VMTs usually define emissive masks in the albedo's alpha channel or a separate mask - // set it to a white glow for now until I can patch the shader - if ( vmt["$selfillum"].as(0) == 1 ) material.colorEmissive = { 1.0f, 1.0f, 1.0f, 1.0f }; + if ( vmt["$selfillum"].as(0) == 1 ) { + material.colorEmissive = { 1.0f, 1.0f, 1.0f, 1.0f }; + material.modeAlpha = pod::Material::AlphaMode::EMISSIVE; + } if ( !vmt["$basetexture"].is() ) goto PEETAH; vtfPath = ::fmt::format("materials/{}.vtf", vmt["$basetexture"].as()); diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 3ca5c491..8867a616 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -339,6 +339,10 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes samples, 0 ); + // cringe + if ( samples > 1 && descriptor.renderTarget == 1 ) { + multisampleState.alphaToCoverageEnable = VK_TRUE; + } if ( samples > 1 && device.features.sampleRateShading ) { multisampleState.sampleShadingEnable = VK_TRUE; multisampleState.minSampleShading = 0.25f; diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index b5d32b5d..bf3ea6c1 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -118,7 +118,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { size_t msaa = ext::vulkan::settings::msaa; struct { - size_t id, bary, depth, uv, normal; + size_t id, bary, depth, depth_resolved, uv, normal; size_t color, scratch, motion, output; } attachments = {}; @@ -172,7 +172,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.format =*/ ext::vulkan::settings::pipelines::hdr ? enums::Format::HDR : enums::Format::SDR, /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - /*.blend =*/ false, + /*.blend =*/ true, /*.samples =*/ 1, }); attachments.scratch = renderTarget.attach(RenderTarget::Attachment::Descriptor{ @@ -192,6 +192,20 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.samples = */1, }); + if ( msaa > 1 ) { + attachments.depth_resolved = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + .format = ext::vulkan::settings::formats::depth, + .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .blend = false, + .samples = 1, + .mips = 1, + }); + } else { + attachments.depth_resolved = attachments.depth; + } + + metadata.attachments["id"] = attachments.id; #if BARYCENTRIC @@ -204,6 +218,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { #endif metadata.attachments["depth"] = attachments.depth; + metadata.attachments["depth_resolved"] = attachments.depth_resolved; metadata.attachments["color"] = attachments.color; metadata.attachments["scratch"] = attachments.scratch; metadata.attachments["motion"] = attachments.motion; @@ -266,7 +281,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { } attachmentsPlus = {}; attachmentsPlus.color = forwardRenderTarget.aliasAttachment(this->getAttachment("color")); - attachmentsPlus.depth = forwardRenderTarget.aliasAttachment(this->getAttachment("depth")); + attachmentsPlus.depth = forwardRenderTarget.aliasAttachment(this->getAttachment("depth_resolved")); metadata.attachments["color+"] = attachmentsPlus.color; metadata.attachments["depth+"] = attachmentsPlus.depth; @@ -387,6 +402,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL); shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL); shader.aliasAttachment("motion", this, VK_IMAGE_LAYOUT_GENERAL); + shader.aliasAttachment("depth_resolved", this, VK_IMAGE_LAYOUT_GENERAL); } if ( settings::pipelines::bloom ) { @@ -429,7 +445,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { auto& shader = blitter.material.getShader("compute", "dof-down"); shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL); - shader.aliasAttachment("depth", this); + shader.aliasAttachment("depth_resolved", this); shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL); // atomic counter buffer @@ -446,7 +462,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { auto& shader = blitter.material.getShader("compute", "dof-up"); shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL); - shader.aliasAttachment("depth", this); + shader.aliasAttachment("depth_resolved", this); shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL); { @@ -463,7 +479,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { auto& shader = blitter.material.getShader("compute", "depth-pyramid"); - shader.aliasAttachment("depth", this); + shader.aliasAttachment("depth_resolved", this); // atomic counter buffer ::postprocesses::depthPyramid.atomicCounter.initialize( (const void*) nullptr, sizeof(::AtomicCounter) * 1, uf::renderer::enums::Buffer::STORAGE ); @@ -650,7 +666,7 @@ void ext::vulkan::DeferredRenderMode::tick() { forwardRenderTarget.scale = renderTarget.scale; forwardRenderTarget.attachments.clear(); forwardRenderTarget.aliasAttachment(this->getAttachment("color")); - forwardRenderTarget.aliasAttachment(this->getAttachment("depth")); + forwardRenderTarget.aliasAttachment(this->getAttachment("depth_resolved")); forwardRenderTarget.initialize( *forwardRenderTarget.device ); } @@ -934,35 +950,35 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto // forward+ { { - device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "forward:setImageLayout" ); + device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "forward:setImageLayout" ); - // Transition Color - VkImageSubresourceRange colorRange = {}; - colorRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - colorRange.baseMipLevel = 0; - colorRange.levelCount = 1; - colorRange.baseArrayLayer = 0; - colorRange.layerCount = metadata.eyes; // Or this->views + // Transition Color + VkImageSubresourceRange colorRange = {}; + colorRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + colorRange.baseMipLevel = 0; + colorRange.levelCount = 1; + colorRange.baseArrayLayer = 0; + colorRange.layerCount = metadata.eyes; - uf::renderer::Texture::setImageLayout( - commandBuffer, - forwardRenderTarget.attachments[0].image, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - colorRange - ); + uf::renderer::Texture::setImageLayout( + commandBuffer, + forwardRenderTarget.attachments[0].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + colorRange + ); - // Transition Depth - VkImageSubresourceRange depthRange = colorRange; - depthRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; // Depth aspect! + // Transition Depth + VkImageSubresourceRange depthRange = colorRange; + depthRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - uf::renderer::Texture::setImageLayout( - commandBuffer, - forwardRenderTarget.attachments[1].image, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - depthRange - ); + uf::renderer::Texture::setImageLayout( + commandBuffer, + forwardRenderTarget.attachments[1].image, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + depthRange + ); } renderPassBeginInfo.clearValueCount = 0; diff --git a/engine/src/ext/vulkan/rendermodes/transition.inl b/engine/src/ext/vulkan/rendermodes/transition.inl index 34da3375..042a3aa2 100644 --- a/engine/src/ext/vulkan/rendermodes/transition.inl +++ b/engine/src/ext/vulkan/rendermodes/transition.inl @@ -35,10 +35,15 @@ namespace { } } if ( image == VK_NULL_HANDLE ) continue; + bool isDepth = descriptor.name.starts_with("depth"); subresourceRange.baseMipLevel = 0; subresourceRange.levelCount = 1; - subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - uf::renderer::Texture::setImageLayout( commandBuffer, image, layout, descriptor.layout, subresourceRange ); + subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + VkImageLayout oldLayout = layout; + if ( isDepth && layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) { + oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + } + uf::renderer::Texture::setImageLayout( commandBuffer, image, oldLayout, descriptor.layout, subresourceRange ); if ( mips > 1 ) { subresourceRange.baseMipLevel = 1; subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; @@ -82,10 +87,15 @@ namespace { } } if ( image == VK_NULL_HANDLE ) continue; + bool isDepth = descriptor.name.starts_with("depth"); subresourceRange.baseMipLevel = 0; subresourceRange.levelCount = 1; - subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - uf::renderer::Texture::setImageLayout( commandBuffer, image, descriptor.layout, layout, subresourceRange ); + subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + VkImageLayout newLayout = layout; + if ( isDepth && layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) { + newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + } + uf::renderer::Texture::setImageLayout( commandBuffer, image, descriptor.layout, newLayout, subresourceRange ); if ( mips > 1 ) { subresourceRange.baseMipLevel = 1; subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; diff --git a/engine/src/utils/math/physics/common.cpp b/engine/src/utils/math/physics/common.cpp index 0239e2a6..736a45ed 100644 --- a/engine/src/utils/math/physics/common.cpp +++ b/engine/src/utils/math/physics/common.cpp @@ -1,14 +1,12 @@ #include // create ID from pointers -uint64_t impl::makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b ) { - uint64_t lhs = reinterpret_cast(&a); - uint64_t rhs = reinterpret_cast(&b); - if (lhs > rhs) std::swap(lhs, rhs); - size_t seed = 0; - seed ^= std::hash{}(lhs) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - seed ^= std::hash{}(rhs) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; +size_t impl::makePairKey( const pod::PhysicsBody& a, const pod::PhysicsBody& b ) { + uintptr_t lhs = reinterpret_cast(&a); + uintptr_t rhs = reinterpret_cast(&b); + if ( lhs > rhs ) std::swap(lhs, rhs); + size_t hash = uf::algo::fnv1a(lhs); + return uf::algo::fnv1a(rhs, hash); } // marks a body as asleep