Progress on surface atlas sampling
This commit is contained in:
BIN
Content/Shaders/GlobalSurfaceAtlas.flax
(Stored with Git LFS)
BIN
Content/Shaders/GlobalSurfaceAtlas.flax
(Stored with Git LFS)
Binary file not shown.
@@ -17,7 +17,7 @@
|
|||||||
#include "Engine/Utilities/RectPack.h"
|
#include "Engine/Utilities/RectPack.h"
|
||||||
|
|
||||||
// This must match HLSL
|
// This must match HLSL
|
||||||
#define GLOBAL_SURFACE_ATLAS_OBJECT_SIZE 5 // Amount of Vector4s per-object
|
#define GLOBAL_SURFACE_ATLAS_OBJECT_SIZE (5 + 6 * 5) // Amount of float4s per-object
|
||||||
#define GLOBAL_SURFACE_ATLAS_TILE_PADDING 1 // 1px padding to prevent color bleeding between tiles
|
#define GLOBAL_SURFACE_ATLAS_TILE_PADDING 1 // 1px padding to prevent color bleeding between tiles
|
||||||
#define GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_TILES_REDRAW 0 // Forces to redraw all object tiles every frame
|
#define GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_TILES_REDRAW 0 // Forces to redraw all object tiles every frame
|
||||||
#define GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_DRAW_OBJECTS 0 // Debug draws object bounds on redraw (and tile draw projection locations)
|
#define GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_DRAW_OBJECTS 0 // Debug draws object bounds on redraw (and tile draw projection locations)
|
||||||
@@ -44,6 +44,11 @@ PACK_STRUCT(struct AtlasTileVertex
|
|||||||
|
|
||||||
struct GlobalSurfaceAtlasTile : RectPack<GlobalSurfaceAtlasTile, uint16>
|
struct GlobalSurfaceAtlasTile : RectPack<GlobalSurfaceAtlasTile, uint16>
|
||||||
{
|
{
|
||||||
|
Vector3 ViewDirection;
|
||||||
|
Vector3 ViewPosition; // TODO: use from ViewMatrix
|
||||||
|
Vector3 ViewBoundsSize;
|
||||||
|
Matrix ViewMatrix;
|
||||||
|
|
||||||
GlobalSurfaceAtlasTile(uint16 x, uint16 y, uint16 width, uint16 height)
|
GlobalSurfaceAtlasTile(uint16 x, uint16 y, uint16 width, uint16 height)
|
||||||
: RectPack<GlobalSurfaceAtlasTile, uint16>(x, y, width, height)
|
: RectPack<GlobalSurfaceAtlasTile, uint16>(x, y, width, height)
|
||||||
{
|
{
|
||||||
@@ -209,6 +214,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
|
|
||||||
// TODO: configurable via graphics settings
|
// TODO: configurable via graphics settings
|
||||||
const int32 resolution = 4096;
|
const int32 resolution = 4096;
|
||||||
|
const float resolutionInv = 1.0f / resolution;
|
||||||
// TODO: configurable via postFx settings (maybe use Global SDF distance?)
|
// TODO: configurable via postFx settings (maybe use Global SDF distance?)
|
||||||
const float distance = 20000;
|
const float distance = 20000;
|
||||||
|
|
||||||
@@ -350,6 +356,55 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
objectData[2] = Vector4(worldToLocalBounds.M21, worldToLocalBounds.M22, worldToLocalBounds.M23, worldToLocalBounds.M42);
|
objectData[2] = Vector4(worldToLocalBounds.M21, worldToLocalBounds.M22, worldToLocalBounds.M23, worldToLocalBounds.M42);
|
||||||
objectData[3] = Vector4(worldToLocalBounds.M31, worldToLocalBounds.M32, worldToLocalBounds.M33, worldToLocalBounds.M43);
|
objectData[3] = Vector4(worldToLocalBounds.M31, worldToLocalBounds.M32, worldToLocalBounds.M33, worldToLocalBounds.M43);
|
||||||
objectData[4] = Vector4(object->Bounds.Extents, 0.0f);
|
objectData[4] = Vector4(object->Bounds.Extents, 0.0f);
|
||||||
|
// TODO: try to optimize memory footprint (eg. merge scale into extents and use rotation+offset but reconstruct rotation from two axes with sign)
|
||||||
|
for (int32 tileIndex = 0; tileIndex < 6; tileIndex++)
|
||||||
|
{
|
||||||
|
auto* tile = object->Tiles[tileIndex];
|
||||||
|
const int32 tileStart = 5 + tileIndex * 5;
|
||||||
|
if (!tile)
|
||||||
|
{
|
||||||
|
// Disable tile
|
||||||
|
objectData[tileStart + 4] = Vector4::Zero;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup view to render object from the side
|
||||||
|
Vector3 xAxis, yAxis, zAxis = Vector3::Zero;
|
||||||
|
zAxis.Raw[tileIndex / 2] = tileIndex & 1 ? 1.0f : -1.0f;
|
||||||
|
yAxis = tileIndex == 2 || tileIndex == 3 ? Vector3::Right : Vector3::Up;
|
||||||
|
Vector3::Cross(yAxis, zAxis, xAxis);
|
||||||
|
Vector3 localSpaceOffset = -zAxis * object->Bounds.Extents;
|
||||||
|
Vector3::TransformNormal(xAxis, object->Bounds.Transformation, xAxis);
|
||||||
|
Vector3::TransformNormal(yAxis, object->Bounds.Transformation, yAxis);
|
||||||
|
Vector3::TransformNormal(zAxis, object->Bounds.Transformation, zAxis);
|
||||||
|
xAxis.NormalizeFast();
|
||||||
|
yAxis.NormalizeFast();
|
||||||
|
zAxis.NormalizeFast();
|
||||||
|
Vector3::Transform(localSpaceOffset, object->Bounds.Transformation, tile->ViewPosition);
|
||||||
|
tile->ViewDirection = zAxis;
|
||||||
|
|
||||||
|
// Create view matrix
|
||||||
|
tile->ViewMatrix.SetColumn1(Vector4(xAxis, -Vector3::Dot(xAxis, tile->ViewPosition)));
|
||||||
|
tile->ViewMatrix.SetColumn2(Vector4(yAxis, -Vector3::Dot(yAxis, tile->ViewPosition)));
|
||||||
|
tile->ViewMatrix.SetColumn3(Vector4(zAxis, -Vector3::Dot(zAxis, tile->ViewPosition)));
|
||||||
|
tile->ViewMatrix.SetColumn4(Vector4(0, 0, 0, 1));
|
||||||
|
|
||||||
|
// Calculate object bounds size in the view
|
||||||
|
OrientedBoundingBox viewBounds(object->Bounds);
|
||||||
|
viewBounds.Transform(tile->ViewMatrix);
|
||||||
|
Vector3 viewExtent;
|
||||||
|
Vector3::TransformNormal(viewBounds.Extents, viewBounds.Transformation, viewExtent);
|
||||||
|
tile->ViewBoundsSize = viewExtent.GetAbsolute() * 2.0f;
|
||||||
|
|
||||||
|
// Per-tile data
|
||||||
|
const float tileWidth = (float)tile->Width - GLOBAL_SURFACE_ATLAS_TILE_PADDING;
|
||||||
|
const float tileHeight = (float)tile->Height - GLOBAL_SURFACE_ATLAS_TILE_PADDING;
|
||||||
|
objectData[tileStart + 0] = Vector4(tile->X, tile->Y, tileWidth, tileHeight);
|
||||||
|
objectData[tileStart + 1] = Vector4(tile->ViewMatrix.M11, tile->ViewMatrix.M12, tile->ViewMatrix.M13, tile->ViewMatrix.M41);
|
||||||
|
objectData[tileStart + 2] = Vector4(tile->ViewMatrix.M21, tile->ViewMatrix.M22, tile->ViewMatrix.M23, tile->ViewMatrix.M42);
|
||||||
|
objectData[tileStart + 3] = Vector4(tile->ViewMatrix.M31, tile->ViewMatrix.M32, tile->ViewMatrix.M33, tile->ViewMatrix.M43);
|
||||||
|
objectData[tileStart + 4] = Vector4(tile->ViewBoundsSize, 1.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,7 +473,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
// Per-tile clear (with a single draw call)
|
// Per-tile clear (with a single draw call)
|
||||||
_vertexBuffer->Clear();
|
_vertexBuffer->Clear();
|
||||||
_vertexBuffer->Data.EnsureCapacity(_dirtyObjectsBuffer.Count() * 6 * sizeof(AtlasTileVertex));
|
_vertexBuffer->Data.EnsureCapacity(_dirtyObjectsBuffer.Count() * 6 * sizeof(AtlasTileVertex));
|
||||||
const Vector2 posToClipMul(2.0f / resolution, -2.0f / resolution);
|
const Vector2 posToClipMul(2.0f * resolutionInv, -2.0f * resolutionInv);
|
||||||
const Vector2 posToClipAdd(-1.0f, 1.0f);
|
const Vector2 posToClipAdd(-1.0f, 1.0f);
|
||||||
for (const auto& e : _dirtyObjectsBuffer)
|
for (const auto& e : _dirtyObjectsBuffer)
|
||||||
{
|
{
|
||||||
@@ -475,41 +530,14 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
|||||||
const float tileWidth = (float)tile->Width - GLOBAL_SURFACE_ATLAS_TILE_PADDING;
|
const float tileWidth = (float)tile->Width - GLOBAL_SURFACE_ATLAS_TILE_PADDING;
|
||||||
const float tileHeight = (float)tile->Height - GLOBAL_SURFACE_ATLAS_TILE_PADDING;
|
const float tileHeight = (float)tile->Height - GLOBAL_SURFACE_ATLAS_TILE_PADDING;
|
||||||
|
|
||||||
// Setup view to render object from the side
|
|
||||||
Vector3 xAxis, yAxis, zAxis = Vector3::Zero;
|
|
||||||
zAxis.Raw[tileIndex / 2] = tileIndex & 1 ? 1.0f : -1.0f;
|
|
||||||
yAxis = tileIndex == 2 || tileIndex == 3 ? Vector3::Right : Vector3::Up;
|
|
||||||
Vector3::Cross(yAxis, zAxis, xAxis);
|
|
||||||
Vector3 localSpaceOffset = -zAxis * object.Bounds.Extents;
|
|
||||||
Vector3::TransformNormal(xAxis, object.Bounds.Transformation, xAxis);
|
|
||||||
Vector3::TransformNormal(yAxis, object.Bounds.Transformation, yAxis);
|
|
||||||
Vector3::TransformNormal(zAxis, object.Bounds.Transformation, zAxis);
|
|
||||||
xAxis.NormalizeFast();
|
|
||||||
yAxis.NormalizeFast();
|
|
||||||
zAxis.NormalizeFast();
|
|
||||||
Vector3::Transform(localSpaceOffset, object.Bounds.Transformation, renderContextTiles.View.Position);
|
|
||||||
renderContextTiles.View.Direction = zAxis;
|
|
||||||
|
|
||||||
// Create view matrix
|
|
||||||
Matrix viewMatrix;
|
|
||||||
viewMatrix.SetColumn1(Vector4(xAxis, -Vector3::Dot(xAxis, renderContextTiles.View.Position)));
|
|
||||||
viewMatrix.SetColumn2(Vector4(yAxis, -Vector3::Dot(yAxis, renderContextTiles.View.Position)));
|
|
||||||
viewMatrix.SetColumn3(Vector4(zAxis, -Vector3::Dot(zAxis, renderContextTiles.View.Position)));
|
|
||||||
viewMatrix.SetColumn4(Vector4(0, 0, 0, 1));
|
|
||||||
|
|
||||||
// Calculate object bounds size in the view
|
|
||||||
OrientedBoundingBox viewBounds(object.Bounds);
|
|
||||||
viewBounds.Transform(viewMatrix);
|
|
||||||
Vector3 viewExtent;
|
|
||||||
Vector3::TransformNormal(viewBounds.Extents, viewBounds.Transformation, viewExtent);
|
|
||||||
Vector3 viewBoundsSize = viewExtent.GetAbsolute() * 2.0f;
|
|
||||||
|
|
||||||
// Setup projection to capture object from the side
|
// Setup projection to capture object from the side
|
||||||
|
renderContextTiles.View.Position = tile->ViewPosition;
|
||||||
|
renderContextTiles.View.Direction = tile->ViewDirection;
|
||||||
renderContextTiles.View.Near = -0.1f; // Small offset to prevent clipping with the closest triangles
|
renderContextTiles.View.Near = -0.1f; // Small offset to prevent clipping with the closest triangles
|
||||||
renderContextTiles.View.Far = viewBoundsSize.Z + 0.2f;
|
renderContextTiles.View.Far = tile->ViewBoundsSize.Z + 0.2f;
|
||||||
Matrix projectionMatrix;
|
Matrix projectionMatrix;
|
||||||
Matrix::Ortho(viewBoundsSize.X, viewBoundsSize.Y, renderContextTiles.View.Near, renderContextTiles.View.Far, projectionMatrix);
|
Matrix::Ortho(tile->ViewBoundsSize.X, tile->ViewBoundsSize.Y, renderContextTiles.View.Near, renderContextTiles.View.Far, projectionMatrix);
|
||||||
renderContextTiles.View.SetUp(viewMatrix, projectionMatrix);
|
renderContextTiles.View.SetUp(tile->ViewMatrix, projectionMatrix);
|
||||||
#if GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_DRAW_OBJECTS
|
#if GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_DRAW_OBJECTS
|
||||||
DebugDraw::DrawLine(renderContextTiles.View.Position, renderContextTiles.View.Position + renderContextTiles.View.Direction * 20.0f, Color::Orange);
|
DebugDraw::DrawLine(renderContextTiles.View.Position, renderContextTiles.View.Position + renderContextTiles.View.Direction * 20.0f, Color::Orange);
|
||||||
DebugDraw::DrawWireSphere(BoundingSphere(renderContextTiles.View.Position, 10.0f), Color::Green);
|
DebugDraw::DrawWireSphere(BoundingSphere(renderContextTiles.View.Position, 10.0f), Color::Green);
|
||||||
@@ -573,8 +601,15 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex
|
|||||||
context->BindSR(i, bindingDataSDF.Cascades[i]->ViewVolume());
|
context->BindSR(i, bindingDataSDF.Cascades[i]->ViewVolume());
|
||||||
context->BindSR(i + 4, bindingDataSDF.CascadeMips[i]->ViewVolume());
|
context->BindSR(i + 4, bindingDataSDF.CascadeMips[i]->ViewVolume());
|
||||||
}
|
}
|
||||||
context->BindSR(8, bindingData.Atlas[1]->View()); // TODO: pass Atlas[4]=AtlasDirectLight
|
context->BindSR(8, bindingData.Objects ? bindingData.Objects->View() : nullptr);
|
||||||
context->BindSR(9, bindingData.Objects ? bindingData.Objects->View() : nullptr);
|
context->BindSR(9, bindingData.Atlas[0]->View());
|
||||||
|
{
|
||||||
|
GPUTexture* tex = bindingData.Atlas[1]; // Preview diffuse
|
||||||
|
//GPUTexture* tex = bindingData.Atlas[2]; // Preview normals
|
||||||
|
//GPUTexture* tex = bindingData.Atlas[3]; // Preview roughness/metalness/ao
|
||||||
|
//GPUTexture* tex = bindingData.Atlas[4]; // Preview direct light
|
||||||
|
context->BindSR(10, tex->View());
|
||||||
|
}
|
||||||
context->SetState(_psDebug);
|
context->SetState(_psDebug);
|
||||||
context->SetRenderTarget(output->View());
|
context->SetRenderTarget(output->View());
|
||||||
context->SetViewportAndScissors(outputSize.X, outputSize.Y);
|
context->SetViewportAndScissors(outputSize.X, outputSize.Y);
|
||||||
|
|||||||
@@ -4,12 +4,14 @@
|
|||||||
#include "./Flax/Collisions.hlsl"
|
#include "./Flax/Collisions.hlsl"
|
||||||
|
|
||||||
// This must match C++
|
// This must match C++
|
||||||
#define GLOBAL_SURFACE_ATLAS_OBJECT_SIZE 5 // Amount of float4s per-object
|
#define GLOBAL_SURFACE_ATLAS_OBJECT_SIZE (5 + 6 * 5) // Amount of float4s per-object
|
||||||
|
#define GLOBAL_SURFACE_ATLAS_TILE_NORMAL_THRESHOLD 0.3f // Cut-off value for tiles transitions blending during sampling
|
||||||
|
|
||||||
struct GlobalSurfaceTile
|
struct GlobalSurfaceTile
|
||||||
{
|
{
|
||||||
uint Index;
|
float4 AtlasRect;
|
||||||
uint2 AtlasCoord;
|
float4x4 WorldToLocal;
|
||||||
|
float3 ViewBoundsSize;
|
||||||
bool Enabled;
|
bool Enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -19,7 +21,6 @@ struct GlobalSurfaceObject
|
|||||||
float BoundsRadius;
|
float BoundsRadius;
|
||||||
float4x4 WorldToLocal;
|
float4x4 WorldToLocal;
|
||||||
float3 Extent;
|
float3 Extent;
|
||||||
GlobalSurfaceTile Tiles[6];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
float4 LoadGlobalSurfaceAtlasObjectBounds(Buffer<float4> objects, uint objectIndex)
|
float4 LoadGlobalSurfaceAtlasObjectBounds(Buffer<float4> objects, uint objectIndex)
|
||||||
@@ -37,7 +38,7 @@ GlobalSurfaceObject LoadGlobalSurfaceAtlasObject(Buffer<float4> objects, uint ob
|
|||||||
float4 vector1 = objects.Load(objectStart + 1);
|
float4 vector1 = objects.Load(objectStart + 1);
|
||||||
float4 vector2 = objects.Load(objectStart + 2);
|
float4 vector2 = objects.Load(objectStart + 2);
|
||||||
float4 vector3 = objects.Load(objectStart + 3);
|
float4 vector3 = objects.Load(objectStart + 3);
|
||||||
float4 vector4 = objects.Load(objectStart + 4);
|
float4 vector4 = objects.Load(objectStart + 4); // w unused
|
||||||
GlobalSurfaceObject object = (GlobalSurfaceObject)0;
|
GlobalSurfaceObject object = (GlobalSurfaceObject)0;
|
||||||
object.BoundsPosition = vector0.xyz;
|
object.BoundsPosition = vector0.xyz;
|
||||||
object.BoundsRadius = vector0.w;
|
object.BoundsRadius = vector0.w;
|
||||||
@@ -46,10 +47,30 @@ GlobalSurfaceObject LoadGlobalSurfaceAtlasObject(Buffer<float4> objects, uint ob
|
|||||||
object.WorldToLocal[2] = float4(vector3.xyz, 0.0f);
|
object.WorldToLocal[2] = float4(vector3.xyz, 0.0f);
|
||||||
object.WorldToLocal[3] = float4(vector1.w, vector2.w, vector3.w, 1.0f);
|
object.WorldToLocal[3] = float4(vector1.w, vector2.w, vector3.w, 1.0f);
|
||||||
object.Extent = vector4.xyz;
|
object.Extent = vector4.xyz;
|
||||||
// TODO: Tiles
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GlobalSurfaceTile LoadGlobalSurfaceAtlasTile(Buffer<float4> objects, uint objectIndex, uint tileIndex)
|
||||||
|
{
|
||||||
|
// This must match C++
|
||||||
|
const uint objectStart = objectIndex * GLOBAL_SURFACE_ATLAS_OBJECT_SIZE;
|
||||||
|
const uint tileStart = objectStart + 5 + tileIndex * 5;
|
||||||
|
float4 vector0 = objects.Load(tileStart + 0);
|
||||||
|
float4 vector1 = objects.Load(tileStart + 1);
|
||||||
|
float4 vector2 = objects.Load(tileStart + 2);
|
||||||
|
float4 vector3 = objects.Load(tileStart + 3);
|
||||||
|
float4 vector4 = objects.Load(tileStart + 4);
|
||||||
|
GlobalSurfaceTile tile = (GlobalSurfaceTile)0;
|
||||||
|
tile.AtlasRect = vector0.xyzw;
|
||||||
|
tile.WorldToLocal[0] = float4(vector1.xyz, 0.0f);
|
||||||
|
tile.WorldToLocal[1] = float4(vector2.xyz, 0.0f);
|
||||||
|
tile.WorldToLocal[2] = float4(vector3.xyz, 0.0f);
|
||||||
|
tile.WorldToLocal[3] = float4(vector1.w, vector2.w, vector3.w, 1.0f);
|
||||||
|
tile.ViewBoundsSize = vector4.xyz;
|
||||||
|
tile.Enabled = vector4.w > 0;
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
|
||||||
// Global Surface Atlas data for a constant buffer
|
// Global Surface Atlas data for a constant buffer
|
||||||
struct GlobalSurfaceAtlasData
|
struct GlobalSurfaceAtlasData
|
||||||
{
|
{
|
||||||
@@ -58,9 +79,10 @@ struct GlobalSurfaceAtlasData
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Samples the Global Surface Atlas and returns the lighting (with opacity) at the given world location (and direction).
|
// Samples the Global Surface Atlas and returns the lighting (with opacity) at the given world location (and direction).
|
||||||
float4 SampleGlobalSurfaceAtlas(const GlobalSurfaceAtlasData data, Texture2D atlas, Buffer<float4> objects, float3 worldPosition, float3 worldNormal)
|
float4 SampleGlobalSurfaceAtlas(const GlobalSurfaceAtlasData data, Buffer<float4> objects, Texture2D depth, Texture2D atlas, float3 worldPosition, float3 worldNormal)
|
||||||
{
|
{
|
||||||
float4 result = float4(0, 0, 0, 0);
|
float4 result = float4(0, 0, 0, 0);
|
||||||
|
float surfaceThreshold = 10.0f; // Additional threshold between object or tile size compared with input data (error due to SDF or LOD incorrect appearance)
|
||||||
// TODO: add grid culling to object for faster lookup
|
// TODO: add grid culling to object for faster lookup
|
||||||
LOOP
|
LOOP
|
||||||
for (uint objectIndex = 0; objectIndex < data.ObjectsCount && result.a <= 0.0f; objectIndex++)
|
for (uint objectIndex = 0; objectIndex < data.ObjectsCount && result.a <= 0.0f; objectIndex++)
|
||||||
@@ -71,16 +93,45 @@ float4 SampleGlobalSurfaceAtlas(const GlobalSurfaceAtlasData data, Texture2D atl
|
|||||||
continue;
|
continue;
|
||||||
GlobalSurfaceObject object = LoadGlobalSurfaceAtlasObject(objects, objectIndex);
|
GlobalSurfaceObject object = LoadGlobalSurfaceAtlasObject(objects, objectIndex);
|
||||||
float3 localPosition = mul(float4(worldPosition, 1), object.WorldToLocal).xyz;
|
float3 localPosition = mul(float4(worldPosition, 1), object.WorldToLocal).xyz;
|
||||||
object.Extent += 10.0f; // TODO: why SDF is so enlarged compared to actual bounds?
|
float3 localExtent = object.Extent + surfaceThreshold;
|
||||||
if (any(localPosition > object.Extent) || any(localPosition < -object.Extent))
|
if (any(localPosition > localExtent) || any(localPosition < -localExtent))
|
||||||
continue;
|
continue;
|
||||||
float3 localNormal = normalize(mul(worldNormal, (float3x3)object.WorldToLocal));
|
float3 localNormal = normalize(mul(worldNormal, (float3x3)object.WorldToLocal));
|
||||||
|
|
||||||
// TODO: select 1, 2 or 3 tiles from object that match normal vector
|
// Pick tiles to sample based on the directionality
|
||||||
// TODO: sample tiles with weight based on sample normal (reject tile if projected UVs are outside 0-1 range)
|
// TODO: sample 1/2/3 tiles with weight based on sample normal
|
||||||
|
uint tileIndex = 2;
|
||||||
|
|
||||||
|
GlobalSurfaceTile tile = LoadGlobalSurfaceAtlasTile(objects, objectIndex, tileIndex);
|
||||||
|
|
||||||
|
// Tile normal weight based on the sampling angle
|
||||||
|
float3 tileNormal = normalize(mul(worldNormal, (float3x3)tile.WorldToLocal));
|
||||||
|
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);
|
||||||
|
if (normalWeight <= 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get tile UV and depth at the world position
|
||||||
|
float3 tilePosition = mul(float4(worldPosition, 1), tile.WorldToLocal).xyz;
|
||||||
|
float tileDepth = tilePosition.z / tile.ViewBoundsSize.z;
|
||||||
|
float2 tileUV = (tilePosition.xy / tile.ViewBoundsSize.xy) + 0.5f;
|
||||||
|
tileUV.y = 1.0 - tileUV.y;
|
||||||
|
float2 atlasCoord = tileUV * tile.AtlasRect.zw + tile.AtlasRect.xy;
|
||||||
|
|
||||||
|
// Tile depth weight based on sample position occlusion
|
||||||
|
// TODO: gather 4 depth samples to smooth weight (depth weight per-sample used late for bilinear weights)
|
||||||
|
float tileZ = depth.Load(int3(atlasCoord, 0)).x;
|
||||||
|
float depthThreshold = 2.0f * surfaceThreshold / tile.ViewBoundsSize.z;
|
||||||
|
float depthWeight = 1.0f - saturate((abs(tileDepth - tileZ) - depthThreshold) / (0.5f * depthThreshold));
|
||||||
|
if (depthWeight <= 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Sample atlas texture
|
||||||
|
// TODO: separate GatherRed/Blue/Green with bilinear weights
|
||||||
|
float4 color = atlas.Load(int3(atlasCoord, 0));
|
||||||
|
|
||||||
// TODO: implement Global Surface Atlas sampling
|
// TODO: implement Global Surface Atlas sampling
|
||||||
result = float4((float)(objectIndex + 1) / (float)data.ObjectsCount, 0, 0, 1);
|
result = float4(color.rgb, 1);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,9 @@ void PS_Clear(out float4 Light : SV_Target0, out float4 RT0 : SV_Target1, out fl
|
|||||||
|
|
||||||
Texture3D<float> GlobalSDFTex[4] : register(t0);
|
Texture3D<float> GlobalSDFTex[4] : register(t0);
|
||||||
Texture3D<float> GlobalSDFMip[4] : register(t4);
|
Texture3D<float> GlobalSDFMip[4] : register(t4);
|
||||||
Texture2D GlobalSurfaceAtlasTex : register(t8);
|
Buffer<float4> GlobalSurfaceAtlasObjects : register(t8);
|
||||||
Buffer<float4> GlobalSurfaceAtlasObjects : register(t9);
|
Texture2D GlobalSurfaceAtlasDepth : register(t9);
|
||||||
|
Texture2D GlobalSurfaceAtlasTex : register(t10);
|
||||||
|
|
||||||
// Pixel shader for Global Surface Atlas debug drawing
|
// Pixel shader for Global Surface Atlas debug drawing
|
||||||
META_PS(true, FEATURE_LEVEL_SM5)
|
META_PS(true, FEATURE_LEVEL_SM5)
|
||||||
@@ -61,7 +62,7 @@ float4 PS_Debug(Quad_VS2PS input) : SV_Target
|
|||||||
//return float4(hit.HitNormal * 0.5f + 0.5f, 1);
|
//return float4(hit.HitNormal * 0.5f + 0.5f, 1);
|
||||||
|
|
||||||
// Sample Global Surface Atlas at the hit location
|
// Sample Global Surface Atlas at the hit location
|
||||||
float4 surfaceColor = SampleGlobalSurfaceAtlas(GlobalSurfaceAtlas, GlobalSurfaceAtlasTex, GlobalSurfaceAtlasObjects, hit.GetHitPosition(trace), -viewRay);
|
float4 surfaceColor = SampleGlobalSurfaceAtlas(GlobalSurfaceAtlas, GlobalSurfaceAtlasObjects, GlobalSurfaceAtlasDepth, GlobalSurfaceAtlasTex, hit.GetHitPosition(trace), -viewRay);
|
||||||
return float4(surfaceColor.rgb, 1);
|
return float4(surfaceColor.rgb, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user