[英]Traversing all the points inside a triangle using loops
以下是3D中三角形的x,y和z坐標的三個頂點:
-0.2035416, 0.1107585, 0.9516008 (vertex A)
-0.0334390, -0.2526040, 0.9751212 (vertex B)
0.2569092, 0.0913718, 0.9817184 (Vertex C)
投影平面分為(高度*寬度)像素的網格。
我想手動遍歷投影平面內三角形內的每個像素,從三角形的底部到頂部,並在c ++中在屏幕上打印三角形內的每個像素坐標 。 說,我已經找到了三角形的頂部和底部頂點。 但是現在,我將如何從下到上遍歷並打印每個像素坐標? 這背后的邏輯是什么?
我有一個使兩個嵌套的for循環(如下所示)的想法,但是在循環內部我將做什么? x和y每次增加后,如何使側面移動?
for (int y = ymin; y <= ymax; ++y) {
for (int x = xmin; x <= xmax; ++x) {
//what to to here?
}
}
遍歷演示:
#include <iostream>
template <size_t kD>
class Vector{
public:
template <class... Args>
Vector(double coord, Args&&... args) {
static_assert( sizeof...(args)+1 == kD, "Unmatched vector dimension" );
InitCoord(0, coord, std::forward<Args>(args)...);
}
Vector(const Vector &) = default;
Vector &operator=(const Vector &) = default;
double &operator[](const size_t i) {
return coord_[i];
}
double operator[](const size_t i) const {
return coord_[i];
}
friend Vector<kD> operator-(const Vector<kD> &A, const Vector<kD> &B) {
Vector v;
for (size_t i=0; i<kD; ++i)
v[i] = A[i]-B[i];
return v;
}
private:
Vector() = default;
template <class... Args>
void InitCoord(const int pos, double coord, Args&&... args) {
coord_[pos] = coord;
InitCoord(pos+1, std::forward<Args>(args)...);
}
void InitCoord(const int pos) {}
double coord_[kD];
};
class Line {
public:
Line(const double x1, const double y1, const double x2, const double y2)
: x1_(x1), y1_(y1), x2_(x2), y2_(y2) {}
Line(const Vector<2> A, const Vector<2> B)
: x1_(A[0]), y1_(A[1]), x2_(B[0]), y2_(B[1]) {}
double operator()(const double x, const double y) const {
return (y-y1_)*(x2_-x1_) - (x-x1_)*(y2_-y1_);
}
int_fast8_t Sign(const double x, const double y) const {
return Signum( (y-y1_)*(x2_-x1_) - (x-x1_)*(y2_-y1_) );
}
private:
int_fast8_t Signum(const double x) const {
return (0.0 < x) - (x < 0.0);
}
const double x1_,y1_;
const double x2_,y2_;
};
void Transpos(Vector<2> &v) {
v[0] = (v[0]+1)/2*720; // col
v[1] = (v[1]+1)/2*480; // row
}
double CalculateZ(const Vector<2> &D, const Vector<2> &AB, const Vector<2> &AC,
const Vector<3> &AB3, const Vector<3> &AC3) {
const double b = (D[1]*AB[0]-D[0]*AB[1]) / (AC[1]*AB[0]-AC[0]*AB[1]);
const double a = AB[0]==0 ? (D[1]-b*AC[1])/AB[1] : (D[0]-b*AC[0])/AB[0];
std::cout << a << " " << b << std::endl;
return a*AB3[2]+b*AC3[2];
}
int main()
{
const auto A3 = Vector<3>(0.0, 0.0, 7.0);
const auto B3 = Vector<3>(0.0, 0.3, 9.0);
const auto C3 = Vector<3>(0.4, 0.0, 1.0);
const auto AB3 = B3-A3;
const auto AC3 = C3-A3;
const auto BC3 = C3-B3;
// Some projection works here, which I am not good at.
// A B C store the projected triangle coordiate in the [-1,1][-1,1] area
auto A = Vector<2>(0.0, 0.0);
auto B = Vector<2>(0.0, 0.3);
auto C = Vector<2>(0.4, 0.0);
Transpos(A);
Transpos(B);
Transpos(C);
const auto AB2 = B-A;
const auto AC2 = C-A;
const auto BC2 = C-B;
const Line AB(A, B);
const Line AC(A, C);
const Line BC(B, C);
const auto signAB = AB.Sign(C[0],C[1]);
const auto signAC = AC.Sign(B[0],B[1]);
const auto signBC = BC.Sign(A[0],A[1]);
// top
// 0------------720 (col x)
// |
// |
// |
// |
// 480 (row y)
// bottom
for (int row=480-1; row>=0; --row) {
for (int col=0; col<720; ++col) {
if (signAB*AB.Sign(col,row)>=0 && signAC*AC.Sign(col,row)>=0 &&
signBC*BC.Sign(col,row)>=0 )
std::cout << row << "," << col << " Z:"
<< CalculateZ(Vector<2>(col, row)-A, AB2, AC2, AB3, AC3) + A3[2]
<< std::endl;
}
}
return 0;
}
投影:
假設我們在第一個空格中有一個(x1,y1),然后第二個空格中的(x_,y_)與x _ =(x1 + 1)/ 2 * 720,y _ =(y1 + 1)/ 2 * 480空間。
更概括地說:
first space [xmin,xmax][ymin,ymax]
second space [xmin_,xmax_][ymin_,ymax_]
(x1,y1)
->
( (x1-xmin)/(xmax-xmin)*(xmax_-xmin_)+xmin_ ,
(y1-ymin)/(ymax-ymin)*(ymax_-ymin_)+ymin_ )
如果您只想縮放它,不要扭曲它或其他東西...
編輯#1:
Ax Ay Bx By Cx Cy
現在是第一個空間中的坐標,然后將它們“轉置”到第二個空間中。 結果, Line AB AC BC
現在“在”第二個空間中。 並且相應地修改了兩個循環,它們現在迭代第二個空間的點。 如何從(x,y)中找到z值:
AB代表從A(Ax,Ay)到B(Bx,By)的向量,即AB = BA =(Bx-Ax,By-Ay)。
對於三角形中任何給定的點D(Dx,Dy),將其表示為AD = a AB + b AC:(Dx-Ax,Dy-Ay)= a *(Bx-Ax,By-Ay)+ b *( Cx-Ax,Cy-Ay),其中Cx Cy的Dx Dy Ax Ay Bx是已知的。 找出a和b,然后Dz = a *(Bz-Az)+ b *(Cz-Az)。 可以以相同的方式計算3D空間中的Dx Dy。
編輯#2:
Z值計算已添加到演示中。
我試圖使演示保持簡單,但是計算Z值確實涉及許多變量和計算。 我聲明了一個稱為Vector的新類來管理點和矢量,而Line類則保持不變。
您需要稍微更改內部循環; 不要從xmin轉到xmax。 對於從ymin到ymax的每個y值,都會有兩個完全不同的像素(兩個不同的x值),它們恰好位於三角形的兩個邊緣上。 計算這些點,然后它們之間的所有點都將在三角形內。 而且,您必須處理一些邊緣情況,例如其中一條邊緣是水平的。
首先,您必須將{0,1}范圍(垂直和水平)轉換為像素坐標。 您說的是720x480。 這不是正方形,而是矩形。 如果您決定保持一對一的比例,則會得到一個變形的三角形。 如果沒有,也許您只使用480x480像素。
其次,現在您在像素空間中擁有三個頂點,您可以迭代此像素空間中的每個像素,並確定其是否屬於三角形。 @felix在他的解決方案代碼中發布了用於此工作的函數“ InTriangle”:
if (signAB*AB(i,j)>=0 && signAC*AC(i,j)>=0 && signBC*BC(i,j)>=0 )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.