Browse Source

add custom intersection shader for efficient ray chunk traversal

Kolja Strohm 2 weeks ago
parent
commit
f89c6e1d77

+ 1 - 3
.gitignore

@@ -268,6 +268,4 @@ KSGClient/Netzwerk/Keys.cpp
 /FactoryCraft/CustomUIDX11PixelShader.h
 /FactoryCraft/CustomUIDX11VertexShader.h
 *.dmp
-/FactoryCraft/CustomClosestHitShader.h
-/FactoryCraft/CustomMissShader.h
-/FactoryCraft/CustomRayGenShader.h
+/FactoryCraft/Custom*Shader.h

+ 63 - 0
FactoryCraft/ChunkAnyHit.hlsl

@@ -0,0 +1,63 @@
+#include "Common.hlsl"
+
+Texture2D<float4> textures[] : register(t0, space1);
+SamplerState gSampler : register(s0, space0);
+
+[shader("anyhit")]
+void ChunkAnyHit(inout HitInfo payload, Attributes attrib)
+{
+    Texture2D<float4> texture = textures[attrib.textureId];
+    float4 color = texture.SampleLevel(gSampler, attrib.texCoord, 0);
+    if (color.w == 0.f)
+    {
+        IgnoreHit();
+    }
+    float distance = RayTCurrent();
+    bool found = false;
+    for (int i = 0; i < payload.hitCount; i++)
+    {
+        if (payload.distance[i] > distance)
+        {
+            found = true;
+            float4 tmpColor = payload.color[i];
+            payload.color[i] = color;
+            float tmpDistance = payload.distance[i];
+            payload.distance[i] = distance;
+            if (color.w == 1.f)
+            {
+                payload.hitCount = i + 1;
+            }
+            else
+            {
+                for (int j = i + 1; j < payload.hitCount + 1 && j < MAX_TRANSPACENT_HITS; j++)
+                {
+                    float4 tmpColor2 = payload.color[j];
+                    float tmpDistance2 = payload.distance[j];
+                    payload.color[j] = tmpColor;
+                    payload.distance[j] = tmpDistance;
+                    tmpColor = tmpColor2;
+                    tmpDistance = tmpDistance2;
+                }
+            }
+            break;
+        }
+        else
+        {
+            if (payload.color[i].w == 1.f)
+            {
+                found = true;
+                break;
+            }
+        }
+    }
+    if (!found && payload.hitCount < MAX_TRANSPACENT_HITS)
+    {
+        payload.color[payload.hitCount] = color;
+        payload.distance[payload.hitCount] = distance;
+        payload.hitCount++;
+    }
+    if (color.w < 1.f)
+    {
+        IgnoreHit();
+    }
+}

+ 10 - 0
FactoryCraft/ChunkClosestHit.hlsl

@@ -0,0 +1,10 @@
+#include "Common.hlsl"
+
+Texture2D<float4> textures[] : register(t0, space1);
+SamplerState gSampler : register(s0, space0);
+
+[shader("closesthit")]
+void ChunkClosestHit(inout HitInfo payload, Attributes attrib)
+{
+    // TODO: reflection rays and shadow rays ...
+}

+ 163 - 0
FactoryCraft/ChunkIntersection.hlsl

