Google ClassroomGoogleクラスルーム
GeoGebraGeoGebra Classroom

同次座標で、平行投影から投影図法まで

このページはマス旅の一部です。 前回は、アフィン変換をまるごと1つの行列で表現できましたね。 今回はアフィン変換から射影変換へと進みましょう。

1.ベクトルで、投影を数式で表そう

射影変換の行列を作る前のウォーミングアップです。 ベクトルと方程式の知識を使って平行投影を数式化し、 それを利用して点からの射影を数式化してみよう。 <ベクトルの表記のお約束> ベクトルはふつうの小文字を扱い、内積だけなので、積マークは省略します2つのベクトルa、bの内積は、成分の積の和です。 「平面の方程式」は、点P(p)を通り法線ベクトルn=(a,b,c)に対して、np=d(dはスカラー) 「直線の方程式」は、点P(p)を通り方向ベクトルv=(i,j,k)に対して、p+tv(tはスカラー) <点Pから平面πへの平行投影> 点P(p=(q,r,s))から法線ベクトルn=(a,b,c)の平面π:np=dに対して、v=(i,j,k)方向の影の点Qの位置をベクトルで表そう。 点Q(q)は直線PQ上にあるので、q=p+tvとかける。 点Q(q)は平面πにあるので、nq=d このqは同じだから、n(p+tv)=np+tnv=dとなり、 t=(d-np)/nv これから、点Qは q=p+{(d-np)/nv} v この平行投影をvによるπへの直交射影(正射影)ともいうね。 <点Vを視点にして、点Pから平面πへの透視点> 直線PVとπの交点を点Qとする。 直線の方向ベクトルがv-pだから、点Q(q)はq=p+t(v-p)とかける。 円Q(q)は平面πにあるので、nq=d。 このpは同じだから、n(p+t(v-p))=np+tn(v-p)=dとなり、 t=(d-np)/n(v-p) これから、点Qは q=p+{(d-np)/n(v-p)} (v-p) 平行投影の数式でベクトルvv-pに置き換えただけの式になったね。

2.Geogebraで確認しよう

ここまでベクトルでやったことの確認をしよう。 課題:3点の平行投影をgeogebraで視覚化しよう。 #q=p+{(d-np)/nv} vの確認 タイトルは「3点の平行投影」 空間図形を選択してアプレットの作成 s=slider(0.1, 0.9, 0.1) p1=(1,2,3)   #投影前の位置ベクトル非表示 p2=(5,6,7)   #投影前の位置ベクトル非表示 p3=p1+s(p1-p2) #投影前の位置ベクトル非表示 n=(1,2,3)    #法線ベクトルは非表示 d=slider(-10,10,1) v=(0,0,1) #投影の方向ベクトル q1=p1+(d-n p1)/(n v) v #投影後の位置ベクトル非表示 q2=p2+(d-n p2)/(n v) v #投影後の位置ベクトル非表示 q3=p3+(d-n p3)/(n v) v #投影後の位置ベクトル非表示 #点として見るために原点にベクトルをたした点を生成します。 A=Point((0,0,0),p1) B=Point((0,0,0),p2) C=Point((0,0,0),p3) D=Point((0,0,0),q1) E=Point((0,0,0),q2) F=Point((0,0,0),q3) Segment(A,B) #青 Segment(A,C) #赤 segment(D,E) #青 segment(D,F) #赤 Vector(A,D) ♯点線で細線太さ2 Vector(B,E) ♯点線で細線太さ2 Vector(C,F) ♯点線で細線太さ2 #法線ベクトルnの平面nx=dと3軸との交点を決める H=(0,0,d/z(n)) ♯非表示 G=(0,d/y(n),0) ♯非表示 I=(d/x(n),0,0) ♯非表示 #3点D,E,Fが平面に乗っかっていることを確認するため Plane(H,G,I) #dをアニメーションにすると平面が動いても、3点A,B,Cの平行投影である3点D,E,Fが予想どうり連動して動くことがわかるね。

