浏览代码

HDRenderLoop: Change ReflectionProbe behavior

- reflection probe are now split in two volume, one influence volume
(for culling and fading) and one projection volume (for cubemap
sampling). Mean we can have box porjection with spherical influecne.
- Refletion volume support both cube and sphere (would like to add
ellipse later)
- Change the behavior of blenddistance to inner blend distance instead
of outer blend distance as it is easy for the artists to use.
/main
sebastienlagarde 8 年前
当前提交
86a97da3
共有 4 个文件被更改,包括 96 次插入56 次删除
  1. 20
      Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs
  2. 23
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs
  3. 44
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs.hlsl
  4. 65
      Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/Lit.hlsl

20
Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs


// CAUTION: localToWorld is the transform for the widget of the reflection probe. i.e the world position of the point use to do the cubemap capture (mean it include the local offset)
l.positionWS = probe.localToWorld.GetColumn(3);
l.shapeType = EnvShapeType.None;
l.projectionShapeType = ProjectionShapeType.None;
// TODO: Support sphere in the interface
l.shapeType = EnvShapeType.Box;
l.projectionShapeType = ProjectionShapeType.Box;
// TODO add influence volume in interface, for now it is coupled with projection volume
// Note that even when there is no projection volume, there is an influence volume.
l.influenceShapeType = InfluenceShapeType.Box;
// remove scale from the matrix (Scale in this matrix is use to scale the widget)
l.right = probe.localToWorld.GetColumn(0);

l.forward = probe.localToWorld.GetColumn(2);
l.forward.Normalize();
l.innerDistance = probe.bounds.extents;
// Artists prefer to have blend distance inside the volume!
// So we let the current UI but we assume blendDistance is an inside factor instead
// Blend distance can't be larger than the max radius
// probe.bounds.extents is BoxSize / 2
float maxBlendDist = Mathf.Min(probe.bounds.extents.x, Mathf.Min(probe.bounds.extents.y, probe.bounds.extents.z));
float blendDistance = Mathf.Min(maxBlendDist, probe.blendDistance);
l.innerDistance = probe.bounds.extents - new Vector3(blendDistance, blendDistance, blendDistance);
l.blendDistance = probe.blendDistance;
l.blendDistance = blendDistance;
lights.Add(l);
}

23
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs


};
[GenerateHLSL]
public enum EnvShapeType
public enum ProjectionShapeType
{
None,
Box,

[GenerateHLSL]
public enum InfluenceShapeType
{
Box,
Sphere
};
[GenerateHLSL]
public EnvShapeType shapeType;
public ProjectionShapeType projectionShapeType;
public int sliceIndex;
public InfluenceShapeType influenceShapeType;
public float blendDistance;
public float blendDistance; // blend transition outside the volume
public int sliceIndex;
public Vector3 innerDistance; // equivalent to volume scale
public Vector3 innerDistance;
public Vector3 offsetLS;
public Vector3 offsetLS;
public float unused2;
};
[GenerateHLSL]

44
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs.hlsl


#define AREASHAPETYPE_CYLINDER (5)
//
// UnityEngine.ScriptableRenderLoop.EnvShapeType: static fields
// UnityEngine.ScriptableRenderLoop.ProjectionShapeType: static fields
#define ENVSHAPETYPE_NONE (0)
#define ENVSHAPETYPE_BOX (1)
#define ENVSHAPETYPE_SPHERE (2)
#define PROJECTIONSHAPETYPE_NONE (0)
#define PROJECTIONSHAPETYPE_BOX (1)
#define PROJECTIONSHAPETYPE_SPHERE (2)
//
// UnityEngine.ScriptableRenderLoop.InfluenceShapeType: static fields
//
#define INFLUENCESHAPETYPE_BOX (0)
#define INFLUENCESHAPETYPE_SPHERE (1)
// Generated from UnityEngine.ScriptableRenderLoop.PunctualLightData
// PackingRules = Exact

