Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// <summary>
- /// Finds the surface of the voxel data using the gradient descent method.
- /// This method assumes there is only one surface within maxDist and will fail on more complex fields.
- /// Good for when you know you are close to the surface.
- /// </summary>
- public static bool FindSurfaceFast<T>(this T dataSource, float3 startingPos, float maxDist, out float3 result, float errorTolerance = 0.01f) where T : IVoxelDataSource
- {
- const int coarseIters = 10;
- const float e = 0.0001f;
- const float eInv = 1 / e;
- result = default;
- var startingSample = dataSource.Sample(startingPos);
- var grad = (dataSource.Sample(startingPos + new float3(0, e, 0)) - startingSample) * eInv;
- var approxDistToSurface = startingSample / grad;
- if (abs(approxDistToSurface) > maxDist * 2)
- return false;
- var secondPos = startingPos - new float3(0, approxDistToSurface, 0);
- var secondSample = dataSource.Sample(secondPos);
- if (abs(secondSample) < errorTolerance) // found it straight away
- {
- result = secondPos;
- return true;
- }
- // if we haven't flipped sign, check again at max dist to make sure there is actually a surface here
- if (sign(startingSample) == sign(secondSample))
- {
- secondPos = startingPos + new float3(0, maxDist * sign(startingSample), 0);
- secondSample = dataSource.Sample(secondPos);
- if (sign(startingSample) == sign(secondSample))
- {
- return false; // no sign flip = no surface
- }
- }
- float4 pos0 = vec4(startingPos, startingSample);
- float4 pos1 = vec4(secondPos, secondSample);
- // we know there is a surface here, iterate to find it
- const int fineIters = 4;
- iters = 0;
- float4 finalPos;
- do
- {
- var t = unlerp(pos1.w, pos0.w, 0);
- finalPos = lerp(pos1, pos0, t);
- finalPos.w = dataSource.Sample(finalPos.xyz);
- if (sign(finalPos.w) == sign(pos1.w))
- {
- pos1 = finalPos;
- }
- else
- {
- pos0 = finalPos;
- }
- iters++;
- if (iters > fineIters)
- {
- break;
- }
- }
- while (abs(finalPos.w) > errorTolerance);
- result = finalPos.xyz;
- return true;
- }
- public void GenerateInstances(JobData jobData)
- {
- var seed = new uint3(worldSeed, (uint)jobData.biomeId, (uint)jobData.prefab.GetHashCode()).GetHashCode();
- jobData.distribution.SetSeed(seed);
- var size = jobData.size;
- var steps = (int3)math.ceil(bounds.Size / size);
- var voxelBounds = new VoxelBounds(bounds, steps);
- // return early if there is no surface nearby
- var sample = terrainData.Sample(bounds.center);
- var deriv = terrainData.Derivative(bounds.center);
- var approxDistToSurface = mafs.length(sample / deriv);
- if (approxDistToSurface > mafs.length(bounds.halfExtents) * 2)
- {
- return;
- }
- for (int i = 0; i < voxelBounds.TotalCubeCount; i++)
- {
- var index3 = Index.FlatToInt3(i, voxelBounds.cubeCount);
- var rand = new Random((uint)seed + (uint)index3.GetHashCode());
- var jitter = rand.NextFloat3() * voxelBounds.cellSize;
- var pos = voxelBounds.IndexToPosition(index3) + jitter;
- // If the size is larger than the bounds, density should be < 1
- float oversizeWeight = size > bounds.Size.x ? 1 : bounds.Size.x / size;
- var biomeWeight = terrainData.GetBiomeWeights(pos).GetWeight(jobData.biomeId);
- if (biomeWeight <= 0)
- continue;
- var noise = jobData.distribution.GetNoise01(pos);
- if (rand.NextFloat() > (noise + jobData.uniformity) * biomeWeight * oversizeWeight)
- continue;
- if (!terrainData.FindSurface(pos, voxelBounds.cellSize.y, out var groundPos))
- continue;
- if (!bounds.Contains(groundPos))
- continue;
- var rot = mafs.lookUpRotation(rand.NextOnUnitCircle(), math.up());
- var scale = rand.NextFloat(jobData.scaleRange);
- var transform = new EntityTransform(groundPos, rot, scale);
- var colliders = entityColliders.GetEntityColliders(jobData.prefab);
- for (int j = 0; j < instances.Length; j++)
- {
- var other = instances[j];
- var otherColliders = entityColliders.GetEntityColliders(other.prefab);
- if (EntityCollisionUtility.Intersects(transform, other.transform, colliders, otherColliders))
- {
- continue;
- }
- }
- var data = new InstanceData
- {
- prefab = jobData.prefab,
- transform = transform
- };
- instances.Add(data);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement