Files
UnrealEngine/Engine/Shaders/Private/HairStrands/HairStrandsAttributeCommon.ush
2025-05-18 13:04:45 +08:00

114 lines
5.8 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "/Engine/Private/HairStrands/HairStrandsPack.ush"
////////////////////////////////////////////////////////////////////////////////
// Data stride in bytes
// Data stride in bytes
#define HAIR_CURVE_ATTRIBUTE_STRIDE_ROOTUV 4
#define HAIR_CURVE_ATTRIBUTE_STRIDE_SEED 1
#define HAIR_CURVE_ATTRIBUTE_STRIDE_LENGTH 2
#define HAIR_CURVE_ATTRIBUTE_STRIDE_CLUMPID 2
#define HAIR_CURVE_ATTRIBUTE_STRIDE_CLUMPID3 8
#define HAIR_POINT_ATTRIBUTE_STRIDE_COLOR 4
#define HAIR_POINT_ATTRIBUTE_STRIDE_ROUGHNESS 1
#define HAIR_POINT_ATTRIBUTE_STRIDE_AO 1
// Data offset in bytes. The order needs to match HairStrandsDefinitions.h
#define HAIR_CURVE_ATTRIBUTE_OFFSET_ROOTUV(InOffsets) (InOffsets[0].x)
#define HAIR_CURVE_ATTRIBUTE_OFFSET_SEED(InOffsets) (InOffsets[0].y)
#define HAIR_CURVE_ATTRIBUTE_OFFSET_LENGTH(InOffsets) (InOffsets[0].z)
#define HAIR_CURVE_ATTRIBUTE_OFFSET_CLUMPID(InOffsets) (InOffsets[0].w)
#define HAIR_CURVE_ATTRIBUTE_OFFSET_CLUMPID3(InOffsets) (InOffsets[1].x)
#define HAIR_POINT_ATTRIBUTE_OFFSET_COLOR(InOffsets) (InOffsets[0].x)
#define HAIR_POINT_ATTRIBUTE_OFFSET_ROUGHNESS(InOffsets) (InOffsets[0].y)
#define HAIR_POINT_ATTRIBUTE_OFFSET_AO(InOffsets) (InOffsets[0].z)
////////////////////////////////////////////////////////////////////////////////
// Attribute access functions
uint InternalGetHairStrandsAttributes(uint Index, uint AttributeOffsetInBytes, uint AttributeStrideInBytes, ByteAddressBuffer InAttributeBuffer, uint InIndexToChunkDivAsShift, uint InChunkElementCount, uint InChunkStrideInBytes)
{
// Adapt index and offset
const uint ChunkIndex = Index >> InIndexToChunkDivAsShift;
Index -= ChunkIndex * InChunkElementCount;
AttributeOffsetInBytes += ChunkIndex * InChunkStrideInBytes;
// Ensure the reading address is 4-byte aligned
const uint Address = AttributeOffsetInBytes + Index * AttributeStrideInBytes;
const uint Address_4BytesAligned = Address & (~0x3);
const uint Packed = InAttributeBuffer.Load(Address_4BytesAligned);
// If the data has a stride < 4bytes, compute the relative offset for reading the data
const uint ElementIndex = Address - Address_4BytesAligned;
return Packed >> (8u * ElementIndex);
}
uint2 InternalGetHairStrandsAttributes64(uint Index, uint AttributeOffsetInBytes, uint AttributeStrideInBytes, ByteAddressBuffer InAttributeBuffer, uint InIndexToChunkDivAsShift, uint InChunkElementCount, uint InChunkStrideInBytes)
{
const uint ChunkIndex = Index >> InIndexToChunkDivAsShift;
Index -= ChunkIndex * InChunkElementCount;
AttributeOffsetInBytes += ChunkIndex * InChunkStrideInBytes;
// Ensure the reading address is 4-byte aligned
const uint Address = AttributeOffsetInBytes + Index * AttributeStrideInBytes;
const uint Address_4BytesAligned = Address & (~0x3);
// For now, do two separate load to as we don't ensure the offset is 2byte-aligned
uint2 OutPacked = 0;
OutPacked.x = InAttributeBuffer.Load(Address_4BytesAligned);
OutPacked.y = InAttributeBuffer.Load(Address_4BytesAligned + 4u);
return OutPacked;
}
uint InternalGetHairStrandsAttributesPerCurve(uint HairControlPointId, uint AttributeOffsetInBytes, uint AttributeStrideInBytes, ByteAddressBuffer InAttributeBuffer, ByteAddressBuffer InPointToCurveBuffer, uint InIndexToChunkDivAsShift, uint InChunkElementCount, uint InChunkStrideInBytes)
{
const uint CurveIndex = ReadHairPointToCurveIndex(InPointToCurveBuffer, HairControlPointId);
return InternalGetHairStrandsAttributes(CurveIndex, AttributeOffsetInBytes, AttributeStrideInBytes, InAttributeBuffer, InIndexToChunkDivAsShift, InChunkElementCount, InChunkStrideInBytes);
}
uint2 InternalGetHairStrandsAttributesPerCurve64(uint HairControlPointId, uint AttributeOffsetInBytes, uint AttributeStrideInBytes, ByteAddressBuffer InAttributeBuffer, ByteAddressBuffer InPointToCurveBuffer, uint InIndexToChunkDivAsShift, uint InChunkElementCount, uint InChunkStrideInBytes)
{
const uint CurveIndex = ReadHairPointToCurveIndex(InPointToCurveBuffer, HairControlPointId);
return InternalGetHairStrandsAttributes64(CurveIndex, AttributeOffsetInBytes, AttributeStrideInBytes, InAttributeBuffer, InIndexToChunkDivAsShift, InChunkElementCount, InChunkStrideInBytes);
}
uint InternalGetHairStrandsAttributesPerVertex(uint HairControlPointId, uint AttributeOffsetInBytes, uint AttributeStrideInBytes, ByteAddressBuffer InAttributeBuffer, uint InIndexToChunkDivAsShift, uint InChunkElementCount, uint InChunkStrideInBytes)
{
return InternalGetHairStrandsAttributes(HairControlPointId, AttributeOffsetInBytes, AttributeStrideInBytes, InAttributeBuffer, InIndexToChunkDivAsShift, InChunkElementCount, InChunkStrideInBytes);
}
float InternalGetHairStrandsCoordU(ByteAddressBuffer InPositionBuffer, uint InPointIndex, float InRadius, float InRootScale, float InTipScale)
{
return ReadHairControlPoint(InPositionBuffer, InPointIndex, float3(0, 0, 0), InRadius, InRootScale, InTipScale).UCoord;
}
float InternalGetHairStrandsWorldRadius(ByteAddressBuffer InPositionBuffer, uint InPointIndex, float InRadius, float InRootScale, float InTipScale)
{
return ReadHairControlPoint(InPositionBuffer, InPointIndex, float3(0, 0, 0), InRadius, InRootScale, InTipScale).WorldRadius;
}
bool IsAttributeValid(uint InOffset)
{
return InOffset != HAIR_ATTRIBUTE_INVALID_OFFSET;
}
////////////////////////////////////////////////////////////////////////////////
// Attribute access with explicit resources
#include "/Engine/Private/HairStrands/HairStrandsVertexFactoryCommon.ush"
#if HAIR_STRAND_MESH_FACTORY
#if HAIR_STRANDS_PARAMETERS == 1
// Global constants access
#define HAIR_STRANDS_ATTRIBUTE_ACCESSORS(Name) HairStrandsVF_##Name
#else
// Uniform Buffer access
#define HAIR_STRANDS_ATTRIBUTE_ACCESSORS(Name) HairStrandsVF.##Name
#endif
#include "/Engine/Private/HairStrands/HairStrandsAttributeTemplate.ush"
#endif