光の屈折とその軌道を描くプログラムについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
g7

光の屈折とその軌道を描くプログラムについて

#1

投稿記事 by g7 » 14年前

初めまして、g7と申します。いつも楽しく拝見させていただいています。
今回どうしても分からないことがあり、質問させていただこうと思っています。

光の屈折とその軌道を描くC言語のプログラムについてです。
三角プリズムに白色光を入射させ、最終的に波長によって軌道が異なる光の軌跡が確認できるといった内容です。

具体的には、
http://www.osaka-c.ed.jp/ed/h19/multi01/hikariFF.html
こちらのサイトに載っているような(まったく同じシチュエーションで考えてます)、正三角プリズムに光を入射させたときの屈折及び分光の実装方法で行き詰まっています。
描画にはOpenGLを用いていますが、根本的な処理の部分が知りたいと思っています。

一応、無理やり実装したプログラムはできているのですが…
真横から入射させたときに、二回の屈折を経て分光するといったさどうを実現できています。
条件を変えると動かなくなる汎用性のないものなので、個人的に論外。(これでは到底満足できません^^;)

入射角や屈折率を変えても動くちゃんとした実装を行う際の考え方、具体的なコードまたはヒントでも構いません、皆さんの知恵を貸してください。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: 光の屈折とその軌道を描くプログラムについて

#2

投稿記事 by h2so5 » 14年前

どこまで出来ているのか分からないので
まず、実装したプログラムを見せてください。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 光の屈折とその軌道を描くプログラムについて

#3

投稿記事 by softya(ソフト屋) » 14年前

まじめな式だと、こんな感じでしょうか。
http://ja.wikipedia.org/wiki/%E3%82%B9% ... 5%E5%89%87
全波長を満遍なくやるのは事実上不可能なので、絵的な表現の都合で端折る必要はあると思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

g7

Re: 光の屈折とその軌道を描くプログラムについて

#4

投稿記事 by g7 » 14年前

返信ありがとうございます。

>h2so5さん

今現在のソースを示していませんでした。申し訳ありません。
実は、ものすごく頭の悪い強引な実装で晒したくないのですがとりあえずそれらしい経路は辿れています。
分岐や進行角度の更新はプリズム内の反射はなく、完全に2回の屈折のみで終わると仮定して進めています。
「実装方法はともかく、画面でみれば光の経路らしい」を実現している程度ですので参考にならないかもしれません・・・。

具体的な角度の計算式はこちらを参考にしました。
http://www.cvimgkk.com/products/cvi/cvi ... guide.html

全ソースコードです。

コード:

#include <math.h>
#include <GL/glut.h>
#include <GL/gl.h>

//ウインドウサイズ
#define WIN_W 400
#define WIN_H 400

//三角形の三点の座標
#define TRI_TX 0.0
#define TRI_TY (-0.8 + sin(M_PI/3)*0.6)
#define TRI_LX -0.3
#define TRI_LY -0.8
#define TRI_RX 0.3
#define TRI_RY -0.8

//光源の初期位置
#define START_X -1.0
#define START_Y -0.5

//プリズムの絶対屈折率
#define N 1.5

//光のパラメータ
float ray_x = START_X;
float ray_y = START_Y;
float angle = 0.0;
int way = 0;

void DrawField(void){
	glColor3f(0.7, 0.7, 0.7);
	glPointSize(1.0);

	glBegin(GL_LINES);
		glVertex2f(-1.0, -0.8);
		glVertex2f(1.0, -0.8);
	glEnd();
	
	glColor3f(0.5, 0.5, 0.5);
	
	glBegin( GL_POLYGON );
		glVertex3f(-1.0, -0.8, 0.0);
		glVertex3f(-1.0,-1.0, 0.0);
		glVertex3f( 1.0,-1.0, 0.0);
		glVertex3f( 1.0, -0.8, 0.0);
	glEnd();
	
	glColor3f(1.0, 1.0, 1.0);
	glBegin( GL_POLYGON );
		glVertex2f(TRI_TX, TRI_TY);
		glVertex2f(TRI_LX, TRI_LY);
		glVertex2f(TRI_RX, TRI_RY);
	glEnd();
}

void DrawPoint(void){
	glColor3f(0.7, 0.7, 0.7);
	glPointSize(4.0);

	glBegin(GL_POINTS);
		glVertex2f(ray_x, ray_y);
	glEnd();
}

void Reshape(GLsizei w, GLsizei h){
	// 画面の大きさを変更する
	glutReshapeWindow(WIN_W,WIN_H);
}

