Forráskód Böngészése

improve rendering performance by building a chunk botom level aceleration structure containing all simple blocks of a chunk

Kolja Strohm 2 hete
szülő
commit
41af9d4f7c

+ 5 - 7
FactoryCraft/Chunk.cpp

@@ -133,8 +133,7 @@ void Chunk::load(Framework::StreamReader* zReader)
             bLock.unlockWrite();
             if (b->isVisible())
             {
-                if (blockTypes[id]->getModelInfo().getModelName().isEqual(
-                        "cube"))
+                if (dx12Data->isSimpleBlock(b))
                 {
                     dx12Data->setBlock(index, b);
                 }
@@ -437,8 +436,7 @@ void Chunk::setBlock(Block* block)
     bLock.lockWrite();
     if (blocks[index])
     {
-        if (!blocks[index]->zBlockType()->getModelInfo().getModelName().isEqual(
-                "cube"))
+        if (!dx12Data->isSimpleBlock(blocks[index]))
         {
             vLock.lockWrite();
             for (Framework::ArrayIterator<Block*> vi = visibleBlocks.begin();
@@ -460,7 +458,7 @@ void Chunk::setBlock(Block* block)
     bLock.unlockWrite();
     if (block && block->isVisible())
     {
-        if (block->zBlockType()->getModelInfo().getModelName().isEqual("cube"))
+        if (dx12Data->isSimpleBlock(block))
         {
             dx12Data->setBlock(index, block);
         }
@@ -480,7 +478,7 @@ void Chunk::setBlock(Block* block)
 
 void Chunk::removeBlock(Block* zBlock)
 {
-    if (!zBlock->zBlockType()->getModelInfo().getModelName().isEqual("cube"))
+    if (!dx12Data->isSimpleBlock(zBlock))
     {
         vLock.lockWrite();
         for (Framework::ArrayIterator<Block*> iterator = visibleBlocks.begin();
@@ -501,7 +499,7 @@ void Chunk::removeBlock(Block* zBlock)
     if (pos.x < 0) pos.x += CHUNK_SIZE;
     if (pos.y < 0) pos.y += CHUNK_SIZE;
     int index = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
-    if (zBlock->zBlockType()->getModelInfo().getModelName().isEqual("cube"))
+    if (dx12Data->isSimpleBlock(zBlock))
     {
         dx12Data->setBlock(index, 0);
     }

+ 5 - 0
FactoryCraft/Common.hlsl

@@ -21,3 +21,8 @@ struct Attributes
     float2 texCoord;
     int textureId;
 };
+
+struct SimpleBlocksAttributes
+{
+    float2 bary;
+};

+ 1 - 1
FactoryCraft/Constants.h

@@ -5,6 +5,6 @@
 #ifdef _DEBUG
 #    define CHUNK_VISIBILITY_RANGE 10
 #else
-#    define CHUNK_VISIBILITY_RANGE 32
+#    define CHUNK_VISIBILITY_RANGE 16
 #endif
 #define MAX_VIEW_DISTANCE CHUNK_SIZE* CHUNK_VISIBILITY_RANGE

+ 126 - 1
FactoryCraft/CustomDX12API.cpp

@@ -13,6 +13,8 @@
 #include "CustomChunkAnyHitShader.h"
 #include "CustomChunkClosestHitShader.h"
 #include "CustomChunkIntersectionShader.h"
+#include "CustomSimpleBlocksAnyHitShader.h"
+#include "CustomSimpleBlocksClosestHitShader.h"
 #include "Dimension.h"
 #include "DX12ChunkData.h"
 
@@ -98,6 +100,7 @@ void CustomDX12API::initializePipeline()
         defaultHitGroup->setClosestHitShaderFunction(closestHitFunction);
         pipeline->addHitGroup(defaultHitGroup);
 
+        // Chunk ray traversal shaders
         DX12ShaderSignature* chunkHitSignature = new DX12ShaderSignature();
         chunkHitSignature->addRegisterUsageLinkedToDescriptorHeap(
             0, DX12_SHADER_REGISTER_S_SAMPLER, 0, 0, SAMPLER_DESCRIPTOR_HEAP);
@@ -153,6 +156,66 @@ void CustomDX12API::initializePipeline()
         chunkHitGroup->setPayloadSize(20 * DEFAULT_MAX_TRANSPARENT_HITS + 4);
         pipeline->addHitGroup(chunkHitGroup);
 
+        // simple blocks hit shaders
+        DX12ShaderSignature* simpleBlocksHitSignature
+            = new DX12ShaderSignature();
+        simpleBlocksHitSignature->addRegisterUsageLinkedToDescriptorHeap(
+            0, DX12_SHADER_REGISTER_S_SAMPLER, 0, 0, SAMPLER_DESCRIPTOR_HEAP);
+        simpleBlocksHitSignature->addRegisterUsageLinkedToDescriptorHeap(0,
+            DX12_SHADER_REGISTER_T_SHADER_RESOURCE,
+            0,
+            1,
+            TEXTURE_DESCRIPTOR_HEAP,
+            1);
+        sbtSimpleBlocksTextureIdBufferOffset
+            = simpleBlocksHitSignature
+                  ->addRegisterUsageLinkedToShaderBindingTable(
+                      DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 2);
+        sbtSimpleBlocksIndexBufferOffset
+            = simpleBlocksHitSignature
+                  ->addRegisterUsageLinkedToShaderBindingTable(
+                      DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 3);
+        sbtSimpleBlocksVertexDataBufferOffset
+            = simpleBlocksHitSignature
+                  ->addRegisterUsageLinkedToShaderBindingTable(
+                      DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 4);
+        sbtSimpleBlocksIndexOffsetBufferOffset
+            = simpleBlocksHitSignature
+                  ->addRegisterUsageLinkedToShaderBindingTable(
+                      DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 5);
+
+        DX12Shader* simpleBlocksAnyHitShader
+            = new DX12Shader(CustomSimpleBlocksAnyHitShader,
+                sizeof(CustomSimpleBlocksAnyHitShader));
+        DX12ShaderFunction* simpleBlocksAnyHitFunction
+            = new DX12ShaderFunction("SimpleBlocksAnyHit",
+                simpleBlocksHitSignature,
+                DX12_SHADER_FUNCTION_TYPE_ANY_HIT);
+        simpleBlocksAnyHitShader->addFunction(simpleBlocksAnyHitFunction);
+        pipeline->addShader(simpleBlocksAnyHitShader);
+
+        DX12Shader* simpleBlocksClosestHitShader
+            = new DX12Shader(CustomSimpleBlocksClosestHitShader,
+                sizeof(CustomSimpleBlocksClosestHitShader));
+        DX12ShaderFunction* simpleBlocksClosestHitFunction
+            = new DX12ShaderFunction("SimpleBlocksClosestHit",
+                dynamic_cast<DX12ShaderSignature*>(
+                    simpleBlocksHitSignature->getThis()),
+                DX12_SHADER_FUNCTION_TYPE_CLOSEST_HIT);
+        simpleBlocksClosestHitShader->addFunction(
+            simpleBlocksClosestHitFunction);
+        pipeline->addShader(simpleBlocksClosestHitShader);
+
+        simpleBlocksHitGroup = new DX12ShaderHitGroup("SimpleBlocksHitGroup");
+        simpleBlocksHitGroup->setAnyHitShaderFunction(
+            simpleBlocksAnyHitFunction);
+        simpleBlocksHitGroup->setClosestHitShaderFunction(
+            simpleBlocksClosestHitFunction);
+        simpleBlocksHitGroup->setAttributeSize(8);
+        simpleBlocksHitGroup->setPayloadSize(
+            20 * DEFAULT_MAX_TRANSPARENT_HITS + 4);
+        pipeline->addHitGroup(simpleBlocksHitGroup);
+
         pipeline->setMaxRecursionDepth(10);
     }
     pipeline->createPipelineState(device, pfnD3D12SerializeRootSignature);
@@ -189,6 +252,66 @@ void CustomDX12API::renderWorld(Framework::World3D* zWorld,
             {
                 DX12ChunkData* chunkData = chunk->zDX12Data();
                 chunkData->updateBuffers(device, directCommandQueue);
+                if (chunkData->hasCustomBlocks())
+                {
+                    bool changed
+                        = chunkData->wasCustomBufferChanged()
+                       || chunkData->getLastCustomObjectIndex() != objectIndex;
+                    if (changed)
+                    {
+                        chunkData->setLastCustomObjectIndex(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->zCustomBlocksBlasBuffer()
+                                  ->zBuffer()
+                                  ->GetGPUVirtualAddress();
+                        Framework::Mat4<float> transform
+                            = Framework::Mat4<float>::translation(
+                                Vec3<float>((float)chunk->getCenter().x,
+                                    (float)chunk->getCenter().y,
+                                    0.f));
+                        memcpy(desc->Transform, &transform, sizeof(float) * 12);
+                    }
+                    else
+                    {
+                        zTLAS->nextInstanceDesc();
+                    }
+                    int hitGroupOffset = zSBT->addHitGroup(simpleBlocksHitGroup,
+                        chunkData->getLastCustomHitGroupIndex());
+                    if (chunkData->getLastCustomHitGroupIndex()
+                            != hitGroupOffset
+                        || chunkData->wasCustomBufferChanged())
+                    {
+                        chunkData->setLastCustomHitGroupIndex(hitGroupOffset);
+                        zSBT->setHitGroupShaderInput(hitGroupOffset,
+                            sbtSimpleBlocksTextureIdBufferOffset,
+                            chunkData->zCustomBlocksTextureBuffer()
+                                ->zBuffer()
+                                ->GetGPUVirtualAddress());
+                        zSBT->setHitGroupShaderInput(hitGroupOffset,
+                            sbtSimpleBlocksIndexBufferOffset,
+                            chunkData->zCustomBlocksCombinedIndexBuffer()
+                                ->zBuffer()
+                                ->GetGPUVirtualAddress());
+                        zSBT->setHitGroupShaderInput(hitGroupOffset,
+                            sbtSimpleBlocksVertexDataBufferOffset,
+                            chunkData->zCustomBlocksVertexDataBuffer()
+                                ->zBuffer()
+                                ->GetGPUVirtualAddress());
+                        zSBT->setHitGroupShaderInput(hitGroupOffset,
+                            sbtSimpleBlocksIndexOffsetBufferOffset,
+                            chunkData->zCustomBlocksIndexOffsetBuffer()
+                                ->zBuffer()
+                                ->GetGPUVirtualAddress());
+                    }
+                    chunkData->setCustomBufferChanged(0);
+                    ++objectIndex;
+                }
                 bool changed = chunkData->wasBufferChanged()
                             || chunkData->getLastObjectIndex() != objectIndex;
                 if (changed)
@@ -211,7 +334,8 @@ void CustomDX12API::renderWorld(Framework::World3D* zWorld,
                 }
                 int hitGroupOffset = zSBT->addHitGroup(
                     chunkHitGroup, chunkData->getLastHitGroupIndex());
-                if (chunkData->getLastHitGroupIndex() != hitGroupOffset)
+                if (chunkData->getLastHitGroupIndex() != hitGroupOffset
+                    || chunkData->wasBufferChanged())
                 {
                     chunkData->setLastHitGroupIndex(hitGroupOffset);
                     zSBT->setHitGroupShaderInput(hitGroupOffset,
@@ -230,6 +354,7 @@ void CustomDX12API::renderWorld(Framework::World3D* zWorld,
                             ->zBuffer()
                             ->GetGPUVirtualAddress());
                 }
+                chunkData->setBufferChanged(0);
                 ++objectIndex;
             }
         }

+ 5 - 0
FactoryCraft/CustomDX12API.h

@@ -10,7 +10,12 @@ private:
     int* sbtChunkTextureIdBufferOffset;
     int* sbtChunkIndexBufferOffset;
     int* sbtChunkDataBufferOffset;
+    int* sbtSimpleBlocksTextureIdBufferOffset;
+    int* sbtSimpleBlocksIndexBufferOffset;
+    int* sbtSimpleBlocksVertexDataBufferOffset;
+    int* sbtSimpleBlocksIndexOffsetBufferOffset;
     Framework::DX12ShaderHitGroup* chunkHitGroup;
+    Framework::DX12ShaderHitGroup* simpleBlocksHitGroup;
 
 public:
     CustomDX12API();

+ 452 - 16
FactoryCraft/DX12ChunkData.cpp

@@ -1,19 +1,33 @@
 #include "Dx12ChunkData.h"
 
+#include <DX12BLASModel.h>
 #include <DX12CommandQueue.h>
 
+#include "Block.h"
 #include "Constants.h"
+#include "d3dx12.h"
+#include "Dimension.h"
 
 DX12ChunkData::DX12ChunkData(Framework::Point center)
     : ReferenceCounter(),
       aabbs(0),
       chunkInfoBuffer(0),
       blasScratchBuffer(0),
+      customBlocksBlasScratchBuffer(0),
+      oldBlasBuffer(0),
       blasBuffer(0),
+      customBlocksBlasBuffer(0),
       blockIndexBuffer(0),
       textureIdBuffer(0),
+      customBlockTextures(0),
+      customBlocksCombinedIndexBuffer(0),
+      customBlocksVertexDataBuffer(0),
+      customBlocksIndexOffsetBuffer(0),
+      customBlockMatrixBuffer(0),
       lastObjectIndex(-1),
+      lastCustomObjectIndex(-1),
       lastHitGroupIndex(-1),
+      lastCustomHitGroupIndex(-1),
       chunkCenter(center),
       blockIndices(new int[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT]),
       textureIds(),
@@ -21,7 +35,9 @@ DX12ChunkData::DX12ChunkData(Framework::Point center)
       bufferChanged(0),
       minZ(WORLD_HEIGHT),
       maxZ(0),
-      minMaxChanged(0)
+      minMaxChanged(0),
+      customBufferChanged(0),
+      customBlocksChanged(0)
 {
     memset(
         blockIndices, -1, sizeof(int) * CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
@@ -41,10 +57,22 @@ DX12ChunkData::~DX12ChunkData()
     {
         blasScratchBuffer->release();
     }
+    if (customBlocksBlasScratchBuffer)
+    {
+        customBlocksBlasScratchBuffer->release();
+    }
+    if (oldBlasBuffer)
+    {
+        oldBlasBuffer->Release();
+    }
     if (blasBuffer)
     {
         blasBuffer->release();
     }
+    if (customBlocksBlasBuffer)
+    {
+        customBlocksBlasBuffer->release();
+    }
     if (blockIndexBuffer)
     {
         blockIndexBuffer->release();
@@ -53,6 +81,26 @@ DX12ChunkData::~DX12ChunkData()
     {
         textureIdBuffer->release();
     }
+    if (customBlockTextures)
+    {
+        customBlockTextures->release();
+    }
+    if (customBlocksCombinedIndexBuffer)
+    {
+        customBlocksCombinedIndexBuffer->release();
+    }
+    if (customBlocksVertexDataBuffer)
+    {
+        customBlocksVertexDataBuffer->release();
+    }
+    if (customBlocksIndexOffsetBuffer)
+    {
+        customBlocksIndexOffsetBuffer->release();
+    }
+    if (customBlockMatrixBuffer)
+    {
+        customBlockMatrixBuffer->release();
+    }
     delete[] blockIndices;
 }
 
@@ -76,10 +124,36 @@ Framework::DX12Buffer* DX12ChunkData::zTextureIdBuffer() const
     return textureIdBuffer;
 }
 
+Framework::DX12Buffer* DX12ChunkData::zCustomBlocksBlasBuffer() const
+{
+    return customBlocksBlasBuffer;
+}
+
+Framework::DX12Buffer* DX12ChunkData::zCustomBlocksTextureBuffer() const
+{
+    return customBlockTextures;
+}
+
+Framework::DX12Buffer* DX12ChunkData::zCustomBlocksVertexDataBuffer() const
+{
+    return customBlocksVertexDataBuffer;
+}
+
+Framework::DX12Buffer* DX12ChunkData::zCustomBlocksCombinedIndexBuffer() const
+{
+    return customBlocksCombinedIndexBuffer;
+}
+
+Framework::DX12Buffer* DX12ChunkData::zCustomBlocksIndexOffsetBuffer() const
+{
+    return customBlocksIndexOffsetBuffer;
+}
+
 void DX12ChunkData::setBlock(int index, Block* zBlock)
 {
     cs.lock();
-    if (zBlock)
+    if (zBlock
+        && zBlock->zBlockType()->getModelInfo().getModelName().isEqual("cube"))
     {
         if (blockIndices[index] < 0)
         {
@@ -159,10 +233,55 @@ void DX12ChunkData::setBlock(int index, Block* zBlock)
         }
         blockIndices[index] = -1;
     }
+    if (zBlock
+        && !zBlock->zBlockType()->getModelInfo().getModelName().isEqual("cube"))
+    {
+        auto iterator = customBlocks.begin();
+        bool found = 0;
+        while (iterator)
+        {
+            if (iterator->getLocation() == zBlock->getLocation())
+            {
+                iterator.set(dynamic_cast<Block*>(zBlock->getThis()));
+                found = 1;
+                break;
+            }
+            ++iterator;
+        }
+        if (!found)
+        {
+            customBlocks.add(dynamic_cast<Block*>(zBlock->getThis()));
+        }
+        customBlocksChanged = 1;
+    }
+    if (!zBlock
+        || zBlock->zBlockType()->getModelInfo().getModelName().isEqual("cube"))
+    {
+        auto iterator = customBlocks.begin();
+        while (iterator)
+        {
+            if (Chunk::index(
+                    Dimension::chunkCoordinates(iterator->getLocation()))
+                == index)
+            {
+                iterator.remove();
+                customBlocksChanged = 1;
+                break;
+            }
+            ++iterator;
+        }
+    }
     changed = 1;
     cs.unlock();
 }
 
+struct ModelIdMapping
+{
+    int modelId;
+    int vertexBufferOffset;
+    int indexBufferOffset;
+};
+
 void DX12ChunkData::updateBuffers(
     ID3D12Device5* zDevice, Framework::DX12CommandQueue* zQueue)
 {
@@ -176,10 +295,10 @@ void DX12ChunkData::updateBuffers(
         aabbs->setLength(sizeof(D3D12_RAYTRACING_AABB));
         D3D12_RAYTRACING_AABB data = {chunkCenter.x - 8.f,
             chunkCenter.y - 8.f,
-            minZ,
+            (float)minZ,
             chunkCenter.x + 8.f,
             chunkCenter.y + 8.f,
-            maxZ};
+            (float)maxZ};
         aabbs->setData(&data, 1);
         aabbs->copyToGPU();
         minMaxChanged = 0;
@@ -188,15 +307,15 @@ void DX12ChunkData::updateBuffers(
     {
         D3D12_RAYTRACING_AABB data = {chunkCenter.x - 8.f,
             chunkCenter.y - 8.f,
-            minZ,
+            (float)minZ,
             chunkCenter.x + 8.f,
             chunkCenter.y + 8.f,
-            maxZ};
+            (float)maxZ};
         aabbs->setData(&data, 1);
         aabbs->copyToGPU();
         minMaxChanged = 0;
     }
-    if (!blasBuffer)
+    if (!blasBuffer || minMaxChanged)
     {
         D3D12_RAYTRACING_GEOMETRY_DESC geometryDesc = {};
         geometryDesc.Type
@@ -219,11 +338,15 @@ void DX12ChunkData::updateBuffers(
         D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO info = {};
         zDevice->GetRaytracingAccelerationStructurePrebuildInfo(
             &prebuildDesc, &info);
-        ID3D12Resource* oldBuffer = 0;
+        if (oldBlasBuffer)
+        {
+            oldBlasBuffer->Release();
+            oldBlasBuffer = 0;
+        }
         if (blasBuffer)
         {
-            oldBuffer = blasBuffer->zBuffer();
-            oldBuffer->AddRef();
+            oldBlasBuffer = blasBuffer->zBuffer();
+            oldBlasBuffer->AddRef();
             blasBuffer->release();
         }
         blasBuffer = new DX12Buffer(1,
@@ -253,18 +376,15 @@ void DX12ChunkData::updateBuffers(
             = {blasBuffer->zBuffer()->GetGPUVirtualAddress()};
         buildDesc.ScratchAccelerationStructureData
             = {blasScratchBuffer->zBuffer()->GetGPUVirtualAddress()};
-        buildDesc.SourceAccelerationStructureData = oldBuffer ? oldBuffer->GetGPUVirtualAddress() : 0;
+        buildDesc.SourceAccelerationStructureData
+            = oldBlasBuffer ? oldBlasBuffer->GetGPUVirtualAddress() : 0;
         buildDesc.Inputs.Flags
-            = oldBuffer
+            = oldBlasBuffer
                 ? D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE
                 : D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE;
 
         zQueue->zCommandList()->BuildRaytracingAccelerationStructure(
             &buildDesc, 0, nullptr);
-        if (oldBuffer)
-        {
-            oldBuffer->Release();
-        }
         bufferChanged = 1;
     }
     if (!blockIndexBuffer)
@@ -300,6 +420,279 @@ void DX12ChunkData::updateBuffers(
             D3D12_RESOURCE_FLAG_NONE);
         chunkInfoBuffer->setLength(sizeof(ChunkShaderInfo));
     }
+    if (customBlocksChanged)
+    {
+        int* cbts = new int[customBlocks.getEntryCount()];
+        int index = 0;
+        D3D12_RAYTRACING_GEOMETRY_DESC* simpleBlockDescs
+            = new D3D12_RAYTRACING_GEOMETRY_DESC[customBlocks.getEntryCount()];
+        int* indexOffsets = new int[customBlocks.getEntryCount()];
+        int vertexCount = 0;
+        int indexCount = 0;
+        Array<ModelIdMapping> idMapping;
+        for (Block* block : customBlocks)
+        {
+            int id = block->zModelData()->getId();
+            bool found = 0;
+            for (const ModelIdMapping& m : idMapping)
+            {
+                if (m.modelId == id)
+                {
+                    found = 1;
+                    break;
+                }
+            }
+            if (!found)
+            {
+                ModelIdMapping mapping;
+                mapping.modelId = id;
+                mapping.vertexBufferOffset = vertexCount;
+                mapping.indexBufferOffset = indexCount;
+                idMapping.add(mapping);
+                vertexCount += block->zModelData()->getVertexCount();
+                indexCount += block->zModelData()->getIndexCount();
+            }
+        }
+        int* combinedIndexBuffer = new int[indexCount];
+        Framework::DX2VertexData* vertexDataBuffer
+            = new Framework::DX2VertexData[vertexCount];
+        int vdIndex = 0;
+        Array<int> modelBuild;
+        float* matrixDataBuffer = new float[customBlocks.getEntryCount() * 12];
+        int blockIndex = 0;
+        for (Block* block : customBlocks)
+        {
+            Mat4<float> transform
+                = Mat4<float>::translation(
+                      (Vec3<float>)Dimension::chunkCoordinates(block->getLocation())
+                      + Vec3<float>(
+                          0.5f - CHUNK_SIZE / 2, 0.5f - CHUNK_SIZE / 2, 0.5f))
+                * Mat4<float>::rotationZ(block->getZRotation())
+                * Mat4<float>::rotationX(block->getXRotation())
+                * Mat4<float>::rotationY(block->getYRotation())
+                * Mat4<float>::scaling(block->getSize());
+            memcpy(matrixDataBuffer + 12 * blockIndex,
+                &transform,
+                12 * sizeof(float));
+            ++blockIndex;
+        }
+        if (!customBlockMatrixBuffer)
+        {
+            customBlockMatrixBuffer = new DX12Buffer(sizeof(float) * 12,
+                zDevice,
+                dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
+                D3D12_RESOURCE_FLAG_NONE);
+        }
+        customBlockMatrixBuffer->setLength(
+            sizeof(float) * 12 * customBlocks.getEntryCount());
+        customBlockMatrixBuffer->setData(matrixDataBuffer, 1);
+        customBlockMatrixBuffer->copyToGPU();
+        CD3DX12_RESOURCE_BARRIER transition
+            = CD3DX12_RESOURCE_BARRIER::Transition(
+                customBlockMatrixBuffer->zBuffer(),
+                D3D12_RESOURCE_STATE_COMMON,
+                D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
+        zQueue->zCommandList()->ResourceBarrier(1, &transition);
+        for (Block* block : customBlocks)
+        {
+            int id = block->zModelData()->getId();
+            ModelIdMapping mapping;
+            int mappingIndex = 0;
+            for (const ModelIdMapping& m : idMapping)
+            {
+                if (m.modelId == id)
+                {
+                    mapping = m;
+                    break;
+                }
+                ++mappingIndex;
+            }
+            if (modelBuild.getValueIndex(id) < 0)
+            {
+                modelBuild.add(id);
+                while (vertexBuffers.getEntryCount() <= mappingIndex)
+                {
+                    DX12Buffer* vBuffer = new DX12Buffer(sizeof(Vec3<float>),
+                        zDevice,
+                        dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
+                        D3D12_RESOURCE_FLAG_NONE);
+                    vertexBuffers.add(vBuffer);
+                }
+                while (indexBuffers.getEntryCount() <= mappingIndex)
+                {
+                    DX12Buffer* iBuffer = new DX12Buffer(sizeof(int),
+                        zDevice,
+                        dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
+                        D3D12_RESOURCE_FLAG_NONE);
+                    indexBuffers.add(iBuffer);
+                }
+                DX12Buffer* vBuffer = vertexBuffers.z(mappingIndex);
+                Vec3<float>* vertexBuffer
+                    = new Vec3<float>[block->zModelData()->getVertexCount()];
+                const Vertex3D* rawVertexData
+                    = block->zModelData()->zVertexBuffer();
+                for (int i = 0; i < block->zModelData()->getVertexCount(); ++i)
+                {
+                    vertexBuffer[i] = rawVertexData[i].pos;
+                    vertexDataBuffer[mapping.vertexBufferOffset + i]
+                        = {rawVertexData[i].tPos, rawVertexData[i].normal};
+                }
+                const int* rawIndexBuffer
+                    = block->zModelData()->getIndexBuffer();
+                for (int i = 0; i < block->zModelData()->getIndexCount(); i++)
+                {
+                    combinedIndexBuffer[mapping.indexBufferOffset + i]
+                        = rawIndexBuffer[i] + mapping.vertexBufferOffset;
+                }
+
+                vBuffer->setLength(sizeof(Vec3<float>)
+                                   * block->zModelData()->getVertexCount());
+                vBuffer->setData(vertexBuffer, 1);
+                vBuffer->copyToGPU();
+                delete[] vertexBuffer;
+
+                DX12Buffer* iBuffer = indexBuffers.z(mappingIndex);
+                iBuffer->setLength(
+                    sizeof(int) * block->zModelData()->getIndexCount());
+                iBuffer->setData((void*)rawIndexBuffer, 1);
+                iBuffer->copyToGPU();
+            }
+            DX12Buffer* vBuffer = vertexBuffers.z(mappingIndex);
+            DX12Buffer* iBuffer = indexBuffers.z(mappingIndex);
+            simpleBlockDescs[index].Type
+                = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;
+            simpleBlockDescs[index].Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE;
+            simpleBlockDescs[index].Triangles.VertexBuffer.StartAddress
+                = vBuffer->zBuffer()->GetGPUVirtualAddress();
+            simpleBlockDescs[index].Triangles.VertexBuffer.StrideInBytes
+                = vBuffer->getElementLength();
+            simpleBlockDescs[index].Triangles.VertexFormat
+                = DXGI_FORMAT_R32G32B32_FLOAT;
+            simpleBlockDescs[index].Triangles.VertexCount
+                = vBuffer->getElementCount();
+            simpleBlockDescs[index].Triangles.IndexBuffer
+                = iBuffer->zBuffer()->GetGPUVirtualAddress();
+            simpleBlockDescs[index].Triangles.IndexFormat
+                = DXGI_FORMAT_R32_UINT;
+            simpleBlockDescs[index].Triangles.IndexCount
+                = iBuffer->getElementCount();
+
+            simpleBlockDescs[index].Triangles.Transform3x4
+                = customBlockMatrixBuffer->zBuffer()->GetGPUVirtualAddress()
+                + 12 * index * sizeof(float);
+            cbts[index] = block->zTexture()->zPolygonTexture(0)->getId();
+            indexOffsets[index] = mapping.indexBufferOffset;
+            ++index;
+        }
+        D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS prebuildDesc;
+        prebuildDesc.Type
+            = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;
+        prebuildDesc.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
+        prebuildDesc.NumDescs = customBlocks.getEntryCount();
+        prebuildDesc.pGeometryDescs = simpleBlockDescs;
+        prebuildDesc.Flags
+            = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE;
+
+        D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO info = {};
+        zDevice->GetRaytracingAccelerationStructurePrebuildInfo(
+            &prebuildDesc, &info);
+
+        if (!customBlocksBlasScratchBuffer)
+        {
+            customBlocksBlasScratchBuffer = new DX12Buffer(1,
+                zDevice,
+                dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
+                D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
+        }
+        if (!customBlocksBlasBuffer)
+        {
+            customBlocksBlasBuffer = new DX12Buffer(1,
+                zDevice,
+                dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
+                D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
+        }
+        customBlocksBlasScratchBuffer->setLength(
+            ROUND_UP_POWER_OF_2((int)info.ScratchDataSizeInBytes, 256));
+        customBlocksBlasScratchBuffer->createBufferWithoutData(
+            D3D12_RESOURCE_STATE_COMMON);
+        customBlocksBlasBuffer->setLength(
+            ROUND_UP_POWER_OF_2((int)info.ResultDataMaxSizeInBytes, 256));
+        customBlocksBlasBuffer->createBufferWithoutData(
+            D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE);
+
+        D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc;
+        buildDesc.Inputs.Type
+            = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;
+        buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
+        buildDesc.Inputs.NumDescs = customBlocks.getEntryCount();
+        buildDesc.Inputs.pGeometryDescs = simpleBlockDescs;
+        buildDesc.DestAccelerationStructureData
+            = {customBlocksBlasBuffer->zBuffer()->GetGPUVirtualAddress()};
+        buildDesc.ScratchAccelerationStructureData = {
+            customBlocksBlasScratchBuffer->zBuffer()->GetGPUVirtualAddress()};
+        buildDesc.SourceAccelerationStructureData = 0;
+        buildDesc.Inputs.Flags
+            = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE;
+
+        zQueue->zCommandList()->BuildRaytracingAccelerationStructure(
+            &buildDesc, 0, nullptr);
+
+        if (!customBlockTextures)
+        {
+            customBlockTextures = new DX12Buffer(sizeof(int),
+                zDevice,
+                dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
+                D3D12_RESOURCE_FLAG_NONE);
+        }
+        customBlockTextures->setLength(
+            sizeof(int) * customBlocks.getEntryCount());
+        customBlockTextures->setData(cbts, 1);
+        customBlockTextures->copyToGPU();
+
+        if (!customBlocksIndexOffsetBuffer)
+        {
+            customBlocksIndexOffsetBuffer = new DX12Buffer(sizeof(int),
+                zDevice,
+                dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
+                D3D12_RESOURCE_FLAG_NONE);
+        }
+        customBlocksIndexOffsetBuffer->setLength(
+            sizeof(int) * customBlocks.getEntryCount());
+        customBlocksIndexOffsetBuffer->setData(indexOffsets, 1);
+        customBlocksIndexOffsetBuffer->copyToGPU();
+
+        if (!customBlocksVertexDataBuffer)
+        {
+            customBlocksVertexDataBuffer
+                = new DX12Buffer(sizeof(Framework::DX2VertexData),
+                    zDevice,
+                    dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
+                    D3D12_RESOURCE_FLAG_NONE);
+        }
+        customBlocksVertexDataBuffer->setLength(
+            sizeof(Framework::DX2VertexData) * vertexCount);
+        customBlocksVertexDataBuffer->setData(vertexDataBuffer, 1);
+        customBlocksVertexDataBuffer->copyToGPU();
+
+        if (!customBlocksCombinedIndexBuffer)
+        {
+            customBlocksCombinedIndexBuffer = new DX12Buffer(sizeof(int),
+                zDevice,
+                dynamic_cast<DX12CommandQueue*>(zQueue->getThis()),
+                D3D12_RESOURCE_FLAG_NONE);
+        }
+        customBlocksCombinedIndexBuffer->setLength(sizeof(int) * indexCount);
+        customBlocksCombinedIndexBuffer->setData(combinedIndexBuffer, 1);
+        customBlocksCombinedIndexBuffer->copyToGPU();
+
+        delete[] cbts;
+        delete[] simpleBlockDescs;
+        delete[] vertexDataBuffer;
+        delete[] indexOffsets;
+        delete[] combinedIndexBuffer;
+        customBlocksChanged = 0;
+        customBufferChanged = 1;
+    }
     if (changed)
     {
         for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; ++i)
@@ -334,21 +727,41 @@ int DX12ChunkData::getLastObjectIndex() const
     return lastObjectIndex;
 }
 
+int DX12ChunkData::getLastCustomObjectIndex() const
+{
+    return lastCustomObjectIndex;
+}
+
 int DX12ChunkData::getLastHitGroupIndex() const
 {
     return lastHitGroupIndex;
 }
 
+int DX12ChunkData::getLastCustomHitGroupIndex() const
+{
+    return lastCustomHitGroupIndex;
+}
+
 void DX12ChunkData::setLastObjectIndex(int index)
 {
     lastObjectIndex = index;
 }
 
+void DX12ChunkData::setLastCustomObjectIndex(int index)
+{
+    lastCustomObjectIndex = index;
+}
+
 void DX12ChunkData::setLastHitGroupIndex(int index)
 {
     lastHitGroupIndex = index;
 }
 
+void DX12ChunkData::setLastCustomHitGroupIndex(int index)
+{
+    lastCustomHitGroupIndex = index;
+}
+
 bool DX12ChunkData::wasBufferChanged() const
 {
     return bufferChanged;
@@ -358,3 +771,26 @@ void DX12ChunkData::setBufferChanged(bool changed)
 {
     bufferChanged = changed;
 }
+
+bool DX12ChunkData::isSimpleBlock(Block* zBlock) const
+{
+    return zBlock->zBlockType()->getModelInfo().getModelName().isEqual("cube")
+        || ((!zBlock->zModelData()->zSkeleton()
+                || zBlock->zModelData()->zSkeleton()->getNextBoneId() <= 1)
+            && zBlock->zModelData()->getPolygonCount() == 1);
+}
+
+bool DX12ChunkData::hasCustomBlocks() const
+{
+    return customBlocks.getEntryCount() > 0;
+}
+
+bool DX12ChunkData::wasCustomBufferChanged() const
+{
+    return customBufferChanged;
+}
+
+void DX12ChunkData::setCustomBufferChanged(bool changed)
+{
+    customBufferChanged = changed;
+}

+ 28 - 0
FactoryCraft/DX12ChunkData.h

@@ -18,16 +18,31 @@ private:
     Framework::DX12Buffer* aabbs;
     Framework::DX12Buffer* chunkInfoBuffer;
     Framework::DX12Buffer* blasScratchBuffer;
+    Framework::DX12Buffer* customBlocksBlasScratchBuffer;
+    ID3D12Resource* oldBlasBuffer;
     Framework::DX12Buffer* blasBuffer;
+    Framework::DX12Buffer* customBlocksBlasBuffer;
     Framework::DX12Buffer* blockIndexBuffer;
     Framework::DX12Buffer* textureIdBuffer;
+    RCArray<DX12Buffer> vertexBuffers;
+    RCArray<DX12Buffer> indexBuffers;
+    Framework::DX12Buffer* customBlockTextures;
+    Framework::DX12Buffer* customBlocksCombinedIndexBuffer;
+    Framework::DX12Buffer* customBlocksVertexDataBuffer;
+    Framework::DX12Buffer* customBlocksIndexOffsetBuffer;
+    Framework::DX12Buffer* customBlockMatrixBuffer;
+    RCArray<Block> customBlocks;
     Framework::Point chunkCenter;
     int* blockIndices;
     Framework::Array<int> textureIds;
     int lastObjectIndex;
+    int lastCustomObjectIndex;
     int lastHitGroupIndex;
+    int lastCustomHitGroupIndex;
     bool changed;
     bool bufferChanged;
+    bool customBufferChanged;
+    bool customBlocksChanged;
     int minZ;
     int maxZ;
     Critical cs;
@@ -40,13 +55,26 @@ public:
     Framework::DX12Buffer* zBlasBuffer() const;
     Framework::DX12Buffer* zBlockIndexBuffer() const;
     Framework::DX12Buffer* zTextureIdBuffer() const;
+    Framework::DX12Buffer* zCustomBlocksBlasBuffer() const;
+    Framework::DX12Buffer* zCustomBlocksTextureBuffer() const;
+    Framework::DX12Buffer* zCustomBlocksVertexDataBuffer() const;
+    Framework::DX12Buffer* zCustomBlocksCombinedIndexBuffer() const;
+    Framework::DX12Buffer* zCustomBlocksIndexOffsetBuffer() const;
     void setBlock(int index, Block* zBlock);
     void updateBuffers(
         ID3D12Device5* zDevice, Framework::DX12CommandQueue* zQueue);
     int getLastObjectIndex() const;
+    int getLastCustomObjectIndex() const;
     int getLastHitGroupIndex() const;
+    int getLastCustomHitGroupIndex() const;
     void setLastObjectIndex(int index);
+    void setLastCustomObjectIndex(int index);
     void setLastHitGroupIndex(int index);
+    void setLastCustomHitGroupIndex(int index);
     bool wasBufferChanged() const;
     void setBufferChanged(bool changed);
+    bool isSimpleBlock(Block* zBlock) const;
+    bool hasCustomBlocks() const;
+    bool wasCustomBufferChanged() const;
+    void setCustomBufferChanged(bool changed);
 };

+ 1 - 1
FactoryCraft/Entity.cpp

@@ -111,7 +111,7 @@ bool Entity::tick(double time)
         Block* b = target ? dynamic_cast<Block*>(target) : 0;
         ((Game*)(Menu*)menuRegister->get("game"))
             ->updatePosition(
-                pos, b != 0, b ? b->getLocation() : Vec3<int>(0, 0, 0));
+                pos, b != 0, b ? b->getLocation() : Vec3<int>(0, 0, 0), time);
         if (target) target->release();
     }
     return Model3D::tick(time);

+ 48 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -301,6 +301,12 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       </EntryPointName>
       <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
       </ObjectFileOutput>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Library</ShaderType>
+      <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6.8</ShaderModel>
+      <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader</VariableName>
+      <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
+      <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </ObjectFileOutput>
     </FxCompile>
     <FxCompile Include="ChunkIntersection.hlsl">
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Library</ShaderType>
@@ -313,6 +319,12 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       </EntryPointName>
       <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
       </ObjectFileOutput>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Library</ShaderType>
+      <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6.8</ShaderModel>
+      <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader</VariableName>
+      <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
+      <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </ObjectFileOutput>
     </FxCompile>
     <FxCompile Include="ChunkClosestHit.hlsl">
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Library</ShaderType>
@@ -325,6 +337,42 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
       </EntryPointName>
       <DisableOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DisableOptimizations>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Library</ShaderType>
+      <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6.8</ShaderModel>
+      <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader</VariableName>
+      <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
+      <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </ObjectFileOutput>
+    </FxCompile>
+    <FxCompile Include="SimpleBlocksAnyHit.hlsl">
+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
+      <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>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Library</ShaderType>
+      <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6.8</ShaderModel>
+      <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader</VariableName>
+      <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
+      <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </ObjectFileOutput>
+    </FxCompile>
+    <FxCompile Include="SimpleBlocksClosestHit.hlsl">
+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
+      <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>
+      <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Library</ShaderType>
+      <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6.8</ShaderModel>
+      <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader</VariableName>
+      <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
+      <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </ObjectFileOutput>
     </FxCompile>
     <None Include="Common.hlsl">
       <FileType>Document</FileType>

+ 6 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -431,6 +431,12 @@
     <FxCompile Include="ChunkAnyHit.hlsl">
       <Filter>graphics\shader</Filter>
     </FxCompile>
+    <FxCompile Include="SimpleBlocksAnyHit.hlsl">
+      <Filter>graphics\shader</Filter>
+    </FxCompile>
+    <FxCompile Include="SimpleBlocksClosestHit.hlsl">
+      <Filter>graphics\shader</Filter>
+    </FxCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="Common.hlsl">

+ 16 - 3
FactoryCraft/Game.cpp

@@ -107,9 +107,22 @@ Game::~Game()
 }
 
 void Game::updatePosition(
-    Vec3<float> position, bool target, Vec3<int> targetPos)
+    Vec3<float> position, bool target, Vec3<int> targetPos, double tickTime)
 {
-    Text txt = "Position: (";
+    fpsHistory.add(tickTime);
+    double fpsSum = 0;
+    for (double d : fpsHistory)
+    {
+        fpsSum += d;
+    }
+    while (fpsSum > 1)
+    {
+        fpsSum -= fpsHistory.get(0);
+        fpsHistory.remove(0);
+    }
+    Text txt = "";
+    txt.append() << "FPS: " << fpsHistory.getEntryCount() << "\n"
+                 << "Position: (";
     txt.setPrecision(2);
     txt += position.x;
     txt += ", ";
@@ -198,7 +211,7 @@ void Game::api(char* data)
                     World::INSTANCE->zKamera()->setControlEnabled(0);
                     window->zScreen()->addMember(dialog);
                     delete[] uiml;
-                    });
+                });
             }
             break;
         }

+ 5 - 1
FactoryCraft/Game.h

@@ -26,6 +26,7 @@ private:
     Framework::ImageView* searchIcon;
     ItemListContainer* itemListContainer;
     Framework::Button* chatButton;
+    Array<double> fpsHistory;
     MapWindow* mapWindow;
     Chat* chat;
     bool recipieVisible;
@@ -36,7 +37,10 @@ public:
     Game(Screen* zScreen);
     ~Game();
 
-    void updatePosition(Vec3<float> position, bool target, Vec3<int> targetPos);
+    void updatePosition(Vec3<float> position,
+        bool target,
+        Vec3<int> targetPos,
+        double tickTime);
     void api(char* data);
     void closeCurrentDialog();
     DragController<InventoryDragSource, int>* zInventoryDragController();

+ 2 - 0
FactoryCraft/Globals.h

@@ -4,6 +4,7 @@
 #include <Font.h>
 #include <HashMap.h>
 #include <RCPointer.h>
+#include <RenderThread.h>
 #include <Screen.h>
 #include <UIInitialization.h>
 #include <Window.h>
@@ -29,6 +30,7 @@ variable ItemType** itemTypes;
 variable int itemTypeCount;
 variable EntityType** entityTypes;
 variable int entityTypeCount;
+variable Framework::RenderTh* renderThread;
 
 void initVariables();
 void initMenus();

+ 0 - 2
FactoryCraft/Main.cpp

@@ -128,8 +128,6 @@ block type to render Block* b = type->createBlock(Vec3<float>(0, 0, 0));
 }
 */
 
-RenderTh* renderThread;
-
 int KSGStart Framework::Start(Framework::Startparam p)
 {
     Network::Start(20);

+ 85 - 0
FactoryCraft/SimpleBlocksAnyHit.hlsl

@@ -0,0 +1,85 @@
+#include "Common.hlsl"
+
+Texture2D<float4> textures[] : register(t0, space1);
+SamplerState gSampler : register(s0, space0);
+
+struct VertexData
+{
+    float2 texcoord;
+    float3 normal;
+};
+
+StructuredBuffer<int> textureIdBuffer : register(t1, space2);
+StructuredBuffer<int> indexBuffer : register(t1, space3);
+StructuredBuffer<VertexData> vertexData : register(t1, space4);
+StructuredBuffer<int> indexOffsetBuffer : register(t1, space5);
+
+
+[shader("anyhit")]
+void SimpleBlocksAnyHit(inout HitInfo payload, SimpleBlocksAttributes attrib)
+{
+    //payload.colorAndDistance = float4(1, 1, 1, 1.0);
+    int instanceId = InstanceID();
+    int currentTriangle = PrimitiveIndex();
+    int geometryIndex = GeometryIndex();
+    int textureId = textureIdBuffer[geometryIndex];
+    Texture2D<float4> texture = textures[textureId];
+    int index = indexOffsetBuffer[geometryIndex] + currentTriangle * 3;
+    VertexData v0 = vertexData[indexBuffer[index]];
+    VertexData v1 = vertexData[indexBuffer[index + 1]];
+    VertexData v2 = vertexData[indexBuffer[index + 2]];
+    float2 texcoord = v0.texcoord * (1 - attrib.bary.x - attrib.bary.y) + v1.texcoord * attrib.bary.x + v2.texcoord * attrib.bary.y;
+    float4 color = texture.SampleLevel(gSampler, 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();
+    }
+}

+ 21 - 0
FactoryCraft/SimpleBlocksClosestHit.hlsl

@@ -0,0 +1,21 @@
+#include "Common.hlsl"
+
+Texture2D<float4> textures[] : register(t0, space1);
+SamplerState gSampler : register(s0, space0);
+
+struct VertexData
+{
+    float2 texcoord;
+    float3 normal;
+};
+
+StructuredBuffer<int> textureIdBuffer : register(t1, space2);
+StructuredBuffer<int> indexBuffer : register(t1, space3);
+StructuredBuffer<VertexData> vertexData : register(t1, space4);
+StructuredBuffer<int> indexOffsetBuffer : register(t1, space5);
+
+[shader("closesthit")]
+void SimpleBlocksClosestHit(inout HitInfo payload, SimpleBlocksAttributes attrib)
+{
+    // TODO: reflection rays and shadow rays ...
+}