浏览代码

Merge pull request #726 from Unity-Technologies/feature/ReflectionProbeEditor

[ReflectionProbeEditor] Proper culling setup for reflection probes
/feature-ReflectionProbeFit
GitHub 7 年前
当前提交
f1f4f471
共有 5 个文件被更改,包括 63 次插入36 次删除
  1. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightDefinition.cs
  2. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightDefinition.cs.hlsl
  3. 79
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs
  4. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightUtilities.hlsl
  5. 10
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightDefinition.cs


// User can chose if they use This is use in case we want to force infinite projection distance (i.e no projection);
public float minProjectionDistance;
public Vector3 innerDistance; // extents of the env light
public Vector3 influenceExtents; // extents of the env light
public float unused0;
public Vector3 offsetLS;

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightDefinition.cs.hlsl


float dimmer;
float3 right;
float minProjectionDistance;
float3 innerDistance;
float3 influenceExtents;
float unused0;
float3 offsetLS;
float unused1;

{
return value.minProjectionDistance;
}
float3 GetInnerDistance(EnvLightData value)
float3 GetInfluenceExtents(EnvLightData value)
return value.innerDistance;
return value.influenceExtents;
}
float GetUnused0(EnvLightData value)
{

79
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs


using UnityEngine.Rendering;
using System.Collections.Generic;
using System;
using UnityEngine.Assertions;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{

public const int k_MaxEnvLightsOnScreen = 64;
public const int k_MaxShadowOnScreen = 16;
public const int k_MaxCascadeCount = 4; //Should be not less than m_Settings.directionalLightCascadeCount;
static readonly Vector3 k_BoxCullingExtentThreshold = Vector3.one * 0.01f;
// Static keyword is required here else we get a "DestroyBuffer can only be call in main thread"
static ComputeBuffer s_DirectionalLightDatas = null;

// probe.bounds.extents is BoxSize / 2
var blendDistancePositive = Vector3.Min(probe.bounds.extents, influenceBlendDistancePositive);
var blendDistanceNegative = Vector3.Min(probe.bounds.extents, influenceBlendDistanceNegative);
envLightData.innerDistance = extents;
envLightData.influenceExtents = extents;
envLightData.envIndex = envIndex;
envLightData.offsetLS = probe.center; // center is misnamed, it is the offset (in local space) from center of the bounding box to the cubemap capture point
envLightData.blendDistancePositive = blendDistancePositive;

public void GetEnvLightVolumeDataAndBound(VisibleReflectionProbe probe, LightVolumeType lightVolumeType, Matrix4x4 worldToView)
{
var add = probe.probe.GetComponent<HDAdditionalReflectionData>();
Assert.IsNotNull(add);
var bnds = probe.bounds;
var boxOffset = probe.center; // reflection volume offset relative to cube map capture point
var blendDistance = probe.blendDistance;
var centerOffset = probe.center; // reflection volume offset relative to cube map capture point
var mat = probe.localToWorld;
Vector3 vx = mat.GetColumn(0);

vz.Normalize();
// C is reflection volume center in world space (NOT same as cube map capture point)
var e = bnds.extents; // 0.5f * Vector3.Max(-boxSizes[p], boxSizes[p]);
var C = vx * boxOffset.x + vy * boxOffset.y + vz * boxOffset.z + vw;
var combinedExtent = e + new Vector3(blendDistance, blendDistance, blendDistance);
var influenceExtents = probe.bounds.extents; // 0.5f * Vector3.Max(-boxSizes[p], boxSizes[p]);
var centerWS = vx * centerOffset.x + vy * centerOffset.y + vz * centerOffset.z + vw;
// transform to camera space (becomes a left hand coordinate frame in Unity since Determinant(worldToView)<0)
vx = worldToView.MultiplyVector(vx);

var Cw = worldToView.MultiplyPoint(C);
bound.center = Cw;
bound.boxAxisX = combinedExtent.x * vx;
bound.boxAxisY = combinedExtent.y * vy;
bound.boxAxisZ = combinedExtent.z * vz;
bound.scaleXY.Set(1.0f, 1.0f);
bound.radius = combinedExtent.magnitude;
var centerVS = worldToView.MultiplyPoint(centerWS);
lightVolumeData.lightPos = Cw;
lightVolumeData.lightAxisX = vx;
lightVolumeData.lightAxisY = vy;
lightVolumeData.lightAxisZ = vz;
var delta = combinedExtent - e;
lightVolumeData.boxInnerDist = e;
lightVolumeData.boxInvRange.Set(1.0f / delta.x, 1.0f / delta.y, 1.0f / delta.z);
switch (lightVolumeType)
{
case LightVolumeType.Sphere:
{
lightVolumeData.lightPos = centerVS;
lightVolumeData.radiusSq = add.influenceSphereRadius * add.influenceSphereRadius;
lightVolumeData.lightAxisX = vx;
lightVolumeData.lightAxisY = vy;
lightVolumeData.lightAxisZ = vz;
bound.center = centerVS;
bound.boxAxisX = vx * add.influenceSphereRadius;
bound.boxAxisY = vy * add.influenceSphereRadius;
bound.boxAxisZ = vz * add.influenceSphereRadius;
bound.scaleXY.Set(1.0f, 1.0f);
bound.radius = add.influenceSphereRadius;
break;
}
case LightVolumeType.Box:
{
bound.center = centerVS;
bound.boxAxisX = influenceExtents.x * vx;
bound.boxAxisY = influenceExtents.y * vy;
bound.boxAxisZ = influenceExtents.z * vz;
bound.scaleXY.Set(1.0f, 1.0f);
bound.radius = influenceExtents.magnitude;
// The culling system culls pixels that are further
// than a threshold to the box influence extents.
// So we use an arbitrary threshold here (k_BoxCullingExtentOffset)
lightVolumeData.lightPos = centerVS;
lightVolumeData.lightAxisX = vx;
lightVolumeData.lightAxisY = vy;
lightVolumeData.lightAxisZ = vz;
lightVolumeData.boxInnerDist = influenceExtents - k_BoxCullingExtentThreshold;
lightVolumeData.boxInvRange.Set(1.0f / k_BoxCullingExtentThreshold.x, 1.0f / k_BoxCullingExtentThreshold.y, 1.0f / k_BoxCullingExtentThreshold.z);
break;
}
}
m_lightList.bounds.Add(bound);
m_lightList.lightVolumes.Add(lightVolumeData);

for (int probeIndex = 0, numProbes = cullResults.visibleReflectionProbes.Count; (probeIndex < numProbes) && (sortCount < probeCount); probeIndex++)
{
VisibleReflectionProbe probe = cullResults.visibleReflectionProbes[probeIndex];
HDAdditionalReflectionData additional = probe.probe.GetComponent<HDAdditionalReflectionData>();
// probe.texture can be null when we are adding a reflection probe in the editor
if (probe.texture == null || envLightCount >= k_MaxEnvLightsOnScreen)

}
// TODO: Support LightVolumeType.Sphere, currently in UI there is no way to specify a sphere influence volume
LightVolumeType lightVolumeType = probe.boxProjection != 0 ? LightVolumeType.Box : LightVolumeType.Box;
LightVolumeType lightVolumeType = LightVolumeType.Box;
if (additional != null && additional.influenceShape == ReflectionInfluenceShape.Sphere)
lightVolumeType = LightVolumeType.Sphere;
++envLightCount;
float boxVolume = 8 * probe.bounds.extents.x * probe.bounds.extents.y * probe.bounds.extents.z;

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightUtilities.hlsl


output.right = float3(1.0, 0.0, 0.0);
output.positionWS = float3(0.0, 0.0, 0.0);
output.offsetLS = float3(0.0, 0.0, 0.0);
output.innerDistance = float3(0.0, 0.0, 0.0);
output.influenceExtents = float3(0.0, 0.0, 0.0);
output.blendDistancePositive = float3(0.0, 0.0, 0.0);
output.blendDistanceNegative = float3(0.0, 0.0, 0.0);
output.blendNormalDistancePositive = float3(0.0, 0.0, 0.0);

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


{
// 1. First process the projection
float3 dirLS = mul(R, worldToLocal);
float sphereOuterDistance = lightData.innerDistance.x;
float sphereOuterDistance = lightData.influenceExtents.x;
float projectionDistance = SphereRayIntersectSimple(positionLS, dirLS, sphereOuterDistance);
projectionDistance = max(projectionDistance, lightData.minProjectionDistance); // Setup projection to infinite if requested (mean no projection shape)

// 2. Process the position influence
float lengthPositionLS = length(positionLS);
float sphereInfluenceDistance = lightData.innerDistance.x - lightData.blendDistancePositive.x;
float sphereInfluenceDistance = lightData.influenceExtents.x - lightData.blendDistancePositive.x;
float insideInfluenceNormalVolume = lengthPositionLS <= (lightData.innerDistance.x - lightData.blendNormalDistancePositive.x) ? 1.0 : 0.0;
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

{
// 1. First process the projection
float3 dirLS = mul(R, worldToLocal);
float3 boxOuterDistance = lightData.innerDistance;
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)

float alpha = saturate(influenceFalloff);
#else
float distFace = DistancePointBox(positionLS, -lightData.innerDistance + lightData.blendDistancePositive.x, lightData.innerDistance - lightData.blendDistancePositive.x);
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

正在加载...
取消
保存