diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp index 1da064fb6..f2dfc3ff6 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp @@ -250,7 +250,7 @@ void VkDescriptorSetManager::CreateLevelMeshLayout() .AddBinding(1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) .AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) .AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) - .AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) .AddBinding(5, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) .AddBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT) .DebugName("VkDescriptorSetManager.LevelMesh.Layout") @@ -273,24 +273,24 @@ void VkDescriptorSetManager::CreateRSBufferLayout() void VkDescriptorSetManager::CreateFixedLayout() { DescriptorSetLayoutBuilder builder; - builder.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.AddBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.AddBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.AddBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.AddBinding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); if (fb->IsRayQueryEnabled()) { - builder.AddBinding(5, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(5, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); } else { - builder.AddBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); } - builder.AddBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.AddBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.AddBinding(8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.AddBinding(9, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.AddBinding(10, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(9, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(10, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); builder.DebugName("VkDescriptorSetManager.Fixed.SetLayout"); Fixed.Layout = builder.Create(fb->GetDevice()); } @@ -383,7 +383,7 @@ void VkDescriptorSetManager::CreateBindlessSet() .AddBinding( 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MaxBindlessTextures, - VK_SHADER_STAGE_FRAGMENT_BIT, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT) .DebugName("Bindless.Layout") .Create(fb->GetDevice()); diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 64195d7e8..a933341cd 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -205,15 +205,16 @@ static std::vector vertexShaderOutputs { {"vTexCoord", "", UniformType::Vec4, FieldCondition::ALWAYS}, //0 {"vColor", "", UniformType::Vec4, FieldCondition::ALWAYS}, //1 - {"pixelpos", "", UniformType::Vec4, FieldCondition::NOTSIMPLE}, //2 + {"pixelpos", "", UniformType::Vec4, FieldCondition::ALWAYS}, //2 {"glowdist", "", UniformType::Vec3, FieldCondition::NOTSIMPLE}, //3 {"gradientdist", "", UniformType::Vec3, FieldCondition::NOTSIMPLE}, //4 - {"vWorldNormal", "", UniformType::Vec4, FieldCondition::NOTSIMPLE}, //5 - {"vEyeNormal", "", UniformType::Vec4, FieldCondition::NOTSIMPLE}, //6 + {"vWorldNormal", "", UniformType::Vec4, FieldCondition::ALWAYS}, //5 + {"vEyeNormal", "", UniformType::Vec4, FieldCondition::ALWAYS}, //6 {"ClipDistanceA", "", UniformType::Vec4, FieldCondition::HAS_CLIPDISTANCE}, //7 {"ClipDistanceB", "", UniformType::Vec4, FieldCondition::HAS_CLIPDISTANCE}, //8 {"vLightmap", "", UniformType::Vec3, FieldCondition::ALWAYS}, //9 {"uDataIndex", "flat", UniformType::Int, FieldCondition::USELEVELMESH}, //10 + {"vLightColor", "", UniformType::Vec3, FieldCondition::SHADE_VERTEX}, //11 }; static std::vector fragShaderOutputs @@ -423,7 +424,7 @@ void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defin switch (key.ShadeVertex) { case 1: definesBlock << "#define SHADE_VERTEX\n"; break; - case 2: definesBlock << "#define SHADE_VERTEX_CENTER\n"; break; + case 2: definesBlock << "#define SHADE_VERTEX\n#define SHADE_VERTEX_CENTER\n"; break; //case 3: definesBlock << "#define ???\n"; break; } diff --git a/wadsrc/static/shaders/scene/binding_fixed.glsl b/wadsrc/static/shaders/scene/binding_fixed.glsl index 4d2215353..a684efb88 100644 --- a/wadsrc/static/shaders/scene/binding_fixed.glsl +++ b/wadsrc/static/shaders/scene/binding_fixed.glsl @@ -6,7 +6,6 @@ layout(set = 0, binding = 2) uniform sampler2D LinearDepth; layout(set = 0, binding = 3) uniform samplerCubeArray IrradianceMap; layout(set = 0, binding = 4) uniform samplerCubeArray PrefilterMap; -#if defined(USE_RAYTRACE) #if defined(SUPPORTS_RAYQUERY) layout(set = 0, binding = 5) uniform accelerationStructureEXT acc; @@ -29,4 +28,4 @@ layout(set = 0, binding = 7, std430) buffer readonly ElementBuffer { int elem layout(set = 0, binding = 8, std430) buffer readonly SurfaceIndexBuffer { uint surfaceIndices[]; }; layout(set = 0, binding = 9, std430) buffer readonly SurfaceBuffer { SurfaceInfo surfaces[]; }; layout(set = 0, binding = 10, std430) buffer readonly PortalBuffer { PortalInfo portals[]; }; -#endif + diff --git a/wadsrc/static/shaders/scene/light_shadow.glsl b/wadsrc/static/shaders/scene/light_shadow.glsl index 2f6bf0647..7a058e7da 100644 --- a/wadsrc/static/shaders/scene/light_shadow.glsl +++ b/wadsrc/static/shaders/scene/light_shadow.glsl @@ -3,84 +3,7 @@ #if defined(USE_RAYTRACE) -#include -#include -#include - -float TraceDynLightRay(vec3 origin, float tmin, vec3 direction, float dist) -{ - float alpha = 1.0; - - for (int i = 0; i < 3; i++) - { - TraceResult result = TraceFirstHit(origin, tmin, direction, dist); - - // Stop if we hit nothing - the point light is visible. - if (result.primitiveIndex == -1) - return alpha; - - SurfaceInfo surface = GetSurface(result.primitiveIndex); - - // Pass through surface texture - alpha = PassRayThroughSurfaceDynLight(surface, GetSurfaceUV(result.primitiveIndex, result.primitiveWeights), alpha); - - // Stop if there is no light left - if (alpha <= 0.0) - return 0.0; - - // Move to surface hit point - origin += direction * result.t; - dist -= result.t; - - // Move through the portal, if any - TransformRay(surface.PortalIndex, origin, direction); - } - - return 0.0; -} - -float traceHit(vec3 origin, vec3 direction, float dist) -{ - #if defined(USE_RAYTRACE_PRECISE) - return TraceDynLightRay(origin, 0.01f, direction, dist); - #else - return TraceAnyHit(origin, 0.01f, direction, dist) ? 0.0 : 1.0; - #endif -} - -float traceShadow(vec3 lightpos, float softShadowRadius) -{ - vec3 origin = pixelpos.xyz + vWorldNormal.xyz; - vec3 target = lightpos.xyz + 0.01; // nudge light position slightly as Doom maps tend to have their lights perfectly aligned with planes - - vec3 direction = normalize(target - origin); - float dist = distance(origin, target); - -#if SHADOWMAP_FILTER == 0 - return traceHit(origin, direction, dist); -#else - if (softShadowRadius == 0) - { - return traceHit(origin, direction, dist); - } - else - { - vec3 v = (abs(direction.x) > abs(direction.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0); - vec3 xdir = normalize(cross(direction, v)); - vec3 ydir = cross(direction, xdir); - - float sum = 0.0; - const int step_count = SHADOWMAP_FILTER * 4; - for (int i = 0; i < step_count; i++) - { - vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * softShadowRadius; - vec3 pos = target + xdir * gridoffset.x + ydir * gridoffset.y; - sum += traceHit(origin, normalize(pos - origin), dist); - } - return (sum / step_count); - } -#endif -} +#include float shadowAttenuation(vec3 lightpos, int shadowIndex, float softShadowRadius) { diff --git a/wadsrc/static/shaders/scene/light_trace.glsl b/wadsrc/static/shaders/scene/light_trace.glsl new file mode 100644 index 000000000..0b6d07e4e --- /dev/null +++ b/wadsrc/static/shaders/scene/light_trace.glsl @@ -0,0 +1,79 @@ + +#include +#include +#include + +float TraceDynLightRay(vec3 origin, float tmin, vec3 direction, float dist) +{ + float alpha = 1.0; + + for (int i = 0; i < 3; i++) + { + TraceResult result = TraceFirstHit(origin, tmin, direction, dist); + + // Stop if we hit nothing - the point light is visible. + if (result.primitiveIndex == -1) + return alpha; + + SurfaceInfo surface = GetSurface(result.primitiveIndex); + + // Pass through surface texture + alpha = PassRayThroughSurfaceDynLight(surface, GetSurfaceUV(result.primitiveIndex, result.primitiveWeights), alpha); + + // Stop if there is no light left + if (alpha <= 0.0) + return 0.0; + + // Move to surface hit point + origin += direction * result.t; + dist -= result.t; + + // Move through the portal, if any + TransformRay(surface.PortalIndex, origin, direction); + } + + return 0.0; +} + +float traceHit(vec3 origin, vec3 direction, float dist) +{ + #if defined(USE_RAYTRACE_PRECISE) + return TraceDynLightRay(origin, 0.01f, direction, dist); + #else + return TraceAnyHit(origin, 0.01f, direction, dist) ? 0.0 : 1.0; + #endif +} + +float traceShadow(vec3 lightpos, float softShadowRadius) +{ + vec3 origin = pixelpos.xyz + vWorldNormal.xyz; + vec3 target = lightpos.xyz + 0.01; // nudge light position slightly as Doom maps tend to have their lights perfectly aligned with planes + + vec3 direction = normalize(target - origin); + float dist = distance(origin, target); + +#if SHADOWMAP_FILTER == 0 + return traceHit(origin, direction, dist); +#else + if (softShadowRadius == 0) + { + return traceHit(origin, direction, dist); + } + else + { + vec3 v = (abs(direction.x) > abs(direction.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0); + vec3 xdir = normalize(cross(direction, v)); + vec3 ydir = cross(direction, xdir); + + float sum = 0.0; + const int step_count = SHADOWMAP_FILTER * 4; + for (int i = 0; i < step_count; i++) + { + vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * softShadowRadius; + vec3 pos = target + xdir * gridoffset.x + ydir * gridoffset.y; + sum += traceHit(origin, normalize(pos - origin), dist); + } + return (sum / step_count); + } +#endif +} \ No newline at end of file diff --git a/wadsrc/static/shaders/scene/lightmodel_normal.glsl b/wadsrc/static/shaders/scene/lightmodel_normal.glsl index bc1a32921..4101e08c0 100644 --- a/wadsrc/static/shaders/scene/lightmodel_normal.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_normal.glsl @@ -44,6 +44,7 @@ vec4 dynlight = uDynLightColor; vec3 normal = material.Normal; +#if !defined(SHADE_VERTEX) if (uLightIndex >= 0) { ivec4 lightRange = getLightRange(); @@ -63,6 +64,9 @@ } } } +#else + dynlight.rgb += vLightColor; +#endif #ifdef LIGHT_BLEND_CLAMPED @@ -80,6 +84,7 @@ #endif +#if !defined(SHADE_VERTEX) if (uLightIndex >= 0) { ivec4 lightRange = getLightRange(); @@ -96,6 +101,7 @@ frag = clamp(frag + desaturate(addlight).rgb, 0.0, 1.0); } } +#endif return frag; } diff --git a/wadsrc/static/shaders/scene/vert_main.glsl b/wadsrc/static/shaders/scene/vert_main.glsl index 6661663f8..0a94c3cd5 100644 --- a/wadsrc/static/shaders/scene/vert_main.glsl +++ b/wadsrc/static/shaders/scene/vert_main.glsl @@ -1,6 +1,89 @@ #include "shaders/scene/bones.glsl" +#if defined(SHADE_VERTEX) && !defined(PBR) && !defined(SPECULAR) && !defined(SIMPLE) +#undef SHADOWMAP_FILTER +#define SHADOWMAP_FILTER 0 + #include + #include + #include + + vec3 lightValue(DynLightInfo light) + { + float lightdistance = distance(light.pos.xyz, pixelpos.xyz); + + if (light.radius < lightdistance) + return vec3(0.0); // Early out lights touching surface but not this fragment + + vec3 lightdir = normalize(light.pos.xyz - pixelpos.xyz); + float dotprod = dot(vWorldNormal.xyz, lightdir); + + float attenuation = distanceAttenuation(lightdistance, light.radius, light.strength, light.linearity); + + if ((light.flags & LIGHTINFO_SPOT) != 0) + { + attenuation *= spotLightAttenuation(light.pos.xyz, light.spotDir.xyz, light.spotInnerAngle, light.spotOuterAngle); + } + + if ((light.flags & LIGHTINFO_ATTENUATED) != 0) + { + attenuation *= clamp(dotprod, 0.0, 1.0); + } + + + if (attenuation > 0.0) // Skip shadow map test if possible + { + #ifdef USE_RAYTRACE + // light.radius >= 1000000.0 is sunlight(?), skip attenuation + if(light.radius < 1000000.0 && (light.flags & LIGHTINFO_SHADOWMAPPED) != 0) + { + attenuation *= traceShadow(light.pos.xyz, light.softShadowRadius); + } + #endif + + return light.color.rgb * attenuation; + } + else + { + return vec3(0.0); + } + + return vec3(0.0); + } + + vec3 ProcessVertexLight() + { + #if defined(USE_LEVELMESH) + const int lightTileSize = 1; + uLightIndex = int(uint(gl_FragCoord.x) / 64 + uint(gl_FragCoord.y) / 64 * uLightTilesWidth) * lightTileSize; + #endif + + vec3 light = vec3(0.0); + + if (uLightIndex >= 0) + { + ivec4 lightRange = getLightRange(); + + if (lightRange.z > lightRange.x) + { + // modulated lights + for(int i=lightRange.x; i 0 || uGlowBottomColor.a > 0) - { - float topatpoint = (uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z; - float bottomatpoint = (uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z; - glowdist.x = topatpoint - worldcoord.y; - glowdist.y = worldcoord.y - bottomatpoint; - glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); - } + #if !defined(SIMPLE) + if (uGlowTopColor.a > 0 || uGlowBottomColor.a > 0) + { + float topatpoint = (uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z; + float bottomatpoint = (uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z; + glowdist.x = topatpoint - worldcoord.y; + glowdist.y = worldcoord.y - bottomatpoint; + glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); + } - if (uObjectColor2.a != 0) - { - float topatpoint = (uGradientTopPlane.w + uGradientTopPlane.x * worldcoord.x + uGradientTopPlane.y * worldcoord.z) * uGradientTopPlane.z; - float bottomatpoint = (uGradientBottomPlane.w + uGradientBottomPlane.x * worldcoord.x + uGradientBottomPlane.y * worldcoord.z) * uGradientBottomPlane.z; - gradientdist.x = topatpoint - worldcoord.y; - gradientdist.y = worldcoord.y - bottomatpoint; - gradientdist.z = clamp(gradientdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); - } + if (uObjectColor2.a != 0) + { + float topatpoint = (uGradientTopPlane.w + uGradientTopPlane.x * worldcoord.x + uGradientTopPlane.y * worldcoord.z) * uGradientTopPlane.z; + float bottomatpoint = (uGradientBottomPlane.w + uGradientBottomPlane.x * worldcoord.x + uGradientBottomPlane.y * worldcoord.z) * uGradientBottomPlane.z; + gradientdist.x = topatpoint - worldcoord.y; + gradientdist.y = worldcoord.y - bottomatpoint; + gradientdist.z = clamp(gradientdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); + } + #endif if (uSplitBottomPlane.z != 0.0) { @@ -123,5 +208,9 @@ void main() gl_PointSize = 1.0; + #if defined(SHADE_VERTEX) && !defined(PBR) && !defined(SPECULAR) && !defined(SIMPLE) + vLightColor = ProcessVertexLight(); + #endif + ModifyVertex(); }