Skip to content

Commit

Permalink
Merge branch 'xbei/subsurface_scattering_nee' into 'main'
Browse files Browse the repository at this point in the history
[REMIX-2184] Implement direct light support for thin opaque

See merge request lightspeedrtx/dxvk-remix-nv!542
  • Loading branch information
xbei-nv committed Oct 24, 2023
2 parents eb10841 + 3fd44ff commit c54cfa2
Show file tree
Hide file tree
Showing 30 changed files with 334 additions and 138 deletions.
4 changes: 4 additions & 0 deletions src/dxvk/rtx_render/rtx_restir_gi_rayquery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ namespace dxvk {
TEXTURE2D(RESTIR_GI_REUSE_BINDING_HIT_GEOMETRY_INPUT)
TEXTURE2D(RESTIR_GI_REUSE_BINDING_POSITION_ERROR_INPUT)
TEXTURE2D(RESTIR_GI_REUSE_BINDING_SHARED_FLAGS_INPUT)
TEXTURE2D(RESTIR_GI_REUSE_BINDING_SHARED_SURFACE_INDEX_INPUT)
RW_TEXTURE2D(RESTIR_GI_REUSE_BINDING_LAST_GBUFFER)
END_PARAMETER()
};
Expand Down Expand Up @@ -107,6 +108,7 @@ namespace dxvk {
TEXTURE2D(RESTIR_GI_REUSE_BINDING_HIT_GEOMETRY_INPUT)
TEXTURE2D(RESTIR_GI_REUSE_BINDING_POSITION_ERROR_INPUT)
TEXTURE2D(RESTIR_GI_REUSE_BINDING_SHARED_FLAGS_INPUT)
TEXTURE2D(RESTIR_GI_REUSE_BINDING_SHARED_SURFACE_INDEX_INPUT)
RW_TEXTURE2D(RESTIR_GI_REUSE_BINDING_LAST_GBUFFER)
END_PARAMETER()
};
Expand Down Expand Up @@ -218,6 +220,7 @@ namespace dxvk {
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_RADIANCE_INPUT, rtOutput.m_restirGIRadiance.view(Resources::AccessType::Read), nullptr);
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_HIT_GEOMETRY_INPUT, rtOutput.m_restirGIHitGeometry.view, nullptr);
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_POSITION_ERROR_INPUT, rtOutput.m_primaryPositionError.view, nullptr);
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_SHARED_SURFACE_INDEX_INPUT, rtOutput.m_sharedSurfaceIndex.view, nullptr);
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_SHARED_FLAGS_INPUT, rtOutput.m_sharedFlags.view, nullptr);

ctx->bindShader(VK_SHADER_STAGE_COMPUTE_BIT, ReSTIRGITemporalReuseShader::getShader());
Expand All @@ -242,6 +245,7 @@ namespace dxvk {
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_RADIANCE_INPUT, rtOutput.m_restirGIRadiance.view(Resources::AccessType::Read), nullptr);
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_HIT_GEOMETRY_INPUT, rtOutput.m_restirGIHitGeometry.view, nullptr);
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_POSITION_ERROR_INPUT, rtOutput.m_primaryPositionError.view, nullptr);
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_SHARED_SURFACE_INDEX_INPUT, rtOutput.m_sharedSurfaceIndex.view, nullptr);
ctx->bindResourceView(RESTIR_GI_REUSE_BINDING_SHARED_FLAGS_INPUT, rtOutput.m_sharedFlags.view, nullptr);