3点の平行投影

課題:視点Vからの透視図をgeogebraでかこう。 #q=p+((d-np)/n(v-p)) (v-p) タイトルは「三角形の透視図」 空間図形を選択してアプレットの作成 p1=(1,4,2)   #投影前の位置ベクトル非表示 p2=(2,2,4)   #投影前の位置ベクトル非表示 p3=(3,1,3)  #投影前の位置ベクトル非表示 n=(1,2,3)    #法線ベクトルは非表示 d=slider(5,10,1) V=(-2,-2,-2)  #視点V v=Vector(V)  #視点の位置ベクトル非表示 q1=p1+(d-n p1)/(n (v-p1)) (v-p1) #投影後の位置ベクトル非表示 q2=p2+(d-n p2)/(n (v-p2)) (v-p2) #投影後の位置ベクトル非表示 q3=p3+(d-n p3)/(n (v-p3)) (v-p3) #投影後の位置ベクトル非表示 #点として見るために原点にベクトルをたした点を生成します。 A=Point((0,0,0),p1) B=Point((0,0,0),p2) C=Point((0,0,0),p3) D=Point((0,0,0),q1) E=Point((0,0,0),q2) F=Point((0,0,0),q3) Polygon(A,B,C) #青 Polygon(D,E,F) #青 ♯polygonを描くと、頂点を結ぶセグメントも自動生成されますのでご注意ください。 うっとうしかったら、自動生成されて自動表示されたセグメント6本を非表示にしよう。 Vector(V,A) #点線の細線(太さを標準の5から2に減らす) Vector(V,B) #点線の細線 Vector(V,C) #点線の細線 #法線ベクトルnの平面nx=dと3軸との交点を決める H=(0,0,d/z(n)) ♯非表示 G=(0,d/y(n),0) ♯非表示 I=(d/x(n),0,0) ♯非表示 #3点D,E,Fが平面に乗っかっていることを確認するため Plane(H,G,I) #dをアニメーションにすると平面が動いても、 3点A,B,Cの透視である3点D,E,Fが予想どうり連動して動くことがわかるね。 また、点Vをつかんで動かしても、連動して透視三角形ができます。

三角形の透視図

3.同次座標で透視変換

