纯 C 中的 glRotatef
glRotatef in pure C
我在用纯 C 编写 glRotatef 的替代函数时遇到问题。我需要实现参数为:点列表、角度和旋转向量的函数。函数必须 return 旋转后的点列表。我的函数如下所示:
void rotate(float * current, float a, float x, float y, float z)
{
float sina = sinf(a);
float cosa = cosf(a);
float rotateMatrix[9] = //creating rotate matrix
{
x*x*(1-cosa) + cosa, x*y*(1-cosa) - z*sina, x*z*(1-cosa) + y*sina,
y*x*(1-cosa) + z*sina, y*y*(1-cosa) + cosa, y*z*(1-cosa) - x*sina,
z*x*(1-cosa) - y*sina, z*y*(1-cosa) + x*sina, z*z*(1-cosa) + cosa
};
float *resultVertexList = current; //temporary help
int i;
for(i=0;current[i] != 0;i++) //multiplying CURRENT_MATRIX * ROTATE_MATRIX
{
int currentVertex = (i/3) * 3;
int rotateColumn = i%3;
resultVertexList[i] =
current[currentVertex] * rotateMatrix[rotateColumn] +
current[currentVertex+1] * rotateMatrix[rotateColumn+3] +
current[currentVertex+2] * rotateMatrix[rotateColumn+6];
}
current = resultVertexList;
}
我在这里这样称呼它:rotate(current, M_PI/10, 0, 1, 0);
之后,我使用 current
个点列表并使用 openGL 简单地绘制它们。为了进行测试,我尝试旋转代表立方体的点列表。它会旋转,但随着 rotate
函数的每一次调用,它都会缩小。我不知道为什么。查看一些屏幕截图:
多次调用rotate
函数后缩小到一点。
我做错了什么?
这行代码:
float *resultVertexList = current; //temporary help
不复制您的顶点列表。您只是将指针复制到列表中,因此在此之后您有两个指向同一个列表的指针。因此,以下循环使用已经旋转的 x/y 坐标来计算新的 y/z 坐标,这显然是错误的。
我也想知道你的终止条件:
current[i] != 0
这没有错,但它会阻止您使用零坐标的任何顶点。相反,我建议使用一个额外的参数来显式传递顶点数。
我也会按顶点而不是按坐标旋转,这样更自然也更容易理解:
void rotate(float * current, int vertexCount, float a, float x, float y, float z)
{
float sina = sinf(a);
float cosa = cosf(a);
float rotateMatrix[9] =
{
x*x*(1 - cosa) + cosa, x*y*(1 - cosa) - z*sina, x*z*(1 - cosa) + y*sina,
y*x*(1 - cosa) + z*sina, y*y*(1 - cosa) + cosa, y*z*(1 - cosa) - x*sina,
z*x*(1 - cosa) - y*sina, z*y*(1 - cosa) + x*sina, z*z*(1 - cosa) + cosa
};
int i;
for (i = 0; i < vertexCount; ++i)
{
float* vertex = current + i * 3;
float x = rotateMatrix[0] * vertex[0] + rotateMatrix[1] * vertex[1] + rotateMatrix[2] * vertex[2];
float y = rotateMatrix[3] * vertex[0] + rotateMatrix[4] * vertex[1] + rotateMatrix[5] * vertex[2];
float z = rotateMatrix[6] * vertex[0] + rotateMatrix[7] * vertex[1] + rotateMatrix[8] * vertex[2];
vertex[0] = x;
vertex[1] = y;
vertex[2] = z;
}
}
您实现矩阵向量乘法的方式非常粗糙,而且 - 更重要的是 - 完全错误。
问题是您覆盖了您仍然需要的数据。因此,在第一次交互中,您有效地写入 current[0]
(并且您的 resultVertexList
指针根本没有帮助。它指向您的唯一一个数据副本,直接就地覆盖它. 在接下来的两次迭代中,将使用 current[0]
的新值,而不是原来的
我建议您简单地实现一个简单的 mat3 * vec3
函数,它可以很容易地在循环中调用,并且注意不要覆盖它仍然需要的数据。
我在用纯 C 编写 glRotatef 的替代函数时遇到问题。我需要实现参数为:点列表、角度和旋转向量的函数。函数必须 return 旋转后的点列表。我的函数如下所示:
void rotate(float * current, float a, float x, float y, float z)
{
float sina = sinf(a);
float cosa = cosf(a);
float rotateMatrix[9] = //creating rotate matrix
{
x*x*(1-cosa) + cosa, x*y*(1-cosa) - z*sina, x*z*(1-cosa) + y*sina,
y*x*(1-cosa) + z*sina, y*y*(1-cosa) + cosa, y*z*(1-cosa) - x*sina,
z*x*(1-cosa) - y*sina, z*y*(1-cosa) + x*sina, z*z*(1-cosa) + cosa
};
float *resultVertexList = current; //temporary help
int i;
for(i=0;current[i] != 0;i++) //multiplying CURRENT_MATRIX * ROTATE_MATRIX
{
int currentVertex = (i/3) * 3;
int rotateColumn = i%3;
resultVertexList[i] =
current[currentVertex] * rotateMatrix[rotateColumn] +
current[currentVertex+1] * rotateMatrix[rotateColumn+3] +
current[currentVertex+2] * rotateMatrix[rotateColumn+6];
}
current = resultVertexList;
}
我在这里这样称呼它:rotate(current, M_PI/10, 0, 1, 0);
之后,我使用 current
个点列表并使用 openGL 简单地绘制它们。为了进行测试,我尝试旋转代表立方体的点列表。它会旋转,但随着 rotate
函数的每一次调用,它都会缩小。我不知道为什么。查看一些屏幕截图:
多次调用rotate
函数后缩小到一点。
我做错了什么?
这行代码:
float *resultVertexList = current; //temporary help
不复制您的顶点列表。您只是将指针复制到列表中,因此在此之后您有两个指向同一个列表的指针。因此,以下循环使用已经旋转的 x/y 坐标来计算新的 y/z 坐标,这显然是错误的。
我也想知道你的终止条件:
current[i] != 0
这没有错,但它会阻止您使用零坐标的任何顶点。相反,我建议使用一个额外的参数来显式传递顶点数。
我也会按顶点而不是按坐标旋转,这样更自然也更容易理解:
void rotate(float * current, int vertexCount, float a, float x, float y, float z)
{
float sina = sinf(a);
float cosa = cosf(a);
float rotateMatrix[9] =
{
x*x*(1 - cosa) + cosa, x*y*(1 - cosa) - z*sina, x*z*(1 - cosa) + y*sina,
y*x*(1 - cosa) + z*sina, y*y*(1 - cosa) + cosa, y*z*(1 - cosa) - x*sina,
z*x*(1 - cosa) - y*sina, z*y*(1 - cosa) + x*sina, z*z*(1 - cosa) + cosa
};
int i;
for (i = 0; i < vertexCount; ++i)
{
float* vertex = current + i * 3;
float x = rotateMatrix[0] * vertex[0] + rotateMatrix[1] * vertex[1] + rotateMatrix[2] * vertex[2];
float y = rotateMatrix[3] * vertex[0] + rotateMatrix[4] * vertex[1] + rotateMatrix[5] * vertex[2];
float z = rotateMatrix[6] * vertex[0] + rotateMatrix[7] * vertex[1] + rotateMatrix[8] * vertex[2];
vertex[0] = x;
vertex[1] = y;
vertex[2] = z;
}
}
您实现矩阵向量乘法的方式非常粗糙,而且 - 更重要的是 - 完全错误。
问题是您覆盖了您仍然需要的数据。因此,在第一次交互中,您有效地写入 current[0]
(并且您的 resultVertexList
指针根本没有帮助。它指向您的唯一一个数据副本,直接就地覆盖它. 在接下来的两次迭代中,将使用 current[0]
的新值,而不是原来的
我建议您简单地实现一个简单的 mat3 * vec3
函数,它可以很容易地在循环中调用,并且注意不要覆盖它仍然需要的数据。