@@ -0,0 +1,163 @@
+#include "Common.hlsl"
+
+#define WORLD_HEIGHT 500
+#define CHUNK_SIZE 16
+#define EPSILON 1e-6f
+
+cbuffer ChunkShaderInfo : register(b0, space2)
+{
+    int2 pos;
+    unsigned int blockCount;
+};
+
+StructuredBuffer<int> textureIdBuffer : register(t1, space2);
+StructuredBuffer<int> indexBuffer : register(t1, space3);
+
+#define minPos(x, y) min(x>0?x:y,y>0?y:x)
+#define minPosV(v1, v2) float3(minPos(v1.x, v2.x), minPos(v1.y, v2.y), minPos(v1.z, v2.z))
+
+#define between(v1, vmin, vmax) (v1.x >= vmin.x && v1.x <= vmax.x && v1.y >= vmin.y && v1.y <= vmax.y && v1.z >= vmin.z && v1.z <= vmax.z)
+
+float GetEntry(float3 minp, float3 maxp, float3 invDir, float3 origin)
+{
+    if (between(origin, minp, maxp))
+    {
+        return 0;
+    }
+    float3 t1 = (minp - origin) * invDir;
+    float3 t2 = (maxp - origin) * invDir;
+    float3 tmin = min(t1, t2);
+    return max(max(tmin.x, tmin.y), tmin.z);
+}
+
+[shader("intersection")]
+void ChunkIntersection()
+{
+    float THit = RayTCurrent();
+    Attributes intersectionAttributes;
+    intersectionAttributes.texCoord = float2(0.5, 0.5);
+    intersectionAttributes.textureId = 2;
+    float3 origin = WorldRayOrigin();
+    float3 direction = WorldRayDirection();
+    float minDistance = RayTMin();
+    float3 invDirection = 1.0 / direction;
+    float3 chunkMin = float3(pos.x - CHUNK_SIZE / 2, pos.y - CHUNK_SIZE / 2, 0);
+    float3 chunkMax = float3(pos.x + CHUNK_SIZE / 2, pos.y + CHUNK_SIZE / 2, WORLD_HEIGHT);
+    float distance = 0;
+    float3 step = sign(direction);
+    int hitSide = -1;
+    float3 currentPos = origin;
+    if (!between(origin, chunkMin, chunkMax))
+    {
+        float3 t1 = (chunkMin - origin) * invDirection;
+        float3 t2 = (chunkMax - origin) * invDirection;
+        float3 tmin = min(t1, t2);
+        if (tmin.x > tmin.y && tmin.x > tmin.z)
+        {
+            hitSide = step.x > 0 ? 3 : 2;
+            distance = tmin.x;
+        }
+        else if (tmin.y > tmin.z)
+        {
+            hitSide = step.y > 0 ? 0 : 1;
+            distance = tmin.y;
+        }
+        else
+        {
+            hitSide = step.z > 0 ? 5 : 4;
+            distance = tmin.z;
+        }
+        currentPos = origin + direction * distance;
+    }
+    float3 chunkPos = currentPos - chunkMin;
+    float3 sum = step + currentPos;
+    float3 nextBorder = float3(step.x > 0 ? floor(sum.x) : ceil(sum.x), step.y > 0 ? floor(sum.y) : ceil(sum.y), step.z > 0 ? floor(sum.z) : ceil(sum.z));
+    int3 block = floor(chunkPos);
+
+    int3 blockMin = int3(0, 0, 0);
+    int3 blockMax = int3(CHUNK_SIZE - 1, CHUNK_SIZE - 1, WORLD_HEIGHT - 1);
+    switch (hitSide)
+    {
+        case 0: // front
+            block.y = blockMin.y;
+            nextBorder.y = blockMin.y + 1 + chunkMin.y;
+            break;
+        case 1: // back
+            block.y = blockMax.y;
+            nextBorder.y = blockMax.y + chunkMin.y;
+            break;
+        case 2: // left
+            block.x = blockMax.x;
+            nextBorder.x = blockMax.x + chunkMin.x;
+            break;
+        case 3: // right
+            block.x = blockMin.x;
+            nextBorder.x = blockMin.x + 1 + chunkMin.x;
+            break;
+        case 4: // top
+            block.z = blockMax.z;
+            nextBorder.z = blockMax.z + chunkMin.z;
+            break;
+        case 5: // bottom
+            block.z = blockMin.z;
+            nextBorder.z = blockMin.z + 1 + chunkMin.z;
+            break;
+    }
+    while (between(block, blockMin, blockMax) && distance < THit)
+    {
+        int index = (block.x * CHUNK_SIZE + block.y) * WORLD_HEIGHT + block.z;
+        if (indexBuffer[index] >= 0 && distance > minDistance && hitSide >= 0)
+        {
+            switch (hitSide)
+            {
+                case 0: // front
+                    intersectionAttributes.texCoord = float2(1 - (currentPos.x - floor(currentPos.x)), 1 - (currentPos.z - floor(currentPos.z)));
+                    break;
+                case 1: // back
+                    intersectionAttributes.texCoord = float2(currentPos.x - floor(currentPos.x), 1 - (currentPos.z - floor(currentPos.z)));
+                    break;
+                case 2: // left
+                    intersectionAttributes.texCoord = float2(1 - (currentPos.y - floor(currentPos.y)), 1 - (currentPos.z - floor(currentPos.z)));
+                    break;
+                case 3: // right
+                    intersectionAttributes.texCoord = float2(currentPos.y - floor(currentPos.y), 1 - (currentPos.z - floor(currentPos.z)));
+                    break;
+                case 4: // top
+                    intersectionAttributes.texCoord = float2(1 - (currentPos.x - floor(currentPos.x)), 1 - (currentPos.y - floor(currentPos.y)));
+                    break;
+                case 5: // bottom
+                    intersectionAttributes.texCoord = float2(1 - (currentPos.x - floor(currentPos.x)), currentPos.y - floor(currentPos.y));
+                    break;
+            }
+            intersectionAttributes.textureId = textureIdBuffer[indexBuffer[index] + hitSide];
+            ReportHit(distance, hitSide, intersectionAttributes);
+            if (RayTCurrent() < THit)
+            {
+                return; // since we go in direction of the ray we will not find a nearer hit in this intersection shader
+            }
+        }
+        float3 stepDist = (nextBorder - origin) * invDirection;
+        if (stepDist.x < stepDist.y && stepDist.x < stepDist.z)
+        {
+            hitSide = step.x > 0 ? 3 : 2;
+            block.x += step.x;
+            nextBorder.x += step.x;
+            distance = stepDist.x;
+        }
+        else if (stepDist.y < stepDist.z)
+        {
+            hitSide = step.y > 0 ? 0 : 1;
+            block.y += step.y;
+            nextBorder.y += step.y;
+            distance = stepDist.y;
+        }
+        else
+        {
+            hitSide = step.z > 0 ? 5 : 4;
+            block.z += step.z;
+            nextBorder.z += step.z;
+            distance = stepDist.z;
+        }
+        currentPos = origin + direction * distance;
+    }
+}

+ 0 - 7
FactoryCraft/ClosestHit.hlsl

@@ -1,7 +0,0 @@
-#include "Common.hlsl"
-
-[shader("closesthit")]
-void ClosestHit(inout HitInfo rayPayload : SV_RayPayload, Attributes attrib)
-{
-    rayPayload.colorAndDistance = float4(0.f, 0.5f, 1.f, RayTCurrent());
-}

+ 6 - 2
FactoryCraft/Common.hlsl

