所以我目前有一个可以动态改变的三角形网格(用贝塞尔曲线制作)。我面临的问题是试图根据相机所处的位置找出实际渲染的三角形。相机始终朝向原点(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);
}
现在,我的代码给出了这个结果。不应该显示用红色圈出的部分(我相信,后面的三角形)。
答案 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
,但我不会超载其他库的功能。