三角形法向表面检测

时间:2013-04-24 15:59:10

标签: c++ c opengl graphics bezier

所以我目前有一个可以动态改变的三角形网格(用贝塞尔曲线制作)。我面临的问题是试图根据相机所处的位置找出实际渲染的三角形。相机始终朝向原点(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);
}

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

2 个答案:

答案 0 :(得分:3)

您测试法线的方法仍会产生视觉效果,因为面向相机的三角形会被遮挡。想象一下,如果那个凸起位于最靠近相机的角落。

您还将拥有部分可见且部分遮挡的三角形。

在像素级别上工作的解决方案是:

  • glEnable(GL_DEPTH_TEST)​
  • 使用实心三角形而不是线框绘制第一表面
  • 清除帧缓冲区,但深度缓冲区
  • 现在绘制整个场景。深度缓冲区将防止绘制模糊的像素

答案 1 :(得分: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()以获取Vector,但我不会超载其他库的功能。

相关问题