55#include <nbl/builtin/hlsl/math/equations/quadratic.hlsl>
66#include <nbl/builtin/hlsl/limits.hlsl>
77#include <nbl/builtin/hlsl/algorithm.hlsl>
8+ #include <nbl/builtin/hlsl/jit/device_capabilities.hlsl>
89
910// TODO[Lucas]: Move these functions to builtin hlsl functions (Even the shadertoy obb and aabb ones)
1011float cross2D (float2 a, float2 b)
@@ -56,6 +57,39 @@ float4 transformFromSreenSpaceToNdc(float2 pos)
5657 return float4 ((pos.xy / globals.resolution) * 2.0 - 1.0 , 0.0f , 1.0f );
5758}
5859
60+ template<bool FragmentShaderPixelInterlock>
61+ void dilateHatch (out float2 outOffsetVec, out float2 outUV, const float2 undilatedCorner, const float2 dilateRate, const float2 ndcAxisU, const float2 ndcAxisV);
62+
63+ // Dilate with ease, our transparency algorithm will handle the overlaps easily with the help of FragmentShaderPixelInterlock
64+ template<>
65+ void dilateHatch<true >(out float2 outOffsetVec, out float2 outUV, const float2 undilatedCorner, const float2 dilateRate, const float2 ndcAxisU, const float2 ndcAxisV)
66+ {
67+ const float2 dilatationFactor = 1.0 + 2.0 * dilateRate;
68+
69+ // cornerMultiplier stores the direction of the corner to dilate:
70+ // (-1,-1)|--|(1,-1)
71+ // | |
72+ // (-1,1) |--|(1,1)
73+ const float2 cornerMultiplier = float2 (undilatedCorner * 2.0 - 1.0 );
74+ outUV = float2 ((cornerMultiplier * dilatationFactor + 1.0 ) * 0.5 );
75+
76+ // vx/vy are vectors in direction of the box's axes and their length is equal to X pixels (X = globals.antiAliasingFactor + 1.0)
77+ // and we use them for dilation of X pixels in ndc space by adding them to the currentCorner in NDC space
78+ const float2 vx = ndcAxisU * dilateRate.x;
79+ const float2 vy = ndcAxisV * dilateRate.y;
80+ outOffsetVec = vx * cornerMultiplier.x + vy * cornerMultiplier.y; // (0, 0) should do -vx-vy and (1, 1) should do +vx+vy
81+ }
82+
83+ // Don't dilate which causes overlap of colors when no fragshaderInterlock which powers our transparency and overlap resolving algorithm
84+ template<>
85+ void dilateHatch<false >(out float2 outOffsetVec, out float2 outUV, const float2 undilatedCorner, const float2 dilateRate, const float2 ndcAxisU, const float2 ndcAxisV)
86+ {
87+ outOffsetVec = float2 (0.0f , 0.0f );
88+ outUV = undilatedCorner;
89+ // TODO: If it became a huge bummer on AMD devices we can consider dilating only in minor direction which may still avoid color overlaps
90+ // Or optionally we could dilate and stuff when we know this hatch is opaque (alpha = 1.0)
91+ }
92+
5993PSInput main (uint vertexID : SV_VertexID )
6094{
6195 const uint vertexIdx = vertexID & 0x3u;
@@ -379,35 +413,26 @@ PSInput main(uint vertexID : SV_VertexID)
379413 curveBox.curveMax[i] = vk::RawBufferLoad<float32_t2>(drawObj.geometryAddress + sizeof (double2 ) * 2 + sizeof (float32_t2) * (3 + i), 4u);
380414 }
381415
382- const float2 ndcBoxAxisX = (float2 )transformVectorNdc (clipProjectionData.projectionToNDC, double2 (curveBox.aabbMax.x, curveBox.aabbMin.y) - curveBox.aabbMin);
383- const float2 ndcBoxAxisY = (float2 )transformVectorNdc (clipProjectionData.projectionToNDC, double2 (curveBox.aabbMin.x, curveBox.aabbMax.y) - curveBox.aabbMin);
416+ const float2 ndcAxisU = (float2 )transformVectorNdc (clipProjectionData.projectionToNDC, double2 (curveBox.aabbMax.x, curveBox.aabbMin.y) - curveBox.aabbMin);
417+ const float2 ndcAxisV = (float2 )transformVectorNdc (clipProjectionData.projectionToNDC, double2 (curveBox.aabbMin.x, curveBox.aabbMax.y) - curveBox.aabbMin);
384418
385- const float2 screenSpaceAabbExtents = float2 (length (ndcBoxAxisX * float2 (globals.resolution)) / 2.0 , length (ndcBoxAxisY * float2 (globals.resolution)) / 2.0 );
419+ const float2 screenSpaceAabbExtents = float2 (length (ndcAxisU * float2 (globals.resolution)) / 2.0 , length (ndcAxisV * float2 (globals.resolution)) / 2.0 );
386420
387421 // we could use something like this to compute screen space change over minor/major change and avoid ddx(minor), ddy(major) in frag shader (the code below doesn't account for rotation)
388422 outV.setCurveBoxScreenSpaceSize (float2 (screenSpaceAabbExtents));
389423
390- const float pixelsToIncreaseOnEachSide = globals.antiAliasingFactor + 1.0 ;
391- const double2 dilateRate = pixelsToIncreaseOnEachSide / screenSpaceAabbExtents;
392- const double2 dilatationFactor = 1.0 + 2.0 * dilateRate;
393- // undilatedMaxCornerNDC stores the quad's UVs:
394- // (-1,-1)|--|(1,-1)
395- // | |
396- // (-1,1) |--|(1,1)
397424 const float2 undilatedCorner = float2 (bool2 (vertexIdx & 0x1u, vertexIdx >> 1 ));
398- const float2 undilatedCornerNDC = float2 (undilatedCorner * 2.0 - 1.0 );
399- // Dilate the UVs
400- const float2 maxCorner = float2 ((undilatedCornerNDC * dilatationFactor + 1.0 ) * 0.5 );
401425
402- // vx/vy are vectors in direction of the box's axes and their length is equal to X pixels (X = globals.antiAliasingFactor + 1.0)
403- // and we use them for dilation of X pixels in ndc space by adding them to the currentCorner in NDC space
404- const double2 vx = ndcBoxAxisX * dilateRate.x;
405- const double2 vy = ndcBoxAxisY * dilateRate.y;
406- const double2 offsetVec = vx * undilatedCornerNDC.x + vy * undilatedCornerNDC.y; // (0, 0) should do -vx-vy and (1, 1) should do +vx+vy
426+ // We don't dilate on AMD (= no fragShaderInterlock)
427+ const float pixelsToIncreaseOnEachSide = globals.antiAliasingFactor + 1.0 ;
428+ const float2 dilateRate = pixelsToIncreaseOnEachSide / screenSpaceAabbExtents; // float sufficient to hold the dilate rect?
429+ float2 dilateVec;
430+ float2 dilatedUV;
431+ dilateHatch<nbl::hlsl::jit::device_capabilities::fragmentShaderPixelInterlock>(dilateVec, dilatedUV, undilatedCorner, dilateRate, ndcAxisU, ndcAxisV);
407432
408433 // doing interpolation this way to ensure correct endpoints and 0 and 1, we can alternatively use branches to set current corner based on vertexIdx
409434 const double2 currentCorner = curveBox.aabbMin * (1.0 - undilatedCorner) + curveBox.aabbMax * undilatedCorner;
410- const float2 coord = (float2 ) (transformPointNdc (clipProjectionData.projectionToNDC, currentCorner) + offsetVec );
435+ const float2 coord = (float2 ) (transformPointNdc (clipProjectionData.projectionToNDC, currentCorner) + dilateVec );
411436
412437 outV.position = float4 (coord, 0.f , 1.f );
413438
@@ -421,8 +446,8 @@ PSInput main(uint vertexID : SV_VertexID)
421446 nbl::hlsl::shapes::Quadratic<float > curveMax = nbl::hlsl::shapes::Quadratic<float >::construct (
422447 curveBox.curveMax[0 ], curveBox.curveMax[1 ], curveBox.curveMax[2 ]);
423448
424- outV.setMinorBBoxUV (maxCorner [minor]);
425- outV.setMajorBBoxUV (maxCorner [major]);
449+ outV.setMinorBBoxUV (dilatedUV [minor]);
450+ outV.setMajorBBoxUV (dilatedUV [major]);
426451
427452 outV.setCurveMinMinor (nbl::hlsl::math::equations::Quadratic<float >::construct (
428453 curveMin.A[minor],
0 commit comments