@@ -5,15 +5,19 @@
 // D3D12_RAYTRACING_SHADER_CONFIG pipeline subobjet.
 
 #pragma pack_matrix(row_major)
+#define MAX_TRANSPACENT_HITS 5
 
 struct [raypayload] HitInfo
 {
-    float4 colorAndDistance : write(caller, closesthit, miss) : read(caller);
+    float4 color[MAX_TRANSPACENT_HITS] : write(caller, closesthit, anyhit, miss) : read(caller, anyhit, closesthit, miss);
+float distance[MAX_TRANSPACENT_HITS] : write(caller, closesthit, anyhit) : read(caller, anyhit, closesthit);
+uint hitCount : write(caller, anyhit, closesthit, miss) : read(caller, anyhit, closesthit, miss);
 };
 
 // Attributes output by the raytracing when hitting a surface,
 // here the barycentric coordinates
 struct Attributes
 {
-    float2 bary;
+    float2 texCoord;
+    int textureId;
 };

+ 1 - 1
FactoryCraft/Constants.h

@@ -3,7 +3,7 @@
 #define CHUNK_SIZE   16
 #define WORLD_HEIGHT 500
 #ifdef _DEBUG
-#    define CHUNK_VISIBILITY_RANGE 2
+#    define CHUNK_VISIBILITY_RANGE 10
 #else
 #    define CHUNK_VISIBILITY_RANGE 32
 #endif

+ 203 - 45
FactoryCraft/CustomDX12API.cpp

@@ -2,11 +2,19 @@
 
 #include <d3d12.h>
 #include <DX12Buffer.h>
+#include <DX12CommandQueue.h>
+#include <DX12DefaultAnyHitShader.h>
+#include <DX12DefaultHitShader.h>
+#include <DX12DefaultMissShader.h>
+#include <DX12DefaultRayGenShader.h>
 #include <DX12Shader.h>
+#include <DX12TLAS.h>
 
-#include "CustomClosestHitShader.h"
-#include "CustomMissShader.h"
-#include "CustomRayGenShader.h"
+#include "CustomChunkAnyHitShader.h"
+#include "CustomChunkClosestHitShader.h"
+#include "CustomChunkIntersectionShader.h"
+#include "Dimension.h"
+#include "DX12ChunkData.h"
 
 using namespace Framework;
 
@@ -14,53 +22,140 @@ CustomDX12API::CustomDX12API()
     : DirectX12()
 {}
 
