Advertisement
cajphrase

Find Instances Optimisations

Aug 18th, 2024
30
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.84 KB | None | 0 0
  1.         /// <summary>
  2.         /// Finds the surface of the voxel data using the gradient descent method.
  3.         /// This method assumes there is only one surface within maxDist and will fail on more complex fields.
  4.         /// Good for when you know you are close to the surface.
  5.         /// </summary>
  6.         public static bool FindSurfaceFast<T>(this T dataSource, float3 startingPos, float maxDist, out float3 result, float errorTolerance = 0.01f) where T : IVoxelDataSource
  7.         {
  8.             const int coarseIters = 10;
  9.             const float e = 0.0001f;
  10.             const float eInv = 1 / e;
  11.  
  12.             result = default;
  13.  
  14.             var startingSample = dataSource.Sample(startingPos);
  15.             var grad = (dataSource.Sample(startingPos + new float3(0, e, 0)) - startingSample) * eInv;
  16.             var approxDistToSurface = startingSample / grad;
  17.             if (abs(approxDistToSurface) > maxDist * 2)
  18.                 return false;
  19.  
  20.             var secondPos = startingPos - new float3(0, approxDistToSurface, 0);
  21.             var secondSample = dataSource.Sample(secondPos);
  22.  
  23.             if (abs(secondSample) < errorTolerance) // found it straight away
  24.             {
  25.                 result = secondPos;
  26.                 return true;
  27.             }
  28.  
  29.             // if we haven't flipped sign, check again at max dist to make sure there is actually a surface here
  30.             if (sign(startingSample) == sign(secondSample))
  31.             {
  32.                 secondPos = startingPos + new float3(0, maxDist * sign(startingSample), 0);
  33.                 secondSample = dataSource.Sample(secondPos);
  34.                 if (sign(startingSample) == sign(secondSample))
  35.                 {
  36.                     return false; // no sign flip = no surface
  37.                 }
  38.             }
  39.  
  40.             float4 pos0 = vec4(startingPos, startingSample);
  41.             float4 pos1 = vec4(secondPos, secondSample);
  42.  
  43.             // we know there is a surface here, iterate to find it
  44.             const int fineIters = 4;
  45.             iters = 0;
  46.             float4 finalPos;
  47.             do
  48.             {
  49.                 var t = unlerp(pos1.w, pos0.w, 0);
  50.                 finalPos = lerp(pos1, pos0, t);
  51.                 finalPos.w = dataSource.Sample(finalPos.xyz);
  52.                 if (sign(finalPos.w) == sign(pos1.w))
  53.                 {
  54.                     pos1 = finalPos;
  55.                 }
  56.                 else
  57.                 {
  58.                     pos0 = finalPos;
  59.                 }
  60.  
  61.                 iters++;
  62.                 if (iters > fineIters)
  63.                 {
  64.                     break;
  65.                 }
  66.             }
  67.             while (abs(finalPos.w) > errorTolerance);
  68.  
  69.             result = finalPos.xyz;
  70.             return true;
  71.         }
  72.    
  73.  
  74.  
  75.  
  76.    
  77.             public void GenerateInstances(JobData jobData)
  78.             {
  79.                 var seed = new uint3(worldSeed, (uint)jobData.biomeId, (uint)jobData.prefab.GetHashCode()).GetHashCode();
  80.                 jobData.distribution.SetSeed(seed);
  81.                 var size = jobData.size;
  82.                 var steps = (int3)math.ceil(bounds.Size / size);
  83.                 var voxelBounds = new VoxelBounds(bounds, steps);
  84.                
  85.                 // return early if there is no surface nearby
  86.                 var sample = terrainData.Sample(bounds.center);
  87.                 var deriv = terrainData.Derivative(bounds.center);
  88.                 var approxDistToSurface = mafs.length(sample / deriv);
  89.                 if (approxDistToSurface > mafs.length(bounds.halfExtents) * 2)
  90.                 {
  91.                     return;
  92.                 }
  93.  
  94.  
  95.                 for (int i = 0; i < voxelBounds.TotalCubeCount; i++)
  96.                 {
  97.                     var index3 = Index.FlatToInt3(i, voxelBounds.cubeCount);
  98.                     var rand = new Random((uint)seed + (uint)index3.GetHashCode());
  99.                     var jitter = rand.NextFloat3() * voxelBounds.cellSize;
  100.                     var pos = voxelBounds.IndexToPosition(index3) + jitter;
  101.  
  102.                     // If the size is larger than the bounds, density should be < 1
  103.                     float oversizeWeight = size > bounds.Size.x ? 1 : bounds.Size.x / size;
  104.  
  105.                     var biomeWeight = terrainData.GetBiomeWeights(pos).GetWeight(jobData.biomeId);
  106.                     if (biomeWeight <= 0)
  107.                         continue;
  108.  
  109.                     var noise = jobData.distribution.GetNoise01(pos);
  110.                     if (rand.NextFloat() > (noise + jobData.uniformity) * biomeWeight * oversizeWeight)
  111.                         continue;
  112.  
  113.                     if (!terrainData.FindSurface(pos, voxelBounds.cellSize.y, out var groundPos))
  114.                         continue;
  115.  
  116.                     if (!bounds.Contains(groundPos))
  117.                         continue;
  118.  
  119.                     var rot = mafs.lookUpRotation(rand.NextOnUnitCircle(), math.up());
  120.                     var scale = rand.NextFloat(jobData.scaleRange);
  121.                     var transform = new EntityTransform(groundPos, rot, scale);
  122.  
  123.                     var colliders = entityColliders.GetEntityColliders(jobData.prefab);
  124.                     for (int j = 0; j < instances.Length; j++)
  125.                     {
  126.                         var other = instances[j];
  127.                         var otherColliders = entityColliders.GetEntityColliders(other.prefab);
  128.                         if (EntityCollisionUtility.Intersects(transform, other.transform, colliders, otherColliders))
  129.                         {
  130.                             continue;
  131.                         }
  132.                     }
  133.  
  134.                     var data = new InstanceData
  135.                     {
  136.                         prefab = jobData.prefab,
  137.                         transform = transform
  138.                     };
  139.                     instances.Add(data);
  140.                 }
  141.             }
  142.        
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement