
關鍵詞:三角形
沖孔網
標題:三角形重心坐標
那里有賣
沖孔板
來源:知乎那里有賣沖孔板
文章內容: 三角形重心坐標
P用A,B,C來表示
對于三角形內的任意一點P
其實學過向量的就能想到, 線性相關。
可以寫成:
這個式子我們可以拆開:
得到:
這也是P的表示,其中 . 來取特殊一點的 u,v 可以得到 A, B, C.
這個式子長的很像 AB 上任意一點D的計算:
也就是線性插值
計算
當然也可以把ABC看成坐標系,始于A點,基為: 和 。所以這個叫做重心坐標系(barycentric,bary- 重的)也能得到式子:
繼續寫:
考慮二維三角形,拆一拆:
甚至我們還可以把它寫成矩陣形式:
實際上我們都可以看做是我們在尋找向量 (u, v, 1) 同時垂直于向量 和向量 。那里有賣沖孔板 這不就是叉乘么?
同時這給了我們一個有了P點,求 u 和 v 的思路。
xvector = (B_x - A_x, C_x - A_x, A_x - P_x) yvector = (B_y - A_y, C_y - A_y, A_y - P_y) u = xvector x yvector # 因為我們討論的是二維的三角形,如果 u 的 z 分量不等于1則說明P點不在三角形內
編碼
然后我們來代碼階段,因為我們的計算中涉及到浮點數,可能u的z分量不會一定等于1.0,
令 u 的三個分量是 (a, b, c),我們代入原式子:
看C++代碼:
Vec3f barycentric(Vec2f A, Vec2f B, Vec2f C, Vec2f P) { Vec3f s[2]; for (int i=2; i--; ) { s[i][0] = C[i]-A[i]; s[i][1] = B[i]-A[i]; s[i][2] = A[i]-P[i]; } Vec3f u = cross(s[0], s[1]); if (std::abs(u[2])>1e-2) // dont forget that u[2] is integer. If it is zero then triangle ABC is degenerate return Vec3f(1.f-(u.x+u.y)/u.z, u.y/u.z, u.x/u.z); return Vec3f(-1,1,1); // in this case generate negative coordinates, it will be thrown away by the rasterizator }
整個Python的:
def barycentric(A, B, C, P): """ A, B, C, P: Vector3, points return u: Vector3, barycentric coordinate of P """ s1 = Vector3(B.x - A.x, C.x - A.x, A.x - P.x) s2 = Vector3(B.y - A.y, C.y - A.y, A.y - P.y) u = s1.cross(s2) if abs(u.z) > EPSILON: # means this works, we have the P inside triangle return Vector3(1-(u.x+u.y)/u.z, u.x/u.z, u.y/u.z) return Vector3(-1,1,1)
應用
重心坐標在CG中的應用可以有以下:
填充三角形
之前我也想過這個問題,因為我們生成圖像,歸根結底是在于畫像素點,那么如果我們要填充一個三角形,對于一個一個的像素點,我們只需要放到上述函數里面去,就可以判斷P是否在三角形內,如果在三角形內,我們就去畫它。這樣填一個三角形的算法可以就是O(image.width * image.height),我們甚至可以進一步降低復雜度,對于一個三角形來說,我們可以由它的bounding box, 只需要檢測它的bounding box里面的點,然后就可以用來填充。
z-buffer
其實這里也不止于 z-buffer,我們已經把P點表示成了A,B,C的線性組合形式,那么對于P點的z,我們也可以這樣來看,我們把P點z值也可以看成A,B,C的線性組合,其實不僅僅是P點的z,對于P點的任意性質,只要是我們覺得可以用線性組合來看的,我們都可以用這個坐標系統。那里有賣沖孔板