一般の平面への透視を考える前に 準備として、yz平面(x=0)への透視を考えよう。 <yz平面に透視する> 法線ベクトルn=(1,0,0)のyz平面:np=0の上に、 点P(p=(p1,p2,p3))の視点V(v=(v1,v2,v3))から見た透視点Qを作る。 直線PVとyzの交点を点Qとする。 直線の方向ベクトルがv-pだから、点Q(q)はq=p+t(v-p)とかける。 円Q(q)はyz平面にあるので、nq=0。 このpは同じだから、n(p+t(v-p))=np+tn(v-p)=0となり、 t=(0-np)/n(v-p) これから、点Qは q=p-np/n(v-p) (v-p) ベクトルがn=(1,0,0)だから、nとの内積はx成分どうしの積(スカラーになる)となるから、 q=p-p1/(v1-p1) (v-p) となる。 列ベクトルqの成分を詳細化してみよう。 q=[p1,p2,p3] - p1/(v1-p1) [v1-p1,v2-p2,v3-p3] =[p1-p1(v1-p1)/(v1-p1) ,p2-p1(v2-p2)/(v1-p1) ,p3-p1(v3-p3)/(v1-p1) ] =[0, p2-p1(v2-p2)/(v1-p1) ,p3-p1(v3-p3)/(v1-p1)] だから、qの同次座標は、 q=[0, p2-p1(v2-p2)/(v1-p1) , p3-p1(v3-p3)/(v1-p1),1 ] =[0, p2(v1-p1)-p1(v2-p2), p3(v1-p1)-p1(v3-p3), (v1-p1)] =[0, p2v1-p1v2, p3v1-p1v3, v1-p1] ここで、 p,vの同次座標をpd=[p1,p2,p3,1]=[a1,a2,a3,a0] , vd=[v1,v2,v3,1]=[b1,b2,b3,b0]とおくと、 p1=a1/a0,p2=a2/a0,p3=a3/a0, v1=b1/b0,v2=b2/b0, v3=b3/b0となるので、 qd=[0,(a2b1-a1b2)/a0b0,(a3b1-a1b3)/a0b0, b1/b0-a1/a0] =[0, (a2b1-a1b2) , (a3b1-a1b3), (a0b1-a1b0)] ={{0,0,0,0},{-b2,b1,0,0},{-b3,0,b1,0},{-b0,0,0,b1}} [a1,a2,a3,a0] =M pd 透視変換行列Mを求めることができました。 課題:同次座標で点Pのyz平面への点Vからの透視点Qを求めよう。 タイトルは「視点Vから点Pをyz平面に透視した点Qを同次座標で求める」 P=(1,4,2)    p=Vector(P) #投影前の位置ベクトル非表示 n=(1,0,0)    #法線ベクトルは非表示 d=0 t=10 #4次元の座標 V=(-2,-2,-2)  #視点V v=Vector(V)  #視点の位置ベクトル非表示 a1=x(p) t a2=y(p) t a3=z(p) t a0= t b1=x(v) t b2=y(v) t b3=z(v) t b0= t pd={{a1},{a2} ,{a3} ,{a0}} #pの同次座標[a1,a2,a3,a0] vd={{b1},{b2} ,{b3} ,{b0}} #vの同次座標[b1,b2,b3,b0] M={{0,0,0,0},{-b2,b1,0,0},{-b3,0,b1,0},{-b0,0,0,b1}} qd = M pd q1=Element(qd,1,1)/Element(qd,4,1) q2=Element(qd,2,1)/Element(qd,4,1) q3=Element(qd,3,1)/Element(qd,4,1) q=(q1,q2,q3) P=Point((0,0,0),p) Q=Point((0,0,0),q) Vector(V,P) #点線の細線(太さを標準の5から2に減らす) 点Pや点Vをつかんで動かすと、点Qも連動して変化することがわかりますね。

視点Vから点Pをyz平面に透視した点Qを同次座標で求める

