Skip to content

Instantly share code, notes, and snippets.

@NicolasCaous
Last active May 3, 2024 16:45
Show Gist options
  • Save NicolasCaous/c933c1399822c9c69ce798384e370e67 to your computer and use it in GitHub Desktop.
Save NicolasCaous/c933c1399822c9c69ce798384e370e67 to your computer and use it in GitHub Desktop.
Triangle subdivision algorithm unity3d
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