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

#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