没有得到正确的阴影位置,基于 CPU 的光线追踪

Posted

技术标签:

【中文标题】没有得到正确的阴影位置,基于 CPU 的光线追踪【英文标题】:Not getting correct position of Shadows , CPU based Raytracing 【发布时间】:2019-10-04 01:23:56 【问题描述】:

我正在尝试在基于 CPU 的光线跟踪中计算阴影,但我没有得到准确位置的阴影, 我正在尝试设计著名的康奈尔盒子,

图中的球体也被不正确地着色,

我已经粘贴了整个代码。 我在场景中使用了 2 个球体和 10 个三角形, 我猜我的阴影追踪算法或正常计算有问题


class Figure
public:
    Vec3 position;
    Vec3 cl;
    Vec3 normal;

    Figure(void);
    Figure(Vec3 pos,Vec3 col,Vec3 Normal);
    virtual bool intersection(float* t,Vec3 origin,Vec3 direction);
    virtual Vec3 calculateNormal(Vec3 p0,float *intensity,Vec3* Diffusecolor,Vec3* Specular);
    virtual bool intersectionShadow(float* t,Vec3 origin,Vec3 direction);

;

Figure::Figure()
    position = Vec3(0,0,0);
    cl = Vec3(0,0,0);
    normal = Vec3(0,0,0);


Figure::Figure(Vec3 post, Vec3 coli,Vec3 Normal)
    position = post;
    cl = coli;
    normal = Normal;


bool Figure::intersection(float *t, Vec3 origin,Vec3 direction)
    return false;

Vec3 Figure::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular)
    return normal;

bool Figure::intersectionShadow(float *t, Vec3 origin, Vec3 direction)
    return false;


class Plane:public Figure
public:
    Vec3 planeNormal;

    Plane(void);
    Plane(Vec3 pos,Vec3 norm,Vec3 c);
    bool intersection(float *t, Vec3 origin, Vec3 direction);
    Vec3 Plane::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular);

                       ;
Plane::Plane(void)
    planeNormal=Vec3(0,0,0);

Plane::Plane(Vec3 pos,Vec3 norm,Vec3 c)
    position = pos;
    planeNormal = norm;
    cl = c;

bool Plane::intersection(float *t, Vec3 origin, Vec3 direction)
    float denom = planeNormal.dot(direction);
    if(abs(denom)<0.0001f)
        return false;
    
    else
        Vec3 p_or = position-origin;
        float res = p_or.dot(planeNormal)/denom;
        *t = res;
    


Vec3 Plane::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular)

    *intensity = 0;
    *Diffusecolor = Vec3(0.7, 0.7, 0.7);
    *Specular = cl;
    return planeNormal;



class Sphere:public Figure
 public:
    float radius;
    Sphere(void);
    Sphere(Vec3 pos,float rad,Vec3 col);
    bool intersection(float* t,Vec3 origin,Vec3 direction);
    Vec3 calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular);


;

Sphere::Sphere()
    position = Vec3(0,0,-2);
    radius = 0.3f;
    cl = Vec3(1.0,0,0);


Sphere::Sphere(Vec3 pos, float rad, Vec3 col)
    position = pos;
    radius = rad;
    cl = col;


bool Sphere::intersection(float *t, Vec3 origin,Vec3 direction)
    Vec3 oc = origin - position;
    float a = direction.dot(direction);
    float b = 2.0f * oc.dot(direction);
    float c = oc.dot(oc) - radius*radius;
    float discriminant = b*b - 4*a*c;
    if (discriminant < 0) 
        return false;
    
    else 
        float t0;
        t0 = std::max((-b + sqrt(discriminant) ) / (2.0f*a),(-b - sqrt(discriminant) ) / (2.0f*a));
        *t = t0;
        return true;
    


Vec3 Sphere::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular)
    *intensity = 50.0f;
    *Diffusecolor = cl;
    *Specular = Vec3(0.7f, 0.7f, 0.7);
    return (p0-position);



class Triangle:public Figure
public:

    Vec3 v0;
    Vec3 v1;
    Vec3 v2;
    Vec3 norm;
    Vec3 ed0,ed1;
    float u,v,w;

    Triangle(void);
    Triangle(Vec3 a,Vec3 b,Vec3 c,Vec3 col);
    bool intersection(float* t,Vec3 origin,Vec3 direction);
    bool intersectionShadow(float* t,Vec3 origin,Vec3 direction);
    Vec3 calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular);



;
Triangle::Triangle()
    v0 = Vec3(0,0,0);
    v1 = Vec3(0,0,0);
    v2 = Vec3(0,0,0);


