#include "Common.hlsl" #define WORLD_HEIGHT 500 #define CHUNK_SIZE 16 #define EPSILON 1e-6f cbuffer ChunkShaderInfo : register(b0, space2) { int2 pos; unsigned int blockCount; }; StructuredBuffer textureIdBuffer : register(t1, space2); StructuredBuffer indexBuffer : register(t1, space3); ByteAddressBuffer lightBuffer : register(t1, space4); #define minPos(x, y) min(x>0?x:y,y>0?y:x) #define minPosV(v1, v2) float3(minPos(v1.x, v2.x), minPos(v1.y, v2.y), minPos(v1.z, v2.z)) #define between(v1, vmin, vmax) (v1.x >= vmin.x && v1.x <= vmax.x && v1.y >= vmin.y && v1.y <= vmax.y && v1.z >= vmin.z && v1.z <= vmax.z) float3 getLight(int index) { uint raw = lightBuffer.Load(index / 4); uint shift = (index % 4) * 8; float r = ((raw >> shift) & 0xFF) / 255.0; shift += 8; if (shift == 32) { raw = lightBuffer.Load(index / 4 + 4); shift = 0; } float g = ((raw >> shift) & 0xFF) / 255.0; shift += 8; if (shift == 32) { raw = lightBuffer.Load(index / 4 + 4); shift = 0; } float b = ((raw >> shift) & 0xFF) / 255.0; return float3(r, g, b); } float3 interpolateLight(float3 topLeft, float3 topRight, float3 bottomLeft, float3 bottomRight, float2 coords) { return (topLeft * (1 - coords.x) + topRight * coords.x) * (1 - coords.y) + (bottomLeft * (1 - coords.x) + bottomRight * coords.x) * coords.y; } [shader("intersection")] void ChunkIntersection() { float THit = RayTCurrent(); Attributes intersectionAttributes; intersectionAttributes.texCoord = float2(0.5, 0.5); intersectionAttributes.textureId = 2; float3 origin = WorldRayOrigin(); float3 direction = WorldRayDirection(); float minDistance = RayTMin(); float3 invDirection = 1.0 / direction; float3 chunkMin = float3(pos.x - CHUNK_SIZE / 2, pos.y - CHUNK_SIZE / 2, 0); float3 chunkMax = float3(pos.x + CHUNK_SIZE / 2, pos.y + CHUNK_SIZE / 2, WORLD_HEIGHT); float distance = 0; float3 step = sign(direction); int hitSide = -1; float3 currentPos = origin; if (!between(origin, chunkMin, chunkMax)) { float3 t1 = (chunkMin - origin) * invDirection; float3 t2 = (chunkMax - origin) * invDirection; float3 tmin = min(t1, t2); if (tmin.x > tmin.y && tmin.x > tmin.z) { hitSide = step.x > 0 ? 3 : 2; distance = tmin.x; } else if (tmin.y > tmin.z) { hitSide = step.y > 0 ? 0 : 1; distance = tmin.y; } else { hitSide = step.z > 0 ? 5 : 4; distance = tmin.z; } currentPos = origin + direction * distance; } float3 chunkPos = currentPos - chunkMin; float3 sum = step + currentPos; float3 nextBorder = float3(step.x > 0 ? floor(sum.x) : ceil(sum.x), step.y > 0 ? floor(sum.y) : ceil(sum.y), step.z > 0 ? floor(sum.z) : ceil(sum.z)); int3 block = floor(chunkPos); int3 blockMin = int3(0, 0, 0); int3 blockMax = int3(CHUNK_SIZE - 1, CHUNK_SIZE - 1, WORLD_HEIGHT - 1); switch (hitSide) { case 0: // front | NORTH block.y = blockMin.y; nextBorder.y = blockMin.y + 1 + chunkMin.y; break; case 1: // back | SOUTH block.y = blockMax.y; nextBorder.y = blockMax.y + chunkMin.y; break; case 2: // left | EAST block.x = blockMax.x; nextBorder.x = blockMax.x + chunkMin.x; break; case 3: // right | WEST block.x = blockMin.x; nextBorder.x = blockMin.x + 1 + chunkMin.x; break; case 4: // top block.z = blockMax.z; nextBorder.z = blockMax.z + chunkMin.z; break; case 5: // bottom block.z = blockMin.z; nextBorder.z = blockMin.z + 1 + chunkMin.z; break; } while (between(block, blockMin, blockMax) && distance < THit) { int index = (block.x * CHUNK_SIZE + block.y) * WORLD_HEIGHT + block.z; if (indexBuffer[index] >= 0 && distance > minDistance && hitSide >= 0) { int lightOffset = indexBuffer[index] * 8; float3 topLeftDayLight; float3 topRightDayLight; float3 bottomLeftDayLight; float3 bottomRightDayLight; float3 topLeftDynamicLight; float3 topRightDynamicLight; float3 bottomLeftDynamicLight; float3 bottomRightDynamicLight; /** Light indices are stored in the following order: lightOffset = TOP | NORTH | EAST lightOffset + 6 = TOP | SOUTH | EAST lightOffset + 12 = TOP | SOUTH | WEST lightOffset + 18 = TOP | NORTH | WEST lightOffset + 24 = BOTTOM | NORTH | EAST lightOffset + 30 = BOTTOM | SOUTH | EAST lightOffset + 36 = BOTTOM | SOUTH | WEST lightOffset + 42 = BOTTOM | NORTH | WEST **/ switch (hitSide) { case 0: // front | NORTH intersectionAttributes.texCoord = float2(1 - (currentPos.x - floor(currentPos.x)), 1 - (currentPos.z - floor(currentPos.z))); topLeftDayLight = getLight(lightOffset + 0); topLeftDynamicLight = getLight(lightOffset + 3); topRightDayLight = getLight(lightOffset + 18); topRightDynamicLight = getLight(lightOffset + 21); bottomLeftDayLight = getLight(lightOffset + 24); bottomLeftDynamicLight = getLight(lightOffset + 27); bottomRightDayLight = getLight(lightOffset + 42); bottomRightDynamicLight = getLight(lightOffset + 45); break; case 1: // back | SOUTH intersectionAttributes.texCoord = float2(currentPos.x - floor(currentPos.x), 1 - (currentPos.z - floor(currentPos.z))); topLeftDayLight = getLight(lightOffset + 12); topLeftDynamicLight = getLight(lightOffset + 15); topRightDayLight = getLight(lightOffset + 6); topRightDynamicLight = getLight(lightOffset + 9); bottomLeftDayLight = getLight(lightOffset + 36); bottomLeftDynamicLight = getLight(lightOffset + 39); bottomRightDayLight = getLight(lightOffset + 30); bottomRightDynamicLight = getLight(lightOffset + 33); break; case 2: // left | EAST intersectionAttributes.texCoord = float2(1 - (currentPos.y - floor(currentPos.y)), 1 - (currentPos.z - floor(currentPos.z))); topLeftDayLight = getLight(lightOffset + 6); topLeftDynamicLight = getLight(lightOffset + 9); topRightDayLight = getLight(lightOffset + 0); topRightDynamicLight = getLight(lightOffset + 3); bottomLeftDayLight = getLight(lightOffset + 30); bottomLeftDynamicLight = getLight(lightOffset + 33); bottomRightDayLight = getLight(lightOffset + 24); bottomRightDynamicLight = getLight(lightOffset + 27); break; case 3: // right | WEST intersectionAttributes.texCoord = float2(currentPos.y - floor(currentPos.y), 1 - (currentPos.z - floor(currentPos.z))); topLeftDayLight = getLight(lightOffset + 18); topLeftDynamicLight = getLight(lightOffset + 21); topRightDayLight = getLight(lightOffset + 12); topRightDynamicLight = getLight(lightOffset + 15); bottomLeftDayLight = getLight(lightOffset + 42); bottomLeftDynamicLight = getLight(lightOffset + 45); bottomRightDayLight = getLight(lightOffset + 36); bottomRightDynamicLight = getLight(lightOffset + 39); break; case 4: // top intersectionAttributes.texCoord = float2(1 - (currentPos.x - floor(currentPos.x)), 1 - (currentPos.y - floor(currentPos.y))); topLeftDayLight = getLight(lightOffset + 6); topLeftDynamicLight = getLight(lightOffset + 9); topRightDayLight = getLight(lightOffset + 12); topRightDynamicLight = getLight(lightOffset + 15); bottomLeftDayLight = getLight(lightOffset + 0); bottomLeftDynamicLight = getLight(lightOffset + 3); bottomRightDayLight = getLight(lightOffset + 18); bottomRightDynamicLight = getLight(lightOffset + 21); break; case 5: // bottom intersectionAttributes.texCoord = float2(1 - (currentPos.x - floor(currentPos.x)), currentPos.y - floor(currentPos.y)); topLeftDayLight = getLight(lightOffset + 24); topLeftDynamicLight = getLight(lightOffset + 27); topRightDayLight = getLight(lightOffset + 42); topRightDynamicLight = getLight(lightOffset + 45); bottomLeftDayLight = getLight(lightOffset + 30); bottomLeftDynamicLight = getLight(lightOffset + 33); bottomRightDayLight = getLight(lightOffset + 36); bottomRightDynamicLight = getLight(lightOffset + 39); break; } intersectionAttributes.dayLight = packLight(interpolateLight(topLeftDayLight, topRightDayLight, bottomLeftDayLight, bottomRightDayLight, intersectionAttributes.texCoord)); intersectionAttributes.dynamicLight = packLight(interpolateLight(topLeftDynamicLight, topRightDynamicLight, bottomLeftDynamicLight, bottomRightDynamicLight, intersectionAttributes.texCoord)); intersectionAttributes.textureId = textureIdBuffer[indexBuffer[index] + hitSide]; ReportHit(distance, hitSide, intersectionAttributes); if (RayTCurrent() < THit) { return; // since we go in direction of the ray we will not find a nearer hit in this intersection shader } } float3 stepDist = (nextBorder - origin) * invDirection; if (stepDist.x < stepDist.y && stepDist.x < stepDist.z) { hitSide = step.x > 0 ? 3 : 2; block.x += step.x; nextBorder.x += step.x; distance = stepDist.x; } else if (stepDist.y < stepDist.z) { hitSide = step.y > 0 ? 0 : 1; block.y += step.y; nextBorder.y += step.y; distance = stepDist.y; } else { hitSide = step.z > 0 ? 5 : 4; block.z += step.z; nextBorder.z += step.z; distance = stepDist.z; } currentPos = origin + direction * distance; } }