Last active
May 3, 2024 16:45
-
-
Save NicolasCaous/c933c1399822c9c69ce798384e370e67 to your computer and use it in GitHub Desktop.
Triangle subdivision algorithm unity3d
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
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using Unity.VisualScripting.Antlr3.Runtime.Tree; | |
using UnityEngine; | |
public class TerrainRenderer : MonoBehaviour | |
{ | |
struct Vertex | |
{ | |
public float x; | |
public float y; | |
} | |
struct Index | |
{ | |
public uint first; | |
public uint second; | |
public uint third; | |
} | |
[Range(0, 13)] | |
public int debugSubdivisions = 0; | |
[Range(1, 100)] | |
public int debugScale = 1; | |
private Vertex[] _debugVertices; | |
private Index[] _debugIndices; | |
void CalculatePoints(int subdivisions, out Vertex[] vertices, out Index[] indices) | |
{ | |
if (subdivisions > 13) throw new Exception("Cannot subdivide 2 triangles more than 14 times (32 bit integer limit)"); | |
// 2 ^ (Subdivisions + 1) - 2 ^ Subdivisions + 1 | |
int side = (1 << (subdivisions + 1)) - (1 << subdivisions) + 1; | |
vertices = new Vertex[side * side]; | |
double gap = 1d / (side - 1); | |
for (int i = 0; i < side; ++i) | |
{ | |
for (int j = 0; j < side; ++j) | |
{ | |
vertices[i * side + j].x = (float) (gap * j); | |
vertices[i * side + j].y = (float) (gap * i); | |
} | |
} | |
int indicesCount = 2; | |
for (int i = 1; i <= subdivisions; ++i) | |
{ | |
indicesCount += 1 << (i * 2 + 1); | |
} | |
indices = new Index[indicesCount]; | |
int subdivisionLevel = 0; | |
int offset = 0; | |
for (int indexGap = side - 1; indexGap > 0; indexGap /= 2) | |
{ | |
int sections = (side - 1) / indexGap; | |
for (int i = 0; i < sections; ++i) | |
{ | |
for (int j = 0; j < sections; ++j) | |
{ | |
int bottomTriangleIndex = offset + (j * sections + i) * 2; | |
int topTriangleIndex = bottomTriangleIndex + 1; | |
{ | |
int x = j * indexGap; | |
int y = i * indexGap; | |
indices[bottomTriangleIndex].first = (uint) (y * side + x); | |
x += indexGap; | |
y += indexGap; | |
indices[bottomTriangleIndex].second= (uint) (y * side + x); | |
y -= indexGap; | |
indices[bottomTriangleIndex].third = (uint) (y * side + x); | |
} | |
{ | |
int x = j * indexGap; | |
int y = i * indexGap; | |
indices[topTriangleIndex].first = (uint)(y * side + x); | |
y += indexGap; | |
indices[topTriangleIndex].second = (uint)(y * side + x); | |
x += indexGap; | |
indices[topTriangleIndex].third = (uint)(y * side + x); | |
} | |
/*Debug.Log($"{j * indexGap}, {i * indexGap}, {bottomTriangleIndex}, {topTriangleIndex}"); | |
Debug.Log($"BOTTOM ({j * indexGap}, {i * indexGap}), ({j * indexGap + indexGap}, {i * indexGap + indexGap}), ({j * indexGap + indexGap}, {i * indexGap})"); | |
Debug.Log($"BOTTOM ({vertices[indices[bottomTriangleIndex].first].x}, {vertices[indices[bottomTriangleIndex].first].y}), " + | |
$"({vertices[indices[bottomTriangleIndex].second].x}, {vertices[indices[bottomTriangleIndex].second].y}), " + | |
$"({vertices[indices[bottomTriangleIndex].third].x}, {vertices[indices[bottomTriangleIndex].third].y})"); | |
Debug.Log($"TOP ({j * indexGap}, {i * indexGap}), ({j * indexGap}, {i * indexGap + indexGap}), ({j * indexGap + indexGap}, {i * indexGap + indexGap})"); | |
Debug.Log($"TOP ({vertices[indices[topTriangleIndex].first].x}, {vertices[indices[topTriangleIndex].first].y}), " + | |
$"({vertices[indices[topTriangleIndex].second].x}, {vertices[indices[topTriangleIndex].second].y}), " + | |
$"({vertices[indices[topTriangleIndex].third].x}, {vertices[indices[topTriangleIndex].third].y})");*/ | |
} | |
} | |
offset += 1 << (subdivisionLevel * 2 + 1); | |
subdivisionLevel += 1; | |
} | |
// first step -> detect every triangle that is bigger than treshhold (+ apply GPU culling) | |
// second step -> for every triangle that is going to be rendered, remove all parents that are going to be rendered | |
// third step -> for every triangle, copy to buffer to be rendered using atomic add | |
} | |
void Start() | |
{ | |
CalculatePoints(13, out _debugVertices, out _debugIndices); | |
} | |
private void OnDrawGizmos() | |
{ | |
if (_debugVertices == null || _debugIndices == null) return; | |
int offset = 0; | |
for (int i = 0; i < debugSubdivisions; ++i) | |
{ | |
offset += 1 << (i * 2 + 1); | |
} | |
int totalTriangles = 1 << (debugSubdivisions * 2 + 1); | |
if (offset + totalTriangles > _debugIndices.Length) return; | |
for (int i = 0; i < totalTriangles; ++i) | |
{ | |
Gizmos.DrawLine( | |
new Vector3(_debugVertices[_debugIndices[offset + i].first].x * debugScale, _debugVertices[_debugIndices[offset + i].first].y * debugScale, 0), | |
new Vector3(_debugVertices[_debugIndices[offset + i].second].x * debugScale, _debugVertices[_debugIndices[offset + i].second].y * debugScale, 0) | |
); | |
Gizmos.DrawLine( | |
new Vector3(_debugVertices[_debugIndices[offset + i].second].x * debugScale, _debugVertices[_debugIndices[offset + i].second].y * debugScale, 0), | |
new Vector3(_debugVertices[_debugIndices[offset + i].third].x * debugScale, _debugVertices[_debugIndices[offset + i].third].y * debugScale, 0) | |
); | |
Gizmos.DrawLine( | |
new Vector3(_debugVertices[_debugIndices[offset + i].third].x * debugScale, _debugVertices[_debugIndices[offset + i].third].y * debugScale, 0), | |
new Vector3(_debugVertices[_debugIndices[offset + i].first].x * debugScale, _debugVertices[_debugIndices[offset + i].first].y * debugScale, 0) | |
); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment