我有一个问题,我似乎无法获得一个有效的算法,我已经尝试了几天,但是到目前为止仍然如此接近。
我想画一个由3个点(p0,p1,p2)定义的三角形。该三角形可以是任何形状,大小和方向。三角形也必须填入内部。
以下是我尝试过的一些事情以及他们失败的原因:
1
2
3
这都是为了制作多边形和平面。 3给了我最大的成功并且制作了精确的三角形,但是当我尝试将这些连接在一起时,一切都崩溃了,我遇到的问题是没有连接,不对称等等。我相信3会有一些调整,但我只是穿着试图让这项工作长期存在并需要帮助。
我的算法中有很多细节并不是真的相关,所以我把它们排除在外。对于3号,它可能是我的实现的问题,而不是算法本身。如果你想要代码我会尝试清理它以使其易于理解,但我需要几分钟时间。但我正在寻找已知可行的算法。我似乎无法在任何地方找到任何体素形状制作算法,我从头开始做各种事情。
编辑:
这是第三次尝试。这是一团糟,但我试图清理它。
// Point3i is a class I made, however the Vector3fs you'll see are from lwjgl
public void drawTriangle (Point3i r0, Point3i r1, Point3i r2)
{
// Util is a class I made with some useful stuff inside
// Starting values for iteration
int sx = (int) Util.min(r0.x, r1.x, r2.x);
int sy = (int) Util.min(r0.y, r1.y, r2.y);
int sz = (int) Util.min(r0.z, r1.z, r2.z);
// Ending values for iteration
int ex = (int) Util.max(r0.x, r1.x, r2.x);
int ey = (int) Util.max(r0.y, r1.y, r2.y);
int ez = (int) Util.max(r0.z, r1.z, r2.z);
// Side lengths
float l0 = Util.distance(r0.x, r1.x, r0.y, r1.y, r0.z, r1.z);
float l1 = Util.distance(r2.x, r1.x, r2.y, r1.y, r2.z, r1.z);
float l2 = Util.distance(r0.x, r2.x, r0.y, r2.y, r0.z, r2.z);
// Calculate the normal vector
Vector3f nn = new Vector3f(r1.x - r0.x, r1.y - r0.y, r1.z - r0.z);
Vector3f n = new Vector3f(r2.x - r0.x, r2.y - r0.y, r2.z - r0.z);
Vector3f.cross(nn, n, n);
// Determines which direction we increment for
int iz = n.z >= 0 ? 1 : -1;
int iy = n.y >= 0 ? 1 : -1;
int ix = n.x >= 0 ? 1 : -1;
// Reorganize for the direction of iteration
if (iz < 0) {
int tmp = sz;
sz = ez;
ez = tmp;
}
if (iy < 0) {
int tmp = sy;
sy = ey;
ey = tmp;
}
if (ix < 0) {
int tmp = sx;
sx = ex;
ex = tmp;
}
// We're we want to iterate over the end vars so we change the value
// by their incrementors/decrementors
ex += ix;
ey += iy;
ez += iz;
// Maximum length
float lmax = Util.max(l0, l1, l2);
// This is a class I made which manually iterates over a line, I already
// know that this class is working
GeneratorLine3d g0, g1, g2;
// This is a vector for the longest side
Vector3f v = new Vector3f();
// make the generators
if (lmax == l0) {
v.x = r1.x - r0.x;
v.y = r1.y - r0.y;
v.z = r1.z - r0.z;
g0 = new GeneratorLine3d(r0, r1);
g1 = new GeneratorLine3d(r0, r2);
g2 = new GeneratorLine3d(r2, r1);
}
else if (lmax == l1) {
v.x = r1.x - r2.x;
v.y = r1.y - r2.y;
v.z = r1.z - r2.z;
g0 = new GeneratorLine3d(r2, r1);
g1 = new GeneratorLine3d(r2, r0);
g2 = new GeneratorLine3d(r0, r1);
}
else {
v.x = r2.x - r0.x;
v.y = r2.y - r0.y;
v.z = r2.z - r0.z;
g0 = new GeneratorLine3d(r0, r2);
g1 = new GeneratorLine3d(r0, r1);
g2 = new GeneratorLine3d(r1, r2);
}
// Absolute values for the normal
float anx = Math.abs(n.x);
float any = Math.abs(n.y);
float anz = Math.abs(n.z);
int i, o;
int si, so;
int ii, io;
int ei, eo;
boolean maxx, maxy, maxz,
midy, midz, midx,
minx, miny, minz;
maxx = maxy = maxz =
midy = midz = midx =
minx = miny = minz = false;
// Absolute values for the longest side vector
float rnx = Math.abs(v.x);
float rny = Math.abs(v.y);
float rnz = Math.abs(v.z);
int rmid = Util.max(rnx, rny, rnz);
if (rmid == rnz) midz = true;
else if (rmid == rny) midy = true;
midx = !midz && !midy;
// Determine the inner and outer loop directions
if (midz) {
if (any > anx)
{
maxy = true;
si = sy;
ii = iy;
ei = ey;
}
else {
maxx = true;
si = sx;
ii = ix;
ei = ex;
}
}
else {
if (anz > anx) {
maxz = true;
si = sz;
ii = iz;
ei = ez;
}
else {
maxx = true;
si = sx;
ii = ix;
ei = ex;
}
}
if (!midz && !maxz) {
minz = true;
so = sz;
eo = ez;
}
else if (!midy && !maxy) {
miny = true;
so = sy;
eo = ey;
}
else {
minx = true;
so = sx;
eo = ex;
}
// GeneratorLine3d is iterable
Point3i p1;
for (Point3i p0 : g0) {
// Make sure the two 'mid' coordinate correspond for the area inside the triangle
if (midz)
do p1 = g1.hasNext() ? g1.next() : g2.next();
while (p1.z != p0.z);
else if (midy)
do p1 = g1.hasNext() ? g1.next() : g2.next();
while (p1.y != p0.y);
else
do p1 = g1.hasNext() ? g1.next() : g2.next();
while (p1.x != p0.x);
eo = (minx ? p0.x : miny ? p0.y : p0.z);
so = (minx ? p1.x : miny ? p1.y : p1.z);
io = eo - so >= 0 ? 1 : -1;
for (o = so; o != eo; o += io) {
for (i = si; i != ei; i += ii) {
int x = maxx ? i : midx ? p0.x : o;
int y = maxy ? i : midy ? p0.y : o;
int z = maxz ? i : midz ? p0.z : o;
// isPassing tests to see if a point goes past a plane
// I know it's working, so no code
// voxels is a member that is an arraylist of Point3i
if (isPassing(x, y, z, r0, n.x, n.y, n.z)) {
voxels.add(new Point3i(x, y, z));
break;
}
}
}
}
}
答案 0 :(得分:1)
您可以使用Besenham's line algorithm之类的内容,但可以扩展为三维。我们想要从中得出的两个主要想法是:
正如Bresenham的算法通过执行初始旋转来防止间隙,我们将通过执行两次初始旋转来避免间隙。
你希望飞机足够不陡,以避免漏洞。您必须满足以下条件:
-1 >= norm.x / norm.y >= 1
-1 >= norm.z / norm.y >= 1
将法线矢量和初始点绕x轴旋转90度,绕z轴旋转90度,直到满足这些条件。我不知道如何以最少的转数做到这一点,但我相当确定你能满足任何飞机的这些条件。
答案 1 :(得分:0)
从检查三角形/体素交叉点的函数开始。现在你可以扫描一个体积并找到与三角形相交的体素 - 这些是你感兴趣的体素。这是一个糟糕的算法,但也是你尝试的其他任何东西的回归测试。使用SAT(分离轴定理)并考虑三角形的简并体积(1面,3条边)并考虑体素对称性(仅3面法线),可以很容易地实现该测试。
我使用octtrees,所以我首选的方法是测试一个大体素的三角形并找出它相交的8个子八分圆中的哪一个。然后对相交的子项使用递归,直到达到所需的细分级别。提示:最多6个孩子可以与三角形相交,并且通常少于三角形。这很棘手,但会产生与第一种方法相同的结果,但速度要快得多。
3D中的光栅化可能是最快的,但恕我直言,更难保证在所有情况下都没有漏洞。再次,使用第一种方法进行比较。