You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
This simplifies the logic for solid/thin glass greatly and makes it easier to support transparent thin glass via the new SurfaceCoverage material output (introduced in 32048301). There is a new shading model id for the path tracer for the solid glass case. This and the existing SHADINGMODELID_THIN_TRANSLUCENT now refer only to the glass lobes. SHADINGMODELID_DEFAULT_LIT can be used for the rest which removes some duplicated logic and makes the common cases much faster. #rb Sebastien.Hillaire [CL 32089900 by chris kulla in ue5-main branch]
845 lines
36 KiB
Plaintext
845 lines
36 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
PathTracingCommon.ush: path tracing payload structures
|
|
=============================================================================*/
|
|
|
|
#pragma once
|
|
|
|
#include "Material/PathTracingMaterialCommon.ush"
|
|
#include "../RayTracing/RayTracingCommon.ush"
|
|
#include "../OctahedralCommon.ush"
|
|
#include "/Engine/Shared/PathTracingDefinitions.h"
|
|
|
|
// These flags are analogous to RAY_TRACING_PAYLOAD_* flags. There are currently 9 bits available.
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_FRONT_FACE (1 << 0) // Indicates that ray has hit the front face of a primitive. Set by closest hit shader.
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_TWO_SIDED_MATERIAL (1 << 1) // Indicates that ray has hit a primitive surface with a two sided material. Set by closest hit shader. Used by GPU Lightmass to detect invalid surfaces.
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_IS_HOLDOUT (1 << 2) // Indicates that ray has hit a primitive which should be held out from alpha.
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_MASK_SHIFT (3)
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_COLOR (1 << 3) // Indicates that ray has hit a primitive that receives decals color. Set by closest hit shader.
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_NORMAL (1 << 4) // Indicates that ray has hit a primitive that receives decals normal. Set by closest hit shader.
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_ROUGHNESS (1 << 5) // Indicates that ray has hit a primitive that receives decals metallic/specular/roughness. Set by closest hit shader.
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_USE_DBUFFER_LOOKUP (1 << 6) // Indicates that ray has hit a primitive that uses DBufferTextureLookup. Set by closest hit shader.
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_OUTOUT_DEPTH (1 << 7) // Indicates that ray has hit a primitive that needs to output depth. Set by closest hit shader and used in primary ray only.
|
|
#define PATH_TRACING_PAYLOAD_OUTPUT_FLAG_UNUSED8 (1 << 8) // Free for future use
|
|
|
|
#define PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_MASK (7 << 0) // Reserve 3 bits for ray-mask
|
|
#define PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_CAMERA 0 // Indicates that this is a camera ray which can trigger a number of special behaviors in the closest hit shader
|
|
#define PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_SHADOW 1 // Indicates that this is a path tracer visibility ray (which supports material evaluation for transparent shadows and fake caustics)
|
|
#define PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_INDIRECT_DIFFUSE 2
|
|
#define PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_INDIRECT_SPECULAR 3
|
|
#define PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_INDIRECT_VOLUME 4
|
|
|
|
#define PATH_TRACING_PAYLOAD_NORMAL_BITS 32
|
|
|
|
// shading model extensions beyond the default count
|
|
#define SHADINGMODELID_MEDIUM (SHADINGMODELID_NUM + 1)
|
|
#define SHADINGMODELID_SOLID_GLASS (SHADINGMODELID_NUM + 2)
|
|
|
|
HLSL_STATIC_ASSERT(SHADINGMODELID_MEDIUM <= SHADINGMODELID_MASK, "");
|
|
HLSL_STATIC_ASSERT(SHADINGMODELID_SOLID_GLASS <= SHADINGMODELID_MASK, "");
|
|
|
|
#define PATH_TRACING_ABSORPTION_SCALE 0.01 // inverse distance at which we hit the transmission color (Beer's law)
|
|
|
|
// This function is meant for the solid glass case so we can store the transmittance as a color in [0,1]
|
|
float3 PathTracingGlassTransmittanceToExtinction(float3 TransmittanceColor)
|
|
{
|
|
return -log(max(TransmittanceColor, 1e-8f)) * PATH_TRACING_ABSORPTION_SCALE;
|
|
}
|
|
|
|
uint PayloadEncodeUnitVector(float3 Normal)
|
|
{
|
|
const int BITS = PATH_TRACING_PAYLOAD_NORMAL_BITS;
|
|
const float Scale = float((1u << (BITS / 2)) - 2) / 2; // largest representable even number (so we can encode 0)
|
|
float2 OctF = UnitVectorToOctahedron(Normal);
|
|
int2 Oct = int2(round(OctF * Scale + Scale));
|
|
return Oct.x + (1u << (BITS / 2)) * Oct.y;
|
|
}
|
|
|
|
float3 PayloadDecodeUnitVector(uint Encoded)
|
|
{
|
|
const int BITS = PATH_TRACING_PAYLOAD_NORMAL_BITS;
|
|
const uint Mask = (1u << (BITS / 2)) - 1;
|
|
const float Scale = float((1u << (BITS / 2)) - 2);
|
|
|
|
int2 Oct = int2(Encoded & Mask, (Encoded >> (BITS / 2)) & Mask);
|
|
float2 OctF = saturate(float2(Oct) / Scale);
|
|
return OctahedronToUnitVector(2 * OctF - 1);
|
|
}
|
|
|
|
uint PayloadEncodeHDRColor(float3 rgb)
|
|
{
|
|
// clamp to the largest representable value
|
|
rgb = clamp(rgb, 0.0, Max111110BitsFloat3);
|
|
return PackR11G11B10F(rgb);
|
|
}
|
|
|
|
float3 PayloadDecodeHDRColor(uint rgb)
|
|
{
|
|
return UnpackR11G11B10F(rgb);
|
|
}
|
|
|
|
uint PayloadEncodeLDRColor(float3 rgb)
|
|
{
|
|
// NOTE: Could add a simple gamma2 here to improve precision of dark colors, but this does not seem necessary for now.
|
|
// unorm 11/11/10 encoding
|
|
uint r = uint(floor(saturate(rgb.r) * 2047.0 + 0.5));
|
|
uint g = uint(floor(saturate(rgb.g) * 2047.0 + 0.5));
|
|
uint b = uint(floor(saturate(rgb.b) * 1023.0 + 0.5));
|
|
return (r << 21) | (g << 10) | b;
|
|
}
|
|
|
|
float3 PayloadDecodeLDRColor(uint rgb)
|
|
{
|
|
float r = float((rgb >> 21) ) * (1.0 / 2047.0);
|
|
float g = float((rgb >> 10) & 2047) * (1.0 / 2047.0);
|
|
float b = float((rgb ) & 1023) * (1.0 / 1023.0);
|
|
return float3(r, g, b);
|
|
}
|
|
|
|
uint PayloadEncodeRoughnessAniso(float3 RoughnessData, float Anisotropy)
|
|
{
|
|
uint r = uint(floor(saturate(RoughnessData.x) * 255.0 + 0.5));
|
|
uint g = uint(floor(saturate(RoughnessData.y) * 255.0 + 0.5));
|
|
uint b = uint(floor(saturate(RoughnessData.z) * 255.0 + 0.5));
|
|
uint a = uint(floor(clamp(Anisotropy, -1.0, 1.0) * 127.0 + 127.0)); // Range is [-1,1] so use an SNorm encoding here so we can represent 0.0 exactly
|
|
return (r << 24) | (g << 16) | (b << 8) | a;
|
|
}
|
|
|
|
float4 PayloadDecodeRoughnessAniso(uint rgba)
|
|
{
|
|
float r = float((rgba >> 24) ) * (1.0 / 255.0);
|
|
float g = float((rgba >> 16) & 255) * (1.0 / 255.0);
|
|
float b = float((rgba >> 8) & 255) * (1.0 / 255.0);
|
|
float a = float((rgba ) & 255) * (1.0 / 127.0) - 1.0;
|
|
return float4(r, g, b, a);
|
|
}
|
|
|
|
float3 AdjustShadingNormal(float3 ShadingNormal, float3 GeoNormal, float3 RayDirection)
|
|
{
|
|
// Clip shading normal in a view dependent way such that the reflection stays above the geometric normal
|
|
// This introduces a bit of view-dependency to the shading normal but fixes dark artifacts around grazing angles
|
|
|
|
float3 D = RayDirection;
|
|
float3 R = reflect(D, ShadingNormal);
|
|
|
|
// https://iquilezles.org/www/articles/dontflip/dontflip.htm
|
|
float k = dot(R, GeoNormal);
|
|
if (k < 0.0)
|
|
{
|
|
return normalize(normalize(R - k * GeoNormal) - D);
|
|
}
|
|
return ShadingNormal;
|
|
}
|
|
|
|
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_PATH_TRACING_MATERIAL) && IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
#error "Path tracing and GPULightmass payloads are mutually exclusive. They should not be both enabled at once."
|
|
#endif
|
|
|
|
#if SUBSTRATE_ENABLED && !IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
#define PATHTRACING_SUBSTRATE_PAYLOAD 1
|
|
#else
|
|
#define PATHTRACING_SUBSTRATE_PAYLOAD 0
|
|
#endif
|
|
|
|
// This payload structure is what we transport between RGS/CHS/AHS programs
|
|
struct FPackedPathTracingPayload : FMinimalPayload
|
|
{
|
|
// float FMinimalPayload::HitT // 4 bytes
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
uint PackedData[7]; // 28 bytes (encoded data, depends on shading model and ray type)
|
|
// 32 bytes total
|
|
#elif PATHTRACING_SUBSTRATE_PAYLOAD
|
|
// Need a bit more space for Substrate slab data
|
|
uint PackedData[18]; // 72 bytes
|
|
// 76 bytes total
|
|
#else
|
|
uint PackedData[15]; // 60 bytes (encoded data, depends on shading model and ray type)
|
|
// 64 bytes total
|
|
#endif
|
|
|
|
float UnpackBSDFOpacity() { return f16tof32(PackedData[0]); }
|
|
uint GetShadingModelID() { return (PackedData[0] >> 16) & 0xF; }
|
|
uint GetFlags() { return (PackedData[0] >> 20) & 0x1FF; }
|
|
void SetFlag(uint Flag) { PackedData[0] |= Flag << 20; }
|
|
void RemoveFlag(uint Flag) { PackedData[0] &= ~(Flag << 20); }
|
|
uint GetPrimitiveLightingChannelMask() { return (PackedData[0] >> 29) & 0x7; }
|
|
|
|
// Flag methods
|
|
void SetCameraRay() { SetFlag(PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_CAMERA); }
|
|
bool IsCameraRay() { return (GetFlags() & PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_MASK) == PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_CAMERA; }
|
|
|
|
void SetVisibilityRay() { SetFlag(PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_SHADOW); }
|
|
bool IsVisibilityRay() { return (GetFlags() & PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_MASK) == PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_SHADOW; }
|
|
|
|
bool IsFrontFace() { return (GetFlags() & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_FRONT_FACE) != 0; }
|
|
|
|
bool IsDecalReceiver()
|
|
{
|
|
const uint Mask =
|
|
PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_COLOR |
|
|
PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_NORMAL |
|
|
PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_ROUGHNESS |
|
|
PATH_TRACING_PAYLOAD_OUTPUT_FLAG_USE_DBUFFER_LOOKUP;
|
|
return (GetFlags() & Mask) != 0;
|
|
}
|
|
bool HasDecalResponseColor() { return (GetFlags() & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_COLOR ) != 0; }
|
|
bool HasDecalResponseNormal() { return (GetFlags() & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_NORMAL ) != 0; }
|
|
bool HasDecalResponseRoughness() { return (GetFlags() & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_ROUGHNESS) != 0; }
|
|
bool UsesDBufferLookup() { return (GetFlags() & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_USE_DBUFFER_LOOKUP ) != 0; }
|
|
|
|
void SetOutputDepth() { SetFlag(PATH_TRACING_PAYLOAD_OUTPUT_FLAG_OUTOUT_DEPTH); }
|
|
bool ShouldOutputDepth() { return (GetFlags() & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_OUTOUT_DEPTH) != 0; }
|
|
|
|
bool IsHoldout() { return (GetFlags() & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_IS_HOLDOUT) != 0; }
|
|
|
|
// These method are meant to be used only when IsVisibilityRay() is true
|
|
float3 GetRayThroughput()
|
|
{
|
|
return float3(
|
|
asfloat(PackedData[1]),
|
|
asfloat(PackedData[2]),
|
|
asfloat(PackedData[3])
|
|
);
|
|
}
|
|
|
|
void SetRayThroughput(float3 RayThroughput)
|
|
{
|
|
PackedData[1] = asuint(RayThroughput.x);
|
|
PackedData[2] = asuint(RayThroughput.y);
|
|
PackedData[3] = asuint(RayThroughput.z);
|
|
}
|
|
|
|
float GetPathRoughness()
|
|
{
|
|
return asfloat(PackedData[4]);
|
|
}
|
|
|
|
void SetPathRoughness(float PathRoughness)
|
|
{
|
|
PackedData[4] = asuint(PathRoughness);
|
|
}
|
|
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
float3 UnpackWorldGeoNormal() { return PayloadDecodeUnitVector(PackedData[1]); }
|
|
float3 UnpackWorldNormal() { return PayloadDecodeUnitVector(PackedData[2]); }
|
|
float3 UnpackRadiance() { return PayloadDecodeHDRColor(PackedData[3]); }
|
|
float3 UnpackBaseColor() { return PayloadDecodeLDRColor(PackedData[4]); }
|
|
float3 UnpackTransparencyColor() { return PayloadDecodeLDRColor(PackedData[5]); }
|
|
float3 UnpackSubsurfaceColor() { return PayloadDecodeLDRColor(PackedData[6]); }
|
|
|
|
|
|
#else
|
|
|
|
float3 UnpackWorldGeoNormal() { return PayloadDecodeUnitVector(PackedData[1]); }
|
|
float3 UnpackWorldSmoothNormal() { return PayloadDecodeUnitVector(PackedData[2]); }
|
|
float3 UnpackWorldNormal() { return PayloadDecodeUnitVector(PackedData[3]); }
|
|
float3 UnpackRadiance() { return PayloadDecodeHDRColor(PackedData[4]); }
|
|
|
|
void PackWorldNormal(float3 N) { PackedData[3] = PayloadEncodeUnitVector(N); }
|
|
void PackRadiance(float3 R) { PackedData[4] = PayloadEncodeHDRColor(R); }
|
|
|
|
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
|
|
float3 UnpackDiffuseColor() { return PayloadDecodeLDRColor(PackedData[5]); }
|
|
float3 UnpackSpecularColor() { return PayloadDecodeLDRColor(PackedData[6]); }
|
|
float3 UnpackSpecularEdgeColor() { return PayloadDecodeLDRColor(PackedData[7]); }
|
|
float4 UnpackRoughnessAniso() { return PayloadDecodeRoughnessAniso(PackedData[8]); }
|
|
float3 UnpackWorldTangent() { return PayloadDecodeUnitVector(PackedData[9]); }
|
|
float3 UnpackTransparencyColor() { return PayloadDecodeLDRColor(PackedData[10]); }
|
|
float3 UnpackMeanFreePath() { return float3(f16tof32(PackedData[11]),
|
|
f16tof32(PackedData[11] >> 16),
|
|
f16tof32(PackedData[12])); }
|
|
float UnpackPhaseG() { return f16tof32(PackedData[12] >> 16); }
|
|
float3 UnpackFuzzColor() { return PayloadDecodeLDRColor(PackedData[13]); }
|
|
float3 UnpackFuzzData() { return PayloadDecodeLDRColor(PackedData[14]); } // x: UNUSED, y: FuzzAmount, z: FuzzRoughness
|
|
float3 UnpackWeightV() { return PayloadDecodeLDRColor(PackedData[15]); }
|
|
float3 UnpackTransmittanceN() { return PayloadDecodeLDRColor(PackedData[16]); }
|
|
float UnpackIor() { return Unpack10F(PackedData[17]); }
|
|
float UnpackCoverageAboveAlongN() { return Unpack10F(PackedData[17] >> 10); }
|
|
float UnpackSpecularProfileId() { return Unpack10F(PackedData[17] >> 20); }
|
|
|
|
void PackDiffuseColor(float3 C) { PackedData[5] = PayloadEncodeLDRColor(C); }
|
|
void PackSpecularColor(float3 C) { PackedData[6] = PayloadEncodeLDRColor(C); }
|
|
void PackRoughnessAniso(float4 D) { PackedData[8] = PayloadEncodeRoughnessAniso(D.xyz, D.w); }
|
|
|
|
#else
|
|
float3 UnpackBaseColor() { return PayloadDecodeLDRColor(PackedData[5]); }
|
|
float3 UnpackTransparencyColor() { return PayloadDecodeLDRColor(PackedData[6]); }
|
|
float UnpackMetallic() { return f16tof32(PackedData[7]); }
|
|
float UnpackSpecular() { return f16tof32(PackedData[7] >> 16); }
|
|
float UnpackRoughness() { return f16tof32(PackedData[8]); }
|
|
float UnpackAnisotropy() { return f16tof32(PackedData[8] >> 16); }
|
|
float3 UnpackWorldTangent() { return PayloadDecodeUnitVector(PackedData[9]); }
|
|
float4 UnpackCustomData0() { return float4(f16tof32(PackedData[10]),
|
|
f16tof32(PackedData[10] >> 16),
|
|
f16tof32(PackedData[11]),
|
|
f16tof32(PackedData[11] >> 16)); }
|
|
float4 UnpackCustomData1() { return float4(f16tof32(PackedData[12]),
|
|
f16tof32(PackedData[12] >> 16),
|
|
f16tof32(PackedData[13]),
|
|
f16tof32(PackedData[13] >> 16)); }
|
|
float UnpackIor() { return f16tof32(PackedData[14]); }
|
|
|
|
|
|
void PackBaseColor(float3 C) { PackedData[5] = PayloadEncodeLDRColor(C); }
|
|
void PackMetallicSpecular(float M, float S) { PackedData[7] = f32tof16(M) | (f32tof16(S) << 16); }
|
|
void PackRoughnessAniso(float R, float A) { PackedData[8] = f32tof16(R) | (f32tof16(A) << 16); }
|
|
|
|
#endif
|
|
|
|
// tau: optical depth along shadow ray, this is the integral of the extinction coefficient
|
|
float3 GetTau()
|
|
{
|
|
return float3(
|
|
asfloat(PackedData[5]),
|
|
asfloat(PackedData[6]),
|
|
asfloat(PackedData[7])
|
|
);
|
|
}
|
|
|
|
void SetTau(float3 Tau)
|
|
{
|
|
PackedData[5] = asuint(Tau.x);
|
|
PackedData[6] = asuint(Tau.y);
|
|
PackedData[7] = asuint(Tau.z);
|
|
}
|
|
|
|
float4 GetDBufferA()
|
|
{
|
|
return float4(
|
|
f16tof32(PackedData[8]),
|
|
f16tof32(PackedData[8] >> 16),
|
|
f16tof32(PackedData[9]),
|
|
f16tof32(PackedData[9] >> 16)
|
|
);
|
|
}
|
|
|
|
void SetDBufferA(float4 DBufferA)
|
|
{
|
|
PackedData[8] = f32tof16(DBufferA.x);
|
|
PackedData[8] |= f32tof16(DBufferA.y) << 16;
|
|
PackedData[9] = f32tof16(DBufferA.z);
|
|
PackedData[9] |= f32tof16(DBufferA.w) << 16;
|
|
}
|
|
|
|
float4 GetDBufferB()
|
|
{
|
|
return float4(
|
|
f16tof32(PackedData[10]),
|
|
f16tof32(PackedData[10] >> 16),
|
|
f16tof32(PackedData[11]),
|
|
f16tof32(PackedData[11] >> 16)
|
|
);
|
|
}
|
|
|
|
void SetDBufferB(float4 DBufferB)
|
|
{
|
|
PackedData[10] = f32tof16(DBufferB.x);
|
|
PackedData[10] |= f32tof16(DBufferB.y) << 16;
|
|
PackedData[11] = f32tof16(DBufferB.z);
|
|
PackedData[11] |= f32tof16(DBufferB.w) << 16;
|
|
}
|
|
|
|
float4 GetDBufferC()
|
|
{
|
|
return float4(
|
|
f16tof32(PackedData[12]),
|
|
f16tof32(PackedData[12] >> 16),
|
|
f16tof32(PackedData[13]),
|
|
f16tof32(PackedData[13] >> 16)
|
|
);
|
|
}
|
|
|
|
void SetDBufferC(float4 DBufferC)
|
|
{
|
|
PackedData[12] = f32tof16(DBufferC.x);
|
|
PackedData[12] |= f32tof16(DBufferC.y) << 16;
|
|
PackedData[13] = f32tof16(DBufferC.z);
|
|
PackedData[13] |= f32tof16(DBufferC.w) << 16;
|
|
}
|
|
|
|
void SetStochasticSlabRand(float SlabRand)
|
|
{
|
|
PackedData[14] = asuint(SlabRand);
|
|
}
|
|
|
|
float GetStochasticSlabRand()
|
|
{
|
|
return asfloat(PackedData[14]);
|
|
}
|
|
|
|
#endif // IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
};
|
|
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_PATH_TRACING_MATERIAL)
|
|
CHECK_RT_PAYLOAD_SIZE(FPackedPathTracingPayload)
|
|
#endif
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
CHECK_RT_PAYLOAD_SIZE(FPackedPathTracingPayload)
|
|
#endif
|
|
|
|
// This payload structure is the expanded version of the above which is more convenient to work with
|
|
struct FPathTracingPayload : FMinimalPayload
|
|
{
|
|
float3 Radiance;
|
|
float3 WorldGeoNormal; // normal of the actual triangle (faceted)
|
|
float3 WorldNormal; // normal output of the material (includes normal/bump)
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
// skip smooth normal for GPULightmass
|
|
#else
|
|
float3 WorldSmoothNormal; // smooth normal before normal/bump is applied
|
|
#endif
|
|
|
|
float BSDFOpacity; // how much should we weigh down the bsdf by? (for glass, controls the blend between solid and glass lobes)
|
|
float3 TransparencyColor; // how much do we see straight through the surface?
|
|
uint ShadingModelID;
|
|
uint Flags;
|
|
uint PrimitiveLightingChannelMask;
|
|
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
float3 DiffuseColor;
|
|
float3 SpecularColor;
|
|
float3 SpecularEdgeColor;
|
|
float3 RoughnessData; // r0,r1,rblend
|
|
float Anisotropy;
|
|
float3 WorldTangent;
|
|
float3 MeanFreePath;
|
|
float PhaseG;
|
|
float Ior;
|
|
float FuzzAmount;
|
|
float FuzzRoughness;
|
|
float3 FuzzColor;
|
|
float3 WeightV;
|
|
float3 TransmittanceN;
|
|
float CoverageAboveAlongN;
|
|
float SpecularProfileId;
|
|
float GlintValue;
|
|
float2 GlintUV;
|
|
float2 GlintUVdx;
|
|
float2 GlintUVdy;
|
|
|
|
// not transported through packed payload, but used in raygen
|
|
float3 SubsurfaceColor;
|
|
|
|
#else // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
|
|
float3 BaseColor;
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
float3 SubsurfaceColor;
|
|
#else
|
|
float3 DiffuseColor;
|
|
float3 SpecularColor;
|
|
float Metallic;
|
|
float Specular;
|
|
float Roughness;
|
|
float Anisotropy;
|
|
float Ior;
|
|
float4 CustomData0;
|
|
float4 CustomData1;
|
|
float3 WorldTangent;
|
|
float3 SubsurfaceColor;
|
|
float3 SubsurfaceRadius;
|
|
#endif // IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
#endif // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
float3 TranslatedWorldPos;
|
|
|
|
void SetFrontFace() { Flags |= PATH_TRACING_PAYLOAD_OUTPUT_FLAG_FRONT_FACE; }
|
|
bool IsFrontFace() { return (Flags & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_FRONT_FACE) != 0; }
|
|
|
|
void SetDecalReceiver(uint DecalResponseMask) { Flags |= (DecalResponseMask & 0x07) << PATH_TRACING_PAYLOAD_OUTPUT_FLAG_DECAL_RESPONSE_MASK_SHIFT; }
|
|
|
|
void SetUseDBufferLookup() { Flags |= PATH_TRACING_PAYLOAD_OUTPUT_FLAG_USE_DBUFFER_LOOKUP; }
|
|
bool UsesDBufferLookup() { return (Flags & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_USE_DBUFFER_LOOKUP) != 0; }
|
|
|
|
void SetHoldout() { Flags |= PATH_TRACING_PAYLOAD_OUTPUT_FLAG_IS_HOLDOUT; }
|
|
bool IsHoldout() { return (Flags & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_IS_HOLDOUT) != 0; }
|
|
|
|
void SetMaterialTwoSided() { Flags |= PATH_TRACING_PAYLOAD_OUTPUT_FLAG_TWO_SIDED_MATERIAL; }
|
|
bool IsMaterialTwoSided() { return (Flags & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_TWO_SIDED_MATERIAL) != 0; }
|
|
|
|
void SetOutputDepth() { Flags |= PATH_TRACING_PAYLOAD_OUTPUT_FLAG_OUTOUT_DEPTH; }
|
|
bool ShouldOutputDepth() { return Flags & PATH_TRACING_PAYLOAD_OUTPUT_FLAG_OUTOUT_DEPTH; }
|
|
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
float3 GetBaseColor() { return BaseColor; }
|
|
float3 GetSubsurfaceColor() { return SubsurfaceColor; }
|
|
bool IsMaterialTransmissive()
|
|
{
|
|
return ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE;
|
|
}
|
|
#else // IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
// SHADINGMODELID_SUBSTRATE
|
|
float3 GetMaxLobeWeight()
|
|
{
|
|
return WeightV * lerp(1.0f, TransmittanceN, CoverageAboveAlongN); // largest value LobeWeight() could return
|
|
}
|
|
|
|
|
|
// SHADINGMODELID_NUM (Lambert diffuse) and SHADINGMODELID_MEDIUM
|
|
float3 GetBaseColor() { return DiffuseColor; }
|
|
void SetBaseColor(float3 BaseColor) { DiffuseColor = BaseColor; }
|
|
|
|
// SHADINGMODELID_MEDIUM
|
|
float3 GetHGWeight() { return SpecularColor; }
|
|
float GetHGPhaseG() { return PhaseG; }
|
|
void SetHG(float3 Weight, float G)
|
|
{
|
|
SpecularColor = Weight;
|
|
PhaseG = G;
|
|
}
|
|
|
|
// SHADINGMODELID_EYE
|
|
float GetEyeRoughness() { return RoughnessData.x; }
|
|
void SetEyeRoughness(float R) { RoughnessData.x = R; }
|
|
float3 GetEyeCausticNormal() { return 2.0 * FuzzColor - 1.0; } // SUBSTRATE_TODO: not optimal since packed as color
|
|
void SetEyeCausticNormal(float3 CausticNormal) { FuzzColor = 0.5 * CausticNormal + 0.5; }
|
|
float GetEyeIrisMask() { return Anisotropy; }
|
|
void SetEyeIrisMask(float IrisMask) { Anisotropy = IrisMask; }
|
|
float3 GetEyeIrisNormal() { return WorldTangent; }
|
|
void SetEyeIrisNormal(float3 IrisNormal) { WorldTangent = IrisNormal; }
|
|
|
|
// SHADINGMODELID_HAIR
|
|
float GetHairLongitudinalRoughness() { return RoughnessData.x; }
|
|
void SetHairLongitudinalRoughness(float Roughness) { RoughnessData.x = Roughness;}
|
|
float GetHairAzimuthalRoughness() { return RoughnessData.y; }
|
|
void SetHairAzimuthalRoughness(float AzimuthalRoughness) { RoughnessData.y = AzimuthalRoughness; }
|
|
float GetHairSpecular() { return RoughnessData.z; }
|
|
void SetHairSpecular(float Specular) { RoughnessData.z = Specular; }
|
|
float2 GetHairPrimitiveUV() { return SpecularEdgeColor.xy; }
|
|
void SetHairPrimitiveUV(float2 UV) { SpecularEdgeColor.xy = UV; }
|
|
|
|
float3 GetExtinction() { return rcp(max(MeanFreePath, 0.0001)); }
|
|
|
|
// SHADINGMODELID_THIN_TRANSLUCENT
|
|
float3 GetTransmittanceColor() { return exp(-GetExtinction() * SUBSTRATE_SIMPLEVOLUME_THICKNESS_CM); }
|
|
|
|
|
|
#else // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
// Various ways to interpret CustomData (depending on ShadingModelID)
|
|
// NOTE: This is not always following the same conventions as GetMaterialCustomData0,1()
|
|
|
|
// SHADINGMODELID_CLOTH
|
|
float3 GetClothColor() { return CustomData0.xyz; }
|
|
void SetClothColor(float3 ClothColor) { CustomData0.xyz = ClothColor; }
|
|
float GetClothAmount() { return CustomData0.w; }
|
|
void SetClothAmount(float ClothAmount) { CustomData0.w = ClothAmount; }
|
|
|
|
// SHADINGMODELID_CLEAR_COAT
|
|
float GetClearCoat() { return CustomData0.x; }
|
|
float GetClearCoatRoughness() { return CustomData0.y; }
|
|
void SetClearCoat(float ClearCoat) { CustomData0.x = ClearCoat; }
|
|
void SetClearCoatRoughness(float ClearCoatRoughness) { CustomData0.y = ClearCoatRoughness; }
|
|
float3 GetClearCoatBottomNormal() { return CustomData1.xyz; }
|
|
void SetClearCoatBottomNormal(float3 BottomNormal) { CustomData1.xyz = BottomNormal; }
|
|
|
|
// SHADINGMODELID_SUBSURFACE, SHADINGMODELID_SUBSURFACE_PROFILE and SHADINGMODELID_EYE
|
|
float3 GetSubsurfaceRadius() { return CustomData0.rgb; }
|
|
void SetSubsurfaceRadius(float3 Radius) { CustomData0.rgb = Radius; }
|
|
float GetSubsurfacePhaseFunction() { return CustomData0.a; }
|
|
void SetSubsurfacePhaseFunction(float G) { CustomData0.a = G; }
|
|
|
|
// SHADINGMODELID_SUBSURFACE, SHADINGMODELID_TWO_SIDED_FOLIAGE (note that SHADINGMODELID_SUBSURFACE_PROFILE and SHADINGMODELID_EYE don't use this as they use DiffuseColor directly)
|
|
float3 GetSubsurfaceColor() { return CustomData1.xyz; }
|
|
void SetSubsurfaceColor(float3 SubsurfaceColor) { CustomData1.xyz = SubsurfaceColor; }
|
|
|
|
// SHADINGMODELID_SUBSURFACE_PROFILE
|
|
float3 GetDualRoughnessSpecular() { return CustomData1.xyz; }
|
|
void SetDualRoughnessSpecular(float Roughness0, float Roughness1, float LobeMix) { CustomData1.xyz = float3(Roughness0, Roughness1, LobeMix); }
|
|
|
|
|
|
// SHADINGMODELID_EYE
|
|
float GetEyeRoughness() { return Roughness; }
|
|
void SetEyeRoughness(float R) { Roughness = R; }
|
|
float3 GetEyeCausticNormal() { return CustomData1.xyz; }
|
|
void SetEyeCausticNormal(float3 CausticNormal) { CustomData1.xyz = CausticNormal; }
|
|
float GetEyeIrisMask() { return Anisotropy; }
|
|
void SetEyeIrisMask(float IrisMask) { Anisotropy = IrisMask; }
|
|
float3 GetEyeIrisNormal() { return WorldTangent; }
|
|
void SetEyeIrisNormal(float3 IrisNormal) { WorldTangent = IrisNormal; }
|
|
|
|
// SHADINGMODELID_HAIR
|
|
float GetHairLongitudinalRoughness() { return Roughness; }
|
|
void SetHairLongitudinalRoughness(float R) { Roughness = R; }
|
|
float GetHairAzimuthalRoughness() { return Metallic; }
|
|
void SetHairAzimuthalRoughness(float AzimuthalRoughness) { Metallic = AzimuthalRoughness; }
|
|
float GetHairSpecular() { return Specular; }
|
|
void SetHairSpecular(float S) { Specular = S; }
|
|
float2 GetHairPrimitiveUV() { return CustomData0.xy; }
|
|
void SetHairPrimitiveUV(float2 UV) { CustomData0.xy = UV; }
|
|
|
|
// SHADINGMODELID_THIN_TRANSLUCENT
|
|
float3 GetTransmittanceColor() { return CustomData0.xyz; }
|
|
void SetTransmittanceColor(float3 TransmittanceColor) { CustomData0.xyz = TransmittanceColor; }
|
|
|
|
// SHADINGMODELID_DEFAULT_LIT
|
|
float3 GetExtinction() { return CustomData0.xyz; }
|
|
void SetExtinction(float3 SigmaT) { CustomData0.xyz = SigmaT; }
|
|
|
|
// SHADINGMODELID_NUM (Lambert diffuse) and SHADINGMODELID_MEDIUM
|
|
float3 GetBaseColor() { return BaseColor; }
|
|
void SetBaseColor(float3 C)
|
|
{
|
|
BaseColor = C;
|
|
}
|
|
|
|
// SHADINGMODELID_MEDIUM
|
|
float3 GetHGWeight() { return CustomData0.xyz; }
|
|
float GetHGPhaseG() { return CustomData0.w; }
|
|
void SetHG(float3 Weight, float G) { CustomData0 = float4(Weight, G); }
|
|
#endif // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
|
|
// Methods used by the integrator
|
|
|
|
bool HasRefraction()
|
|
{
|
|
return Ior > 0.0;
|
|
}
|
|
|
|
bool IsMaterialSolidGlass()
|
|
{
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
return ShadingModelID == SHADINGMODELID_SUBSTRATE && HasRefraction();
|
|
#else
|
|
return ShadingModelID == SHADINGMODELID_SOLID_GLASS;
|
|
#endif
|
|
}
|
|
|
|
bool IsMaterialThinGlass()
|
|
{
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
return ShadingModelID == SHADINGMODELID_THIN_TRANSLUCENT && HasRefraction();
|
|
#else
|
|
return ShadingModelID == SHADINGMODELID_THIN_TRANSLUCENT && HasRefraction();
|
|
#endif
|
|
}
|
|
|
|
bool IsMaterialTransmissive()
|
|
{
|
|
return ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE ||
|
|
ShadingModelID == SHADINGMODELID_HAIR ||
|
|
ShadingModelID == SHADINGMODELID_MEDIUM ||
|
|
IsMaterialSolidGlass() ||
|
|
IsMaterialThinGlass();
|
|
}
|
|
|
|
bool IsSubsurfaceMaterial()
|
|
{
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
return ShadingModelID == SHADINGMODELID_SUBSTRATE ||
|
|
ShadingModelID == SHADINGMODELID_EYE;
|
|
#else
|
|
return ShadingModelID == SHADINGMODELID_SUBSURFACE ||
|
|
ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN ||
|
|
ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE ||
|
|
ShadingModelID == SHADINGMODELID_EYE;
|
|
#endif
|
|
|
|
}
|
|
#endif // IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
};
|
|
|
|
FPackedPathTracingPayload InitPathTracingPayload(uint ScatterType, float PathRoughness)
|
|
{
|
|
FPackedPathTracingPayload Output = (FPackedPathTracingPayload)0;
|
|
Output.SetPathRoughness(PathRoughness);
|
|
Output.SetMiss();
|
|
switch (ScatterType)
|
|
{
|
|
case PATHTRACER_SCATTER_DIFFUSE: Output.SetFlag(PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_INDIRECT_DIFFUSE); break;
|
|
case PATHTRACER_SCATTER_SPECULAR:
|
|
case PATHTRACER_SCATTER_REFRACT: Output.SetFlag(PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_INDIRECT_SPECULAR); break;
|
|
case PATHTRACER_SCATTER_VOLUME: Output.SetFlag(PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_INDIRECT_VOLUME); break;
|
|
case PATHTRACER_SCATTER_CAMERA:
|
|
default: Output.SetFlag(PATH_TRACING_PAYLOAD_INPUT_FLAG_RAY_TYPE_CAMERA); break;
|
|
}
|
|
return Output;
|
|
}
|
|
|
|
FPackedPathTracingPayload InitPathTracingVisibilityPayload(float PathRoughness)
|
|
{
|
|
FPackedPathTracingPayload Output = (FPackedPathTracingPayload)0;
|
|
// Signal to the AHS we want to evaluate the opacity
|
|
// The payload is used to carry the path throughput (for transparent shadows)
|
|
// and current path roughness (for approximate caustics)
|
|
Output.SetVisibilityRay();
|
|
Output.SetPathRoughness(PathRoughness);
|
|
Output.SetRayThroughput(1.0);
|
|
// NOTE: We start with HitT = 0 which counts as "IsHit()". This will be changed by the miss shader if we don't register any hits (or the AHS writes don't accumulate all the way to 0)
|
|
// This is because we want to be able to skip the CHS on shadow rays. Therefore the miss shader is the one that will be responsible for telling us a ray did not hit anything opaque.
|
|
// If after tracing the ray we still have IsHit() returning true, this means we must have hit something opaque (without having run either CHS or AHS).
|
|
// This also has the benefit of preparing the "mailbox" used for detecting duplicate invocations of AHS with an invalid value.
|
|
Output.HitT = 0.0;
|
|
return Output;
|
|
}
|
|
|
|
FPackedPathTracingPayload PackPathTracingPayload(FPathTracingPayload Input)
|
|
{
|
|
FPackedPathTracingPayload Output = (FPackedPathTracingPayload)0;
|
|
Output.HitT = Input.HitT;
|
|
|
|
Output.PackedData[0] = f32tof16(Input.BSDFOpacity);
|
|
Output.PackedData[0] |= (Input.ShadingModelID & 0xF) << 16; // 4 bits
|
|
Output.PackedData[0] |= (Input.Flags & 0x1FF) << 20; // 9 bits
|
|
Output.PackedData[0] |= (Input.PrimitiveLightingChannelMask & 0x7) << 29; // 3 bits
|
|
// total 32 bits
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
Output.PackedData[1] = PayloadEncodeUnitVector(Input.WorldGeoNormal);
|
|
Output.PackedData[2] = PayloadEncodeUnitVector(Input.WorldNormal);
|
|
Output.PackedData[3] = PayloadEncodeHDRColor(Input.Radiance);
|
|
Output.PackedData[4] = PayloadEncodeLDRColor(Input.BaseColor);
|
|
Output.PackedData[5] = PayloadEncodeLDRColor(Input.TransparencyColor);
|
|
Output.PackedData[6] = PayloadEncodeLDRColor(Input.SubsurfaceColor);
|
|
#else
|
|
Output.PackedData[1] = PayloadEncodeUnitVector(Input.WorldGeoNormal);
|
|
Output.PackedData[2] = PayloadEncodeUnitVector(Input.WorldSmoothNormal);
|
|
Output.PackedData[3] = PayloadEncodeUnitVector(Input.WorldNormal);
|
|
Output.PackedData[4] = PayloadEncodeHDRColor(Input.Radiance);
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
Output.PackedData[5] = PayloadEncodeLDRColor(Input.DiffuseColor);
|
|
Output.PackedData[6] = PayloadEncodeLDRColor(Input.SpecularColor);
|
|
Output.PackedData[7] = PayloadEncodeLDRColor(Input.SpecularEdgeColor);
|
|
Output.PackedData[8] = PayloadEncodeRoughnessAniso(Input.RoughnessData, Input.Anisotropy);
|
|
Output.PackedData[9] = PayloadEncodeUnitVector(Input.WorldTangent);
|
|
Output.PackedData[10] = PayloadEncodeLDRColor(Input.TransparencyColor);
|
|
Output.PackedData[11] = f32tof16(Input.MeanFreePath.x);
|
|
Output.PackedData[11]|= f32tof16(Input.MeanFreePath.y) << 16;
|
|
Output.PackedData[12] = f32tof16(Input.MeanFreePath.z);
|
|
Output.PackedData[12]|= f32tof16(Input.PhaseG) << 16;
|
|
Output.PackedData[13] = PayloadEncodeLDRColor(Input.FuzzColor);
|
|
Output.PackedData[14] = PayloadEncodeLDRColor(float3(0, Input.FuzzAmount, Input.FuzzRoughness));
|
|
Output.PackedData[15] = PayloadEncodeLDRColor(Input.WeightV);
|
|
Output.PackedData[16] = PayloadEncodeLDRColor(Input.TransmittanceN);
|
|
Output.PackedData[17] = Pack10F(Input.Ior);
|
|
Output.PackedData[17]|= Pack10F(Input.CoverageAboveAlongN) << 10;
|
|
Output.PackedData[17]|= Pack10F(Input.SpecularProfileId) << 20;
|
|
Output.PackedData[17]|= (Input.GlintValue > 0 ? 1u : 0u) << 30; // Bit flag for glint.
|
|
|
|
// In order to not increase the data payload size, we alias SSS/Fuzz parameters when glint are enabled
|
|
if (Input.GlintValue > 0)
|
|
{
|
|
const uint2 PackedGlintsData = PackGlints(Input.GlintValue, Input.GlintUV);
|
|
Output.PackedData[11] = PackedGlintsData.x;
|
|
Output.PackedData[12] = PackedGlintsData.y;
|
|
Output.PackedData[13] = PackFloat2ToUInt(Input.GlintUVdx);
|
|
Output.PackedData[14] = PackFloat2ToUInt(Input.GlintUVdx);
|
|
}
|
|
|
|
#else // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
|
|
|
|
|
|
Output.PackedData[5] = PayloadEncodeLDRColor(Input.BaseColor);
|
|
Output.PackedData[6] = PayloadEncodeLDRColor(Input.TransparencyColor);
|
|
|
|
Output.PackedData[7] = f32tof16(Input.Metallic);
|
|
Output.PackedData[7] |= f32tof16(Input.Specular) << 16;
|
|
Output.PackedData[8] = f32tof16(Input.Roughness);
|
|
Output.PackedData[8] |= f32tof16(Input.Anisotropy) << 16;
|
|
|
|
Output.PackedData[9] = PayloadEncodeUnitVector(Input.WorldTangent);
|
|
|
|
Output.PackedData[10] = f32tof16(Input.CustomData0.x);
|
|
Output.PackedData[10] |= f32tof16(Input.CustomData0.y) << 16;
|
|
Output.PackedData[11] = f32tof16(Input.CustomData0.z);
|
|
Output.PackedData[11] |= f32tof16(Input.CustomData0.w) << 16;
|
|
|
|
Output.PackedData[12] = f32tof16(Input.CustomData1.x);
|
|
Output.PackedData[12] |= f32tof16(Input.CustomData1.y) << 16;
|
|
Output.PackedData[13] = f32tof16(Input.CustomData1.z);
|
|
Output.PackedData[13] |= f32tof16(Input.CustomData1.w) << 16;
|
|
|
|
Output.PackedData[14] = f32tof16(Input.Ior);
|
|
// NOTE: 16 bits left in PackedData[14]
|
|
#endif // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
#endif // IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
return Output;
|
|
}
|
|
|
|
FPathTracingPayload UnpackPathTracingPayload(FPackedPathTracingPayload Input, FRayDesc Ray)
|
|
{
|
|
FPathTracingPayload Output = (FPathTracingPayload)0;
|
|
|
|
Output.HitT = Input.HitT;
|
|
Output.TranslatedWorldPos = Ray.Origin + Output.HitT * Ray.Direction;
|
|
|
|
Output.BSDFOpacity = Input.UnpackBSDFOpacity();
|
|
Output.ShadingModelID = Input.GetShadingModelID();
|
|
Output.Flags = Input.GetFlags();
|
|
Output.PrimitiveLightingChannelMask = Input.GetPrimitiveLightingChannelMask();
|
|
#if IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
Output.WorldGeoNormal = Input.UnpackWorldGeoNormal();
|
|
Output.WorldNormal = Input.UnpackWorldNormal();
|
|
Output.Radiance = Input.UnpackRadiance();
|
|
Output.BaseColor = Input.UnpackBaseColor();
|
|
Output.TransparencyColor = Input.UnpackTransparencyColor();
|
|
Output.SubsurfaceColor = Input.UnpackSubsurfaceColor();
|
|
#else
|
|
Output.WorldGeoNormal = Input.UnpackWorldGeoNormal();
|
|
Output.WorldSmoothNormal = Input.UnpackWorldSmoothNormal();
|
|
Output.WorldNormal = Input.UnpackWorldNormal();
|
|
Output.Radiance = Input.UnpackRadiance();
|
|
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
Output.DiffuseColor = Input.UnpackDiffuseColor();
|
|
Output.SpecularColor = Input.UnpackSpecularColor();
|
|
Output.SpecularEdgeColor = Input.UnpackSpecularEdgeColor();
|
|
float4 RoughnessAniso = Input.UnpackRoughnessAniso();
|
|
Output.RoughnessData = RoughnessAniso.xyz;
|
|
Output.Anisotropy = RoughnessAniso.w;
|
|
Output.WorldTangent = Input.UnpackWorldTangent();
|
|
Output.TransparencyColor = Input.UnpackTransparencyColor();
|
|
Output.MeanFreePath = Input.UnpackMeanFreePath();
|
|
Output.PhaseG = Input.UnpackPhaseG();
|
|
Output.FuzzColor = Input.UnpackFuzzColor();
|
|
const float3 Data14 = Input.UnpackFuzzData();
|
|
Output.FuzzAmount = Data14.y;
|
|
Output.FuzzRoughness = Data14.z;
|
|
Output.WeightV = Input.UnpackWeightV();
|
|
Output.TransmittanceN = Input.UnpackTransmittanceN();
|
|
Output.Ior = Input.UnpackIor();
|
|
Output.CoverageAboveAlongN = Input.UnpackCoverageAboveAlongN();
|
|
Output.SpecularProfileId = Input.UnpackSpecularProfileId();
|
|
|
|
// TODO: figure out how to make glint unpacking closer to functions above
|
|
// In order to not increase the data payload size, we alias SSS/Fuzz parameters when glint are enabled
|
|
const bool bHasGlints = ((Input.PackedData[17] >> 30u) & 0x1u) > 0u;
|
|
if (bHasGlints)
|
|
{
|
|
Output.MeanFreePath.x = 0.f;
|
|
Output.MeanFreePath.y = 0.f;
|
|
Output.MeanFreePath.z = 0.f;
|
|
Output.PhaseG = 0.f;
|
|
Output.FuzzColor = 0.f;
|
|
Output.FuzzAmount = 0.f;
|
|
Output.FuzzRoughness = 0.f;
|
|
|
|
UnpackGlints(uint2(Input.PackedData[11], Input.PackedData[12]), Output.GlintValue, Output.GlintUV);
|
|
Output.GlintUVdx = UnpackFloat2FromUInt(Input.PackedData[13]);
|
|
Output.GlintUVdy = UnpackFloat2FromUInt(Input.PackedData[14]);
|
|
}
|
|
|
|
#else // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
Output.BaseColor = Input.UnpackBaseColor();
|
|
Output.TransparencyColor = Input.UnpackTransparencyColor();
|
|
Output.Metallic = Input.UnpackMetallic();
|
|
Output.Specular = Input.UnpackSpecular();
|
|
Output.Roughness = Input.UnpackRoughness();
|
|
Output.Anisotropy = Input.UnpackAnisotropy();
|
|
Output.WorldTangent = Input.UnpackWorldTangent();
|
|
Output.CustomData0 = Input.UnpackCustomData0();
|
|
Output.CustomData1 = Input.UnpackCustomData1();
|
|
Output.Ior = Input.UnpackIor();
|
|
|
|
//
|
|
Output.DiffuseColor = Output.BaseColor - Output.BaseColor * Output.Metallic;
|
|
Output.SpecularColor = ComputeF0(Output.Specular, Output.BaseColor, Output.Metallic);
|
|
#endif // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
#endif // IS_PAYLOAD_ENABLED(RT_PAYLOAD_TYPE_GPULIGHTMASS)
|
|
return Output;
|
|
}
|