You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

317 lines
9.9 KiB

#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/LineRendering/Core/LineRendering.Data.cs.hlsl"
// Shader Variable Constant Aliases
#define _DimBin _Params0.xy
#define _SegmentCount _Params0.z
#define _BinCount _Params0.w
#define _SizeScreen _Params1
#define _SizeBin _Params2
#define _VertexCount _Params3.x
#define _VertexStride _Params3.y
#define _ActiveBinCount _Params3.z
#define _ClusterDepth _Params3.w
#define _ShadingAtlasDimensions _Params4.xy
#define _ClusterCount _Params4.z
#define _TileOpacityThreshold _Params4.w
#define _ViewIndex (uint)_Params5.x
#define COUNTER_BIN_RECORD 0 << 2
#define COUNTER_BIN_QUEUE_SIZE 1 << 2
#define COUNTER_BIN_QUEUE_INDEX 2 << 2
#define COUNTER_CLUSTER_QUEUE_SIZE 3 << 2
#define COUNTER_CLUSTER_QUEUE_INDEX 4 << 2
#define COUNTER_ACTIVE_SEGMENTS 5 << 2
#define COUNTER_SHADING_SAMPLES 6 << 2
#define COUNTER_GROUP_SEG_OFFSET 7 << 2
#define OFFSETS_VERTEX 0 << 2
#define OFFSETS_SEGMENT 1 << 2
// Maximum representable floating-point number
#define FLT_MAX 3.402823466e+38
#define DEPTH_CLIP_BIAS 1e-4
#define INTERP(coords, a, b) (coords.y * a) + (coords.x * b)
//TODO: make this a performance config for artists
#define SamplesPerSegment 2
#define INVALID_SHADING_SAMPLE 0xFFFFFFFF
struct PackedSegmentRecord
{
uint4 A; // PositionSS0, DepthVS0, VertexID0
uint4 B; // PositionSS1, DepthVS1, VertexID1
static PackedSegmentRecord Pack(SegmentRecord record)
{
PackedSegmentRecord packedRecord;
{
packedRecord.A = uint4(asuint(float3(record.positionSS0, record.depthVS0)), record.vertexIndex0);
packedRecord.B = uint4(asuint(float3(record.positionSS1, record.depthVS1)), record.vertexIndex1);
}
return packedRecord;
}
static SegmentRecord Unpack(PackedSegmentRecord packedRecord)
{
SegmentRecord record;
{
record.positionSS0 = asfloat(packedRecord.A.xy);
record.positionSS1 = asfloat(packedRecord.B.xy);
record.depthVS0 = asfloat(packedRecord.A.z);
record.depthVS1 = asfloat(packedRecord.B.z);
record.vertexIndex0 = packedRecord.A.w;
record.vertexIndex1 = packedRecord.B.w;
}
return record;
}
};
void StoreSegmentRecord(RWByteAddressBuffer buffer, SegmentRecord record, uint index)
{
const PackedSegmentRecord packedSegment = PackedSegmentRecord::Pack(record);
const uint offset = 32 * index;
buffer.Store4(offset + (0 << 4), packedSegment.A);
buffer.Store4(offset + (1 << 4), packedSegment.B);
}
SegmentRecord LoadSegmentRecord(ByteAddressBuffer buffer, uint index)
{
const uint offset = 32 * index;
PackedSegmentRecord packedRecord;
{
packedRecord.A = buffer.Load4(offset + (0 << 4));
packedRecord.B = buffer.Load4(offset + (1 << 4));
}
return PackedSegmentRecord::Unpack(packedRecord);
}
struct PackedVertexRecord
{
uint4 A; // PositionCS
uint4 B; // PreviousPositionCS
uint4 C; // Tangent, Normal
uint4 D; // Texcoord0, Texcoord1
static PackedVertexRecord Pack(VertexRecord record)
{
PackedVertexRecord packedRecord;
{
packedRecord.A = asuint(record.positionCS);
packedRecord.B = asuint(record.previousPositionCS);
packedRecord.C = asuint(float4(record.tangentWS, record.texCoord0));
}
return packedRecord;
}
static VertexRecord Unpack(PackedVertexRecord packedRecord)
{
const float4 A = asfloat(packedRecord.A);
const float4 B = asfloat(packedRecord.B);
const float4 C = asfloat(packedRecord.C);
const float4 D = asfloat(packedRecord.D);
VertexRecord record;
{
record.positionCS = A;
record.previousPositionCS = B;
record.tangentWS = C.xyz;
record.texCoord0 = C.w;;
record.normalWS = D.xyz;
record.texCoord1 = D.w;
}
return record;
}
};
void StoreVertexRecord(RWByteAddressBuffer buffer, VertexRecord record, uint index)
{
const PackedVertexRecord packedVertex = PackedVertexRecord::Pack(record);
const uint offset = 80 * index;
buffer.Store4(offset + (0 << 4), packedVertex.A);
buffer.Store4(offset + (1 << 4), packedVertex.B);
buffer.Store4(offset + (2 << 4), packedVertex.C);
buffer.Store4(offset + (3 << 4), packedVertex.D);
}
VertexRecord LoadVertexRecord(ByteAddressBuffer buffer, uint index)
{
const uint offset = 80 * index;
PackedVertexRecord packedRecord;
{
packedRecord.A = buffer.Load4(offset + (0 << 4));
packedRecord.B = buffer.Load4(offset + (1 << 4));
packedRecord.C = buffer.Load4(offset + (2 << 4));
packedRecord.D = buffer.Load4(offset + (3 << 4));
}
return PackedVertexRecord::Unpack(packedRecord);
}
// Structures
// -----------------------------------------------------
struct AABB
{
float2 min;
float2 max;
float2 Center()
{
return (min + max) * 0.5;
}
};
#define INSIDE 0 // 0000
#define LEFT 1 // 0001
#define RIGHT 2 // 0010
#define BOTTOM 4 // 0100
#define TOP 8 // 1000
struct ClippingParams
{
float minX;
float maxX;
float minY;
float maxY;
};
ClippingParams DefaultClippingParams()
{
ClippingParams params;
{
params.minX = -1;
params.maxX = +1;
params.minY = -1;
params.maxY = +1;
}
return params;
}
uint ComputeOutCode(float x, float y, ClippingParams clipping)
{
uint code = INSIDE;
{
if (x < clipping.minX ) { code |= LEFT; }
else if (x > clipping.maxX ) { code |= RIGHT; }
if (y < clipping.minY ) { code |= BOTTOM; }
else if (y > clipping.maxY ) { code |= TOP; }
}
return code;
}
// TODO: Investigate "Improvement in the Cohen-Sutherland Line Segment Clipping Algorithm" for something faster.
bool ClipSegmentCohenSutherland(inout float x0, inout float y0, inout float x1, inout float y1, ClippingParams clipping)
{
uint outCode0 = ComputeOutCode(x0, y0, clipping);
uint outCode1 = ComputeOutCode(x1, y1, clipping);
bool accept = false;
for(;;)
{
// Trivially accept, both points inside the viewport.
if(!(outCode0 | outCode1))
{
accept = true;
break;
}
// Trivially reject, both points outside the viewport.
else if(outCode0 & outCode1)
{
break;
}
// Both tests failed, calculate the clipped segment.
else
{
// One point is outside the window. Need to compute a new point clipped to the viewport edge.
// Default initialize to keep the compiler warnings away.
float x = -1, y = -1;
// Choose the out code that is outside the viewport.
uint outCodeOut = outCode1 > outCode0 ? outCode1 : outCode0;
// Determine the clipped position based on the out code.
if (outCodeOut & TOP) { x = x0 + (x1 - x0) * (clipping.maxY - y0) / (y1 - y0); y = clipping.maxY; }
else if (outCodeOut & BOTTOM) { x = x0 + (x1 - x0) * (clipping.minY - y0) / (y1 - y0); y = clipping.minY; }
else if (outCodeOut & RIGHT) { y = y0 + (y1 - y0) * (clipping.maxX - x0) / (x1 - x0); x = clipping.maxX; }
else if (outCodeOut & LEFT) { y = y0 + (y1 - y0) * (clipping.minX - x0) / (x1 - x0); x = clipping.minX; }
if (outCodeOut == outCode0)
{
x0 = x;
y0 = y;
outCode0 = ComputeOutCode(x0, y0, clipping);
}
else
{
x1 = x;
y1 = y;
outCode1 = ComputeOutCode(x1, y1, clipping);
}
}
}
return accept;
}
bool ClipSegmentCohenSutherland(inout float x0, inout float y0, inout float x1, inout float y1)
{
return ClipSegmentCohenSutherland(x0, y0, x1, y1, DefaultClippingParams());
}
// Signed distance to a line segment.
// Ref: https://www.shadertoy.com/view/3tdSDj
float DistanceToSegmentAndTValueSq(float2 P, float2 A, float2 B, out float T)
{
float2 BA = B - A;
float2 PA = P - A;
// Also output the 'barycentric' segment coordinate computed as a bi-product of the coverage.
T = clamp( dot(PA, BA) / dot(BA, BA), 0.0, 1.0);
const float2 V = PA - T * BA;
return dot(V, V);
}
float DistanceToSegmentAndTValue(float2 P, float2 A, float2 B, out float T)
{
return sqrt(DistanceToSegmentAndTValueSq(P, A, B, T));
}
void GetSegmentBoundingBox(SegmentRecord segment, float screenSpaceWidthPadding, out uint2 tilesB, out uint2 tilesE)
{
// Determine the Tile-Space AABB of the segment.
tilesB = (min(segment.positionSS0, segment.positionSS1) - screenSpaceWidthPadding) / _SizeBin.x;
tilesE = (max(segment.positionSS0, segment.positionSS1) + screenSpaceWidthPadding) / _SizeBin.x;
// Clamp AABB to tiled raster space.
tilesB = clamp(tilesB, int2(0, 0), _DimBin - 1);
tilesE = clamp(tilesE, int2(0, 0), _DimBin - 1);
}
bool SegmentsIntersectsBin(uint x, uint y, float2 p0, float2 p1, float screenSpaceWidthPadding)
{
float2 tileB = float2(x, y);
float2 tileE = tileB + 1.0;
float2 tileMin = float2(tileB * 8.0);
float2 tileMax = float2(tileE * 8.0);
ClippingParams clippingParams;
clippingParams.minX = tileMin.x - screenSpaceWidthPadding;
clippingParams.minY = tileMin.y - screenSpaceWidthPadding;
clippingParams.maxX = tileMax.x + screenSpaceWidthPadding;
clippingParams.maxY = tileMax.y + screenSpaceWidthPadding;
return ClipSegmentCohenSutherland(p0.x, p0.y, p1.x, p1.y, clippingParams);
}