+CustomDX12API::~CustomDX12API() {}
+
 void CustomDX12API::initializePipeline()
 {
-    /*
-    DX12Shader* rayGenShader
-        = new DX12Shader(CustomRayGenShader, sizeof(CustomRayGenShader));
-    // RayGen from RayGen.hlsl
-    DX12ShaderSignature* rayGenSignature = new DX12ShaderSignature();
-    rayGenSignature->addRegisterUsageLinkedToDescriptorHeap(
-        0, DX12_SHADER_REGISTER_U_UNORDERED_ACCESS, 0);
-    rayGenSignature->addRegisterUsageLinkedToDescriptorHeap(
-        1, DX12_SHADER_REGISTER_U_UNORDERED_ACCESS, 1);
-    rayGenSignature->addRegisterUsageLinkedToDescriptorHeap(
-        2, DX12_SHADER_REGISTER_B_CONST_BUFFER, 0);
-    rayGenSignature->addRegisterUsageLinkedToDescriptorHeap(
-        3, DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 0);
-    defaultRayGenerationShaderFunction = new DX12ShaderFunction(
-        "RayGen", rayGenSignature, DX12_SHADER_FUNCTION_TYPE_RAY_GEN);
-    rayGenShader->addFunction(defaultRayGenerationShaderFunction);
-    pipeline->addShader(rayGenShader);
-
-    DX12Shader* missShader
-        = new DX12Shader(CustomMissShader, sizeof(CustomMissShader));
-    // Miss from Miss.hlsl
-    missShader->addFunction(new DX12ShaderFunction(
-        "Miss", new DX12ShaderSignature(), DX12_SHADER_FUNCTION_TYPE_MISS));
-    pipeline->addShader(missShader);
-
-    DX12Shader* hitShader = new DX12Shader(
-        CustomClosestHitShader, sizeof(CustomClosestHitShader));
-    // ClosestHit from Hit.hlsl
-    DX12ShaderFunction* closestHitFunction
-        = new DX12ShaderFunction("ClosestHit",
-            new DX12ShaderSignature(),
-            DX12_SHADER_FUNCTION_TYPE_CLOSEST_HIT);
-    hitShader->addFunction(closestHitFunction);
-    pipeline->addShader(hitShader);
+    if (pipeline->getShaders().getEntryCount() == 0)
+    { // add default shaders
+        DX12Shader* rayGenShader = new DX12Shader(
+            DX12DefaultRayGenShaderBytes, sizeof(DX12DefaultRayGenShaderBytes));
+        // RayGen from RayGen.hlsl
+        DX12ShaderSignature* rayGenSignature = new DX12ShaderSignature();
+        rayGenSignature->addRegisterUsageLinkedToDescriptorHeap(
+            0, DX12_SHADER_REGISTER_U_UNORDERED_ACCESS, 0);
+        rayGenSignature->addRegisterUsageLinkedToDescriptorHeap(
+            1, DX12_SHADER_REGISTER_U_UNORDERED_ACCESS, 1);
+        rayGenSignature->addRegisterUsageLinkedToDescriptorHeap(
+            2, DX12_SHADER_REGISTER_B_CONST_BUFFER, 0);
+        rayGenSignature->addRegisterUsageLinkedToDescriptorHeap(
+            3, DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 0);
+        defaultRayGenerationShaderFunction = new DX12ShaderFunction(
+            "RayGen", rayGenSignature, DX12_SHADER_FUNCTION_TYPE_RAY_GEN);
+        rayGenShader->addFunction(defaultRayGenerationShaderFunction);
+        pipeline->addShader(rayGenShader);
+
+        DX12Shader* missShader = new DX12Shader(
+            DX12DefaultMissShaderBytes, sizeof(DX12DefaultMissShaderBytes));
+        // Miss from Miss.hlsl
+        missShader->addFunction(new DX12ShaderFunction(
+            "Miss", new DX12ShaderSignature(), DX12_SHADER_FUNCTION_TYPE_MISS));
+        pipeline->addShader(missShader);
+
+        DX12ShaderSignature* hitSignature = new DX12ShaderSignature();
+        hitSignature->addRegisterUsageLinkedToDescriptorHeap(
+            0, DX12_SHADER_REGISTER_S_SAMPLER, 0, 0, SAMPLER_DESCRIPTOR_HEAP);
+        hitSignature->addRegisterUsageLinkedToDescriptorHeap(0,
+            DX12_SHADER_REGISTER_T_SHADER_RESOURCE,
+            0,
+            1,
+            TEXTURE_DESCRIPTOR_HEAP,
+            1);
+        sbtTextureIdBufferOffset
+            = hitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 2);
+        sbtIndexBufferOffset
+            = hitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 3);
+        sbtVertexDataBufferOffset
+            = hitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 4);
+        sbtPolygonSizeBufferOffset
+            = hitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 5);
+        DX12Shader* anyHitShader = new DX12Shader(
+            DX12DefaultAnyHitShaderBytes, sizeof(DX12DefaultAnyHitShaderBytes));
+        DX12ShaderFunction* anyHitFunction = new DX12ShaderFunction(
+            "AnyHit", hitSignature, DX12_SHADER_FUNCTION_TYPE_ANY_HIT);
+        // AnyHit from AnyHit.hlsl
+        anyHitShader->addFunction(anyHitFunction);
+        pipeline->addShader(anyHitShader);
+
+        DX12Shader* hitShader = new DX12Shader(
+            DX12DefaultHitShaderBytes, sizeof(DX12DefaultHitShaderBytes));
+        // ClosestHit from Hit.hlsl
+        DX12ShaderFunction* closestHitFunction
+            = new DX12ShaderFunction("ClosestHit",
+                dynamic_cast<DX12ShaderSignature*>(hitSignature->getThis()),
+                DX12_SHADER_FUNCTION_TYPE_CLOSEST_HIT);
+        hitShader->addFunction(closestHitFunction);
+        pipeline->addShader(hitShader);
+
+        defaultHitGroup = new DX12ShaderHitGroup("HitGroup");
+        defaultHitGroup->setAttributeSize(8);
+        defaultHitGroup->setPayloadSize(20 * DEFAULT_MAX_TRANSPARENT_HITS + 4);
+        defaultHitGroup->setAnyHitShaderFunction(anyHitFunction);
+        defaultHitGroup->setClosestHitShaderFunction(closestHitFunction);
+        pipeline->addHitGroup(defaultHitGroup);
+
+        DX12ShaderSignature* chunkHitSignature = new DX12ShaderSignature();
+        chunkHitSignature->addRegisterUsageLinkedToDescriptorHeap(
+            0, DX12_SHADER_REGISTER_S_SAMPLER, 0, 0, SAMPLER_DESCRIPTOR_HEAP);
+        chunkHitSignature->addRegisterUsageLinkedToDescriptorHeap(0,
+            DX12_SHADER_REGISTER_T_SHADER_RESOURCE,
+            0,
+            1,
+            TEXTURE_DESCRIPTOR_HEAP,
+            1);
+        sbtChunkTextureIdBufferOffset
+            = chunkHitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 2);
+        sbtChunkIndexBufferOffset
+            = chunkHitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 3);
+        sbtChunkDataBufferOffset
+            = chunkHitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_B_CONST_BUFFER, 0, 2);
 
-    defaultHitGroup = new DX12ShaderHitGroup("HitGroup");
-    defaultHitGroup->setAttributeSize(8);
-    defaultHitGroup->setPayloadSize(16);
-    defaultHitGroup->setClosestHitShaderFunction(closestHitFunction);
-    pipeline->addHitGroup(defaultHitGroup);
+        DX12Shader* chunkIntersectionShader
+            = new DX12Shader(CustomChunkIntersectionShader,
+                sizeof(CustomChunkIntersectionShader));
+        DX12ShaderFunction* chunkIntersectionFunction
+            = new DX12ShaderFunction("ChunkIntersection",
+                chunkHitSignature,
+                DX12_SHADER_FUNCTION_TYPE_INTERSECTION);
+        chunkIntersectionShader->addFunction(chunkIntersectionFunction);
+        pipeline->addShader(chunkIntersectionShader);
 
-    pipeline->setMaxRecursionDepth(10);
+        DX12Shader* chunkAnyHitShader = new DX12Shader(
+            CustomChunkAnyHitShader, sizeof(CustomChunkAnyHitShader));
+        DX12ShaderFunction* chunkAnyHitFunction = new DX12ShaderFunction(
+            "ChunkAnyHit",
+            dynamic_cast<DX12ShaderSignature*>(chunkHitSignature->getThis()),
+            DX12_SHADER_FUNCTION_TYPE_ANY_HIT);
+        chunkAnyHitShader->addFunction(chunkAnyHitFunction);
+        pipeline->addShader(chunkAnyHitShader);
 
-    pipeline->createPipelineState(device, pfnD3D12SerializeRootSignature);*/
-    DirectX12::initializePipeline();
+        DX12Shader* chunkClosestHitShader = new DX12Shader(
+            CustomChunkClosestHitShader, sizeof(CustomChunkClosestHitShader));
+        DX12ShaderFunction* chunkClosestHitFunction = new DX12ShaderFunction(
+            "ChunkClosestHit",
+            dynamic_cast<DX12ShaderSignature*>(chunkHitSignature->getThis()),
+            DX12_SHADER_FUNCTION_TYPE_CLOSEST_HIT);
+        chunkClosestHitShader->addFunction(chunkClosestHitFunction);
+        pipeline->addShader(chunkClosestHitShader);
+
+        chunkHitGroup = new DX12ShaderHitGroup("ChunkHitGroup");
+        chunkHitGroup->setIntersectionShaderFunction(chunkIntersectionFunction);
+        chunkHitGroup->setAnyHitShaderFunction(chunkAnyHitFunction);
+        chunkHitGroup->setClosestHitShaderFunction(chunkClosestHitFunction);
+        chunkHitGroup->setAttributeSize(12);
+        chunkHitGroup->setPayloadSize(20 * DEFAULT_MAX_TRANSPARENT_HITS + 4);
+        pipeline->addHitGroup(chunkHitGroup);
+
+        pipeline->setMaxRecursionDepth(10);
+    }
+    pipeline->createPipelineState(device, pfnD3D12SerializeRootSignature);
 }
 
 void CustomDX12API::initializeGlobalDescriptorHeap()