void MyIdle(void){
	//光が地面についたらそれ以上進まない
	if(ray_y<=-0.8)
		return;
		
	//光のx,y座標。x座標は0.001ずつ増える。
	ray_x += 0.001;
	ray_y += tan(angle)*0.001;
	
	//異なる媒質へ進むときの屈折 空気→プリズム
	if(ray_y <= (float)(((TRI_TY-TRI_LY)/(TRI_TX-TRI_LX))*(ray_x-TRI_TX)+TRI_TY) && way == 0){
		angle = -M_PI/6 + asin(sin(M_PI/6)/N);
		way = 1;
	}
	
	//異なる媒質へ進むときの屈折 プリズム→空気
	if(ray_y >= (float)(((TRI_TY-TRI_RY)/(TRI_TX-TRI_RX))*(ray_x-TRI_TX)+TRI_TY) && way == 1){
		angle += N*sin(M_PI/3-asin(sin(M_PI/6)/N)) - asin(N*sin(M_PI/3-asin(sin(M_PI/6)/N)));
		way = 2;
	}
		
	glutPostRedisplay();
}

void RenderScene(void){
	glClear(GL_COLOR_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	DrawField();
	DrawPoint();

	glutSwapBuffers();
}

int main( int argc, char** argv ){
	//初期化
	glutInit( &argc, argv );
	
	//ディスプレイの設定
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(WIN_W,WIN_H);
	
	//ウインドウを開く
	glutCreateWindow("Prism");
	
	//描写に関する関数の定義
	glutReshapeFunc(Reshape);
	glutDisplayFunc(RenderScene);
	glutIdleFunc(MyIdle);

	glClearColor(0.0, 0.0, 0.0, 1.0);

	glutMainLoop();
}

>softyaさん
ありがとうございます。
いい忘れていました。屈折の公式は把握できています。

しかしプリズムを含んだ屈折、反射に関する処理の一般化で苦戦しております。。

不明な点は
・光の現在の座標の更新方法は、いまのままでよいのか。
・光の進む角度の更新は、どのように行えばいいのか。何を基準(0度)にするとわかりやすいのか。
・軌跡の描きかた。(画面クリアをせず、描画された点を残しておく方法はありますか。)


不明な点ばかりですみません。厚かましいようですがお力を貸してください。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: 光の屈折とその軌道を描くプログラムについて

#5

投稿記事 by h2so5 » 14年前

別にg7さんの方法でも構わないかもしれませんが、
私はこのようなアルゴリズムはあまり好きではありません。

ray_x += 0.001; を何度も実行してチマチマ進める力押しの方法よりも、
例えば光線とプリズムの辺の交点を連立方程式を解いて求める数学的なやりかたが、
ずっとスマートだと思います。

アニメーションがしたいのであれば、最初に屈折点を全て求めてしまい、
あとでアニメーションをすれば良いのではないでしょうか。

g7

Re: 光の屈折とその軌道を描くプログラムについて

#6

投稿記事 by g7 » 14年前

>h2so5さん
助言ありがとうございます。
いくらなんでも今のままではスッキリしないので再実装してみます。
計算終了後に描画の方がシンプルでスマートですね、こちらも試してみます。



実はこれは提出する課題なのですが、
厳密な物理計算よりOpenGLを用いることに意味のある課題だったので今の時点で正しい軌跡が描けていれば大丈夫そうです。(多分)
しかし、引き続き屈折角に関する強引な算出方法以外の実装も考えてみます。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 光の屈折とその軌道を描くプログラムについて

#7

投稿記事 by softya(ソフト屋) » 14年前

プリズムでの屈折を考えたら線分の交差の交点を求めることと
http://www.hiramine.com/programming/gra ... ction.html
線分の角度
http://www.h4.dion.ne.jp/~zero1341/t/04.htm
が分かれば良いので、これを光の周波数パターン分(有限個数の適当な値)で計算して配列に格納すれば、あとで表示はどうにでもなる気がします。

[補足]
片方の線分がプリズムの辺で、もう一つの線分が光です。
で、交点で屈折したら、そこからの光は新たな線分として計算します。
これを繰り返せば、光の線分が屈折回数分手に入ります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

g7

Re: 光の屈折とその軌道を描くプログラムについて

#8

投稿記事 by g7 » 14年前

>softyaさん
助言とリンク、ありがとうございます。
リンク先で紹介されていた方法を組み合わせて、やっと実装方法が見えてきました。
周波数パターンは7個ほど、代表的な周波数を定めてあらかじめ屈折率を求めることで、問題を簡単にしています。

皆さんのおかげでソースの書き方の助言や、屈折に関する根本の考え方が聞けましたから、あとは自力で実装することとして「解決」としておきます。


同じような疑問がある方へ
・軌跡のシミュレーションは少しづつ進めてリアルタイムに処理をする必要はない→すべて計算してからの方がシンプル。
・上記URLのとおり、角度と交点の求め方を参照。屈折角は物理の公式より(スネルの公式?)
・光は直線的に進むため、最終的な描画は屈折ポイントを折れ線状にで辿っていくようにすればよい。

今回、このあたりが新たに分かったことです。
参考にしてみてください。


ソースの方は私が納得のいくように書けたらまたここに貼り付けて置こうと思います。
ありがとうございました!

閉鎖

“C言語何でも質問掲示板” へ戻る