/*
* q: 終了
* i: 初期化
*/
//main.h
#include <math.h>
#include <GL/glut.h>
const int WINDOW_WIDTH = 512;
const int WINDOW_HEIGHT = 512;
//時間刻み
const float dt = 0.01f;
//壁の大きさ
const float WALL_SIZE = 5.f;
//反発係数 ( 球と球、球と壁で共通 )
const float coeff = .9f;
//球の数
const int numSpheres = 3;
//球の速度
float vx[ numSpheres ];
float vy[ numSpheres ];
//球の中心の座標
float px[ numSpheres ];
float py[ numSpheres ];
//球の半径
float radius[ numSpheres ];
//球の重さ
float mass[ numSpheres ];
//球の色( diffuse )
float color[ numSpheres ][ 3 ];
void setCamera( void );
void setLight( void );
void initSphere( void );
void display( void );
void displayAxis( float length );
void displaySphere( float r,
float dr, float dg, float db,
float sr, float sg, float sb,
float shininess );
void displayWall( float size );
void keyboardFunction( unsigned char key, int x, int y );
void update( void );
bool collisionDetection( const int id0, const int id1 );
void calculateCollideVelocity( const int id0, const int id1 );
void calculateWall( const int id0 );
//main.cpp
// #include "main.h"
void setCamera( void ) {
glViewport( 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 30.f, ( GLdouble ) WINDOW_WIDTH / ( GLdouble ) WINDOW_HEIGHT,
0.1f, 100.f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt( 0.f, 0.f, 20.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f );
}
void setLight( void )
{
//点光源
GLfloat light_position[ 4 ] = { 5.f, 5.f, 5.f, 1.f };
GLfloat light_ambient[ 4 ] = { 0.3f, 0.3f, 0.3f, 0.f };
GLfloat light_diffuse[ 4 ] = { 1.f, 1.f, 1.f, 1.f };
GLfloat light_specular[ 4 ] = { 1.f, 1.f, 1.f, 1.f };
glLightfv( GL_LIGHT0, GL_POSITION, light_position );
glLightfv( GL_LIGHT0, GL_AMBIENT, light_ambient );
glLightfv( GL_LIGHT0, GL_DIFFUSE, light_diffuse );
glLightfv( GL_LIGHT0, GL_SPECULAR, light_specular );
}
//速度と位置の初期化
void initSphere( void )
{
{ // 0: Blue
vx[ 0 ] = 10.f; vy[ 0 ] = 20.f;
px[ 0 ] = 0.f; py[ 0 ] = 0.f;
radius[ 0 ] = 1.f;
mass[ 0 ] = 8.f;
color[ 0 ][ 0 ] = 0.f; color[ 0 ][ 1 ] = 0.3f; color[ 0 ][ 2 ] = 1.f;
}
{ // 1: Red
vx[ 1 ] = 0.f; vy[ 1 ] = 0.f;
px[ 1 ] = 3.f; py[ 1 ] = 3.f;
radius[ 1 ] = 0.5f;
mass[ 1 ] = 1.f;
color[ 1 ][ 0 ] = 1.f; color[ 1 ][ 1 ] = 0.3f; color[ 1 ][ 2 ] = 0.3f;
}
{ // 2: Green
vx[ 2 ] = 0.f; vy[ 2 ] = 0.f;
px[ 2 ] = -3.f; py[ 2 ] = -2.f;
radius[ 2 ] = 2.f;
mass[ 2 ] = 64.f;
color[ 2 ][ 0 ] = 0.3f; color[ 2 ][ 1 ] = 1.f; color[ 2 ][ 2 ] = 0.3f;
}
}
void keyboardFunction( unsigned char key, int x, int y )
{
switch( key ) {
case 'q': exit( 0 ); break;
case 'i': initSphere(); break;
default: break;
}
glutPostRedisplay();
}
void displayAxis( float length )
{
glBegin( GL_LINES );
glColor3f( 1.f, 0.f, 0.f );
glVertex3f( 0.f, 0.f, 0.f );
glVertex3f( length, 0.f, 0.f );
glColor3f( 0.f, 1.f, 0.f );
glVertex3f( 0.f, 0.f, 0.f );
glVertex3f( 0.f, length, 0.f );
glColor3f( 0.f, 0.f, 1.f );
glVertex3f( 0.f, 0.f, 0.f );
glVertex3f( 0.f, 0.f, length );
glEnd();
}
void displaySphere( float r,
float dr, float dg, float db,
float sr, float sg, float sb,
float shininess )
{
float diffuse[ 4 ] = { dr, dg, db, 1.f };
float specular[ 4 ] = { sr, sg, sb, 1.f };
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse );
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, specular );
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, shininess );
glutSolidSphere( r, 100, 100 );
}
void displayWall( float size ) {
glBegin( GL_LINE_LOOP );
glColor3f( .9f, .9f, .9f );
glVertex3f( -size, -size, 0.f ); glVertex3f( +size, -size, 0.f );
glVertex3f( +size, +size, 0.f ); glVertex3f( -size, +size, 0.f );
glEnd();
}
void display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
setCamera();
setLight();
displayAxis( 5.f );
displayWall( WALL_SIZE );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
for ( int i = 0; i < numSpheres; i++ ) {
glPushMatrix();
glTranslatef( px[ i ], py[ i ], 0.f );
displaySphere( radius[ i ], color[ i ][ 0 ], color[ i ][ 1 ], color[ i ][ 2 ],
0.3f, 0.3f, 0.3f, 30.f );
glPopMatrix();
}
glDisable( GL_LIGHT0 );
glDisable( GL_LIGHTING );
glutSwapBuffers();
}
void update( void )
{
for ( int i = 0; i < numSpheres; i++ ) {
px[ i ] += vx[ i ] * dt;
py[ i ] += vy[ i ] * dt;
}
for ( int i = 0; i < numSpheres; i++ ) {
for ( int j = i + 1; j < numSpheres; j++ ) {
if ( collisionDetection( i, j ) ) {
calculateCollideVelocity( i, j );
}
}
calculateWall( i ); // 壁との衝突処理
}
glutPostRedisplay();
}
bool collisionDetection( const int id0, const int id1 )
{
float d = ( px[ id0 ] - px[ id1 ] ) * ( px[ id0 ] - px[ id1 ] ) +
( py[ id0 ] - py[ id1 ] ) * ( py[ id0 ] - py[ id1 ] );
float r = radius[ id0 ] + radius[ id1 ];
return ( d <= r * r );
}
void calculateCollideVelocity( const int id0, const int id1 )
{
float nx, ny, l, vn[ 2 ], vnn[ 2 ];
nx = px[ id1 ] - px[ id0 ];
ny = py[ id1 ] - py[ id0 ];
l = 1.f / sqrtf( nx * nx + ny * ny );
nx *= l;
ny *= l;
vn[ 0 ] = vx[ id0 ] * nx + vy[ id0 ] * ny;
vn[ 1 ] = vx[ id1 ] * nx + vy[ id1 ] * ny;
// 離れていく場合は衝突とみなさない
if ( ( ( vn[ 1 ] * nx - vn[ 0 ] * nx ) * nx +
( vn[ 1 ] * ny - vn[ 0 ] * ny ) * ny ) > 0.f ) {
return;
}
vx[ id0 ] -= vn[ 0 ] * nx;
vy[ id0 ] -= vn[ 0 ] * ny;
vx[ id1 ] -= vn[ 1 ] * nx;
vy[ id1 ] -= vn[ 1 ] * ny;
vnn[ 0 ] = 1.f / ( mass[ id0 ] + mass[ id1 ] ) *
( ( mass[ id0 ] - coeff * mass[ id1 ] ) * vn[ 0 ] +
mass[ id1 ] * ( 1.f + coeff ) * vn[ 1 ] );
vnn[ 1 ] = 1.f / ( mass[ id0 ] + mass[ id1 ] ) *
( mass[ id0 ] * ( 1.f + coeff ) * vn[ 0 ] +
( mass[ id1 ] - mass[ id0 ] * coeff ) * vn[ 1 ] );
vx[ id0 ] += vnn[ 0 ] * nx;
vy[ id0 ] += vnn[ 0 ] * ny;
vx[ id1 ] += vnn[ 1 ] * nx;
vy[ id1 ] += vnn[ 1 ] * ny;
}
// 壁との衝突処理
void calculateWall ( const int i )
{
float left = -WALL_SIZE + radius[ i ];
if ( px[ i ] < left && vx[ i ] < 0.f ) {
px[ i ] = left;
vx[ i ] *= -coeff;
}
float right = WALL_SIZE - radius[ i ];
if ( right < px[ i ] && 0.f < vx[ i ] ) {
px[ i ] = right;
vx[ i ] *= -coeff;
}
float bottom = -WALL_SIZE + radius[ i ];
if ( py[ i ] < bottom && vy[ i ] < 0.f ) {
py[ i ] = bottom;
vy[ i ] *= -coeff;
}
float top = WALL_SIZE - radius[ i ];
if ( top < py[ i ] && 0.f < vy[ i ] ) {
py[ i ] = top;
vy[ i ] *= -coeff;
}
}
int main( int argc, char** argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( WINDOW_WIDTH, WINDOW_HEIGHT );
glutCreateWindow( "OpenGL Based Renderer" );
glClearColor( 0.f, 0.f, 0.f, 0.f );
glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LESS );
initSphere();
glutDisplayFunc( display );
glutKeyboardFunc( keyboardFunction );
glutIdleFunc( update );
glutMainLoop();
return 0;
}