gpt4 book ai didi

c++ - 光线追踪 - 光照方程

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:48:51 25 4
gpt4 key购买 nike

我正在尝试用 C++ 编写光线追踪器,但到目前为止的结果与我预期的不一样,所以我猜光照方程式中存在错误。这是我到目前为止所得到的:

Picture of my result. In the upper line what I've got, in the bottom line what I would like to get

我正在使用 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;
}

现在我的问题是:

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

    ray3f reflectionRay = ray3f(intersection.pos, -l + 2 * dot(l, normal)*normal);
    c += intersection.mat->kr*raytrace_ray(scene, reflectionRay);
  4. 从第二次测试图片来看,交叉口也有问题,但不知道是哪里。我还尝试以这种方式用逆向改变正常计算:

    auto normal = transform_normal_inverse(scene->camera->frame, surface->frame.z);

    但是我没有解决第二个测试也只得到了飞机的另一个倾斜度。这是我的交集代码(我只使用了四边形和球体):

    intersection3f intersect_surfaces(Scene* scene, ray3f ray) {
    auto intersection = intersection3f();

    float currentDistance = INFINITY;
    float t;

    // foreach surface
    for (Surface* surface : scene->surfaces) {
    // if it is a quad
    if (surface->isquad) {

    /// compute ray intersection (and ray parameter), continue if not hit
    auto normal = transform_normal(scene->camera->frame, surface->frame.z);

    if (dot(ray.d, normal) == 0) {
    continue;
    }
    t = dot(surface->frame.o - ray.e, normal)/dot(ray.d,normal);

    // check if computed param is within ray.tmin and ray.tmax
    if (t < ray.tmin or t > ray.tmax) continue;

    // check if this is the closest intersection, continue if not
    auto p = ray.eval(t);//Intersection point

    if (dist(ray.e, p) >= currentDistance) {
    continue;
    }

    currentDistance = dist(ray.e, p);

    // if hit, set intersection record values
    intersection.ray_t = t;
    intersection.pos = p;
    intersection.norm = normalize(ray.e - p);
    intersection.mat = surface->mat;
    intersection.hit = true;
    }
    // if it is a sphere
    else {
    // compute ray intersection (and ray parameter), continue if not hit
    auto a = lengthSqr(ray.d);
    auto b = 2 * dot(ray.d, ray.e - surface->frame.o);
    auto c = lengthSqr(ray.e - surface->frame.o) - surface->radius*surface->radius;
    auto det = b*b - 4 * a*c;

    if (det < 0) {
    continue;
    }

    float t1 = (-b - sqrt(det)) / (2 * a);
    float t2 = (-b + sqrt(det)) / (2 * a);

    // check if computed param is within ray.tmin and ray.tmax
    if (t1 >= ray.tmin && t1 <= ray.tmax) t = t1;
    else if (t2 >= ray.tmin && t2 <= ray.tmax) t = t2;
    else continue;

    auto p = ray.eval(t); //Intersection point

    // check if this is the closest intersection, continue if not
    if (dist(ray.e, p) > currentDistance) {
    continue;
    }

    currentDistance = dist(ray.e, p);

    // if hit, set intersection record values
    intersection.ray_t = t;
    intersection.pos = p;
    intersection.norm = normalize(ray.e - p);
    intersection.mat = surface->mat;
    intersection.hit = true;

    intersection.ray_t = 2;


    }
    }
    return intersection;
    }

提前致谢。

最佳答案

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

表面的环境颜色就像对象具有的最小颜色,即使它被另一个对象遮挡也是如此。基本上每个对象都有一种颜色,由 float (0 - 1) 或整数 (0 - 255) 表示。要应用 phong 模型的第一部分,您假设对象被遮蔽,因为光线不会到达对象的每一英寸。要应用环境光着色,您只需将环境系数(它是一个表面属性,通常在 0 到 1 之间)乘以对象的颜色。

现在我们需要检查对象是否被遮蔽。如果物体没有被遮蔽(并且只有这样),您需要应用 phong 模型的其他两个部分,因为它们仅在物体被光线照射时才相关。

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

我添加了一段代码摘录来指导您。我删掉了很多计算交点和反射光线的代码。我留下了评论以明确步骤。

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

如果您还没有听说过 http://scratchapixel.com ,那么你一定要检查一下。当我编写我的 raytracer 时,它对我有很大的帮助。注意:我不是专家,但我自己在空闲时间用 C++ 编写了一个 raytracer,所以我尝试分享我的经验,因为我遇到了与您的屏幕截图中相同的问题。

    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;

很抱歉这个问题的简短回答,但时间不早了,我也变得懒惰了。当我有更多时间时,我会再次入住。我希望我能帮上一点忙。

关于c++ - 光线追踪 - 光照方程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33054399/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com