C 我的光线跟踪器中看起来像颗粒状的球体

C 我的光线跟踪器中看起来像颗粒状的球体,c,opengl,raytracing,C,Opengl,Raytracing,我想写一个简单的光线跟踪器。最后一张图片应该是这样的:我已经读了一些关于它的东西,下面是我正在做的事情: create an empty image (to fill each pixel, via ray tracing) for each pixel [for each row, each column] create the equation of the ray emanating from our pixel trace() ray: if ray intersects SP

我想写一个简单的光线跟踪器。最后一张图片应该是这样的:我已经读了一些关于它的东西,下面是我正在做的事情:

 create an empty image (to fill each pixel, via ray tracing)
 for each pixel [for each row, each column]
 create the equation of the ray emanating from our pixel
 trace() ray:
 if ray intersects SPHERE
 compute local shading (including shadow determination)
 return color;
现在,场景数据如下:它将半径为1的灰色球体设置为(0,0,-3)。它在原点设置一个白色光源

 2
 amb: 0.3 0.3 0.3
 sphere
 pos: 0.0 0.0 -3.0
 rad: 1
 dif: 0.3 0.3 0.3
 spe: 0.5 0.5 0.5
 shi: 1
 light
 pos: 0 0 0
 col: 1 1 1
我的看起来很奇怪:

