-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
324 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
using Elements.Assets; | ||
using Elements.Core; | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace Obsidian | ||
{ | ||
public class Planet : MeshXShape | ||
{ | ||
public int Subdivisions; | ||
public float Radius; | ||
public float NoiseScale; | ||
public float NoiseStrength; | ||
|
||
public Planet(MeshX mesh, int subdivisions, float radius, float noiseScale, float noiseStrength) : base(mesh) | ||
{ | ||
Subdivisions = subdivisions; | ||
Radius = radius; | ||
NoiseScale = noiseScale; | ||
NoiseStrength = noiseStrength; | ||
mesh.Clear(); | ||
GeneratePlanet(mesh, Subdivisions, Radius, NoiseScale, NoiseStrength); | ||
} | ||
|
||
private void GeneratePlanet(MeshX mesh, int subdivisions, float radius, float noiseScale, float noiseStrength) | ||
{ | ||
List<float3> vertices = new List<float3>(); | ||
List<int> triangles = new List<int>(); | ||
|
||
// Generate initial icosahedron | ||
CreateIcosahedron(vertices, triangles); | ||
|
||
// Subdivide icosahedron | ||
for (int i = 0; i < subdivisions; i++) | ||
{ | ||
Subdivide(vertices, triangles); | ||
} | ||
|
||
// Apply noise to vertices | ||
ApplyPerlinNoise(vertices, radius, noiseScale, noiseStrength); | ||
|
||
// Assign vertices and triangles to the mesh | ||
mesh.SetVertexCount(vertices.Count); | ||
for (int i = 0; i < vertices.Count; i++) | ||
{ | ||
mesh.SetVertex(i, vertices[i]); | ||
} | ||
|
||
for (int i = 0; i < triangles.Count; i += 3) | ||
{ | ||
mesh.AddTriangle(triangles[i], triangles[i + 1], triangles[i + 2]); | ||
} | ||
|
||
mesh.RecalculateNormals(AllTriangles); | ||
} | ||
|
||
private void CreateIcosahedron(List<float3> vertices, List<int> triangles) | ||
{ | ||
float t = (1.0f + MathX.Sqrt(5.0f)) / 2.0f; | ||
|
||
vertices.Add(new float3(-1, t, 0)); | ||
vertices.Add(new float3(1, t, 0)); | ||
vertices.Add(new float3(-1, -t, 0)); | ||
vertices.Add(new float3(1, -t, 0)); | ||
|
||
vertices.Add(new float3(0, -1, t)); | ||
vertices.Add(new float3(0, 1, t)); | ||
vertices.Add(new float3(0, -1, -t)); | ||
vertices.Add(new float3(0, 1, -t)); | ||
|
||
vertices.Add(new float3(t, 0, -1)); | ||
vertices.Add(new float3(t, 0, 1)); | ||
vertices.Add(new float3(-t, 0, -1)); | ||
vertices.Add(new float3(-t, 0, 1)); | ||
|
||
triangles.AddRange(new int[] { | ||
0, 11, 5, | ||
0, 5, 1, | ||
0, 1, 7, | ||
0, 7, 10, | ||
0, 10, 11, | ||
|
||
1, 5, 9, | ||
5, 11, 4, | ||
11, 10, 2, | ||
10, 7, 6, | ||
7, 1, 8, | ||
|
||
3, 9, 4, | ||
3, 4, 2, | ||
3, 2, 6, | ||
3, 6, 8, | ||
3, 8, 9, | ||
|
||
4, 9, 5, | ||
2, 4, 11, | ||
6, 2, 10, | ||
8, 6, 7, | ||
9, 8, 1 | ||
}); | ||
} | ||
|
||
private void Subdivide(List<float3> vertices, List<int> triangles) | ||
{ | ||
Dictionary<long, int> midpointCache = new Dictionary<long, int>(); | ||
List<int> newTriangles = new List<int>(); | ||
|
||
for (int i = 0; i < triangles.Count; i += 3) | ||
{ | ||
int v1 = triangles[i]; | ||
int v2 = triangles[i + 1]; | ||
int v3 = triangles[i + 2]; | ||
|
||
int a = GetMidpoint(midpointCache, vertices, v1, v2); | ||
int b = GetMidpoint(midpointCache, vertices, v2, v3); | ||
int c = GetMidpoint(midpointCache, vertices, v3, v1); | ||
|
||
newTriangles.AddRange(new int[] { v1, a, c }); | ||
newTriangles.AddRange(new int[] { v2, b, a }); | ||
newTriangles.AddRange(new int[] { v3, c, b }); | ||
newTriangles.AddRange(new int[] { a, b, c }); | ||
} | ||
|
||
triangles.Clear(); | ||
triangles.AddRange(newTriangles); | ||
} | ||
|
||
private int GetMidpoint(Dictionary<long, int> midpointCache, List<float3> vertices, int v1, int v2) | ||
{ | ||
long key = ((long)Math.Min(v1, v2) << 32) + Math.Max(v1, v2); | ||
|
||
if (midpointCache.TryGetValue(key, out int midpoint)) | ||
{ | ||
return midpoint; | ||
} | ||
|
||
float3 p1 = vertices[v1]; | ||
float3 p2 = vertices[v2]; | ||
float3 middle = new float3( | ||
(p1.x + p2.x) / 2.0f, | ||
(p1.y + p2.y) / 2.0f, | ||
(p1.z + p2.z) / 2.0f | ||
); | ||
|
||
midpoint = vertices.Count; | ||
vertices.Add(middle); | ||
|
||
midpointCache[key] = midpoint; | ||
return midpoint; | ||
} | ||
|
||
private void ApplyPerlinNoise(List<float3> vertices, float radius, float noiseScale, float noiseStrength) | ||
{ | ||
for (int i = 0; i < vertices.Count; i++) | ||
{ | ||
float3 vertex = vertices[i]; | ||
float noise = NodeExtensions.PerlinNoise(vertex.x * noiseScale, vertex.y * noiseScale, vertex.z * noiseScale); | ||
float displacement = radius + noise * noiseStrength; | ||
vertices[i] = vertex.Normalized * displacement; | ||
} | ||
} | ||
|
||
public override void Update() | ||
{ | ||
Mesh.RecalculateNormals(AllTriangles); | ||
Mesh.RecalculateTangents(AllTriangles); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
using Elements.Assets; | ||
using Elements.Core; | ||
using FrooxEngine; | ||
using System; | ||
|
||
namespace Obsidian | ||
{ | ||
[Category(new string[] { "Obsidian/Assets/Procedural Meshes" })] | ||
public class PlanetMesh : ProceduralMesh | ||
{ | ||
[Range(1, 8)] public readonly Sync<int> Subdivisions; | ||
[Range(0.5f, 10.0f)] public readonly Sync<float> Radius; | ||
[Range(0.1f, 10.0f)] public readonly Sync<float> NoiseScale; | ||
[Range(0.0f, 2.0f)] public readonly Sync<float> NoiseStrength; | ||
|
||
private Planet planet; | ||
private int _subdivisions; | ||
private float _radius; | ||
private float _noiseScale; | ||
private float _noiseStrength; | ||
|
||
protected override void OnAwake() | ||
{ | ||
base.OnAwake(); | ||
Subdivisions.Value = 4; | ||
Radius.Value = 1.0f; | ||
NoiseScale.Value = 1.0f; | ||
NoiseStrength.Value = 0.5f; | ||
} | ||
|
||
protected override void PrepareAssetUpdateData() | ||
{ | ||
_subdivisions = Subdivisions.Value; | ||
_radius = Radius.Value; | ||
_noiseScale = NoiseScale.Value; | ||
_noiseStrength = NoiseStrength.Value; | ||
} | ||
|
||
protected override void ClearMeshData() | ||
{ | ||
planet = null; | ||
} | ||
|
||
protected override void UpdateMeshData(MeshX meshx) | ||
{ | ||
bool value = false; | ||
if (planet == null || planet.Subdivisions != _subdivisions || planet.Radius != _radius || planet.NoiseScale != _noiseScale || planet.NoiseStrength != _noiseStrength) | ||
{ | ||
planet?.Remove(); | ||
planet = new Planet(meshx, _subdivisions, _radius, _noiseScale, _noiseStrength); | ||
value = true; | ||
} | ||
|
||
planet.Subdivisions = Subdivisions.Value; | ||
planet.Radius = Radius.Value; | ||
planet.NoiseScale = NoiseScale.Value; | ||
planet.NoiseStrength = NoiseStrength.Value; | ||
planet.Update(); | ||
uploadHint[MeshUploadHint.Flag.Geometry] = value; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters