8dcb8601a2
Hopefully this is the first and last time we have to do this.
173 lines
7.9 KiB
C#
173 lines
7.9 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
|
|
using OpenTK;
|
|
|
|
namespace Examples.Shapes
|
|
{
|
|
public sealed partial class SierpinskiTetrahedron: DrawableShape
|
|
{
|
|
|
|
public enum eSubdivisions
|
|
{
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 4 triangles.</summary>
|
|
Zero = 0,
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 16 triangles.</summary>
|
|
One = 1,
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 64 triangles.</summary>
|
|
Two = 2,
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 256 triangles.</summary>
|
|
Three = 3,
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 1024 triangles.</summary>
|
|
Four = 4,
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 4096 triangles.</summary>
|
|
Five = 5,
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 16384 triangles.</summary>
|
|
Six = 6,
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 65536 triangles.</summary>
|
|
Seven = 7,
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 262144 triangles.</summary>
|
|
Eight = 8,
|
|
/// <summary>Creates a Sierpinski Tetrahedron using 1048576 triangles.</summary>
|
|
Nine = 9,
|
|
}
|
|
|
|
/// <summary>Creates a Sierpinski Tetrahedron which is centered at (0,0,0) and fits into a sphere of radius 1f, or a diameter of 2f</summary>
|
|
/// <param name="scale">Default: 1f.</param>
|
|
/// <param name="subdivs">The number of subdivisions of the Tetrahedron.</param>
|
|
/// <param name="useDL"></param>
|
|
public SierpinskiTetrahedron( double scale, eSubdivisions subdivs, bool useDL )
|
|
: base( useDL )
|
|
{
|
|
TetrahedronFace[] Triangles;
|
|
|
|
switch ( subdivs )
|
|
{
|
|
case eSubdivisions.Zero:
|
|
CreateDefaultTetrahedron( scale, out Triangles );
|
|
break;
|
|
case eSubdivisions.One:
|
|
case eSubdivisions.Two:
|
|
case eSubdivisions.Three:
|
|
case eSubdivisions.Four:
|
|
case eSubdivisions.Five:
|
|
case eSubdivisions.Six:
|
|
case eSubdivisions.Seven:
|
|
case eSubdivisions.Eight:
|
|
case eSubdivisions.Nine:
|
|
CreateDefaultTetrahedron( scale, out Triangles );
|
|
for ( int i = 0; i < (int)subdivs; i++ )
|
|
{
|
|
TetrahedronFace[] temp;
|
|
SubdivideTetrahedron( ref Triangles, out temp );
|
|
Triangles = temp;
|
|
}
|
|
break;
|
|
default: throw new ArgumentOutOfRangeException( "Subdivisions other than contained in the enum cause overflows and are not allowed." );
|
|
}
|
|
|
|
PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.Triangles;
|
|
SierpinskiTetrahedron.GetVertexArray( ref Triangles, out VertexArray );
|
|
IndexArray = null;
|
|
}
|
|
|
|
internal static void GetVertexArray( ref TetrahedronFace[] input, out VertexT2dN3dV3d[] output )
|
|
{
|
|
output = new VertexT2dN3dV3d[input.Length * 3];
|
|
int counter = 0;
|
|
for ( int i = 0; i < input.Length; i++ )
|
|
{
|
|
input[i].GetVertices( out output[counter + 0], out output[counter + 1], out output[counter + 2] );
|
|
counter += 3;
|
|
}
|
|
}
|
|
|
|
/// <summary>Generates the lowest subdivision mesh, which consists of 4 Triangles.</summary>
|
|
internal static void CreateDefaultTetrahedron( double scale, out TetrahedronFace[] array )
|
|
{
|
|
Vector3d[] Points = new Vector3d[4];
|
|
Points[0] = new Vector3d( 0.0 * scale, 0.0 * scale, 1.0 * scale );
|
|
Points[1] = new Vector3d( -0.816 * scale, 0.471 * scale, -0.333 * scale );
|
|
Points[2] = new Vector3d( 0.816 * scale, 0.471 * scale, -0.333 * scale );
|
|
Points[3] = new Vector3d( 0.0 * scale, -0.943 * scale, -0.333 * scale );
|
|
|
|
Vector2d[] TexCoords = new Vector2d[4];
|
|
TexCoords[0] = new Vector2d( 0.0, 0.0 );
|
|
TexCoords[1] = new Vector2d( 1.0, 0.0 );
|
|
TexCoords[2] = new Vector2d( 0.0, 1.0 );
|
|
TexCoords[3] = new Vector2d( 1.0, 1.0 );
|
|
|
|
Vector3d Normal;
|
|
array = new TetrahedronFace[4];
|
|
|
|
FindNormal( ref Points[0], ref Points[2], ref Points[1], ref Points[3], out Normal );
|
|
array[0] = new TetrahedronFace( ref Points[0], ref TexCoords[2],
|
|
ref Points[2], ref TexCoords[0],
|
|
ref Points[1], ref TexCoords[1],
|
|
ref Points[3],
|
|
ref Normal );
|
|
|
|
FindNormal( ref Points[0], ref Points[3], ref Points[2], ref Points[1], out Normal );
|
|
array[1] = new TetrahedronFace( ref Points[0], ref TexCoords[0],
|
|
ref Points[3], ref TexCoords[1],
|
|
ref Points[2], ref TexCoords[2],
|
|
ref Points[1],
|
|
ref Normal );
|
|
|
|
FindNormal( ref Points[0], ref Points[1], ref Points[3], ref Points[2], out Normal );
|
|
array[2] = new TetrahedronFace( ref Points[0], ref TexCoords[2],
|
|
ref Points[1], ref TexCoords[1],
|
|
ref Points[3], ref TexCoords[3],
|
|
ref Points[2],
|
|
ref Normal );
|
|
|
|
FindNormal( ref Points[1], ref Points[2], ref Points[3], ref Points[0], out Normal );
|
|
array[3] = new TetrahedronFace( ref Points[1], ref TexCoords[3],
|
|
ref Points[2], ref TexCoords[2],
|
|
ref Points[3], ref TexCoords[1],
|
|
ref Points[0],
|
|
ref Normal );
|
|
}
|
|
|
|
/// <summary>Subdivides each triangle into 4 new ones.</summary>
|
|
private void SubdivideTetrahedron( ref TetrahedronFace[] source, out TetrahedronFace[] output )
|
|
{
|
|
|
|
output = new TetrahedronFace[source.Length * 4];
|
|
|
|
int counter = 0;
|
|
for ( int i = 0; i < source.Length; i++ )
|
|
{
|
|
source[i].SubdivideSierpinski( out output[counter + 0], out output[counter + 1], out output[counter + 2], out output[counter + 3] );
|
|
counter += 4; // every source triangle emits 4 new triangles
|
|
}
|
|
}
|
|
|
|
/// <summary>A, B and C are the triangle whos normal is to be determined. D is the 4th Point in the Tetraeder which does not belong to the triangle.</summary>
|
|
internal static void FindNormal( ref Vector3d A, ref Vector3d B, ref Vector3d C, ref Vector3d D, out Vector3d result )
|
|
{
|
|
Vector3d temp1, temp2, temp3;
|
|
|
|
Vector3d.Subtract( ref A, ref D, out temp1 );
|
|
Vector3d.Subtract( ref B, ref D, out temp2 );
|
|
Vector3d.Subtract( ref C, ref D, out temp3 );
|
|
|
|
Vector3d.Add( ref temp1, ref temp2, out result );
|
|
Vector3d.Add(ref result, ref temp3, out result);
|
|
result.Normalize();
|
|
}
|
|
|
|
internal static void FindNormal( ref Vector3d A, ref Vector3d B, ref Vector3d C, out Vector3d result )
|
|
{
|
|
Vector3d temp1, temp2;
|
|
Vector3d.Subtract( ref A, ref B, out temp1 );
|
|
temp1.Normalize();
|
|
Vector3d.Subtract(ref C, ref B, out temp2);
|
|
temp2.Normalize();
|
|
Vector3d.Cross( ref temp1, ref temp2, out result );
|
|
result *= -1.0;
|
|
result.Normalize();
|
|
}
|
|
|
|
}
|
|
}
|