/******************************************************************************/ /* Project - MudBun Publisher - Long Bunny Labs http://LongBunnyLabs.com Author - Ming-Lun "Allen" Chou http://AllenChou.net */ /******************************************************************************/ #ifndef MUDBUN_RAY_TRACED_VOXELS_COMMON #define MUDBUN_RAY_TRACED_VOXELS_COMMON #ifdef MUDBUN_VALID #include "../../Customization/CustomRayTracedVoxels.cginc" #include "../AabbTreeFuncs.cginc" #include "../BrushFuncs.cginc" #include "../GenPointDefs.cginc" #include "../Math/Codec.cginc" #include "../Math/Geometry.cginc" #include "../Math/Vector.cginc" #include "../Math/Quaternion.cginc" #include "../MeshingModeDefs.cginc" #include "../Noise/ClassicNoise3D.cginc" #include "../Noise/SimplexNoise3D.cginc" #include "../Noise/RandomNoise.cginc" #include "../NormalFuncs.cginc" #include "../RenderModeDefs.cginc" #include "../SDF/Util.cginc" #include "../VoxelDefs.cginc" #include "../VoxelHashDefs.cginc" #include "../VoxelModeDefs.cginc" #endif float rayTracedVoxelSizeMultiplier; float rayTracedVoxelSmoothCubeNormal; float rayTracedVoxelRadius; int3 ray_step(float3 ro, float3 s, float3 m, float3 k, float3 nodeCenter) { ro -= nodeCenter; float3 n = m * ro; float3 tMax = -n + k; float3 tMaxNeg = -tMax; return s * step(tMaxNeg.yzx, tMaxNeg.xyz) * step(tMaxNeg.zxy, tMaxNeg.xyz); } static const float3 aUnitBoxVertLs[8] = { float3(-0.5f, -0.5f, -0.5f), float3( 0.5f, -0.5f, -0.5f), float3( 0.5f, -0.5f, 0.5f), float3(-0.5f, -0.5f, 0.5f), float3(-0.5f, 0.5f, -0.5f), float3( 0.5f, 0.5f, -0.5f), float3( 0.5f, 0.5f, 0.5f), float3(-0.5f, 0.5f, 0.5f), }; static const int aiUnitBoxTriVert[36] = { 0, 1, 2, 0, 2, 3, 3, 2, 6, 3, 6, 7, 7, 6, 5, 7, 5, 4, 4, 5, 1, 4, 1, 0, 1, 5, 6, 1, 6, 2, 0, 3, 7, 0, 7, 4, }; static const int aiInvertedUnitBoxTriVert[36] = { 0, 2, 1, 0, 3, 2, 3, 6, 2, 3, 7, 6, 7, 5, 6, 7, 4, 5, 4, 1, 5, 4, 0, 1, 1, 6, 5, 1, 2, 6, 0, 7, 3, 0, 4, 7, }; void mudbun_ray_traced_voxels_vert ( uint id, out float3 vertPosLs, out float3 vertPosWs ) { #ifdef MUDBUN_VALID uint iChunk = id % 36; Aabb rootBounds = aabbTree[aabbRoot].aabb; #if !defined(SHADERPASS_SHADOWCASTER) vertPosLs = aUnitBoxVertLs[aiInvertedUnitBoxTriVert[iChunk]]; #else vertPosLs = aUnitBoxVertLs[aiUnitBoxTriVert[iChunk]]; #endif vertPosLs *= voxelNodeSizes[0]; vertPosLs += nodePool[id / 36].center; vertPosLs = clamp(vertPosLs, rootBounds.boundsMin, rootBounds.boundsMax); vertPosWs = mul(localToWorld, float4(vertPosLs, 1.0f)).xyz; #else vertPosLs = 0.0f; vertPosWs = 0.0f; #endif } float3 msign(float3 v) { return v >= 0.0f ? float3(1.0f, 1.0f, 1.0f) : float3(-1.0f, -1.0f, -1.0f); } void mudbun_ray_traced_voxels_frag ( uint id, float3 vertPosLs, float3 rayOriginLs, float3 rayDirLs, float3 viewDirLs, out float3 posLs, out float3 normLs, out float depth, out float4 color, out float3 emission, out float metallic, out float smoothness, out float4 textureWeight ) { #ifdef MUDBUN_VALID posLs = 0.0f; normLs = 0.0f; depth = 0.0f; color = 0.0f; emission = 0.0f; metallic = 0.0f; smoothness = 0.0f; textureWeight = 0.0f; uint iChunk = id / 36; float4 aNodeExtent = 0.5f * voxelNodeSizes; float4 aVoxelNodeSizeInv = rcp(voxelNodeSizes) * 0.9999999f; // make sure cell node coords are not out-of-bounds uint4 aBranchingFactor = get_voxel_tree_branching_factors(); uint4 aHalfBranchingFactor = aBranchingFactor / 2; uint4 aMaxSteps = 3 * aBranchingFactor; float voxelExtent = aNodeExtent[3]; float voxelHalfDiag = 1.733f * voxelExtent; float3 ro = rayOriginLs; float3 rd = rayDirLs; #if defined(SHADERPASS_SHADOWCASTER) #if defined(MUDBUN_URP) rd = normalize(mul((float3x3) worldToLocalIt, _MainLightPosition.xyz)); ro = vertPosLs + 0.01f * voxelNodeSizes[3] * rd; rayOriginLs = ro - 1.733f * voxelNodeSizes[0] * rd; #endif // TODO: HDRP #endif float3 rayS = msign(rd); float3 rayM = (abs(rd) > 1e-6f) ? rcp(rd) : kFltMax; float3 absRayM = abs(rayM); float3 rayK0 = absRayM * aNodeExtent[0]; float3 rayK1 = absRayM * aNodeExtent[1]; float3 rayK2 = absRayM * aNodeExtent[2]; float3 rayK3 = absRayM * aNodeExtent[3]; float3 rayNudge0 = 0.01f * voxelNodeSizes[3] * rd; float3 rayNudge1 = 0.01f * voxelNodeSizes[3] * rd; float3 rayNudge2 = 0.01f * voxelNodeSizes[3] * rd; float3 rayNudge3 = 0.01f * voxelNodeSizes[3] * rd; float3 center0 = nodePool[iChunk].center; float3 chunkOrigin = center0 - aNodeExtent[0]; // quantize ro at node 0 boundaries ro += ray_box_intersect_fast_raw(ro, rayM, rayK0, center0).x * rd; // depth 1 uint key0 = nodePool[iChunk].key; float3 rw1 = ro; // ray walker int3 coord1 = (rw1 - chunkOrigin + rayNudge1) * aVoxelNodeSizeInv[1] % aBranchingFactor[0]; float3 center1 = (coord1 + 0.5f - aHalfBranchingFactor[0]) * voxelNodeSizes[1] + center0; [loop] for(int iter1 = 0, maxIter1 = aMaxSteps[0]; iter1 < maxIter1; ++iter1) { uint key1 = concat_node_key(key0, coord1); int iNode1 = look_up_node(key1); // hit node at depth 1? if (iNode1 >= 0) { // depth 2 float3 rw2 = rw1; int3 coord2 = ((rw2 - chunkOrigin + rayNudge2) * aVoxelNodeSizeInv[2]) % aBranchingFactor[1]; float3 center2 = (coord2 + 0.5f - aHalfBranchingFactor[1]) * voxelNodeSizes[2] + center1; [loop] for (int iter2 = 0, maxIter2 = aMaxSteps[1]; iter2 < maxIter2; ++iter2) { uint key2 = concat_node_key(key1, coord2); int iNode2 = look_up_node(key2); // hit node at depth 2? if (iNode2 >= 0) { // depth 3 float3 rw3 = rw2; int3 coord3 = ((rw3 - chunkOrigin + rayNudge3) * aVoxelNodeSizeInv[3]) % aBranchingFactor[2]; float3 center3 = (coord3 + 0.5f - aHalfBranchingFactor[2]) * voxelNodeSizes[3] + center2; [loop] for (int iter3 = 0, maxIter3 = aMaxSteps[2]; iter3 < maxIter3; ++iter3) { uint key3 = concat_node_key(key2, coord3); int iNode3 = look_up_node(key3); // hit node at depth 3? // voxel hit test if (iNode3 >= 0) { // in front of ray origin? float3 voxelCenter = nodePool[iNode3].center; if (dot(voxelCenter - rayOriginLs, rd) > 0.0f) { bool hitVoxel = false; float sizeMult = saturate(rayTracedVoxelSizeMultiplier * aGenPoint[iNode3].material.size); switch (rayTracedVoxelPaddingMode) { case kVoxelPaddingModeByDistance: case kVoxelPaddingModeFull: if (rayTracedVoxelSizeFadeDistance > kEpsilon) { sizeMult *= saturate(-aGenPoint[iNode3].sdfValue / rayTracedVoxelSizeFadeDistance); } break; } switch (rayTracedVoxelMode) { case kVoxelModeFlatCubes: case kVoxelModeFacetedCubes: { float t = ray_box_intersect_fast(ro, rayM, rayK3 * sizeMult, voxelCenter).x; if (t >= -1e-3f) { posLs = ro + t * rd; normLs = (rayTracedVoxelMode == kVoxelModeFlatCubes) ? unpack_normal(aGenPoint[iNode3].posNorm.w) : box_gradient(posLs, voxelCenter, voxelExtent * sizeMult * (1.0f - rayTracedVoxelSmoothCubeNormal)); hitVoxel = true; } } break; case kVoxelModeSmoothSpheres: case kVoxelModeFlatSpheres: { float2 tSphere = ray_sphere_intersect(ro - voxelCenter, rd, voxelExtent * rayTracedVoxelRadius * sizeMult); float2 tBox = ray_box_intersect_fast(ro, rayM, rayK3 * sizeMult, voxelCenter); if (tBox.x >= -1e-3f && tSphere.x <= tBox.y && tBox.x <= tSphere.y) { float t = max(tSphere.x, tBox.x); posLs = ro + t * rd; normLs = (rayTracedVoxelMode == kVoxelModeFlatSpheres) ? unpack_normal(aGenPoint[iNode3].posNorm.w) : (tSphere.x >= tBox.x) ? sphere_gradient(posLs - voxelCenter) : box_gradient(posLs, voxelCenter, voxelExtent * sizeMult); hitVoxel = true; } } break; case kVoxelModeCustom: hitVoxel = ray_traced_voxels_hit_func(ro, rd, voxelCenter, voxelExtent, posLs, normLs); break; } if (hitVoxel) { #if !defined(SHADERPASS_SHADOWCASTER) #if defined(MUDBUN_URP) { color = unpack_rgba(aGenPoint[iNode3].material.color); emission = unpack_rgba(aGenPoint[iNode3].material.emissionTightness).rgb; float2 metallicSmoothness = unpack_saturated(aGenPoint[iNode3].material.metallicSmoothness); metallic = metallicSmoothness.x; smoothness = metallicSmoothness.y; textureWeight = unpack_rgba(aGenPoint[iNode3].material.textureWeight); float4 posWs = mul(localToWorld, float4(posLs, 1.0f)); float4 posCs = mul(UNITY_MATRIX_VP, posWs); depth = clamp(posCs.z / posCs.w, 1e-6f, 1.0f); } #endif // TODO: HDRP #else // shadow pass #if defined (MUDBUN_URP) { color = unpack_rgba(aGenPoint[iNode3].material.color); float4 posWs = mul(localToWorld, float4(posLs, 1.0f)); float3 normWs = mul((float3x3) localToWorldIt, normLs); float invNdotL = 1.0f - saturate(dot(_MainLightPosition.xyz, normWs)); posWs.xyz += _MainLightPosition.xyz * _ShadowBias.x; posWs.xyz += invNdotL * _ShadowBias.y * normWs; float4 posCs = mul(UNITY_MATRIX_VP, posWs); depth = clamp(posCs.z / posCs.w, 1e-6f, 1.0f); } #endif // TODO: HDRP #endif return; } } // end: in front of ray origin? } // end: voxel hit test int3 coordStep3 = ray_step(ro, rayS, rayM, rayK3, center3); coord3 += coordStep3; if (any(coord3 < 0 || coord3 >= int(aBranchingFactor[2]))) break; float tNextRw3 = ray_box_intersect_fast(ro, rayM, rayK3, center3).y; rw3 = ro + tNextRw3 * rd; center3 += coordStep3 * voxelNodeSizes[3]; } // end: depth 3 } int3 coordStep2 = ray_step(ro, rayS, rayM, rayK2, center2); coord2 += coordStep2; if (any(coord2 < 0 || coord2 >= int(aBranchingFactor[1]))) break; float tNextRw2 = ray_box_intersect_fast(ro, rayM, rayK2, center2).y; rw2 = ro + tNextRw2 * rd; center2 += coordStep2 * voxelNodeSizes[2]; } // end: depth 2 } int3 coordStep1 = ray_step(ro, rayS, rayM, rayK1, center1); coord1 += coordStep1; if (any(coord1 < 0 || coord1 >= int(aBranchingFactor[0]))) break; float tNextRw1 = ray_box_intersect_fast(ro, rayM, rayK1, center1).y; rw1 = ro + tNextRw1 * rd; center1 += coordStep1 * voxelNodeSizes[1]; } // end: depth 1 #else posLs = 0.0f; normLs = 0.0f; depth = 0.0f; color = 0.0f; emission = 0.0f; metallic = 0.0f; smoothness = 0.0f; textureWeight = 0.0f; #endif } #endif