The Sierpinski Tetrahedron is a 3-dimensional version of the Sierpinski Triangle. In simple terms, the Sierpinski Triangle is a fractal created by cutting a triangle out of another triangle, and then repeating for the triangles you make doing so.
![]() |
(public domain image from Wikimedia Commons) |
For this, we'll need to make two classes. The first is a tetrahedron, which I called Tetra:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | class Tetra : Volume { Vector3 PointApex; Vector3 PointA; Vector3 PointB; Vector3 PointC; public Tetra(Vector3 apex, Vector3 a, Vector3 b, Vector3 c) { PointApex = apex; PointA = a; PointB = b; PointC = c; VertCount = 4; IndiceCount = 12; ColorDataCount = 4; } public List<Tetra> Divide( int n = 0) { if (n == 0) { return new List<Tetra>( new Tetra[] { this }); } else { Vector3 halfa = (PointApex + PointA) / 2.0f; Vector3 halfb = (PointApex + PointB) / 2.0f; Vector3 halfc = (PointApex + PointC) / 2.0f; // Calculate points half way between base points Vector3 halfab = (PointA + PointB) / 2.0f; Vector3 halfbc = (PointB + PointC) / 2.0f; Vector3 halfac = (PointA + PointC) / 2.0f; Tetra t1 = new Tetra(PointApex, halfa, halfb, halfc); Tetra t2 = new Tetra(halfa, PointA, halfab, halfac); Tetra t3 = new Tetra(halfb, halfab, PointB, halfbc); Tetra t4 = new Tetra(halfc, halfac, halfbc, PointC); List<Tetra> output = new List<Tetra>(); output.AddRange(t1.Divide(n - 1)); output.AddRange(t2.Divide(n - 1)); output.AddRange(t3.Divide(n - 1)); output.AddRange(t4.Divide(n - 1)); return output; } } public override Vector3[] GetVerts() { return new Vector3[] { PointApex, PointA, PointB, PointC }; } public override int [] GetIndices( int offset = 0) { int [] inds = new int [] { //bottom 1,3,2, //other sides 0,1,2, 0,2,3, 0,3,1 }; if (offset != 0) { for ( int i = 0; i < inds.Length; i++) { inds[i] += offset; } } return inds; } public override Vector3[] GetColorData() { return new Vector3[] { new Vector3(1f, 0f, 0f), new Vector3(0f, 1f, 0f), new Vector3(0f, 0f, 1f), new Vector3(1f, 1f, 0f) }; } public override void CalculateModelMatrix() { ModelMatrix = Matrix4.Scale(Scale) * Matrix4.CreateRotationX(Rotation.X) * Matrix4.CreateRotationY(Rotation.Y) * Matrix4.CreateRotationZ(Rotation.Z) * Matrix4.CreateTranslation(Position); } } |
In this class we have four vertices defined and have indices to make a tetrahedron out of them (if you want individually colored sides, you'll need to add more indices). It also has a function to divide the tetrahedron, making the smaller ones for the fractal.
Next we have a class for the fractal itself:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | class Sierpinski : Volume { public Sierpinski( int numSubdivisions = 1) { int NumTris = ( int )Math.Pow(4,numSubdivisions + 1); VertCount = NumTris; ColorDataCount = NumTris; IndiceCount = 3 * NumTris; Tetra twhole = new Tetra( new Vector3(0.0f, 0.0f, 1.0f), // Apex center new Vector3(0.943f, 0.0f, -0.333f), // Base center top new Vector3(-0.471f, 0.816f, -0.333f), // Base left bottom new Vector3(-0.471f, -0.816f, -0.333f)); List<Tetra> allTets = twhole.Divide(numSubdivisions); int offset = 0; foreach (Tetra t in allTets) { verts.AddRange(t.GetVerts()); indices.AddRange(t.GetIndices(offset * 4)); colors.AddRange(t.GetColorData()); offset++; } } private List<Vector3> verts = new List<Vector3>(); private List< int > indices = new List< int >(); private List<Vector3> colors = new List<Vector3>(); public override Vector3[] GetVerts() { return verts.ToArray(); } public override Vector3[] GetColorData() { return colors.ToArray(); } public override int [] GetIndices( int offset = 0) { int [] inds = indices.ToArray(); if (offset != 0) { for ( int i = 0; i < inds.Length; i++) { inds[i] += offset; } } return inds; } public override void CalculateModelMatrix() { ModelMatrix = Matrix4.Scale(Scale) * Matrix4.CreateRotationX(Rotation.X) * Matrix4.CreateRotationY(Rotation.Y) * Matrix4.CreateRotationZ(Rotation.Z) * Matrix4.CreateTranslation(Position); } } |
fun way to get out of memory exception...
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDelete