/******************************************************************************/ /* Project - MudBun Publisher - Long Bunny Labs http://LongBunnyLabs.com Author - Ming-Lun "Allen" Chou http://AllenChou.net */ /******************************************************************************/ #ifndef MUDBUN_SPLAT_COMMON #define MUDBUN_SPLAT_COMMON #ifdef MUDBUN_VALID #include "../GenPointDefs.cginc" #include "../Math/Codec.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 "../NormalDefs.cginc" #include "../RenderModeDefs.cginc" #include "../SDF/Util.cginc" #include "../VoxelDefs.cginc" #ifdef MUDBUN_QUAD_SPLATS static const float2 splatVertOffsetLsTableQuad[6] = { float2(-0.5f, -0.5f), float2( 0.5f, 0.5f), float2( 0.5f, -0.5f), float2(-0.5f, -0.5f), float2(-0.5f, 0.5f), float2( 0.5f, 0.5f), }; #else static const float2 splatVertOffsetLsTableTri[3] = { float2(-0.866f, -0.5f), float2( 0.0f , 1.0f), float2( 0.866f, -0.5f), }; #endif #endif void mudbun_splat_vert ( uint id, out uint iGenPoint, out float4 vertexWs, out float3 vertexLs, out float3 normalWs, out float3 normalLs, out float3 tangentWs, out float3 tangentLs, out float3 centerWs, out float3 centerLs, out float2 tex, out float hash, out float sdfValue, out float3 normal2dLs, out float3 normal2dWs ) { #if MUDBUN_VALID iGenPoint = id; uint iOffset = 0; #ifdef MUDBUN_QUAD_SPLATS iGenPoint = id / 6; iOffset = id % 6; #else iGenPoint = id / 3; iOffset = id % 3; #endif switch (meshingMode) { case kMeshingModeSurfaceNets: case kMeshingModeDualContouring: iGenPoint *= 6; break; } float3 rawCenterLs = aGenPoint[iGenPoint].posNorm.xyz; float3 noiseSeedBase = rawCenterLs * splatJitterNoisiness / voxelSize; float noiseSeedOffset = 10.0f * splatJitterNoisiness; normalLs = unpack_normal(aGenPoint[iGenPoint].posNorm.w); normal2dLs = unpack_normal(aGenPoint[iGenPoint].norm2d); float normalShift = splatNormalShift; if (splatNormalShiftJitter > kEpsilon) { float noiseRes = mbn_cnoise(noiseSeedBase + noiseSeedOffset); normalShift = sign(normalShift) * max(0.0f, abs(normalShift) * (1.0f + (noiseRes - 0.5f) * splatNormalShiftJitter)); } centerLs = rawCenterLs + normalShift * normalLs; float3 originalNormalLs = normalLs; // jitter orientation after normal shift has been applied noiseSeedOffset += noiseSeedOffset; if (splatOrientationJitter > kEpsilon) { float3 axisNoiseRes = snoise_grad(noiseSeedBase).xyz; float angleNoiseRes = mbn_cnoise(noiseSeedBase + noiseSeedOffset); float angle = angleNoiseRes * kPi; float4 q = quat_axis_angle(normalize_safe(axisNoiseRes, normalLs), angle * splatOrientationJitter); normalLs = quat_rot(q, normalLs); } float3 normalJitter = float3(0.01f * (mbn_rand(centerLs) * 0.6f + 0.4f), 0.0f, 0.0f); // mitigate singularities tangentLs = normalize(find_ortho_consistent(normalLs + normalJitter)); noiseSeedOffset += noiseSeedOffset; if (splatPositionJitter > kEpsilon) { float noiseRes = mbn_cnoise(noiseSeedBase + noiseSeedOffset); float angle = noiseRes * kPi; float4 q = quat_axis_angle(normalLs, angle); float3 jitterDirLs = quat_rot(q, tangentLs); centerLs += jitterDirLs * noiseRes * splatPositionJitter * voxelSize; } centerWs = mul(localToWorld, float4(centerLs, 1.0f)).xyz; //float3 camDir = normalize(UNITY_MATRIX_V._m20_m21_m22); float3 camDir = normalize(_WorldSpaceCameraPos - centerWs); normalWs = normalize(mul(localToWorldIt, float4(normalLs, 0.0f)).xyz); normal2dWs = normalize(mul(localToWorldIt, float4(normal2dLs, 0.0f)).xyz); tangentWs = normalize(mul(localToWorldIt, float4(tangentLs, 0.0f)).xyz); #if defined(MUDBUN_SHADOW_PASS) float3 geomNormal = splatShadowsMatchCameraFacing > 0 ? normalize(lerp(normalWs, camDir, splatCameraFacing)) : normalWs; #else float3 geomNormal = normalize(lerp(normalWs, camDir, splatCameraFacing)); #endif float3 geomTangent = normalize(find_ortho_consistent(geomNormal + normalJitter)); float3 geomTangent2 = normalize(cross(geomTangent, geomNormal)); noiseSeedOffset += noiseSeedOffset; if (splatRotationJitter > kEpsilon) { float noiseRes = mbn_cnoise(noiseSeedBase + noiseSeedOffset); float angle = noiseRes * splatRotationJitter * kPi; float4 q = quat_axis_angle(geomNormal, angle); geomTangent = quat_rot(q, geomTangent); geomTangent2 = quat_rot(q, geomTangent2); } if (splatOriginalNormalBlend > kEpsilon) { normalLs = lerp(normalLs, originalNormalLs, splatOriginalNormalBlend); normalWs = normalize(mul(localToWorldIt, float4(normalLs, 0.0f)).xyz); } if (should_quantize_normal()) { normalLs = quantize_normal(normalLs); normalWs = normalize(mul(localToWorldIt, float4(normalLs, 0.0f)).xyz); } if (splatNormalsMatchCameraFacing > 0) { normalWs = camDir; normalLs = normalize(mul(localToWorld, float4(normalWs, 0.0f)).xyz); } #ifdef MUDBUN_QUAD_SPLATS tex = splatVertOffsetLsTableQuad[iOffset]; #else tex = splatVertOffsetLsTableTri[iOffset]; #endif float sizeMult = aGenPoint[iGenPoint].material.size; noiseSeedOffset += noiseSeedOffset; if (splatSizeJitter > kEpsilon) { float noiseRes = mbn_cnoise(noiseSeedBase + noiseSeedOffset); sizeMult = max(0.0f, sizeMult * (1.0f + (noiseRes - 0.5f) * splatSizeJitter)); } float effectiveSplatSize = splatSize * sizeMult; float2 splatVertOffsetLs = effectiveSplatSize * tex; float3 splatVertOffsetWs = splatVertOffsetLs.x * localToWorldScale.xyz * geomTangent + splatVertOffsetLs.y * localToWorldScale.xyz * geomTangent2; vertexWs = float4(centerWs + splatVertOffsetWs, 1.0f); vertexLs = mul(worldToLocal, vertexWs).xyz; #if !defined(MUDBUN_SHADOW_PASS) vertexWs.xyz -= splatScreenSpaceFlattening * project_vec(splatVertOffsetWs, camDir); #endif hash = aGenPoint[iGenPoint].material.hash; sdfValue = aGenPoint[iGenPoint].sdfValue; #endif } void mudbun_splat_vert ( uint id, out float4 vertexWs, out float3 vertexLs, out float3 normalWs, out float3 normalLs, out float3 tangentWs, out float3 tangentLs, out float3 centerWs, out float3 centerLs, out float4 color, out float4 emissionHash, out float2 metallicSmoothness, out float2 tex, out float4 textureWeight, out float sdfValue, out float3 normal2dLs, out float3 normal2dWs ) { #ifdef MUDBUN_VALID uint iGenPoint = 0; mudbun_splat_vert(id, iGenPoint, vertexWs, vertexLs, normalWs, normalLs, tangentWs, tangentLs, centerWs, centerLs, tex, emissionHash.a, sdfValue, normal2dLs, normal2dWs); color = unpack_rgba(aGenPoint[iGenPoint].material.color); emissionHash.rgb = unpack_rgba(aGenPoint[iGenPoint].material.emissionTightness).rgb; if (!IsGammaSpace()) { color.rgb = gamma_to_linear_space(color.rgb); emissionHash.rgb = gamma_to_linear_space(emissionHash.rgb); } metallicSmoothness = unpack_saturated(aGenPoint[iGenPoint].material.metallicSmoothness); textureWeight = unpack_rgba(aGenPoint[iGenPoint].material.textureWeight); if (splatColorJitter > kEpsilon) { float noiseRes = mbn_cnoise(3 * splatJitterNoisiness + aGenPoint[iGenPoint].posNorm.xyz * splatJitterNoisiness / voxelSize); color.rgb = saturate(color.rgb + splatColorJitter * (noiseRes - 0.5f)); } #else vertexWs = float4(0.0f, 0.0f, 0.0f, 1.0f); vertexLs = float3(0.0f, 0.0f, 0.0f); normalWs = float3(0.0f, 0.0f, 0.0f); normalLs = float3(0.0f, 0.0f, 0.0f); normalWs = float3(0.0f, 0.0f, 0.0f); tangentWs = float3(0.0f, 0.0f, 0.0f); tangentLs = float3(0.0f, 0.0f, 0.0f); centerWs = float3(0.0f, 0.0f, 0.0f); centerLs = float3(0.0f, 0.0f, 0.0f); color = float4(0.0f, 0.0f, 0.0f, 1.0f); emissionHash = float4(0.0f, 0.0f, 0.0f, 0.0f); metallicSmoothness = float2(0.0f, 0.0f); tex = float2(0.0f, 0.0f); textureWeight = int4(1.0f, 0.0f, 0.0f, 0.0f); sdfValue = 0.0f; normal2dLs = float3(0.0f, 0.0f, 0.0f); normal2dWs = float3(0.0f, 0.0f, 0.0f); #endif } #endif