From cd902baa8540c37ae09f375fb21853fcc0439f0d Mon Sep 17 00:00:00 2001 From: Peter Li Date: Sat, 10 May 2025 17:27:37 -0700 Subject: [PATCH] very shitty ssao implementation --- engine/core/src/math.zig | 4 + engine/core/tests/tests.zig | 32 +++ engine/imgui/src/sgpu/backend_impl.zig | 9 + engine/rend/build.zig | 2 + engine/rend/shaders/lit_mesh.frag.hlsl | 5 + engine/rend/shaders/lit_mesh.frag.json | 22 +- engine/rend/shaders/meshes.vert.hlsl | 3 +- engine/rend/shaders/postProc.frag.hlsl | 16 +- engine/rend/shaders/postProc.frag.json | 12 + engine/rend/shaders/randomSamplesFloat3.hlsli | 65 +++++ engine/rend/shaders/ssao.frag.hlsl | 79 +++++++ engine/rend/shaders/ssao.frag.json | 119 ++++++++++ engine/rend/src/sgpu/DebugDrawSystem.zig | 10 +- engine/rend/src/sgpu/renderer.zig | 69 +++++- engine/rend/src/sgpu/ssao.zig | 222 ++++++++++++++++++ engine/ui/src/sgpu/papyrusSgpu.zig | 22 +- .../content/_shaders/dxil/lit_mesh.frag.dxil | Bin 7840 -> 8136 bytes .../content/_shaders/dxil/meshes.vert.dxil | Bin 6796 -> 6904 bytes .../content/_shaders/dxil/postProc.frag.dxil | Bin 4508 -> 4696 bytes projects/content/_shaders/dxil/ssao.frag.dxil | Bin 0 -> 8364 bytes .../content/_shaders/msl/lit_mesh.frag.msl | 178 +++++++------- projects/content/_shaders/msl/meshes.vert.msl | 12 +- .../content/_shaders/msl/postProc.frag.msl | 36 +-- projects/content/_shaders/msl/ssao.frag.msl | 115 +++++++++ .../content/_shaders/spv/lit_mesh.frag.spv | Bin 7652 -> 7980 bytes projects/content/_shaders/spv/meshes.vert.spv | Bin 3280 -> 3232 bytes .../content/_shaders/spv/postProc.frag.spv | Bin 2780 -> 3156 bytes projects/content/_shaders/spv/ssao.frag.spv | Bin 0 -> 9064 bytes 28 files changed, 900 insertions(+), 132 deletions(-) create mode 100644 engine/rend/shaders/randomSamplesFloat3.hlsli create mode 100644 engine/rend/shaders/ssao.frag.hlsl create mode 100644 engine/rend/shaders/ssao.frag.json create mode 100644 engine/rend/src/sgpu/ssao.zig create mode 100644 projects/content/_shaders/dxil/ssao.frag.dxil create mode 100644 projects/content/_shaders/msl/ssao.frag.msl create mode 100644 projects/content/_shaders/spv/ssao.frag.spv diff --git a/engine/core/src/math.zig b/engine/core/src/math.zig index f0ba558..0df548a 100644 --- a/engine/core/src/math.zig +++ b/engine/core/src/math.zig @@ -605,6 +605,10 @@ pub const Rotation = struct { } }; +pub fn lerp(a: f32, b: f32, t: f32) f32 { + return a + t * (b - a); +} + pub fn simdVec4ToVec(vec: zm.Vec) Vector4f { return .{ .x = vec[0], diff --git a/engine/core/tests/tests.zig b/engine/core/tests/tests.zig index 9be35ec..f4b4f7b 100644 --- a/engine/core/tests/tests.zig +++ b/engine/core/tests/tests.zig @@ -25,9 +25,41 @@ test "simple systems setup for core" { try test_consoleCommands(); try test_gameObjects(std.testing.allocator); + try generateRandomSamples(); + try memory.dumpTimeline("test-core-timeline.txt"); } +fn generateRandomSamples() !void { + var prng = std.Random.DefaultPrng.init(blk: { + var seed: u64 = undefined; + try std.posix.getrandom(std.mem.asBytes(&seed)); + break :blk seed; + }); + const rand = prng.random(); + + std.debug.print("const float3[] = {{", .{}); + for (0..64) |i| { + var vec = core.Vectorf{ + .x = rand.float(f32) * 2.0 - 1.0, + .y = rand.float(f32) * 2.0 - 1.0, + .z = rand.float(f32), + }; + + vec = vec.normalize(); + vec = vec.fmul(rand.float(f32)); + + var scale: f32 = @as(f32, @floatFromInt(i)) / 64.0; + scale = scale * core.lerp(0.1, 1.0, scale * scale); + vec = vec.fmul(scale); + + // std.debug.print("( {d}, {d}, {d} )\n", .{ vec.x, vec.y, vec.z }); + std.debug.print(" float3( {d}, {d}, {d} ),\n", .{ vec.x, vec.y, vec.z }); + } + + std.debug.print("}};\n", .{}); +} + fn test_loadingConfigs() !void { if (core.getConfigVar(u32, "platform.extent.width")) |width| { core.engine_log("config: {d}", .{width}); diff --git a/engine/imgui/src/sgpu/backend_impl.zig b/engine/imgui/src/sgpu/backend_impl.zig index cd1c2cf..5027319 100644 --- a/engine/imgui/src/sgpu/backend_impl.zig +++ b/engine/imgui/src/sgpu/backend_impl.zig @@ -88,6 +88,15 @@ pub const Impl = struct { if (self.dtAverage > 0.000001) { ig.textFmt("frameTime: {d:.2}ms ({d:.2}fps)", .{ self.dtAverage * 1000, @as(u32, @intFromFloat(1 / self.dtAverage)) }) catch return error.UnknownStatePanic; } + + ig.textFmt("SSAO settings: ", .{}) catch unreachable; + + const ssao = rend.context().ssaoSystem; + _ = ig.sliderFloat("radius", &ssao.radius, 0.1, 1.0, null, .{}); + _ = ig.sliderFloat("bias", &ssao.bias, 0.0025, 1.0, null, .{}); + + _ = ig.checkbox("enable SSAO", &ssao.enable); + ig.end(); } } diff --git a/engine/rend/build.zig b/engine/rend/build.zig index 832ab05..2cf2924 100644 --- a/engine/rend/build.zig +++ b/engine/rend/build.zig @@ -47,6 +47,8 @@ pub fn build(b: *std.Build) void { sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "postProc.frag", b.path("shaders/postProc.frag.json")); sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "postProc.vert", b.path("shaders/postProc.vert.json")); + sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "ssao.frag", b.path("shaders/ssao.frag.json")); + // ========== tests ========== const tests = b.addTest(.{ .target = target, diff --git a/engine/rend/shaders/lit_mesh.frag.hlsl b/engine/rend/shaders/lit_mesh.frag.hlsl index c2a7ff7..2a6f215 100644 --- a/engine/rend/shaders/lit_mesh.frag.hlsl +++ b/engine/rend/shaders/lit_mesh.frag.hlsl @@ -177,6 +177,8 @@ float3 DirectionalLight(float3 normal, float3 fragPos, float4 DirectionalShadow struct PixelOutput { float4 Color : SV_Target0; // First render target float4 Emissive : SV_Target1; // Second render target + float4 Position : SV_Target2; // Used for SSAO + float4 Normal : SV_Target3; // Used for SSAO }; PixelOutput main( @@ -251,6 +253,9 @@ PixelOutput main( PixelOutput o; + o.Position = float4(WorldPos, 1.0); + o.Normal = float4(Normal, 1.0); + o.Color = float4(c2, alpha); o.Emissive = float4(0.0, 0.0, 0.0, 1.0); if(c2.x > 1.0) o.Emissive.x = c2.x; diff --git a/engine/rend/shaders/lit_mesh.frag.json b/engine/rend/shaders/lit_mesh.frag.json index d5c016a..a619351 100644 --- a/engine/rend/shaders/lit_mesh.frag.json +++ b/engine/rend/shaders/lit_mesh.frag.json @@ -6,7 +6,7 @@ } ], "types" : { - "_20" : { + "_22" : { "name" : "type.Uniforms", "members" : [ { @@ -46,7 +46,7 @@ } ] }, - "_23" : { + "_25" : { "name" : "Scene", "members" : [ { @@ -78,12 +78,12 @@ } ] }, - "_22" : { + "_24" : { "name" : "type.StructuredBuffer.Scene", "members" : [ { "name" : "_m0", - "type" : "_23", + "type" : "_25", "array" : [ 0 ], @@ -133,6 +133,16 @@ "type" : "vec4", "name" : "out.var.SV_Target1", "location" : 1 + }, + { + "type" : "vec4", + "name" : "out.var.SV_Target2", + "location" : 2 + }, + { + "type" : "vec4", + "name" : "out.var.SV_Target3", + "location" : 3 } ], "separate_images" : [ @@ -189,7 +199,7 @@ ], "ssbos" : [ { - "type" : "_22", + "type" : "_24", "name" : "scene", "readonly" : true, "block_size" : 0, @@ -199,7 +209,7 @@ ], "ubos" : [ { - "type" : "_20", + "type" : "_22", "name" : "type.Uniforms", "block_size" : 80, "set" : 3, diff --git a/engine/rend/shaders/meshes.vert.hlsl b/engine/rend/shaders/meshes.vert.hlsl index 1aff330..970779d 100644 --- a/engine/rend/shaders/meshes.vert.hlsl +++ b/engine/rend/shaders/meshes.vert.hlsl @@ -81,8 +81,7 @@ Output main(Input input) output.WorldPos = WorldPos.xyz; float4x4 noTranslate = ExtractRotation(scene[input.Instance].Model); - // output.Normal = mul(scene[input.Instance].Model, float4(input.Normal, 1.0)).xyz; - output.Normal = mul(noTranslate, input.Normal); + output.Normal = normalize(mul(noTranslate, float4(input.Normal, 1.0))).xyz; output.DirectionalShadowFragPos = mul(ShadowMapProjection, WorldPos); output.Instance = input.Instance; diff --git a/engine/rend/shaders/postProc.frag.hlsl b/engine/rend/shaders/postProc.frag.hlsl index ddc5c71..5eda966 100644 --- a/engine/rend/shaders/postProc.frag.hlsl +++ b/engine/rend/shaders/postProc.frag.hlsl @@ -4,6 +4,9 @@ SamplerState Sampler0 : register(s0, space2); Texture2D EmissiveTexture : register(t1, space2); SamplerState Sampler1 : register(s1, space2); +Texture2D SsaoTexture : register(t2, space2); +SamplerState Sampler2 : register(s2, space2); + float3 reinhard2(float3 x) { const float L_white = 10.0; @@ -88,16 +91,25 @@ float4 main(float2 UV : TEXCOORD0) : SV_Target0 c = c + blur(uv) * 0.05; float exposure = 1.0; - c *= exposure;//= exposure(c, 1.0, 0.3); + c *= exposure; //= exposure(c, 1.0, 0.3); + // c = blur(uv) * 0.01; + + // c = float3(1.0, 1.0, 1.0) - (step(0.91, length(float3(1.0, 1.0, 1.0) - (e - c)))); // c = c * c ; - // c = e; // c = float3(uv.x, uv.y, 0.0); + // c = SsaoTexture.Sample(Sampler2, uv).x; + + float ssao = SsaoTexture.Sample(Sampler2, uv).x; + c = ssao * c; + c.x *= 1.0 + 0.000001 * EmissiveTexture.Sample(Sampler1, uv).x; c.x *= 1.0 + 0.000001 * ColorTexture.Sample(Sampler0, uv).x; + c.x *= 1.0 + 0.000001 * SsaoTexture.Sample(Sampler2, uv).x; + return float4(c, 1.0); } diff --git a/engine/rend/shaders/postProc.frag.json b/engine/rend/shaders/postProc.frag.json index 537472b..b2e2b5d 100644 --- a/engine/rend/shaders/postProc.frag.json +++ b/engine/rend/shaders/postProc.frag.json @@ -31,6 +31,12 @@ "name" : "EmissiveTexture", "set" : 2, "binding" : 1 + }, + { + "type" : "texture2D", + "name" : "SsaoTexture", + "set" : 2, + "binding" : 2 } ], "separate_samplers" : [ @@ -45,6 +51,12 @@ "name" : "Sampler1", "set" : 2, "binding" : 1 + }, + { + "type" : "sampler", + "name" : "Sampler2", + "set" : 2, + "binding" : 2 } ] } \ No newline at end of file diff --git a/engine/rend/shaders/randomSamplesFloat3.hlsli b/engine/rend/shaders/randomSamplesFloat3.hlsli new file mode 100644 index 0000000..6610d82 --- /dev/null +++ b/engine/rend/shaders/randomSamplesFloat3.hlsli @@ -0,0 +1,65 @@ +static const float3 SamplingKernel[64] = { float3( -0, 0, 0 ), + float3( 0.00039307403, 0.00020744701, 0.00023402007 ), + float3( -0.0013183617, -0.001457856, 0.001546739 ), + float3( 0.00034961867, 0.000084181214, 0.000058608897 ), + float3( -0.0005043492, -0.0038330406, 0.0029292488 ), + float3( -0.0024177164, 0.005713524, 0.0017336456 ), + float3( -0.0007101023, 0.00041329022, 0.00037520085 ), + float3( 0.000015587833, -0.00011572848, 0.00007356792 ), + float3( 0.0033403218, -0.0051653436, 0.0050431825 ), + float3( -0.006396646, 0.012900719, 0.0014770345 ), + float3( 0.007907788, -0.0049759555, 0.001991992 ), + float3( -0.0003332807, -0.0010008786, 0.0010310012 ), + float3( 0.00011193146, 0.0003611636, 0.0010905899 ), + float3( -0.003853666, -0.0046293857, 0.0027080767 ), + float3( -0.005521812, 0.01639079, 0.003326437 ), + float3( -0.002978282, -0.0034022515, 0.0009606515 ), + float3( 0.00056433195, -0.0012372117, 0.0011423329 ), + float3( 0.004264683, 0.0016907869, 0.003383593 ), + float3( 0.028113492, -0.018816402, 0.014087889 ), + float3( -0.030224549, -0.0008946165, 0.008499113 ), + float3( -0.019619143, -0.035032418, 0.014081306 ), + float3( 0.015496987, -0.0109031275, 0.0018075232 ), + float3( 0.01965354, 0.017109247, 0.014284793 ), + float3( -0.028926125, 0.0032248388, 0.06573774 ), + float3( -0.0016983883, 0.00040745927, 0.0037293378 ), + float3( -0.03353675, 0.059106316, 0.0014771292 ), + float3( 0.01729743, 0.0209541, 0.061427496 ), + float3( -0.036244053, -0.010973344, 0.052580632 ), + float3( -0.010873114, 0.07166689, 0.07090236 ), + float3( 0.04043038, -0.07589081, 0.066407025 ), + float3( 0.0064247856, -0.008888489, 0.0057132393 ), + float3( -0.04249787, 0.122786455, 0.030131085 ), + float3( -0.012614764, -0.011735871, 0.016145077 ), + float3( 0.022467306, -0.023659669, 0.01735905 ), + float3( 0.028099436, -0.028635133, 0.0076164785 ), + float3( 0.070179075, -0.15321687, 0.08871499 ), + float3( 0.0073889424, 0.15228039, 0.006640831 ), + float3( 0.07831906, -0.07210498, 0.094614334 ), + float3( 0.032895967, -0.04089934, 0.040609412 ), + float3( -0.14140445, 0.17826557, 0.06704617 ), + float3( 0.108955644, 0.11149475, 0.21018304 ), + float3( 0.027592616, 0.013900582, 0.03667716 ), + float3( 0.05564411, -0.09973075, 0.11314424 ), + float3( -0.03156544, -0.2242651, 0.23739193 ), + float3( -0.047421616, 0.0056678373, 0.17368564 ), + float3( 0.088452466, 0.09633193, 0.08357883 ), + float3( -0.0036428333, 0.010955554, 0.0033084971 ), + float3( -0.19118926, -0.18971312, 0.15644875 ), + float3( 0.034361146, 0.06554529, 0.030825432 ), + float3( 0.3718893, 0.02290428, 0.29824117 ), + float3( -0.014679887, 0.013492301, 0.007404959 ), + float3( -0.0065382663, -0.005886981, 0.0057258857 ), + float3( -0.23331204, -0.35499394, 0.03432809 ), + float3( 0.041135747, -0.023320116, 0.018914448 ), + float3( -0.0945929, 0.025291005, 0.09295652 ), + float3( -0.03173818, 0.22602636, 0.23679778 ), + float3( -0.38012174, 0.24812445, 0.47917068 ), + float3( 0.13565014, 0.13791494, 0.40774575 ), + float3( 0.52387995, -0.38875812, 0.2438776 ), + float3( -0.052082617, -0.11840963, 0.09570911 ), + float3( 0.12260949, -0.4220635, 0.17810947 ), + float3( -0.28019544, -0.52029127, 0.26809025 ), + float3( -0.3271856, 0.23393591, 0.09812375 ), + float3( 0.3826407, 0.08367093, 0.2575612 ), +}; diff --git a/engine/rend/shaders/ssao.frag.hlsl b/engine/rend/shaders/ssao.frag.hlsl new file mode 100644 index 0000000..adea668 --- /dev/null +++ b/engine/rend/shaders/ssao.frag.hlsl @@ -0,0 +1,79 @@ +Texture2D PositionTexture : register(t0, space2); +SamplerState Sampler0 : register(s0, space2); + +Texture2D NormalTexture : register(t1, space2); +SamplerState Sampler1 : register(s1, space2); + +Texture2D NoiseTexture : register(t2, space2); +SamplerState Sampler2 : register(s2, space2); + +#include "randomSamplesFloat3.hlsli" + +cbuffer Uniforms : register(b0, space3) +{ + float4x4 View; + float4x4 ViewProjection; + float4x4 Projection; + float2 extents; + float radius; // = 0.5; + float bias; // = 0.025; + int numSamples; // up to 64 +}; + +float4 main(float2 UV: TEXCOORD0) : SV_Target0 +{ + float2 uv = UV; + uv.y *= -1; + uv.y += 1.0; + + float2 scale = float2(1280 / 4.0, 720 / 4.0); + + float4 c = PositionTexture.Sample(Sampler0, uv); + float3 position = mul(View, PositionTexture.Sample(Sampler0, uv)).xyz; + if (position.z < 0.01) + { + return 1.0; + } + float3 normal = normalize(mul(View, NormalTexture.Sample(Sampler1, uv)).xyz); + float3 randomVec = normalize(NoiseTexture.Sample(Sampler2, uv * scale).xyz); + + float3 tangent = normalize(randomVec - normal * dot(randomVec, normal)); + float3 bitangent = cross(normal, tangent); + float3x3 TBN = float3x3(tangent, bitangent, normal); + + float occlusion = 0.0; + + for(int i = 0; i < numSamples; i += 1) + { + float3 samplePos = mul(TBN, SamplingKernel[i]); // from tangent to view-space + samplePos = position + samplePos * radius; + + // project sample position (to sample texture) (to get position on screen/texture) + float4 offset = float4(samplePos, 1.0); + offset = mul(Projection, offset); // from view to clip-space + offset.xyz /= offset.w; // perspective divide + offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0 + + offset.y *= -1; + // get sample depth + float sampleDepth = mul(View, PositionTexture.Sample(Sampler0, offset.xy)).z; // texture(gPosition, offset.xy).z; // get depth value of kernel sample + // c = float4(sampleDepth, sampleDepth, sampleDepth, 1.0) / 100; + // c = float4(offset) * 2.0 - 0.6 ; + + // range check & accumulate + float rangeCheck = smoothstep(0.0, 1.0, radius / abs(position.z - sampleDepth)); + occlusion += (sampleDepth >= samplePos.z + bias ? 1.0 : 0.0) * rangeCheck; + } + occlusion = 1.0 - (occlusion / numSamples); + + // c += PositionTexture.Sample(Sampler0, uv).x * 0.00001; + // c += NormalTexture.Sample(Sampler1, uv).x * 0.00001; + // c += NoiseTexture.Sample(Sampler2, uv).x * 0.00001; + // float x = length(c); + // c = float4(x, x, x, 1.0); + + + + c = occlusion; + return c + occlusion * 0.00001; +} diff --git a/engine/rend/shaders/ssao.frag.json b/engine/rend/shaders/ssao.frag.json new file mode 100644 index 0000000..f519949 --- /dev/null +++ b/engine/rend/shaders/ssao.frag.json @@ -0,0 +1,119 @@ +{ + "entryPoints" : [ + { + "name" : "main", + "mode" : "frag" + } + ], + "types" : { + "_14" : { + "name" : "type.Uniforms", + "members" : [ + { + "name" : "View", + "type" : "mat4", + "offset" : 0, + "matrix_stride" : 16, + "row_major" : true + }, + { + "name" : "ViewProjection", + "type" : "mat4", + "offset" : 64, + "matrix_stride" : 16, + "row_major" : true + }, + { + "name" : "Projection", + "type" : "mat4", + "offset" : 128, + "matrix_stride" : 16, + "row_major" : true + }, + { + "name" : "extents", + "type" : "vec2", + "offset" : 192 + }, + { + "name" : "radius", + "type" : "float", + "offset" : 200 + }, + { + "name" : "bias", + "type" : "float", + "offset" : 204 + }, + { + "name" : "numSamples", + "type" : "int", + "offset" : 208 + } + ] + } + }, + "inputs" : [ + { + "type" : "vec2", + "name" : "in.var.TEXCOORD0", + "location" : 0 + } + ], + "outputs" : [ + { + "type" : "vec4", + "name" : "out.var.SV_Target0", + "location" : 0 + } + ], + "separate_images" : [ + { + "type" : "texture2D", + "name" : "PositionTexture", + "set" : 2, + "binding" : 0 + }, + { + "type" : "texture2D", + "name" : "NormalTexture", + "set" : 2, + "binding" : 1 + }, + { + "type" : "texture2D", + "name" : "NoiseTexture", + "set" : 2, + "binding" : 2 + } + ], + "separate_samplers" : [ + { + "type" : "sampler", + "name" : "Sampler0", + "set" : 2, + "binding" : 0 + }, + { + "type" : "sampler", + "name" : "Sampler1", + "set" : 2, + "binding" : 1 + }, + { + "type" : "sampler", + "name" : "Sampler2", + "set" : 2, + "binding" : 2 + } + ], + "ubos" : [ + { + "type" : "_14", + "name" : "type.Uniforms", + "block_size" : 212, + "set" : 3, + "binding" : 0 + } + ] +} \ No newline at end of file diff --git a/engine/rend/src/sgpu/DebugDrawSystem.zig b/engine/rend/src/sgpu/DebugDrawSystem.zig index 8a82ba7..07288b9 100644 --- a/engine/rend/src/sgpu/DebugDrawSystem.zig +++ b/engine/rend/src/sgpu/DebugDrawSystem.zig @@ -194,7 +194,7 @@ pub fn createPipeline(self: *@This()) !*gpu.GPUGraphicsPipeline { pci.target_info.has_depth_stencil_target = true; pci.target_info.depth_stencil_format = rend.context().depthFormat; - pci.target_info.num_color_targets = 2; + pci.target_info.num_color_targets = 4; pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{ .{ .format = rend.context().hdrTextureFormat, @@ -204,6 +204,14 @@ pub fn createPipeline(self: *@This()) !*gpu.GPUGraphicsPipeline { .format = rend.context().hdrTextureFormat, .blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState), }, + .{ + .format = rend.context().positionTargetFormat, + .blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState), + }, + .{ + .format = rend.context().normalTargetFormat, + .blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState), + }, }; pci.rasterizer_state.fill_mode = .fillmodeLine; diff --git a/engine/rend/src/sgpu/renderer.zig b/engine/rend/src/sgpu/renderer.zig index c6843fe..c1f29c7 100644 --- a/engine/rend/src/sgpu/renderer.zig +++ b/engine/rend/src/sgpu/renderer.zig @@ -81,6 +81,10 @@ pub const Renderer = struct { lightPower: f32 = 4.0, + ssaoSystem: *SsaoSystem = undefined, + positionTargetFormat: gpu.GPUTextureFormat = .textureformatR16g16b16a16Float, + normalTargetFormat: gpu.GPUTextureFormat = .textureformatB8g8r8a8Unorm, + pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); pub const MaxObjectCount = 50000; @@ -99,7 +103,7 @@ pub const Renderer = struct { return self; } - pub fn createHDRTexture(self: *@This()) !void { + pub fn createRenderTargets(self: *@This()) !void { var gci = std.mem.zeroes(gpu.GPUTextureCreateInfo); gci.type = .texturetype2d; @@ -116,6 +120,12 @@ pub const Renderer = struct { self.state.targetTexture = self.device.createGPUTexture(&gci); self.state.emissiveTarget = self.device.createGPUTexture(&gci); + + gci.format = self.positionTargetFormat; + self.state.positionTarget = self.device.createGPUTexture(&gci); + + gci.format = self.normalTargetFormat; + self.state.normalTarget = self.device.createGPUTexture(&gci); } pub fn startRenderer(self: *@This()) !void { @@ -139,7 +149,7 @@ pub const Renderer = struct { try self.createMeshPipeline(); try self.createBuffers(); try self.createDepthTexture(); - try self.createHDRTexture(); + try self.createRenderTargets(); try self.createPostProcessingPipeline(); self.meshPool = try self.createRendererObject(MeshPool); @@ -188,6 +198,23 @@ pub const Renderer = struct { .{ .path = "embedded:screenPlane.obj" }, ), ); + + self.ssaoSystem = try self.createRendererEngineObject(SsaoSystem); + } + + pub fn addVertexAttributes(self: *@This(), pci: *gpu.GPUGraphicsPipelineCreateInfo) !std.ArrayList(gpu.GPUVertexAttribute) { + const attributes = try self.generateVertexAttributeList(); + + pci.vertex_input_state = .{ + .num_vertex_buffers = 1, + .vertex_buffer_descriptions = &[_]gpu.GPUVertexBufferDescription{ + .{ .slot = 0, .pitch = @sizeOf(rend.MeshVertex), .input_rate = .vertexinputrateVertex, .instance_step_rate = 0 }, + }, + .num_vertex_attributes = @intCast(attributes.items.len), + .vertex_attributes = @ptrCast(attributes.items.ptr), + }; + + return attributes; } pub fn createPostProcessingPipeline(self: *@This()) !void { @@ -434,8 +461,8 @@ pub const Renderer = struct { core.graphics_log("swapchain format: {any}", .{self.swapchainTargetFormat}); pci.target_info.has_depth_stencil_target = true; pci.target_info.depth_stencil_format = self.depthFormat; - pci.target_info.num_color_targets = 2; - pci.target_info.color_target_descriptions = &[2]gpu.GPUColorTargetDescription{ + pci.target_info.num_color_targets = 4; + pci.target_info.color_target_descriptions = &[4]gpu.GPUColorTargetDescription{ .{ .format = self.hdrTextureFormat, .blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState), @@ -444,6 +471,14 @@ pub const Renderer = struct { .format = self.hdrTextureFormat, .blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState), }, + .{ + .format = self.positionTargetFormat, + .blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState), + }, + .{ + .format = self.normalTargetFormat, + .blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState), + }, }; pci.rasterizer_state.fill_mode = .fillmodeFill; @@ -713,7 +748,7 @@ pub const Renderer = struct { pub fn drawMeshes(self: *@This(), cmd: *gpu.GPUCommandBuffer) void { // can cache this - const targetInfo: [2]gpu.GPUColorTargetInfo = .{ + const targetInfo: [4]gpu.GPUColorTargetInfo = .{ std.mem.zeroInit(gpu.GPUColorTargetInfo, .{ .texture = self.state.targetTexture, .load_op = .loadopLoad, @@ -724,6 +759,16 @@ pub const Renderer = struct { .load_op = .loadopClear, .store_op = .storeopStore, }), + std.mem.zeroInit(gpu.GPUColorTargetInfo, .{ + .texture = self.state.positionTarget, + .load_op = .loadopClear, + .store_op = .storeopStore, + }), + std.mem.zeroInit(gpu.GPUColorTargetInfo, .{ + .texture = self.state.normalTarget, + .load_op = .loadopClear, + .store_op = .storeopStore, + }), }; const depthTarget = std.mem.zeroInit(gpu.GPUDepthStencilTargetInfo, .{ @@ -736,7 +781,7 @@ pub const Renderer = struct { .clear_stencil = 0, }); - self.state.pass = cmd.beginGPURenderPass(&targetInfo, 2, &depthTarget); + self.state.pass = cmd.beginGPURenderPass(&targetInfo, 4, &depthTarget); const renderpass = self.state.pass.?; renderpass.setGPUScissor(&self.scissor); @@ -783,6 +828,7 @@ pub const Renderer = struct { interface.func(interface.ptr, cmd, renderpass); } renderpass.endGPURenderPass(); + self.state.pass = null; } pub fn drawPostProcess(self: *@This(), cmd: *gpu.GPUCommandBuffer) void { @@ -795,10 +841,11 @@ pub const Renderer = struct { const postProcPass = cmd.beginGPURenderPass(&postProcTargetInfo, 1, null); postProcPass.bindGPUGraphicsPipeline(self.postProcessingPipeline); - postProcPass.bindGPUFragmentSamplers(0, &[2]gpu.GPUTextureSamplerBinding{ + postProcPass.bindGPUFragmentSamplers(0, &[3]gpu.GPUTextureSamplerBinding{ .{ .sampler = self.blockySampler, .texture = self.state.targetTexture }, .{ .sampler = self.linearSampler, .texture = self.state.emissiveTarget }, - }, 2); + .{ .sampler = self.linearSampler, .texture = self.ssaoSystem.ssaoTexture }, + }, 3); postProcPass.bindGPUVertexBuffers(0, &.{ .buffer = self.meshPool.vertexBuffer, .offset = 0 }, 1); postProcPass.bindGPUIndexBuffer(&.{ .buffer = self.meshPool.indexBuffer, .offset = 0 }, .indexelementsize32bit); @@ -835,6 +882,7 @@ pub const Renderer = struct { self.drawDirectionalShadowMap(cmd); self.skyboxSystem.render(cmd); self.drawMeshes(cmd); + self.ssaoSystem.render(cmd); self.drawPostProcess(cmd); for (self.postRenders.items) |interface| { @@ -904,6 +952,7 @@ pub fn reloadShaders() !void { }; try gRenderer.createMeshPipeline(); try gRenderer.createPostProcessingPipeline(); + try gRenderer.ssaoSystem.createPipeline(); } // ====== renderer API ======= @@ -953,6 +1002,8 @@ pub const RendererState = struct { swapchainTargetTexture: ?*gpu.GPUTexture = null, targetTexture: *gpu.GPUTexture = undefined, emissiveTarget: *gpu.GPUTexture = undefined, + positionTarget: *gpu.GPUTexture = undefined, + normalTarget: *gpu.GPUTexture = undefined, }; pub const CustomMeshRenderFunc = *const fn (?*anyopaque) void; @@ -961,3 +1012,5 @@ pub const GPUTextureType = gpu.GPUTexture; const plane_obj align(8) = @embedFile("embedded/plane.obj").*; const screenPlane_obj align(8) = @embedFile("embedded/screenPlane.obj").*; const tracy = core.tracy; + +pub const SsaoSystem = @import("ssao.zig"); diff --git a/engine/rend/src/sgpu/ssao.zig b/engine/rend/src/sgpu/ssao.zig new file mode 100644 index 0000000..0930584 --- /dev/null +++ b/engine/rend/src/sgpu/ssao.zig @@ -0,0 +1,222 @@ +pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + +allocator: std.mem.Allocator, + +ssaoOutputFormat: gpu.GPUTextureFormat = .textureformatR16g16b16a16Float, +noiseTextureFormat: gpu.GPUTextureFormat = .textureformatR16g16b16a16Float, + +// outputs an SSAO texture at half the resolution +ssaoPipeline: *gpu.GPUGraphicsPipeline = undefined, +ssaoTexture: *gpu.GPUTexture = undefined, + +noiseTexture: *gpu.GPUTexture = undefined, +noiseSampler: *gpu.GPUSampler = undefined, + +radius: f32 = 0.5, +bias: f32 = 0.05, +numSamples: i32 = 64, +enable: bool = true, + +// float radius; // = 0.5; +// float bias; // = 0.025; +// int numSamples; // up to 64 + +pub fn create(allocator: std.mem.Allocator) !*@This() { + const self = try allocator.create(@This()); + + self.* = .{ + .allocator = allocator, + }; + + return self; +} + +pub fn setup(self: *@This(), device: *gpu.GPUDevice) !void { + _ = device; + core.engine_log("creating ssao pipeline", .{}); + try self.createBuffersAndTextures(); + try self.createPipeline(); + try self.createNoiseTexture(); +} + +pub fn createNoiseTexture(self: *@This()) !void { + const ctx = rend.context(); + + self.noiseSampler = ctx.device.createGPUSampler(&std.mem.zeroInit(gpu.GPUSamplerCreateInfo, .{ + .min_filter = .filterLinear, + .mag_filter = .filterLinear, + .mipmap_mode = .samplermipmapmodeNearest, + .address_mode_u = .sampleraddressmodeRepeat, + .address_mode_v = .sampleraddressmodeRepeat, + .address_mode_w = .sampleraddressmodeRepeat, + })); + + var prng = std.Random.DefaultPrng.init(blk: { + var seed: u64 = undefined; + try std.posix.getrandom(std.mem.asBytes(&seed)); + break :blk seed; + }); + const rand = prng.random(); + + const textureSize = 4; + var tci: gpu.GPUTextureCreateInfo = std.mem.zeroInit(gpu.GPUTextureCreateInfo, .{ + .type = .texturetype2d, + .format = self.noiseTextureFormat, + .usage = .{ .textureusageSampler = true }, + .width = textureSize, + .height = textureSize, + .layer_count_or_depth = 1, + .num_levels = 1, + }); + self.noiseTexture = ctx.device.createGPUTexture(&tci); + + const transferBuffer = ctx.device.createGPUTransferBuffer(&.{ + .usage = .transferbufferusageUpload, + .size = textureSize * textureSize * @sizeOf(f32) * 4, + .props = 0, + }); + defer ctx.device.releaseGPUTransferBuffer(transferBuffer); + + const gtti: gpu.GPUTextureTransferInfo = .{ + .transfer_buffer = transferBuffer, + .offset = 0, + .pixels_per_row = textureSize, + .rows_per_layer = textureSize, + }; + + const data: [*][4]f16 = @ptrCast(@alignCast(ctx.device.mapGPUTransferBuffer(transferBuffer, false))); + for (0..16) |i| { + data[i][0] = @as(f16, @floatCast(rand.float(f32))) * 2.0 - 1.0; + data[i][1] = @as(f16, @floatCast(rand.float(f32))) * 2.0 - 1.0; + data[i][2] = 0.0; + data[i][3] = 0.0; + } + + const cmd = ctx.device.acquireGPUCommandBuffer(); + + const copyPass = cmd.beginGPUCopyPass(); + + const textureRegion = std.mem.zeroInit(gpu.GPUTextureRegion, .{ + .texture = self.noiseTexture, + .w = textureSize, + .h = textureSize, + .d = 1, + }); + + copyPass.uploadToGPUTexture(>ti, &textureRegion, false); + + copyPass.endGPUCopyPass(); + + _ = cmd.submitGPUCommandBuffer(); +} + +pub fn createBuffersAndTextures(self: *@This()) !void { + var gci = std.mem.zeroes(gpu.GPUTextureCreateInfo); + + gci.type = .texturetype2d; + gci.format = self.ssaoOutputFormat; + gci.width = @divFloor(@as(u32, @intCast(platform.getInstance().windowExtent.x)), 2); + gci.height = @divFloor(@as(u32, @intCast(platform.getInstance().windowExtent.y)), 2); + gci.layer_count_or_depth = 1; + gci.num_levels = 1; + gci.sample_count = .samplecount1; + gci.usage = .{ + .textureusageSampler = true, + .textureusageColorTarget = true, + }; + + self.ssaoTexture = rend.context().device.createGPUTexture(&gci); +} + +pub fn uploadUniforms(self: *@This(), cmd: *gpu.GPUCommandBuffer) void { + const ctx = rend.context(); + + var data = std.mem.zeroes([@sizeOf(ssao_frag.Uniforms) / 8 + 1]usize); + const ptr: *ssao_frag.Uniforms = @ptrCast(@alignCast(&data)); + ptr.numSamples = self.numSamples; + ptr.radius = self.radius; + ptr.bias = self.bias; + ptr.extents.x = @floatFromInt(platform.getInstance().windowExtent.x); + ptr.extents.y = @floatFromInt(platform.getInstance().windowExtent.y); + + if (ctx.activeCamera) |camera| { + ptr.ViewProjection = @bitCast(camera.final); + ptr.Projection = @bitCast(camera.projection); + ptr.View = @bitCast(camera.transform); + } + + cmd.pushGPUFragmentUniformData(0, &data, @sizeOf(ssao_frag.Uniforms)); +} + +pub fn render(self: *@This(), cmd: *gpu.GPUCommandBuffer) void { + const targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{ + .texture = self.ssaoTexture, + .clear_color = .{ .r = 1.0, .g = 1.0, .b = 1.0, .a = 1.0 }, + .load_op = .loadopClear, + .store_op = .storeopStore, + }); + + const ctx = rend.context(); + const pass = cmd.beginGPURenderPass(&targetInfo, 1, null); + + if (self.enable) { + pass.bindGPUGraphicsPipeline(self.ssaoPipeline); + pass.bindGPUVertexBuffers(0, &.{ .buffer = ctx.meshPool.vertexBuffer, .offset = 0 }, 1); + pass.bindGPUIndexBuffer(&.{ .buffer = ctx.meshPool.indexBuffer, .offset = 0 }, .indexelementsize32bit); + + pass.bindGPUFragmentSamplers(0, &[3]gpu.GPUTextureSamplerBinding{ + .{ .sampler = ctx.blockySampler, .texture = ctx.state.positionTarget }, + .{ .sampler = ctx.linearSampler, .texture = ctx.state.normalTarget }, + .{ .sampler = self.noiseSampler, .texture = self.noiseTexture }, + }, 3); + + self.uploadUniforms(cmd); + + if (rend.context().screenPlane) |mesh| { + pass.drawGPUIndexedPrimitives(mesh.index.size, 1, mesh.index.start, @intCast(mesh.vertex.start), 0); + } + } + + pass.endGPURenderPass(); +} + +pub fn createPipeline(self: *@This()) !void { + const ctx = rend.context(); + const vertex = try ctx.loadShader("postProc.vert", postProc_vert.LoadArgs); + const fragment = try ctx.loadShader("ssao.frag", ssao_frag.LoadArgs); + + var pci = std.mem.zeroes(gpu.GPUGraphicsPipelineCreateInfo); + pci.vertex_shader = vertex; + pci.fragment_shader = fragment; + + var vertexList = try ctx.addVertexAttributes(&pci); + defer vertexList.deinit(); + + pci.target_info.num_color_targets = 1; + pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{ + .{ + .format = self.ssaoOutputFormat, + .blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState), + }, + }; + + pci.rasterizer_state.cull_mode = .cullmodeNone; + pci.rasterizer_state.fill_mode = .fillmodeFill; + + self.ssaoPipeline = ctx.device.createGPUGraphicsPipeline(&pci); +} + +pub fn destroy(self: *@This()) void { + self.allocator.destroy(self); +} + +const core = @import("core"); +const rend = @import("../rend.zig"); +const std = @import("std"); +const sdl3 = @import("sdl3"); +const platform = @import("platform"); + +const postProc_vert = @import("postProc.vert"); +const ssao_frag = @import("ssao.frag"); + +pub const gpu = sdl3.gpu; diff --git a/engine/ui/src/sgpu/papyrusSgpu.zig b/engine/ui/src/sgpu/papyrusSgpu.zig index 837f52f..e9f18f2 100644 --- a/engine/ui/src/sgpu/papyrusSgpu.zig +++ b/engine/ui/src/sgpu/papyrusSgpu.zig @@ -98,8 +98,6 @@ pub fn postRender(p: *anyopaque, cmd: *gpu.GPUCommandBuffer) void { } pub fn drawToTarget(self: *@This(), ctx: *papyrus.Context, targetTexture: *gpu.GPUTexture) void { - _ = targetTexture; - ctx.makeDrawList(&self.drawList, &self.stringArena) catch return; if (self.first) { @@ -109,6 +107,26 @@ pub fn drawToTarget(self: *@This(), ctx: *papyrus.Context, targetTexture: *gpu.G core.engine_log("{any}", .{item}); } } + + const cmd = rend.context().state.cmd.?; + + const targetInfo: gpu.GPUColorTargetInfo = std.mem.zeroInit(gpu.GPUColorTargetInfo, .{ + .texture = targetTexture, + .load_op = .loadopLoad, + .store_op = .storeopStore, + }); + + const pass = cmd.beginGPURenderPass(&targetInfo, 1, null); + pass.bindGPUVertexBuffers(1, &.{ .buffer = rend.context().meshPool.vertexBuffer, .offset = 0 }, 1); + pass.bindGPUIndexBuffer(&.{ .buffer = rend.context().meshPool.indexBuffer, .offset = 0 }, .indexelementsize32bit); + for (self.drawList.items) |item| { + switch (item.primitive) { + .Rect => {}, + .Text => {}, + } + } + + pass.endGPURenderPass(); } pub const rect_frag = @import("rect.frag"); diff --git a/projects/content/_shaders/dxil/lit_mesh.frag.dxil b/projects/content/_shaders/dxil/lit_mesh.frag.dxil index 1918753411cf19137506bea3a52fa35715dc80cb..ab723e73a0553ea8afc6ef3b584096ce37f6527b 100644 GIT binary patch delta 2935 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 delta 2646 zcmY*b3se(V8lIVi$uJ3IcqqZ3NqEU4qytq@7SlWwS*l&Ewg*_;4oN{;G2+`w+Jpo& zU?{P1T@<$lA5>l7fcSt@b&~*+qR2zL%h`i2Vh&|JND@wW18p5>7;t_JS_=b$ zD1Qjj`X5Oh3fKf92pt8Delo0!VF8?BT?O;4wJ_nc8U&YFTj3z99rj})kPp%}2=~Kr zIxv@R-e(^$yp8sG?R}8-2_r7*JPtMm?u!6!b@p%9LEs<+7+Zi}p|n2~aUiI^Z6&jg z0pGWN&x(muynZBrMwd)ITB0v)KU4|<1N>f>xkAAz2>Of%L6L1DY#T!-&tUBtCTlxW zp`h{<%IJp-`tz$cmiX+Y82g0b(IMl>2R}?skqgrn6&7#L-@Pk{Ii@}`p1d{%`0V=C zC-@IWm}MAa(XLOnd{q4Lvhkt2H^(PT1Alzg?wQj8w5-R&?Nnf=_ zV`Orl3AxW@+<#Nt|LFAG9Tx608@E$Bt$Zi%gW=)Hf8-6hdPgQ2nDPZlX(8Vxb#z=# zxfTl#mUH^MCFZ{7b(+kq`=ZWW$Cd1ecoiDlBa#!G*wyn#jHa#Ow**KvbaiOZeCiPX~*|~wO~j0jP2pj$OKqD zHBiCnFPLn)TMc&8WDanlwvQJ0BGyrVBDE^`nepy~uV(l4vAzH8`RNL+M;H);0=%-A zZ|cJYey={S8EtXgMn;5N@EV@e0|vshv*tvadL%HNq_b{LnImm41Fyk4qYOXSl8^ap zgrc$S5XxsF3zCDk=+SRv=!L9`>b~Z_sOrW$)tXFV6JVn?-dgu=>8`p!Vm)}9N$2on zue*VnzBnoEPb)8zmy$XfQZ6N3jg`NDkkh}Wxp=DSJxyb=CX+i=fK_ipBT!$+Kn>J8kFicu_*PGNb6m-R61>6g4PQ`PV|_#7+q|pe_8%bd`cZGV z)p?E8K;hfHtK;>spwSs;cbMdeUdY?sOrW~YTkyXSEYEf~47{J=_!dK$nHLFR2H3#9 zV8NRRT;)MHC^_$pZ8yZ2JqWySTk!MK_!lzIj?^>~e-;s&6`}J0WrOS{8{SIdg6pV^W7|SfiIfst4 zjmd*e^8Jj|^Yb3k=FShsReIxZvWz*1s@;*#B5MnHCaP-`mJyt@2gr)I31d~Rae2|9 zy+p-w-g-h5lzthw2qWe9V1zudHrN*~O2>6@}sKOU398n-ZEt6yEL8t?jnri&Cgn&OQ zlqPd#TJynlSZfx#)e0a2gI?6~1tLJ$$V<*zOm{=5z2|qs&X)Ty{MH6P6>6jPMr{M% zAm@E48N`ho1~xtnjQ`Ew`X&A4@sqfrsBobqUOZ=%v(C6j)L&9tg4H9EflZLw)otz>$q z=RIEf>*;@wIsD7?ev^YP99eDhg|95!S(3gj^f{qbVWG5*c}La_#ohjavx$goGnc8~-Vic4p-iB&XNAhQ z{6|B*m>N}^wR);ul;H=iUC9Z1_$$a!qHI|Ns>3uXe^jmowSp4RwL)Ijr~HGfXI%c4 zTm8Hx1iX!-^;f#I|G;+?4P@J$}+yAWOY5? zneu>|NcR-ks^fQ9HPe_ma{jwutNl(pjny<_N%LQ+`LOG7*c;*YjP;(9tBQU;7?FlV jbkBchVhWQ4tDF(>NpFN_!s!Yg2(rf$mpJ)z{{sI9xDuXk diff --git a/projects/content/_shaders/dxil/meshes.vert.dxil b/projects/content/_shaders/dxil/meshes.vert.dxil index 5b76d0bed35923c4fd96ff856e24483f41527157..817386d8b35099b333045db26a4db5fbfcd02753 100644 GIT binary patch delta 4111 zcmds3Yg7|w8lFie7a$1(0UQY61jK>}hFbs&o+MC=7FrZh>gAAd6D&axv{hM?$s~vh zB^am(tqo!+YPTJfDyX#yAVrIcm$uwi5iQa?($?bEG2xgMwQX-q!h2Lb>vUF|Mltl>r1BvNR+N^byTjd>6Xwix$Af$F22ZV{(T#GyxLBjuP$ zJNs!Uxn1~#{}?`aUA3mw*_b{e_9;^$E$y4zpW5waUv|WD(%3F*^d|NJ(@7V42#20s z3`s*4A4SV6+Z)Qhc#qg?cv@>%n=w^AoWPL6&?@^Xf~~!XX}XRD9MxUEOYG|}6Z$O3 zYg)8lTb?X2L{&&QDjd{?7CdfnIa*1$K!**WFvK|DVMn`{ zkMMMLXobats1pPh2R5Ma^)g+un-)Q618_KB7bd5ROLi7!r>7R=|L6>$_@$)IF2cL@j%|MnyWQmt~)sFxv6eA?KS5cP$Pod$)rpH zq#7X9xuyNAohYkFG>y5j)CAUozc@fo9w6YY0ILXP?G!x#omjgFr8`Aw=1nQ;a3Q5% zs7m{Y(ns|%$oS}f`qDboC0is#39fdBy}<29?kLKeL>-wa{bPWu7#b*J?8cXs(^DsL ziz5*=joZXqr&_zK;pL{6cNY&6ge=f(@$AI{IL&7JB8|O(vkK9#mg`ds_1rlB z3p9~bj)#$rZ6z9`=#d)6O1Ip))=%{}t|r0k%9rYgJ^wKRVFU7G9W$1Y%dTzKTU4lYj}bXyxVLJNMN4K6%ycKCGE;WJaJ zGV}E7#VdRRi<=spq14{VjXzv@Fn;sSNHY}A4~?03UL-yr+7TdKwU=`}n-^5^Vd6*M zR(@EaTB)fKb`@6#HtarW6a+RjI49PUYbT~guV_a`?o4z}kQC$1>}(TrJH>hP%1;M- z7d4aiE6q@TGD-G+U*#*oj^71ctt=>5i8^c|Q9XCQ8<`;0o1xE6FSB0;s+W+5=s9Oq_X9SUD#DnF~%#@`|X@wIK=wx?eT=jNI!t_e=-h~C;(g`{|5Mw zbTRc0L|y-Fl>oeIV;G=El6Ux}6!@(xWOyW_j5P}CI#?@Wq$2v1H2v}}1XQ!N=ra)T zW!eE+h1mkSFjf7`ugj%04T=;N!5AiJ2gMl%0A(}Fz3VWK3l?PKELbsVaX$un8f@-_ z`Q%O9Ek&}d?rEt+)~xXj`+N;UMHzoHfL7oK z_FD-?A!YMBY_olBzipIJOxaQ!Z8ny}c9@BIQ6kEZ39Il`nzun}U{S$r5SXn2o*`J9 z;Ylj!n%|isG7%3lll0(e%mY$WoUY8>WG`j{e`H+c>azIm5(CW>dY|%bXYR21_H_mH zNj3Hq_ZAI{;-P4a)vhkI$wuP`t}^whJuoZRMe9U|0I8_=snXN5ioIB4%Ipv5-P{d; z5}0$!AYx5CN5qeLno?#Fi=HD6CbM!~Z5)XiUZ&JpMBsBoO(ARIIbzM2muVe^2+L3t zR73|~Cg@11H&S}190SSzNJRH|7((s2W_ehNAY^mEc>WZe z1~aEZgq#Oq8M8D={ePy3QaV1T>0yqc^Bs^Uvn`W0^Z#Y8h!ZWEEy>_38Yqm1wPMk| zpVJaZNvg7jC*5+U45Xoopl6BVry>%-GDNXkSG9#@b7~Z z+WF>;a3PSu*D1o4a00(v**yx7O$a{Mvd@rvKz&08AW5+HhE9qkp=C}uo$OlslynkHL)c6j7FVKS?V`P)_Ebs%lwSWVk+i)Uw8kJgzT!-ci<;#TRTTC3qh%dLUE0 z9c|mjq3U1KxOtwooqi3E@GP|D6j$|C@-88f=tb_vnPYZ%*M)@bJX@u|2L(>iHkH=p z`Qi6q4$|*8G7u{+?SkY1r$8Qztt4r_7jZ_HZd9KkQSRd2#CDL#9m5>)00Q?(2 CZoR1h delta 4036 zcmdT`YgiLk8lEJ>ObA0V$i+Yc4yY7`g>VZOshfm|h|tC=mLe8HMZhLp3|hR@TnH&D zv|w;W&~5T1PHx7u|tXGntW^YqvL>-?JezW2P} z?VNYclgP?QPidMYe(cD^H!&|PyODe6=uIJ(bDRc2P-TrL&mjVXAlb>7LdN0>CIn?c zG{}z*LDIBU$>0^j0jvnvCGqC#z5wZI9AGrimKpP5f@U)Ag9Ft%%p$;g1l4N|S}rqo zOXoAkUCax&g~!wOUI;1Rx%3FIbz|Wf|IxpwpL$0W9t5*mB#H0}S?WG5*Pv~S(V4hz zYjA18XiCq`mq+3g|C5v$82Yqd*{ma&x&VijGFbe*$Sl9?wx)Zka73EdgS#B)ShGSb z4Ir5O1j69A2~N;bkv^>8vh{U@UhCCf#|u;i zHW2urK`-;rak=ynJi=8UCSnLnb`<4grWWLHF5IeAxx$m*X>d*i9uF&+$DH+yWHYSA z291>{&qL$Sly=C??QiNtiLP*VJ%L|=eFKf>(53vVh{MyiWJX!ljaZ?bDzhYCnd1s~ z8yUN>HPf;pm*Zb+-=xg7U9(fGF)mNYp^CQ|Tyh4G?foFy0`@~#=mOBvA>jF^ft zIlCg-ROU>!%RR3{>`60wGOMo4mpz>oZvsmw@TlSDP6`}XQRd5OiymSK*RIc8RiG-7 z7rc?PO6sbYVE)YWTm{}C?`cv$5HFb0@-5^zn$CYlB2DZcvp6DokK`aol9_e#W{H zJd5XX*ZCKMy^iD{e>P8!bNrcbZ_dR#PU<_#;Huzz1InIm)<+PkBG48=9X-%OTdEL9 zkGa4Yp~*!}(Y{#2>ZiAsX*TppXgC5-M+%bZRZIdxV$eP+H# z4|%K$d8S)mUNz7*u(;~PrK*A?e4THP>SUm?Vf8Lm!#q5teV9(DmbAiND`#_^{5)ZEDLnns@m1;)J#z{_|JUYyu-bJ=?#Qdr>P zJA^sO9R`b@4&LAlmi+6ya)UX7TC$&kWj~S`0oXB_0)G*0CWM?waM-VjA}PS-DJh(k z0xaj1JaJ@(`q!p@B~LfY;_8yZ#N~U6uWg>eKxWIYLN2%Ff2xFF2H|W!(~07>iEg%! zk;+YvHdnHqUN{r@x=c>or<5&%ZB@D|aPEJtbbMg9E1jNU9Awo0@ucoOV;4I;_WzVS z2%2xKLgpKbIDG$DC;dfFD6DU%7v}SHM!RzP?(rJV0?5L^IiffSXyf>~1q)clk2%q5 zyXMsq_y8go1dI%%;LO|}%_0lzi*;*&dX)+nS-Nq{5NT{I7lXECM}c^Dm5EK zqoO!7oQz+BFd=*u7DI_00Z!B{^$# z$Jw6muRhE>n&ES0Lp|^Nv0BIt`U9(hoPeM&z&*wl76(yx8E_qdq;B70B44C-W7omt z3+{O$t(#2i4%9!LbX!NdCrr4lpI9RVcc6ucBc#hRouk2s!i=cN3Nc+naPx}rx0ORk zxAluCl_B}#NOn;bcM-(YX&cea8l+Hwj9A^=T}4Pfgl1LS+$5Supv5v|)aHJ>8Ueqd z>~@=b0^K4)RWfAE=2o{OB_cF$h;pj|JB_7~q1$B0b(_C&2-%*6=FOxwU8tZ@$(8Jc zkYpTbcBIJ|=t6`E@*nz%fk*%n&+l-VZe}B(D{p;Z(73)(wN>DTGF3ufoLKe3$7NR({l*PB;T~widZ^_ zI3Ppw-0d7m+1{p9DQkhitu?J6!8jFYy=^#PuSBM(D;v8nKED^1Fk-_i)z z7&-H~YVx4#f6bNgwk98XNdt$owI{VP{eAQVKuf()x_xTB8I;4El}QqXZ9& z_9GnnjU=(XXElcOtR{QUQoY_3|JxqqP=33E1q7KbQ@yUW(L)&O^}BVR>fLZxy5+ZZ z+Pb=!S3>h>`Q5HwRZgvVt)urhO)X0~NBq^ck4xhtd^R#|C8_UJ4W||O+G_eTD)EM? z+Hyi80VY3 zQeQ!^H`tA{hk5?aPGmD1G+IrGRK^bvyskvsqx>CJh{i#bS^10cf!DO*dR}J!Y0^lRSel~%eK~-Z3VRI=0|H=Zl=X}6DouC1~s@dm%S#FIP diff --git a/projects/content/_shaders/dxil/postProc.frag.dxil b/projects/content/_shaders/dxil/postProc.frag.dxil index 04ff0116a02ba83483058df136fa41b58d88e77e..750c0a380eaf1e4fad84bc21e8c65471e13edbff 100644 GIT binary patch delta 1801 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 IA2a;^1wKAS1^@s6 diff --git a/projects/content/_shaders/dxil/ssao.frag.dxil b/projects/content/_shaders/dxil/ssao.frag.dxil new file mode 100644 index 0000000000000000000000000000000000000000..12b73f91a533b61cf04ecb804a3d2f527e427b4a GIT binary patch literal 8364 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 literal 0 HcmV?d00001 diff --git a/projects/content/_shaders/msl/lit_mesh.frag.msl b/projects/content/_shaders/msl/lit_mesh.frag.msl index 59e33df..5a036d0 100644 --- a/projects/content/_shaders/msl/lit_mesh.frag.msl +++ b/projects/content/_shaders/msl/lit_mesh.frag.msl @@ -28,13 +28,15 @@ struct type_StructuredBuffer_Scene Scene _m0[1]; }; -constant float4 _88 = {}; -constant float3 _90 = {}; +constant float4 _90 = {}; +constant float3 _92 = {}; struct main0_out { float4 out_var_SV_Target0 [[color(0)]]; float4 out_var_SV_Target1 [[color(1)]]; + float4 out_var_SV_Target2 [[color(2)]]; + float4 out_var_SV_Target3 [[color(3)]]; }; struct main0_in @@ -49,145 +51,147 @@ struct main0_in fragment main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_Scene& scene [[buffer(1)]], texture2d Texture0 [[texture(0)]], texture2d Texture1 [[texture(1)]], texture2d Texture2 [[texture(2)]], texture2d DirectionalShadowDepthMap [[texture(3)]], sampler Sampler0 [[sampler(0)]], sampler Sampler1 [[sampler(1)]], sampler Sampler2 [[sampler(2)]], sampler DirectionalShadowSampler [[sampler(3)]]) { main0_out out = {}; - int _99 = int(scene._m0[in.in_var_TEXCOORD4].textureMode); - int _100 = _99 & 240; - float4 _134; - if (_100 == 16) + int _101 = int(scene._m0[in.in_var_TEXCOORD4].textureMode); + int _102 = _101 & 240; + float4 _136; + if (_102 == 16) { - float3 _121 = float3(Texture0.sample(Sampler0, in.in_var_TEXCOORD0).x, Texture1.sample(Sampler1, in.in_var_TEXCOORD0).x, Texture2.sample(Sampler2, in.in_var_TEXCOORD0).x) + float3(-0.0625, -0.5, -0.5); - _134 = float4(dot(_121, float3(1.164000034332275390625, 0.0, 1.7929999828338623046875)), dot(_121, float3(1.164000034332275390625, -0.212999999523162841796875, -0.53299999237060546875)), dot(_121, float3(1.164000034332275390625, 2.111999988555908203125, 0.0)), 1.0); + float3 _123 = float3(Texture0.sample(Sampler0, in.in_var_TEXCOORD0).x, Texture1.sample(Sampler1, in.in_var_TEXCOORD0).x, Texture2.sample(Sampler2, in.in_var_TEXCOORD0).x) + float3(-0.0625, -0.5, -0.5); + _136 = float4(dot(_123, float3(1.164000034332275390625, 0.0, 1.7929999828338623046875)), dot(_123, float3(1.164000034332275390625, -0.212999999523162841796875, -0.53299999237060546875)), dot(_123, float3(1.164000034332275390625, 2.111999988555908203125, 0.0)), 1.0); } else { - float4 _133; - if (_100 == 0) + float4 _135; + if (_102 == 0) { - _133 = Texture0.sample(Sampler0, in.in_var_TEXCOORD0); + _135 = Texture0.sample(Sampler0, in.in_var_TEXCOORD0); } else { - _133 = _88; + _135 = _90; } - _134 = _133; + _136 = _135; } - float4 _140; - if ((_99 & 1) == 1) + float4 _142; + if ((_101 & 1) == 1) { - _140 = powr(_134, float4(2.2000000476837158203125)); + _142 = powr(_136, float4(2.2000000476837158203125)); } else { - _140 = _134; + _142 = _136; } - if (_140.w < 0.00999999977648258209228515625) + if (_142.w < 0.00999999977648258209228515625) { discard_fragment(); } - float3 _150 = float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5) * Uniforms.lightPower; - float3 _197; + float3 _152 = float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5) * Uniforms.lightPower; + float3 _199; do { - float3 _154 = Uniforms.lightPosition.xyz - in.in_var_TEXCOORD1; - float _155 = length(_154); - float _156 = _155 * _155; - float _162; - if (_155 > 2.0) + float3 _156 = Uniforms.lightPosition.xyz - in.in_var_TEXCOORD1; + float _157 = length(_156); + float _158 = _157 * _157; + float _164; + if (_157 > 2.0) { - _162 = 0.5 / _156; + _164 = 0.5 / _158; } else { - _162 = 1.0 / _156; + _164 = 1.0 / _158; } - float _167; - if (_155 > 4.0) + float _169; + if (_157 > 4.0) { - _167 = _162 * 0.5; + _169 = _164 * 0.5; } else { - _167 = _162; + _169 = _164; } - float _169 = (_155 > 15.0) ? 0.0 : _167; - float _171 = (_169 > 1.0) ? 1.0 : _169; + float _171 = (_157 > 15.0) ? 0.0 : _169; + float _173 = (_171 > 1.0) ? 1.0 : _171; if (length(in.in_var_TEXCOORD2) < 0.100000001490116119384765625) { - _197 = (in.in_var_TEXCOORD1 * _150) * _171; + _199 = (in.in_var_TEXCOORD1 * _152) * _173; break; } - float3 _178 = fast::normalize(_154); - _197 = ((_150 * precise::max(dot(_178, in.in_var_TEXCOORD2), 0.0)) * _171) + (((_150 * powr(precise::max(dot(in.in_var_TEXCOORD2, fast::normalize(_178 + fast::normalize(in.in_var_TEXCOORD1 - Uniforms.viewPos.xyz))), 0.0), 30.0)) * 2.0) * _171); + float3 _180 = fast::normalize(_156); + _199 = ((_152 * precise::max(dot(_180, in.in_var_TEXCOORD2), 0.0)) * _173) + (((_152 * powr(precise::max(dot(in.in_var_TEXCOORD2, fast::normalize(_180 + fast::normalize(in.in_var_TEXCOORD1 - Uniforms.viewPos.xyz))), 0.0), 30.0)) * 2.0) * _173); break; } while(false); - float3 _214 = ((in.in_var_TEXCOORD3.xyz / float3(in.in_var_TEXCOORD3.w)) * 0.5) + float3(0.5); - float3 _216; - _216.x = _214.x; - float2 _217 = _216.xy; - _217.y = -_214.y; - float _224; - int _227; + float3 _216 = ((in.in_var_TEXCOORD3.xyz / float3(in.in_var_TEXCOORD3.w)) * 0.5) + float3(0.5); + float3 _218; + _218.x = _216.x; + float2 _219 = _218.xy; + _219.y = -_216.y; + float _226; int _229; - _224 = 0.0; - _227 = 0; - _229 = -4; - float _225; - int _228; - for (; _229 <= 4; _224 = _225, _227 = _228, _229++) + int _231; + _226 = 0.0; + _229 = 0; + _231 = -4; + float _227; + int _230; + for (; _231 <= 4; _226 = _227, _229 = _230, _231++) { - _228 = _227; - _225 = _224; - for (int _238 = -4; _238 <= 4; ) + _230 = _229; + _227 = _226; + for (int _240 = -4; _240 <= 4; ) { - _228++; - _225 += float((in.in_var_TEXCOORD3.z - 0.004999999888241291046142578125) > DirectionalShadowDepthMap.sample(DirectionalShadowSampler, (_217 + float2(float(_238) * 0.000244140625, float(_229) * 0.000244140625))).x); - _238++; + _230++; + _227 += float((in.in_var_TEXCOORD3.z - 0.004999999888241291046142578125) > DirectionalShadowDepthMap.sample(DirectionalShadowSampler, (_219 + float2(float(_240) * 0.000244140625, float(_231) * 0.000244140625))).x); + _240++; continue; } } - float3 _267; - if ((_99 & 2) > 0) + float3 _269; + if ((_101 & 2) > 0) { - _267 = _140.xyz * 2.0; + _269 = _142.xyz * 2.0; } else { - _267 = _140.xyz * ((float3(0.100000001490116119384765625) + _197) + ((Uniforms.directionalLightColor.xyz * precise::max(dot(Uniforms.directionalLight.xyz, in.in_var_TEXCOORD2), 0.0)) * (1.0 - (_224 / float(_227))))); - } - float4 _276; - if (_267.x > 1.0) - { - float4 _275 = float4(0.0, 0.0, 0.0, 1.0); - _275.x = _267.x; - _276 = _275; - } - else - { - _276 = float4(0.0, 0.0, 0.0, 1.0); - } - float4 _281; - if (_267.y > 1.0) - { - float4 _280 = _276; - _280.y = _267.y; - _281 = _280; - } - else - { - _281 = _276; + _269 = _142.xyz * ((float3(0.100000001490116119384765625) + _199) + ((Uniforms.directionalLightColor.xyz * precise::max(dot(Uniforms.directionalLight.xyz, in.in_var_TEXCOORD2), 0.0)) * (1.0 - (_226 / float(_229))))); } float4 _286; - if (_267.z > 1.0) + if (_269.x > 1.0) { - float4 _285 = _281; - _285.z = _267.z; + float4 _285 = float4(0.0, 0.0, 0.0, 1.0); + _285.x = _269.x; _286 = _285; } else { - _286 = _281; + _286 = float4(0.0, 0.0, 0.0, 1.0); } - out.out_var_SV_Target0 = float4(_267, _140.w); - out.out_var_SV_Target1 = _286; + float4 _291; + if (_269.y > 1.0) + { + float4 _290 = _286; + _290.y = _269.y; + _291 = _290; + } + else + { + _291 = _286; + } + float4 _296; + if (_269.z > 1.0) + { + float4 _295 = _291; + _295.z = _269.z; + _296 = _295; + } + else + { + _296 = _291; + } + out.out_var_SV_Target0 = float4(_269, _142.w); + out.out_var_SV_Target1 = _296; + out.out_var_SV_Target2 = float4(in.in_var_TEXCOORD1, 1.0); + out.out_var_SV_Target3 = float4(in.in_var_TEXCOORD2, 1.0); return out; } diff --git a/projects/content/_shaders/msl/meshes.vert.msl b/projects/content/_shaders/msl/meshes.vert.msl index 55d2e3c..4e8f7a3 100644 --- a/projects/content/_shaders/msl/meshes.vert.msl +++ b/projects/content/_shaders/msl/meshes.vert.msl @@ -44,14 +44,14 @@ struct main0_in vertex main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_Scene& scene [[buffer(1)]], uint gl_InstanceIndex [[instance_id]]) { main0_out out = {}; - float4 _52 = float4(in.in_var_TEXCOORD0, 1.0); - float4 _55 = scene._m0[gl_InstanceIndex].Model * _52; + float4 _51 = float4(in.in_var_TEXCOORD0, 1.0); + float4 _54 = scene._m0[gl_InstanceIndex].Model * _51; out.out_var_TEXCOORD0 = in.in_var_TEXCOORD3; - out.out_var_TEXCOORD1 = _55.xyz; - out.out_var_TEXCOORD2 = float3((in.in_var_TEXCOORD1 * float4x3(float4(fast::normalize(float3(scene._m0[gl_InstanceIndex].Model[0][0], scene._m0[gl_InstanceIndex].Model[1][0], scene._m0[gl_InstanceIndex].Model[2][0])), 0.0).xyz, float4(fast::normalize(float3(scene._m0[gl_InstanceIndex].Model[0][1], scene._m0[gl_InstanceIndex].Model[1][1], scene._m0[gl_InstanceIndex].Model[2][1])), 0.0).xyz, float4(fast::normalize(float3(scene._m0[gl_InstanceIndex].Model[0][2], scene._m0[gl_InstanceIndex].Model[1][2], scene._m0[gl_InstanceIndex].Model[2][2])), 0.0).xyz, float3(0.0))).xyz); - out.out_var_TEXCOORD3 = Uniforms.ShadowMapProjection * _55; + out.out_var_TEXCOORD1 = _54.xyz; + out.out_var_TEXCOORD2 = fast::normalize(float4(in.in_var_TEXCOORD1, 1.0) * float4x4(float4(fast::normalize(float3(scene._m0[gl_InstanceIndex].Model[0][0], scene._m0[gl_InstanceIndex].Model[1][0], scene._m0[gl_InstanceIndex].Model[2][0])), 0.0), float4(fast::normalize(float3(scene._m0[gl_InstanceIndex].Model[0][1], scene._m0[gl_InstanceIndex].Model[1][1], scene._m0[gl_InstanceIndex].Model[2][1])), 0.0), float4(fast::normalize(float3(scene._m0[gl_InstanceIndex].Model[0][2], scene._m0[gl_InstanceIndex].Model[1][2], scene._m0[gl_InstanceIndex].Model[2][2])), 0.0), float4(0.0, 0.0, 0.0, 1.0))).xyz; + out.out_var_TEXCOORD3 = Uniforms.ShadowMapProjection * _54; out.out_var_TEXCOORD4 = gl_InstanceIndex; - out.gl_Position = Uniforms.ViewProjection * (scene._m0[gl_InstanceIndex].Model * _52); + out.gl_Position = Uniforms.ViewProjection * (scene._m0[gl_InstanceIndex].Model * _51); return out; } diff --git a/projects/content/_shaders/msl/postProc.frag.msl b/projects/content/_shaders/msl/postProc.frag.msl index e2a7c04..49e57cd 100644 --- a/projects/content/_shaders/msl/postProc.frag.msl +++ b/projects/content/_shaders/msl/postProc.frag.msl @@ -13,31 +13,31 @@ struct main0_in float2 in_var_TEXCOORD0 [[user(locn0)]]; }; -fragment main0_out main0(main0_in in [[stage_in]], texture2d ColorTexture [[texture(0)]], texture2d EmissiveTexture [[texture(1)]], sampler Sampler0 [[sampler(0)]], sampler Sampler1 [[sampler(1)]]) +fragment main0_out main0(main0_in in [[stage_in]], texture2d ColorTexture [[texture(0)]], texture2d EmissiveTexture [[texture(1)]], texture2d SsaoTexture [[texture(2)]], sampler Sampler0 [[sampler(0)]], sampler Sampler1 [[sampler(1)]], sampler Sampler2 [[sampler(2)]]) { main0_out out = {}; - float2 _43 = in.in_var_TEXCOORD0; - _43.y = (_43.y * (-1.0)) + 1.0; - float4 _51 = ColorTexture.sample(Sampler0, _43); - float3 _52 = _51.xyz; - float3 _66; - int _69; - _66 = EmissiveTexture.sample(Sampler1, _43).xyz * 0.2270270287990570068359375; - _69 = 0; - float3 _67; - for (; _69 < 5; _66 = _67, _69++) + float2 _45 = in.in_var_TEXCOORD0; + _45.y = (_45.y * (-1.0)) + 1.0; + float4 _53 = ColorTexture.sample(Sampler0, _45); + float3 _54 = _53.xyz; + float3 _68; + int _71; + _68 = EmissiveTexture.sample(Sampler1, _45).xyz * 0.2270270287990570068359375; + _71 = 0; + float3 _69; + for (; _71 < 5; _68 = _69, _71++) { - _67 = _66; - for (int _77 = 0; _77 < 5; ) + _69 = _68; + for (int _79 = 0; _79 < 5; ) { - float2 _85 = float2(float(_69) - 2.5, float(_77)) * float2(0.001953125); - _67 = (_67 + (EmissiveTexture.sample(Sampler1, (_43 + _85)).xyz * float3(0.039999999105930328369140625))) + (EmissiveTexture.sample(Sampler1, (_43 - _85)).xyz * float3(0.039999999105930328369140625)); - _77++; + float2 _87 = float2(float(_71) - 2.5, float(_79)) * float2(0.001953125); + _69 = (_69 + (EmissiveTexture.sample(Sampler1, (_45 + _87)).xyz * float3(0.039999999105930328369140625))) + (EmissiveTexture.sample(Sampler1, (_45 - _87)).xyz * float3(0.039999999105930328369140625)); + _79++; continue; } } - float3 _99 = (powr((_52 * (float3(1.0) + (_52 * float3(0.00999999977648258209228515625)))) / (float3(1.0) + _52), float3(0.4545454680919647216796875)) + (_66 * 0.0500000007450580596923828125)) * 1.0; - out.out_var_SV_Target0 = float4((_99.x * (1.0 + (9.9999999747524270787835121154785e-07 * EmissiveTexture.sample(Sampler1, _43).x))) * (1.0 + (9.9999999747524270787835121154785e-07 * ColorTexture.sample(Sampler0, _43).x)), _99.yz, 1.0); + float3 _107 = ((powr((_54 * (float3(1.0) + (_54 * float3(0.00999999977648258209228515625)))) / (float3(1.0) + _54), float3(0.4545454680919647216796875)) + (_68 * 0.0500000007450580596923828125)) * 1.0) * SsaoTexture.sample(Sampler2, _45).x; + out.out_var_SV_Target0 = float4(((_107.x * (1.0 + (9.9999999747524270787835121154785e-07 * EmissiveTexture.sample(Sampler1, _45).x))) * (1.0 + (9.9999999747524270787835121154785e-07 * ColorTexture.sample(Sampler0, _45).x))) * (1.0 + (9.9999999747524270787835121154785e-07 * SsaoTexture.sample(Sampler2, _45).x)), _107.yz, 1.0); return out; } diff --git a/projects/content/_shaders/msl/ssao.frag.msl b/projects/content/_shaders/msl/ssao.frag.msl new file mode 100644 index 0000000..31f85f1 --- /dev/null +++ b/projects/content/_shaders/msl/ssao.frag.msl @@ -0,0 +1,115 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_Uniforms +{ + float4x4 View; + float4x4 ViewProjection; + float4x4 Projection; + float2 extents; + float radius; + float bias0; + int numSamples; +}; + +constant spvUnsafeArray _311 = spvUnsafeArray({ float3(0.0), float3(0.00039307403494603931903839111328125, 0.00020744701032526791095733642578125, 0.00023402007354889065027236938476562), float3(-0.001318361726589500904083251953125, -0.001457856036722660064697265625, 0.001546739018522202968597412109375), float3(0.0003496186691336333751678466796875, 8.4181214333511888980865478515625e-05, 5.8608897234080359339714050292969e-05), float3(-0.0005043491837568581104278564453125, -0.00383304059505462646484375, 0.002929248847067356109619140625), float3(-0.00241771643050014972686767578125, 0.0057135238312184810638427734375, 0.00173364556394517421722412109375), float3(-0.0007101023220457136631011962890625, 0.000413290224969387054443359375, 0.00037520084879361093044281005859375), float3(1.5587833331665024161338806152344e-05, -0.00011572847870411351323127746582031, 7.3567920480854809284210205078125e-05), float3(0.00334032182581722736358642578125, -0.0051653436385095119476318359375, 0.0050431825220584869384765625), float3(-0.0063966461457312107086181640625, 0.01290071941912174224853515625, 0.00147703452967107295989990234375), float3(0.007907788269221782684326171875, -0.0049759554676711559295654296875, 0.001991991885006427764892578125), float3(-0.0003332807100377976894378662109375, -0.00100087863393127918243408203125, 0.001031001214869320392608642578125), float3(0.00011193146201549097895622253417969, 0.00036116360570304095745086669921875, 0.0010905899107456207275390625), float3(-0.00385366589762270450592041015625, -0.004629385657608509063720703125, 0.00270807673223316669464111328125), float3(-0.0055218120105564594268798828125, 0.0163907893002033233642578125, 0.0033264369703829288482666015625), float3(-0.00297828204929828643798828125, -0.00340225151740014553070068359375, 0.0009606514940969645977020263671875), float3(0.0005643319454975426197052001953125, -0.00123721174895763397216796875, 0.001142332912422716617584228515625), float3(0.0042646829970180988311767578125, 0.001690786913968622684478759765625, 0.00338359293527901172637939453125), float3(0.028113491833209991455078125, -0.01881640218198299407958984375, 0.0140878893435001373291015625), float3(-0.03022454865276813507080078125, -0.000894616474397480487823486328125, 0.008499112911522388458251953125), float3(-0.01961914263665676116943359375, -0.0350324176251888275146484375, 0.014081305824220180511474609375), float3(0.015496986918151378631591796875, -0.010903127491474151611328125, 0.00180752319283783435821533203125), float3(0.0196535401046276092529296875, 0.01710924692451953887939453125, 0.0142847932875156402587890625), float3(-0.02892612479627132415771484375, 0.00322483875788748264312744140625, 0.06573773920536041259765625), float3(-0.0016983882524073123931884765625, 0.0004074592725373804569244384765625, 0.00372933782637119293212890625), float3(-0.0335367508232593536376953125, 0.0591063164174556732177734375, 0.001477129175327718257904052734375), float3(0.01729742996394634246826171875, 0.02095410041511058807373046875, 0.061427496373653411865234375), float3(-0.0362440533936023712158203125, -0.01097334362566471099853515625, 0.052580632269382476806640625), float3(-0.010873113758862018585205078125, 0.071666888892650604248046875, 0.07090236246585845947265625), float3(0.0404303781688213348388671875, -0.0758908092975616455078125, 0.066407024860382080078125), float3(0.006424785591661930084228515625, -0.00888848863542079925537109375, 0.00571323931217193603515625), float3(-0.0424978695809841156005859375, 0.122786454856395721435546875, 0.03013108484447002410888671875), float3(-0.012614764273166656494140625, -0.01173587143421173095703125, 0.0161450766026973724365234375), float3(0.02246730588376522064208984375, -0.023659668862819671630859375, 0.01735904999077320098876953125), float3(0.0280994363129138946533203125, -0.0286351330578327178955078125, 0.0076164784841239452362060546875), float3(0.0701790750026702880859375, -0.1532168686389923095703125, 0.0887149870395660400390625), float3(0.0073889424093067646026611328125, 0.152280390262603759765625, 0.00664083100855350494384765625), float3(0.07831905782222747802734375, -0.072104983031749725341796875, 0.094614334404468536376953125), float3(0.03289596736431121826171875, -0.0408993400633335113525390625, 0.040609411895275115966796875), float3(-0.141404449939727783203125, 0.17826557159423828125, 0.067046172916889190673828125), float3(0.108955644071102142333984375, 0.1114947497844696044921875, 0.21018303930759429931640625), float3(0.02759261615574359893798828125, 0.0139005817472934722900390625, 0.036677159368991851806640625), float3(0.05564410984516143798828125, -0.099730752408504486083984375, 0.113144241273403167724609375), float3(-0.0315654389560222625732421875, -0.22426509857177734375, 0.23739193379878997802734375), float3(-0.0474216155707836151123046875, 0.00566783733665943145751953125, 0.1736856400966644287109375), float3(0.088452465832233428955078125, 0.096331931650638580322265625, 0.083578832447528839111328125), float3(-0.0036428333260118961334228515625, 0.010955554433166980743408203125, 0.00330849713645875453948974609375), float3(-0.1911892592906951904296875, -0.18971312046051025390625, 0.1564487516880035400390625), float3(0.034361146390438079833984375, 0.0655452907085418701171875, 0.0308254323899745941162109375), float3(0.371889293193817138671875, 0.0229042805731296539306640625, 0.2982411682605743408203125), float3(-0.014679887332022190093994140625, 0.01349230110645294189453125, 0.00740495882928371429443359375), float3(-0.00653826631605625152587890625, -0.0058869807980954647064208984375, 0.005725885741412639617919921875), float3(-0.2333120405673980712890625, -0.35499393939971923828125, 0.03432808816432952880859375), float3(0.0411357469856739044189453125, -0.023320116102695465087890625, 0.01891444809734821319580078125), float3(-0.0945928990840911865234375, 0.02529100514948368072509765625, 0.092956520617008209228515625), float3(-0.0317381806671619415283203125, 0.226026356220245361328125, 0.2367977797985076904296875), float3(-0.3801217377185821533203125, 0.2481244504451751708984375, 0.47917068004608154296875), float3(0.13565014302730560302734375, 0.13791494071483612060546875, 0.4077457487583160400390625), float3(0.523879945278167724609375, -0.388758122920989990234375, 0.24387760460376739501953125), float3(-0.0520826168358325958251953125, -0.118409633636474609375, 0.095709107816219329833984375), float3(0.122609488666057586669921875, -0.4220634996891021728515625, 0.178109467029571533203125), float3(-0.2801954448223114013671875, -0.520291268825531005859375, 0.26809024810791015625), float3(-0.3271856009960174560546875, 0.23393590748310089111328125, 0.098123751580715179443359375), float3(0.3826406896114349365234375, 0.08367092907428741455078125, 0.257561206817626953125) }); + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + float2 in_var_TEXCOORD0 [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], texture2d PositionTexture [[texture(0)]], texture2d NormalTexture [[texture(1)]], texture2d NoiseTexture [[texture(2)]], sampler Sampler0 [[sampler(0)]], sampler Sampler1 [[sampler(1)]], sampler Sampler2 [[sampler(2)]]) +{ + main0_out out = {}; + float2 _314 = in.in_var_TEXCOORD0; + float4 _410; + do + { + _314.y = (_314.y * (-1.0)) + 1.0; + float4 _326 = PositionTexture.sample(Sampler0, _314); + float4 _327 = Uniforms.View * _326; + float3 _328 = _327.xyz; + float _329 = _327.z; + if (_329 < 0.00999999977648258209228515625) + { + _410 = float4(1.0); + break; + } + float4 _336 = NormalTexture.sample(Sampler1, _314); + float3 _339 = fast::normalize((Uniforms.View * _336).xyz); + float4 _344 = NoiseTexture.sample(Sampler2, (_314 * float2(320.0, 180.0))); + float3 _346 = fast::normalize(_344.xyz); + float3 _350 = fast::normalize(_346 - (_339 * dot(_346, _339))); + float3x3 _352 = float3x3(_350, cross(_339, _350), _339); + float _354; + _354 = 0.0; + for (int _357 = 0; _357 < Uniforms.numSamples; ) + { + float3 _369 = _328 + ((_311[_357] * _352) * Uniforms.radius); + float4 _376 = Uniforms.Projection * float4(_369, 1.0); + float3 _383 = ((_376.xyz / float3(_376.w)).xyz * 0.5) + float3(0.5); + float4 _384 = float4(_383.x, _383.y, _383.z, _376.w); + _384.y = _383.y * (-1.0); + float4 _391 = Uniforms.View * PositionTexture.sample(Sampler0, _384.xy); + float _392 = _391.z; + _354 += (float(_392 >= (_369.z + Uniforms.bias0)) * smoothstep(0.0, 1.0, Uniforms.radius / abs(_329 - _392))); + _357++; + continue; + } + float _405 = 1.0 - (_354 / float(Uniforms.numSamples)); + _410 = float4(_405) + float4(_405 * 9.9999997473787516355514526367188e-06); + break; + } while(false); + out.out_var_SV_Target0 = _410; + return out; +} + diff --git a/projects/content/_shaders/spv/lit_mesh.frag.spv b/projects/content/_shaders/spv/lit_mesh.frag.spv index 13a99ea6689baa9653b22f2f39f337068758241f..b2e4ad4ba1dc89a7994f3a1a552a0f6ab1be0b9c 100644 GIT binary patch literal 7980 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 NX=d;Fzf^J+`48iS%$ooJ literal 3280 zcmZXVYg1fB5QZmQ79*Ibkq|E-OYlxyQIi;rNq`VR1%Z%6yk}*XaxG!0Wik3KKf#~t z7pr`pb518y>rlPZ@7tH@o|!WY56zCHbRwm6D(&&>cp(iH%y_C5^UB)xTH~nSYFxfD zul-aSb}DSA)9FGV;&;E5pTV4A22=fvwpY_;Bf> z?RUEDN{t=RW?kFAHe20C>&?T=!CJIiU%#{8W`Y^zEKuC3$Ttpm!XG&OL&r^HUBM$p2)!CP0wwzMVS*v$sm36|;b;HM;#w}!= zb;~VhoW0AfW}JEC))4D{k=cFUM9lBE>Cnev4Z)oQdoE&g>u;Tor~Xg5ypQmUKE#84 z1UDF`Umh2|K8Cj*TH?jG3$OOX!ZX_)ap{5pC*ck(3_a3g0P^vF5VhI^qcb zmrIzYu)l(C4r@Ed@2kvm;%RQ2XD4T#T+UO6`>uT&-Tf5TiF}ROUgV~${WXVD);^NX zqw8be*5SR>=9!q|0<%5HYp*kFH%9vmv-Wz0FIKqhcceJWGFR#UI(D)7jDMrT_9}j} z!p5IrmA9B@hU7vTDUBBFqk@PNld{5W0+qd78K4N?Hn+a@B)^GyRE_R;-&!GFw z2ev2gb>LZa@0B@>w^n#Ju5(Tdq+RD9(56rAU| z4mOW`K7M$_=Yxf%p z|GVhc;s|aVJ?abYUd82k@533dzxF)u1F*d~BF8uA(O+;o6_@Az7S4G6wVOBY=XdD# zqd43{W5fPEx^*dzLHiGI=2skH_q+Ao{1I^t^XTil6W_~E=)NKPMEyUb%R7R5h%RUD z;F=Xz_F3NfU*L>?h-i=Rdl%jBdkTr~u7xfiwY1UwM&)nv%K85Ko~irx`W>sEWOf~O W-(2I=$C-V5)F+sI3;w0zYsh~g2G6Ac diff --git a/projects/content/_shaders/spv/postProc.frag.spv b/projects/content/_shaders/spv/postProc.frag.spv index 9f5a7d13f4d7c25ce2219992202b8537efde9c7a..76a405bdd4143cafa276cee5531c54ac06a086d7 100644 GIT binary patch literal 3156 zcmZXV+frOr5QaC92^x@u9Ka+VKs!sB)zWiS1sp?v_wphN=*s4jVynCea_0sz0TDjKb3(0L53r#A`%{^|1 zn_jQf>y_Df#-l?)t+%DCMi_^G6= zH2~Uxx_)oYH~t_X{(L|BAuKs-7W*B>KJoo;lOt3{{Rof?L|h--FF(&tgx`<(KAQ=2jQX_iilnwN^*zP~-HyuUrg$#{g^M z?TtM~l;42-y#_GCAHa5n3~m zI|n@1??v73GVVHoZ4bp=C$a6Jxa;{;OA`6G>jiB2*1J9przRY6*Kf1jo`EyQJpQ5z zQ_Q}v^Y2-%7qN}=&8NY$K+WHy8Q^b&+H*kdJNEW_c^;_y8}JA3_5!oI<8OTR7lFKI zYMaAs<~v6Yo@*Y)yaZkbk;5FeIjCI%YLUZbZ1u=tKGT`f9Mp}MHwW!1x%DtF0Q3Kn z`{*xboWEfa^9r{6Un0i-T>{3*+b42YfV|(IeImCEe5}wgA{+GwwaK_~G z@cqn1ZI?XkBj3$B_JVv5_%8bPjql?eYwS1QC)Pyo+E3Bn?_k?EeIV+vg6;RG7I9^4 z`GX+7!*{W}GQX2~6?B964zFVyBOl*k1zX;lI^s9+J!~~cocTVs=c>h?YuK%|Ux$-# z-E#v@&EdP-qgBuk)V#0UCh%Trk`$>hTP@-~!}ff& qsL$uv*2nKExZR9vXTHSm-yri%;CkbCfqPH#-*6AJ+CS`Y7W@mXt>$I` literal 2780 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 S@vMP=r{G-TyQ*DjA^AT`UFrw` literal 0 HcmV?d00001