3D圓柱體透視效果
總效果
原理:
3D面+面在攝像機方向上的2D投影點的集合
3D面效果:
2D線:
畫線時需要注意兩個點:
1 在圓柱體上下兩個圓之間有兩條豎著的稜邊代表圓柱體邊緣
2 被遮蓋的圓面後半面顯示為虛線
1 如何確定兩條稜邊的位置
我們需要確定上下兩個圓面最左邊和最右邊的點。
隨著攝像機的移動,上面的左右兩個點和下面的左右兩個點也隨之變化
點的變化和Y軸無關,所以我們可以把它看作是個2維關係。
其中直線是攝像機位置視角與面中心的連線,兩個紅點則是這個面最左邊的點和最右邊的點。
即問題轉變為:求一條過圓心的點直線的垂線與圓的交點。
即:
Point3D cameraRealPosition = transform.Transform(carema.Position);
Point caremaRealPoint = new Point(cameraRealPosition.X, cameraRealPosition.Z);
var l1 = caremaRealPoint.X - center.X;
var l2 = caremaRealPoint.Y - center.Y;
var l3 = Math.Sqrt(l1 * l1 + l2 * l2);
var sinb = l2 / l3;
var cosb = l1 / l3;
var x1 = r * sinb + center.X;
var y1 = -r * cosb + center.Y;
var x2 = -r * sinb + center.X;
var y2 = r * cosb + center.Y;
此時我們求出一個面的點(x1,y1)(x2,y2)
在三維中,y是z軸,則點為
new Point3D(x1, pointTopCenter.Y, y1)
new Point3D(x2, pointTopCenter.Y, y2)
new Point3D(x1, pointBottomCenter.Y, y1)
new Point3D(x2, pointBottomCenter.Y, y2)
上下點連線則為圓柱體的側邊。
2 如何確定虛線位置。
2.1分離實線點和虛線點
我們可以發現虛線與實線是以(x1,y1)(x2,y2)分離的。
由於線是以投影點的集合組合而成。
我們可以根據每個點在(x1,y1)-(x2,y2)這條直線的左邊還是右邊把這個集合分成兩部分。
根據向量叉乘來判斷在左邊還是右邊。
bool IsPointOnLineLeftOrRight(Point a, Point b, Point p)
{
Vector pa = new Vector(a.X - p.X, a.Y - p.Y);
Vector pb = new Vector(b.X - p.X, b.Y - p.Y);
return Vector.CrossProduct(pa, pb) < 0;
}
其中ab為分別為x1y1左邊兩個點。
2.2確定上面存在虛線還是下面存在虛線
思路:從四個集合中選取位置相同四個點,通過和攝像機的距離比較來判斷哪個集合是虛線集合
1 通過上下面相同位置的點F1,F2的距離,判斷是上面存在被遮蓋的面還是下面存在被遮蓋的面。
如圖:
DistanceF2ToCamera>DistanceF1ToCamera
則虛線應該在下邊這個圓上。
2.3 確定面左邊集合是虛線還是右邊集合
同樣DistanceF3ToCamera>DistanceF4ToCamera
所以F3所在的集合是虛線點集
由此就可以判斷虛線點集了。
3 點集的順序一致性。
我們畫的是開放的半圓,在畫2D半圓線的時候,我們需要保證從左邊第一個點開始畫,畫到最右邊的點,
如果是從中間開始畫,那麼就會是個封閉的半圓了。
開放的半圓:
封閉的半圓:
所以我們要保證點集的順序是從左到右的:
正常視角:
那我們存在兩種情況:
若以A為起點,則按順序有三個點集:A1,B,A2
則
點集A=A2+A1
點集B=B
若以A為起點,則按順序有三個點集:A1,B,A2
則
點集A=A2+A1
點集B=B
兩種情況統一:
我們需要注意的是A=A2+A1
兩個集合新增的時候順序要變一下。