// ■立体の演算 // // 【図形A,Bの演算】 // // 演算の種類   表記  描く部分(Aの表面) 描く部分(Bの表面) // ------------------------------------------------------------- // 和(合体)  A ∪ B Bの外部(!in(B)) Aの外部(!in(A)) // 積(共通)  A ∩ B Bの内部( in(B)) Aの内部( in(A)) // 差(カット) A − B Bの外部(!in(B)) Aの内部( in(A)) // // 描く部分がA, B 共通にある場合、視点に近いほうを描く。 // #include "myWin.h" #include "my3Dmat.h" #include "stdio.h" #include "stdlib.h" #include "locale.h" #define LWIDTH 4 //線幅 #define AWIDTH 2 //軸の線幅 // ラベル #define LB_1 1001 // 方位角 #define LB_2 1002 // 仰角 #define LB_3 1003 // 距離 // エディットボックス #define ED_1 2001 // 方位角 #define ED_2 2002 // 仰角 #define ED_3 2003 // 距離 // ボタン #define BT_1 3001 // ボタン1 #define BT_2 3002 // ボタン2 #define BT_3 3003 // ボタン3 // カラー分離 #define RED(C) ( C & 0xFF) #define GREEN(C) ((C>>8) & 0xFF) #define BLUE(C) ((C>>16) & 0xFF) static HWND bt1, bt2, bt3; // 実行指定用ボタン static HWND editA, editB, editC;//変換用係数を指定するエディットボックス static HDC hbuf; static HBITMAP hBM;//ビットマップ描画用 // 立体表示用 Point org, v0;//原点、視点位置 TMatrix t, it;//変換マトリックス double dv;//Z方向にずらす量 double size_x, size_y;//表示画面サイズ double diffuse; //拡散反射係数 double specular;//鏡面反射係数 double ambient; //環境光 void clearBitmap(){//ビットマップクリア SelectObject(hbuf,GetStockObject(NULL_PEN)); PatBlt(hbuf,0,0,2000,1000,WHITENESS); } void setView(double a,double e, double d){ // 角度による方向設定 Point P1=setPoint(0,0,1); TMatrix PP=perspect(d), RX=rot_x(e-90), RZ=rot_z(-90-a); t=mlt(mlt(perspect(d),rot_x(e-90)),rot_z(-90-a)); v0=mlt(mlt(rot_z(90+a),rot_x(90-e)),mlt(P1,d)); } void setview(Point p){//視点位置による方向設定 Point P1=setPoint(0,0,1); dv=len(p); Point wa=unit(p); v0=p; if((wa.X==0) &&(wa.Y==0)){ t=perspect(dv);return;} double wd=sqrt(wa.X*wa.X+wa.Y*wa.Y); t=mlt(mlt(perspect(dv),rot_x(-wd,wa.Z)),rot_z(-wa.X/wd,-wa.Y/wd)); it=mlt(rot_z(wa.X/wd,-wa.Y/wd),rot_x(wd,wa.Z)); } Point screen(Point p){//スクリーン座標系への変換 Point a=mlt(t,p); double s=(t.mat[3][0]*p.X+t.mat[3][1]*p.Y+t.mat[3][2]*p.Z+t.mat[3][3]); return setPoint(org.X+a.X/s,org.Y-a.Y/s,a.Z); } Point world(Point p){ //View座標をWorld座標に変換 double sz=-p.Z/dv; return mlt(it,(setPoint((p.X-org.X)*sz,(-p.Y+org.Y)*sz,p.Z+dv))); } void init2D(int x, int y){//描画初期設定 size_x=x; size_y=y; org.X=size_x/2-0.5; org.Y=size_y/2-1.5; org.Z=0; setView(30,30,1000); } void origin(int x, int y){ org = setPoint(x+0.5F , y-0.5F,0); } //--------------------------------------------------------------------- //■Ray Tracing法による立体描画 // 以下の係数を用いる //  diffuse:拡散反射係数, specular: 鏡面反射係数, ambient: 環境光 // int shading(Point V, Point L, Point N, int CU){ double kd=diffuse, ks=specular, ke=ambient, D1, D2; Point RV=sub(L,mlt(2,mlt(mlt(L,N),N))); //反射方向ベクトル D1=(mlt(minus(N),L))/(len(N)*len(L)); if(D1<0)D1=0; // 拡散および環境光 D1=kd*D1+ke; D2=ks*(mlt(minus(RV),V))/(len(RV)*len(V)); if( D2 < 0)D2 = 0; int R=(int)(D1*(double)(RED (CU))+D2*255);if(R>255)R=255; int G=(int)(D1*(double)(GREEN(CU))+D2*255);if(G>255)G=255; int B=(int)(D1*(double)(BLUE (CU))+D2*255);if(B>255)B=255; return RGB(R,G,B); } int mix(int C1,double d1, int C2,double d2){// C1とC2をd1:d2で混ぜる int R=(int)(d1*(double)(RED (C1))+d2*(double)(RED (C2)));if(R>255)R=255; int G=(int)(d1*(double)(GREEN(C1))+d2*(double)(GREEN(C2)));if(G>255)G=255; int B=(int)(d1*(double)(BLUE (C1))+d2*(double)(BLUE (C2)));if(B>255)B=255; return RGB(R,G,B); } int shading(Point V, Point L, Point N, int CU, double s){ double kd=diffuse, ks=specular, ke=ambient, D1, D2; Point RV=sub(L,mlt(mlt(mlt(2,L),N),N)); //反射方向ベクトル D1=mlt(minus(N),L)/(len(N)*len(L));if(D1<0)D1=0;// 拡散および環境光 D1=kd*s*D1+ke; D2=s*ks*mlt(minus(RV),V)/(len(RV)*len(V)); if(D2<0)D2=0;// 反射 int R=(int)(D1*(double)(RED(CU) )+D2*255);if(R>255)R=255; int G=(int)(D1*(double)(GREEN(CU))+D2*255);if(G>255)G=255; int B=(int)(D1*(double)(BLUE(CU) )+D2*255);if(B>255)B=255; return RGB(R,G,B); } void drawPoint(double x,double y, int C){//点を描く SetPixel(hbuf,(int)(x+0.5), (int)(y+0.5),C); } //---------------------------------------------------------------- // 図形演算では図形内部かどうかを判定する必要があるので以下の2関数追加 bool In(Ball B, Point P){//球の内部かどうかの判定 double L=len(sub(P,B.o)); //if(abs(L-B.r)<0.0001) return true; if(L<=B.r) return true; else return false; } double hitIn(Ball B, Ray VR,Point *P, Point *N) {//差表示用 double ds=mlt(VR.d,sub(VR.o,B.o)); double d2=ds*ds-mlt(sub(VR.o,B.o),sub(VR.o,B.o))+B.r*B.r; if(d2<0) return 1E+8F; double t= -ds + sqrt(d2); *P=add(VR.o,mlt(t , VR.d)); *N=unit(sub(*P, B.o)); return t; } void orFig(){ //和(Ba2 ∪ Ba1) init2D(500,400); origin(250,200); Ball Ba1 = setBall(setPoint(0,0,60),40); //球体の定義 Ball Ba2 = setBall(setPoint(0,0,0),70); //球体の定義 Point L0 = setPoint(0,400,1000); //照明光 Point V0 = setPoint(500,500,500); //視点 setview(V0); for(int x=0;x