feat(graphics): improve rendering pipeline and docs
- Refactor D3D12 backend and RenderGraph module - Update graphics RHI and core rendering components - Add Random.hlsl shader include - Regenerate API documentation and update user guides
This commit is contained in:
@@ -50,12 +50,11 @@ public readonly struct Result
|
||||
|
||||
public void Deconstruct(out bool success, out string? message)
|
||||
{
|
||||
success = IsSuccess;
|
||||
message = Message;
|
||||
success = _isSuccess;
|
||||
message = _message;
|
||||
}
|
||||
|
||||
public override string ToString() => IsSuccess ? "OK" : $"Error: {Message}";
|
||||
|
||||
public override string ToString() => _isSuccess ? "OK" : $"Error: {_message}";
|
||||
public static implicit operator bool(Result result) => result.IsSuccess;
|
||||
}
|
||||
|
||||
@@ -105,12 +104,12 @@ public readonly struct Result<T>
|
||||
|
||||
public void Deconstruct(out bool success, out T value, out string? message)
|
||||
{
|
||||
success = IsSuccess;
|
||||
value = Value;
|
||||
message = Message;
|
||||
success = _isSuccess;
|
||||
value = _value;
|
||||
message = _message;
|
||||
}
|
||||
|
||||
public override string ToString() => IsSuccess ? $"OK: {Value}" : $"Error: {Message}";
|
||||
public override string ToString() => _isSuccess ? $"OK: {_value}" : $"Error: {_message}";
|
||||
|
||||
public static implicit operator Result<T>(T? data) => data is not null ? Success(data) : Failure(null);
|
||||
public static implicit operator Result<T>(Result result) => result.IsSuccess ? Success(default!) : Failure(result.Message);
|
||||
@@ -179,8 +178,8 @@ public readonly struct Result<T, E>
|
||||
|
||||
public void Deconstruct(out T value, out E status)
|
||||
{
|
||||
value = Value;
|
||||
status = Error;
|
||||
value = _value;
|
||||
status = _error;
|
||||
}
|
||||
|
||||
public override string ToString() => $"Value: {_value}, Status: {_error}";
|
||||
@@ -233,11 +232,10 @@ public readonly ref struct RefResult<T, E>
|
||||
return new RefResult<T, E>(ref Unsafe.NullRef<T>(), error);
|
||||
}
|
||||
|
||||
public void Deconstruct(out bool success, out Ref<T> value, out E status)
|
||||
public void Deconstruct(out Ref<T> value, out E status)
|
||||
{
|
||||
success = IsSuccess;
|
||||
value = new Ref<T>(ref Value);
|
||||
status = Error;
|
||||
value = new Ref<T>(ref _value);
|
||||
status = _error;
|
||||
}
|
||||
|
||||
public override string ToString() => $"Value: {_value}, Status: {_error}";
|
||||
|
||||
@@ -32,42 +32,6 @@ public class RenderExtractionSystem : ISystem
|
||||
.Build(systemAPI.World, true);
|
||||
}
|
||||
|
||||
private static float3 IntersectFrustumPlanes(float4 p0, float4 p1, float4 p2)
|
||||
{
|
||||
float3 n0 = p0.xyz;
|
||||
float3 n1 = p1.xyz;
|
||||
float3 n2 = p2.xyz;
|
||||
|
||||
float det = math.dot(math.cross(n0, n1), n2);
|
||||
return (math.cross(n2, n1) * p0.w + math.cross(n0, n2) * p1.w - math.cross(n0, n1) * p2.w) * (1.0f / det);
|
||||
}
|
||||
|
||||
private static Frustum CreateFrustum(Camera camRef, float4x4 vp, float3 viewDir, float3 viewPos)
|
||||
{
|
||||
var frustum = new Frustum();
|
||||
Frustum.CalculateFrustumPlanes(vp, ref frustum.planes);
|
||||
|
||||
// We need to recalculate the near and far planes otherwise it does not work for oblique projection matrices used for reflection.
|
||||
var nearPlane = Plane.CreateFromUnitNormalAndPointInPlane(viewDir, viewPos);
|
||||
nearPlane.Distance -= camRef.nearClipPlane;
|
||||
|
||||
var farPlane = Plane.CreateFromUnitNormalAndPointInPlane(-viewDir, viewPos);
|
||||
farPlane.Distance += camRef.farClipPlane;
|
||||
|
||||
frustum.planes[4] = nearPlane;
|
||||
frustum.planes[5] = farPlane;
|
||||
|
||||
frustum.corners[0] = IntersectFrustumPlanes(frustum.planes[0], frustum.planes[3], frustum.planes[4]);
|
||||
frustum.corners[1] = IntersectFrustumPlanes(frustum.planes[1], frustum.planes[3], frustum.planes[4]);
|
||||
frustum.corners[2] = IntersectFrustumPlanes(frustum.planes[0], frustum.planes[2], frustum.planes[4]);
|
||||
frustum.corners[3] = IntersectFrustumPlanes(frustum.planes[1], frustum.planes[2], frustum.planes[4]);
|
||||
frustum.corners[4] = IntersectFrustumPlanes(frustum.planes[0], frustum.planes[3], frustum.planes[5]);
|
||||
frustum.corners[5] = IntersectFrustumPlanes(frustum.planes[1], frustum.planes[3], frustum.planes[5]);
|
||||
frustum.corners[6] = IntersectFrustumPlanes(frustum.planes[0], frustum.planes[2], frustum.planes[5]);
|
||||
frustum.corners[7] = IntersectFrustumPlanes(frustum.planes[1], frustum.planes[2], frustum.planes[5]);
|
||||
return frustum;
|
||||
}
|
||||
|
||||
public unsafe void Update(ref readonly SystemAPI systemAPI)
|
||||
{
|
||||
if (_meshQueryID.IsInvalid)
|
||||
@@ -83,15 +47,6 @@ public class RenderExtractionSystem : ISystem
|
||||
ref readonly var camRef = ref cam.Get();
|
||||
ref readonly var camLtwRef = ref camLtw.Get();
|
||||
|
||||
var rtResult = _renderSystem.GraphicsEngine.ResourceDatabase.GetResourceDescription(camRef.colorTarget.AsResource());
|
||||
if (rtResult.IsFailure)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var rtSize = new uint2(rtResult.Value.TextureDescription.Width, rtResult.Value.TextureDescription.Height);
|
||||
var aspectScreen = (float)rtSize.x / rtSize.y;
|
||||
|
||||
// TODO: Classify transparent objects into a separate render list and render via oit.
|
||||
var renderList = new RenderList(1, 64, Allocator.FreeList);
|
||||
var transparentRenderList = new RenderList(1, 64, Allocator.FreeList);
|
||||
@@ -148,70 +103,9 @@ public class RenderExtractionSystem : ISystem
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: We assume camera's scale is always (1, 1, 1). Otherwise fastinverse will fail and we need to use regular inverse which is more expensive.
|
||||
var viewMatrix = math.fastinverse(camLtwRef.matrix);
|
||||
|
||||
var vfov = 2.0f * math.atan(camRef.sensorSize.y / 2.0f * camRef.focalLength);
|
||||
var hfov = 2.0f * math.atan(camRef.sensorSize.x / 2.0f * camRef.focalLength);
|
||||
var aspectSensor = camRef.sensorSize.x / camRef.sensorSize.y;
|
||||
|
||||
float vfovF;
|
||||
switch (camRef.gateFit)
|
||||
{
|
||||
case GateFit.Vertical:
|
||||
vfovF = vfov;
|
||||
break;
|
||||
|
||||
case GateFit.Horizontal:
|
||||
// Adjust VFOV so that the sensor width fits the screen width
|
||||
var horizontalAspectBuffer = math.tan(hfov * 0.5f);
|
||||
vfovF = 2.0f * math.atan(horizontalAspectBuffer / aspectScreen);
|
||||
break;
|
||||
|
||||
case GateFit.Fill:
|
||||
if (aspectSensor > aspectScreen)
|
||||
{
|
||||
goto case GateFit.Vertical;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto case GateFit.Horizontal;
|
||||
}
|
||||
|
||||
case GateFit.Overscan:
|
||||
if (aspectSensor > aspectScreen)
|
||||
{
|
||||
goto case GateFit.Horizontal;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto case GateFit.Vertical;
|
||||
}
|
||||
default:
|
||||
vfovF = vfov;
|
||||
break;
|
||||
}
|
||||
|
||||
var m_00 = 1.0f / aspectScreen * math.tan(vfovF * 0.5f);
|
||||
var m_11 = 1.0f / math.tan(vfovF * 0.5f);
|
||||
var m_22 = -(camRef.farClipPlane + camRef.nearClipPlane) / (camRef.farClipPlane - camRef.nearClipPlane);
|
||||
var m_23 = -(2.0f * camRef.farClipPlane * camRef.nearClipPlane) / (camRef.farClipPlane - camRef.nearClipPlane);
|
||||
|
||||
var projectionMatrix = new float4x4
|
||||
(
|
||||
m_00, 0, 0, 0,
|
||||
0, m_11, 0, 0,
|
||||
0, 0, m_22, m_23,
|
||||
0, 0, -1, 0
|
||||
);
|
||||
|
||||
var vp = math.mul(projectionMatrix, viewMatrix);
|
||||
var viewDir = math.normalize(camLtwRef.matrix.c2.xyz);
|
||||
var viewPos = camLtwRef.matrix.c3.xyz;
|
||||
var frustum = CreateFrustum(camRef, vp, viewDir, viewPos);
|
||||
|
||||
var request = new RenderRequest
|
||||
{
|
||||
swapChainIndex = camRef.swapChainIndex,
|
||||
colorTarget = camRef.colorTarget,
|
||||
depthTarget = camRef.depthTarget,
|
||||
opaqueRenderList = renderList,
|
||||
@@ -220,11 +114,12 @@ public class RenderExtractionSystem : ISystem
|
||||
renderFunc = camRef.renderFunc,
|
||||
view = new RenderView
|
||||
{
|
||||
viewMatrix = viewMatrix,
|
||||
projectionMatrix = projectionMatrix,
|
||||
position = camLtwRef.matrix.c3.xyz,
|
||||
localToWorld = camLtwRef.matrix,
|
||||
//viewMatrix = viewMatrix,
|
||||
//projectionMatrix = projectionMatrix,
|
||||
//position = camLtwRef.matrix.c3.xyz,
|
||||
|
||||
frustum = frustum,
|
||||
//frustum = frustum,
|
||||
nearClipPlane = camRef.nearClipPlane,
|
||||
farClipPlane = camRef.farClipPlane,
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
public void SetScissorRect(RectDesc rect)
|
||||
public void SetScissorRect(ScissorRectDesc rect)
|
||||
{
|
||||
AssertNotDisposed();
|
||||
ThrowIfNotRecording();
|
||||
@@ -154,7 +154,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
pNativeObject->RSSetScissorRects(1, &d3d12Rect);
|
||||
}
|
||||
|
||||
public void ResourceBarrier(params ReadOnlySpan<BarrierDesc> barrierDescs)
|
||||
public void Barrier(params ReadOnlySpan<BarrierDesc> barrierDescs)
|
||||
{
|
||||
AssertNotDisposed();
|
||||
ThrowIfNotRecording();
|
||||
@@ -201,9 +201,9 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
case BarrierType.Global:
|
||||
pGlobalBarriers[globalIndex++] = new D3D12_GLOBAL_BARRIER
|
||||
{
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)desc.SyncBefore,
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)(desc.SyncBefore ?? 0),
|
||||
SyncAfter = (D3D12_BARRIER_SYNC)desc.SyncAfter,
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)desc.AccessBefore,
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)(desc.AccessBefore ?? 0),
|
||||
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter
|
||||
};
|
||||
break;
|
||||
@@ -212,7 +212,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
var r = _resourceDatabase.GetResourceRecord(desc.Resource);
|
||||
if (r.IsFailure)
|
||||
{
|
||||
RecordError(nameof(ResourceBarrier), r.Error);
|
||||
RecordError(nameof(Barrier), r.Error);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -220,9 +220,9 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
var resource = record.ResourcePtr;
|
||||
pBufferBarriers[bufferIndex++] = new D3D12_BUFFER_BARRIER
|
||||
{
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)desc.SyncBefore,
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)(desc.SyncBefore ?? record.barrierData.sync),
|
||||
SyncAfter = (D3D12_BARRIER_SYNC)desc.SyncAfter,
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)desc.AccessBefore,
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)(desc.AccessBefore ?? record.barrierData.access),
|
||||
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter,
|
||||
pResource = resource,
|
||||
Offset = 0,
|
||||
@@ -237,7 +237,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
var r = _resourceDatabase.GetResourceRecord(desc.Resource);
|
||||
if (r.IsFailure)
|
||||
{
|
||||
RecordError(nameof(ResourceBarrier), r.Error);
|
||||
RecordError(nameof(Barrier), r.Error);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -245,11 +245,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
var resource = record.ResourcePtr;
|
||||
pTextureBarriers[textureIndex++] = new D3D12_TEXTURE_BARRIER
|
||||
{
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)desc.SyncBefore,
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)(desc.SyncBefore ?? record.barrierData.sync),
|
||||
SyncAfter = (D3D12_BARRIER_SYNC)desc.SyncAfter,
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)desc.AccessBefore,
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)(desc.AccessBefore ?? record.barrierData.access),
|
||||
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter,
|
||||
LayoutBefore = (D3D12_BARRIER_LAYOUT)desc.LayoutBefore,
|
||||
LayoutBefore = (D3D12_BARRIER_LAYOUT)(desc.LayoutBefore ?? record.barrierData.layout),
|
||||
LayoutAfter = (D3D12_BARRIER_LAYOUT)desc.LayoutAfter,
|
||||
pResource = resource,
|
||||
Subresources = new D3D12_BARRIER_SUBRESOURCE_RANGE
|
||||
@@ -844,6 +844,14 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
public void UploadBuffer<T>(Handle<GraphicsBuffer> buffer, params ReadOnlySpan<T> data)
|
||||
where T : unmanaged
|
||||
{
|
||||
static void Map(T* pData, nuint size, ulong offset, SharedPtr<ID3D12Resource> resource)
|
||||
{
|
||||
void* pMappedData;
|
||||
resource.Get()->Map(0, null, &pMappedData);
|
||||
MemoryUtility.MemCpy((byte*)pMappedData + offset, pData, size);
|
||||
resource.Get()->Unmap(0, null);
|
||||
}
|
||||
|
||||
AssertNotDisposed();
|
||||
ThrowIfNotRecording();
|
||||
#if !DEBUG
|
||||
@@ -854,21 +862,33 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
#endif
|
||||
IncrementCommandCount();
|
||||
|
||||
var sizeInBytes = (uint)(data.Length * sizeof(T));
|
||||
|
||||
var uploadHandle = _resourceAllocator.CreateTempUploadBuffer(sizeInBytes, out var offset);
|
||||
var uploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
||||
|
||||
void* pMappedData;
|
||||
uploadResource.Get()->Map(0, null, &pMappedData);
|
||||
fixed (T* pData = data)
|
||||
{
|
||||
MemoryUtility.MemCpy((byte*)pMappedData + offset, pData, sizeInBytes);
|
||||
}
|
||||
uploadResource.Get()->Unmap(0, null);
|
||||
|
||||
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
|
||||
pNativeObject->CopyBufferRegion(pResource, 0, uploadResource, offset, sizeInBytes);
|
||||
|
||||
D3D12_HEAP_PROPERTIES properties;
|
||||
D3D12_HEAP_FLAGS flags;
|
||||
ThrowIfFailed(pResource.Get()->GetHeapProperties(&properties, &flags));
|
||||
|
||||
if (properties.Type == D3D12_HEAP_TYPE_UPLOAD)
|
||||
{
|
||||
fixed (T* pData = data)
|
||||
{
|
||||
Map(pData, (nuint)(data.Length * sizeof(T)), 0, pResource);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var sizeInBytes = (uint)(data.Length * sizeof(T));
|
||||
|
||||
var uploadHandle = _resourceAllocator.CreateTempUploadBuffer(sizeInBytes, out var offset);
|
||||
var uploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
||||
|
||||
fixed (T* pData = data)
|
||||
{
|
||||
Map(pData, sizeInBytes, offset, uploadResource);
|
||||
}
|
||||
|
||||
pNativeObject->CopyBufferRegion(pResource, 0, uploadResource, offset, sizeInBytes);
|
||||
}
|
||||
}
|
||||
|
||||
public void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources)
|
||||
|
||||
@@ -83,7 +83,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
{
|
||||
ShaderRegister = 0, // b0
|
||||
RegisterSpace = 0, // space0
|
||||
Num32BitValues = 4 // Global, View, Object, Material indices
|
||||
Num32BitValues = PushConstantsData.NUM_32BITS_VALUE
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ internal class D3D12Renderer : IRenderer
|
||||
}
|
||||
|
||||
//// TODO: A proper render graph integration.
|
||||
//private Error RenderScene(Handle<Texture> target, ViewportDesc viewport, RectDesc rect)
|
||||
//private Error RenderScene(Handle<Texture> target, ViewportDesc viewport, ScissorRectDesc rect)
|
||||
//{
|
||||
// // NOTE: Testing only.
|
||||
// var ctx = new RenderingContext(_graphicsEngine, _commandBuffer);
|
||||
|
||||
@@ -186,6 +186,7 @@ internal unsafe class DXGISwapChain : ISwapChain
|
||||
var presentFlags = 0u;
|
||||
var syncInterval = vsync ? 1u : 0u;
|
||||
|
||||
var i =_swapChain.Get()->GetCurrentBackBufferIndex();
|
||||
ThrowIfFailed(_swapChain.Get()->Present(syncInterval, presentFlags));
|
||||
}
|
||||
|
||||
|
||||
@@ -302,7 +302,7 @@ public struct RenderDesc
|
||||
get; set;
|
||||
}
|
||||
|
||||
public RectDesc Viewport
|
||||
public ScissorRectDesc Viewport
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
@@ -345,7 +345,7 @@ public struct ViewportDesc
|
||||
|
||||
}
|
||||
|
||||
public struct RectDesc
|
||||
public struct ScissorRectDesc
|
||||
{
|
||||
public uint Left
|
||||
{
|
||||
@@ -539,7 +539,7 @@ public struct BarrierDesc
|
||||
get; set;
|
||||
}
|
||||
|
||||
public BarrierSync SyncBefore
|
||||
public BarrierSync? SyncBefore
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
@@ -549,7 +549,7 @@ public struct BarrierDesc
|
||||
get; set;
|
||||
}
|
||||
|
||||
public BarrierAccess AccessBefore
|
||||
public BarrierAccess? AccessBefore
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
@@ -559,7 +559,7 @@ public struct BarrierDesc
|
||||
get; set;
|
||||
}
|
||||
|
||||
public BarrierLayout LayoutBefore
|
||||
public BarrierLayout? LayoutBefore
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
@@ -596,7 +596,7 @@ public struct BarrierDesc
|
||||
};
|
||||
}
|
||||
|
||||
public static BarrierDesc Buffer(Handle<GPUResource> resource, BarrierSync syncBefore, BarrierSync syncAfter, BarrierAccess accessBefore, BarrierAccess accessAfter)
|
||||
public static BarrierDesc Buffer(Handle<GPUResource> resource, BarrierSync? syncBefore, BarrierSync syncAfter, BarrierAccess? accessBefore, BarrierAccess accessAfter)
|
||||
{
|
||||
return new BarrierDesc
|
||||
{
|
||||
@@ -609,7 +609,7 @@ public struct BarrierDesc
|
||||
};
|
||||
}
|
||||
|
||||
public static BarrierDesc Texture(Handle<GPUResource> resource, BarrierSync syncBefore, BarrierSync syncAfter, BarrierAccess accessBefore, BarrierAccess accessAfter, BarrierLayout layoutBefore, BarrierLayout layoutAfter, BarrierSubresourceRange subresources = default, bool discard = false)
|
||||
public static BarrierDesc Texture(Handle<GPUResource> resource, BarrierSync? syncBefore, BarrierSync syncAfter, BarrierAccess? accessBefore, BarrierAccess accessAfter, BarrierLayout? layoutBefore, BarrierLayout layoutAfter, BarrierSubresourceRange subresources = default, bool discard = false)
|
||||
{
|
||||
return new BarrierDesc
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ public interface ICommandBuffer : IDisposable
|
||||
/// Sets the scissor rectangle
|
||||
/// </summary>
|
||||
/// <param name="rect">Scissor rectangle to set</param>
|
||||
void SetScissorRect(RectDesc rect);
|
||||
void SetScissorRect(ScissorRectDesc rect);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the optional render targets and optional depth Target for subsequent rendering operations.
|
||||
@@ -99,7 +99,7 @@ public interface ICommandBuffer : IDisposable
|
||||
/// Inserts multiple resource barriers.
|
||||
/// </summary>
|
||||
/// <param name="barrierDescs">Resource barrier descriptions</param>
|
||||
void ResourceBarrier(params ReadOnlySpan<BarrierDesc> barrierDescs);
|
||||
void Barrier(params ReadOnlySpan<BarrierDesc> barrierDescs);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the pipeline state object
|
||||
|
||||
@@ -9,7 +9,7 @@ public interface IRenderOutput
|
||||
get; set;
|
||||
}
|
||||
|
||||
RectDesc Scissor
|
||||
ScissorRectDesc Scissor
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
@@ -10,23 +10,22 @@ public static class RootSignatureLayout
|
||||
public const int ROOT_PARAMETER_COUNT = 1;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 20)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||
public struct PushConstantsData
|
||||
{
|
||||
public uint globalIndex;
|
||||
public uint viewIndex;
|
||||
public uint objectIndex;
|
||||
public const uint NUM_32BITS_VALUE = 16u / sizeof(uint);
|
||||
|
||||
public uint frameBuffer;
|
||||
public uint viewBuffer;
|
||||
public uint instanceBuffer;
|
||||
public uint instanceIndex;
|
||||
public uint materialIndex;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 20)]
|
||||
public struct GlobalFrameData
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FrameData
|
||||
{
|
||||
public uint viewBufferIndex;
|
||||
public uint instanceBufferIndex;
|
||||
public uint viewBufferCount;
|
||||
public uint instanceBufferCount;
|
||||
public uint userBufferIndex;
|
||||
}
|
||||
|
||||
@@ -34,10 +33,12 @@ public struct GlobalFrameData
|
||||
public struct InstanceData
|
||||
{
|
||||
public float4x4 localToWorld;
|
||||
public uint meshBufferIndex;
|
||||
public uint materialBufferIndex;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct PerViewData
|
||||
public struct ViewData
|
||||
{
|
||||
public float4x4 viewMatrix;
|
||||
public float4x4 projectionMatrix;
|
||||
@@ -49,7 +50,7 @@ public struct PerViewData
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct PerObjectData
|
||||
public struct MeshData
|
||||
{
|
||||
public float3 worldBoundsMin;
|
||||
public uint vertexBuffer;
|
||||
|
||||
@@ -265,7 +265,7 @@ public struct Material : IResourceReleasable
|
||||
barrierData.access,
|
||||
BarrierAccess.CopyDest);
|
||||
|
||||
cmd.ResourceBarrier(desc);
|
||||
cmd.Barrier(desc);
|
||||
cmd.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan());
|
||||
|
||||
desc = BarrierDesc.Buffer(
|
||||
@@ -275,7 +275,7 @@ public struct Material : IResourceReleasable
|
||||
BarrierAccess.CopyDest,
|
||||
BarrierAccess.ShaderResource);
|
||||
|
||||
cmd.ResourceBarrier(desc);
|
||||
cmd.Barrier(desc);
|
||||
}
|
||||
|
||||
public void ReleaseResource(IResourceDatabase database)
|
||||
|
||||
@@ -55,6 +55,7 @@ public struct MeshletMeshData : IDisposable
|
||||
public UnsafeList<MeshletHierarchyNode> hierarchyNodes;
|
||||
public UnsafeList<uint> meshletVertices;
|
||||
public UnsafeList<uint> meshletTriangles;
|
||||
public int meshletCount;
|
||||
public int lodLevelCount;
|
||||
public int materialSlotCount;
|
||||
|
||||
@@ -236,6 +237,8 @@ public struct Mesh : IResourceReleasable
|
||||
|
||||
// 3. Build
|
||||
MeshletUtility.Build(config, clodMesh, Unsafe.AsPointer(ref this), MeshletOutputCallback);
|
||||
|
||||
_meshletData.meshletCount = _meshletData.meshlets.Count;
|
||||
}
|
||||
|
||||
private static unsafe int MeshletOutputCallback(void* context, ClodGroup group, ReadOnlyUnsafeCollection<ClodCluster> clusters)
|
||||
|
||||
@@ -12,7 +12,7 @@ internal class SwapChainRenderOutput : IRenderOutput
|
||||
get; set;
|
||||
}
|
||||
|
||||
public RectDesc Scissor
|
||||
public ScissorRectDesc Scissor
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
@@ -22,7 +22,7 @@ internal class SwapChainRenderOutput : IRenderOutput
|
||||
_swapChain = swapChain;
|
||||
|
||||
Viewport = new ViewportDesc { Width = swapChain.Width, Height = swapChain.Height, MinDepth = 0, MaxDepth = 1 };
|
||||
Scissor = new RectDesc { Right = swapChain.Width, Bottom = swapChain.Height };
|
||||
Scissor = new ScissorRectDesc { Right = swapChain.Width, Bottom = swapChain.Height };
|
||||
}
|
||||
|
||||
public Handle<Texture> GetRenderTarget()
|
||||
@@ -37,7 +37,7 @@ internal class SwapChainRenderOutput : IRenderOutput
|
||||
BarrierAccess.NoAccess, BarrierAccess.RenderTarget,
|
||||
BarrierLayout.Present, BarrierLayout.RenderTarget);
|
||||
|
||||
cmd.ResourceBarrier(barrierDesc);
|
||||
cmd.Barrier(barrierDesc);
|
||||
}
|
||||
|
||||
public void EndRender(ICommandBuffer cmd)
|
||||
@@ -47,7 +47,7 @@ internal class SwapChainRenderOutput : IRenderOutput
|
||||
BarrierAccess.RenderTarget, BarrierAccess.NoAccess,
|
||||
BarrierLayout.RenderTarget, BarrierLayout.Present);
|
||||
|
||||
cmd.ResourceBarrier(barrierDesc);
|
||||
cmd.Barrier(barrierDesc);
|
||||
}
|
||||
|
||||
public void Present()
|
||||
@@ -65,7 +65,7 @@ internal class TextureRenderOutput : IRenderOutput
|
||||
get; set;
|
||||
}
|
||||
|
||||
public RectDesc Scissor
|
||||
public ScissorRectDesc Scissor
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
@@ -157,11 +157,12 @@ public struct Frustum
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct RenderView
|
||||
{
|
||||
public float4x4 viewMatrix;
|
||||
public float4x4 projectionMatrix;
|
||||
public float3 position;
|
||||
public float4x4 localToWorld;
|
||||
//public float4x4 viewMatrix;
|
||||
//public float4x4 projectionMatrix;
|
||||
//public float3 position;
|
||||
|
||||
public Frustum frustum; // 192 bytes
|
||||
//public Frustum frustum; // 192 bytes
|
||||
public float nearClipPlane;
|
||||
public float farClipPlane;
|
||||
|
||||
@@ -181,6 +182,7 @@ public unsafe struct RenderRequest: IDisposable
|
||||
{
|
||||
public RenderView view;
|
||||
|
||||
public int swapChainIndex;
|
||||
public Handle<Texture> colorTarget;
|
||||
public Handle<Texture> depthTarget;
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ public readonly unsafe ref struct RenderingContext
|
||||
data.access, newAccess);
|
||||
}
|
||||
|
||||
_directCmd.ResourceBarrier(new ReadOnlySpan<BarrierDesc>(in desc));
|
||||
_directCmd.Barrier(new ReadOnlySpan<BarrierDesc>(in desc));
|
||||
ResourceDatabase.SetResourceBarrierData(resource, new ResourceBarrierData(newLayout, newAccess, newSync));
|
||||
}
|
||||
|
||||
@@ -103,14 +103,14 @@ public readonly unsafe ref struct RenderingContext
|
||||
_directCmd.UploadBuffer(meshData.VertexBuffer, meshData.Vertices.AsSpan());
|
||||
_directCmd.UploadBuffer(meshData.IndexBuffer, meshData.Indices.AsSpan());
|
||||
|
||||
TransitionBarrier(vertexHandle, false, BarrierLayout.Undefined, BarrierAccess.ShaderResource, BarrierSync.VertexShading);
|
||||
TransitionBarrier(indexHandle, false, BarrierLayout.Undefined, BarrierAccess.IndexBuffer, BarrierSync.IndexInput);
|
||||
|
||||
if (staticMesh)
|
||||
{
|
||||
meshData.CookMeshlets();
|
||||
meshData.ReleaseCpuResources();
|
||||
TransitionBarrier(vertexHandle, false, BarrierLayout.Undefined, BarrierAccess.ShaderResource, BarrierSync.VertexShading);
|
||||
TransitionBarrier(indexHandle, false, BarrierLayout.Undefined, BarrierAccess.IndexBuffer, BarrierSync.IndexInput);
|
||||
|
||||
UploadMeshlets(mesh);
|
||||
meshData.ReleaseCpuResources();
|
||||
}
|
||||
|
||||
return mesh;
|
||||
@@ -142,7 +142,7 @@ public readonly unsafe ref struct RenderingContext
|
||||
return;
|
||||
}
|
||||
|
||||
ref readonly var meshRef = ref r.Value;
|
||||
ref var meshRef = ref r.Value;
|
||||
var vertexHandle = meshRef.VertexBuffer.AsResource();
|
||||
var indexHandle = meshRef.IndexBuffer.AsResource();
|
||||
|
||||
@@ -224,7 +224,7 @@ public readonly unsafe ref struct RenderingContext
|
||||
}
|
||||
|
||||
ref readonly var meshData = ref r.Value;
|
||||
var data = new PerObjectData
|
||||
var data = new MeshData
|
||||
{
|
||||
worldBoundsMin = meshData.BoundingBox.Min,
|
||||
worldBoundsMax = meshData.BoundingBox.Max,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.RHI;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ghost.Graphics.RenderGraphModule;
|
||||
|
||||
@@ -111,6 +112,7 @@ public sealed class RenderGraph : IDisposable
|
||||
var r = _resourceDatabase.GetResourceDescription(texture.AsResource());
|
||||
if (r.IsFailure)
|
||||
{
|
||||
Debug.Fail("Failed to get resource description for texture handle: " + texture);
|
||||
return Identifier<RGTexture>.Invalid;
|
||||
}
|
||||
|
||||
@@ -128,6 +130,7 @@ public sealed class RenderGraph : IDisposable
|
||||
var r = _resourceDatabase.GetResourceDescription(buffer.AsResource());
|
||||
if (r.IsFailure)
|
||||
{
|
||||
Debug.Fail("Failed to get resource description for buffer handle: " + buffer);
|
||||
return Identifier<RGBuffer>.Invalid;
|
||||
}
|
||||
|
||||
@@ -177,7 +180,7 @@ public sealed class RenderGraph : IDisposable
|
||||
/// <summary>
|
||||
/// Compiles the render graph by culling unused passes and determining resource lifetimes.
|
||||
/// </summary>
|
||||
public Error Compile(in ViewState viewState)
|
||||
public Error Compile(ViewState viewState)
|
||||
{
|
||||
if (_compiled)
|
||||
{
|
||||
|
||||
@@ -343,6 +343,11 @@ internal class RenderGraphBuilder : IRasterRenderGraphBuilder, IComputeRenderGra
|
||||
throw new InvalidOperationException("RenderGraphBuilder must be disposed after setting up the render function.");
|
||||
}
|
||||
|
||||
if (_pass.type == RenderPassType.Raster && _pass.colorAccess[0].id.IsInvalid && _pass.depthAccess.id.IsInvalid)
|
||||
{
|
||||
throw new InvalidOperationException("Raster render pass must have at least one color or depth attachment.");
|
||||
}
|
||||
|
||||
_graph = null!;
|
||||
_pass = null!;
|
||||
_resources = null!;
|
||||
|
||||
@@ -16,13 +16,17 @@ public interface IRenderGraphContext
|
||||
|
||||
Handle<Texture> GetHistoryTexture(ReadOnlySpan<Identifier<RGTexture>> texture, int historyOffset);
|
||||
Handle<GraphicsBuffer> GetHistoryBuffer(ReadOnlySpan<Identifier<RGBuffer>> buffer, int historyOffset);
|
||||
|
||||
ICommandBuffer GetCommandBufferUnsafe();
|
||||
}
|
||||
|
||||
public interface IRasterRenderContext : IRenderGraphContext
|
||||
{
|
||||
int ActiveMeshIndexCount { get; }
|
||||
void SetViewport(ViewportDesc desc);
|
||||
void SetScissorRect(ScissorRectDesc desc);
|
||||
|
||||
void SetGlobalData(uint globalIndex, uint viewIndex);
|
||||
void SetInstanceData(uint instanceBuffer);
|
||||
void SetInstanceIndex(uint instanceIndex);
|
||||
|
||||
void SetActiveMaterial(Handle<Material> material);
|
||||
@@ -37,12 +41,11 @@ public interface IComputeRenderContext : IRenderGraphContext
|
||||
void DispatchCompute(uint3 threadGroupCount);
|
||||
}
|
||||
|
||||
public interface IUnsafeRenderContext : IRasterRenderContext, IRenderGraphContext
|
||||
public interface IUnsafeRenderContext : IRasterRenderContext, IComputeRenderContext
|
||||
{
|
||||
ICommandBuffer CommandBuffer { get; }
|
||||
}
|
||||
|
||||
internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderContext, IUnsafeRenderContext
|
||||
internal sealed class RenderGraphContext : IUnsafeRenderContext
|
||||
{
|
||||
private readonly ResourceManager _resourceManager;
|
||||
private readonly IResourceDatabase _resourceDatabase;
|
||||
@@ -61,8 +64,9 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
||||
private Handle<GraphicsBuffer> _activePerMeshData;
|
||||
private int _activeMeshIndexCount;
|
||||
|
||||
private uint _activeGlobalIndex;
|
||||
private uint _activeViewIndex;
|
||||
private uint _activeFrameBuffer;
|
||||
private uint _activeViewBuffer;
|
||||
private uint _activeInstanceBuffer;
|
||||
private uint _activeInstanceIndex;
|
||||
|
||||
public ResourceManager ResourceManager => _resourceManager;
|
||||
@@ -70,8 +74,6 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
||||
|
||||
public int ActiveMeshIndexCount => _activeMeshIndexCount;
|
||||
|
||||
public ICommandBuffer CommandBuffer => _commandBuffer;
|
||||
|
||||
internal RenderGraphContext(ResourceManager resourceManager, IResourceDatabase resourceDatabase, IPipelineLibrary pipelineLibrary, IShaderCompiler shaderCompiler, RenderGraphResourceRegistry resources)
|
||||
{
|
||||
_resourceManager = resourceManager;
|
||||
@@ -105,6 +107,11 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
||||
|
||||
public Handle<GPUResource> GetActualResource(Identifier<RGResource> resource)
|
||||
{
|
||||
if (resource.IsInvalid)
|
||||
{
|
||||
return Handle<GPUResource>.Invalid;
|
||||
}
|
||||
|
||||
return _resources.GetResource(resource).backingResource;
|
||||
}
|
||||
|
||||
@@ -150,6 +157,16 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
||||
return GetActualBuffer(buffers[index]);
|
||||
}
|
||||
|
||||
public void SetViewport(ViewportDesc desc)
|
||||
{
|
||||
_commandBuffer.SetViewport(desc);
|
||||
}
|
||||
|
||||
public void SetScissorRect(ScissorRectDesc desc)
|
||||
{
|
||||
_commandBuffer.SetScissorRect(desc);
|
||||
}
|
||||
|
||||
public void SetActiveMaterial(Handle<Material> material)
|
||||
{
|
||||
var r = _resourceManager.GetMaterialReference(material);
|
||||
@@ -228,10 +245,15 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
||||
_activeMeshIndexCount = mesh.IndexCount;
|
||||
}
|
||||
|
||||
public void SetGlobalData(uint globalIndex, uint viewIndex)
|
||||
public void SetGlobalData(uint frameBuffer, uint viewBuffer)
|
||||
{
|
||||
_activeGlobalIndex = globalIndex;
|
||||
_activeViewIndex = viewIndex;
|
||||
_activeFrameBuffer = frameBuffer;
|
||||
_activeViewBuffer = viewBuffer;
|
||||
}
|
||||
|
||||
public void SetInstanceData(uint instanceBuffer)
|
||||
{
|
||||
_activeInstanceBuffer = instanceBuffer;
|
||||
}
|
||||
|
||||
public void SetInstanceIndex(uint instanceIndex)
|
||||
@@ -241,14 +263,12 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
||||
|
||||
public unsafe void DispatchMesh(uint3 threadGroupCount)
|
||||
{
|
||||
// TODO: Global, view, and instance constants
|
||||
var data = new PushConstantsData
|
||||
{
|
||||
globalIndex = _activeGlobalIndex,
|
||||
viewIndex = _activeViewIndex,
|
||||
objectIndex = _resourceDatabase.GetBindlessIndex(_activePerMeshData.AsResource()),
|
||||
frameBuffer = _activeFrameBuffer,
|
||||
viewBuffer = _activeViewBuffer,
|
||||
instanceBuffer = _activeInstanceBuffer,
|
||||
instanceIndex = _activeInstanceIndex,
|
||||
materialIndex = _resourceDatabase.GetBindlessIndex(_activePerMaterialData.AsResource()),
|
||||
};
|
||||
|
||||
var pushConstantSpan = new ReadOnlySpan<uint>(&data, sizeof(PushConstantsData) / sizeof(uint));
|
||||
@@ -260,4 +280,10 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public ICommandBuffer GetCommandBufferUnsafe()
|
||||
{
|
||||
return _commandBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.RHI;
|
||||
using System.Diagnostics;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
namespace Ghost.Graphics.RenderGraphModule;
|
||||
|
||||
@@ -24,6 +26,59 @@ internal sealed class RenderGraphExecutor
|
||||
_context = context;
|
||||
}
|
||||
|
||||
private void SetViewport(ReadOnlySpan<RenderTargetInfo> color, DepthStencilInfo depthStencil)
|
||||
{
|
||||
// This should not happened since the compiler should have rejected any render pass with an invalid render target configuration, but just in case, we use Debug.Assert to validate our assumptions.
|
||||
Debug.Assert(color.Length > 0 || depthStencil.texture.IsValid);
|
||||
|
||||
ViewportDesc viewportDesc = default;
|
||||
ScissorRectDesc scissorDesc = default;
|
||||
|
||||
if (depthStencil.texture.IsValid)
|
||||
{
|
||||
viewportDesc = new ViewportDesc
|
||||
{
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Width = _resources.GetResource(depthStencil.texture).resolvedWidth,
|
||||
Height = _resources.GetResource(depthStencil.texture).resolvedHeight,
|
||||
MinDepth = 0,
|
||||
MaxDepth = 1
|
||||
};
|
||||
|
||||
scissorDesc = new ScissorRectDesc
|
||||
{
|
||||
Left = 0,
|
||||
Top = 0,
|
||||
Right = (uint)viewportDesc.Width,
|
||||
Bottom = (uint)viewportDesc.Height
|
||||
};
|
||||
}
|
||||
else if (color[0].texture.IsValid)
|
||||
{
|
||||
viewportDesc = new ViewportDesc
|
||||
{
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Width = _resources.GetResource(color[0].texture).resolvedWidth,
|
||||
Height = _resources.GetResource(color[0].texture).resolvedHeight,
|
||||
MinDepth = 0,
|
||||
MaxDepth = 1
|
||||
};
|
||||
|
||||
scissorDesc = new ScissorRectDesc
|
||||
{
|
||||
Left = 0,
|
||||
Top = 0,
|
||||
Right = (uint)viewportDesc.Width,
|
||||
Bottom = (uint)viewportDesc.Height
|
||||
};
|
||||
}
|
||||
|
||||
_context.SetViewport(viewportDesc);
|
||||
_context.SetScissorRect(scissorDesc);
|
||||
}
|
||||
|
||||
public unsafe Error Execute(
|
||||
ICommandBuffer commandBuffer,
|
||||
List<RenderGraphPassBase> compiledPasses,
|
||||
@@ -60,6 +115,9 @@ internal sealed class RenderGraphExecutor
|
||||
}
|
||||
|
||||
// Begin native render pass
|
||||
|
||||
SetViewport(nativePass.colorAttachments, nativePass.depthAttachment);
|
||||
|
||||
for (var i = 0; i < nativePass.colorAttachmentCount; i++)
|
||||
{
|
||||
var attachment = nativePass.colorAttachments[i];
|
||||
@@ -121,7 +179,10 @@ internal sealed class RenderGraphExecutor
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute pass or standalone raster pass (not merged) or Unsafe pass
|
||||
// All the reaster pass should be merged into native render pass, so if we encounter a raster pass here, it means something went wrong during compilation.
|
||||
Debug.Assert(pass.type != RenderPassType.Raster);
|
||||
|
||||
// Compute pass or Unsafe pass
|
||||
var e = ExecuteBarriersForPass(commandBuffer, logicalPassIndex, ref barrierIndex, compiledBarriers);
|
||||
if (e != Error.None)
|
||||
{
|
||||
@@ -150,7 +211,7 @@ internal sealed class RenderGraphExecutor
|
||||
{
|
||||
if (barrierCount > 0)
|
||||
{
|
||||
cmd.ResourceBarrier(new ReadOnlySpan<BarrierDesc>(barriers, barrierCount));
|
||||
cmd.Barrier(new ReadOnlySpan<BarrierDesc>(barriers, barrierCount));
|
||||
barrierCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,19 +6,21 @@ struct PixelInput
|
||||
float4 position : SV_POSITION;
|
||||
float4 color : COLOR;
|
||||
float4 uv : TEXCOORD0;
|
||||
nointerpolation uint meshletID : MESHLET_ID;
|
||||
};
|
||||
|
||||
[numthreads(128, 1, 1)] // 128 threads to cover max 64 vertices and 124 triangles
|
||||
[outputtopology("triangle")]
|
||||
void MSMain(
|
||||
uint3 groupThreadID : SV_GroupThreadID,
|
||||
uint groupID : SV_GroupID,
|
||||
uint3 groupID : SV_GroupID,
|
||||
out vertices PixelInput outVerts[64],
|
||||
out indices uint3 outTris[124])
|
||||
{
|
||||
PerObjectData perObjectData = LoadData<PerObjectData>(g_PushConstantData.perObjectBuffer, 0);
|
||||
InstanceData instanceData = LoadData<InstanceData>(g_PushConstantData.instanceBuffer, g_PushConstantData.instanceIndex);
|
||||
MeshData meshData = LoadData<MeshData>(instanceData.meshBuffer, 0);
|
||||
|
||||
ByteAddressBuffer meshletBuffer = GET_BUFFER(perObjectData.meshletBuffer);
|
||||
ByteAddressBuffer meshletBuffer = GET_BUFFER(meshData.meshletBuffer);
|
||||
Meshlet m = meshletBuffer.Load<Meshlet>(groupID.x * sizeof(Meshlet));
|
||||
|
||||
uint vertexCount = m.packedCounts & 0xFF;
|
||||
@@ -26,26 +28,27 @@ void MSMain(
|
||||
|
||||
SetMeshOutputCounts(vertexCount, triangleCount);
|
||||
|
||||
ByteAddressBuffer meshletVerticesBuffer = GET_BUFFER(perObjectData.meshletVerticesBuffer);
|
||||
ByteAddressBuffer meshletTrianglesBuffer = GET_BUFFER(perObjectData.meshletTrianglesBuffer);
|
||||
ByteAddressBuffer meshletVerticesBuffer = GET_BUFFER(meshData.meshletVerticesBuffer);
|
||||
ByteAddressBuffer meshletTrianglesBuffer = GET_BUFFER(meshData.meshletTrianglesBuffer);
|
||||
|
||||
// Write vertex output
|
||||
if (groupThreadID.x < vertexCount)
|
||||
{
|
||||
uint vertexIndex = meshletVerticesBuffer.Load((m.vertexOffset + groupThreadID.x) * 4);
|
||||
ByteAddressBuffer vertices = GET_BUFFER(perObjectData.vertexBuffer);
|
||||
ByteAddressBuffer vertices = GET_BUFFER(meshData.vertexBuffer);
|
||||
Vertex v = vertices.Load<Vertex>(vertexIndex * sizeof(Vertex));
|
||||
|
||||
// Basic MVP transform not needed if already in world space, but usually we need localToWorld and ViewProj
|
||||
PerViewData perViewData = LoadData<PerViewData>(g_PushConstantData.perViewBuffer, 0);
|
||||
PerInstanceData perInstanceData = LoadData<PerInstanceData>(g_PushConstantData.perInstanceBuffer, 0);
|
||||
FrameData globalFrameData = LoadData<FrameData>(g_PushConstantData.frameBuffer, 0);
|
||||
ViewData viewData = LoadData<ViewData>(g_PushConstantData.viewBuffer, 0);
|
||||
|
||||
float4 worldPos = mul(perInstanceData.localToWorld, float4(v.position.xyz, 1.0f));
|
||||
outVerts[groupThreadID.x].position = mul(perViewData.viewMatrix, worldPos);
|
||||
outVerts[groupThreadID.x].position = mul(perViewData.projectionMatrix, outVerts[groupThreadID.x].position);
|
||||
float4 worldPos = mul(instanceData.localToWorld, float4(v.position.xyz, 1.0f));
|
||||
float4 viewPos = mul(viewData.viewMatrix, worldPos);
|
||||
|
||||
outVerts[groupThreadID.x].position = mul(viewData.projectionMatrix, viewPos);
|
||||
|
||||
outVerts[groupThreadID.x].color = v.color;
|
||||
outVerts[groupThreadID.x].uv = v.uv;
|
||||
outVerts[groupThreadID.x].meshletID = groupID.x;
|
||||
}
|
||||
|
||||
// Write triangle output (1 thread processes 1 triangle)
|
||||
@@ -66,7 +69,7 @@ void MSMain(
|
||||
|
||||
float4 PSMain(PixelInput input) : SV_TARGET
|
||||
{
|
||||
// PerMaterialData perMaterialData = LoadData<PerMaterialData>(g_PushConstantData.perMaterialBuffer, 0);
|
||||
// PerMaterialData perMaterialData = LoadData<PerMaterialData>(g_PushConstantData.materialIndex, 0);
|
||||
//
|
||||
// float4 color1 = SAMPLE_TEXTURE2D(perMaterialData.texture1, perMaterialData.tex_sampler, input.uv.xy);
|
||||
// float4 color2 = SAMPLE_TEXTURE2D(perMaterialData.texture2, perMaterialData.tex_sampler, input.uv.xy);
|
||||
@@ -75,4 +78,14 @@ float4 PSMain(PixelInput input) : SV_TARGET
|
||||
//
|
||||
// float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
|
||||
// return perMaterialData.color * blendedColor + input.color;
|
||||
}
|
||||
|
||||
// TODO: Randome color on meshlet.
|
||||
// return float4(1, 0, 0, 1);
|
||||
uint hash = PCGHash(input.meshletID);
|
||||
|
||||
float r = float((hash & 0xFF0000u) >> 16) / 255.0;
|
||||
float g = float((hash & 0x00FF00u) >> 8) / 255.0;
|
||||
float b = float((hash & 0x0000FFu)) / 255.0;
|
||||
|
||||
return float4(r, g, b, 1.0);
|
||||
}
|
||||
@@ -68,7 +68,7 @@ public class RenderSystem : IDisposable
|
||||
[UnscopedRef]
|
||||
public ref UnsafeList<RenderRequest> RenderRequests => ref _renderRequests;
|
||||
|
||||
public void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
CpuReadyEvent.Dispose();
|
||||
GpuReadyEvent.Dispose();
|
||||
@@ -87,6 +87,7 @@ public class RenderSystem : IDisposable
|
||||
|
||||
private readonly IGraphicsEngine _graphicsEngine;
|
||||
private readonly ResourceManager _resourceManager;
|
||||
private readonly SwapChainManager _swapChainManager;
|
||||
|
||||
private readonly FrameResource[] _frameResources;
|
||||
private readonly Thread _renderThread;
|
||||
@@ -104,6 +105,8 @@ public class RenderSystem : IDisposable
|
||||
private bool _isRunning;
|
||||
private bool _disposed;
|
||||
|
||||
internal SwapChainManager SwapChainManager => _swapChainManager;
|
||||
|
||||
public IGraphicsEngine GraphicsEngine => _graphicsEngine;
|
||||
public ResourceManager ResourceManager => _resourceManager;
|
||||
public bool IsRunning => _isRunning;
|
||||
@@ -161,6 +164,7 @@ public class RenderSystem : IDisposable
|
||||
}
|
||||
|
||||
_resourceManager = new ResourceManager(_graphicsEngine.ResourceAllocator, _graphicsEngine.ResourceDatabase);
|
||||
_swapChainManager = new SwapChainManager(_graphicsEngine);
|
||||
|
||||
// Create frame resources for synchronization
|
||||
_frameResources = new FrameResource[desc.FrameBufferCount];
|
||||
@@ -280,6 +284,7 @@ public class RenderSystem : IDisposable
|
||||
|
||||
// TODO: How can we support async compute and async copy?
|
||||
var cmd = _graphicsEngine.GetPooledCommandBuffer(CommandBufferType.Graphics);
|
||||
ref var renderRequests = ref frameResource.RenderRequests;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -290,8 +295,8 @@ public class RenderSystem : IDisposable
|
||||
CommandBuffer = cmd
|
||||
};
|
||||
|
||||
ref var renderRequests = ref frameResource.RenderRequests;
|
||||
_renderPipeline.Render(renderCtx, renderRequests.AsSpan());
|
||||
_swapChainManager.TransitionToPresent(cmd);
|
||||
|
||||
// End recording commands and submit
|
||||
r = cmd.End();
|
||||
@@ -302,6 +307,11 @@ public class RenderSystem : IDisposable
|
||||
}
|
||||
|
||||
_graphicsEngine.Device.GraphicsQueue.Submit(cmd);
|
||||
_swapChainManager.PresentAll(cmd);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_graphicsEngine.ReturnPooledCommandBuffer(cmd);
|
||||
|
||||
for (var i = 0; i < renderRequests.Count; i++)
|
||||
{
|
||||
@@ -310,10 +320,6 @@ public class RenderSystem : IDisposable
|
||||
|
||||
renderRequests.Clear();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_graphicsEngine.ReturnPooledCommandBuffer(cmd);
|
||||
}
|
||||
|
||||
// End the frame and present
|
||||
_resourceManager.EndFrame(_cpuFenceValue);
|
||||
@@ -325,9 +331,6 @@ public class RenderSystem : IDisposable
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Present here.
|
||||
|
||||
|
||||
// Prepare for the next frame.
|
||||
_gpuFenceValue++;
|
||||
|
||||
@@ -415,13 +418,15 @@ public class RenderSystem : IDisposable
|
||||
|
||||
Stop();
|
||||
|
||||
for (int i = 0; i < _frameResources.Length; i++)
|
||||
for (var i = 0; i < _frameResources.Length; i++)
|
||||
{
|
||||
ref var frameResource = ref _frameResources[i];
|
||||
frameResource.Dispose();
|
||||
}
|
||||
|
||||
_renderPipeline.Dispose();
|
||||
|
||||
_swapChainManager.Dispose();
|
||||
_resourceManager.Dispose();
|
||||
_graphicsEngine.Dispose();
|
||||
_shutdownEvent.Dispose();
|
||||
|
||||
@@ -112,8 +112,8 @@ public sealed class ResourceManager : IDisposable
|
||||
|
||||
var objectBufferDesc = new BufferDesc
|
||||
{
|
||||
Size = (uint)sizeof(PerObjectData),
|
||||
Stride = (uint)sizeof(PerObjectData),
|
||||
Size = (uint)sizeof(MeshData),
|
||||
Stride = (uint)sizeof(MeshData),
|
||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BUILTIN_COMMON_HLSL
|
||||
#define BUILTIN_COMMON_HLSL
|
||||
#ifndef GHOST_COMMON_HLSL
|
||||
#define GHOST_COMMON_HLSL
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
@@ -104,4 +104,4 @@ static inline T LoadData(BYTE_ADDRESS_BUFFER buffer, uint index)
|
||||
return buf.Load<T>(index * sizeof(T));
|
||||
}
|
||||
|
||||
#endif // BUILTIN_COMMON_HLSL
|
||||
#endif // GHOST_COMMON_HLSL
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
#ifndef BUILTIN_PROPERTIES_HLSL
|
||||
#define BUILTIN_PROPERTIES_HLSL
|
||||
#ifndef GHOST_PROPERTIES_HLSL
|
||||
#define GHOST_PROPERTIES_HLSL
|
||||
|
||||
#include "F:/csharp/GhostEngine/src/Runtime/Ghost.Graphics/Shaders/Includes/Common.hlsl"
|
||||
|
||||
// TODO: This should be auto generated to match the c# side.
|
||||
|
||||
struct PushConstantData
|
||||
{
|
||||
uint globalIndex;
|
||||
uint viewIndex;
|
||||
uint objectIndex;
|
||||
BYTE_ADDRESS_BUFFER frameBuffer;
|
||||
BYTE_ADDRESS_BUFFER viewBuffer;
|
||||
BYTE_ADDRESS_BUFFER instanceBuffer;
|
||||
uint instanceIndex;
|
||||
uint materialIndex;
|
||||
};
|
||||
|
||||
struct GlobalFrameData
|
||||
struct FrameData
|
||||
{
|
||||
uint viewBufferIndex;
|
||||
uint instanceBufferIndex;
|
||||
uint viewBufferCount;
|
||||
uint instanceBufferCount;
|
||||
uint userBufferIndex;
|
||||
BYTE_ADDRESS_BUFFER viewBuffer;
|
||||
BYTE_ADDRESS_BUFFER instanceBuffer;
|
||||
BYTE_ADDRESS_BUFFER userBuffer;
|
||||
};
|
||||
|
||||
struct PerViewData
|
||||
struct ViewData
|
||||
{
|
||||
float4x4 viewMatrix;
|
||||
float4x4 projectionMatrix;
|
||||
@@ -32,17 +31,20 @@ struct PerViewData
|
||||
float4 screenSize; // xy: size, zw: 1/size
|
||||
};
|
||||
|
||||
struct PerInstanceData
|
||||
struct InstanceData
|
||||
{
|
||||
float4x4 localToWorld;
|
||||
BYTE_ADDRESS_BUFFER meshBuffer;
|
||||
BYTE_ADDRESS_BUFFER materialBuffer;
|
||||
};
|
||||
|
||||
struct PerObjectData
|
||||
struct MeshData
|
||||
{
|
||||
float3 worldBoundsMin;
|
||||
BYTE_ADDRESS_BUFFER vertexBuffer;
|
||||
float3 worldBoundsMax;
|
||||
BYTE_ADDRESS_BUFFER indexBuffer;
|
||||
|
||||
BYTE_ADDRESS_BUFFER meshletBuffer;
|
||||
BYTE_ADDRESS_BUFFER meshletVerticesBuffer;
|
||||
BYTE_ADDRESS_BUFFER meshletTrianglesBuffer;
|
||||
@@ -50,4 +52,4 @@ struct PerObjectData
|
||||
|
||||
PushConstantData g_PushConstantData : register(b0);
|
||||
|
||||
#endif // BUILTIN_PROPERTIES_HLSL
|
||||
#endif // GHOST_PROPERTIES_HLSL
|
||||
|
||||
123
src/Runtime/Ghost.Graphics/Shaders/Includes/Random.hlsl
Normal file
123
src/Runtime/Ghost.Graphics/Shaders/Includes/Random.hlsl
Normal file
@@ -0,0 +1,123 @@
|
||||
#ifndef GHOST_RANDOM_HLSL
|
||||
#define GHOST_RANDOM_HLSL
|
||||
|
||||
float RandomFloat(float2 uv)
|
||||
{
|
||||
return frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
float Hash(uint s)
|
||||
{
|
||||
s = s ^ 2747636419u;
|
||||
s = s * 2654435769u;
|
||||
s = s ^ (s >> 16);
|
||||
s = s * 2654435769u;
|
||||
s = s ^ (s >> 16);
|
||||
s = s * 2654435769u;
|
||||
return float(s) * rcp(4294967296.0); // 2^-32
|
||||
}
|
||||
|
||||
// A single iteration of Bob Jenkins' One-At-A-Time hashing algorithm.
|
||||
uint JenkinsHash(uint x)
|
||||
{
|
||||
x += (x << 10u);
|
||||
x ^= (x >> 6u);
|
||||
x += (x << 3u);
|
||||
x ^= (x >> 11u);
|
||||
x += (x << 15u);
|
||||
return x;
|
||||
}
|
||||
|
||||
// Compound versions of the hashing algorithm.
|
||||
uint JenkinsHash(uint2 v)
|
||||
{
|
||||
return JenkinsHash(v.x ^ JenkinsHash(v.y));
|
||||
}
|
||||
|
||||
uint JenkinsHash(uint3 v)
|
||||
{
|
||||
return JenkinsHash(v.x ^ JenkinsHash(v.yz));
|
||||
}
|
||||
|
||||
uint JenkinsHash(uint4 v)
|
||||
{
|
||||
return JenkinsHash(v.x ^ JenkinsHash(v.yzw));
|
||||
}
|
||||
|
||||
uint PCGHash(uint input)
|
||||
{
|
||||
uint state = input * 747796405u + 2891336453u;
|
||||
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
||||
return (word >> 22u) ^ word;
|
||||
}
|
||||
|
||||
// Construct a float with half-open range [0, 1) using low 23 bits.
|
||||
// All zeros yields 0, all ones yields the next smallest representable value below 1.
|
||||
float ConstructFloat(int m)
|
||||
{
|
||||
const int ieeeMantissa = 0x007FFFFF; // Binary FP32 mantissa bitmask
|
||||
const int ieeeOne = 0x3F800000; // 1.0 in FP32 IEEE
|
||||
|
||||
m &= ieeeMantissa; // Keep only mantissa bits (fractional part)
|
||||
m |= ieeeOne; // Add fractional part to 1.0
|
||||
|
||||
float f = asfloat(m); // Range [1, 2)
|
||||
return f - 1; // Range [0, 1)
|
||||
}
|
||||
|
||||
float ConstructFloat(uint m)
|
||||
{
|
||||
return ConstructFloat(asint(m));
|
||||
}
|
||||
|
||||
// Pseudo-random value in half-open range [0, 1). The distribution is reasonably uniform.
|
||||
// Ref: https://stackoverflow.com/a/17479300
|
||||
float GenerateHashedRandomFloat(uint x)
|
||||
{
|
||||
return ConstructFloat(JenkinsHash(x));
|
||||
}
|
||||
|
||||
float GenerateHashedRandomFloat(uint2 v)
|
||||
{
|
||||
return ConstructFloat(JenkinsHash(v));
|
||||
}
|
||||
|
||||
float GenerateHashedRandomFloat(uint3 v)
|
||||
{
|
||||
return ConstructFloat(JenkinsHash(v));
|
||||
}
|
||||
|
||||
float GenerateHashedRandomFloat(uint4 v)
|
||||
{
|
||||
return ConstructFloat(JenkinsHash(v));
|
||||
}
|
||||
|
||||
float2 InitRandom(float2 input)
|
||||
{
|
||||
float2 r;
|
||||
r.x = Hash(uint(input.x * 0xFFFFFFFFu));
|
||||
r.y = Hash(uint(input.y * 0xFFFFFFFFu));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
//From Next Generation Post Processing in Call of Duty: Advanced Warfare [Jimenez 2014]
|
||||
// http://advances.realtimerendering.com/s2014/index.html
|
||||
float InterleavedGradientNoise(float2 pixCoord, int frameCount)
|
||||
{
|
||||
const float3 magic = float3(0.06711056f, 0.00583715f, 52.9829189f);
|
||||
float2 frameMagicScale = float2(2.083f, 4.867f);
|
||||
pixCoord += frameCount * frameMagicScale;
|
||||
return frac(magic.z * frac(dot(pixCoord, magic.xy)));
|
||||
}
|
||||
|
||||
// 32-bit Xorshift random number generator
|
||||
uint XorShift(inout uint rngState)
|
||||
{
|
||||
rngState ^= rngState << 13;
|
||||
rngState ^= rngState >> 17;
|
||||
rngState ^= rngState << 5;
|
||||
return rngState;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -50,7 +50,7 @@ internal sealed class SwapChainRecord
|
||||
}
|
||||
}
|
||||
|
||||
internal class SwapChainManager
|
||||
internal class SwapChainManager : IDisposable
|
||||
{
|
||||
public const int MAX_SWAP_CHAINS = 8;
|
||||
private readonly IGraphicsEngine _graphicsEngine;
|
||||
@@ -115,4 +115,59 @@ internal class SwapChainManager
|
||||
Interlocked.CompareExchange(ref _swapChains[index], null, record);
|
||||
}
|
||||
}
|
||||
|
||||
public void TransitionToPresent(ICommandBuffer commandBuffer)
|
||||
{
|
||||
for (int i = 0; i < MAX_SWAP_CHAINS; i++)
|
||||
{
|
||||
var record = Volatile.Read(ref _swapChains[i]);
|
||||
if (record == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
commandBuffer.Barrier(BarrierDesc.Texture(record.SwapChain.GetCurrentBackBuffer().AsResource(),
|
||||
null, BarrierSync.None,
|
||||
null, BarrierAccess.NoAccess,
|
||||
null, BarrierLayout.Present));
|
||||
}
|
||||
}
|
||||
|
||||
public void Present(int index, ICommandBuffer commandBuffer)
|
||||
{
|
||||
var record = Volatile.Read(ref _swapChains[index]);
|
||||
if (record == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
record.SwapChain.Present();
|
||||
}
|
||||
|
||||
public void PresentAll(ICommandBuffer commandBuffer)
|
||||
{
|
||||
for (int i = 0; i < MAX_SWAP_CHAINS; i++)
|
||||
{
|
||||
var record = Volatile.Read(ref _swapChains[i]);
|
||||
if (record == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
record?.SwapChain.Present();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
for (int i = 0; i < MAX_SWAP_CHAINS; i++)
|
||||
{
|
||||
var record = Volatile.Read(ref _swapChains[i]);
|
||||
if (record != null)
|
||||
{
|
||||
record.SwapChain.Dispose();
|
||||
Interlocked.CompareExchange(ref _swapChains[i], null, record);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ shader "MyShader/Standard"
|
||||
includes
|
||||
{
|
||||
"F:/csharp/GhostEngine/src/Runtime/Ghost.Graphics/Shaders/Includes/Properties.hlsl";
|
||||
"F:/csharp/GhostEngine/src/Runtime/Ghost.Graphics/Shaders/Includes/Random.hlsl";
|
||||
}
|
||||
|
||||
hlsl
|
||||
@@ -33,6 +34,7 @@ shader "MyShader/Standard"
|
||||
float4 position : SV_POSITION;
|
||||
float4 color : COLOR;
|
||||
float4 uv : TEXCOORD0;
|
||||
nointerpolation uint meshletID : MESHLET_ID;
|
||||
};
|
||||
|
||||
[numthreads(128, 1, 1)] // 128 threads to cover max 64 vertices and 124 triangles
|
||||
@@ -43,9 +45,10 @@ shader "MyShader/Standard"
|
||||
out vertices PixelInput outVerts[64],
|
||||
out indices uint3 outTris[124])
|
||||
{
|
||||
PerObjectData perObjectData = LoadData<PerObjectData>(g_PushConstantData.objectIndex, 0);
|
||||
InstanceData instanceData = LoadData<InstanceData>(g_PushConstantData.instanceBuffer, g_PushConstantData.instanceIndex);
|
||||
MeshData meshData = LoadData<MeshData>(instanceData.meshBuffer, 0);
|
||||
|
||||
ByteAddressBuffer meshletBuffer = GET_BUFFER(perObjectData.meshletBuffer);
|
||||
ByteAddressBuffer meshletBuffer = GET_BUFFER(meshData.meshletBuffer);
|
||||
Meshlet m = meshletBuffer.Load<Meshlet>(groupID.x * sizeof(Meshlet));
|
||||
|
||||
uint vertexCount = m.packedCounts & 0xFF;
|
||||
@@ -53,27 +56,29 @@ shader "MyShader/Standard"
|
||||
|
||||
SetMeshOutputCounts(vertexCount, triangleCount);
|
||||
|
||||
ByteAddressBuffer meshletVerticesBuffer = GET_BUFFER(perObjectData.meshletVerticesBuffer);
|
||||
ByteAddressBuffer meshletTrianglesBuffer = GET_BUFFER(perObjectData.meshletTrianglesBuffer);
|
||||
ByteAddressBuffer meshletVerticesBuffer = GET_BUFFER(meshData.meshletVerticesBuffer);
|
||||
ByteAddressBuffer meshletTrianglesBuffer = GET_BUFFER(meshData.meshletTrianglesBuffer);
|
||||
|
||||
// Write vertex output
|
||||
if (groupThreadID.x < vertexCount)
|
||||
{
|
||||
uint vertexIndex = meshletVerticesBuffer.Load((m.vertexOffset + groupThreadID.x) * 4);
|
||||
ByteAddressBuffer vertices = GET_BUFFER(perObjectData.vertexBuffer);
|
||||
ByteAddressBuffer vertices = GET_BUFFER(meshData.vertexBuffer);
|
||||
Vertex v = vertices.Load<Vertex>(vertexIndex * sizeof(Vertex));
|
||||
|
||||
GlobalFrameData globalFrameData = LoadData<GlobalFrameData>(g_PushConstantData.globalIndex, 0);
|
||||
PerViewData perViewData = LoadData<PerViewData>(g_PushConstantData.viewIndex, 0);
|
||||
PerInstanceData perInstanceData = LoadData<PerInstanceData>(globalFrameData.instanceBufferIndex, g_PushConstantData.instanceIndex);
|
||||
FrameData globalFrameData = LoadData<FrameData>(g_PushConstantData.frameBuffer, 0);
|
||||
ViewData viewData = LoadData<ViewData>(g_PushConstantData.viewBuffer, 0);
|
||||
|
||||
float4 worldPos = mul(perInstanceData.localToWorld, float4(v.position.xyz, 1.0f));
|
||||
float4 viewPos = mul(perViewData.viewMatrix, worldPos);
|
||||
float4 worldPos = mul(instanceData.localToWorld, float4(v.position.xyz, 1.0f));
|
||||
float4 viewPos = mul(viewData.viewMatrix, worldPos);
|
||||
|
||||
outVerts[groupThreadID.x].position = mul(perViewData.projectionMatrix, viewPos);
|
||||
// outVerts[groupThreadID.x].position = mul(viewData.projectionMatrix, viewPos);
|
||||
// For testing.
|
||||
outVerts[groupThreadID.x].position = float4(v.position.xyz, 1.0f);
|
||||
|
||||
outVerts[groupThreadID.x].color = v.color;
|
||||
outVerts[groupThreadID.x].uv = v.uv;
|
||||
outVerts[groupThreadID.x].meshletID = groupID.x;
|
||||
}
|
||||
|
||||
// Write triangle output (1 thread processes 1 triangle)
|
||||
@@ -105,9 +110,15 @@ shader "MyShader/Standard"
|
||||
// return perMaterialData.color * blendedColor + input.color;
|
||||
|
||||
// TODO: Randome color on meshlet.
|
||||
return float4(1, 0, 0, 1);
|
||||
// return 1.0;
|
||||
uint hash = PCGHash(input.meshletID);
|
||||
|
||||
float r = float((hash & 0xFF0000u) >> 16) / 255.0;
|
||||
float g = float((hash & 0x00FF00u) >> 8) / 255.0;
|
||||
float b = float((hash & 0x0000FFu)) / 255.0;
|
||||
|
||||
return float4(r, g, b, 1.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mesh "hlsl_block" : "MSMain";
|
||||
|
||||
Reference in New Issue
Block a user