Skip to content

Commit

Permalink
🔀 Merge develop into master (pull request #9)
Browse files Browse the repository at this point in the history
# Package changes (external)
- Replace linear interpolation with spherical (linear) interpolation in spherical mesh fragmentation as discussed [here](https://blog.matheusamazonas.net/posts/generating_icosphere_with_code#step-2-fragmentation).
- Fix Randomizer sample sometimes creating terrains with holes.
- Add an assembly definition file for each sample.

# Project changes (internal)
In addition to the package (external) changes, this version contains the following internal changes:
- Use LSL's information in the package's "author" section.
- Upgrade to Unity 2022.3.47.
- Optimize Display's setup warmup.
  • Loading branch information
matheusamazonas authored Sep 22, 2024
2 parents 9d0a426 + e72eadd commit f22abad
Show file tree
Hide file tree
Showing 21 changed files with 203 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
namespace LazySquirrelLabs.TerracedTerrainGenerator.MeshFragmentation
{
/// <summary>
/// Fragments a mesh into sub-triangles given an arbitrary depth. The original mesh is modified.
/// Fragments a mesh into sub-triangles given an arbitrary depth, following a strategy defined by the inheritors.
/// The original mesh is modified.
/// </summary>
internal class MeshFragmenter
internal abstract class MeshFragmenter
{
#region Fields

Expand All @@ -26,13 +27,26 @@ internal class MeshFragmenter
/// <see cref="MeshFragmenter"/>'s constructor. To actually fragment a mesh, call <see cref="Fragment"/>.
/// </summary>
/// <param name="depth">The depth (how many consecutive times) the mesh will be fragmented.</param>
internal MeshFragmenter(ushort depth)
protected MeshFragmenter(ushort depth)
{
_depth = depth;
}

#endregion

#region Protected

/// <summary>
/// Finds the middle point between the given vectors. The implementation defines what these vectors
/// represent (e.g. point, direction).
/// </summary>
/// <param name="v1">The first vector to find the middle point for.</param>
/// <param name="v2">The second vector to find the middle point for.</param>
/// <returns>The middle point between <paramref name="v1"/> and <paramref name="v2"/>.</returns>
protected abstract Vector3 FindMiddlePoint(Vector3 v1, Vector3 v2);

#endregion

#region Internal

/// <summary>
Expand Down Expand Up @@ -88,7 +102,7 @@ void FragmentAllTrianglesForDepth(int depth, double triangleCount)
{
for (var i = 0; i < triangleCount; i++)
{
FragmentTriangle(i, readIndices, writeIndices, readVertices, writeVertices);
FragmentTriangle(i, readIndices, writeIndices, readVertices, writeVertices, FindMiddlePoint);
}

currentDepthTotalTriangles = GetTriangleCountForDepth(initialTriangleCount, depth);
Expand Down Expand Up @@ -116,7 +130,8 @@ static NativeList<T> CreateNativeList<T>(int length, Allocator allocator) where
}

static void FragmentTriangle(int triangleIx, NativeList<int> readTriangles, NativeList<int> writeTriangles,
NativeArray<Vector3> readVertices, NativeArray<Vector3> writeVertices)
NativeArray<Vector3> readVertices, NativeArray<Vector3> writeVertices,
Func<Vector3, Vector3, Vector3> findMiddlePoint)
{
// Each original triangle has 3 vertices, so we need to offset that from reading
var readTriangleIx = triangleIx * 3;
Expand All @@ -134,9 +149,9 @@ static void FragmentTriangle(int triangleIx, NativeList<int> readTriangles, Nati
var v1 = readVertices[indexVertex1];
var v2 = readVertices[indexVertex2];
var v3 = readVertices[indexVertex3];
var v4 = (v1 + v2) / 2;
var v5 = (v2 + v3) / 2;
var v6 = (v3 + v1) / 2;
var v4 = findMiddlePoint(v1, v2);
var v5 = findMiddlePoint(v2, v3);
var v6 = findMiddlePoint(v3, v1);

// Add new vertices
var ix1 = AddVertex(v1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using UnityEngine;

namespace LazySquirrelLabs.TerracedTerrainGenerator.MeshFragmentation
{
/// <summary>
/// Fragments a planar mesh into sub-triangles given an arbitrary depth. The original mesh is modified.
/// </summary>
internal class PlanarMeshFragmenter : MeshFragmenter
{
#region Setup

/// <summary>
/// <see cref="PlanarMeshFragmenter"/>'s constructor. To actually fragment a mesh, call
/// <see cref="MeshFragmenter.Fragment"/>.
/// </summary>
/// <param name="depth">The depth (how many consecutive times) the mesh will be fragmented.</param>
internal PlanarMeshFragmenter(ushort depth) : base(depth) { }

#endregion

#region Internal

/// <summary>
/// Finds the middle point between the given positions.
/// </summary>
/// <param name="v1">The first position to find the middle point for.</param>
/// <param name="v2">The second position to find the middle point for.</param>
/// <returns>The middle point between <paramref name="v1"/> and <paramref name="v2"/>.</returns>
protected override Vector3 FindMiddlePoint(Vector3 v1, Vector3 v2)
{
return (v1 + v2) / 2;
}

#endregion
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using UnityEngine;

namespace LazySquirrelLabs.TerracedTerrainGenerator.MeshFragmentation
{
/// <summary>
/// Fragments a spherical mesh into sub-triangles given an arbitrary depth. The original mesh is modified.
/// </summary>
internal class SphericalMeshFragmenter : MeshFragmenter
{
#region Setup

/// <summary>
/// <see cref="SphericalMeshFragmenter"/>'s constructor. To actually fragment a mesh, call
/// <see cref="MeshFragmenter.Fragment"/>.
/// </summary>
/// <param name="depth">The depth (how many consecutive times) the mesh will be fragmented.</param>
internal SphericalMeshFragmenter(ushort depth) : base(depth) { }

#endregion

#region Protected

/// <summary>
/// Finds the middle point between the given directions.
/// </summary>
/// <param name="v1">The first direction to find the middle point for.</param>
/// <param name="v2">The second direction to find the middle point for.</param>
/// <returns>The middle point between <paramref name="v1"/> and <paramref name="v2"/>.</returns>
protected override Vector3 FindMiddlePoint(Vector3 v1, Vector3 v2)
{
return Vector3.Slerp(v1, v2, 0.5f);
}

#endregion
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using LazySquirrelLabs.TerracedTerrainGenerator.Data;
using LazySquirrelLabs.TerracedTerrainGenerator.MeshFragmentation;
using LazySquirrelLabs.TerracedTerrainGenerator.Sculpting;
using LazySquirrelLabs.TerracedTerrainGenerator.Sculpting.Plane;
using LazySquirrelLabs.TerracedTerrainGenerator.ShapeGeneration.Plane.Polygons;
Expand All @@ -10,7 +11,7 @@
namespace LazySquirrelLabs.TerracedTerrainGenerator
{
/// <summary>
/// /// Top-class responsible for the generation of planar terraced terrains.
/// Top class responsible for the generation of planar terraced terrains.
/// </summary>
public class PlanarTerrainGenerator : TerrainGenerator
{
Expand All @@ -32,10 +33,15 @@ public class PlanarTerrainGenerator : TerrainGenerator
/// individual arguments for valid ranges.</exception>
/// <exception cref="NotImplementedException">Thrown whenever the provided number of <paramref name="sides"/>
/// is not supported (greater than 10).</exception>
public PlanarTerrainGenerator(ushort sides, float radius, float maxHeight, float[] relativeTerraceHeights,
public PlanarTerrainGenerator(ushort sides, float radius, float maxHeight, float[] relativeTerraceHeights,
SculptSettings sculptSettings, ushort depth)
: base(0, maxHeight, relativeTerraceHeights, depth)
: base(0, maxHeight, relativeTerraceHeights)
{
if (depth == 0)
{
throw new ArgumentOutOfRangeException(nameof(depth), "Depth must be greater than zero.");
}

if (sides < 3)
{
throw new ArgumentOutOfRangeException(nameof(sides), "Sides must be greater than 2.");
Expand All @@ -54,6 +60,7 @@ public PlanarTerrainGenerator(ushort sides, float radius, float maxHeight, float
_ => throw new NotImplementedException($"Polygon with {sides} not implemented")
};

Fragmenter = new PlanarMeshFragmenter(depth);
Sculptor = new PlaneSculptor(sculptSettings, maxHeight);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using LazySquirrelLabs.TerracedTerrainGenerator.Data;
using LazySquirrelLabs.TerracedTerrainGenerator.MeshFragmentation;
using LazySquirrelLabs.TerracedTerrainGenerator.Sculpting;
using LazySquirrelLabs.TerracedTerrainGenerator.Sculpting.Sphere;
using LazySquirrelLabs.TerracedTerrainGenerator.ShapeGeneration.Sphere;
Expand All @@ -10,7 +11,7 @@
namespace LazySquirrelLabs.TerracedTerrainGenerator
{
/// <summary>
/// Top-class responsible for the generation of spherical terraced terrains.
/// Top class responsible for the generation of spherical terraced terrains.
/// </summary>
public class SphericalTerrainGenerator : TerrainGenerator
{
Expand All @@ -31,10 +32,15 @@ public class SphericalTerrainGenerator : TerrainGenerator
/// <param name="depth">Depth to fragment the basic mesh. Value must be greater than zero.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if any of the arguments is out of range. Checks
/// individual arguments for valid ranges.</exception>
public SphericalTerrainGenerator(float minHeight, float maxHeight, float[] relativeTerraceHeights,
public SphericalTerrainGenerator(float minHeight, float maxHeight, float[] relativeTerraceHeights,
SculptSettings sculptSettings, ushort depth)
: base(minHeight, maxHeight, relativeTerraceHeights, depth)
: base(minHeight, maxHeight, relativeTerraceHeights)
{
if (depth == 0)
{
throw new ArgumentOutOfRangeException(nameof(depth), "Depth must be greater than zero.");
}

if (minHeight <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxHeight), "Minimum height must be greater than zero.");
Expand All @@ -47,6 +53,7 @@ public SphericalTerrainGenerator(float minHeight, float maxHeight, float[] relat
}

ShapeGenerator = new SphereGenerator(minHeight);
Fragmenter = new SphericalMeshFragmenter(depth);
Sculptor = new SphereSculptor(sculptSettings, minHeight, maxHeight);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ public abstract class TerrainGenerator
/// </summary>
private readonly Allocator _allocator;

/// <summary>
/// The mesh fragmenter used to fragment a basic shape, creating a more detailed mesh.
/// </summary>
private readonly MeshFragmenter _fragmenter;

#endregion

#region Protected
Expand All @@ -47,6 +42,11 @@ public abstract class TerrainGenerator
/// </summary>
private protected ShapeGenerator ShapeGenerator { private get; set; }

/// <summary>
/// The mesh fragmenter used to fragment a basic shape, creating a more detailed mesh.
/// </summary>
private protected MeshFragmenter Fragmenter { get; set; }

/// <summary>
/// The sculptor used to create hills/valleys on the mesh.
/// </summary>
Expand All @@ -62,29 +62,22 @@ public abstract class TerrainGenerator
#region Setup

/// <summary>
/// <see cref="PlanarTerrainGenerator"/>'s constructor.
/// <see cref="TerrainGenerator"/>'s constructor.
/// </summary>
/// <param name="minHeight">The minimum height of the terrain, in units.</param>
/// <param name="maxHeight">The maximum height of the terrain, in units.</param>
/// <param name="relativeTerraceHeights">Terrace heights, relative to the terrain's maximum height. Values
/// must be in the [0, 1] range, in ascending order. Each terrace's final height will be calculated by
/// multiplying the relative height by the terrain's height.</param>
/// <param name="depth">Depth to fragment the basic mesh. Value must be greater than zero.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown if any of the arguments is out of range. Checks
/// individual arguments for valid ranges.</exception>
private protected TerrainGenerator(float minHeight, float maxHeight, float[] relativeTerraceHeights,
ushort depth)
private protected TerrainGenerator(float minHeight, float maxHeight, float[] relativeTerraceHeights)
{
if (maxHeight <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxHeight), "Height must be greater than zero.");
}

if (depth == 0)
{
throw new ArgumentOutOfRangeException(nameof(depth), "Depth must be greater than zero.");
}

if (relativeTerraceHeights.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(relativeTerraceHeights), "Relative heights is empty.");
Expand All @@ -108,8 +101,6 @@ private protected TerrainGenerator(float minHeight, float maxHeight, float[] rel
}
}

_fragmenter = new MeshFragmenter(depth);

var heightDelta = maxHeight - minHeight;
TerraceHeights = new float[relativeTerraceHeights.Length];

Expand Down Expand Up @@ -189,7 +180,7 @@ Terracer GenerateTerracedTerrainData()
private SimpleMeshData GenerateTerrainData(Allocator allocator)
{
var meshData = ShapeGenerator.Generate(allocator);
var fragmentedMeshData = _fragmenter.Fragment(meshData, allocator);
var fragmentedMeshData = Fragmenter.Fragment(meshData, allocator);
meshData.Dispose();
Sculptor.Sculpt(fragmentedMeshData);
return fragmentedMeshData;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

namespace LazySquirrelLabs.TerracedTerrainGenerator.Samples.Display
Expand All @@ -25,19 +27,23 @@ private async void Start()
{
try
{
var token = _cancellationTokenSource.Token;
{
foreach (var setup in _setups)
{
await setup.WarmUpAsync(token);
setup.Show();
}
}
var tasks = _setups.Select(WarmupAndShowSetup);
await Task.WhenAll(tasks);
}
catch (OperationCanceledException)
{
Debug.Log("Terrain switching stopped because the operation was cancelled.");
}

return;

async Task WarmupAndShowSetup(TerrainSetup setup)
{
var token = _cancellationTokenSource.Token;
await setup.WarmUpAsync(token);
token.ThrowIfCancellationRequested();
setup.Show();
}
}

private void OnDestroy()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "LazySquirrelLabs.TerracedTerrainGenerator.Samples",
"rootNamespace": "LazySquirrelLabs.TerracedTerrainGenerator.Samples",
"name": "LazySquirrelLabs.TerracedTerrainGenerator.Samples.Display",
"rootNamespace": "LazySquirrelLabs.TerracedTerrainGenerator.Samples.Display",
"references": [
"GUID:3a0a9c0c8ea5546ce85aca8e39ded36b"
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "LazySquirrelLabs.TerracedTerrainGenerator.Samples.ParametersTest",
"rootNamespace": "LazySquirrelLabs.TerracedTerrainGenerator.Samples.ParametersTest",
"references": [
"GUID:3a0a9c0c8ea5546ce85aca8e39ded36b"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f22abad

Please sign in to comment.