3

所以我目前有一个可以动态更改的三角形网格(用贝塞尔曲线制成)。我面临的问题是试图根据相机所在的位置确定要实际渲染的三角形。相机总是看向原点(0,0,0),所以我找到了每个三角形的法线,并用我的相机矢量取它的点积。然后,根据结果,确定三角形是否应该“可见”。

以下是我用于计算的代码:

void bezier_plane()
{
    for (int i = 0; i < 20; i++) {
        for (int j = 0; j < 20; j++) {
            grid[i][j].x = 0;
            grid[i][j].y = 0;
            grid[i][j].z = 0;
        }
    }
    //Creates the grid using bezier calculation
    CalcBezier();
    for (int i = 0; i < 19; i++) {
        for (int j = 0; j < 19; j++) {
            Vector p1, p2, p3, normal;
            p1.x = grid[i+1][j+1].x - grid[i][j].x; p1.y = grid[i+1][j+1].y - grid[i][j].y; p1.z = grid[i+1][j+1].z - grid[i][j].z;
            p2.x = grid[i+1][j].x - grid[i][j].x;   p1.y = grid[i+1][j].y - grid[i][j].y; p1.z = grid[i+1][j].z - grid[i][j].z;

            normal = CalcNormal(p2, p1);
            double first = dotproduct(normal, Camera);

            p3.x = grid[i][j+1].x - grid[i][j].x; p3.y = grid[i][j+1].y - grid[i][j].y; p3.z = grid[i][j+1].z - grid[i][j].z;

            normal = CalcNormal(p1, p3);
            double second = dotproduct(normal, Camera);

            if (first < 0 && second < 0) {
                glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                glColor3f(0, 1, 0);
                glBegin(GL_TRIANGLE_STRIP);
                    glVertex3f(grid[i][j].x, grid[i][j].y, grid[i][j].z);
                    glVertex3f(grid[i][j+1].x, grid[i][j+1].y, grid[i][j+1].z);
                    glVertex3f(grid[i+1][j].x, grid[i+1][j].y, grid[i+1][j].z);
                    glVertex3f(grid[i+1][j+1].x, grid[i+1][j+1].y, grid[i+1][j+1].z);
                glEnd();
            } else if (first < 0 && second > 0) {
                glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                glColor3f(0, 1, 0);
                glBegin(GL_TRIANGLE_STRIP);
                    glVertex3f(grid[i][j].x, grid[i][j].y, grid[i][j].z);
                    glVertex3f(grid[i+1][j].x, grid[i+1][j].y, grid[i+1][j].z);
                    glVertex3f(grid[i+1][j+1].x, grid[i+1][j+1].y, grid[i+1][j+1].z);
                glEnd();
            } else if (first > 0 && second < 0) {
                glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                glColor3f(0, 1, 0);
                glBegin(GL_TRIANGLE_STRIP);
                    glVertex3f(grid[i][j].x, grid[i][j].y, grid[i][j].z);
                    glVertex3f(grid[i][j+1].x, grid[i][j+1].y, grid[i][j+1].z);
                    glVertex3f(grid[i+1][j+1].x, grid[i+1][j+1].y, grid[i+1][j+1].z);
                glEnd();
            }
        }
    }
}

这是 CalcNormal:

   Vector CalcNormal(Vector p1, Vector p2)
{
    Vector normal;
    normal.x = (p1.y * p2.z) - (p1.z * p2.y);
    normal.y = (p1.z * p2.x) - (p1.x * p2.z);
    normal.z = (p1.x * p2. y) - (p1.y * p2.x);
    return normal;
}

double dotproduct(Vector normal, Vector Camera)
{
    return (normal.x * Camera.x + normal.y * Camera.y + normal.z + Camera.z);
}

现在,我的代码给出了这个结果。不应显示红色圈出的部分(我相信,后面的三角形)。 结果

4

2 回答 2

3
于 2013-04-24T16:22:23.267 回答
2

“正常是一个全局变量” - 这可能已经是你的问题了吗?这看起来是我能想到的最糟糕的全局数据应用!相反,调用这个东西crossproduct并返回一个向量听起来是个好主意,不是吗?此外,dotproduct应该以两个向量作为参数。

也就是说,你的方法是合理的。如果三角形的角始终具有相同的方向,则两条边的叉积将为您提供法线。此外,如果法线和视图之间的角度小于 90 度,则它看起来远离视图并且应该不可见。因此,问题必须出在您的实现中,并且使用无论如何都可以存储在 CPU 寄存器中的全局状态是您应该解决的第一件事。

编辑:您可以在这里使用运算符重载对读者有利:

class Vector
{
   Vector(){}
   Vector(scalar x0, scalar y0, scalar z0): x(x0), y(y0), z(z0){}
   float x, y, z;
};

Vector operator-(Vector const& v1, Vector const& v2)
{
   return Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}

然后,像这样启动循环体:

Vector const point1 = grid[i, j];
Vector const point2 = grid[i + 1, j];
Vector const point3 = grid[i, j + 1];
Vector const point4 = grid[i + 1, j + 1];

这些将很容易被编译器优化出来,同时它们简化了调试并提高了可读性。另请注意,它们是常量,这使编译器验证您不会意外更改它们。然后,计算两个三角形的两条法线:

Vector const norm1 = crossproduct(point2 - point1, point3 - point1);
Vector const norm2 = crossproduct(point4 - point2, point4 - point3);

然后,您可以检查 dotproduct 的可见性:

bool const visible1 = dotproduct(norm1, Camera) > 0;
bool const visible2 = dotproduct(norm2, Camera) > 0;

最后,您可以重载glVertex3f()a Vector,但我会远离重载其他库的函数。

于 2013-04-24T16:08:59.687 回答