Skip to content

Commit af4375f

Browse files
committed
hatch dilation based on fragShaderInterlock availability
1 parent e341792 commit af4375f

File tree

1 file changed

+46
-21
lines changed

1 file changed

+46
-21
lines changed

62_CAD/vertex_shader.hlsl

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
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)
1011
float 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+
5993
PSInput 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

Comments
 (0)