以下是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?
}
}
答案 0 :(得分:1)
遍历演示:
#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 = B-A =(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)其中Dx Dy Ax Ay Bx由Cx Cy已知。找出a和b,然后Dz = a *(Bz-Az)+ b *(Cz-Az)。 3D空间中的Dx Dy可以用相同的方式计算。
编辑#2:
Z值计算添加到演示中。
我试图保持演示简单,但计算Z值确实涉及许多变量和计算。我声明了一个名为Vector的新类来管理点和向量,而Line类保持不变。
答案 1 :(得分:0)
你需要稍微改变内环;不要从xmin到xmax。对于从ymin到ymax的y的每个值,将恰好有两个不同的像素(两个不同的x值),它们恰好位于三角形的两个边缘上。计算这些点,然后它们之间的所有点都在三角形内。而且你必须处理一些边缘情况,例如当其中一条边是水平的时。
答案 2 :(得分:0)
首先,您必须将{0,1}范围(vert&amp; horz)转换为像素坐标。你说的是720x480。这不是正方形,而是矩形。如果你决定保持一对一的比例,你会得到一个扭曲的三角形。如果没有,也许你只使用480x480像素。
其次,现在你在像素空间中有三个顶点,你可以迭代这个像素空间中的每个像素,并判断它是否属于三角形。这项工作的“InTriangle”函数是@felix在其解决方案代码中发布的内容:
@synchronized