ctx->bindShader(VK_SHADER_STAGE_COMPUTE_BIT, ReSTIRGISpatialReuseShader::getShader());
Expand Down
4 changes: 4 additions & 0 deletions src/dxvk/rtx_render/rtx_rtxdi_rayquery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ namespace dxvk {
TEXTURE2D(RTXDI_REUSE_BINDING_WS_MVEC_INPUT_OUTPUT)
TEXTURE2D(RTXDI_REUSE_BINDING_SS_MVEC_INPUT)
TEXTURE2D(RTXDI_REUSE_BINDING_POSITION_ERROR_INPUT)
TEXTURE2D(RTXDI_REUSE_BINDING_SHARED_SURFACE_INDEX_INPUT)
TEXTURE2D(RTXDI_REUSE_BINDING_SHARED_FLAGS_INPUT)
RW_TEXTURE2D(RTXDI_REUSE_BINDING_LAST_GBUFFER)
RW_TEXTURE2D(RTXDI_REUSE_BINDING_REPROJECTION_CONFIDENCE_OUTPUT)
Expand Down Expand Up @@ -103,6 +104,7 @@ namespace dxvk {
TEXTURE2D(RTXDI_REUSE_BINDING_WS_MVEC_INPUT_OUTPUT)
TEXTURE2D(RTXDI_REUSE_BINDING_SS_MVEC_INPUT)
TEXTURE2D(RTXDI_REUSE_BINDING_POSITION_ERROR_INPUT)
TEXTURE2D(RTXDI_REUSE_BINDING_SHARED_SURFACE_INDEX_INPUT)
TEXTURE2D(RTXDI_REUSE_BINDING_SHARED_FLAGS_INPUT)
RW_TEXTURE2D(RTXDI_REUSE_BINDING_LAST_GBUFFER)
RW_TEXTURE2D(RTXDI_REUSE_BINDING_REPROJECTION_CONFIDENCE_OUTPUT)
Expand Down Expand Up @@ -253,6 +255,7 @@ namespace dxvk {
ctx->bindResourceView(RTXDI_REUSE_BINDING_POSITION_ERROR_INPUT, rtOutput.m_primaryPositionError.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_LAST_GBUFFER, rtOutput.m_gbufferLast.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_REPROJECTION_CONFIDENCE_OUTPUT, rtOutput.m_reprojectionConfidence.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_SHARED_SURFACE_INDEX_INPUT, rtOutput.m_sharedSurfaceIndex.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_SHARED_FLAGS_INPUT, rtOutput.m_sharedFlags.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_BSDF_FACTOR_OUTPUT, rtOutput.m_bsdfFactor.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_TEMPORAL_POSITION_OUTPUT, rtOutput.m_primaryRtxdiTemporalPosition.view, nullptr);
Expand Down Expand Up @@ -281,6 +284,7 @@ namespace dxvk {
ctx->bindResourceView(RTXDI_REUSE_BINDING_POSITION_ERROR_INPUT, rtOutput.m_primaryPositionError.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_LAST_GBUFFER, rtOutput.m_gbufferLast.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_REPROJECTION_CONFIDENCE_OUTPUT, rtOutput.m_reprojectionConfidence.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_SHARED_SURFACE_INDEX_INPUT, rtOutput.m_sharedSurfaceIndex.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_SHARED_FLAGS_INPUT, rtOutput.m_sharedFlags.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_BSDF_FACTOR_OUTPUT, rtOutput.m_bsdfFactor.view, nullptr);
ctx->bindResourceView(RTXDI_REUSE_BINDING_TEMPORAL_POSITION_OUTPUT, rtOutput.m_primaryRtxdiTemporalPosition.view, nullptr);
Expand Down
3 changes: 0 additions & 3 deletions src/dxvk/rtx_render/rtx_scene_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -894,9 +894,6 @@ namespace dxvk {
bool alphaIsThinFilmThickness = false;
float thinFilmThicknessConstant = 0.0f;
float displaceIn = 1.0f;
float thinOpaqueThickness = 0.0f;
float thinOpaqueAttenuationCoefficient = 0.0f;
uint8_t thinOpaqueSingleScatteringAlbedoScale = 0;

Vector3 subsurfaceTransmittanceColor(0.0f, 0.0f, 0.0f);
float subsurfaceMeasurementDistance = 0.0f;
Expand Down
17 changes: 12 additions & 5 deletions src/dxvk/shaders/rtx/algorithm/integrator.slangh
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ bool evalNEESecondary(
Ray viewRay,
MinimalRayInteraction minimalRayInteraction,
MinimalSurfaceInteraction minimalSurfaceInteraction,
OpaqueSurfaceMaterialInteraction opaqueSurfaceMaterialInteraction,
inout vec3 diffuseLight,
inout vec3 specularLight,
uint16_t surfaceIndex, float2 texcoords)
Expand All @@ -223,13 +224,17 @@ bool evalNEESecondary(
uint8_t rayMask = OBJECT_MASK_OPAQUE | (objectMask & OBJECT_MASK_ALL_DYNAMIC);
if (cb.enableIndirectTranslucentShadows) rayMask |= OBJECT_MASK_TRANSLUCENT;

// Load Subsurface Material
SubsurfaceMaterial subSurfaceMaterial;
const bool isSubSurface = subSurfaceMaterialReadHelper(opaqueSurfaceMaterialInteraction.subsurfaceMaterialIndex, subSurfaceMaterial);

VisibilityResult visibility = traceVisibilityRay(minimalSurfaceInteraction,
lightSample.position, false, rayMask,
lightSample.position, rayMask,
visibilityModeEnableTranslucentMaterials,
sampledTransportPortalIndex, portalSpace,
minimalRayInteraction.coneRadius, viewRay.spreadAngle, 0.98, isViewModelSurface, false,
surfaceIndex, texcoords);

surfaceIndex, texcoords,
isSubSurface, opaqueSurfaceMaterialInteraction.shadingNormal);

if (visibility.hasOpaqueHit)
{
Expand Down Expand Up @@ -259,7 +264,9 @@ void evaluateUnshadowedLight(
out vec3 diffuseLight,
out vec3 specularLight)
{
if (dot(inputDirection, opaqueSurfaceMaterialInteraction.shadingNormal) < 0.0)
if (dot(inputDirection, opaqueSurfaceMaterialInteraction.shadingNormal) < 0.0 &&
(!cb.thinOpaqueEnable ||
opaqueSurfaceMaterialInteraction.subsurfaceMaterialIndex == BINDING_INDEX_INVALID))
{
diffuseLight = specularLight = 0;
return;
Expand All @@ -268,6 +275,6 @@ void evaluateUnshadowedLight(
const SurfaceMaterialInteractionSplitWeight splitWeight = opaqueSurfaceMaterialInteractionCalcProjectedWeight(
opaqueSurfaceMaterialInteraction, minimalRayInteraction, inputDirection);

diffuseLight = lightSample.radiance * splitWeight.diffuseReflectionWeight;
diffuseLight = lightSample.radiance * (splitWeight.diffuseReflectionWeight + splitWeight.diffuseTransmissionWeight);
specularLight = lightSample.radiance * splitWeight.specularReflectionWeight;
}
34 changes: 24 additions & 10 deletions src/dxvk/shaders/rtx/algorithm/integrator_direct.slangh
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ void evalNEEPrimary(
PortalSpace2BitsType portalSpace,
uint8_t objectMask,
bool isViewModelSurface,
Ray viewRay,
MinimalRayInteraction minimalRayInteraction,
Ray viewRay,
MinimalRayInteraction minimalRayInteraction,
MinimalSurfaceInteraction minimalSurfaceInteraction,
OpaqueSurfaceMaterialInteraction opaqueSurfaceMaterialInteraction)
OpaqueSurfaceMaterialInteraction opaqueSurfaceMaterialInteraction
)
{
// Setup and trace the visibility ray

Expand All @@ -64,19 +65,27 @@ void evalNEEPrimary(
const bool enablePOM = cb.pomEnableDirectLighting && opaqueSurfaceMaterialInteractionHasHeightTexture(opaqueSurfaceMaterialInteraction);
const uint16_t primarySurfaceIndex = enablePOM ? uint16_t(SharedSurfaceIndex[pixelCoordinate]) : BINDING_INDEX_INVALID;

VisibilityResult visibility = traceVisibilityRay(minimalSurfaceInteraction,
lightSample.position, false, rayMask,
// Load Subsurface Material
SubsurfaceMaterial subSurfaceMaterial;
const bool isSubSurface = subSurfaceMaterialReadHelper(opaqueSurfaceMaterialInteraction.subsurfaceMaterialIndex, subSurfaceMaterial);

const VisibilityResult visibility = traceVisibilityRay(
minimalSurfaceInteraction,
lightSample.position, rayMask,
visibilityModeAccurateHitDistance | visibilityModeEnableTranslucentMaterials,
sampledTransportPortalIndex, portalSpace,
minimalRayInteraction.coneRadius, viewRay.spreadAngle, 1.0, isViewModelSurface, false,
primarySurfaceIndex, DisplacementTextureCoord[pixelCoordinate]);
primarySurfaceIndex, DisplacementTextureCoord[pixelCoordinate],
isSubSurface, opaqueSurfaceMaterialInteraction.shadingNormal);

hitDistance = visibility.hitDistance;
hasOpaqueHit = visibility.hasOpaqueHit;
illuminance = 0;

if (visibility.hasOpaqueHit)
{
return;
}

// Evaluate the material and accumulate throughput and hit distance

Expand All @@ -89,16 +98,21 @@ void evalNEEPrimary(

const f16vec3 diffuseLobeWeight = splitWeight.diffuseReflectionWeight;
const f16vec3 specularLobeWeight = splitWeight.specularReflectionWeight;
const f16vec3 diffuseTransmissionLobeWeight = splitWeight.diffuseTransmissionWeight;

// TODO: Handle Transmission Weight

// Accumulate Radiance

const vec3 commonLightThroughput = lightSampleThroughput * vec3(visibility.attenuation);
const vec3 diffuseLobeLightThroughput = vec3(diffuseLobeWeight) * commonLightThroughput;
const vec3 specularLobeLightThroughput = vec3(specularLobeWeight) * commonLightThroughput;
const vec3 diffuseTransmissionLobeLightThroughput = vec3(diffuseTransmissionLobeWeight) * commonLightThroughput;
const vec3 diffuseAttenuatedRadiance = lightSample.radiance * diffuseLobeLightThroughput;
const vec3 specularAttenuatedRadiance = lightSample.radiance * specularLobeLightThroughput;
const vec3 diffuseTransmissionAttenuatedRadiance = lightSample.radiance * diffuseTransmissionLobeLightThroughput;

diffuseLobeRadiance += throughput * diffuseAttenuatedRadiance;
diffuseLobeRadiance += throughput * (diffuseAttenuatedRadiance + diffuseTransmissionAttenuatedRadiance);
specularLobeRadiance += throughput * specularAttenuatedRadiance;

// Illuminance for RTXDI gradients: just light sample radiance and visibility over sampling PDF
Expand Down Expand Up @@ -330,12 +344,13 @@ void integrateDirectPath(
lightSample, inverseSelectionPdf, lightIdx);
}

// Evaluate NEE
SubsurfaceMaterial subSurfaceMaterial;
const bool sssEnable = subSurfaceMaterialReadHelper(opaqueSurfaceMaterialInteraction.subsurfaceMaterialIndex, subSurfaceMaterial);

// Evaluate NEE
if (rtxdiLightSampleValid || risLightSampleValid)
{
bool hasOpaqueHit = false;

evalNEEPrimary(
throughput, pixelCoordinate,
diffuseLobeRadiance, specularLobeRadiance, lightHitDistance, hasOpaqueHit, illuminance,
Expand Down Expand Up @@ -390,7 +405,6 @@ void integrateDirectPath(

directPathTextures.SecondaryCombinedDiffuseLobeRadianceHitDistance[pixelCoordinate] = secondaryCombinedDiffuseLobeRadianceHitDistance;
directPathTextures.SecondaryCombinedSpecularLobeRadianceHitDistance[pixelCoordinate] = secondaryCombinedSpecularLobeRadianceHitDistance;

directPathTextures.PrimaryRtxdiIlluminance[pixelCoordinate] = 0;
}

Expand Down
4 changes: 2 additions & 2 deletions src/dxvk/shaders/rtx/algorithm/integrator_indirect.slangh
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ void integratePathVertex(
// Todo: Ray Portal transport sampling in the future.
evalNEESecondary(
lightSample, invalidRayPortalIndex, pathState.portalSpace, pathState.rayMask,
isViewModel, ray, rayInteraction, surfaceInteraction,
isViewModel, ray, rayInteraction, surfaceInteraction, opaqueSurfaceMaterialInteraction,
diffuseLight, specularLight, surfaceIndex, surfaceInteraction.textureCoordinates);

// Create a NEE Cache task for lights with non-zero contributions.
Expand Down Expand Up @@ -728,7 +728,7 @@ void integratePathVertex(
minimalRayInteraction2.viewDirection = -incomingDirection;
vec3 L2 = normalize(spatialReservoir.position - surfaceInteraction.position);
SurfaceMaterialInteractionSplitWeight brdf2 = opaqueSurfaceMaterialInteractionCalcProjectedWeight(opaqueSurfaceMaterialInteraction, minimalRayInteraction2, L2);
indirectLight += spatialReservoir.radiance * brdf2.diffuseReflectionWeight * spatialReservoir.avgWeight;
indirectLight += spatialReservoir.radiance * (brdf2.diffuseReflectionWeight + brdf2.diffuseTransmissionWeight) * spatialReservoir.avgWeight;
if (opaqueSurfaceMaterialInteraction.isotropicRoughness > RAB_RESTIR_GI_MIN_ROUGHNESS)
{
indirectLight += spatialReservoir.radiance * brdf2.specularReflectionWeight * spatialReservoir.avgWeight;
Expand Down
12 changes: 9 additions & 3 deletions src/dxvk/shaders/rtx/algorithm/lighting.slangh
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ bool sampleLightRTXDI(
bool sampleLightBasicRIS(
inout RNG randomState,
MinimalSurfaceInteraction surfaceInteraction,
OpaqueSurfaceMaterialInteraction opaqueSurfaceMaterialInteraction,
inout LightSample lightSample, inout float inverseSelectionPdf)
{
if (cb.risTotalSampleCount == 0)
Expand All @@ -89,6 +90,10 @@ bool sampleLightBasicRIS(
float selectedLightTargetPdf = 0.0f;
float weightSum = 0.0f;

// Load Subsurface Material
SubsurfaceMaterial subSurfaceMaterial;
const bool isSubSurface = subSurfaceMaterialReadHelper(opaqueSurfaceMaterialInteraction.subsurfaceMaterialIndex, subSurfaceMaterial);

[unroll]
for (uint lightType = 0; lightType < lightTypeCount; ++lightType)
{
Expand Down Expand Up @@ -118,7 +123,7 @@ bool sampleLightBasicRIS(
// can effectively unroll the loop and remove the switch from decodedPolymorphicLightCalcWeight
DecodedPolymorphicLight decodedPolymorphicLight = decodePolymorphicLight(memoryPolymorphicLight);
decodedPolymorphicLight.polymorphicType = lightType;
const float targetPdf = decodedPolymorphicLightCalcWeight(decodedPolymorphicLight, surfaceInteraction);
const float targetPdf = decodedPolymorphicLightCalcWeight(decodedPolymorphicLight, surfaceInteraction, isSubSurface);

// Accumulate the light's weight

Expand Down Expand Up @@ -227,7 +232,8 @@ bool sampleLightAdvancedRIS(
const SurfaceMaterialInteractionSplitWeight splitWeight = opaqueSurfaceMaterialInteractionCalcApproxProjectedWeight(opaqueSurfaceMaterialInteraction, minimalRayInteraction, inputDirection);
// Note: Only divide by the light sample's PDF if it is non-zero (as it may be zero when sampling a light from a specific location is impossible).
const float lightThroughput = candidateSample.solidAnglePdf > 0.0f ? 1.0f / candidateSample.solidAnglePdf : 0.0f;
const float targetPdf = calcBt709Luminance(candidateSample.radiance * (splitWeight.diffuseReflectionWeight + splitWeight.specularReflectionWeight));
const float targetPdf = calcBt709Luminance(candidateSample.radiance * (
splitWeight.diffuseReflectionWeight + splitWeight.specularReflectionWeight + splitWeight.diffuseTransmissionWeight));

// Accumulate the light's weight
const float risWeight = targetPdf * rangeInvSourcePdf * lightThroughput;
Expand Down Expand Up @@ -304,7 +310,7 @@ bool sampleLightRIS(
switch(kSurfaceRISType)
{
case 0:
return sampleLightBasicRIS(randomState, surfaceInteraction, lightSample, inverseSelectionPdf);
return sampleLightBasicRIS(randomState, surfaceInteraction, opaqueSurfaceMaterialInteraction, lightSample, inverseSelectionPdf);
case 1:
return sampleLightAdvancedRIS(randomState, surfaceInteraction, opaqueSurfaceMaterialInteraction, viewDirection, lightSample, inverseSelectionPdf, lightIndex);
case 2:
Expand Down
1 change: 1 addition & 0 deletions src/dxvk/shaders/rtx/algorithm/nee_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ struct NEECell
float ndotm = saturate(dot(halfVector, normal));
float specularTerm = specularRatio * evalGGXNormalDistributionIsotropic(roughness, ndotm) * cb.neeCacheArgs.specularFactor * 0.25;

// TODO: SSS - Add transmission radiance
float radiance = candidate.getRadiance();
return radiance * (diffuseTerm + specularTerm) * ndoti;
}
Expand Down
Loading

0 comments on commit c54cfa2

Please sign in to comment.