剪辑中的 3D 透视投影坐标 space
3D perspective projection coordinates in clip space
我正在尝试 3D 投影几个点。据我所知,在将投影矩阵应用于顶点后,该顶点最终出现在剪辑 space 中。此时如果 -w < x,y,z < w 顶点可见,否则它在可见区域之外,需要被裁剪。我遇到的问题是我无法将顶点设置为 -w < x,y,z < w。我一定是做错了什么,但我不知道是什么。我尽量坚持 openGL 约定(坐标系等)。请看看这个SSCCE。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define DEG2RAD 0.01745329f
// multiplies two matrices
void m3d_matrixMul(const float matrix1[], const float matrix2[], float destination[])
{
int i, row, col;
for (i = 15; i >= 0; i--)
{
row = i % 4;
col = i / 4 * 4;
destination[i] = matrix1[row] * matrix2[col] + matrix1[row + 4] * matrix2[col + 1] + matrix1[row + 8] * matrix2[col + 2] + matrix1[row + 12] * matrix2[col + 3];
}
}
// multiplies matrix with vector/vertex
void m3d_matVecMul(const float matrix[], const float vector[], float destination[])
{
float x = vector[0], y = vector[1], z = vector[2], w = vector[3];
destination[0] = x * matrix[0] + y * matrix[4] + z * matrix[8] + w * matrix[12];
destination[1] = x * matrix[1] + y * matrix[5] + z * matrix[9] + w * matrix[13];
destination[2] = x * matrix[2] + y * matrix[6] + z * matrix[10] + w * matrix[14];
destination[3] = x * matrix[3] + y * matrix[7] + z * matrix[11] + w * matrix[15];
}
// creates the projection matrix (column major)
void m3d_getFrustum(float left, float right, float bottom, float top, float near, float far, float matrix[])
{
matrix[0] = 2.0f * near / (right - left);
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 2.0f * near / (top - bottom);
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = (right + left) / (right - left);
matrix[9] = (top + bottom) / (top - bottom);
matrix[10] = -(far + near) / (far - near);
matrix[11] = -1.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = -2.0f * far * near / (far - near);
matrix[15] = 0.0f;
}
void m3d_getPerspective(float vfov, float aspect, float near, float far, float matrix[])
{
float height = tanf(vfov * 0.5f * DEG2RAD) * near;
float width = aspect * height;
m3d_getFrustum(-width, width, -height, height, near, far, matrix);
}
void m3d_getIdentity(float matrix[])
{
matrix[0] = 1.0f;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 1.0f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = 0.0f;
matrix[9] = 0.0f;
matrix[10] = 1.0f;
matrix[11] = 0.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;
}
void m3d_translate(float x, float y, float z, float matrix[])
{
matrix[12] += x;
matrix[13] += y;
matrix[14] += z;
}
int main(void)
{
float vertex[4] = {0.5f, 0.5f, 0.5f, 1.0f};
float modelView[16];
float projection[16];
float mvp[16];
char buffer[4];
// initialize model-view matrix with identity matrix
m3d_getIdentity(modelView);
// add z-translation to model-view matrix
m3d_translate(0.0f, 0.0f, -2.0f, modelView);
// get perspective projection matrix
m3d_getPerspective(45.0f, 800.0f / 600.0f, -0.5f, -1000.0f, projection);
// fuse projection and model-view matrix into one matrix
m3d_matrixMul(projection, modelView, mvp);
// apply model-view-projection matrix to vertex
m3d_matVecMul(mvp, vertex, vertex);
printf("Projected vertex: %f, %f, %f, %f\n", vertex[0], vertex[1], vertex[2], vertex[3]);
printf("Press ENTER to quit.");
fgets(buffer, 4, stdin);
return EXIT_SUCCESS;
// Projected vertex: 0.905330, 1.207107, 2.502001, 1.500000
}
提前致谢。
好的,我又看了一遍你的代码,我认为你的投影矩阵计算有问题。我已将 m3d_getPerspective
方法替换为 gluPerspective 中的定义,并添加了 printMatrix (pm) 方法。对于某些示例点,结果现在似乎是合理的(下面的代码)。
我没有具体发现你的错误,因为我不确定你为什么要这样做 - 解决方法。一个提示可能是您似乎使用了 tanf
而我现在使用了余切线,但这不是我认为的完整问题。此外,将 near 和 far 设置为负值并不直观,因为它们应该代表距离。你的乘法似乎没问题,我没有意识到你一开始是将顶点复制到 x,y,z,w。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define DEG2RAD 0.01745329f
void m3d_matrixMul(const float matrix1[], const float matrix2[], float destination[])
{
int i, row, col;
for (i = 15; i >= 0; i--)
{
row = i % 4;
col = i / 4 * 4;
destination[i] = matrix1[row] * matrix2[col] + matrix1[row + 4] * matrix2[col + 1] + matrix1[row + 8] * matrix2[col + 2] + matrix1[row + 12] * matrix2[col + 3];
}
}
void m3d_matVecMul(const float matrix[], const float vector[], float destination[])
{
float x = vector[0], y = vector[1], z = vector[2], w = vector[3];
destination[0] = x * matrix[0] + y * matrix[4] + z * matrix[8] + w * matrix[12];
destination[1] = x * matrix[1] + y * matrix[5] + z * matrix[9] + w * matrix[13];
destination[2] = x * matrix[2] + y * matrix[6] + z * matrix[10] + w * matrix[14];
destination[3] = x * matrix[3] + y * matrix[7] + z * matrix[11] + w * matrix[15];
}
//not used anymore
void m3d_getFrustum(float left, float right, float bottom, float top, float near, float far, float matrix[])
{
matrix[0] = 2.0f * near / (right - left);
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 2.0f * near / (top - bottom);
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = (right + left) / (right - left);
matrix[9] = (top + bottom) / (top - bottom);
matrix[10] = -(far + near) / (far - near);
matrix[11] = -1.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = -2.0f * far * near / (far - near);
matrix[15] = 0.0f;
}
void m3d_getPerspective(float vfov, float aspect, float near, float far, float matrix[])
{
float f = 1.0f/tanf(vfov * 0.5f * DEG2RAD);
matrix[0] = f/aspect;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = 0;
matrix[9] = 0;
matrix[10] = (near+far)/(near-far);
matrix[11] = -1;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 2.0f * far * near / (near-far);
matrix[15] = 0.0f;
}
void m3d_getIdentity(float matrix[])
{
matrix[0] = 1.0f;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 1.0f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = 0.0f;
matrix[9] = 0.0f;
matrix[10] = 1.0f;
matrix[11] = 0.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;
}
void m3d_translate(float x, float y, float z, float matrix[])
{
matrix[12] += x;
matrix[13] += y;
matrix[14] += z;
}
void pm(float* m) {
printf("%f, %f, %f, %f\n", m[0], m[4], m[8], m[12]);
printf("%f, %f, %f, %f\n", m[1], m[5], m[9], m[13]);
printf("%f, %f, %f, %f\n", m[2], m[6], m[10], m[14]);
printf("%f, %f, %f, %f\n", m[3], m[7], m[11], m[15]);
printf("\n");
}
int main(void)
{
//float vertex[4] = {0.0f, 0.0f, -1000.0f, 1.0f}; //point at center & far
//float vertex[4] = {0.0f, 0.0f, -0.5f, 1.0f}; //point at center & near
float vertex[4] = {(800.0f/600.0f)*1.0f, 1.0f, -2.0f, 1.0f}; //point at one quater of the x and y range
float modelView[16];
float projection[16];
float mvp[16];
char buffer[4];
m3d_getIdentity(modelView);
pm(modelView);
m3d_translate(0.0f, 0.0f, 0.0f, modelView);
pm(modelView);
m3d_getPerspective(90.0f, 800.0f / 600.0f, 0.5f, 1000.0f, projection);
pm(projection);
m3d_matrixMul(projection, modelView, mvp);
pm(mvp);
m3d_matVecMul(mvp, vertex, vertex);
printf("Projected vertex: %f, %f, %f, %f\n", vertex[0], vertex[1], vertex[2], vertex[3]);
printf("Press ENTER to quit.");
fgets(buffer, 4, stdin);
return EXIT_SUCCESS;
}
我正在尝试 3D 投影几个点。据我所知,在将投影矩阵应用于顶点后,该顶点最终出现在剪辑 space 中。此时如果 -w < x,y,z < w 顶点可见,否则它在可见区域之外,需要被裁剪。我遇到的问题是我无法将顶点设置为 -w < x,y,z < w。我一定是做错了什么,但我不知道是什么。我尽量坚持 openGL 约定(坐标系等)。请看看这个SSCCE。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define DEG2RAD 0.01745329f
// multiplies two matrices
void m3d_matrixMul(const float matrix1[], const float matrix2[], float destination[])
{
int i, row, col;
for (i = 15; i >= 0; i--)
{
row = i % 4;
col = i / 4 * 4;
destination[i] = matrix1[row] * matrix2[col] + matrix1[row + 4] * matrix2[col + 1] + matrix1[row + 8] * matrix2[col + 2] + matrix1[row + 12] * matrix2[col + 3];
}
}
// multiplies matrix with vector/vertex
void m3d_matVecMul(const float matrix[], const float vector[], float destination[])
{
float x = vector[0], y = vector[1], z = vector[2], w = vector[3];
destination[0] = x * matrix[0] + y * matrix[4] + z * matrix[8] + w * matrix[12];
destination[1] = x * matrix[1] + y * matrix[5] + z * matrix[9] + w * matrix[13];
destination[2] = x * matrix[2] + y * matrix[6] + z * matrix[10] + w * matrix[14];
destination[3] = x * matrix[3] + y * matrix[7] + z * matrix[11] + w * matrix[15];
}
// creates the projection matrix (column major)
void m3d_getFrustum(float left, float right, float bottom, float top, float near, float far, float matrix[])
{
matrix[0] = 2.0f * near / (right - left);
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 2.0f * near / (top - bottom);
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = (right + left) / (right - left);
matrix[9] = (top + bottom) / (top - bottom);
matrix[10] = -(far + near) / (far - near);
matrix[11] = -1.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = -2.0f * far * near / (far - near);
matrix[15] = 0.0f;
}
void m3d_getPerspective(float vfov, float aspect, float near, float far, float matrix[])
{
float height = tanf(vfov * 0.5f * DEG2RAD) * near;
float width = aspect * height;
m3d_getFrustum(-width, width, -height, height, near, far, matrix);
}
void m3d_getIdentity(float matrix[])
{
matrix[0] = 1.0f;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 1.0f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = 0.0f;
matrix[9] = 0.0f;
matrix[10] = 1.0f;
matrix[11] = 0.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;
}
void m3d_translate(float x, float y, float z, float matrix[])
{
matrix[12] += x;
matrix[13] += y;
matrix[14] += z;
}
int main(void)
{
float vertex[4] = {0.5f, 0.5f, 0.5f, 1.0f};
float modelView[16];
float projection[16];
float mvp[16];
char buffer[4];
// initialize model-view matrix with identity matrix
m3d_getIdentity(modelView);
// add z-translation to model-view matrix
m3d_translate(0.0f, 0.0f, -2.0f, modelView);
// get perspective projection matrix
m3d_getPerspective(45.0f, 800.0f / 600.0f, -0.5f, -1000.0f, projection);
// fuse projection and model-view matrix into one matrix
m3d_matrixMul(projection, modelView, mvp);
// apply model-view-projection matrix to vertex
m3d_matVecMul(mvp, vertex, vertex);
printf("Projected vertex: %f, %f, %f, %f\n", vertex[0], vertex[1], vertex[2], vertex[3]);
printf("Press ENTER to quit.");
fgets(buffer, 4, stdin);
return EXIT_SUCCESS;
// Projected vertex: 0.905330, 1.207107, 2.502001, 1.500000
}
提前致谢。
好的,我又看了一遍你的代码,我认为你的投影矩阵计算有问题。我已将 m3d_getPerspective
方法替换为 gluPerspective 中的定义,并添加了 printMatrix (pm) 方法。对于某些示例点,结果现在似乎是合理的(下面的代码)。
我没有具体发现你的错误,因为我不确定你为什么要这样做 - 解决方法。一个提示可能是您似乎使用了 tanf
而我现在使用了余切线,但这不是我认为的完整问题。此外,将 near 和 far 设置为负值并不直观,因为它们应该代表距离。你的乘法似乎没问题,我没有意识到你一开始是将顶点复制到 x,y,z,w。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define DEG2RAD 0.01745329f
void m3d_matrixMul(const float matrix1[], const float matrix2[], float destination[])
{
int i, row, col;
for (i = 15; i >= 0; i--)
{
row = i % 4;
col = i / 4 * 4;
destination[i] = matrix1[row] * matrix2[col] + matrix1[row + 4] * matrix2[col + 1] + matrix1[row + 8] * matrix2[col + 2] + matrix1[row + 12] * matrix2[col + 3];
}
}
void m3d_matVecMul(const float matrix[], const float vector[], float destination[])
{
float x = vector[0], y = vector[1], z = vector[2], w = vector[3];
destination[0] = x * matrix[0] + y * matrix[4] + z * matrix[8] + w * matrix[12];
destination[1] = x * matrix[1] + y * matrix[5] + z * matrix[9] + w * matrix[13];
destination[2] = x * matrix[2] + y * matrix[6] + z * matrix[10] + w * matrix[14];
destination[3] = x * matrix[3] + y * matrix[7] + z * matrix[11] + w * matrix[15];
}
//not used anymore
void m3d_getFrustum(float left, float right, float bottom, float top, float near, float far, float matrix[])
{
matrix[0] = 2.0f * near / (right - left);
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 2.0f * near / (top - bottom);
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = (right + left) / (right - left);
matrix[9] = (top + bottom) / (top - bottom);
matrix[10] = -(far + near) / (far - near);
matrix[11] = -1.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = -2.0f * far * near / (far - near);
matrix[15] = 0.0f;
}
void m3d_getPerspective(float vfov, float aspect, float near, float far, float matrix[])
{
float f = 1.0f/tanf(vfov * 0.5f * DEG2RAD);
matrix[0] = f/aspect;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = 0;
matrix[9] = 0;
matrix[10] = (near+far)/(near-far);
matrix[11] = -1;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 2.0f * far * near / (near-far);
matrix[15] = 0.0f;
}
void m3d_getIdentity(float matrix[])
{
matrix[0] = 1.0f;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = 0.0f;
matrix[5] = 1.0f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = 0.0f;
matrix[9] = 0.0f;
matrix[10] = 1.0f;
matrix[11] = 0.0f;
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
matrix[15] = 1.0f;
}
void m3d_translate(float x, float y, float z, float matrix[])
{
matrix[12] += x;
matrix[13] += y;
matrix[14] += z;
}
void pm(float* m) {
printf("%f, %f, %f, %f\n", m[0], m[4], m[8], m[12]);
printf("%f, %f, %f, %f\n", m[1], m[5], m[9], m[13]);
printf("%f, %f, %f, %f\n", m[2], m[6], m[10], m[14]);
printf("%f, %f, %f, %f\n", m[3], m[7], m[11], m[15]);
printf("\n");
}
int main(void)
{
//float vertex[4] = {0.0f, 0.0f, -1000.0f, 1.0f}; //point at center & far
//float vertex[4] = {0.0f, 0.0f, -0.5f, 1.0f}; //point at center & near
float vertex[4] = {(800.0f/600.0f)*1.0f, 1.0f, -2.0f, 1.0f}; //point at one quater of the x and y range
float modelView[16];
float projection[16];
float mvp[16];
char buffer[4];
m3d_getIdentity(modelView);
pm(modelView);
m3d_translate(0.0f, 0.0f, 0.0f, modelView);
pm(modelView);
m3d_getPerspective(90.0f, 800.0f / 600.0f, 0.5f, 1000.0f, projection);
pm(projection);
m3d_matrixMul(projection, modelView, mvp);
pm(mvp);
m3d_matVecMul(mvp, vertex, vertex);
printf("Projected vertex: %f, %f, %f, %f\n", vertex[0], vertex[1], vertex[2], vertex[3]);
printf("Press ENTER to quit.");
fgets(buffer, 4, stdin);
return EXIT_SUCCESS;
}