Browse Source

work on shadows

Kolja Strohm 1 tuần trước cách đây
mục cha
commit
8dd79d3945

+ 37 - 28
FactoryCraft/ChunkAnyHit.hlsl

@@ -1,45 +1,53 @@
 #include "Common.hlsl"
 
 [shader("anyhit")]
-void ChunkAnyHit(inout HitInfo payload, ChunkHitAttributes attrib)
+void ChunkAnyHit(inout HitInfo rayPayload, ChunkHitAttributes attrib)
 {
+    if (rayPayload.hitCount < 0)
+    { // shadow ray
+        rayPayload.hitCount = 0;
+        // TODO: transparent objects should lead to half shadows
+        AcceptHitAndEndSearch();
+        return;
+    }
     Texture2D<float4> texture = textures[attrib.textureId];
     float4 color = texture.SampleLevel(gSampler, attrib.texCoord, 0);
     if (color.w == 0.f)
     {
         IgnoreHit();
+        return;
     }
     float distance = RayTCurrent();
     bool found = false;
-    for (int i = 0; i < payload.hitCount; i++)
+    for (int i = 0; i < rayPayload.hitCount; i++)
     {
-        if (payload.distance[i] > distance)
+        if (rayPayload.distance[i] > distance)
         {
             found = true;
-            float4 tmpColor = payload.color[i];
-            payload.color[i] = color;
-            float tmpDistance = payload.distance[i];
-            payload.distance[i] = distance;
-            int tmpDayLight = payload.dayLight[i];
-            payload.dayLight[i] = attrib.dayLight;
-            int tmpDynamicLight = payload.dynamicLight[i];
-            payload.dynamicLight[i] = attrib.dynamicLight;
+            float4 tmpColor = rayPayload.color[i];
+            rayPayload.color[i] = color;
+            float tmpDistance = rayPayload.distance[i];
+            rayPayload.distance[i] = distance;
+            int tmpDayLight = rayPayload.dayLight[i];
+            rayPayload.dayLight[i] = attrib.dayLight;
+            int tmpDynamicLight = rayPayload.dynamicLight[i];
+            rayPayload.dynamicLight[i] = attrib.dynamicLight;
             if (color.w == 1.f)
             {
-                payload.hitCount = i + 1;
+                rayPayload.hitCount = i + 1;
             }
             else
             {
-                for (int j = i + 1; j < payload.hitCount + 1 && j < MAX_TRANSPACENT_HITS; j++)
+                for (int j = i + 1; j < rayPayload.hitCount + 1 && j < MAX_TRANSPACENT_HITS; j++)
                 {
-                    float4 tmpColor2 = payload.color[j];
-                    float tmpDistance2 = payload.distance[j];
-                    int tmpDayLight2 = payload.dayLight[j];
-                    int tmpDynamicLight2 = payload.dynamicLight[j];
-                    payload.color[j] = tmpColor;
-                    payload.distance[j] = tmpDistance;
-                    payload.dayLight[j] = tmpDayLight;
-                    payload.dynamicLight[j] = tmpDynamicLight;
+                    float4 tmpColor2 = rayPayload.color[j];
+                    float tmpDistance2 = rayPayload.distance[j];
+                    int tmpDayLight2 = rayPayload.dayLight[j];
+                    int tmpDynamicLight2 = rayPayload.dynamicLight[j];
+                    rayPayload.color[j] = tmpColor;
+                    rayPayload.distance[j] = tmpDistance;
+                    rayPayload.dayLight[j] = tmpDayLight;
+                    rayPayload.dynamicLight[j] = tmpDynamicLight;
                     tmpColor = tmpColor2;
                     tmpDistance = tmpDistance2;
                     tmpDayLight = tmpDayLight2;
@@ -50,23 +58,24 @@ void ChunkAnyHit(inout HitInfo payload, ChunkHitAttributes attrib)
         }
         else
         {
-            if (payload.color[i].w == 1.f)
+            if (rayPayload.color[i].w == 1.f)
             {
                 found = true;
                 break;
             }
         }
     }
-    if (!found && payload.hitCount < MAX_TRANSPACENT_HITS)
+    if (!found && rayPayload.hitCount < MAX_TRANSPACENT_HITS)
     {
-        payload.color[payload.hitCount] = color;
-        payload.distance[payload.hitCount] = distance;
-        payload.dayLight[payload.hitCount] = attrib.dayLight;
-        payload.dynamicLight[payload.hitCount] = attrib.dynamicLight;
-        payload.hitCount++;
+        rayPayload.color[rayPayload.hitCount] = color;
+        rayPayload.distance[rayPayload.hitCount] = distance;
+        rayPayload.dayLight[rayPayload.hitCount] = attrib.dayLight;
+        rayPayload.dynamicLight[rayPayload.hitCount] = attrib.dynamicLight;
+        rayPayload.hitCount++;
     }
     if (color.w < 1.f)
     {
         IgnoreHit();
+        return;
     }
 }

+ 26 - 2
FactoryCraft/ChunkClosestHit.hlsl

@@ -1,7 +1,31 @@
 #include "Common.hlsl"
 
 [shader("closesthit")]
-void ChunkClosestHit(inout HitInfo payload, ChunkHitAttributes attrib)
+void ChunkClosestHit(inout HitInfo currentPayload, ChunkHitAttributes attrib)
 {
-    // TODO: reflection rays and shadow rays ...
+    if (currentPayload.hitCount == 0)
+    {
+        return; // already inside of shadow ray
+    }
+    HitInfo tmpPayload;
+    // shadow rays
+    for (int i = 0; i < currentPayload.hitCount; i++)
+    {
+        tmpPayload.color[0].rgb = unpackLight(currentPayload.dayLight[i]) * dayLightFactor;
+        /*tmpPayload.hitCount = -1; // shadow ray
+        RayDesc ray;
+        ray.Origin = WorldRayOrigin() + (currentPayload.distance[i] - 0.0001) * WorldRayDirection();
+        ray.Direction = -dayLightDirection;
+        ray.TMin = 0.1;
+        ray.TMax = 1000;
+        TraceRay(TLAS,
+            0, 0xFF, 0,
+           0, 0, ray, tmpPayload);
+        if (tmpPayload.hitCount == 0)
+        {
+            tmpPayload.color[0].rgb = tmpPayload.color[0].rgb / 2;
+        }*/
+        currentPayload.dayLight[i] = packLight(tmpPayload.color[0].rgb);
+    }
+    // TODO: reflection rays
 }

+ 35 - 9
FactoryCraft/Common.hlsl

@@ -1,6 +1,6 @@
 // Hit information, aka ray payload
 // This sample only carries a shading color and hit distance.
-// Note that the payload should be kept as small as possible,
+// Note that the rayPayload should be kept as small as possible,
 // and that its size must be declared in the corresponding
 // D3D12_RAYTRACING_SHADER_CONFIG pipeline subobjet.
 
@@ -9,11 +9,11 @@
 
 struct [raypayload] HitInfo
 {
-    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);
-int dayLight[MAX_TRANSPACENT_HITS] : write(caller, closesthit, anyhit, miss) : read(caller, anyhit, closesthit);
-int dynamicLight[MAX_TRANSPACENT_HITS] : write(caller, closesthit, anyhit, miss) : read(caller, anyhit, closesthit);
-uint hitCount : write(caller, anyhit, closesthit, miss) : read(caller, anyhit, closesthit, miss);
+    float4 color[MAX_TRANSPACENT_HITS] : write(closesthit, anyhit, miss) : read(caller, anyhit, closesthit, miss);
+float distance[MAX_TRANSPACENT_HITS] : write(anyhit) : read(anyhit, closesthit);
+int dayLight[MAX_TRANSPACENT_HITS] : write(closesthit, anyhit, miss) : read(caller, anyhit, closesthit, miss);
+int dynamicLight[MAX_TRANSPACENT_HITS] : write(closesthit, anyhit, miss) : read(caller, anyhit, closesthit, miss);
+int hitCount : write(caller, anyhit, closesthit, miss) : read(caller, anyhit, closesthit, miss);
 };
 
 // Attributes output by the raytracing when hitting a surface,
@@ -31,12 +31,18 @@ struct SimpleBlocksAttributes
     float2 bary;
 };
 
