use OpenGL;
#2 The notched cube
This script shows an animation of a cube that turns into an anticube (or
stella octangula).
The notched cube construction, from a part of a dihedron, is shown in the second animated picture.
notched.pl
#!/usr/local/bin/perl
#
# nodched.pl : from cube to anticube (stella octangula)
# (c) 2013 jl_morel@bribes.org - http://http://bribes.org/perl
use strict;
use warnings;
use OpenGL qw/ :all /;
# ============ Some math routines
#------ Returns the cross product of 2 vectors
sub CrossProduct {
return (
$_[1] * $_[5] - $_[2] * $_[4],
$_[3] * $_[2] - $_[0] * $_[5],
$_[0] * $_[4] - $_[1] * $_[3]
);
}
#------ Returns the length of a vector
sub GetVectorLength {
return sqrt( $_[0] * $_[0] + $_[1] * $_[1] + $_[2] * $_[2] );
}
#------ Returns the vector scaled by the last parameter
sub ScaleVector {
return ( $_[0] * $_[3], $_[1] * $_[3], $_[2] * $_[3] );
}
#------ Returns a normalized vector (length = 1)
sub NormalizeVector {
return ( 0, 0, 0 ) if ( my $norm = GetVectorLength(@_) ) == 0;
return ScaleVector( @_, 1 / $norm );
}
#------ Returns the unit normal vector of a triangle specified by the three
# points P1, P2, and P3.
sub FindUnitNormal {
return NormalizeVector(
CrossProduct(
$_[0] - $_[3], $_[1] - $_[4], $_[2] - $_[5], # P1-P2
$_[3] - $_[6], $_[4] - $_[7], $_[5] - $_[8] # P2-P3
)
);
}
#------ Base vectors
my @i = ( 1, 0, 0 );
my @j = ( 0, 1, 0 );
my @k = ( 0, 0, 1 );
#============ End math routines
my $spin = 0; # rotation angle
my $k = 0; # notch depth 0<$k<1
my $delta = 0.005; # increment for $k
my @light0_position = ( 2, 8, 2, 0 );
my @mat_amb_diff_color = ( 1, 0.7, 0.5, 0 );
my @light_diffuse = ( 1, 1, 1, 1 );
my @light_ambient = ( 0.15, 0.15, 0.15, 0.15 );
#------ Draw only a diedre (1/12th of the cube)
sub DrawDiedre {
my $h = 1 - $k;
my @A = ( -1, 1, 1 );
my @B = ( 1, 1, 1 );
my @C = ( 0, 1, 0 );
my @D = ( 0, 0, 1 );
my @E = ( -$k, 1, 1 );
my @F = ( $k, 1, 1 );
my @G = ( 0, 1, $h );
my @H = ( 0, $h, 1 );
glBegin(GL_QUADS); # The upper polygon is concave,
glNormal3d(@j); # we draw it with two convex quads.
glVertex3d(@A); # We don't want to use a tessallator!
glVertex3d(@E);
glVertex3d(@G);
glVertex3d(@C);
glVertex3d(@F);
glVertex3d(@B);
glVertex3d(@C);
glVertex3d(@G);
glNormal3d(@k); # idem for the front polygon
glVertex3d(@A);
glVertex3d(@D);
glVertex3d(@H);
glVertex3d(@E);
glVertex3d(@B);
glVertex3d(@F);
glVertex3d(@H);
glVertex3d(@D);
glEnd();
# the two triangles of the notch
glBegin(GL_TRIANGLES);
glNormal3d( FindUnitNormal( @E, @H, @G ) );
glVertex3d(@E);
glVertex3d(@H);
glVertex3d(@G);
glNormal3d( FindUnitNormal( @H, @F, @G ) );
glVertex3d(@H);
glVertex3d(@F);
glVertex3d(@G);
glEnd();
}
#------ Draw the notched cube
sub display {
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLightfv_p( GL_LIGHT0, GL_POSITION, @light0_position );
glLoadIdentity();
gluLookAt( 2, 4, 10, 0, 0, 0, 0, 1, 0 );
glPushMatrix();
glScalef( 2, 2, 2 );
glRotatef( $spin, @j );
DrawDiedre(); # The cube is built with 11 rotations
glRotatef( 90, @j );
DrawDiedre();
glRotatef( 90, @j );
DrawDiedre();
glRotatef( 90, @j );
DrawDiedre();
glRotatef( 90, @i );
DrawDiedre();
glRotatef( 90, @j );
DrawDiedre();
glRotatef( 90, @k );
DrawDiedre();
glRotatef( 90, @k );
DrawDiedre();
glRotatef( 90, @j );
DrawDiedre();
glRotatef( 90, @j );
DrawDiedre();
glRotatef( 90, @i );
DrawDiedre();
glRotatef( -90, @j );
DrawDiedre();
glPopMatrix();
glutSwapBuffers();
# debug code
# if ( ( my $e = glGetError() ) != GL_NO_ERROR ) {
# print "error : ", gluErrorString($e), "\n";
# }
}
#------ Initialization routine
sub init {
glClearColor( 0, 0, 0, 0 ); # Black background
glShadeModel(GL_SMOOTH); # Smooth shading
glEnable(GL_MULTISAMPLE); # Enable multisample antialiasing
glEnable(GL_DEPTH_TEST); # Enable hidden surface removal
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
# Light and material
glLightfv_p( GL_LIGHT0, GL_DIFFUSE, @light_diffuse );
glLightfv_p( GL_LIGHT0, GL_AMBIENT, @light_ambient );
glMaterialfv_p( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @mat_amb_diff_color );
}
#------ GLUT Callback called when the window is resized
sub reshape {
my ( $w, $h ) = @_;
glViewport( 0, 0, $w, $h );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective( 45, $h ? $w / $h : 0, 1, 20 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
#------ Routine for rotating the cube
my $WaitUntil = 0;
sub spinDisplay {
my $TimeNow = glutGet(GLUT_ELAPSED_TIME);
if ( $TimeNow >= $WaitUntil ) {
$spin += 1;
$delta = -$delta if $k > 1 or $k < 0;
$k += $delta;
$spin = $spin - 360 if ( $spin > 360 );
glutPostRedisplay();
$WaitUntil = $TimeNow + 1000 / 25; # 25 frames/s
}
}
#------ GLUT callback for the mouse
sub mouse {
my ( $button, $state, $x, $y ) = @_;
if ( $button == GLUT_LEFT_BUTTON ) {
glutIdleFunc( \&spinDisplay ) if ( $state == GLUT_DOWN );
}
elsif ( $button == GLUT_RIGHT_BUTTON ) {
glutIdleFunc(undef) if ( $state == GLUT_DOWN );
}
}
#------ Main program
glutInit();
glutInitDisplayMode(
GLUT_DOUBLE # Double buffering
| GLUT_RGB # RGB color mode
| GLUT_DEPTH # Hidden surface removal
| GLUT_MULTISAMPLE # Multisample antialiasing
);
glutInitWindowSize( 300, 300 );
glutCreateWindow("Notched cube");
init();
glutDisplayFunc( \&display );
glutReshapeFunc( \&reshape );
glutMouseFunc( \&mouse );
glutIdleFunc( \&spinDisplay );
glutMainLoop();
The script as .txt for download:
notched.pl.txt
Back to Top
BðP © 2013 J-L Morel - Contact : jl_morel@bribes.org