struct EnvLightData
{
float3 positionWS;
int shapeType;
int projectionShapeType;
int sliceIndex;
int influenceShapeType;
float unused0;
int sliceIndex;
float unused0;
float3 offsetLS;
float3 offsetLS;
float unused2;
};
// Generated from UnityEngine.ScriptableRenderLoop.PlanarLightData

{
return value.positionWS;
}
int GetShapeType(EnvLightData value)
int GetProjectionShapeType(EnvLightData value)
return value.shapeType;
return value.projectionShapeType;
int GetSliceIndex(EnvLightData value)
int GetInfluenceShapeType(EnvLightData value)
return value.sliceIndex;
return value.influenceShapeType;
}
float3 GetUp(EnvLightData value)
{

{
return value.right;
}
float GetUnused0(EnvLightData value)
int GetSliceIndex(EnvLightData value)
return value.unused0;
return value.sliceIndex;
float GetUnused1(EnvLightData value)
float GetUnused0(EnvLightData value)
return value.unused1;
return value.unused0;
float GetUnused2(EnvLightData value)
float GetUnused1(EnvLightData value)
return value.unused2;
return value.unused1;
}
//

65
Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/Lit.hlsl


float3 R = rayWS;
float weight = 1.0;
// In this code we redefine a bit the behavior of the reflcetion proble. We separate the projection volume (the proxy of the scene) form the influence volume (what pixel on the screen is affected)
// 1. First determine the projection volume
if (lightData.shapeType == ENVSHAPETYPE_BOX)
// 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.
if (lightData.projectionShapeType == PROJECTIONSHAPETYPE_BOX)
// 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.
// worldToLocal assume no scaling
float3x3 worldToLocal = transpose(float3x3(lightData.right, lightData.up, lightData.forward));
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.

R = (positionWS + dist * rayWS) - lightData.positionWS;
// TODO: add distance based roughness
// Calculate falloff value, so reflections on the edges of the volume would gradually blend to previous reflection.
float distFade = DistancePointBox(positionLS, -lightData.innerDistance, lightData.innerDistance);
weight = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
// Smooth weighting
weight = smoothstep01(weight);
else if (lightData.shapeType == ENVSHAPETYPE_SPHERE)
else if (lightData.projectionShapeType == PROJECTIONSHAPETYPE_SPHERE)
// For now there is no specific interface for sphere proxy and it can have offset and arbitrary orientation. So we need to transform
// to local space position and direction like for OBB.
float3x3 worldToLocal = transpose(float3x3(lightData.right, lightData.up, lightData.forward));
float3x3 worldToLocal = transpose(float3x3(lightData.right, lightData.up, lightData.forward)); // worldToLocal assume no scaling
float sphereRadius = lightData.innerDistance.x;
float dist = SphereRayIntersectSimple(positionLS, rayLS, sphereRadius + lightData.blendDistance);
float sphereOuterDistance = lightData.innerDistance.x + lightData.blendDistance;
float dist = SphereRayIntersectSimple(positionLS, rayLS, sphereOuterDistance);
}
float distFade = length(positionWS - lightData.positionWS);
weight = saturate(((sphereRadius + lightData.blendDistance) - distFade) / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
// Smooth weighting
weight = smoothstep01(weight);
// 2. Apply the influence volume (Box volume is used for culling whatever the influence shape)
// TODO: Optimize this code! We can remove offset in case of influence volume!
if (lightData.influenceShapeType == INFLUENCESHAPETYPE_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.
// Calculate falloff value, so reflections on the edges of the volume would gradually blend to previous reflection.
float distFade = DistancePointBox(positionLS, -lightData.innerDistance, lightData.innerDistance);
weight = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
else // INFLUENCESHAPETYPE_SPHERE
{
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.
float distFade = max(length(positionLS) - lightData.innerDistance.x, 0.0);
weight = saturate(1.0 - distFade / max(lightData.blendDistance, 0.0001)); // avoid divide by zero
}
// Smooth weighting
weight = smoothstep01(weight);
// TODO: we must always perform a weight calculation as due to tiled rendering we need to smooth out cubemap at boundaries.
// So goal is to split into two category and have an option to say if we parallax correct or not.

正在加载...
取消
保存