-uint packLight(float3 light)
+struct VertexData
+{
+    float2 texcoord;
+    float3 normal;
+};
+
+int packLight(float3 light)
 {
     uint r = (uint) (light.r * 255.0) & 0xFF;
     uint g = (uint) (light.g * 255.0) & 0xFF;
     uint b = (uint) (light.b * 255.0) & 0xFF;
-    return (r << 16) | (g << 8) | b;
+    return (int) ((r << 16) | (g << 8) | b);
 }
 
 float3 unpackLight(int light)
@@ -49,4 +55,24 @@ float3 unpackLight(int light)
 
 // Global resources
 Texture2D<float4> textures[] : register(t0, space1);
-SamplerState gSampler : register(s0, space0);
+SamplerState gSampler : register(s0, space0);
+cbuffer DX12ShaderLightInfo : register(b0, space1)
+{
+    float3 dayLightFactor;
+    uint padding;
+    float3 dayLightDirection;
+};
+// Raytracing acceleration structure, accessed as a SRV
+RaytracingAccelerationStructure TLAS : register(t0, space0);
+
+RWTexture2D<float4> gOutput : register(u0);
+RWTexture2D<float4> guiTexture : register(u1);
+cbuffer RayGenerationSettings : register(b0, space0)
+{
+    int renderGui;
+    int useRays;
+    float minDistance;
+    float maxDistance;
+    float4x4 inverseView;
+    float4x4 inverseProjection;
+};

+ 1 - 1
FactoryCraft/Constants.h

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

+ 86 - 16
FactoryCraft/CustomDX12API.cpp

@@ -3,6 +3,7 @@
 #include <DX12Buffer.h>
 #include <DX12CommandQueue.h>
 #include <DX12Shader.h>
+#include <DX12Texture.h>
 #include <DX12TLAS.h>
 
 #include "CustomChunkAnyHitShader.h"
@@ -16,40 +17,76 @@
 #include "CustomSimpleBlocksClosestHitShader.h"
 #include "Dimension.h"
 #include "DX12ChunkData.h"
+#include "World.h"
 
 using namespace Framework;
 
 CustomDX12API::CustomDX12API()
-    : DirectX12()
+    : DirectX12(),
+      lightInfoBuffer(0)
 {}
 