@@ -78,3 +173,66 @@ void CustomDX12API::fillShaderBindingTable(
     DirectX12::fillShaderBindingTable(
         zShaderBindingTable, zModel, objectIndex, zBLAS, lastHitGroupIndex);
 }
+
+void CustomDX12API::renderWorld(Framework::World3D* zWorld,
+    DX12TLAS* zTLAS,
+    DX12ShaderBindingTable* zSBT,
+    int& objectIndex)
+{
+    Mat4<float> identity = Mat4<float>::identity();
+    for (const Model3DCollection* collection : zWorld->getCollections())
+    {
+        const Dimension* dim = dynamic_cast<const Dimension*>(collection);
+        if (dim)
+        {
+            for (const Chunk* chunk : dim->getChunks())
+            {
+                DX12ChunkData* chunkData = chunk->zDX12Data();
+                chunkData->updateBuffers(device, directCommandQueue);
+                bool changed = chunkData->wasBufferChanged()
+                            || chunkData->getLastObjectIndex() != objectIndex;
+                if (changed)
+                {
+                    chunkData->setLastObjectIndex(objectIndex);
+                    D3D12_RAYTRACING_INSTANCE_DESC* desc
+                        = zTLAS->nextInstanceDesc();
+                    desc->InstanceID = objectIndex;
+                    desc->InstanceContributionToHitGroupIndex = objectIndex;
+                    desc->Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE;
+                    desc->InstanceMask = 0xFF;
+                    desc->AccelerationStructure = chunkData->zBlasBuffer()
+                                                      ->zBuffer()
+                                                      ->GetGPUVirtualAddress();
+                    memcpy(desc->Transform, &identity, sizeof(float) * 12);
+                }
+                else
+                {
+                    zTLAS->nextInstanceDesc();
+                }
+                int hitGroupOffset = zSBT->addHitGroup(
+                    chunkHitGroup, chunkData->getLastHitGroupIndex());
+                if (chunkData->getLastHitGroupIndex() != hitGroupOffset)
+                {
+                    chunkData->setLastHitGroupIndex(hitGroupOffset);
+                    zSBT->setHitGroupShaderInput(hitGroupOffset,
+                        sbtChunkIndexBufferOffset,
+                        chunkData->zBlockIndexBuffer()
+                            ->zBuffer()
+                            ->GetGPUVirtualAddress());
+                    zSBT->setHitGroupShaderInput(hitGroupOffset,
+                        sbtChunkTextureIdBufferOffset,
+                        chunkData->zTextureIdBuffer()
+                            ->zBuffer()
+                            ->GetGPUVirtualAddress());
+                    zSBT->setHitGroupShaderInput(hitGroupOffset,
+                        sbtChunkDataBufferOffset,
+                        chunkData->zChunkInfoBuffer()
+                            ->zBuffer()
+                            ->GetGPUVirtualAddress());
+                }
+                ++objectIndex;
+            }
+        }
+    }
+    DirectX12::renderWorld(zWorld, zTLAS, zSBT, objectIndex);
+}

+ 13 - 0
FactoryCraft/CustomDX12API.h

@@ -1,11 +1,20 @@
 #pragma once
 
 #include <DX12GraphicsApi.h>
