浏览代码

[PlanarReflection] (wip) refactoring of projection environments

/main
Frédéric Vauchelles 7 年前
当前提交
1279bb4e
共有 4 个文件被更改,包括 109 次插入95 次删除
  1. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Lighting.hlsl
  2. 95
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/VolumeProjection.hlsl
  3. 104
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl
  4. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Material.hlsl

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Lighting.hlsl


#ifndef UNITY_LIGHTING_INCLUDED
#ifndef UNITY_LIGHTING_INCLUDED
#define UNITY_LIGHTING_INCLUDED
#include "CoreRP/ShaderLibrary/CommonLighting.hlsl"

#include "LightLoop/Shadow.hlsl"
#if defined(LIGHTLOOP_SINGLE_PASS) || defined(LIGHTLOOP_TILE_PASS)
#include "../Lighting/VolumeProjection.hlsl"
#include "../Lighting/LightLoop/LightLoopDef.hlsl"
#endif

95
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/VolumeProjection.hlsl


#ifndef UNITY_VOLUMEPROJECTION_INCLUDED
#define UNITY_VOLUMEPROJECTION_INCLUDED
float3x3 EnvProjData_GetWorldToLocal(EnvProjData projData)
#define ENVMAP_FEATURE_PERFACEINFLUENCE
#define ENVMAP_FEATURE_PERFACEFADE
#define ENVMAP_FEATURE_INFLUENCENORMAL
float3x3 WorldToProjectionSpace(EnvProjData projData)
float3x3 EnvProjData_WorldToLocalPosition(EnvProjData projData, float3x3 worldToLS, float3 positionWS)
float3 WorldToProjectionPosition(EnvProjData projData, float3x3 worldToLS, float3 positionWS)
{
float3 positionLS = positionWS - projData.positionWS;
positionLS = mul(positionLS, worldToLS).xyz;

float EnvProjData_Sphere_Project(EnvProjData projData, float3 dirPS, float3 positionPS)
float IntersectSphereProxy(EnvProjData projData, float3 dirPS, float3 positionPS)
{
float sphereOuterDistance = projData.extents.x;
float projectionDistance = SphereRayIntersectSimple(positionPS, dirPS, sphereOuterDistance);

}
float3x3 EnvLightData_GetWorldToLocal(EnvLightData lightData)
float IntersectBoxProxy(EnvProjData projData, float3 dirPS, float3 positionPS)
{
float3 boxOuterDistance = projData.extents;
float projectionDistance = BoxRayIntersectSimple(positionPS, dirPS, -boxOuterDistance, boxOuterDistance);
projectionDistance = max(projectionDistance, projData.minProjectionDistance); // Setup projection to infinite if requested (mean no projection shape)
return projectionDistance;
}
float InfluenceSphereWeight(EnvLightData lightData, BSDFData bsdfData, float3 positionWS, float3 positionLS, float3 dirLS)
{
float lengthPositionLS = length(positionLS);
float sphereInfluenceDistance = lightData.influenceExtents.x - lightData.blendDistancePositive.x;
float distFade = max(lengthPositionLS - sphereInfluenceDistance, 0.0);
float alpha = saturate(1.0 - distFade / max(lightData.blendDistancePositive.x, 0.0001)); // avoid divide by zero
#if defined(ENVMAP_FEATURE_INFLUENCENORMAL)
float insideInfluenceNormalVolume = lengthPositionLS <= (lightData.influenceExtents.x - lightData.blendNormalDistancePositive.x) ? 1.0 : 0.0;
float insideWeight = InfluenceFadeNormalWeight(bsdfData.normalWS, normalize(positionWS - lightData.positionWS));
alpha *= insideInfluenceNormalVolume ? 1.0 : insideWeight;
#endif
return alpha;
}
float InfluenceBoxWeight(EnvLightData lightData, BSDFData bsdfData, float3 positionWS, float3 positionLS, float3 dirLS)
{
float3 boxOuterDistance = lightData.influenceExtents;
// 2. Process the position influence
// Calculate falloff value, so reflections on the edges of the volume would gradually blend to previous reflection.
#if defined(ENVMAP_FEATURE_PERFACEINFLUENCE) || defined(ENVMAP_FEATURE_INFLUENCENORMAL) || defined(ENVMAP_FEATURE_PERFACEFADE)
// Distance to each cube face
float3 negativeDistance = boxOuterDistance + positionLS;
float3 positiveDistance = boxOuterDistance - positionLS;
#endif
#if defined(ENVMAP_FEATURE_PERFACEINFLUENCE)
// Influence falloff for each face
float3 negativeFalloff = negativeDistance / max(0.0001, lightData.blendDistanceNegative);
float3 positiveFalloff = positiveDistance / max(0.0001, lightData.blendDistancePositive);
// Fallof is the min for all faces
float influenceFalloff = min(
min(min(negativeFalloff.x, negativeFalloff.y), negativeFalloff.z),
min(min(positiveFalloff.x, positiveFalloff.y), positiveFalloff.z));
float alpha = saturate(influenceFalloff);
#else
float distFace = DistancePointBox(positionLS, -lightData.influenceExtents + lightData.blendDistancePositive.x, lightData.influenceExtents - lightData.blendDistancePositive.x);
float alpha = saturate(1.0 - distFace / max(lightData.blendDistancePositive.x, 0.0001));
#endif
#if defined(ENVMAP_FEATURE_INFLUENCENORMAL)
// 3. Process the normal influence
// Calculate a falloff value to discard normals pointing outward the center of the environment light
float3 belowPositiveInfluenceNormalVolume = positiveDistance / max(0.0001, lightData.blendNormalDistancePositive);
float3 aboveNegativeInfluenceNormalVolume = negativeDistance / max(0.0001, lightData.blendNormalDistanceNegative);
float insideInfluenceNormalVolume = all(belowPositiveInfluenceNormalVolume >= 1.0) && all(aboveNegativeInfluenceNormalVolume >= 1.0) ? 1.0 : 0;
float insideWeight = InfluenceFadeNormalWeight(bsdfData.normalWS, normalize(positionWS - lightData.positionWS));
alpha *= insideInfluenceNormalVolume ? 1.0 : insideWeight;
#endif
#if defined(ENVMAP_FEATURE_PERFACEFADE)
// 4. Fade specific cubemap faces
// For each axes (both positive and negative ones), we want to fade from the center of one face to another
// So we normalized the sample direction (R) and use its component to fade for each axis
// We consider R.x as cos(X) and then fade as angle from 60°(=acos(1/2)) to 75°(=acos(1/4))
// For positive axes: axisFade = (R - 1/4) / (1/2 - 1/4)
// <=> axisFace = 4 * R - 1;
float3 faceFade = saturate((4 * dirLS - 1) * lightData.boxSideFadePositive) + saturate((-4 * dirLS - 1) * lightData.boxSideFadeNegative);
alpha *= saturate(faceFade.x + faceFade.y + faceFade.z);
#endif
return alpha;
}
float3x3 WorldToLightSpace(EnvLightData lightData)
// CAUTION: localToWorld is the transform use to convert the cubemap capture point to world space (mean it include the offset)
// the center of the bounding box is thus in locals space: positionLS - offsetLS
// We use this formulation as it is the one of legacy unity that was using only AABB box.
float3 EnvLightData_WorldToLocalPosition(EnvLightData lightData, float3x3 worldToLS, float3 positionWS)
float3 WorldToLightPosition(EnvLightData lightData, float3x3 worldToLS, float3 positionWS)
{
// CAUTION: localToWorld is the transform use to convert the cubemap capture point to world space (mean it include the offset)
// the center of the bounding box is thus in locals space: positionLS - offsetLS

104
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


#define ENVMAP_FEATURE_PERFACEINFLUENCE
#define ENVMAP_FEATURE_INFLUENCENORMAL
#define ENVMAP_FEATURE_PERFACEFADE
// SurfaceData is define in Lit.cs which generate Lit.cs.hlsl
// SurfaceData is define in Lit.cs which generate Lit.cs.hlsl
#include "../../Lighting/VolumeProjection.hlsl"
#include "../SubsurfaceScattering/SubsurfaceScattering.hlsl"
//-----------------------------------------------------------------------------

// In Unity the cubemaps are capture with the localToWorld transform of the component.
// This mean that location and orientation matter. So after intersection of proxy volume we need to convert back to world.
// CAUTION: localToWorld is the transform use to convert the cubemap capture point to world space (mean it include the offset)
// the center of the bounding box is thus in locals space: positionLS - offsetLS
// We use this formulation as it is the one of legacy unity that was using only AABB box.
float3x3 worldToLocal = transpose(float3x3(lightData.right, lightData.up, lightData.forward)); // worldToLocal assume no scaling
float3 positionLS = positionWS - lightData.positionWS;
positionLS = mul(positionLS, worldToLocal).xyz - lightData.offsetLS; // We want to calculate the intersection from the center of the bounding box.
float3x3 worldToLS = WorldToLightSpace(lightData);
float3 positionLS = WorldToLightPosition(lightData, worldToLS, positionWS);
float3x3 worldToLS = EnvLightData_GetWorldToLocal(lightData);
float3 positionLS = EnvLightData_WorldToLocalPosition(lightData, worldToLS, positionWS);
// Projection and influence share the shape
// Projection and influence share the space
float3x3 worldToPS = worldToLS;
float3 positionPS = positionLS;

// 1. First process the projection
float3 dirPS = mul(R, worldToPS);
float projectionDistance = EnvProjData_Sphere_Project(projData, dirPS, positionPS);
float projectionDistance = IntersectSphereProxy(projData, dirPS, positionPS);
// We can reuse dist calculate in LS directly in WS as there is no scaling. Also the offset is already include in lightData.positionWS
R = (positionWS + projectionDistance * R) - lightData.positionWS;

dirPS = mul(coatR, worldToPS);
projectionDistance = EnvProjData_Sphere_Project(projData, dirPS, positionPS);
projectionDistance = IntersectSphereProxy(projData, dirPS, positionPS);
// 2. Process the position influence
float lengthPositionLS = length(positionLS);
float sphereInfluenceDistance = lightData.influenceExtents.x - lightData.blendDistancePositive.x;
float distFade = max(lengthPositionLS - sphereInfluenceDistance, 0.0);
float alpha = saturate(1.0 - distFade / max(lightData.blendDistancePositive.x, 0.0001)); // avoid divide by zero
#if defined(ENVMAP_FEATURE_INFLUENCENORMAL)
// 3. Process the normal influence
float insideInfluenceNormalVolume = lengthPositionLS <= (lightData.influenceExtents.x - lightData.blendNormalDistancePositive.x) ? 1.0 : 0.0;
float insideWeight = InfluenceFadeNormalWeight(bsdfData.normalWS, normalize(positionWS - lightData.positionWS));
alpha *= insideInfluenceNormalVolume ? 1.0 : insideWeight;
#endif
weight = alpha;
// 2. Process the influence
float3 dirLS = dirPS; // Projection and influence share the space
weight = InfluenceSphereWeight(lightData, bsdfData, positionWS, positionLS, dirLS);
float3 dirLS = mul(R, worldToLocal);
float3 boxOuterDistance = lightData.influenceExtents;
float projectionDistance = BoxRayIntersectSimple(positionLS, dirLS, -boxOuterDistance, boxOuterDistance);
projectionDistance = max(projectionDistance, lightData.minProjectionDistance); // Setup projection to infinite if requested (mean no projection shape)
float3 dirPS = mul(R, worldToPS);
float projectionDistance = IntersectBoxProxy(projData, dirPS, positionPS);
// No need to normalize for fetching cubemap
// We can reuse dist calculate in LS directly in WS as there is no scaling. Also the offset is already include in lightData.positionWS
R = (positionWS + projectionDistance * R) - lightData.positionWS;

// Test again for clear code
if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT && HasMaterialFeatureFlag(MATERIALFEATUREFLAGS_LIT_CLEAR_COAT))
{
dirLS = mul(coatR, worldToLocal);
projectionDistance = BoxRayIntersectSimple(positionLS, dirLS, -boxOuterDistance, boxOuterDistance);
projectionDistance = max(projectionDistance, lightData.minProjectionDistance); // Setup projection to infinite if requested (mean no projection shape)
dirPS = mul(coatR, worldToPS);
projectionDistance = IntersectBoxProxy(projData, dirPS, positionPS);
// 2. Process the position influence
// Calculate falloff value, so reflections on the edges of the volume would gradually blend to previous reflection.
#if defined(ENVMAP_FEATURE_PERFACEINFLUENCE) || defined(ENVMAP_FEATURE_INFLUENCENORMAL) || defined(ENVMAP_FEATURE_PERFACEFADE)
// Distance to each cube face
float3 negativeDistance = boxOuterDistance + positionLS;
float3 positiveDistance = boxOuterDistance - positionLS;
#endif
#if defined(ENVMAP_FEATURE_PERFACEINFLUENCE)
// Influence falloff for each face
float3 negativeFalloff = negativeDistance / max(0.0001, lightData.blendDistanceNegative);
float3 positiveFalloff = positiveDistance / max(0.0001, lightData.blendDistancePositive);
// Fallof is the min for all faces
float influenceFalloff = min(
min(min(negativeFalloff.x, negativeFalloff.y), negativeFalloff.z),
min(min(positiveFalloff.x, positiveFalloff.y), positiveFalloff.z));
float alpha = saturate(influenceFalloff);
#else
float distFace = DistancePointBox(positionLS, -lightData.influenceExtents + lightData.blendDistancePositive.x, lightData.influenceExtents - lightData.blendDistancePositive.x);
float alpha = saturate(1.0 - distFace / max(lightData.blendDistancePositive.x, 0.0001));
#endif
#if defined(ENVMAP_FEATURE_INFLUENCENORMAL)
// 3. Process the normal influence
// Calculate a falloff value to discard normals pointing outward the center of the environment light
float3 belowPositiveInfluenceNormalVolume = positiveDistance / max(0.0001, lightData.blendNormalDistancePositive);
float3 aboveNegativeInfluenceNormalVolume = negativeDistance / max(0.0001, lightData.blendNormalDistanceNegative);
float insideInfluenceNormalVolume = all(belowPositiveInfluenceNormalVolume >= 1.0) && all(aboveNegativeInfluenceNormalVolume >= 1.0) ? 1.0 : 0;
float insideWeight = InfluenceFadeNormalWeight(bsdfData.normalWS, normalize(positionWS - lightData.positionWS));
alpha *= insideInfluenceNormalVolume ? 1.0 : insideWeight;
#endif
#if defined(ENVMAP_FEATURE_PERFACEFADE)
// 4. Fade specific cubemap faces
// For each axes (both positive and negative ones), we want to fade from the center of one face to another
// So we normalized the sample direction (R) and use its component to fade for each axis
// We consider R.x as cos(X) and then fade as angle from 60°(=acos(1/2)) to 75°(=acos(1/4))
// For positive axes: axisFade = (R - 1/4) / (1/2 - 1/4)
// <=> axisFace = 4 * R - 1;
R = normalize(R);
float3 faceFade = saturate((4 * R - 1) * lightData.boxSideFadePositive) + saturate((-4 * R - 1) * lightData.boxSideFadeNegative);
alpha *= saturate(faceFade.x + faceFade.y + faceFade.z);
#endif
weight = alpha;
// 2. Process the influence
float3 dirLS = dirPS; // Projection and influence share the space
weight = InfluenceBoxWeight(lightData, bsdfData, positionWS, positionLS, dirLS);
}
// Smooth weighting

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Material.hlsl


#ifndef UNITY_MATERIAL_INCLUDED
#ifndef UNITY_MATERIAL_INCLUDED
#define UNITY_MATERIAL_INCLUDED
#include "CoreRP/ShaderLibrary/Color.hlsl"

正在加载...
取消
保存