<一般平面に透視する> 法線ベクトルn=(a,b,c)のyz平面:np=0の上に、 点P(p=(p1,p2,p3))の視点V(v=(v1,v2,v3))から見た透視点Qを作る。 直線PVとyzの交点を点Qとする。 直線の方向ベクトルがv-pだから、点Q(q)はq=p+t(v-p)とかける。 円Q(q)はyz平面にあるので、nq=d。 このpは同じだから、n(p+t(v-p))=np+tn(v-p)=0となり、 t=(d-np)/n(v-p) これから、点Qは q=p+((d-np)/n(v-p)) (v-p) =p+(d-np)(v-p)/n(v-p) =p+(dv-dp-npv+npp)/(nv-np) =(nvp -npp+ dv-dp-npv-npp)/(nv-np) =(nvp +dv-dp-npv)/(nv-np) ={(nv-d)p+(d-np)v}/(nv-np) ={kp+(d-np)v}/(nv-np)( nv-d=kとおく。) k=nv-d=av1+bv2+cv3-dだから、点pを動かしても変わらない定数扱いができる。 d-np=d-(ap1+bp2+cp3)=lは、成分によらない。 分母はnv-np=nv-d+d-np=k+(d-np)=k+l 分子はkp+(d-np)v=kp+lv 列ベクトルqの成分を詳細化してみよう。 q=(kp+lv)/(k+l)=[(kp1+lv1)/(k+l),(kp2+lv2)/(k+l),(kp3+lv3)/(k+l)] だから、qの同次座標は、 qd=[kp1+lv1,kp2+lv2,kp3+lv3,k+l] ここで、 p,vの同次座標をpd=[p1,p2,p3,1]=[a1,a2,a3,a0] , vd=[v1,v2,v3,1]=[b1,b2,b3,b0]とおくと、 p1=a1/a0,p2=a2/a0,p3=a3/a0, v1=b1/b0,v2=b2/b0, v3=b3/b0となるので、 k=av1+bv2+cv3-d=(ab1+bb2+cb3-db0)/b0 l=d-(ap1+bp2+cp3)=(da0-aa1-ba2-ca3)/a0となるので、 qdの第1成分=kp1+lv1 =(ab1+bb2+cb3-db0)/b0 *(a1/a0 )+ (da0-aa1-ba2-ca3)/a0*(b1/b0) ={a1(ab1+bb2+cb3-db0)+b1(da0-aa1-ba2-ca3)}/a0b0 ={b (a1b2-a2b1)+c(a1b3-a3b1)+d(a0b1-a1b0)}/a0b0 qdの第2成分=kp2+lv2 ={a2(ab1+bb2+cb3-db0)+b2(da0-aa1-ba2-ca3)}/a0b0 ={a(a2b1-a1b2)+c(a2b3-a3b2)+d(-a2b0+a0b2)}/a0b0 qdの第3成分=kp3+lv3=d(a0b3-a3b0)/a0b0 ={a3(ab1+bb2+cb3-db0)+b3(da0-aa1-ba2-ca3)}/a0b0 ={a(a3b1-a1b3)+b(a3b2-a2b3)+d(-a3b0+a0b3)}/a0b0 qdの第4成分=k+l =(ab1+bb2+cb3-db0)/b0 + (da0-aa1-ba2-ca3)/a0 ={a0(ab1+bb2+cb3-db0)+b0(da0-aa1-ba2-ca3)}/a0b0 ={a(a0b1-a1b0)+b(a0b2-a2b0)+c(a0b3-a3b0)}/a0b0 これらから、 qd=[{b (a1b2-a2b1)+c(a1b3-a3b1)+d(a0b1-a1b0)} , {a(a2b1-a1b2)+c(a2b3-a3b2)+d(-a2b0+a0b2)} , {a(a3b1-a1b3)+b(a3b2-a2b3)+d(-a3b0+a0b3)},{a(a0b1-a1b0)+b(a0b2-a2b0)+c(a0b3-a3b0)}] =[a1(bb2+cb3-db0) +a2(-bb1) +a3(-cb1) +a0(db1), a1(-ab2) + a2( ab1+cb3-db0) +a3(cb2) +a0(db2), a1(-ab3) + a2(-bb3) + a3(ab1+bb2-db0) +a0(db3), a1(-ab0) + a2(-bb0) + a3(-cb0) + a0(ab1+bb2+cb3)] ={{bb2+cb3-db0 ,-bb1 , -cb1 , db1 }, {-ab2 , ab1+cb3-db0 , -cb2 , db2 }, {-ab3 ,-bb3 , ab1+bb2-db0 , db3 }, {-ab0 ,-bb0 , -cb0 , ab1+bb2+cb3 }} [a1,a2,a3,a0] =M pd 透視変換行列Mを求めることができました。 形をそろえるために、 k=av1+bv2+cv3-d=(ab1+bb2+cb3-db0)/b0を利用して、 kb0=ab1+bb2+cb3-db0となるから、 M= ={{kb0-ab1, -bb1 , -cb1 , db1}, { -ab2, kb0-bb2 , -cb2 , db2}, { -ab3, -bb3 ,kb0-cb3 , db3}, { -ab0, -bb0 . -cb0 ,kb0+db0 }} =(ab1+bb2+cb3-db0) E4+[b1,b2,b3,b0]{-a,-b,-c,d} =nd vd E4 - vd nd vdは列ベクトルで、 nd={a,b,c,-d}は行ベクトルです。 4行1列ベクトルに1行4列ベクトルをかけると4行4列の行列になり、 1行4列ベクトルに4行1列ベクトルをかけるとスカラーになることを利用しました。 yz平面の場合をあてはめて検証しましょう。 (a,b,c,d)=(1,0,0,0)から、kb0=ab1+bb2+cb3-db0=b1,[-a,-b,-c,d]=[-1,0,0,0] Myz=diag(b1,b1,b1,b1)+{b1{-1,0,0,0},b2{-1,0,0,0},b3{-1,0,0,0},b0{-1,0,0,0}} ={{0,0,0,0},{-b2,b1,0,0},{-b3,0,b1,0},{-b0,0,0,b1}} 同じになったね。
課題:同次座標で、点Pの一般平面への点Vからの透視点Qを求めよう。 タイトルは「視点Vから点Pを一般平面に透視した点Qを同次座標で求める」 #演算部 p1=(1,4,2)   #投影前の位置ベクトル非表示 p2=(2,2,4)   #投影前の位置ベクトル非表示 p3=(3,1,3)    #投影前の位置ベクトル非表示 n=(1,2,3)    #法線ベクトルは非表示 d=slider(5,10,1) t=10 #4次元の座標 V=(-2,-2,-2) #視点V v=Vector(V)  #視点の位置ベクトル非表示 #点として見るために原点にベクトルをたした点を生成します。 vd={{x(v) t},{y(v) t} ,{z(v) t} ,{t}} #vの同次座標[b1,b2,b3,b0]列ベクトル nd={{x(n),y(n) ,z(n) ,-d}} #[a,b,c,-d]行ベクトルにするにはカッコを2重にする。 p1d={{x(p1) t},{y(p1) t} ,{z(p1) t} ,{t}} p2d={{x(p2) t},{y(p2) t} ,{z(p2) t} ,{t}} p3d={{x(p3) t},{y(p3) t} ,{z(p3) t} ,{t}} E4 = Identity(4) # geogebraが行ベクトル×列ベクトルが1行1列の行列とみなすため m1=nd vd a=Element(m1,1,1) M = a E4 - vd nd q1d= M p1d q2d= M p2d q3d= M p3d #geogebraのバグ?列ベクトルか行ベクトルに設定したとしても、表示は行列なのにリスト扱いになるので、最初っからリストを作ることにした。 q1={Element(q1d,1,1)/Element(q1d,4,1),Element(q1d,2,1)/Element(q1d,4,1),Element(q1d,3,1)/Element(q1d,4,1)} q2={Element(q2d,1,1)/Element(q2d,4,1),Element(q2d,2,1)/Element(q2d,4,1),Element(q2d,3,1)/Element(q2d,4,1)} q3={Element(q3d,1,1)/Element(q3d,4,1),Element(q3d,2,1)/Element(q3d,4,1),Element(q3d,3,1)/Element(q3d,4,1)} #ここから表示部 A=Point((0,0,0),p1) B=Point((0,0,0),p2) C=Point((0,0,0),p3) D=(q1(1),q1(2),q1(3)) E=(q2(1),q2(2),q2(3)) F=(q3(1),q3(2),q3(3)) Polygon(A,B,C) #緑 Polygon(D,E,F) #緑 ♯polygonを描くと、頂点を結ぶセグメントも自動生成されますのでご注意ください。 うっとうしかったら、自動生成されて自動表示されたセグメント6本を非表示にしよう。 Vector(V,A) #点線の細線(太さを標準の5から2に減らす) Vector(V,B) #点線の細線 Vector(V,C) #点線の細線 #法線ベクトルnの平面nx=dと3軸との交点を決める H=(0,0,d/z(n)) ♯非表示 G=(0,d/y(n),0) ♯非表示 I=(d/x(n),0,0) ♯非表示 #3点D,E,Fが平面に乗っかっていることを確認するため Plane(H,G,I) dをアニメーションにすると、透視図変換が正しく動いているのがわかりますね。

視点Vから点Pを一般平面に透視した点Qを同次座標で求める