Triangle::Triangle(Vec3 a, Vec3 b, Vec3 c, Vec3 col)
    v0 = a;
    v1 = b;
    v2 = c;
    cl = col;





bool Triangle::intersection(float *t, Vec3 origin,Vec3 direction)
    ed0 = v1-v0;
    ed1 = v2-v0;
    Vec3 r_o = origin-v0;
    Vec3 r_ed = direction.cross(ed1);
    u = r_o.dot(r_ed)/ed0.dot(r_ed);

    Vec3 r0_ed0 = r_o.cross(ed0);
    float rd_r0_ed0 = direction.dot(r0_ed0);
    v = rd_r0_ed0/ed0.dot(r_ed);
    float ed_r0_ed0 = ed1.dot(r0_ed0);
    float t0 = ed_r0_ed0/ed0.dot(r_ed);

    w = 1-u-v;

    if((u<0) || (u>1))
        return false;
    
    else if((v<0) || (u+v>1))
        return false;
    
    else 

        *t = t0;
        return true;
    


Vec3 Triangle::calculateNormal(Vec3 p0, float *intensity, Vec3 *Diffusecolor, Vec3 *Specular)

    *intensity = 0;
    *Diffusecolor = Vec3(0.7, 0.7, 0.7);
    *Specular = cl;

    //https://www.tjhsst.edu/~dhyatt/supercomp/n310.html
    Vec3 d1 = Vec3(v1.x()-v0.x(),v1.y()-v0.y(),v1.z()-v0.z());
    Vec3 d2 = Vec3(v2.x()-v1.x(),v2.y()-v1.y(),v2.z()-v1.z());
    Vec3 n = (d1.cross(d2));
    return n ;


bool Triangle::intersectionShadow(float* t,Vec3 origin,Vec3 direction)
return false;


using Colour = Vec3; // RGB Value
Colour red()  return Colour(1.0f, 0.0f, 0.0f); 
Colour white()  return Colour(1.0f, 1.0f, 1.0f); 
Colour black()  return Colour(0.0f, 0.0f, 0.0f); 

uchar BoundPixelValue(int shading)

    if (shading < 0) return 0;
    if (shading >= 255) return 255;
    return shading;

Vec3 scalar_multiply(Vec3 b,float v)
    return Vec3(b.x()*v,b.y()*v,b.z()*v);