+#include <DX12Shader.h>
+#include <World3D.h>
 
 class CustomDX12API : public Framework::DirectX12
 {
+private:
+    int* sbtChunkTextureIdBufferOffset;
+    int* sbtChunkIndexBufferOffset;
+    int* sbtChunkDataBufferOffset;
+    Framework::DX12ShaderHitGroup* chunkHitGroup;
+
 public:
     CustomDX12API();
+    ~CustomDX12API();
 
     void initializePipeline() override;
     void initializeGlobalDescriptorHeap() override;
@@ -15,4 +24,8 @@ public:
         int objectIndex,
         const Framework::DX12BLAS* zBLAS,
         int& lastHitGroupIndex) override;
+    void renderWorld(Framework::World3D* zWorld,
+        Framework::DX12TLAS* zTLAS,
+        Framework::DX12ShaderBindingTable* zSBT,
+        int& objectIndex) override;
 };

+ 149 - 61
FactoryCraft/DX12ChunkData.cpp

@@ -12,12 +12,20 @@ DX12ChunkData::DX12ChunkData(Framework::Point center)
       blasBuffer(0),
       blockIndexBuffer(0),
       textureIdBuffer(0),
+      lastObjectIndex(-1),
+      lastHitGroupIndex(-1),
       chunkCenter(center),
-      blockIndices(),
+      blockIndices(new int[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT]),
       textureIds(),
       changed(0),
