同次座標で、平行投影から投影図法まで
このページはマス旅の一部です。
前回は、アフィン変換をまるごと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)
平行投影の数式でベクトルvをv-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をアニメーションにすると、透視図変換が正しく動いているのがわかりますね。