VisualC++ と OpenGL を利用した仮想物理実験室
仮想物理実験室の構築 (ver1.0)
コンピュータ・シミュレーションによる、仮想物理実験室のプロトタイプ(ver.1.0)です。
マウスドラッグで回転し、キーボードの「I」でズームイン、キーボードの「O」でズームアウトします。
OpenGL と C++ によるソース
VisualC++ の新規プロジェクトを立ち上げ、 以下のC++言語のソースを次のソースをコピー&ペーストしてください。実行の前にこのページの下にある「gl_screenshot.h」と「gl_material.h」を予め準備してください。
main.cpp ファイル
//////////////////////////////////////////////////////////////////////////
// 仮想物理実験室(ver 1.0)
//////////////////////////////////////////////////////////////////////////
#include <math.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <direct.h>
#include <time.h>
#include <GL/glut.h>
#include <GL/gl_material.h>
#include <GL/gl_screenshot.h>
using namespace std;
double PI = acos(-1.0);
//////////////////////////////////////////////////////////////////////////
// 変数の定義
//////////////////////////////////////////////////////////////////////////
#define _BITMAP 0 //アニメーション作成用ビットマップの保存 0:しない 1:する
//--------------------------------------------------------
// 仮想物理実験室変数の定義
//--------------------------------------------------------
double t = 0.0; //時刻
double dt= 0.01; //時間刻み
int tn = 0; //ステップ数
//--------------------------------------------------------
// OpenGL用変数定義
//--------------------------------------------------------
//////////////////////////////////////////
// ウィンドウ生成用
int WindowPositionX = 200; //生成するウィンドウ位置のX座標
int WindowPositionY = 200; //生成するウィンドウ位置のY座標
int WindowWidth = 512; //生成するウィンドウの幅
int WindowHeight = 512; //生成するウィンドウの高さ
char WindowTitle[] = "仮想物理実験室(ver 1.0)"; //ウィンドウのタイトル
//////////////////////////////////////////
// アニメーション用 ビットマップ保存
gl_screenshot gs; //「gl_screenshot」クラスのインスタンス「gs」を宣言
//////////////////////////////////////////
// 床描画用
static GLfloat floor_planar[4];
static GLfloat floor_s = 50.0f; //床の広さ(1辺=2.0*floor_s)
static GLfloat pM[16];
static GLfloat LightPosition[4] = { -10, -20, 70, 1 }; //光源の位置
typedef struct _QUADS_VERTEX{
GLfloat v0[3];
GLfloat v1[3];
GLfloat v2[3];
GLfloat v3[3];
}QUADS_VERTEX;
static QUADS_VERTEX floor_v = {
{ floor_s, floor_s, 0.0f },
{ -floor_s, floor_s, 0.0f },
{ -floor_s, -floor_s, 0.0f },
{ floor_s, -floor_s, 0.0f },
};
void findPlane(GLfloat plane[4], GLfloat v0[3], GLfloat v1[3], GLfloat v2[3]);
void DrawFloor(bool bTexture);
//////////////////////////////////////////
// マウスドラッグ用
int cx, cy; // ドラッグ開始位置
double sx, sy; // マウスの絶対位置→ウィンドウ内での相対位置の換算係数
double cq[4] = { 1.0, 0.0, 0.0, 0.0 }; // 回転の初期値 (クォータニオン)
double tq[4]; // ドラッグ中の回転 (クォータニオン)
double rt[16]; // 回転の変換行列
unsigned int listNumber;
float camera_z_pos =200.0;
//////////////////////////////////////////
// 文字描画用
int text_list;
char t_char[20];
char t_char2[20];
void DRAW_STRING(int x, int y, char *string, void *font = GLUT_BITMAP_TIMES_ROMAN_24);
void DISPLAY_TEXT(int x, int y, char *string);
//--------------------------------------------------------
// 回転用
//--------------------------------------------------------
void qmul(double r[], const double p[], const double q[]);
void qrot(double r[], double q[]);
//--------------------------------------------------------
// 関数のプロトタイプ
//--------------------------------------------------------
//////////////////////////////////////////
// メイン関数用
void Initialize(void);
void Display(void);
void Idle(void);
void Keyboard(unsigned char key, int x, int y);
void mouse_motion(int x, int y);
void mouse_on(int button, int state, int x, int y);
void mouse_wheel(float);
//////////////////////////////////////////
// 描画用
void Calculate(void); //計算
void DrawStructure(void); //描画
void Ground(void); //大地の描画
//////////////////////////////////////////
// 影描画用
void shadowMatrix(GLfloat *m, GLfloat plane[4], GLfloat light[4]);
void DrawShadow(void);
//--------------------------------------------------------
// メイン関数
//--------------------------------------------------------
int main(int argc, char *argv[]){
srand((unsigned)time(NULL));
#if _BITMAP
_mkdir("bitmap"); //bmpファイル保存用のフォルダの作成
#endif
glutInit(&argc, argv); //環境の初期化
glutInitWindowPosition(WindowPositionX, WindowPositionY); //ウィンドウの位置の指定
glutInitWindowSize(WindowWidth, WindowHeight); //ウィンドウサイズの指定
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); //ディスプレイモードの指定
glutCreateWindow(WindowTitle); //ウィンドウの作成
glutDisplayFunc(Display); //描画時に呼び出される関数を指定する(関数名:Display)
glutMouseFunc(mouse_on); //マウスクリック時に呼び出される関数
glutMotionFunc(mouse_motion); //マウスドラッグ解除時に呼び出される関数
glutKeyboardFunc(Keyboard); //キーボード入力時に呼び出される関数を指定する(関数名:Keyboard)
glutIdleFunc(Idle); //プログラムアイドル状態時に呼び出される関数
Initialize(); //初期設定の関数を呼び出す
glutMainLoop();
return 0;
}
//--------------------------------------------------------
// 初期設定の関数
//--------------------------------------------------------
void Initialize(void){
glClearColor(1.0, 1.0, 1.0, 1.0); //背景色
glEnable( GL_DEPTH_TEST ); //デプスバッファを使用:glutInitDisplayMode() で GLUT_DEPTH を指定する
glDepthFunc( GL_LEQUAL );
glClearDepth( 1.0 );
//////////////////////////////////////////
// ディスプレイリストを作成
listNumber = glGenLists(1);
glNewList( listNumber, GL_COMPILE );
glEndList();
//////////////////////////////////////////
// マウスポインタ位置のウィンドウ内の相対的位置への換算用
sx = 1.0 / (double)WindowWidth;
sy = 1.0 / (double)WindowHeight;
// 回転行列の初期化
qrot(rt, cq);
//////////////////////////////////////////
// 床
findPlane( floor_planar,
floor_v.v0,
floor_v.v1,
floor_v.v2 );
//////////////////////////////////////////
//透視変換行列の設定
glMatrixMode(GL_PROJECTION);//行列モードの設定(GL_PROJECTION : 透視変換行列の設定、GL_MODELVIEW:モデルビュー変換行列)
glLoadIdentity();//行列の初期化
gluPerspective(30.0, (double)WindowWidth/(double)WindowHeight, 0.1, 1000.0); //透視投影法の視体積gluPerspactive(th, w/h, near, far);
}
//--------------------------------------------------------
// 描画の関数
//--------------------------------------------------------
void Display(void) {
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//////////////////////////////////////////
//モデルビュー変換行列の設定
glMatrixMode(GL_MODELVIEW);//行列モードの設定(GL_PROJECTION : 透視変換行列の設定、GL_MODELVIEW:モデルビュー変換行列)
glLoadIdentity();//行列の初期化
glViewport(0, 0, WindowWidth, WindowHeight);
//////////////////////////////////////////
//視点の設定
gluLookAt(
0.0, 0.0, camera_z_pos, // 視点の位置x,y,z;
0.0, 0.0, 0.0, // 視界の中心位置の参照点座標x,y,z
0.0, 1.0, 0.0 ) ; //視界の上方向のベクトルx,y,z
//////////////////////////////////////////
//ステンシルバッファクリア値の設定
glClearStencil( 0 );
glCullFace( GL_BACK );
glEnable( GL_CULL_FACE );
glEnable( GL_AUTO_NORMAL );
glEnable( GL_NORMALIZE );
//////////////////////////////////////////
// 平面射影行列の算出
shadowMatrix(pM,floor_planar,LightPosition);
//////////////////////////////////////////
// 回転
glMultMatrixd(rt);
//////////////////////////////////////////
// 光源ON
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glLightfv( GL_LIGHT0,GL_POSITION,LightPosition );
//////////////////////////////////////////
// 描画
glPushMatrix();
Calculate(); //計算
DrawStructure(); //物体
DrawShadow(); //影
glPopMatrix();
//////////////////////////////////////////
//陰影OFF
glDisable(GL_AUTO_NORMAL);
glDisable(GL_NORMALIZE);
glDisable(GL_LIGHTING);
Ground(); // 地面の描画
//////////////////////////////////////////
//文字の描画
strcpy_s(t_char2, "t = ");
sprintf_s(t_char, "%5.2f", t);
strcat_s(t_char2, t_char);
DISPLAY_TEXT(5, 95, t_char2 );
//////////////////////////////////////////
//ビットマップの保存
#if _BITMAP
ostringstream fname;
int tt = tn +10000;
fname << "bitmap/" << tt << ".bmp" ;//出力ファイル名
string name = fname.str();
gs.screenshot(name.c_str(), 24);
#endif
glutSwapBuffers(); //glutInitDisplayMode(GLUT_DOUBLE)でダブルバッファリングを利用可
}
//--------------------------------------------------------
// 計算と物体の描画
//--------------------------------------------------------
void Calculate(){
t = dt * double(tn);
tn++;
}
void DrawStructure(){
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT, ms_ruby.ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, ms_ruby.diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, ms_ruby.specular);
glMaterialfv(GL_FRONT, GL_SHININESS, &ms_ruby.shininess);
glTranslated(0.0, 0.0, 20.0);//平行移動値の設定
glutSolidCube(10.0);//引数:(一辺の長さ)
glPopMatrix();
}
//--------------------------------------------------------
// 大地の描画
//--------------------------------------------------------
void Ground(void) {
double ground_max_x = 300.0;
double ground_max_y = 300.0;
glColor3d(0.8, 0.8, 0.8); // 大地の色
glBegin(GL_LINES);
for(double ly = -ground_max_y ;ly <= ground_max_y; ly+=10.0){
glVertex3d(-ground_max_x, ly, -1.1);
glVertex3d(ground_max_x, ly , -1.1);
}
for(double lx = -ground_max_x ;lx <= ground_max_x; lx+=10.0){
glVertex3d(lx, ground_max_y , -1.1);
glVertex3d(lx, -ground_max_y, -1.1);
}
glEnd();
}
//--------------------------------------------------------
// アイドル時に呼び出される関数
//--------------------------------------------------------
void Idle(){
glutPostRedisplay(); //glutDisplayFunc()を1回実行する
}
//--------------------------------------------------------
// キーボード入力時に呼び出される関数
//--------------------------------------------------------
void Keyboard(unsigned char key, int x, int y){
switch ( key )
{
case 'i':
camera_z_pos -= 10.0;
break;
case 'o':
camera_z_pos += 10.0;
break;
default:
break;
}
cout << camera_z_pos << endl;
}
//--------------------------------------------------------
// マウスドラッグ時
//--------------------------------------------------------
void mouse_motion(int x, int y){
double dx, dy, a;
// マウスポインタの位置のドラッグ開始位置からの変位
dx = (x - cx) * sx;
dy = (y - cy) * sy;
// マウスポインタの位置のドラッグ開始位置からの距離
a = sqrt(dx * dx + dy * dy);
if( a != 0.0 )
{
// マウスのドラッグに伴う回転のクォータニオン dq を求める
double ar = a * 2.0 * PI * 0.5;
double as = sin(ar) / a;
double dq[4] = { cos(ar), dy * as, dx * as, 0.0 };
// 回転の初期値 cq に dq を掛けて回転を合成
qmul(tq, dq, cq);
// クォータニオンから回転の変換行列を求める
qrot(rt, tq);
}
}
//--------------------------------------------------------
// マウスクリック時
//--------------------------------------------------------
void mouse_on(int button, int state, int x, int y){
switch (button) {
case 0:
switch (state) {
case 0:
// ドラッグ開始点を記録
cx = x;
cy = y;
break;
case 1:
// 回転の保存
cq[0] = tq[0];
cq[1] = tq[1];
cq[2] = tq[2];
cq[3] = tq[3];
break;
default:
break;
}
break;
default:
break;
}
cout << x << " " << y<<endl;
}
//--------------------------------------------------------
// 床平面の方程式と行列の計算
//--------------------------------------------------------
void findPlane(
GLfloat plane[4], // 作成する平面方程式の係数
GLfloat v0[3], // 頂点1
GLfloat v1[3], // 頂点2
GLfloat v2[3]) // 頂点3
{
GLfloat vec0[3], vec1[3];
// Need 2 vectors to find cross product.
vec0[0] = v1[0] - v0[0];
vec0[1] = v1[1] - v0[1];
vec0[2] = v1[2] - v0[2];
vec1[0] = v2[0] - v0[0];
vec1[1] = v2[1] - v0[1];
vec1[2] = v2[2] - v0[2];
// find cross product to get A, B, and C of plane equation
plane[0] = vec0[1] * vec1[2] - vec0[2] * vec1[1];
plane[1] = -(vec0[0] * vec1[2] - vec0[2] * vec1[0]);
plane[2] = vec0[0] * vec1[1] - vec0[1] * vec1[0];
plane[3] = -(plane[0] * v0[0] + plane[1] * v0[1] + plane[2] * v0[2]);
}
void shadowMatrix(
GLfloat *m, // 作成する行列のポインタ
GLfloat plane[4], // 射影する表面の平面方程式の係数
GLfloat light[4]) // 光源の同時座標値
{
GLfloat dot;
// Find dot product between light position vector and ground plane normal.
dot = plane[0] * light[0] +
plane[1] * light[1] +
plane[2] * light[2] +
plane[3] * light[3];
m[0] = dot - light[0] * plane[0];
m[4] = 0.f - light[0] * plane[1];
m[8] = 0.f - light[0] * plane[2];
m[12] = 0.f - light[0] * plane[3];
m[1] = 0.f - light[1] * plane[0];
m[5] = dot - light[1] * plane[1];
m[9] = 0.f - light[1] * plane[2];
m[13] = 0.f - light[1] * plane[3];
m[2] = 0.f - light[2] * plane[0];
m[6] = 0.f - light[2] * plane[1];
m[10] = dot - light[2] * plane[2];
m[14] = 0.f - light[2] * plane[3];
m[3] = 0.f - light[3] * plane[0];
m[7] = 0.f - light[3] * plane[1];
m[11] = 0.f - light[3] * plane[2];
m[15] = dot - light[3] * plane[3];
}
//--------------------------------------------------------
// 床の描画と影の描画
//--------------------------------------------------------
void DrawFloor(bool bTexture){
if( bTexture ){
// 床にテクスチャを使う時はココで設定する
// glBindTexture( GL_TEXTURE_2D, );
glDisable(GL_LIGHTING);
glBegin(GL_QUADS);
// glTexCoord2f( , );
glVertex3fv( floor_v.v0 );
// glTexCoord2f( , );
glVertex3fv( floor_v.v1 );
// glTexCoord2f( , );
glVertex3fv( floor_v.v2 );
// glTexCoord2f( , );
glVertex3fv( floor_v.v3 );
glEnd();
glEnable(GL_LIGHTING);
}else{
glDisable(GL_LIGHTING);
glBegin(GL_QUADS);
glVertex3fv( floor_v.v0 );
glVertex3fv( floor_v.v1 );
glVertex3fv( floor_v.v2 );
glVertex3fv( floor_v.v3 );
glEnd();
glEnable(GL_LIGHTING);
}
}
void DrawShadow(void){
/////////////////////////////////////////////
//床のステンシルを付ける
glEnable(GL_STENCIL_TEST);
glStencilFunc( GL_ALWAYS, 1, ~0);
//これから描画するもののステンシル値にすべて1タグをつける
glStencilOp(GL_KEEP,GL_KEEP ,GL_REPLACE);
glColor4f(0.7f, 0.4f, 0.0f, 1.0f);
DrawFloor( true );//床の描画
/////////////////////////////////////////////
//カラー・デプスバッファマスクをセットする
//これで以下の内容のピクセルの色の値は、書き込まれない。
glColorMask(0,0,0,0);
glDepthMask(0);
/////////////////////////////////////////////
//床にオブジェクトの影のステンシルを付ける
glEnable(GL_STENCIL_TEST);
glStencilFunc( GL_EQUAL, 1, ~0);
//これから描画するもののステンシル値にすべて1タグをつける
glStencilOp(GL_KEEP,GL_KEEP ,GL_INCR);
glDisable(GL_DEPTH_TEST);
glPushMatrix();
glMultMatrixf(pM);
DrawStructure();
glPopMatrix();
glEnable(GL_DEPTH_TEST);
/////////////////////////////////////////////
//ビットマスクを解除
glColorMask(1,1,1,1);
glDepthMask(1);
/////////////////////////////////////////////
//影をつける
glStencilFunc( GL_EQUAL, 2, ~0 );
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.1f, 0.1f, 0.1f, 0.5f);
glDisable(GL_DEPTH_TEST);
DrawFloor( false );//床の描画
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
}
//--------------------------------------------------------
// 文字描画
//--------------------------------------------------------
void DISPLAY_TEXT(int x, int y, char *string){
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glPushAttrib(GL_ENABLE_BIT);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 100, 0, 100);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glColor3f(0.0, 0.0, 0.0);
glCallList(text_list);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
glMatrixMode(GL_MODELVIEW);
text_list=glGenLists(1);
glNewList(text_list,GL_COMPILE);
DRAW_STRING(x, y, string , GLUT_BITMAP_TIMES_ROMAN_24);
glEndList();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
void DRAW_STRING(int x, int y, char *string, void *font){
int len, i;
glRasterPos2f(x, y);
len = (int) strlen(string);
for (i = 0; i < len; i++){
glutBitmapCharacter(font, string[i]);
}
}
//--------------------------------------------------------
// マウスドラッグによる回転
//--------------------------------------------------------
//////////////////////////////////////////////
// クォータニオンの積 r <- p x q
static void qmul(double r[], const double p[], const double q[])
{
r[0] = p[0] * q[0] - p[1] * q[1] - p[2] * q[2] - p[3] * q[3];
r[1] = p[0] * q[1] + p[1] * q[0] + p[2] * q[3] - p[3] * q[2];
r[2] = p[0] * q[2] - p[1] * q[3] + p[2] * q[0] + p[3] * q[1];
r[3] = p[0] * q[3] + p[1] * q[2] - p[2] * q[1] + p[3] * q[0];
}
/////////////////////////////////////////////
// 回転の変換行列 r <- クォータニオン q
static void qrot(double r[], double q[]){
double x2 = q[1] * q[1] * 2.0;
double y2 = q[2] * q[2] * 2.0;
double z2 = q[3] * q[3] * 2.0;
double xy = q[1] * q[2] * 2.0;
double yz = q[2] * q[3] * 2.0;
double zx = q[3] * q[1] * 2.0;
double xw = q[1] * q[0] * 2.0;
double yw = q[2] * q[0] * 2.0;
double zw = q[3] * q[0] * 2.0;
r[ 0] = 1.0 - y2 - z2;
r[ 1] = xy + zw;
r[ 2] = zx - yw;
r[ 4] = xy - zw;
r[ 5] = 1.0 - z2 - x2;
r[ 6] = yz + xw;
r[ 8] = zx + yw;
r[ 9] = yz - xw;
r[10] = 1.0 - x2 - y2;
r[ 3] = r[ 7] = r[11] = r[12] = r[13] = r[14] = 0.0;
r[15] = 1.0;
}
gl_screenshot.h
「gl_screenshot.h」は、ウインドウの内容をビットマップファイルへ出力するために必要なプログラムです。本プログラムは「OpenGL(Akita National College of Technology Yamamoto's Laboratory )」で公開されています。オリジナルは、「gl_screenshot.cpp」「gl_screenshot.h」で構成されていますが、本講座では2つの上記の2つのファイルを「gl_screenshot.h」にまとめて利用しています。
テキストエディタを起動し以下のソースをコピー&ペーストし、ファイル名を「gl_screenshot.h」としてください。 今後も利用するので、「gl_screenshot.h」ファイルを「glut.h」と同じ場所におきます。
//--------------------------------------------------------
// 画面の内容をビットマップファイルに出力
//--------------------------------------------------------
// 以下のページで公開されているソースを利用させていただきます。
// http://akita-nct.jp/yamamoto/comp/OpenGL/OpenGL.html
//--------------------------------------------------------
// filename: 出力ファイル名
// bpp: ピクセルあたりのビット数(24, 32)
#ifndef GL_SCREENSHOT_H_INCLUDED
#define GL_SCREENSHOT_H_INCLUDED
#include <stdlib.h>
#include <GL/glut.h>
#include <iostream>
#include <fstream>
#include <vector>
// ビットマップのヘッダ
struct BITMAPFILEHEADER_ {
//char bfType1;
//char bfType2;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
};
struct BITMAPINFOHEADER_ {
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPixPerMeter;
long biYPixPerMeter;
unsigned long biClrUsed;
unsigned long biClrImporant;
};
class gl_screenshot {
public:
gl_screenshot(){};
~gl_screenshot(){};
bool screenshot(const char* filename, int bpp=32)
{
const int width = glutGet(GLUT_WINDOW_WIDTH); // 画像の大きさ
const int height = glutGet(GLUT_WINDOW_HEIGHT);
// ピクセルデータ全体のサイズ
const int datasize = height*((((width*bpp/8) + 3) >> 2) << 2);
// ファイルサイズ
const int filesize = 2 + sizeof(BITMAPFILEHEADER_) + sizeof(BITMAPINFOHEADER_) + datasize;
// ビットマップのヘッダ
BITMAPFILEHEADER_ bmfh = {filesize, 0, 0, 54,};
BITMAPINFOHEADER_ bmih = {40, width, height, 1, bpp, 0, 0, 0, 0, 0, 0,};
// データのフォーマット
int format;
if (bpp == 24) {
format = GL_RGB;
}
else if (bpp == 32) {
format = GL_RGBA;
}
else {
std::cerr << "invalid parameter 'bpp'" << std::endl;
return false;
}
// データをもらう
std::vector<GLubyte> buf(datasize);
//glPixelStorei(GL_PACK_ALIGNMENT, 1);
//glReadBuffer(GL_FRONT);
glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, &buf[0]);
// RGB → BGR
for (int i=0; i<datasize; i+=bpp/8) {
std::swap(buf[i], buf[i+2]);
}
// 出力
std::ofstream fs(filename, std::ios::out | std::ios::trunc | std::ios::binary);
if (!fs) {
std::cerr << "fstream::open() failed." << std::endl;
return false;
}
fs.write("BM", 2);
fs.write(reinterpret_cast<const char*>(&bmfh), sizeof(BITMAPFILEHEADER_));
fs.write(reinterpret_cast<const char*>(&bmih), sizeof(BITMAPINFOHEADER_));
fs.write(reinterpret_cast<const char*>(&buf[0]), datasize);
fs.close();
return true;
}
};
#endif
gl_material.h
「gl_material.h」は、光源に対する光沢などの質感を定義しているインクルードファイルです。 本プログラムは「OpenGL(Akita National College of Technology Yamamoto's Laboratory )」で公開されています。
テキストエディタを起動し以下のソースをコピー&ペーストし、ファイル名を「gl_material.h」としてください。今後も利用するので、「gl_material.h」ファイルを「glut.h」と同じ場所におきます。
//--------------------------------------------------------
// 物質質感の定義
//--------------------------------------------------------
// 以下のページで公開されているソースを利用させていただきます。
// http://akita-nct.jp/yamamoto/comp/OpenGL/OpenGL.html
//--------------------------------------------------------
struct MaterialStruct {
GLfloat ambient[4];
GLfloat diffuse[4];
GLfloat specular[4];
GLfloat shininess;
};
//////////////////////////////////////////
//ruby(ルビー)
MaterialStruct ms_ruby = {
{0.1745, 0.01175, 0.01175, 1.0},
{0.61424, 0.04136, 0.04136, 1.0},
{0.727811, 0.626959, 0.626959, 1.0},
76.8};
//emerald(エメラルド)
MaterialStruct ms_emerald = {
{0.0215, 0.1745, 0.0215, 1.0},
{0.07568, 0.61424, 0.07568, 1.0},
{0.633, 0.727811, 0.633, 1.0},
76.8};
//jade(翡翠)
MaterialStruct ms_jade = {
{0.135, 0.2225, 0.1575, 1.0},
{0.54, 0.89, 0.63, 1.0},
{0.316228, 0.316228, 0.316228, 1.0},
12.8};
//obsidian(黒曜石)
MaterialStruct ms_obsidian = {
{0.05375, 0.05, 0.06625, 1.0},
{0.18275, 0.17, 0.22525, 1.0},
{0.332741,0.328634,0.346435,1.0},
38.4};
// pearl(真珠)
MaterialStruct ms_pearl = {
{0.25, 0.20725, 0.20725, 1.0},
{1, 0.829, 0.829, 1.0},
{0.296648, 0.296648, 0.296648, 1.0},
10.24};
//turquoise(トルコ石)
MaterialStruct ms_turquoise = {
{0.1, 0.18725, 0.1745, 1.0},
{0.396, 0.74151, 0.69102, 1.0},
{0.297254,0.30829, 0.306678,1.0},
12.8};
//brass(真鍮)
MaterialStruct ms_brass = {
{0.329412, 0.223529, 0.027451, 1.0},
{0.780392, 0.568627, 0.113725, 1.0},
{0.992157, 0.941176, 0.807843, 1.0},
27.89743616};
//bronze(青銅)
MaterialStruct ms_bronze = {
{0.2125, 0.1275, 0.054, 1.0},
{0.714, 0.4284, 0.18144, 1.0},
{0.393548, 0.271906, 0.166721,1.0},
25.6};
//chrome(クローム)
MaterialStruct ms_chrome = {
{0.25, 0.25, 0.25, 1.0},
{0.4, 0.4, 0.4, 1.0},
{0.774597,0.774597, 0.774597, 1.0},
76.8};
//copper(銅)
MaterialStruct ms_copper = {
{0.19125, 0.0735, 0.0225, 1.0},
{0.7038, 0.27048, 0.0828, 1.0},
{0.256777, 0.137622, 0.086014,1.0},
12.8};
//gold(金)
MaterialStruct ms_gold = {
{0.24725, 0.1995, 0.0745, 1.0},
{0.75164, 0.60648, 0.22648, 1.0},
{0.628281, 0.555802, 0.366065, 1.0},
51.2};
//silver(銀)
MaterialStruct ms_silver = {
{0.19225, 0.19225, 0.19225, 1.0},
{0.50754, 0.50754, 0.50754, 1.0},
{0.508273, 0.508273, 0.508273,1.0},
51.2};
//プラスチック(黒)
MaterialStruct ms_black_plastic = {
{0.0, 0.0, 0.0, 1.0},
{0.01, 0.01, 0.01, 1.0},
{0.50, 0.50, 0.50, 1.0},
32};
//プラスチック(シアン)
MaterialStruct ms_cyan_plastic = {
{0.0, 0.1, 0.06, 1.0},
{0.0, 0.50980392,0.50980392,1.0},
{0.50196078,0.50196078,0.50196078,1.0},
32};
//プラスチック(緑)
MaterialStruct ms_green_plastic = {
{0.0, 0.0, 0.0, 1.0},
{0.1, 0.35, 0.1, 1.0},
{0.45, 0.55, 0.45, 1.0},
32};
//プラスチック(赤)
MaterialStruct ms_red_plastic = {
{0.0, 0.0, 0.0, 1.0},
{0.5, 0.0, 0.0, 1.0},
{0.7, 0.6, 0.6, 1.0},
32};
//プラスチック(白)
MaterialStruct ms_white_plastic = {
{0.0, 0.0, 0.0, 1.0},
{0.55, 0.55, 0.55, 1.0},
{0.70, 0.70, 0.70, 1.0},
32};
//プラスチック(黄)
MaterialStruct ms_yellow_plastic = {
{0.0, 0.0, 0.0, 1.0},
{0.5, 0.5, 0.0, 1.0},
{0.60, 0.60, 0.50, 1.0},
32};
//ゴム(黒)
MaterialStruct ms_black_rubber = {
{0.02, 0.02, 0.02, 1.0},
{0.01, 0.01, 0.01, 1.0},
{0.4, 0.4, 0.4, 1.0},
10.0};
//ゴム(シアン)
MaterialStruct ms_cyan_rubber = {
{0.0, 0.05, 0.05, 1.0},
{0.4, 0.5, 0.5, 1.0},
{0.04, 0.7, 0.7, 1.0},
10.0};
//ゴム(緑)
MaterialStruct ms_green_rubber = {
{0.0, 0.05, 0.0, 1.0},
{0.4, 0.5, 0.4, 1.0},
{0.04, 0.7, 0.04, 1.0},
10.0};
//ゴム(赤)
MaterialStruct ms_red_rubber = {
{0.05, 0.0, 0.0, 1.0},
{0.5, 0.4, 0.4, 1.0},
{0.7, 0.04, 0.04, 1.0},
10.0};
//ゴム(白)
MaterialStruct ms_white_rubber = {
{0.05, 0.05, 0.05, 1.0},
{0.5, 0.5, 0.5, 1.0},
{0.7, 0.7, 0.7, 1.0},
10.0};
//ゴム(黄)
MaterialStruct ms_yellow_rubber = {
{0.05, 0.05, 0.0, 1.0},
{0.5, 0.5, 0.4, 1.0},
{0.7, 0.7, 0.04, 1.0},
10.0};
プログラムの説明
利用時に必要な部分だけを解説します。それ以外は必要に応じて行います。
アニメーション作成用ビットマップの保存
#define _BITMAP 1 // 0:しない 1:する
上記のパラメータで「1」を設定すると、ウィンドウ画面に描画された図を1フレームごとに保存します。 保存先は「(実行フォルダ)/bitmap/」で、「10000.bmp」から順番にファイル名をつけていきます。 その後、ビットマップデータを連続的につなげることでアニメーションを作成します。 (アニメーションの作り方は後日解説します)
#define _BITMAP 1 //アニメーション作成用ビットマップの保存 0:しない 1:する
上記のパラメータで「1」を設定すると、ウィンドウ画面に描画された図を1フレームごとに保存します。 保存先は「(実行フォルダ)/bitmap/」で、「10000.bmp」から順番にファイル名をつけていきます。 その後、ビットマップデータを連続的につなげることでアニメーションを作成します。 (アニメーションの作り方は後日解説します)
物体の描画
void DrawStructure(){
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT, ms_ruby.ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, ms_ruby.diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, ms_ruby.specular);
glMaterialfv(GL_FRONT, GL_SHININESS, &ms_ruby.shininess);
glTranslated(0.0, 0.0, 20.0); //平行移動値の設定
glutSolidCube(10.0); //引数:(一辺の長さ)
glPopMatrix();
}
この関数の中で描画した物体は、光源による光沢や影が描画されます。
VisualC++ と OpenGL を利用した仮想物理実験室
第0章 仮想物理実験室の構築
- 【0-1】OpenGL と Visual C++ 2008 Express Edition の準備
- 【0-2】仮想物理実験室の構築 ・(0-2-1)ver1.0:基本形 ・(0-2-1)ver1.1:基本形+ばねの描画 ・(0-2-2)ver1.2:基本形+ばねの描画
- 【0-3】グラフ作成ソフト gnuplot のインストールと使い方
- 【A-1】参考文献
・(A-1-1)OpenGL について
・(A-1-2)VisualC++ について
・(A-1-3)物理シミュレーション
・(A-1-4)数値計算
第1章 様々な運動
- 【1-1】等速度直線運動
- ・(1-1-1)物理量について
- ・(1-1-2)等速度直線運動のアルゴリズムの導出
- ・(1-1-3)等速度直線運動のシミュレーション
- ・(1-1-4)等速度直線運動のグラフ化
- ・(1-1-5)等差数列を用いた等速度直線運動の解析解の導出
- ・(1-1-6)等速度直線運動のシミュレーション結果と解析解との比較
- 【1-2】等加速度直線運動
- ・(1-2-1)等加速度直線運動のアルゴリズムの導出
- ・(1-2-2)等加速度直線運動のシミュレーション
- ・(1-2-3)等加速度直線運動のグラフ化
- ・(1-2-4)階差数列を用いた等加速度直線運動の解析解の導出
- ・(1-2-5)等加速度直線運動のシミュレーション結果と解析解との比較
- ・(1-2-6)差分と微分
- ・(1-2-7)和分と積分
- ・(1-2-8)微分・積分を利用した等加速度直線運動の解析解の導出
- 【1-3】等加加速度直線運動
- ・(1-3-1)等加加速度直線運動のアルゴリズムの導出
- ・(1-3-2)等加加速度直線運動のシミュレーション
- ・(1-3-3)等加加速度直線運動のグラフ化
- ・(1-3-4)等加加速度直線運動の解析解の導出
- ・(1-3-5)等速度直線運動のシミュレーション結果と解析解との比較
- 【1-4】等速度円運動
- ・(1-4-1)等速度円運動のアルゴリズムの導出
- ・(1-4-2)等速度円運動のシミュレーション
- ・(1-4-3)等速度円運動のグラフ化
- ・(1-4-4)等速度円運動の解析解の導出
- ・(1-4-5)等速度円運動のシミュレーション結果と解析解との比較
- 【1-5】等加速度円運動
- ・(1-5-1)等加速度円運動のアルゴリズムの導出
- ・(1-5-2)等加速度円運動のシミュレーション
- ・(1-5-3)等加速度円運動のグラフ化
- ・(1-5-4)等加速度円運動の解析解の導出
- ・(1-5-5)等加速度円運動のシミュレーション結果と解析解との比較
第2章 ニュートンの運動方程式
- 【2-1】重力による運動:自由落下運動
- ・(2-1-1)加速度・力・質量の関係:ニュートンの運動方程式
- ・(2-1-2)重力による運動のアルゴリズムの導出
- ・(2-1-3)重力による自由落下運動のシミュレーション
- ・(2-1-4)重力による自由落下運動のグラフ化
- ・(2-1-5)重力による自由落下運動の解析解の導出
- ・(2-1-6)重力による自由落下運動のシミュレーション結果と解析解との比較
- 【2-2】重力による運動:鉛直投射運動
- ・(2-2-1)重力による鉛直投射運動のシミュレーション
- ・(2-2-2)重力による鉛直投射運動のグラフ化
- ・(2-2-3)重力による鉛直投射運動の解析解
- ・(2-2-4)重力による鉛直投射運動のシミュレーション結果と解析解との比較
- 【2-3】重力による運動:水平投射運動
- ・(2-3-1)重力による水平投射運動のシミュレーション
- ・(2-3-2)重力による水平投射運動のグラフ化
- ・(2-3-3)重力による水平投射運動の解析解
- ・(2-3-4)重力による水平投射運動のシミュレーション結果と解析解との比較
- 【2-4】重力による運動:斜方投射運動
- ・(2-4-1)重力による斜方投射運動のシミュレーション
- ・(2-4-2)重力による斜方投射運動のグラフ化
- ・(2-4-2)重力による斜方投射運動の解析解
- ・(2-4-3)重力による斜方投射運動のシミュレーション結果と解析解との比較
- 【2-5】重力による運動:斜方投射運動2
- ・(2-5-1)重力による斜方投射運動における初速度の分解
- ・(2-5-2)重力による斜方投射運動2のシミュレーション
- ・(2-5-3)重力による斜方投射運動2のグラフ化
- ・(2-5-4)重力による斜方投射運動2の投射角度と飛距離の関係
- ・(2-5-5)重力による斜方投射運動2の解析解
- ・(2-5-6)重力による斜方投射運動2のシミュレーション結果と解析解との比較
- 【2-6】重力+空気抵抗力による運動:自由落下運動
- ・(2-6-1)重力+空気抵抗力による運動の運動方程式とアルゴリズム
- ・(2-6-2)重力+空気抵抗力による自由落下運動のシミュレーション
- ・(2-6-3)重力+空気抵抗力による自由落下運動の解析解の導出
- ・(2-6-4)重力+空気抵抗力による自由落下運動のシミュレーション結果と解析解との比較
- 【2-7】重力+空気抵抗力による運動:斜方投射運動
- ・(2-7-1)重力+空気抵抗力による斜方投射運動のシミュレーション
- ・(2-7-2)重力+空気抵抗力による斜方投射運動の解析解の導出
- ・(2-7-3)重力+空気抵抗力による斜方投射運動のシミュレーション結果と解析解との比較
- 【2-8】ばね弾性力による運動:単振動運動(1次元)
- ・(2-8-1)ばね弾性力による運動の運動方程式(1次元)とアルゴリズム
- ・(2-8-2)ばね弾性力による単振動運動(1次元)のシミュレーション
- ・(2-8-3)ばね弾性力による単振動運動(1次元)の解析解の導出
- ・(2-8-4)ばね弾性力による単振動運動(1次元)のシミュレーション結果と解析解との比較
- 【2-9】ばね弾性力による運動:単振動運動(2次元)
- ・(2-9-1)ばね弾性力による運動の運動方程式と(2次元)アルゴリズム
- ・(2-9-2)ばね弾性力による単振動運動(2次元)のシミュレーション
- ・(2-9-3)ばね弾性力による単振動運動(2次元)の解析解:微分・積分を利用した解析解の導出
- ・(2-9-4)ばね弾性力による単振動運動(2次元)のシミュレーション結果と解析解との比較
- 【2-10】ばね弾性力+重力がある場合の運動:単振動運動(3次元)
- ・(2-10-1)ばね弾性力+重力による運動の運動方程式(3次元)とアルゴリズム
- ・(2-10-2)ばね弾性力+重力による単振動運動(3次元)のシミュレーション
- ・(2-10-3)ばね弾性力+重力による単振動運動(3次元)の解析解の導出
- ・(2-10-4)ばね弾性力+重力による単振動運動(3次元)のシミュレーション結果と解析解との比較
- 【2-11】ばね弾性力+重力がある場合の運動:多重連結ばねの運動
- ・(2-11-1)ばね弾性力の一般化
- ・(2-11-2)ばね弾性力+重力による多重連結ばねの運動の運動方程式
- ・(2-11-3)ばね弾性力+重力による多重連結ばねの運動のアルゴリズムの導出
- ・(2-11-4)ばね弾性力+重力による多重連結ばねの運動のシミュレーション
- 【2-12】ばね弾性力+遠心力がある場合の運動:円運動
- ・(2-12-1)遠心力の導出
- ・(2-12-2)遠心力+ばね弾性力による運動の運動方程式
- ・(2-12-3)遠心力+ばね弾性力による運動のアルゴリズムの導出
- ・(2-12-4)遠心力+ばね弾性力による運動のシミュレーション
- 【2-13】張力+重力がある場合の運動:単振子運動.html
- ・(2-13-1)張力の導出
- ・(2-13-2)張力+重力による多重連結ばねの運動の運動方程式
- ・(2-13-3)張力による多重連結ばねの運動のアルゴリズムの導出
- ・(2-13-4)張力による多重連結ばねの運動のシミュレーション
- 【2-14】万有引力による運動1:楕円運動
- ・(2-14-1)万有引力の導出
- ・(2-14-2)万有引力による運動の運動方程式
- ・(2-14-3)万有引力による運動のアルゴリズムの導出
- ・(2-14-4)初速度と軌道の関係
- ・(2-14-5)万有引力による運動のシミュレーション
- 【2-15】万有引力による運動2:円運動
- ・(2-15-1)万有引力による運動が円運動になるための条件
- ・(2-15-2)初速度の与え方
- ・(2-15-3)万有引力による円運動のシミュレーション
- 【2-16】万有引力による運動3:3体運動
- ・(2-16-1)3体運動とは
- ・(2-16-2)万有引力による3体運動の運動方程式
- ・(2-16-3)万有引力による3体運動のアルゴリズムの導出
- ・(2-16-3)万有引力による3体運動のシミュレーション
第3章 剛体の運動(エネルギー保存則と運動量保存則)
- 【3-1】床と球の衝突
- 【3-2】壁と球の衝突
- 【3-3】円柱と球の衝突(1次元)
- 【3-4】円柱と球の衝突(2次元 x-y平面)
- 【3-4-2】円柱と球の衝突(2次元 x-z平面)
- 【3-5】球と球の衝突(1次元)
- 【3-6】球と球の衝突(2次元)
- 【3-7】球と球の衝突(3次元)
付録
- 【A-1】参考文献
・(A-1-1)OpenGL について
・(A-1-2)VisualC++ について
・(A-1-3)物理シミュレーション
・(A-1-4)数値計算
未分類
力学
- ・ 2体問題のシミュレーション(C言語+ルンゲクッタ法)
- ・ ラグランジュ未定乗数法を用いた2重振子のシミュレーション
- ・ ラグランジュ未定乗数法を用いた球面振子のシミュレーション
- ・ ラグランジュ運動方程式2:極座標を用いた球面振子
- ・ ラグランジュ運動方程式1:極座標を用いた単振子
量子力学
- ・ 1次元量子力学の調和振動子における単一エネルギーの時間発展
- ・ 1次元量子力学の調和振動子における任意の初期状態に対する時間発展
- ・ 1次元量子力学の調和振動子におけるコヒーレント状態の空間分布
- ・ 1次元量子力学の調和振動子におけるコヒーレント状態の時間発展
- ・ 1次元量子力学の調和振動子における n励起状態の運動量表示
- ・ 1次元量子力学の調和振動子における任意の初期運動量分布に対する時間発展
- ・ 1次元量子力学の調和振動子における任意の初期運動量分布+任意の中心座標に対する時間発展
- ・ 1次元量子力学の調和振動子における任意の初期空間分布+任意の中心運動量に対する時間発展(最も簡単な方法)
- ・ 無限に深い2次元井戸型ポテンシャル
- ・ 無限に深い2次元井戸型ポテンシャル2
- ・ 無限に深い2次元井戸型ポテンシャル3
- ・ 無限に深い2次元井戸型ポテンシャル
- ・ 2次元自由粒子
- ・ 無限に深い井戸型ポテンシャルの時間発展2
- ・ シュレディンガー方程式に従う粒子の時間発展2:無限に深い井戸型ポテンシャルの時間発展
- ・ シュレディンガー方程式に従う粒子の時間発展:自由粒子
波動論
- ・ google API を用いてルジャンドル陪関数を描画する
- ・ ルジャンドル陪関数の漸化式と規格化
- ・ 任意の関数をエルミート多項式で展開する
- ・ エルミート多項式の規格化
- ・ エルミート多項式の直交性を確かめる
- ・ 太鼓の振動の固有振動(第1種ベッセル関数)
- ・ 任意の周期関数をフーリエ変換+逆フーリエ変換する
- ・ ステップ関数のフーリエ級数展開
- ・ デルタ関数の定義
- ・ フーリエ級数展開2:f=x^2
- ・ フーリエ級数1:f=x
- ・ 波動方程式のテスト
【目次】 (VisualC++ を使った OpenGL 入門)
- 【参考文献リスト】
- ■ 【0日目】はじめに ・ (0.1日目)OpenGL と Visual C++ 2008 Express Edition の準備
- ■ 【1日目】 世界の始まり ・(1.1日目)OpenGL の基本形
- ■ 【2日目】 地平線 ・ (2.1日目)視点の設定
- ■ 【3日目】 創造物
- ■ 【4日目】 光源
- ■ 【5日目】 視点
- ■ 【6日目】 記憶
- ■ 【7日目】 キーボード入力
- ■ 【8日目】 影
- ■ 【9日目】 文字
- ■ 【10日目】 回転
未分類
- ・ Windows7 OpenGL freeglut のインストール
- ・ OpenGLで霧を表現
- ・ 光源のパラメータ設定1
- ・ 光源のパラメータ設定2
- ・ 光源のパラメータ設定3
- ・ 平面に光をあてるときの注意点
- ・ 波動方程式のテスト
- ・ OpenGLで霧を表現
- ・ OpenGLのカラーサンプル(teapots.c)
- ・ 直方体を回転させよう!




