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.
238 lines
8.4 KiB
238 lines
8.4 KiB
#ifndef UNITY_PATH_TRACING_INTEGRATOR_INCLUDED
|
|
#define UNITY_PATH_TRACING_INTEGRATOR_INCLUDED
|
|
|
|
#define ENABLE_MATERIAL_AMBIENT_OCCLUSION
|
|
|
|
// Ray tracing includes
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingFragInputs.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Common/AtmosphericScatteringRayTracing.hlsl"
|
|
|
|
// Path tracing includes
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingPayload.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingSkySampling.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingAOV.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingSurface.hlsl"
|
|
#ifdef HAS_LIGHTLOOP
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingLight.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingVolume.hlsl"
|
|
#endif
|
|
|
|
float3 GetSkyValue(PathPayload payload, float3 direction)
|
|
{
|
|
if (payload.segmentID == 0 && all(direction == WorldRayDirection()))
|
|
{
|
|
// If we can, access our high resolution screen-space background
|
|
return GetSkyBackground(payload.pixelCoord).rgb;
|
|
}
|
|
|
|
// Otherwise query the lower resolution cubemap
|
|
return GetSkyValue(direction);
|
|
}
|
|
|
|
// Generic function that handles one scattering event (a vertex along the full path), can be either:
|
|
// - Surface scattering
|
|
// - Volume scattering
|
|
[shader("closesthit")]
|
|
void ClosestHit(inout PathPayload payload : SV_RayPayload, AttributeData attributeData : SV_IntersectionAttributes)
|
|
{
|
|
// Always set the new t and initial alpha value
|
|
payload.rayTHit = RayTCurrent();
|
|
payload.alpha = 1.0;
|
|
|
|
bool minDepthAllowsEmissive = payload.segmentID >= _RaytracingMinRecursion - 1;
|
|
bool sampleVolume = false;
|
|
|
|
float4 inputSample = 0.0;
|
|
float volSurfPdf = 1.0;
|
|
|
|
SurfaceInfo surfaceInfo = (SurfaceInfo)0;
|
|
|
|
#ifdef HAS_LIGHTLOOP
|
|
|
|
float3 lightPosition;
|
|
bool sampleLocalLights;
|
|
|
|
// Generate a 4D unit-square sample for this depth, from our QMC sequence
|
|
inputSample = GetSample4D(payload.pixelCoord, _RaytracingSampleIndex, 4 * payload.segmentID);
|
|
|
|
// For the time being, we test for volumetric scattering only on camera rays
|
|
float scatteringT = payload.rayTHit;
|
|
if (!payload.segmentID && minDepthAllowsEmissive)
|
|
sampleVolume = SampleVolumeScatteringPosition(payload.pixelCoord, inputSample.w, scatteringT, volSurfPdf, sampleLocalLights, lightPosition);
|
|
|
|
// If we need to sample volume we won't do the scattering part in the function but we might still need it to evaluate
|
|
// the AOV values if we write the volumetric scattering values separately in another AOV.
|
|
const bool alwaysWriteAOV = NeedAOVData(payload);
|
|
if (!sampleVolume || alwaysWriteAOV)
|
|
{
|
|
GetSurfaceInfo(payload, attributeData, surfaceInfo);
|
|
PushSurfaceAOVData(surfaceInfo, payload);
|
|
}
|
|
|
|
if (sampleVolume)
|
|
{
|
|
payload.rayTHit = scatteringT;
|
|
ComputeVolumeScattering(payload, inputSample.xyz, sampleLocalLights, lightPosition);
|
|
|
|
// Override AOV motion vector information unless we always need to output the value
|
|
if (!alwaysWriteAOV)
|
|
payload.aovMotionVector = 0.0;
|
|
}
|
|
else
|
|
{
|
|
ComputeSurfaceScattering(payload, surfaceInfo, inputSample);
|
|
}
|
|
|
|
minDepthAllowsEmissive &= !sampleVolume;
|
|
|
|
// If we don't always write AOV data, depending if we have evaluated a surface or volume scattering event,
|
|
// we need to normalize with the PDF of going through one of these two events. If we always write AOV data
|
|
// then probability is 1 anyway.
|
|
if (!alwaysWriteAOV)
|
|
{
|
|
payload.aovAlbedo /= volSurfPdf;
|
|
payload.aovNormal /= volSurfPdf;
|
|
payload.aovMotionVector /= volSurfPdf;
|
|
}
|
|
|
|
#else // HAS_LIGHTLOOP
|
|
|
|
GetSurfaceInfo(payload, attributeData, surfaceInfo);
|
|
PushSurfaceAOVData(surfaceInfo, payload);
|
|
ComputeSurfaceScattering(payload, surfaceInfo, inputSample);
|
|
|
|
#endif // HAS_LIGHTLOOP
|
|
|
|
// Apply volumetric attenuation (beware of passing the right distance to the shading point)
|
|
ApplyFogAttenuation(WorldRayOrigin(), WorldRayDirection(), payload.rayTHit, payload.value, payload.lightSampleShadowColor, payload.alpha,
|
|
payload.lightSampleShadowOpacityAndShadowTint.y, payload.throughput, payload.segmentThroughput, payload.lightSampleValue, minDepthAllowsEmissive);
|
|
|
|
// Apply the volume/surface PDF
|
|
payload.value /= volSurfPdf;
|
|
payload.alpha /= volSurfPdf;
|
|
payload.lightSampleShadowOpacityAndShadowTint.y /= volSurfPdf;
|
|
payload.throughput /= volSurfPdf;
|
|
payload.segmentThroughput /= volSurfPdf;
|
|
payload.lightSampleValue /= volSurfPdf;
|
|
}
|
|
|
|
|
|
[shader("anyhit")]
|
|
void AnyHit(inout PathPayload payload : SV_RayPayload, AttributeData attributeData : SV_IntersectionAttributes)
|
|
{
|
|
#ifdef _ALPHATEST_ON
|
|
|
|
// First grab the intersection vertex
|
|
IntersectionVertex currentVertex;
|
|
GetCurrentIntersectionVertex(attributeData, currentVertex);
|
|
|
|
// Build the Frag inputs from the intersection vertex
|
|
FragInputs fragInput;
|
|
BuildFragInputsFromIntersection(currentVertex, fragInput);
|
|
|
|
PositionInputs posInput;
|
|
posInput.positionWS = fragInput.positionRWS;
|
|
posInput.positionSS = payload.pixelCoord;
|
|
|
|
// Build the surfacedata and builtindata
|
|
SurfaceData surfaceData;
|
|
BuiltinData builtinData;
|
|
bool isVisible;
|
|
GetSurfaceAndBuiltinData(fragInput, -WorldRayDirection(), posInput, surfaceData, builtinData, currentVertex, payload.cone, isVisible);
|
|
|
|
// Check alpha clipping
|
|
if (!isVisible)
|
|
{
|
|
IgnoreHit();
|
|
return;
|
|
}
|
|
|
|
#endif // _ALPHATEST_ON
|
|
|
|
if (payload.segmentID == SEGMENT_ID_NEAREST_HIT )
|
|
{
|
|
// We just need the nearest hit distance here
|
|
payload.rayTHit = min(payload.rayTHit, RayTCurrent());
|
|
}
|
|
else if (payload.segmentID == SEGMENT_ID_RANDOM_WALK)
|
|
{
|
|
if (RayTCurrent() < payload.rayTHit)
|
|
{
|
|
|
|
#ifndef _ALPHATEST_ON
|
|
|
|
// First grab the intersection vertex
|
|
IntersectionVertex currentVertex;
|
|
GetCurrentIntersectionVertex(attributeData, currentVertex);
|
|
|
|
// Build the Frag inputs from the intersection vertex
|
|
FragInputs fragInput;
|
|
BuildFragInputsFromIntersection(currentVertex, fragInput);
|
|
|
|
#endif // _ALPHATEST_ON
|
|
|
|
payload.value = fragInput.tangentToWorld[2];
|
|
payload.rayTHit = RayTCurrent();
|
|
}
|
|
}
|
|
else if (payload.segmentID == SEGMENT_ID_TRANSMISSION)
|
|
{
|
|
#ifdef _SURFACE_TYPE_TRANSPARENT
|
|
|
|
#ifndef _ALPHATEST_ON
|
|
|
|
// First grab the intersection vertex
|
|
IntersectionVertex currentVertex;
|
|
GetCurrentIntersectionVertex(attributeData, currentVertex);
|
|
|
|
// Build the Frag inputs from the intersection vertex
|
|
FragInputs fragInput;
|
|
BuildFragInputsFromIntersection(currentVertex, fragInput);
|
|
|
|
PositionInputs posInput;
|
|
posInput.positionWS = fragInput.positionRWS;
|
|
posInput.positionSS = payload.pixelCoord;
|
|
|
|
// Build the surfacedata and builtindata
|
|
SurfaceData surfaceData;
|
|
BuiltinData builtinData;
|
|
bool isVisible;
|
|
GetSurfaceAndBuiltinData(fragInput, -WorldRayDirection(), posInput, surfaceData, builtinData, currentVertex, payload.cone, isVisible);
|
|
|
|
#endif // _ALPHATEST_ON
|
|
|
|
#if HAS_REFRACTION
|
|
payload.value *= surfaceData.transmittanceMask * surfaceData.transmittanceColor;
|
|
#else
|
|
payload.value *= 1.0 - builtinData.opacity;
|
|
#endif
|
|
if (Luminance(payload.value) > 0)
|
|
{
|
|
IgnoreHit();
|
|
}
|
|
|
|
#else // _SURFACE_TYPE_TRANSPARENT
|
|
|
|
payload.value = 0.0; // Opaque surface
|
|
|
|
#endif // _SURFACE_TYPE_TRANSPARENT
|
|
|
|
}
|
|
#ifdef _PATH_TRACED_DUAL_SCATTERING
|
|
else if (payload.segmentID == SEGMENT_ID_DUAL_SCATTERING)
|
|
{
|
|
// We have intersected one strand.
|
|
payload.alpha = payload.alpha + 1.0;
|
|
|
|
// And keep going until TMax.
|
|
IgnoreHit();
|
|
}
|
|
else if (payload.segmentID == SEGMENT_ID_DUAL_SCATTERING_VIS)
|
|
{
|
|
IgnoreHit();
|
|
return;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif // UNITY_PATH_TRACING_INTEGRATOR_INCLUDED
|