-CustomDX12API::~CustomDX12API() {}
+CustomDX12API::~CustomDX12API()
+{
+    if (lightInfoBuffer)
+    {
+        lightInfoBuffer->release();
+    }
+}
 
 void CustomDX12API::initializePipeline()
 {
+    if (!lightInfoBuffer)
+    {
+        lightInfoBuffer = new DX12Buffer(sizeof(DX12ShaderLightInfo),
+            device,
+            dynamic_cast<DX12CommandQueue*>(directCommandQueue->getThis()),
+            D3D12_RESOURCE_FLAG_NONE);
+        lightInfoBuffer->setData(&lightInfo, 1);
+        lightInfoBuffer->setLength(sizeof(DX12ShaderLightInfo));
+    }
     if (pipeline->getShaders().getEntryCount() == 0)
     { // add default shaders
         pipeline->zGlobalSignature()->addRegisterUsageLinkedToDescriptorHeap(
             0, DX12_SHADER_REGISTER_S_SAMPLER, 0, 0, SAMPLER_DESCRIPTOR_HEAP);
-        pipeline->zGlobalSignature()->addRegisterUsageLinkedToDescriptorHeap(0,
+        pipeline->zGlobalSignature()->addRegisterUsageLinkedToDescriptorHeap(2,
             DX12_SHADER_REGISTER_T_SHADER_RESOURCE,
             0,
             1,
             TEXTURE_DESCRIPTOR_HEAP,
             1);
+        globalLightBufferOffset
+            = pipeline->zGlobalSignature()
+                  ->addRegisterUsageLinkedToShaderBindingTable(
+                      DX12_SHADER_REGISTER_B_CONST_BUFFER, 0, 1);
+        globalTLASoffset = pipeline->zGlobalSignature()
+                               ->addRegisterUsageLinkedToShaderBindingTable(
+                                   DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 0);
+        pipeline->zGlobalSignature()->addRegisterUsageLinkedToDescriptorHeap(0,
+            DX12_SHADER_REGISTER_U_UNORDERED_ACCESS,
+            0,
+            0,
+            TEXTURE_DESCRIPTOR_HEAP);
+        pipeline->zGlobalSignature()->addRegisterUsageLinkedToDescriptorHeap(1,
+            DX12_SHADER_REGISTER_U_UNORDERED_ACCESS,
+            1,
+            0,
+            TEXTURE_DESCRIPTOR_HEAP);
+        globalRayGenerationSettingsOffset
+            = pipeline->zGlobalSignature()
+                  ->addRegisterUsageLinkedToShaderBindingTable(
+                      DX12_SHADER_REGISTER_B_CONST_BUFFER, 0);
 
         DX12Shader* rayGenShader = new DX12Shader(
             CustomCustomRayGenShader, sizeof(CustomCustomRayGenShader));
         // 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);
+        // 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);
         defaultRayGenerationShaderFunction = new DX12ShaderFunction(
             "RayGen", rayGenSignature, DX12_SHADER_FUNCTION_TYPE_RAY_GEN);
         rayGenShader->addFunction(defaultRayGenerationShaderFunction);
@@ -208,11 +245,6 @@ void CustomDX12API::initializePipeline()
     pipeline->createPipelineState(device, pfnD3D12SerializeRootSignature);
 }
 
-void CustomDX12API::initializeGlobalDescriptorHeap()
-{
-    DirectX12::initializeGlobalDescriptorHeap();
-}
-
 void CustomDX12API::fillShaderBindingTable(
     Framework::DX12ShaderBindingTable* zShaderBindingTable,
     Framework::Model3D* zModel,
@@ -224,6 +256,35 @@ void CustomDX12API::fillShaderBindingTable(
         zShaderBindingTable, zModel, objectIndex, zBLAS, lastHitGroupIndex);
 }
 
+int CustomDX12API::fillGlobalShaderParams(
+    Cam3D* zCam, DX12TLAS* zTLAS, DX12Texture* zTarget, int startIndex)
+{
+    if (World::INSTANCE)
+    {
+        lightInfo.dayLightFactor = World::INSTANCE->getDayLightFactor();
+        lightInfo.dayLightDirection = World::INSTANCE->getDayLightDirection();
+    }
+    else
+    {
+        lightInfo.dayLightFactor = Vec3<float>(1.f, 1.f, 1.f);
+        lightInfo.dayLightDirection = Vec3<float>(0.f, 0.f, -1.f);
+    }
+    lightInfoBuffer->setChanged();
+    lightInfoBuffer->copyToGPU();
+    int result
+        = DirectX12::fillGlobalShaderParams(zCam, zTLAS, zTarget, startIndex);
+    directCommandQueue->zCommandList()->SetComputeRootConstantBufferView(
+        *globalLightBufferOffset,
+        lightInfoBuffer->zBuffer()->GetGPUVirtualAddress());
+    directCommandQueue->zCommandList()->SetComputeRootShaderResourceView(
+        *globalTLASoffset,
+        zTLAS->zResultBuffer()->zBuffer()->GetGPUVirtualAddress());
+    directCommandQueue->zCommandList()->SetComputeRootConstantBufferView(
+        *globalRayGenerationSettingsOffset,
+        rayGenSettingsBuffer->zBuffer()->GetGPUVirtualAddress());
+    return result;
+}
+
 void CustomDX12API::renderWorld(Framework::World3D* zWorld,
     DX12TLAS* zTLAS,
     DX12ShaderBindingTable* zSBT,
@@ -353,3 +414,12 @@ void CustomDX12API::renderWorld(Framework::World3D* zWorld,
     }
     DirectX12::renderWorld(zWorld, zTLAS, zSBT, objectIndex);
 }
+
+void CustomDX12API::initializeTextureDescriptorHeap()
+{
+    textureDescriptorHeap->addTextureInput(
+        DX12_SHADER_REGISTER_U_UNORDERED_ACCESS, defaultRenderTarget);
+    textureDescriptorHeap->addTextureInput(
+        DX12_SHADER_REGISTER_U_UNORDERED_ACCESS, uiTexture);
+    DirectX12::initializeTextureDescriptorHeap();
+}

+ 19 - 1
FactoryCraft/CustomDX12API.h

@@ -2,8 +2,17 @@
 
 #include <DX12GraphicsApi.h>
 #include <DX12Shader.h>
+#include <Vec3.h>
 #include <World3D.h>
 
+struct DX12ShaderLightInfo
+{
+    Framework::Vec3<float> dayLightFactor;
+    unsigned int padding; // Padding to align to 16 bytes
+    Framework::Vec3<float> dayLightDirection;
+    unsigned int padding2; // Padding to align to 16 bytes
+};
+
 class CustomDX12API : public Framework::DirectX12
 {
 private:
@@ -15,23 +24,32 @@ private:
     int* sbtSimpleBlocksIndexBufferOffset;
     int* sbtSimpleBlocksVertexDataBufferOffset;
     int* sbtSimpleBlocksIndexOffsetBufferOffset;
+    int* globalLightBufferOffset;
+    int* globalTLASoffset;
+    int* globalRayGenerationSettingsOffset;
     Framework::DX12ShaderHitGroup* chunkHitGroup;
     Framework::DX12ShaderHitGroup* simpleBlocksHitGroup;
+    Framework::DX12Buffer* lightInfoBuffer;
+    DX12ShaderLightInfo lightInfo;
 
 public:
     CustomDX12API();
     ~CustomDX12API();
 
     void initializePipeline() override;
-    void initializeGlobalDescriptorHeap() override;
     void fillShaderBindingTable(
         Framework::DX12ShaderBindingTable* zShaderBindingTable,
         Framework::Model3D* zModel,
         int objectIndex,
         const Framework::DX12BLAS* zBLAS,
         int& lastHitGroupIndex) override;
+    int fillGlobalShaderParams(Framework::Cam3D* zCam,
+        Framework::DX12TLAS* zTLAS,
+        Framework::DX12Texture* zTarget,
+        int startIndex = 0) override;
     void renderWorld(Framework::World3D* zWorld,
         Framework::DX12TLAS* zTLAS,
         Framework::DX12ShaderBindingTable* zSBT,
         int& objectIndex) override;
+    void initializeTextureDescriptorHeap() override;
 };

+ 10 - 6
FactoryCraft/CustomMiss.hlsl

@@ -1,13 +1,17 @@
 #include "Common.hlsl"
 
 [shader("miss")]
-void Miss(inout HitInfo payload : SV_RayPayload)
+void Miss(inout HitInfo rayPayload : SV_RayPayload)
 {
-    if (payload.hitCount < MAX_TRANSPACENT_HITS)
+    if (rayPayload.hitCount < 0)
+    { // shadow ray
+        return;
+    }
+    if (rayPayload.hitCount < MAX_TRANSPACENT_HITS)
     {
-        payload.color[payload.hitCount] = float4(0.2f, 0.2f, 0.2f, -1.f);
-        payload.dayLight[payload.hitCount] = 0xFFFFFF;
-        payload.dynamicLight[payload.hitCount] = 0;
-        payload.hitCount++;
+        rayPayload.color[rayPayload.hitCount] = float4(0.2f, 0.2f, 0.2f, -1.f);
+        rayPayload.dayLight[rayPayload.hitCount] = 0xFFFFFF;
+        rayPayload.dynamicLight[rayPayload.hitCount] = 0;
+        rayPayload.hitCount++;
     }
 }

+ 7 - 18
FactoryCraft/CustomRayGen.hlsl

@@ -1,29 +1,18 @@
 #include "Common.hlsl"
 
-// Raytracing output texture, accessed as a UAV
-RWTexture2D<float4> gOutput : register(u0);
-
-RWTexture2D<float4> guiTexture : register(u1);
-
-// Raytracing acceleration structure, accessed as a SRV
-RaytracingAccelerationStructure TLAS : register(t0);
-
-cbuffer RayGenerationSettings : register(b0)
-{
-    int renderGui;
-    int useRays;
-    float minDistance;
-    float maxDistance;
-    float4x4 inverseView;
-    float4x4 inverseProjection;
-}
-
 [shader("raygeneration")]
 void RayGen()
 {
   // Initialize the ray payload
     HitInfo rayPayload;
     rayPayload.hitCount = 0;
+    for (int i = 0; i < MAX_TRANSPACENT_HITS; i++)
+    {
+        rayPayload.color[i] = float4(0, 0, 0, 0.f);
+        rayPayload.dayLight[i] = 0;
+        rayPayload.dynamicLight[i] = 0;
+        rayPayload.distance[i] = 0;
+    }
     float3 color = float3(0, 0, 0);
 
     // Get the location within the dispatched 2D grid of work items

+ 8 - 5
FactoryCraft/DX12ChunkData.cpp

@@ -318,11 +318,13 @@ void DX12ChunkData::updateLightning(Chunk* zChunk)
         {
             Vec3<int> blockLocation = Chunk::chunkCoordinates(i);
             Block* zBlock = zChunk->zBlockAt(blockLocation);
+
             union
             {
                 const unsigned char* neighborLightMap[3][3][3];
                 const unsigned char* neighborLightMapEntries[3 * 3 * 3];
             };
+
             for (int j = 0; j < 3 * 3 * 3; j++)
             {
                 neighborLightMapEntries[j] = noLightData;
@@ -378,9 +380,10 @@ void DX12ChunkData::updateLightning(Chunk* zChunk)
                 int count = 0;
                 for (int d = 1; d < 8; d++)
                 {
-                    Directions direction = vertexDirections[j][0] * ((d & 0x1) != 0)
-                                         + vertexDirections[j][1] * ((d & 0x2) != 0)
-                                         + vertexDirections[j][2] * ((d & 0x4) != 0);
+                    Directions direction
+                        = vertexDirections[j][0] * ((d & 0x1) != 0)
+                        + vertexDirections[j][1] * ((d & 0x2) != 0)
+                        + vertexDirections[j][2] * ((d & 0x4) != 0);
                     Vec3<int> index = getDirection(direction);
                     bool notZero = 0;
                     const unsigned char* currentLight
@@ -706,13 +709,13 @@ void DX12ChunkData::updateBuffers(
             simpleBlockDescs[index].Triangles.VertexFormat
                 = DXGI_FORMAT_R32G32B32_FLOAT;
             simpleBlockDescs[index].Triangles.VertexCount
-                = vBuffer->getElementCount();
+                = (unsigned)vBuffer->getElementCount();
             simpleBlockDescs[index].Triangles.IndexBuffer
                 = iBuffer->zBuffer()->GetGPUVirtualAddress();
             simpleBlockDescs[index].Triangles.IndexFormat
                 = DXGI_FORMAT_R32_UINT;
             simpleBlockDescs[index].Triangles.IndexCount
-                = iBuffer->getElementCount();
+                = (unsigned)iBuffer->getElementCount();
 
             simpleBlockDescs[index].Triangles.Transform3x4
                 = customBlockMatrixBuffer->zBuffer()->GetGPUVirtualAddress()

+ 53 - 36
FactoryCraft/DefaultAnyHit.hlsl

@@ -1,30 +1,45 @@
 #include "Common.hlsl"
 
-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> polygonSizeBuffer : register(t1, space5);
 
 [shader("anyhit")]
-void AnyHit(inout HitInfo payload, SimpleBlocksAttributes attrib)
+void AnyHit(inout HitInfo rayPayload, SimpleBlocksAttributes attrib)
 {
-    //payload.colorAndDistance = float4(1, 1, 1, 1.0);
+    if (rayPayload.hitCount < 0)
+    { // shadow ray
+        rayPayload.hitCount = 0;
+        // TODO: transparent objects should lead to half shadows
+        AcceptHitAndEndSearch();
+        return;
+    }
     int instanceId = InstanceID();
     int currentTriangle = PrimitiveIndex();
     int textureId = 0;
-    for (int i = 0; currentTriangle >= 0; i++)
+    int i;
+    for (i = 0; currentTriangle >= 0 && polygonSizeBuffer[i] > 0; i++)
     {
         currentTriangle -= polygonSizeBuffer[i];
         textureId = textureIdBuffer[i];
     }
+    if (polygonSizeBuffer[i] <= 0)
+    {
+        // Could not find geometry index, ignore hit
+        IgnoreHit();
+        return;
+    }
     Texture2D<float4> texture = textures[textureId];
     int index = PrimitiveIndex() * 3;
+
+    // Bounds check for vertex indices
+    if (indexBuffer[index] < 0 || indexBuffer[index + 1] < 0 || indexBuffer[index + 2] < 0)
+    {
+        IgnoreHit();
+        return;
+    }
+
     VertexData v0 = vertexData[indexBuffer[index]];
     VertexData v1 = vertexData[indexBuffer[index + 1]];
     VertexData v2 = vertexData[indexBuffer[index + 2]];
@@ -33,38 +48,39 @@ void AnyHit(inout HitInfo payload, SimpleBlocksAttributes attrib)
     if (color.w == 0.f)
     {
         IgnoreHit();
+        return;
     }
     float distance = RayTCurrent();
     bool found = false;
-    for (int i = 0; i < payload.hitCount; i++)
+    for (i = 0; i < rayPayload.hitCount; i++)
     {
-        if (payload.distance[i] > distance)
+        if (rayPayload.distance[i] > distance)
         {
             found = true;
-            float4 tmpColor = payload.color[i];
-            payload.color[i] = color;
-            float tmpDistance = payload.distance[i];
-            payload.distance[i] = distance;
-            int tmpDayLight = payload.dayLight[i];
-            payload.dayLight[i] = 0xFFFFFF;
-            int tmpDynamicLight = payload.dynamicLight[i];
-            payload.dynamicLight[i] = 0xFFFFFF;
+            float4 tmpColor = rayPayload.color[i];
+            rayPayload.color[i] = color;
+            float tmpDistance = rayPayload.distance[i];
+            rayPayload.distance[i] = distance;
+            int tmpDayLight = rayPayload.dayLight[i];
+            rayPayload.dayLight[i] = 0xFFFFFF;
+            int tmpDynamicLight = rayPayload.dynamicLight[i];
+            rayPayload.dynamicLight[i] = 0xFFFFFF;
             if (color.w == 1.f)
             {
-                payload.hitCount = i + 1;
+                rayPayload.hitCount = i + 1;
             }
             else
             {
-                for (int j = i + 1; j < payload.hitCount + 1 && j < MAX_TRANSPACENT_HITS; j++)
+                for (int j = i + 1; j < rayPayload.hitCount + 1 && j < MAX_TRANSPACENT_HITS; j++)
                 {
-                    float4 tmpColor2 = payload.color[j];
-                    float tmpDistance2 = payload.distance[j];
-                    int tmpDayLight2 = payload.dayLight[j];
-                    int tmpDynamicLight2 = payload.dynamicLight[j];
-                    payload.color[j] = tmpColor;
-                    payload.distance[j] = tmpDistance;
-                    payload.dayLight[j] = tmpDayLight;
-                    payload.dynamicLight[j] = tmpDynamicLight;
+                    float4 tmpColor2 = rayPayload.color[j];
+                    float tmpDistance2 = rayPayload.distance[j];
+                    int tmpDayLight2 = rayPayload.dayLight[j];
+                    int tmpDynamicLight2 = rayPayload.dynamicLight[j];
+                    rayPayload.color[j] = tmpColor;
+                    rayPayload.distance[j] = tmpDistance;
+                    rayPayload.dayLight[j] = tmpDayLight;
+                    rayPayload.dynamicLight[j] = tmpDynamicLight;
                     tmpColor = tmpColor2;
                     tmpDistance = tmpDistance2;
                     tmpDayLight = tmpDayLight2;
@@ -75,23 +91,24 @@ void AnyHit(inout HitInfo payload, SimpleBlocksAttributes attrib)
         }
         else
         {
-            if (payload.color[i].w == 1.f)
+            if (rayPayload.color[i].w == 1.f)
             {
                 found = true;
                 break;
             }
         }
     }
-    if (!found && payload.hitCount < MAX_TRANSPACENT_HITS)
+    if (!found && rayPayload.hitCount < MAX_TRANSPACENT_HITS)
     {
-        payload.color[payload.hitCount] = color;
-        payload.distance[payload.hitCount] = distance;
-        payload.dayLight[payload.hitCount] = 0xFFFFFF;
-        payload.dynamicLight[payload.hitCount] = 0xFFFFFF;
-        payload.hitCount++;
+        rayPayload.color[rayPayload.hitCount] = color;
+        rayPayload.distance[rayPayload.hitCount] = distance;
+        rayPayload.dayLight[rayPayload.hitCount] = 0xFFFFFF;
+        rayPayload.dynamicLight[rayPayload.hitCount] = 0xFFFFFF;
+        rayPayload.hitCount++;
     }
     if (color.w < 1.f)
     {
         IgnoreHit();
+        return;
     }
 }

+ 1 - 7
FactoryCraft/DefaultClosestHit.hlsl

@@ -1,18 +1,12 @@
 #include "Common.hlsl"
 
-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> polygonSizeBuffer : register(t1, space5);
 
 [shader("closesthit")]
-void ClosestHit(inout HitInfo payload, SimpleBlocksAttributes attrib)
+void ClosestHit(inout HitInfo rayPayload, SimpleBlocksAttributes attrib)
 {
     // TODO: reflection rays and shadow rays ...
 }

+ 52 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -307,6 +307,8 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
       <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
       </ObjectFileOutput>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">COMPILE</PreprocessorDefinitions>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">COMPILE</PreprocessorDefinitions>
     </FxCompile>
     <FxCompile Include="ChunkIntersection.hlsl">
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Library</ShaderType>
@@ -325,6 +327,8 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
       <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
       </ObjectFileOutput>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">COMPILE</PreprocessorDefinitions>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">COMPILE</PreprocessorDefinitions>
     </FxCompile>
     <FxCompile Include="ChunkClosestHit.hlsl">
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Library</ShaderType>
@@ -343,6 +347,8 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
       <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
       </ObjectFileOutput>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">COMPILE</PreprocessorDefinitions>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">COMPILE</PreprocessorDefinitions>
     </FxCompile>
     <FxCompile Include="CustomMiss.hlsl">
       <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
@@ -358,6 +364,13 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6.8</ShaderModel>
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Library</ShaderType>
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">6.8</ShaderModel>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">COMPILE</PreprocessorDefinitions>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </PreprocessorDefinitions>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </EntryPointName>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </EntryPointName>
     </FxCompile>
     <FxCompile Include="CustomRayGen.hlsl">
       <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
@@ -373,6 +386,13 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">6.8</ShaderModel>
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Library</ShaderType>
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6.8</ShaderModel>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </PreprocessorDefinitions>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">COMPILE</PreprocessorDefinitions>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </EntryPointName>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </EntryPointName>
     </FxCompile>
     <FxCompile Include="DefaultAnyHit.hlsl">
       <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
@@ -388,6 +408,14 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6.8</ShaderModel>
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Library</ShaderType>
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">6.8</ShaderModel>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </PreprocessorDefinitions>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </PreprocessorDefinitions>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </EntryPointName>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </EntryPointName>
     </FxCompile>
     <FxCompile Include="DefaultClosestHit.hlsl">
       <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
@@ -403,6 +431,14 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">6.8</ShaderModel>
       <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Library</ShaderType>
       <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6.8</ShaderModel>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </PreprocessorDefinitions>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </PreprocessorDefinitions>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </EntryPointName>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </EntryPointName>
     </FxCompile>
     <FxCompile Include="SimpleBlocksAnyHit.hlsl">
       <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
@@ -418,6 +454,14 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
       <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
       </ObjectFileOutput>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </PreprocessorDefinitions>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </PreprocessorDefinitions>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </EntryPointName>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </EntryPointName>
     </FxCompile>
     <FxCompile Include="SimpleBlocksClosestHit.hlsl">
       <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">-Fd Custom%(Filename).pdb %(AdditionalOptions)</AdditionalOptions>
@@ -433,6 +477,14 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
       <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Custom%(Filename)Shader.h</HeaderFileOutput>
       <ObjectFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
       </ObjectFileOutput>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </PreprocessorDefinitions>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </PreprocessorDefinitions>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </EntryPointName>
+      <EntryPointName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+      </EntryPointName>
     </FxCompile>
     <None Include="Common.hlsl">
       <FileType>Document</FileType>

+ 56 - 36
FactoryCraft/SimpleBlocksAnyHit.hlsl

@@ -1,11 +1,5 @@
 #include "Common.hlsl"
 
-struct VertexData
-{
-    float2 texcoord;
-    float3 normal;
-};
-
 StructuredBuffer<int> textureIdBuffer : register(t1, space2);
 StructuredBuffer<int> indexBuffer : register(t1, space3);
 StructuredBuffer<VertexData> vertexData : register(t1, space4);
@@ -13,15 +7,39 @@ StructuredBuffer<int> indexOffsetBuffer : register(t1, space5);
 
 
 [shader("anyhit")]
-void SimpleBlocksAnyHit(inout HitInfo payload, SimpleBlocksAttributes attrib)
+void SimpleBlocksAnyHit(inout HitInfo rayPayload, SimpleBlocksAttributes attrib)
 {
-    //payload.colorAndDistance = float4(1, 1, 1, 1.0);
+    if (rayPayload.hitCount < 0)
+    { // shadow ray
+        rayPayload.hitCount = 0;
+        // TODO: transparent objects should lead to half shadows
+        AcceptHitAndEndSearch();
+        return;
+    }
     int instanceId = InstanceID();
     int currentTriangle = PrimitiveIndex();
     int geometryIndex = GeometryIndex();
+
+    // Bounds check for geometryIndex
+    if (geometryIndex < 0)
+    {
+        IgnoreHit();
+        return;
+    }
+
     int textureId = textureIdBuffer[geometryIndex];
     Texture2D<float4> texture = textures[textureId];
-    int index = indexOffsetBuffer[geometryIndex] + currentTriangle * 3;
+
+    int indexOffset = indexOffsetBuffer[geometryIndex];
+    int index = indexOffset + currentTriangle * 3;
+
+    // Bounds check for indices
+    if (indexBuffer[index] < 0 || indexBuffer[index + 1] < 0 || indexBuffer[index + 2] < 0)
+    {
+        IgnoreHit();
+        return;
+    }
+
     VertexData v0 = vertexData[indexBuffer[index]];
     VertexData v1 = vertexData[indexBuffer[index + 1]];
     VertexData v2 = vertexData[indexBuffer[index + 2]];
@@ -30,38 +48,39 @@ void SimpleBlocksAnyHit(inout HitInfo payload, SimpleBlocksAttributes attrib)
     if (color.w == 0.f)
     {
         IgnoreHit();
+        return;
     }
     float distance = RayTCurrent();
     bool found = false;
-    for (int i = 0; i < payload.hitCount; i++)
+    for (int i = 0; i < rayPayload.hitCount; i++)
     {
-        if (payload.distance[i] > distance)
+        if (rayPayload.distance[i] > distance)
         {
             found = true;
-            float4 tmpColor = payload.color[i];
-            payload.color[i] = color;
-            float tmpDistance = payload.distance[i];
-            payload.distance[i] = distance;
-            int tmpDayLight = payload.dayLight[i];
-            payload.dayLight[i] = 0xFFFFFF;
-            int tmpDynamicLight = payload.dynamicLight[i];
-            payload.dynamicLight[i] = 0xFFFFFF;
+            float4 tmpColor = rayPayload.color[i];
+            rayPayload.color[i] = color;
+            float tmpDistance = rayPayload.distance[i];
+            rayPayload.distance[i] = distance;
+            int tmpDayLight = rayPayload.dayLight[i];
+            rayPayload.dayLight[i] = 0xFFFFFF;
+            int tmpDynamicLight = rayPayload.dynamicLight[i];
+            rayPayload.dynamicLight[i] = 0xFFFFFF;
             if (color.w == 1.f)
             {
-                payload.hitCount = i + 1;
+                rayPayload.hitCount = i + 1;
             }
             else
             {
-                for (int j = i + 1; j < payload.hitCount + 1 && j < MAX_TRANSPACENT_HITS; j++)
+                for (int j = i + 1; j < rayPayload.hitCount + 1 && j < MAX_TRANSPACENT_HITS; j++)
                 {
-                    float4 tmpColor2 = payload.color[j];
-                    float tmpDistance2 = payload.distance[j];
-                    int tmpDayLight2 = payload.dayLight[j];
-                    int tmpDynamicLight2 = payload.dynamicLight[j];
-                    payload.color[j] = tmpColor;
-                    payload.distance[j] = tmpDistance;
-                    payload.dayLight[j] = tmpDayLight;
-                    payload.dynamicLight[j] = tmpDynamicLight;
+                    float4 tmpColor2 = rayPayload.color[j];
+                    float tmpDistance2 = rayPayload.distance[j];
+                    int tmpDayLight2 = rayPayload.dayLight[j];
+                    int tmpDynamicLight2 = rayPayload.dynamicLight[j];
+                    rayPayload.color[j] = tmpColor;
+                    rayPayload.distance[j] = tmpDistance;
+                    rayPayload.dayLight[j] = tmpDayLight;
+                    rayPayload.dynamicLight[j] = tmpDynamicLight;
                     tmpColor = tmpColor2;
                     tmpDistance = tmpDistance2;
                     tmpDayLight = tmpDayLight2;
@@ -72,23 +91,24 @@ void SimpleBlocksAnyHit(inout HitInfo payload, SimpleBlocksAttributes attrib)
         }
         else
         {
-            if (payload.color[i].w == 1.f)
+            if (rayPayload.color[i].w == 1.f)
             {
                 found = true;
                 break;
             }
         }
     }
-    if (!found && payload.hitCount < MAX_TRANSPACENT_HITS)
+    if (!found && rayPayload.hitCount < MAX_TRANSPACENT_HITS)
     {
-        payload.color[payload.hitCount] = color;
-        payload.distance[payload.hitCount] = distance;
-        payload.dayLight[payload.hitCount] = 0xFFFFFF;
-        payload.dynamicLight[payload.hitCount] = 0xFFFFFF;
-        payload.hitCount++;
+        rayPayload.color[rayPayload.hitCount] = color;
+        rayPayload.distance[rayPayload.hitCount] = distance;
+        rayPayload.dayLight[rayPayload.hitCount] = 0xFFFFFF;
+        rayPayload.dynamicLight[rayPayload.hitCount] = 0xFFFFFF;
+        rayPayload.hitCount++;
     }
     if (color.w < 1.f)
     {
         IgnoreHit();
+        return;
     }
 }

+ 1 - 7
FactoryCraft/SimpleBlocksClosestHit.hlsl

@@ -1,18 +1,12 @@
 #include "Common.hlsl"
 
-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)
+void SimpleBlocksClosestHit(inout HitInfo rayPayload, SimpleBlocksAttributes attrib)
 {
     // TODO: reflection rays and shadow rays ...
 }

+ 53 - 13
FactoryCraft/World.cpp

@@ -36,7 +36,8 @@ World::World(Screen3D* zScreen, FactoryClient* client)
     firstMessage = 1;
     ownEntityId = -1;
     currentTarget = 0;
-    dayLightFactor = 1;
+    dayLightFactor = Vec3<float>(1.f, 1.f, 1.f);
+    dayLightDirection = Vec3<float>(0.f, 0.f, -1.f);
     time = 0;
     dayLength = 1000;
     transitionLength = 0;
@@ -262,38 +263,72 @@ int World::update(bool background)
 void World::onTick(double time)
 {
     // selectionModel->tick(0.1);
+    Vec3<float> dayColor = Vec3<float>(1.f, 1.f, 1.f);
+    Vec3<float> dawnColor = Vec3<float>(1.f, 0.8f, 0.f);
+    Vec3<float> nightColor = Vec3<float>(0.05f, 0.05f, 0.05f);
+    Vec3<float> beginDayLightDirection = Vec3<float>(-1.f, -0.2f, 0.2f);
     this->time += time;
     if (this->time >= dayLength + nightLength + transitionLength * 2)
     {
         this->time -= dayLength + nightLength + transitionLength * 2;
     }
-    if (this->time > dayLength && this->time < dayLength + transitionLength)
+    double startTime = dayLength + transitionLength + nightLength;
+    float dayDirectionRotation = (float)(this->time - startTime);
+    if (dayDirectionRotation < 0)
     {
+        dayDirectionRotation
+            += (float)(dayLength + nightLength + transitionLength * 2);
+    }
+    dayDirectionRotation = max(0.f,
+        (float)(dayDirectionRotation
+                / (dayLength + transitionLength + 2 * transitionLength
+                    + nightLength)));
+    dayLightDirection
+        = beginDayLightDirection.rotateY(dayDirectionRotation * (float)PI);
+    if (this->time > dayLength && this->time < dayLength + transitionLength)
+    { // transition from day to night;
+        float transformation = (float)min(
+            (this->time - dayLength) / (transitionLength / 2), 1.0);
+        float transformation2
+            = (float)min(max((this->time - dayLength - transitionLength / 2)
+                                 / (transitionLength / 2),
+                             0.0),
+                1.0);
         dayLightFactor
-            = 1.f
-            - (float)((this->time - dayLength) / transitionLength) * 0.95f;
+            = dawnColor * transformation + dayColor * (1.f - transformation);
+        dayLightFactor = dayLightFactor * (1.f - transformation2)
+                       + nightColor * transformation2;
     }
     else if (this->time > dayLength + transitionLength
              && this->time < dayLength + transitionLength + nightLength)
     {
         // night
-        dayLightFactor = 0.05f;
+        dayLightFactor = nightColor;
         if (renderedWorld->getDiffuseLightCount() > 0)
         {
             renderedWorld->removeDiffuseLight(0);
         }
     }
     else if (this->time > dayLength + transitionLength + nightLength)
-    {
+    { // transition from night to day
+        float transformation = (float)min(
+            (this->time - dayLength - transitionLength - nightLength)
+                / (transitionLength / 2),
+            1.0);
+        float transformation2
+            = (float)min(max((this->time - dayLength - transitionLength
+                                 - nightLength - transitionLength / 2)
+                                 / (transitionLength / 2),
+                             0.0),
+                1.0);
         dayLightFactor
-            = (float)((this->time - dayLength - nightLength - transitionLength)
-                      / transitionLength)
-                * 0.95f
-            + 0.05f;
+            = nightColor * (1.f - transformation) + dawnColor * transformation;
+        dayLightFactor = dayLightFactor * (1.f - transformation2)
+                       + dayColor * transformation2;
     }
     else
     {
-        dayLightFactor = 1.f;
+        dayLightFactor = dayColor;
     }
     if (this->time < dayLength + transitionLength
         || this->time > dayLength + transitionLength + nightLength)
@@ -537,7 +572,12 @@ FactoryClient* World::zClient() const
     return client;
 }
 
-float World::getDayLightFactor() const
+Vec3<float> World::getDayLightFactor() const
 {
     return dayLightFactor;
-}
+}
+
+Vec3<float> World::getDayLightDirection() const
+{
+    return dayLightDirection;
+}

+ 5 - 2
FactoryCraft/World.h

@@ -3,6 +3,7 @@
 #include <Critical.h>
 #include <Screen.h>
 #include <Thread.h>
+#include <Vec3.h>
 #include <World3D.h>
 
 class PlayerKam;
@@ -31,7 +32,8 @@ private:
     FactoryCraftModel* selectionModel;
     Framework::ReadWriteLock subLock;
     Framework::Critical targetLock;
-    float dayLightFactor;
+    Framework::Vec3<float> dayLightFactor;
+    Framework::Vec3<float> dayLightDirection;
     double time;
     double dayLength;
     double transitionLength;
@@ -63,5 +65,6 @@ public:
     Framework::Model3D* getCurrentTarget() const;
     FactoryCraftModel* zSelectedEffectModel() const;
     FactoryClient* zClient() const;
-    float getDayLightFactor() const;
+    Framework::Vec3<float> getDayLightFactor() const;
+    Framework::Vec3<float> getDayLightDirection() const;
 };