Various DDGI improvements to the quality of the final effect
This commit is contained in:
BIN
Content/Shaders/GI/DDGI.flax
(Stored with Git LFS)
BIN
Content/Shaders/GI/DDGI.flax
(Stored with Git LFS)
Binary file not shown.
@@ -116,44 +116,6 @@ void CalculateVolumeRandomRotation(Matrix3x3& matrix)
|
|||||||
matrix.M33 = 1.0f - 2.0f * u3;
|
matrix.M33 = 1.0f - 2.0f * u3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 AbsFloor(const float value)
|
|
||||||
{
|
|
||||||
return value >= 0.0f ? (int32)Math::Floor(value) : (int32)Math::Ceil(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 GetSignNotZero(const float value)
|
|
||||||
{
|
|
||||||
return value >= 0.0f ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 GetVolumeOrigin(DDGICustomBuffer& ddgiData)
|
|
||||||
{
|
|
||||||
return ddgiData.ProbesOrigin + Vector3(ddgiData.ProbeScrollOffsets) * ddgiData.ProbesSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CalculateVolumeScrolling(DDGICustomBuffer& ddgiData, const Vector3& viewOrigin)
|
|
||||||
{
|
|
||||||
// Reset the volume origin and scroll offsets for each axis
|
|
||||||
for (int32 axis = 0; axis < 3; axis++)
|
|
||||||
{
|
|
||||||
if (ddgiData.ProbeScrollOffsets.Raw[axis] != 0 && (ddgiData.ProbeScrollOffsets.Raw[axis] % ddgiData.ProbeCounts.Raw[axis] == 0))
|
|
||||||
{
|
|
||||||
ddgiData.ProbesOrigin.Raw[axis] += (float)ddgiData.ProbeCounts.Raw[axis] * ddgiData.ProbesSpacing * (float)ddgiData.ProbeScrollDirections.Raw[axis];
|
|
||||||
ddgiData.ProbeScrollOffsets.Raw[axis] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the count of grid cells between the view origin and the scroll anchor
|
|
||||||
const Vector3 translation = viewOrigin - GetVolumeOrigin(ddgiData);
|
|
||||||
for (int32 axis = 0; axis < 3; axis++)
|
|
||||||
{
|
|
||||||
const int32 scroll = AbsFloor(translation.Raw[axis] / ddgiData.ProbesSpacing);
|
|
||||||
ddgiData.ProbeScrollOffsets.Raw[axis] += scroll;
|
|
||||||
ddgiData.ProbeScrollClear[axis] = scroll != 0;
|
|
||||||
ddgiData.ProbeScrollDirections.Raw[axis] = GetSignNotZero(translation.Raw[axis]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String DynamicDiffuseGlobalIlluminationPass::ToString() const
|
String DynamicDiffuseGlobalIlluminationPass::ToString() const
|
||||||
{
|
{
|
||||||
return TEXT("DynamicDiffuseGlobalIlluminationPass");
|
return TEXT("DynamicDiffuseGlobalIlluminationPass");
|
||||||
@@ -294,6 +256,17 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
|||||||
const Vector3 probesDistance = Vector3(probesCounts) * giResolution;
|
const Vector3 probesDistance = Vector3(probesCounts) * giResolution;
|
||||||
const int32 probeRaysCount = Math::Min(Math::AlignUp(256, DDGI_TRACE_RAYS_GROUP_SIZE_X), DDGI_TRACE_RAYS_LIMIT); // TODO: make it based on the GI Quality
|
const int32 probeRaysCount = Math::Min(Math::AlignUp(256, DDGI_TRACE_RAYS_GROUP_SIZE_X), DDGI_TRACE_RAYS_LIMIT); // TODO: make it based on the GI Quality
|
||||||
|
|
||||||
|
// Calculate view origin
|
||||||
|
Vector3 viewOrigin = renderContext.View.Position;
|
||||||
|
Vector3 viewDirection = renderContext.View.Direction;
|
||||||
|
const float probesDistanceMax = probesDistance.MaxValue();
|
||||||
|
const Vector2 viewRayHit = CollisionsHelper::LineHitsBox(viewOrigin, viewOrigin + viewDirection * (probesDistanceMax * 2.0f), viewOrigin - probesDistance, viewOrigin + probesDistance);
|
||||||
|
const float viewOriginOffset = viewRayHit.Y * probesDistanceMax * 0.8f;
|
||||||
|
viewOrigin += viewDirection * viewOriginOffset;
|
||||||
|
const float viewOriginSnapping = giResolution;
|
||||||
|
viewOrigin = Vector3::Floor(viewOrigin / viewOriginSnapping) * viewOriginSnapping;
|
||||||
|
//viewOrigin = Vector3::Zero;
|
||||||
|
|
||||||
// Init buffers
|
// Init buffers
|
||||||
const int32 probesCount = probesCounts.X * probesCounts.Y * probesCounts.Z;
|
const int32 probesCount = probesCounts.X * probesCounts.Y * probesCounts.Z;
|
||||||
if (probesCount == 0 || indirectLightingIntensity <= ZeroTolerance)
|
if (probesCount == 0 || indirectLightingIntensity <= ZeroTolerance)
|
||||||
@@ -308,6 +281,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
|||||||
ddgiData.ProbeRaysCount = probeRaysCount;
|
ddgiData.ProbeRaysCount = probeRaysCount;
|
||||||
ddgiData.ProbesSpacing = giResolution;
|
ddgiData.ProbesSpacing = giResolution;
|
||||||
ddgiData.ProbeCounts = probesCounts;
|
ddgiData.ProbeCounts = probesCounts;
|
||||||
|
ddgiData.ProbesOrigin = viewOrigin;
|
||||||
|
|
||||||
// Allocate probes textures
|
// Allocate probes textures
|
||||||
uint64 memUsage = 0;
|
uint64 memUsage = 0;
|
||||||
@@ -335,29 +309,36 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
|||||||
context->ClearUA(ddgiData.ProbesDistance, Vector4::Zero);
|
context->ClearUA(ddgiData.ProbesDistance, Vector4::Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute random rotation matrix for probe rays orientation (randomized every frame)
|
|
||||||
Matrix3x3 raysRotationMatrix;
|
|
||||||
CalculateVolumeRandomRotation(raysRotationMatrix);
|
|
||||||
|
|
||||||
// Compute scrolling (probes are placed around camera but are scrolling to increase stability during movement)
|
// Compute scrolling (probes are placed around camera but are scrolling to increase stability during movement)
|
||||||
Vector3 viewOrigin = renderContext.View.Position;
|
{
|
||||||
Vector3 viewDirection = renderContext.View.Direction;
|
|
||||||
const float probesDistanceMax = probesDistance.MaxValue();
|
// Reset the volume origin and scroll offsets for each axis
|
||||||
const Vector2 viewRayHit = CollisionsHelper::LineHitsBox(viewOrigin, viewOrigin + viewDirection * (probesDistanceMax * 2.0f), viewOrigin - probesDistance, viewOrigin + probesDistance);
|
for (int32 axis = 0; axis < 3; axis++)
|
||||||
const float viewOriginOffset = viewRayHit.Y * probesDistanceMax * 0.8f;
|
{
|
||||||
viewOrigin += viewDirection * viewOriginOffset;
|
if (ddgiData.ProbeScrollOffsets.Raw[axis] != 0 && (ddgiData.ProbeScrollOffsets.Raw[axis] % ddgiData.ProbeCounts.Raw[axis] == 0))
|
||||||
const float viewOriginSnapping = giResolution;
|
{
|
||||||
viewOrigin = Vector3::Floor(viewOrigin / viewOriginSnapping) * viewOriginSnapping;
|
ddgiData.ProbesOrigin.Raw[axis] += (float)ddgiData.ProbeCounts.Raw[axis] * ddgiData.ProbesSpacing * (float)ddgiData.ProbeScrollDirections.Raw[axis];
|
||||||
//viewOrigin = Vector3::Zero;
|
ddgiData.ProbeScrollOffsets.Raw[axis] = 0;
|
||||||
CalculateVolumeScrolling(ddgiData, viewOrigin);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the count of grid cells between the view origin and the scroll anchor
|
||||||
|
const Vector3 volumeOrigin = ddgiData.ProbesOrigin + Vector3(ddgiData.ProbeScrollOffsets) * ddgiData.ProbesSpacing;
|
||||||
|
const Vector3 translation = viewOrigin - volumeOrigin;
|
||||||
|
for (int32 axis = 0; axis < 3; axis++)
|
||||||
|
{
|
||||||
|
const float value = translation.Raw[axis] / ddgiData.ProbesSpacing;
|
||||||
|
const int32 scroll = value >= 0.0f ? (int32)Math::Floor(value) : (int32)Math::Ceil(value);
|
||||||
|
ddgiData.ProbeScrollOffsets.Raw[axis] += scroll;
|
||||||
|
ddgiData.ProbeScrollClear[axis] = scroll != 0;
|
||||||
|
ddgiData.ProbeScrollDirections.Raw[axis] = translation.Raw[axis] >= 0.0f ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Upload constants
|
// Upload constants
|
||||||
{
|
{
|
||||||
ddgiData.Result.Constants.ProbesOrigin = ddgiData.ProbesOrigin;
|
ddgiData.Result.Constants.ProbesOrigin = ddgiData.ProbesOrigin;
|
||||||
ddgiData.Result.Constants.ProbesSpacing = ddgiData.ProbesSpacing;
|
ddgiData.Result.Constants.ProbesSpacing = ddgiData.ProbesSpacing;
|
||||||
Quaternion& raysRotation = *(Quaternion*)&ddgiData.Result.Constants.RaysRotation;
|
|
||||||
Quaternion::RotationMatrix(raysRotationMatrix, raysRotation);
|
|
||||||
raysRotation.Conjugate();
|
|
||||||
ddgiData.Result.Constants.ProbesCounts[0] = probesCounts.X;
|
ddgiData.Result.Constants.ProbesCounts[0] = probesCounts.X;
|
||||||
ddgiData.Result.Constants.ProbesCounts[1] = probesCounts.Y;
|
ddgiData.Result.Constants.ProbesCounts[1] = probesCounts.Y;
|
||||||
ddgiData.Result.Constants.ProbesCounts[2] = probesCounts.Z;
|
ddgiData.Result.Constants.ProbesCounts[2] = probesCounts.Z;
|
||||||
@@ -375,6 +356,13 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
|||||||
ddgiData.Result.ProbesDistance = ddgiData.ProbesDistance->View();
|
ddgiData.Result.ProbesDistance = ddgiData.ProbesDistance->View();
|
||||||
ddgiData.Result.ProbesIrradiance = ddgiData.ProbesIrradiance->View();
|
ddgiData.Result.ProbesIrradiance = ddgiData.ProbesIrradiance->View();
|
||||||
|
|
||||||
|
// Compute random rotation matrix for probe rays orientation (randomized every frame)
|
||||||
|
Matrix3x3 raysRotationMatrix;
|
||||||
|
CalculateVolumeRandomRotation(raysRotationMatrix);
|
||||||
|
Quaternion& raysRotation = *(Quaternion*)&ddgiData.Result.Constants.RaysRotation;
|
||||||
|
Quaternion::RotationMatrix(raysRotationMatrix, raysRotation);
|
||||||
|
raysRotation.Conjugate();
|
||||||
|
|
||||||
Data0 data;
|
Data0 data;
|
||||||
data.DDGI = ddgiData.Result.Constants;
|
data.DDGI = ddgiData.Result.Constants;
|
||||||
data.GlobalSDF = bindingDataSDF.Constants;
|
data.GlobalSDF = bindingDataSDF.Constants;
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
|
|||||||
probeState.xyz = float3(0, 0, 0);
|
probeState.xyz = float3(0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RWProbesState[probeDataCoords] = probeState;
|
RWProbesState[probeDataCoords] = probeState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +236,8 @@ void CS_UpdateProbes(uint3 DispatchThreadId : SV_DispatchThreadID, uint GroupInd
|
|||||||
uint coord = (probeCount + (scrollDirection ? (scrollOffset - 1) : (scrollOffset % probeCount))) % probeCount;
|
uint coord = (probeCount + (scrollDirection ? (scrollOffset - 1) : (scrollOffset % probeCount))) % probeCount;
|
||||||
if (probeCoords[planeIndex] == coord)
|
if (probeCoords[planeIndex] == coord)
|
||||||
{
|
{
|
||||||
// Skip scrolled probes
|
// Clear and skip scrolled probes
|
||||||
|
RWOutput[outputCoords] = float4(0, 0, 0, 0);
|
||||||
skip = true;
|
skip = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,11 +263,7 @@ void CS_UpdateProbes(uint3 DispatchThreadId : SV_DispatchThreadID, uint GroupInd
|
|||||||
}
|
}
|
||||||
GroupMemoryBarrierWithGroupSync();
|
GroupMemoryBarrierWithGroupSync();
|
||||||
if (skip)
|
if (skip)
|
||||||
{
|
|
||||||
// Clear probe
|
|
||||||
RWOutput[outputCoords] = float4(0, 0, 0, 0);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate octahedral projection for probe (unwraps spherical projection into a square)
|
// Calculate octahedral projection for probe (unwraps spherical projection into a square)
|
||||||
float2 octahedralCoords = GetOctahedralCoords(DispatchThreadId.xy, DDGI_PROBE_RESOLUTION);
|
float2 octahedralCoords = GetOctahedralCoords(DispatchThreadId.xy, DDGI_PROBE_RESOLUTION);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#define GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION 40 // Amount of chunks (in each direction) to split atlas draw distance for objects culling
|
#define GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION 40 // Amount of chunks (in each direction) to split atlas draw distance for objects culling
|
||||||
#define GLOBAL_SURFACE_ATLAS_CHUNKS_GROUP_SIZE 4
|
#define GLOBAL_SURFACE_ATLAS_CHUNKS_GROUP_SIZE 4
|
||||||
#define GLOBAL_SURFACE_ATLAS_TILE_DATA_STRIDE 5 // Amount of float4s per-tile
|
#define GLOBAL_SURFACE_ATLAS_TILE_DATA_STRIDE 5 // Amount of float4s per-tile
|
||||||
|
#define GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD_ENABLED 1 // Enables using tile normal threshold to prevent sampling pixels behind the view point (but might cause back artifacts)
|
||||||
#define GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD 0.05f // Cut-off value for tiles transitions blending during sampling
|
#define GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD 0.05f // Cut-off value for tiles transitions blending during sampling
|
||||||
#define GLOBAL_SURFACE_ATLAS_TILE_PROJ_PLANE_OFFSET 0.1f // Small offset to prevent clipping with the closest triangles (shifts near and far planes)
|
#define GLOBAL_SURFACE_ATLAS_TILE_PROJ_PLANE_OFFSET 0.1f // Small offset to prevent clipping with the closest triangles (shifts near and far planes)
|
||||||
|
|
||||||
@@ -108,12 +109,14 @@ float3 SampleGlobalSurfaceAtlasTex(Texture2D atlas, float2 atlasUV, float4 bilin
|
|||||||
|
|
||||||
float4 SampleGlobalSurfaceAtlasTile(const GlobalSurfaceAtlasData data, GlobalSurfaceTile tile, Texture2D depth, Texture2D atlas, float3 worldPosition, float3 worldNormal, float surfaceThreshold)
|
float4 SampleGlobalSurfaceAtlasTile(const GlobalSurfaceAtlasData data, GlobalSurfaceTile tile, Texture2D depth, Texture2D atlas, float3 worldPosition, float3 worldNormal, float surfaceThreshold)
|
||||||
{
|
{
|
||||||
|
#if GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD_ENABLED
|
||||||
// Tile normal weight based on the sampling angle
|
// Tile normal weight based on the sampling angle
|
||||||
float3 tileNormal = normalize(mul(worldNormal, (float3x3)tile.WorldToLocal));
|
float3 tileNormal = normalize(mul(worldNormal, (float3x3)tile.WorldToLocal));
|
||||||
float normalWeight = saturate(dot(float3(0, 0, -1), tileNormal));
|
float normalWeight = saturate(dot(float3(0, 0, -1), tileNormal));
|
||||||
normalWeight = (normalWeight - GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD) / (1.0f - GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD);
|
normalWeight = (normalWeight - GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD) / (1.0f - GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD);
|
||||||
if (normalWeight <= 0.0f)
|
if (normalWeight <= 0.0f)
|
||||||
return 0;
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Get tile UV and depth at the world position
|
// Get tile UV and depth at the world position
|
||||||
float3 tilePosition = mul(float4(worldPosition, 1), tile.WorldToLocal).xyz;
|
float3 tilePosition = mul(float4(worldPosition, 1), tile.WorldToLocal).xyz;
|
||||||
@@ -141,7 +144,10 @@ float4 SampleGlobalSurfaceAtlasTile(const GlobalSurfaceAtlasData data, GlobalSur
|
|||||||
if (tileZ[i] >= 1.0f)
|
if (tileZ[i] >= 1.0f)
|
||||||
depthVisibility[i] = 0.0f;
|
depthVisibility[i] = 0.0f;
|
||||||
}
|
}
|
||||||
float sampleWeight = normalWeight * dot(depthVisibility, bilinearWeights);
|
float sampleWeight = dot(depthVisibility, bilinearWeights);
|
||||||
|
#if GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD_ENABLED
|
||||||
|
sampleWeight *= normalWeight;
|
||||||
|
#endif
|
||||||
if (sampleWeight <= 0.0f)
|
if (sampleWeight <= 0.0f)
|
||||||
return 0;
|
return 0;
|
||||||
bilinearWeights = depthVisibility * bilinearWeights;
|
bilinearWeights = depthVisibility * bilinearWeights;
|
||||||
@@ -209,26 +215,65 @@ float4 SampleGlobalSurfaceAtlas(const GlobalSurfaceAtlasData data, ByteAddressBu
|
|||||||
worldToLocal[2] *= invScale.z;
|
worldToLocal[2] *= invScale.z;
|
||||||
|
|
||||||
// Sample tiles based on the directionality
|
// Sample tiles based on the directionality
|
||||||
|
#if GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD_ENABLED
|
||||||
float3 localNormal = normalize(mul(worldNormal, worldToLocal));
|
float3 localNormal = normalize(mul(worldNormal, worldToLocal));
|
||||||
float3 localNormalSq = localNormal * localNormal;
|
float3 localNormalSq = localNormal * localNormal;
|
||||||
uint tileOffset = object.TileOffsets[localNormal.x > 0.0f ? 0 : 1];
|
uint tileOffset = object.TileOffsets[localNormal.y > 0.0f ? 0 : 1];
|
||||||
if (localNormalSq.x > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0)
|
if (localNormalSq.x > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0)
|
||||||
|
{
|
||||||
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
||||||
|
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
||||||
|
}
|
||||||
|
tileOffset = object.TileOffsets[localNormal.y > 0.0f ? 2 : 3];
|
||||||
|
if (localNormalSq.y > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0)
|
||||||
|
{
|
||||||
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
||||||
|
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
||||||
|
}
|
||||||
|
tileOffset = object.TileOffsets[localNormal.z > 0.0f ? 4 : 5];
|
||||||
|
if (localNormalSq.z > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0)
|
||||||
|
{
|
||||||
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
||||||
|
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
uint tileOffset = object.TileOffsets[0];
|
||||||
|
if (tileOffset != 0)
|
||||||
{
|
{
|
||||||
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
||||||
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
||||||
}
|
}
|
||||||
tileOffset = object.TileOffsets[localNormal.y > 0.0f ? 2 : 3];
|
tileOffset = object.TileOffsets[1];
|
||||||
if (localNormalSq.y > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0)
|
if (tileOffset != 0)
|
||||||
{
|
{
|
||||||
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
||||||
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
||||||
}
|
}
|
||||||
tileOffset = object.TileOffsets[localNormal.z > 0.0f ? 4 : 5];
|
tileOffset = object.TileOffsets[2];
|
||||||
if (localNormalSq.z > GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD * GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD && tileOffset != 0)
|
if (tileOffset != 0)
|
||||||
{
|
{
|
||||||
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
||||||
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
||||||
}
|
}
|
||||||
|
tileOffset = object.TileOffsets[3];
|
||||||
|
if (tileOffset != 0)
|
||||||
|
{
|
||||||
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
||||||
|
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
||||||
|
}
|
||||||
|
tileOffset = object.TileOffsets[4];
|
||||||
|
if (tileOffset != 0)
|
||||||
|
{
|
||||||
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
||||||
|
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
||||||
|
}
|
||||||
|
tileOffset = object.TileOffsets[5];
|
||||||
|
if (tileOffset != 0)
|
||||||
|
{
|
||||||
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(culledObjects, objectAddress + tileOffset);
|
||||||
|
result += SampleGlobalSurfaceAtlasTile(data, tile, depth, atlas, worldPosition, worldNormal, surfaceThreshold);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize result
|
// Normalize result
|
||||||
|
|||||||
Reference in New Issue
Block a user