C 三维到二维坐标问题
我正试图从头开始用C语言编写一个非常基本的光线跟踪器。我在从空间中的3d点获取2d坐标时遇到了一些问题 我能够轻松准确地拍摄相机光线,在屏幕上很好地绘制模型。现在我想为屏幕上的模型定义一个边界框,这样我就可以快速移动到与渲染过程无关的图像区域 当物体离相机越近时,我得到的最接近的结果越好。当我把相机向后推(递增cam->pos.z)时,我的边界框开始变得很遥远 我在stackoverflow上看到了十几个不同的公式,我一直在试验/应用这些公式,但都没有成功。如果有人能看看我在做什么,并提供一些建议/纠正,那就太好了 我的坐标是y向上的 我用于获取光线方向的函数(似乎正在工作,但认为可能相关): 三维到二维坐标版本(工作不太好): 编辑:试图利用一些矩阵C 三维到二维坐标问题,c,coordinates,raytracing,C,Coordinates,Raytracing,我正试图从头开始用C语言编写一个非常基本的光线跟踪器。我在从空间中的3d点获取2d坐标时遇到了一些问题 我能够轻松准确地拍摄相机光线,在屏幕上很好地绘制模型。现在我想为屏幕上的模型定义一个边界框,这样我就可以快速移动到与渲染过程无关的图像区域 当物体离相机越近时,我得到的最接近的结果越好。当我把相机向后推(递增cam->pos.z)时,我的边界框开始变得很遥远 我在stackoverflow上看到了十几个不同的公式,我一直在试验/应用这些公式,但都没有成功。如果有人能看看我在做什么,并提供一些建
void matrix_projection(double ***m, double fov,
double aspect,double znear, double zfar)
{
double xymax = znear * tan(fov * M_PI / 360);
double ymin = -xymax;
double xmin = -xymax;
double width = xymax - xmin;
double height = xymax - ymin;
double depth = zfar - znear;
double q = -(zfar + znear) / depth;
double qn = -2 * (zfar * znear) / depth;
double w = 2 * znear / width;
w = w / aspect;
double h = 2 * znear / height;
(*m)[0][0] = w; (*m)[1][0] = 0; (*m)[2][0] = 0; (*m)[3][0] = 0;
(*m)[0][1] = 0; (*m)[1][1] = h; (*m)[2][1] = 0; (*m)[3][1] = 0;
(*m)[0][2] = 0; (*m)[1][2] = 0; (*m)[2][2] = q; (*m)[3][2] = qn;
(*m)[0][3] = 0; (*m)[1][3] = 0; (*m)[2][3] = -1; (*m)[3][3] = 0;
}
//projection_matrix * modelview_matrix * world_coordinates
void matrix_multiply(double ***result, double ***m1, int r1,
int c1, double ***m2, int c2)
{
int i, j, k;
for(i=0; i<r1; ++i)
for(j=0; j<c2; ++j)
for(k=0; k<c1; ++k)
{
(*result)[i][j] += ((*m1)[i][k]) * ((*m2)[k][j]);
}
}
void matrix_allocate(double ***matrix, int rows, int cols)
{
int x, y;
*matrix = (double**) malloc(sizeof(double *) * rows);
for (x=0; x < rows; x++) {
(*matrix)[x] = malloc(sizeof(double) * cols);
for(y=0; y < cols; y++) {
(*matrix)[x][y] = 0.0;
}
}
}
Coordinate coord_fromVector(Vector *v, Vector *cam_pos, int width, int height) {
Coordinate screen;
double hwidth = ((double)width) / 2;
double hheight = ((double)height) / 2;
double aspect = hwidth / hheight;
double **proj;
matrix_allocate(&proj, 4, 4);
double **model;
matrix_allocate(&model, 4, 4);
double **vmatrix;
matrix_allocate(&vmatrix, 1, 4);
vmatrix[0][1] = v->x;
vmatrix[0][2] = v->y;
vmatrix[0][3] = v->z;
vmatrix[0][4] = 1;
matrix_projection(&proj, 55, aspect, 1.0, 2000.0);
model[0][0] = model[1][1] = model[2][2] = model[3][3] = 1;
model[3][0] = cam_pos->x;
model[3][1] = cam_pos->y;
model[3][2] = cam_pos->z;
double **proj_model;
matrix_allocate(&proj_model, 4, 4);
matrix_multiply(&proj_model, &proj, 4, 4, &model, 4) ;
double **proj_model_v;
matrix_allocate(&proj_model_v, 1, 4);
matrix_multiply(&proj_model_v, &proj_model, 4, 4, &vmatrix, 1);
screen.x = proj_model_v[0][0] / proj_model_v[0][3];
screen.y = proj_model_v[0][1] / proj_model_v[0][3];
return screen;
}
void matrix_投影(双***m,双视野,
双纵横比、双znear、双zfar)
{
双xymax=znear*tan(视场*M_PI/360);
双ymin=-xymax;
双xmin=-xymax;
双倍宽度=xymax-xmin;
双倍高度=xymax-ymin;
双深度=zfar-znear;
双q=-(zfar+znear)/深度;
双qn=-2*(zfar*znear)/深度;
双w=2*Z线/宽度;
w=w/方面;
双h=2*Z耳/高;
(*m)[0][0]=w;(*m)[1][0]=0;(*m)[2][0]=0;(*m)[3][0]=0;
(*m)[0][1]=0;(*m)[1][1]=h;(*m)[2][1]=0;(*m)[3][1]=0;
(*m)[0][2]=0;(*m)[1][2]=0;(*m)[2][2]=q;(*m)[3][2]=qn;
(*m)[0][3]=0;(*m)[1][3]=0;(*m)[2][3]=1;(*m)[3][3]=0;
}
//投影矩阵*模型视图矩阵*世界坐标
空矩阵乘以(双***结果,双***m1,整数r1,
内部c1,双***平方米,内部c2)
{
int i,j,k;
对于(i=0;iz;
vmatrix[0][4]=1;
矩阵投影(和proj,55,aspect,1.02000.0);
模型[0][0]=模型[1][1]=模型[2][2]=模型[3][3]=1;
模型[3][0]=凸轮位置->x;
模型[3][1]=凸轮位置->y;
模型[3][2]=凸轮位置->z;
双**项目模型;
矩阵分配(项目模型,4,4);
矩阵乘法(&proj_模型,&proj,4,4,&model,4);
双**项目型号v;
矩阵分配(项目模型v,1,4);
矩阵乘法(&proj_模型v,&proj_模型,4,4,&vmatrix,1);
screen.x=proj_model_v[0][0]/proj_model_v[0][3];
screen.y=proj_model_v[0][1]/proj_model_v[0][3];
返回屏幕;
}
不幸的是,在这一阶段还有很长的路要走。我建议使用与图形库中使用的方法相同的方法(特别是OpenGL的GLU,它有完善的矩阵构造文档)。它记录下来,你可以算出光线的方向。基本上,光线从
winZ=0
向正winZ
方向移动。我不知道什么是“三维坐标到二维坐标”应该可以。你是在尝试透视投影吗?是的。或多或少。当我将模型解析到内存中时,我注意到我加载的模型的3d边界框是什么。我希望将它们应用到各自的屏幕坐标,并使用它们跳过图像中不需要渲染/光线跟踪的部分。您是否使用投影矩阵等典型的计算机图形学方法?如果是,请参见。您可以使用那里的win{X,Y,Z}
方程来帮助您。model
=模型视图矩阵,proj
=投影矩阵,view
是视口信息(整数(X,Y,宽度,高度)
——通常是(0,0,窗口宽度,窗口高度)
)。我使用的是你上面看到的。我没有使用OpenGL,是的,我已经看到了所有这些页面。如果我知道如何将这些网站中包含的信息应用到我上面看到的内容,我就不会问这个问题了。
Coordinate coord_fromVector(Vector *v, Vector *cam_pos, int width, int height) {
Coordinate screen;
double hwidth = ((double)width) / 2;
double hheight = ((double)height) / 2;
double x_3D = v->x - cam_pos->x;
double y_3D = v->y - cam_pos->y;
double z_3D = v->z - cam_pos->z;
screen.x = hwidth + (x_3D / z_3D) * hwidth;
screen.y = hheight - (y_3D / z_3D) * hheight;
/* aspect ratio is commented out as its moving the box off screen */
/*
double aspect = screen.resolution.width / screen.resolution.height;
if (aspect > 1.0) {
screen.x /= aspect;
} else {
screen.y *= aspect;
}
*/
return screen;
}
void matrix_projection(double ***m, double fov,
double aspect,double znear, double zfar)
{
double xymax = znear * tan(fov * M_PI / 360);
double ymin = -xymax;
double xmin = -xymax;
double width = xymax - xmin;
double height = xymax - ymin;
double depth = zfar - znear;
double q = -(zfar + znear) / depth;
double qn = -2 * (zfar * znear) / depth;
double w = 2 * znear / width;
w = w / aspect;
double h = 2 * znear / height;
(*m)[0][0] = w; (*m)[1][0] = 0; (*m)[2][0] = 0; (*m)[3][0] = 0;
(*m)[0][1] = 0; (*m)[1][1] = h; (*m)[2][1] = 0; (*m)[3][1] = 0;
(*m)[0][2] = 0; (*m)[1][2] = 0; (*m)[2][2] = q; (*m)[3][2] = qn;
(*m)[0][3] = 0; (*m)[1][3] = 0; (*m)[2][3] = -1; (*m)[3][3] = 0;
}
//projection_matrix * modelview_matrix * world_coordinates
void matrix_multiply(double ***result, double ***m1, int r1,
int c1, double ***m2, int c2)
{
int i, j, k;
for(i=0; i<r1; ++i)
for(j=0; j<c2; ++j)
for(k=0; k<c1; ++k)
{
(*result)[i][j] += ((*m1)[i][k]) * ((*m2)[k][j]);
}
}
void matrix_allocate(double ***matrix, int rows, int cols)
{
int x, y;
*matrix = (double**) malloc(sizeof(double *) * rows);
for (x=0; x < rows; x++) {
(*matrix)[x] = malloc(sizeof(double) * cols);
for(y=0; y < cols; y++) {
(*matrix)[x][y] = 0.0;
}
}
}
Coordinate coord_fromVector(Vector *v, Vector *cam_pos, int width, int height) {
Coordinate screen;
double hwidth = ((double)width) / 2;
double hheight = ((double)height) / 2;
double aspect = hwidth / hheight;
double **proj;
matrix_allocate(&proj, 4, 4);
double **model;
matrix_allocate(&model, 4, 4);
double **vmatrix;
matrix_allocate(&vmatrix, 1, 4);
vmatrix[0][1] = v->x;
vmatrix[0][2] = v->y;
vmatrix[0][3] = v->z;
vmatrix[0][4] = 1;
matrix_projection(&proj, 55, aspect, 1.0, 2000.0);
model[0][0] = model[1][1] = model[2][2] = model[3][3] = 1;
model[3][0] = cam_pos->x;
model[3][1] = cam_pos->y;
model[3][2] = cam_pos->z;
double **proj_model;
matrix_allocate(&proj_model, 4, 4);
matrix_multiply(&proj_model, &proj, 4, 4, &model, 4) ;
double **proj_model_v;
matrix_allocate(&proj_model_v, 1, 4);
matrix_multiply(&proj_model_v, &proj_model, 4, 4, &vmatrix, 1);
screen.x = proj_model_v[0][0] / proj_model_v[0][3];
screen.y = proj_model_v[0][1] / proj_model_v[0][3];
return screen;
}