int main(int, char**)
    Vec3 v0 = Vec3(-1.0f,-1.0f,-1.0f);
    Vec3 v1 = Vec3(-1.0f,-1.0f,-2.0f);
    Vec3 v2 = Vec3(-1.0f,1.0f,-1.0f);
    Vec3 v3 = Vec3(-1.0f,1.0f,-2.0f);
    Vec3 v4 = Vec3(1.0f,-1.0f,-1.0f);
    Vec3 v5 = Vec3(1.0f,-1.0f,-2.0f);
    Vec3 v6 = Vec3(1.0f,1.0f,-2.0f);
    Vec3 v7 = Vec3(1.0f,1.0f,-1.0f);
    Vec3 point_0 = Vec3();



    Figure* figurelist[12];
    //sphere
    figurelist[0]=new Sphere(Vec3(-0.2f,0.3f,-1.5f),0.3f,Vec3(1.000f, 0.196f, 0.000f));
    figurelist[1]=new Sphere(Vec3(0.5f,-0.3f,-1.3f),0.4f,Vec3(0.054f, 0.172f, 0.847f));

    //floor
    figurelist[2]=new Triangle(v1,v0,v2,Vec3(0.752f, 0.713f, 0.823f));
    figurelist[3]=new Triangle(v2,v3,v1,Vec3(0.752f, 0.713f, 0.823f));
    //left
    figurelist[4]=new Triangle(v5,v1,v0,Vec3(0.749f, 0.105f, 0.101f));
    figurelist[5]=new Triangle(v0,v4,v5,Vec3(0.749f, 0.105f, 0.101f));
    //back
    figurelist[6]=new Triangle(v5,v1,v3,Vec3(0.925f, 0.639f, 0.454f));
    figurelist[7]=new Triangle(v3,v6,v5,Vec3(0.925f, 0.639f, 0.454f));
    //right
    figurelist[8]=new Triangle(v7,v6,v3,Vec3(0.415f, 0.733f, 0.164f));
    figurelist[9]=new Triangle(v3,v2,v7,Vec3(0.415f, 0.733f, 0.164f));
    //top
    figurelist[10]=new Triangle(v5,v6,v7,Vec3(0.925f, 0.639f, 0.454f));
    figurelist[11]=new Triangle(v7,v4,v5,Vec3(0.925f, 0.639f, 0.454f));










    int wResolution = 640;
    int hResolution = 480;
    // #rows = hResolution, #cols = wResolution
    Image<Colour> image(hResolution, wResolution);
    Vec3 llc=  Vec3(-1.0,-1.0,-1.0);
    Vec3 urc = Vec3(1.0,1.0,-1.0);
    Vec3 CameraPos = Vec3(0,0,0);
    Vec3 sphere_amient(0.960, 0.968, 0.811);



    for (int row = 0; row < image.rows(); ++row) 
        for (int col = 0; col < image.cols(); ++col) 
            float u = float(row+0.5)/float(image.rows());
            float v = float(col+0.5)/float(image.cols());

            Vec3 PointPos = Vec3(llc(0) + u * (urc.x() - llc.x()), llc.y() + v * (urc.y() - llc.y()), -1);
            Vec3 direction=(PointPos-CameraPos).normalized();



            float minT = INFINITY;
            int figureHit = -1;

            float t0=0.0;


            for (int k =0;k<sizeof (figurelist)/sizeof (figurelist[0]);k++)
                bool hit = figurelist[k]->intersection(&t0,CameraPos,direction);
                if(hit && t0<minT)
                    minT = t0;
                    figureHit = k;
                
                if(figureHit != -1)
                    Vec3 p0 = CameraPos+minT*direction;
                    Vec3 lightSource=Vec3(2.0f,0.0f,-1.0f);
                    float lightIntensity=0.7f;
                    Vec3 diffuseColour(0.0f, 0.392f, 0.0f);
                    Vec3 specularColour(0.0,0.0,0.0);
                    float intensity = 0;

                    //ambient Colour for shadows
                    Vec3 AmbientColour = figurelist[figureHit]->cl.cross(Vec3(0.1f, 0.1f, 0.1f));

                    //Diffuse Lightning
                    Vec3 light_direction = (lightSource-p0).normalized();
                    Vec3 Normal = Vec3(figurelist[figureHit]->calculateNormal(p0,&intensity,&diffuseColour,&specularColour)).normalized();
                    float diffuse_term =std::max(0.0f,light_direction.dot(Normal));
                    Vec3 diffuse = (diffuseColour*lightIntensity*diffuse_term);

                    //Specular Highlights
                    Vec3 e = (p0-CameraPos).normalized();
                    Vec3 R = (e+light_direction).normalized();
                    float dot2 = std::max(0.0f,R.dot(Normal));
                    Vec3 specular = specularColour*lightIntensity*pow(dot2,intensity);



                    Vec3 shadow_direction = p0-light_direction;
                    float bias = 0.001f;
                    Vec3 p_shadow = p0+Normal;



              //For hard shadows


                    int lightHit = -1;
                    for ( int i=0;i<sizeof (figurelist)/sizeof (figurelist[0]);i++)

                        bool lightRayHit = figurelist[i]->intersection(&t0,p_shadow,shadow_direction);
                        if(lightRayHit && t0<minT)
                            minT = t0;
                            lightHit = i;
                        
                    
                        if(lightHit != -1)
                                image(row,col) = AmbientColour;
                            
                        else
                            image(row,col) = [enter image description here][1]specular+diffuse;
                        

                
             else 
                 image(row,col)=white();
             


         

    
 

 bmpwrite("../../out.bmp", image);
 imshow(image);

 return EXIT_SUCCESS;

附件是我得到的输出图像。这是应用阴影跟踪后的图像:

还有没有阴影的原图:

【问题讨论】:

【参考方案1】:

应该是这个问题:

Vec3 shadow_direction = p0-light_direction;

p0 是一个位置,light_direction 是一个方向,因此,结果是一个position。但是你把它作为一个方向。而是这样做:

Vec3 shadow_direction = -light_direction;

还有

float bias = 0.001f;
Vec3 p_shadow = p0+Normal;

应该是

Vec3 p_shadow = p0 + bias * Normal;

【讨论】:

我试过这个,但仍然没有得到阴影,可能是我的代码/算法中的其他问题

以上是关于没有得到正确的阴影位置,基于 CPU 的光线追踪的主要内容,如果未能解决你的问题,请参考以下文章

为啥在我的光线追踪器中计算阴影和反射时会丢失细节

GAMES202 笔记-实时光线追踪

光线追踪 - 反射

2 追踪光线=》2.1

计算在基于瓦片的游戏中哪些瓦片被点亮(“光线追踪”)

为啥我们使用 CPU 而不是 GPU 进行光线追踪?