Post date: Feb 12, 2013 12:38:00 AM
立体視をするには右目用と左目用の映像を準備する必要が出てきてしまう。
また、3D映像を作るにはいくつかの方法があるみたいで、今回は画面右半分を右目用、左半分を左目用とする、
サイド・バイ・サイド方式を使うことにする。また、その方式に対応したヘッドマウントディスプレイ(Wrap920)を使用した。
まず、右目と左目で、見ている方向は同じ(並行)だと考えると、違う点は横の移動量のみ(x軸平行移動)となる。
そこで、1つのウインドウで2つの三次元座標系を作るために透視投影を使った3次元を自分で2つ実装することにした。
DualPanel3d a;
float angle;
int x,y,z;
void setup(){
size(screen.width,screen.height);
a=new DualPanel3d(width,height);
}
void draw(){
background(255);
//scale(width/640,height,480);
int r=20/2;
a.reset();
a.translate(x,y,z+100);
a.rotateY(angle);
a.box(100);
//a.sphere(100);
angle+=0.01;
if(keyPressed){
if(keyCode==UP)y--;
if(keyCode==DOWN)y++;
if(keyCode==LEFT)x--;
if(keyCode==RIGHT)x++;
if(key=='e')z--;
if(key=='r')z++;
}
}
class DualPanel3d{
P3 left,right;
float r;//目の間
DualPanel3d(float x,float y){
left=new P3(0,0,x/2,y);
right=new P3(x/2,0,x/2,y);
r=20/2;
}
void reset(){
left.reset();
right.reset();
left.translate(r,0,0);
right.translate(-r,0,0);
}
void line(float x1,float y1,float z1,float x2,float y2,float z2){
left.line3D(x1,y1,z1,x2,y2,z2);
right.line3D(x1,y1,z1,x2,y2,z2);
}
void box(int r){
left.box(r);
right.box(r);
}
void sphere(int r){
left.sphere(r);
right.sphere(r);
}
void translate(float x,float y,float z){
left.translate(x,y,z);
right.translate(x,y,z);
}
void rotateX(float x){
left.rotateX(x);
right.rotateX(x);
}
void rotateY(float y){
left.rotateY(y);
right.rotateY(y);
}
void rotateZ(float z){
left.rotateZ(z);
right.rotateZ(z);
}
}
class P3{
float width,height;
private float P3x,P3y;
private float tan;
private int z0;
private float mat[][]=new float[4][4];
P3(float P3x,float P3y,float width,float height){
this.width=width;
this.height=height;
this.P3x=P3x;
this.P3y=P3y;
tan=tan(PI/3);
z0=100;
mat[0][0]=1;mat[0][1]=0;mat[0][2]=0;mat[0][3]=0;
mat[1][0]=0;mat[1][1]=1;mat[1][2]=0;mat[1][3]=0;
mat[2][0]=0;mat[2][1]=0;mat[2][2]=1;mat[2][3]=0;
mat[3][0]=0;mat[3][1]=0;mat[3][2]=0;mat[3][3]=1;
}
void reset(){
mat[0][0]=1;mat[0][1]=0;mat[0][2]=0;mat[0][3]=0;
mat[1][0]=0;mat[1][1]=1;mat[1][2]=0;mat[1][3]=0;
mat[2][0]=0;mat[2][1]=0;mat[2][2]=1;mat[2][3]=0;
mat[3][0]=0;mat[3][1]=0;mat[3][2]=0;mat[3][3]=1;
}
void line2(float x1,float y1,float x2,float y2){
if(x1==x2){
for(int i=(int)max(min(y1,y2),P3y);i<=(int)min(max(y2,y1),height+P3y);i++)if(x1>=P3x&&x1<=P3x+width)point(x1,i);
}else if (abs((y1-y2)/(x1-x2))<=1){
for(int i=(int)max(min(x1,x2),P3x);i<=(int)min(max(x2,x1),P3x+width);i++)if((y2-y1)*(i-x1)/(x2-x1)+y1>=P3y&&(y2-y1)*(i-x1)/(x2-x1)+y1<=P3y+height)point(i,(y2-y1)*(i-x1)/(x2-x1)+y1);
}else{
for(int i=(int)max(min(y1,y2),P3y);i<=(int)min(max(y2,y1),P3y+height);i++)if((x2-x1)*(i-y1)/(y2-y1)+x1>=P3x&&(x2-x1)*(i-y1)/(y2-y1)+x1<=P3x+width)point((x2-x1)*(i-y1)/(y2-y1)+x1,i);
}
}
void line3D(float x1,float y1,float z1,float x2,float y2,float z2){
float tr[][]=new float[2][3];
tr[0]=trans(x1,y1,z1);
tr[1]=trans(x2,y2,z2);
float mom1=(float)(z0+tr[0][2])*tan;
float mom2=(float)(z0+tr[1][2])*tan;
if(mom1<=0||mom2<=0)return;
float x3=width*2*tr[0][0]/mom1;
float y3=width*2*tr[0][1]/mom1;
float x4=width*2*tr[1][0]/mom2;
float y4=width*2*tr[1][1]/mom2;
line2(x3+width/2+P3x,y3+height/2+P3y,x4+width/2+P3x,y4+height/2+P3y);
}
void box(int r){
line3D(r/2.0,r/2.0,r/2.0,-r/2.0,r/2.0,r/2.0);
line3D(r/2.0,-r/2.0,r/2.0,-r/2.0,-r/2.0,r/2.0);
line3D(r/2.0,r/2.0,-r/2.0,-r/2.0,r/2.0,-r/2.0);
line3D(r/2.0,-r/2.0,-r/2.0,-r/2.0,-r/2.0,-r/2.0);
line3D(r/2.0,r/2.0,r/2.0,r/2.0,-r/2.0,r/2.0);
line3D(-r/2.0,r/2.0,r/2.0,-r/2.0,-r/2.0,r/2.0);
line3D(r/2.0,r/2.0,-r/2.0,r/2.0,-r/2.0,-r/2.0);
line3D(-r/2.0,r/2.0,-r/2.0,-r/2.0,-r/2.0,-r/2.0);
line3D(r/2.0,r/2.0,r/2.0,r/2.0,r/2.0,-r/2.0);
line3D(-r/2.0,r/2.0,r/2.0,-r/2.0,r/2.0,-r/2.0);
line3D(r/2.0,-r/2.0,r/2.0,r/2.0,-r/2.0,-r/2.0);
line3D(-r/2.0,-r/2.0,r/2.0,-r/2.0,-r/2.0,-r/2.0);
}
void sphere(float r){
int n=10;
float s=PI/n;
float s2=s*2;
//pushMatrix();
//translate(x,y,z);
//beginShape(TRIANGLE_STRIP);
for(int i=0;i<n;i++){
//vertex(0,r,0);
line3D(0,r,0,r*sin(s)*cos(s2*i),r*cos(s),r*sin(s)*sin(s2*i));
line3D(r*sin(s)*cos(s2*i),r*cos(s),r*sin(s)*sin(s2*i)
,r*sin(s)*cos(s2*(i+1)),r*cos(s),r*sin(s)*sin(s2*(i+1)));
/*line3D(r*sin(s)*cos(s2*(i+1)),r*cos(s),r*sin(s)*sin(s2*(i+1)),0,r,0);*/
}
//endShape(CLOSE);
for(int i=1;i<=n-2;i++){
//vertex(r*sin(s*i),r*cos(s*i),0);
for(int j=0;j<n;j++){
//beginShape(QUADS);
line3D(r*sin(s*(i+1))*cos(s2*j),r*cos(s*(i+1)),r*sin(s*(i+1))*sin(s2*j),
r*sin(s*(i+1))*cos(s2*(j+1)),r*cos(s*(i+1)),r*sin(s*(i+1))*sin(s2*(j+1)));
line3D(r*sin(s*(i+1))*cos(s2*(j+1)),r*cos(s*(i+1)),r*sin(s*(i+1))*sin(s2*(j+1)),
r*sin(s*i)*cos(s2*(j+1)),r*cos(s*i),r*sin(s*i)*sin(s2*(j+1)));
/*line3D(r*sin(s*i)*cos(s2*(j+1)),r*cos(s*i),r*sin(s*i)*sin(s2*(j+1)),
r*sin(s*i)*cos(s2*j),r*cos(s*i),r*sin(s*i)*sin(s2*j));*/
/*line3D(r*sin(s*i)*cos(s2*j),r*cos(s*i),r*sin(s*i)*sin(s2*j),
r*sin(s*(i+1))*cos(s2*j),r*cos(s*(i+1)),r*sin(s*(i+1))*sin(s2*j));*/
}
}
//beginShape(TRIANGLE_STRIP);
for(int i=0;i<n;i++){
line3D(0,-r,0,r*sin(s)*cos(s2*i),-r*cos(s),r*sin(s)*sin(s2*i));
line3D(r*sin(s)*cos(s2*i),-r*cos(s),r*sin(s)*sin(s2*i),
r*sin(s)*cos(s2*(i+1)),-r*cos(s),r*sin(s)*sin(s2*(i+1)));
/*line3D(r*sin(s)*cos(s2*(i+1)),-r*cos(s),r*sin(s)*sin(s2*(i+1)),0,-r,0);*/
}
//endShape(CLOSE);
//popMatrix();
}
private float[] trans(float x,float y,float z){
float tmp[]=new float[3];
tmp[0]=mat[0][0]*x+mat[0][1]*y+mat[0][2]*z+mat[0][3];
tmp[1]=mat[1][0]*x+mat[1][1]*y+mat[1][2]*z+mat[1][3];
tmp[2]=mat[2][0]*x+mat[2][1]*y+mat[2][2]*z+mat[2][3];
return tmp;
}
private void mul(float m00,float m01,float m02,float m03,
float m10,float m11,float m12,float m13,
float m20,float m21,float m22,float m23,
float m30,float m31,float m32,float m33){
float tmp[][]=new float[4][4];
/*
tmp[0][0]=m00*mat[0][0]+m01*mat[1][0]+m02*mat[2][0]+m03*mat[3][0];
tmp[0][1]=m00*mat[0][1]+m01*mat[1][1]+m02*mat[2][1]+m03*mat[3][1];
tmp[0][2]=m00*mat[0][2]+m01*mat[1][2]+m02*mat[2][2]+m03*mat[3][2];
tmp[0][3]=m00*mat[0][3]+m01*mat[1][3]+m02*mat[2][3]+m03*mat[3][3];
tmp[1][0]=m10*mat[0][0]+m11*mat[1][0]+m12*mat[2][0]+m13*mat[3][0];
tmp[1][1]=m10*mat[0][1]+m11*mat[1][1]+m12*mat[2][1]+m13*mat[3][1];
tmp[1][2]=m10*mat[0][2]+m11*mat[1][2]+m12*mat[2][2]+m13*mat[3][2];
tmp[1][3]=m10*mat[0][3]+m11*mat[1][3]+m12*mat[2][3]+m13*mat[3][3];
tmp[2][0]=m20*mat[0][0]+m21*mat[1][0]+m22*mat[2][0]+m23*mat[3][0];
tmp[2][1]=m20*mat[0][1]+m21*mat[1][1]+m22*mat[2][1]+m23*mat[3][1];
tmp[2][2]=m20*mat[0][2]+m21*mat[1][2]+m22*mat[2][2]+m23*mat[3][2];
tmp[2][3]=m20*mat[0][3]+m21*mat[1][3]+m22*mat[2][3]+m23*mat[3][3];
tmp[3][0]=m30*mat[0][0]+m31*mat[1][0]+m32*mat[2][0]+m33*mat[3][0];
tmp[3][1]=m30*mat[0][1]+m31*mat[1][1]+m32*mat[2][1]+m33*mat[3][1];
tmp[3][2]=m30*mat[0][2]+m31*mat[1][2]+m32*mat[2][2]+m33*mat[3][2];
tmp[3][3]=m30*mat[0][3]+m31*mat[1][3]+m32*mat[2][3]+m33*mat[3][3];
*/
tmp[0][0]=m00*mat[0][0]+m10*mat[0][1]+m20*mat[0][2]+m30*mat[0][3];
tmp[0][1]=m01*mat[0][0]+m11*mat[0][1]+m21*mat[0][2]+m31*mat[0][3];
tmp[0][2]=m02*mat[0][0]+m12*mat[0][1]+m22*mat[0][2]+m32*mat[0][3];
tmp[0][3]=m03*mat[0][0]+m13*mat[0][1]+m23*mat[0][2]+m33*mat[0][3];
tmp[1][0]=m00*mat[1][0]+m10*mat[1][1]+m20*mat[1][2]+m30*mat[1][3];
tmp[1][1]=m01*mat[1][0]+m11*mat[1][1]+m21*mat[1][2]+m31*mat[1][3];
tmp[1][2]=m02*mat[1][0]+m12*mat[1][1]+m22*mat[1][2]+m32*mat[1][3];
tmp[1][3]=m03*mat[1][0]+m13*mat[1][1]+m23*mat[1][2]+m33*mat[1][3];
tmp[2][0]=m00*mat[2][0]+m10*mat[2][1]+m20*mat[2][2]+m30*mat[2][3];
tmp[2][1]=m01*mat[2][0]+m11*mat[2][1]+m21*mat[2][2]+m31*mat[2][3];
tmp[2][2]=m02*mat[2][0]+m12*mat[2][1]+m22*mat[2][2]+m32*mat[2][3];
tmp[2][3]=m03*mat[2][0]+m13*mat[2][1]+m23*mat[2][2]+m33*mat[2][3];
tmp[3][0]=m00*mat[3][0]+m10*mat[3][1]+m20*mat[3][2]+m30*mat[3][3];
tmp[3][1]=m01*mat[3][0]+m11*mat[3][1]+m21*mat[3][2]+m31*mat[3][3];
tmp[3][2]=m02*mat[3][0]+m12*mat[3][1]+m22*mat[3][2]+m32*mat[3][3];
tmp[3][3]=m03*mat[3][0]+m13*mat[3][1]+m23*mat[3][2]+m33*mat[3][3];
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
mat[i][j]=tmp[i][j];
}
void translate(float x,float y,float z){
mul(1,0,0,x,
0,1,0,y,
0,0,1,z,
0,0,0,1);
}
void rotateX(float r){
mul(1, 0, 0,0,
0,cos(r),-sin(r),0,
0,sin(r), cos(r),0,
0, 0, 0,1);
}
void rotateY(float r){
mul( cos(r),0,sin(r),0,
0,1, 0,0,
-sin(r),0,cos(r),0,
0,0, 0,1);
}
void rotateZ(float r){
mul(cos(r),-sin(r),0,0,
sin(r), cos(r),0,0,
0, 0,0,0,
0, 0,0,1);
}
void scale(float x,float y,float z){
mul(x,0,0,0,
0,y,0,0,
0,0,z,0,
0,0,0,1);
}
}
P3クラスが任意の場所・大きさに3次元空間を作るクラスである。座標変換にも対応している。DualPanelクラスが2個インスタンス(右目用と左目用)
を作ることによって立体視を可能としている。