//check ray intersection with the sphere
boolean intersectsWithSphere(struct point rayPosition, struct point rayDirection,    Sphere sp,float* t){

//float a = (rayDirection.x * rayDirection.x) + (rayDirection.y * rayDirection.y) +(rayDirection.z * rayDirection.z);
// value for a is 1 since rayDirection vector is normalized
double radius = sp.radius;
double xc = sp.position[0];
double yc =sp.position[1];
double zc =sp.position[2];

double xo = rayPosition.x;
double yo = rayPosition.y;
double zo = rayPosition.z;

double xd = rayDirection.x;
double yd = rayDirection.y;
double zd = rayDirection.z;

double b = 2 * ((xd*(xo-xc))+(yd*(yo-yc))+(zd*(zo-zc)));
double c = (xo-xc)*(xo-xc) + (yo-yc)*(yo-yc) + (zo-zc)*(zo-zc) - (radius * radius);
float D = b*b + (-4.0f)*c;

//ray does not intersect the sphere
if(D < 0 ){
    return false;
}

D = sqrt(D);
float t0 = (-b - D)/2 ;
float t1 = (-b + D)/2;

//printf("D=%f",D);
//printf(" t0=%f",t0);
//printf(" t1=%f\n",t1);

if((t0 > 0) && (t1 > 0)){
    *t = min(t0,t1);
    return true;
}
else {
    *t = 0;
    return false;
}

调用
trace()
的代码如下所示:

void draw_scene()
{
//Aspect Ratio
double a = WIDTH / HEIGHT;
double angel = tan(M_PI * 0.5 * fov/ 180);
ray[0].x = 0.0;
ray[0].y = 0.0;
ray[0].z = 0.0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
unsigned int x,y;
float sx, sy;
for(x=0;x < WIDTH;x++)
{
    glPointSize(2.0); 
    glBegin(GL_POINTS);
    for(y=0;y < HEIGHT;y++)
    {
        sx = (((x + 0.5) / WIDTH) * 2.0 ) - 1;
        sy = (((y + 0.5) / HEIGHT) * 2.0 ) - 1;;
        sx  = sx * angel * a;
        sy = sy * angel;
        //set ray direction
        ray[1].x = sx;
        ray[1].y = sy;
        ray[1].z = -1;
        normalizedRayDirection[0] = normalize(ray[1]);
        unsigned char* color = trace(ray[0],normalizedRayDirection[0],spheres);
        unsigned char  x1 = color[0] * 255;
        unsigned char  y1 = color[1] * 255;
        unsigned char  z1 = color[2] * 255;
        plot_pixel(x,y,x1 %256,y1%256,z1%256);
    }
   glEnd();
   glFlush();
 }
}
void draw_场景()
{
//纵横比
双a=宽度/高度;
双角度=tan(μPI*0.5*fov/180);
射线[0],x=0.0;
射线[0],y=0.0;
射线[0],z=0.0;
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
无符号整数x,y;
浮子sx,sy;
对于(x=0;x

代码/理解可能会有很多很多问题。

您这样做的可能原因是什么(在
跟踪(…)
的非阴影分支中):

您还可以注释掉前两个计算,因为您将每个计算的结果写入同一个组件。我想你可能是想这样做的:

V[0].x = - rayDirection.x;
V[0].y = - rayDirection.y;
V[0].z = - rayDirection.z;

也就是说,您还应该避免使用
GL_POINT
原语来覆盖2x2像素的四边形。点原语不能保证为正方形,OpenGL实现不需要支持除1.0以外的任何大小。实际上,大多数支持1.0-~64.0,但
glDrawPixels(…)
是一种更好的写入2x2像素的方法,因为它跳过了基本体组装和上述限制。无论如何,您在本例中使用的是立即模式,因此
glRasterPos(…)
glDrawPixels(…)
仍然是一种有效的方法。

您这样做的可能原因是什么(在
跟踪(…)
的非阴影分支中):

您还可以注释掉前两个计算,因为您将每个计算的结果写入同一个组件。我想你可能是想这样做的:

V[0].x = - rayDirection.x;
V[0].y = - rayDirection.y;
V[0].z = - rayDirection.z;

也就是说,您还应该避免使用
GL_POINT
原语来覆盖2x2像素的四边形。点原语不能保证为正方形,OpenGL实现不需要支持除1.0以外的任何大小。实际上,大多数支持1.0-~64.0,但
glDrawPixels(…)
是一种更好的写入2x2像素的方法,因为它跳过了基本体组装和上述限制。无论如何,在本例中,您使用的是立即模式,因此
glRasterPos(…)
glDrawPixels(…)
仍然是一种有效的方法。

看起来您正在实现公式,但最后偏离了本文的方向

首先,文章警告说D&b的价值可能非常接近,因此-b+D得到的数字非常有限。他们提出了另一种选择

另外,您正在测试t0和t1是否都大于0。这并不一定是真的,你可以击中球体,你可以在里面(虽然你显然不应该在你的测试场景)


最后,我将在开始时添加一个测试,以确认方向向量已规范化。在我的渲染器中,我不止一次地把这个问题搞砸了。

看起来你在实现这个公式,但你最终偏离了文章的方向

首先,文章警告说D&b的价值可能非常接近,因此-b+D得到的数字非常有限。他们提出了另一种选择

另外,您正在测试t0和t1是否都大于0。这并不一定是真的,你可以击中球体,你可以在里面(虽然你显然不应该在你的测试场景)


最后,我将在开始时添加一个测试,以确认方向向量已规范化。在我的渲染器中,我已经不止一次地把这个问题搞砸了。

我没有花时间去理解你所有的代码,而且我肯定不是一个图形专家,但我相信你遇到的问题被称为“表面痤疮”。在这种情况下,这可能是因为阴影光线与对象本身相交。我在代码中所做的是将epsilon*hitPoint.normal添加到阴影光线原点。这将有效地使光线稍微远离对象,因此它们不会相交


我用的epsilon值是
1.19209290*10^-7的平方根,因为这是一个叫做
epsilon
的常数的平方根,这个常数是用我使用的特定语言定义的。

我没有花时间理解你所有的代码,而且我肯定不是一个图形专家,但我相信你的问题被称为“表面痤疮”。在这种情况下,这可能是因为阴影光线与对象本身相交。我在代码中所做的是将epsilon*hitPoint.normal添加到阴影光线原点。这将有效地使光线稍微远离对象,因此它们不会相交


我使用的epsilon值是
1.19209290*10^-7
的平方根,因为这是一个名为
epsilon
的常数的平方根,该常数是用我使用的特定语言定义的。

如果有命中,请尝试打印黑色,如果没有则打印白色。因此,我们可以查看结果并从中获取结果。此外,不要尝试使用
GL_POINTS
原语
V[0].x = - rayDirection.x;
V[0].y = - rayDirection.y;
V[0].z = - rayDirection.z;