-      bufferChanged(0)
-{}
+      bufferChanged(0),
+      minZ(WORLD_HEIGHT),
+      maxZ(0),
+      minMaxChanged(0)
+{
+    memset(
+        blockIndices, -1, sizeof(int) * CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
+}
 
 DX12ChunkData::~DX12ChunkData()
 {
@@ -45,6 +53,7 @@ DX12ChunkData::~DX12ChunkData()
     {
         textureIdBuffer->release();
     }
+    delete[] blockIndices;
 }
 
 Framework::DX12Buffer* DX12ChunkData::zChunkInfoBuffer() const
@@ -69,66 +78,95 @@ Framework::DX12Buffer* DX12ChunkData::zTextureIdBuffer() const
 
 void DX12ChunkData::setBlock(int index, Block* zBlock)
 {
+    cs.lock();
     if (zBlock)
     {
-        ArrayIterator<int> it = blockIndices.begin();
-        ArrayIterator<int> textureIt = textureIds.begin();
-        int pos = 0;
-        while (it)
+        if (blockIndices[index] < 0)
         {
-            if (it.val() == index)
+            blockIndices[index] = textureIds.getEntryCount();
+            for (int i = 0; i < 6; ++i)
             {
-                for (int i = 0; i < 6; ++i)
-                {
-                    textureIt.set(
-                        zBlock->zTexture()->zPolygonTexture(i)->getId());
-                    ++textureIt;
-                }
-                changed = 1;
-                return;
+                textureIds.add(zBlock->zTexture()->zPolygonTexture(i)->getId());
+            }
+        }
+        else
+        {
+            ArrayIterator<int> textureIt = textureIds.begin();
+            int tmp = blockIndices[index];
+            while (tmp > 0)
+            {
+                ++textureIt;
+                --tmp;
             }
-            ++it;
-            ++pos;
             for (int i = 0; i < 6; ++i)
             {
+                textureIt.set(zBlock->zTexture()->zPolygonTexture(i)->getId());
                 ++textureIt;
             }
         }
-        blockIndices.add(index);
-        for (int i = 0; i < 6; ++i)
+        if (zBlock->getLocation().z + 1 > maxZ)
+        {
+            maxZ = zBlock->getLocation().z + 1;
+            minMaxChanged = 1;
+        }
+        if (zBlock->getLocation().z < minZ)
         {
-            textureIds.add(zBlock->zTexture()->zPolygonTexture(i)->getId());
+            minZ = zBlock->getLocation().z;
+            minMaxChanged = 1;
         }
-        changed = 1;
     }
     else
     {
-        ArrayIterator<int> it = blockIndices.begin();
-        ArrayIterator<int> textureIt = textureIds.begin();
-        while (it)
+        if (blockIndices[index] >= 0)
         {
-            if (it.val() == index)
+            int tmp = blockIndices[index];
+            ArrayIterator<int> textureIt = textureIds.begin();
+            while (tmp > 0)
+            {
+                ++textureIt;
+                --tmp;
+            }
+            for (int i = 0; i < 6; ++i)
+            {
+                textureIt.remove();
+            }
+            int oldMinZ = minZ;
+            int oldMaxZ = maxZ;
+            maxZ = 0;
+            minZ = WORLD_HEIGHT;
+            for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; ++i)
             {
-                for (int i = 0; i < 6; ++i)
+                if (blockIndices[i] > blockIndices[index])
                 {
-                    textureIt.remove();
+                    blockIndices[i] -= 6;
+                }
+                if (blockIndices[i] >= 0)
+                {
+                    if (i % WORLD_HEIGHT + 1 > maxZ)
+                    {
+                        maxZ = i % WORLD_HEIGHT + 1;
+                    }
+                    if (i % WORLD_HEIGHT < minZ)
+                    {
+                        minZ = i % WORLD_HEIGHT;
+                    }
                 }
-                it.remove();
-                changed = 1;
-                return;
             }
-            ++it;
-            for (int i = 0; i < 6; ++i)
+            if (minZ != oldMinZ || maxZ != oldMaxZ)
             {
-                ++textureIt;
+                minMaxChanged = 1;
             }
         }
+        blockIndices[index] = -1;
     }
+    changed = 1;
+    cs.unlock();
 }
 
 void DX12ChunkData::updateBuffers(
     ID3D12Device5* zDevice, Framework::DX12CommandQueue* zQueue)
 {
+    cs.lock();
     if (!aabbs)
     {
         aabbs = new DX12Buffer(sizeof(D3D12_RAYTRACING_AABB),
@@ -138,12 +176,25 @@ void DX12ChunkData::updateBuffers(
         aabbs->setLength(sizeof(D3D12_RAYTRACING_AABB));
         D3D12_RAYTRACING_AABB data = {chunkCenter.x - 8.f,
             chunkCenter.y - 8.f,
-            0,
+            minZ,
+            chunkCenter.x + 8.f,
+            chunkCenter.y + 8.f,
+            maxZ};
+        aabbs->setData(&data, 1);
+        aabbs->copyToGPU();
+        minMaxChanged = 0;
+    }
+    if (minMaxChanged)
+    {
+        D3D12_RAYTRACING_AABB data = {chunkCenter.x - 8.f,
+            chunkCenter.y - 8.f,
+            minZ,
             chunkCenter.x + 8.f,
             chunkCenter.y + 8.f,
-            WORLD_HEIGHT};
+            maxZ};
         aabbs->setData(&data, 1);
         aabbs->copyToGPU();
+        minMaxChanged = 0;
     }
     if (!blasBuffer)
     {
@@ -163,12 +214,18 @@ void DX12ChunkData::updateBuffers(
         prebuildDesc.NumDescs = 1;
         prebuildDesc.pGeometryDescs = &geometryDesc;
         prebuildDesc.Flags
-            = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE;
+            = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE;
 
         D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO info = {};
         zDevice->GetRaytracingAccelerationStructurePrebuildInfo(
             &prebuildDesc, &info);
-
+        ID3D12Resource* oldBuffer = 0;
+        if (blasBuffer)
+        {
+            oldBuffer = blasBuffer->zBuffer();
+            oldBuffer->AddRef();
+            blasBuffer->release();
+        }
         blasBuffer = new DX12Buffer(1,
             zDevice,
             dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
@@ -196,18 +253,19 @@ void DX12ChunkData::updateBuffers(
             = {blasBuffer->zBuffer()->GetGPUVirtualAddress()};
         buildDesc.ScratchAccelerationStructureData
             = {blasScratchBuffer->zBuffer()->GetGPUVirtualAddress()};
-        buildDesc.SourceAccelerationStructureData = 0;
+        buildDesc.SourceAccelerationStructureData = oldBuffer ? oldBuffer->GetGPUVirtualAddress() : 0;
         buildDesc.Inputs.Flags
-            = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE;
+            = oldBuffer
+                ? D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE
+                : D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE;
 
         zQueue->zCommandList()->BuildRaytracingAccelerationStructure(
             &buildDesc, 0, nullptr);
-    }
-    if (blockIndexBuffer
-        && blockIndexBuffer->getElementCount() < blockIndices.getEntryCount())
-    {
-        blockIndexBuffer->release();
-        blockIndexBuffer = 0;
+        if (oldBuffer)
+        {
+            oldBuffer->Release();
+        }
+        bufferChanged = 1;
     }
     if (!blockIndexBuffer)
     {
@@ -215,7 +273,8 @@ void DX12ChunkData::updateBuffers(
             zDevice,
             dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
             D3D12_RESOURCE_FLAG_NONE);
-        blockIndexBuffer->setLength(blockIndices.getEntryCount() * sizeof(int));
+        blockIndexBuffer->setLength(
+            sizeof(int) * CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
         bufferChanged = 1;
     }
     if (textureIdBuffer
@@ -243,30 +302,59 @@ void DX12ChunkData::updateBuffers(
     }
     if (changed)
     {
-        int* blockIndexData = new int[blockIndices.getEntryCount()];
+        for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; ++i)
+        {
+            assert(blockIndices[i] < 0
+                   || blockIndices[i] <= textureIds.getEntryCount() - 6);
+        }
         int* textureIdData = new int[textureIds.getEntryCount()];
-        ArrayIterator<int> it = blockIndices.begin();
         ArrayIterator<int> textureIt = textureIds.begin();
         int index = 0;
-        while (it)
+        while (textureIt)
         {
-            blockIndexData[index] = it.val();
-            for (int i = 0; i < 6; i++)
-            {
-                textureIdData[index * 6 + i] = textureIt.val();
-                ++textureIt;
-            }
-            ++it;
+            textureIdData[index++] = textureIt.val();
+            ++textureIt;
         }
-        blockIndexBuffer->setData(blockIndexData, 1);
+        blockIndexBuffer->setData(blockIndices, 1);
         textureIdBuffer->setData(textureIdData, 1);
-        blockIndexBuffer->copyToGPU(sizeof(int) * blockIndices.getEntryCount());
+        blockIndexBuffer->copyToGPU();
         textureIdBuffer->copyToGPU(sizeof(int) * textureIds.getEntryCount());
-        delete[] blockIndexData;
         delete[] textureIdData;
         ChunkShaderInfo info
-            = {chunkCenter, (unsigned int)blockIndices.getEntryCount()};
+            = {chunkCenter, (unsigned int)textureIds.getEntryCount()};
         chunkInfoBuffer->setData(&info, 1);
         chunkInfoBuffer->copyToGPU();
+        changed = 0;
     }
+    cs.unlock();
+}
+
+int DX12ChunkData::getLastObjectIndex() const
+{
+    return lastObjectIndex;
+}
+
+int DX12ChunkData::getLastHitGroupIndex() const
+{
+    return lastHitGroupIndex;
+}
+
+void DX12ChunkData::setLastObjectIndex(int index)
+{
+    lastObjectIndex = index;
+}
+
+void DX12ChunkData::setLastHitGroupIndex(int index)
+{
+    lastHitGroupIndex = index;
+}
+
+bool DX12ChunkData::wasBufferChanged() const
+{
+    return bufferChanged;
+}
+
+void DX12ChunkData::setBufferChanged(bool changed)
+{
+    bufferChanged = changed;
 }

+ 13 - 1
FactoryCraft/DX12ChunkData.h

@@ -22,10 +22,16 @@ private:
     Framework::DX12Buffer* blockIndexBuffer;
     Framework::DX12Buffer* textureIdBuffer;
     Framework::Point chunkCenter;
-    Framework::Array<int> blockIndices;
+    int* blockIndices;
     Framework::Array<int> textureIds;
+    int lastObjectIndex;
+    int lastHitGroupIndex;
     bool changed;
     bool bufferChanged;
+    int minZ;
+    int maxZ;
+    Critical cs;
+    bool minMaxChanged;
 
 public:
     DX12ChunkData(Framework::Point center);
@@ -37,4 +43,10 @@ public:
     void setBlock(int index, Block* zBlock);
     void updateBuffers(
         ID3D12Device5* zDevice, Framework::DX12CommandQueue* zQueue);
+    int getLastObjectIndex() const;
+    int getLastHitGroupIndex() const;
+    void setLastObjectIndex(int index);
+    void setLastHitGroupIndex(int index);
+    bool wasBufferChanged() const;
+    void setBufferChanged(bool changed);
 };

+ 5 - 0
FactoryCraft/Dimension.cpp

@@ -340,3 +340,8 @@ Lock& Dimension::getReadLock() const
 {
     return lock.getReadLock();
 }
+
+const Framework::Array<Chunk*>& Dimension::getChunks() const
+{
+    return chunkList;
+}

+ 1 - 0
FactoryCraft/Dimension.h

@@ -45,6 +45,7 @@ public:
     void removeEntity(int id);
     int getId() const;
     Lock& getReadLock() const;
+    const Framework::Array<Chunk*>& getChunks() const;
 
     inline static Framework::Vec3<int> chunkCoordinates(
         Framework::Vec3<int> worldLocation)

+ 15 - 12
FactoryCraft/FactoryCraft.vcxproj

@@ -290,32 +290,31 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
     <ClInclude Include="World.h" />
   </ItemGroup>
   <ItemGroup>
-    <FxCompile Include="ClosestHit.hlsl">
+    <FxCompile Include="ChunkAnyHit.hlsl">
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Library</ShaderType>
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">6.8</ShaderModel>
+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
       <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Custom%(Filename)Shader</VariableName>
       <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
-      <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-      </ObjectFileOutput>
-      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
+      <DisableOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DisableOptimizations>
       <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
       </EntryPointName>
+      <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </ObjectFileOutput>
     </FxCompile>
-    <None Include="Common.hlsl">
-      <FileType>Document</FileType>
-    </None>
-    <FxCompile Include="Miss.hlsl">
-      <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Custom%(Filename)Shader</VariableName>
+    <FxCompile Include="ChunkIntersection.hlsl">
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Library</ShaderType>
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">6.8</ShaderModel>
+      <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Custom%(Filename)Shader</VariableName>
       <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
-      <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-      </ObjectFileOutput>
       <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
+      <DisableOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DisableOptimizations>
       <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
       </EntryPointName>
+      <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </ObjectFileOutput>
     </FxCompile>
-    <FxCompile Include="RayGen.hlsl">
+    <FxCompile Include="ChunkClosestHit.hlsl">
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Library</ShaderType>
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">6.8</ShaderModel>
       <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Custom%(Filename)Shader</VariableName>
@@ -325,7 +324,11 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
       <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
       </EntryPointName>
+      <DisableOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DisableOptimizations>
     </FxCompile>
+    <None Include="Common.hlsl">
+      <FileType>Document</FileType>
+    </None>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 3 - 3
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -422,13 +422,13 @@
     </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <FxCompile Include="RayGen.hlsl">
+    <FxCompile Include="ChunkClosestHit.hlsl">
       <Filter>graphics\shader</Filter>
     </FxCompile>
-    <FxCompile Include="ClosestHit.hlsl">
+    <FxCompile Include="ChunkIntersection.hlsl">
       <Filter>graphics\shader</Filter>
     </FxCompile>
-    <FxCompile Include="Miss.hlsl">
+    <FxCompile Include="ChunkAnyHit.hlsl">
       <Filter>graphics\shader</Filter>
     </FxCompile>
   </ItemGroup>

+ 1 - 1
FactoryCraft/World.cpp

@@ -258,7 +258,7 @@ int World::update(bool background)
 
 void World::onTick(double time)
 {
-    selectionModel->tick(0.1);
+    //selectionModel->tick(0.1);
     this->time += time;
     if (this->time >= dayLength + nightLength + transitionLength * 2)
     {