光线追踪-照明方程 我试图在C++中写一个光线跟踪器,但是到目前为止的结果并不像我所期望的那样,所以我猜想光照方程式中有一个错误。 到目前为止,我得到的是:

光线追踪-照明方程 我试图在C++中写一个光线跟踪器,但是到目前为止的结果并不像我所期望的那样,所以我猜想光照方程式中有一个错误。 到目前为止,我得到的是:,c++,graphics,3d,raytracing,lighting,C++,Graphics,3d,Raytracing,Lighting,我使用的是Blinn(-Phong)模型,并假设所有灯光都是点光源。这是我的代码: vec3f raytrace_ray(Scene* scene, ray3f ray) { // get scene intersection auto intersection = intersect_surfaces(scene, ray); // if not hit, return background if (!intersection.hit) { return scene->back

我使用的是Blinn(-Phong)模型,并假设所有灯光都是点光源。这是我的代码:

vec3f raytrace_ray(Scene* scene, ray3f ray) {
// get scene intersection
auto intersection = intersect_surfaces(scene, ray);

// if not hit, return background
if (!intersection.hit) {
    return scene->background;
}

// accumulate color starting with ambient
vec3f c = zero3f;
c += scene->ambient*intersection.mat->kd;

//Add emission
c += intersection.mat->ke;

// foreach light
for (Light* light : scene->lights) {
    // compute light response
    auto lightRadiance = light->intensity / distSqr(light->frame.o, intersection.pos);
    if(lightRadiance == zero3f) continue;

    // compute light direction
    auto l = normalize(light->frame.o - intersection.pos);

    auto v = normalize(intersection.pos - ray.e);

    auto h = normalize(l+v); //bisector

    auto n = intersection.mat->n;
    auto normal = intersection.norm;

    // compute the material response (brdf*cos)
    auto brdf = intersection.mat->ks*pow(max(0.0f, dot(normal,h)), intersection.mat->n);

    // check for shadows and accumulate if needed
    auto shadowRay = ray3f(intersection.pos, l, 0.001f, length(light->frame.o - intersection.pos));

    float visibleTerm;
    auto shadowIntersect = intersect_surfaces(scene, shadowRay);
    if (shadowIntersect.hit) {
        visibleTerm = 0;
    }
    else {
        visibleTerm = 1;
    }

    //Accumulate
    c += lightRadiance*visibleTerm*(intersection.mat->kd + brdf)*abs(dot(normal, l));
}

// if the material has reflections
    // create the reflection ray
    // accumulate the reflected light (recursive call) scaled by the material reflection

// return the accumulated color∫
return c;
}
现在我的问题是:

  • 方程式哪里错了
  • 在上一次编辑中,我还添加了阴影,通过创建光线(光线构造函数的最后两个参数是tmin和tmax)并检查它是否击中了什么东西。如果是,我将visibileTerm设置为零(我还更新了屏幕截图)。我不确定这是否正确
  • 如何进一步添加反射和折射?我知道我必须递归调用这个函数,但首先我必须计算什么,用哪种方式?我尝试在for灯光循环中使用此代码进行反射,但在某些测试无限递归中,它不起作用:

    ray3f reflectionRay = ray3f(intersection.pos, -l + 2 * dot(l, normal)*normal);
    c += intersection.mat->kr*raytrace_ray(scene, reflectionRay);
    
  • 从图片的第二次测试来看,十字路口也有问题,但我不知道在哪里。我还试着用这种方法改变正常的计算:

    auto normal = transform_normal_inverse(scene->camera->frame, surface->frame.z);
    
    但是我只得到了飞机的另一个倾斜度,而没有解决第二次测试。这是我的交点代码(我只使用了四边形和球体):

    intersection3f intersect_曲面(场景*场景,光线3f){
    自动相交=相交3f();
    浮动电流距离=无穷大;
    浮动t;
    //前刀面
    用于(曲面*曲面:场景->曲面){
    //如果它是四边形
    如果(曲面->isquad){
    ///计算光线交点(和光线参数),如果未命中,则继续
    自动法线=变换_法线(场景->摄影机->帧、曲面->帧.z);
    if(点(光线d,法线)==0){
    继续;
    }
    t=点(表面->帧.o-射线e,法线)/点(射线d,法线);
    //检查计算的参数是否在ray.tmin和ray.tmax范围内
    如果(tray.tmax)继续;
    //检查这是否是最近的交叉口,如果不是,继续
    自动p=ray.eval(t);//交点
    if(距离(光线e,p)>=当前距离){
    继续;
    }
    当前距离=距离(光线e,p);
    //如果命中,则设置交叉点记录值
    交叉点.ray_t=t;
    交叉点位置=p;
    交叉点.norm=规格化(光线.e-p);
    intersection.mat=曲面->垫;
    intersection.hit=true;
    }
    //如果它是一个球体
    否则{
    //计算光线交点(和光线参数),如果未命中,则继续
    自动a=长度SQR(射线d);
    自动b=2*dot(ray.d,ray.e-surface->frame.o);
    自动c=长度SQR(光线.e-表面->帧.o-表面->半径*表面->半径;
    自动检测=b*b-4*a*c;
    如果(det<0){
    继续;
    }
    浮点数t1=(-b-sqrt(det))/(2*a);
    浮点数t2=(-b+sqrt(det))/(2*a);
    //检查计算的参数是否在ray.tmin和ray.tmax范围内
    如果(t1>=ray.tmin&&t1=ray.tmin&&t2当前距离){
    继续;
    }
    当前距离=距离(光线e,p);
    //如果命中,则设置交叉点记录值
    交叉点.ray_t=t;
    交叉点位置=p;
    交叉点.norm=规格化(光线.e-p);
    intersection.mat=曲面->垫;
    intersection.hit=true;
    交点.ray_t=2;
    }
    }
    折返交叉口;
    }
    

  • 提前感谢。

    关于phong着色模型:它是一个描述光在表面上散射的模型。 因此,每个曲面都有不同的属性,这些属性由环境、漫反射和镜面反射系数表示。 根据您拥有的表面,它们会有所不同(如玻璃、木材等)

    表面的环境色类似于对象的最小颜色,即使它被另一个对象遮挡。 基本上,每个对象都有一种颜色,由float(0-1)或int(0-255)表示。 若要应用phong模型的第一部分,假设对象已被遮挡,因为灯光不会到达对象的每一寸。 要应用环境光着色,只需将环境光系数(它是一个曲面属性,通常介于0和1之间)与对象的颜色相乘即可

    现在我们需要检查对象是否有阴影。如果对象未被遮挡(并且仅在此时),则需要应用phong模型的其他两个部分,因为它们仅在对象被灯光照射时才相关

    漫反射系数是衡量光线散射程度的指标。镜面反射成分是衡量反光度的指标。 有一些近似公式可以有效地计算这两个系数

    我从代码中添加了一个摘录来指导您。我截取了很多计算交点和反射光线的代码。 我留下评论是为了让步骤更清楚

    从屏幕截图的外观来看,似乎您忘记添加镜面反射组件

    如果你还没有听说过,那么你一定要去看看。当我写我的光线跟踪器时,这对我是一个很大的帮助。 注:我不是专家,但我自己写了一个在RayTraceC++在我的空闲时间,所以我试图分享我的经验,因为我遇到了同样的问题,张贴在您的截图。
        double ka = 0.1; //ambient coefficient
        double kd; //diffuse coefficient
        double ks; //specular coefficient
    
        /****** First handle ambient shading ******/
        Colour ambient = ka * objectColor; //ambient component
    
        Colour diffuse, specular; // automatically set to 0
        double brightness;
        localColour = ambient; //localColour is the current colour of the object
        /************ Next check wether the object is in shadow or light
        * do this by casting a ray from the obj and
        * check if there is an intersection with another obj ******/
        for(int i = 0; i < objSize; i++)
        {//iterate over all lights
            if(dynamic_cast<Light *>(objects[i])) //if object is a light
            {
                //for each light
                //create a Ray to light
                //its origin is the intersection point
                //its direction is the position of the light - intersection
            //check for an intersection with a light
            //if there is no intersection then we don't need to apply the specular and the diffuse components
                if(t_light < 0) //no intersect, which is quite impossible
                    continue;
    
                //then we check if that Ray intersects one object that is not a light
    
                            //we compute the distance to the object and compare it
                            //to the light distance, for each light seperately
                            //if it is smaller we know the light is behind the object
                            //--> shadowed by this light
    
                //we know if inersection is shadowed or not
                if(!shadowed)// if obj is not shadowed
                {
    //------->  //The important part. Adding the diffuse and the specular components.
                    rRefl = objects[index_nearObj]->calcReflectingRay(rShadow, intersect, normal); //reflected ray from light source, for ks
                    kd = maximum(0.0, (normal|rShadow.getDirection())); // calculate the diffuse coefficient
            //the max of 0 and the cosine of the angle between the direction of the light source and 
            //the surface normal at the intersection point
                    ks = pow(maximum(0.0, (r.getDirection()|rRefl.getDirection())), objects[index_nearObj]->getShiny()); //calc the specular component
            //the cosine of the angle between the incoming ray and the reflected ray to the power of a material property
                    diffuse = kd * objectColor; //diffuse colour
                    specular = ks * objects[i]->getColor(); //specular colour
                    brightness = 1 /(1 + t_light * DISTANCE_DEPENDENCY_LIGHT); 
            //Determines the brightness by how far the light source is apart from the object
            // 1/(1 + distance to light * parameter)... change the parameter to have a stronger or weaker distance dependency                
            localColour += brightness * (diffuse + specular); //ADD the diffuse and the specular components to the object
                }
            }
        }
    
    double ka=0.1//环境系数
    双kd//扩散系数
    双ks//镜面反射系数
    /******第一个处理环境光着色******/
    环境颜色=ka*对象颜色//环境分量
    颜色漫反射、镜面反射;//自动设置为0
    双亮度;
    本地颜色=环境颜色//LocalColor是对象的当前颜色
    /************接下来检查对象是否处于阴影或灯光中
    *通过从obj投射光线和
    *检查是否与另一个obj相交******/
    for(int i=0;i    double ka = 0.1; //ambient coefficient
        double kd; //diffuse coefficient
        double ks; //specular coefficient
    
        /****** First handle ambient shading ******/
        Colour ambient = ka * objectColor; //ambient component
    
        Colour diffuse, specular; // automatically set to 0
        double brightness;
        localColour = ambient; //localColour is the current colour of the object
        /************ Next check wether the object is in shadow or light
        * do this by casting a ray from the obj and
        * check if there is an intersection with another obj ******/
        for(int i = 0; i < objSize; i++)
        {//iterate over all lights
            if(dynamic_cast<Light *>(objects[i])) //if object is a light
            {
                //for each light
                //create a Ray to light
                //its origin is the intersection point
                //its direction is the position of the light - intersection
            //check for an intersection with a light
            //if there is no intersection then we don't need to apply the specular and the diffuse components
                if(t_light < 0) //no intersect, which is quite impossible
                    continue;
    
                //then we check if that Ray intersects one object that is not a light
    
                            //we compute the distance to the object and compare it
                            //to the light distance, for each light seperately
                            //if it is smaller we know the light is behind the object
                            //--> shadowed by this light
    
                //we know if inersection is shadowed or not
                if(!shadowed)// if obj is not shadowed
                {
    //------->  //The important part. Adding the diffuse and the specular components.
                    rRefl = objects[index_nearObj]->calcReflectingRay(rShadow, intersect, normal); //reflected ray from light source, for ks
                    kd = maximum(0.0, (normal|rShadow.getDirection())); // calculate the diffuse coefficient
            //the max of 0 and the cosine of the angle between the direction of the light source and 
            //the surface normal at the intersection point
                    ks = pow(maximum(0.0, (r.getDirection()|rRefl.getDirection())), objects[index_nearObj]->getShiny()); //calc the specular component
            //the cosine of the angle between the incoming ray and the reflected ray to the power of a material property
                    diffuse = kd * objectColor; //diffuse colour
                    specular = ks * objects[i]->getColor(); //specular colour
                    brightness = 1 /(1 + t_light * DISTANCE_DEPENDENCY_LIGHT); 
            //Determines the brightness by how far the light source is apart from the object
            // 1/(1 + distance to light * parameter)... change the parameter to have a stronger or weaker distance dependency                
            localColour += brightness * (diffuse + specular); //ADD the diffuse and the specular components to the object
                }
            }
        }
    
        Ray rRefl, rRefr; //reflected and refracted Ray
        Colour reflectionColour = finalColour, refractionColour = finalColour; //reflected and refrated objects colour;
    //initialize them to the background colour
        //if there is no intersection of the reflected ray,
    //then the backgroundcolour should be returned
        double reflectance = 0, transmittance = 0;
        //check if obj is reflective, and calc reflection
        if(object->isReflective && depth < MAX_TRACE_DEPTH)
        {
            //handle reflection
            rRefl = object->calcReflectingRay(r, intersect, normal);
            if(REFL_COLOUR_ADD)//if the reflected colour is added to the object's colour
            {
            reflectionColour = raytrace(rRefl, depth + 1);//trace the reflected ray
            reflectance = 1;
            }
            else   objectColor = raytrace(rRefl, depth + 1);//otherwise set the object's clolour to the reflected colour(eg: Glass)
    
        }
    
        if(object->isRefractive() && depth < MAX_TRACE_DEPTH)
        {
            //handle transmission
            rRefr = object->calcRefractingRay(r, intersect, normal, reflectance, transmittance);
            if(rRefr.getDirection() != NullVector) // ignore total inner refl
                refractionColour = raytrace(rRefr, depth + 1);//trace the refracted ray
        }
    
        //then calculate light ,shading and colour with the phong illumination model
    
        //in the end add the reflected and refracted colours
    
        finalColour = phongColour + transmittance * refractionColour + reflectance * reflectionColour;//Add phong, refraction and reflection
        //if transmittance is 0 the object will not let light pass through, if reflectance is 0 the object will not reflect
        return finalColour;