Light(灯光)

笑死,光线追踪终于有光了。

实际上是对一些常规的物体,让它发射出光线。

Emissive Materials(发光材质)

首先,我们来制作一种发光材料。我们需要添加一个发射函数(我们也可以将这个函数添加到hit_record中——这取决于设计偏好)。就像背景一样,它只告诉光线它是什么颜色,并且不进行反射。

class diffuse_light : public material{
public:
diffuse_light(shared_ptr<texture> tex) : tex(tex){}
diffuse_light(const color& emit) : tex(make_shared<solid_color>(emit)) {}
color emitted(double u,double v,const Point3& p){
    return tex->value(u,v,p);
}
private:
shared_ptr<texture> tex;
};

对于其它的材质,不具备发射光的能力,自然当光线打到这个物体上的时候,他们不应该有颜色的发聩(逆光路)。

class material{
public:
virtual ~material() = default;
virtual color emitted(double u,double v,const Point3& p) const{
    return color(0,0,0);
}
virtual bool scatter(
const Ray& r_in,const hit_record& rec,color& attenuation,Ray& scattered
) const {
    return false;
}
};

同时之前我们定义,当没有打到物体的时候,返回了一个颜色,理论上这里就像是背景在发光的意思,所以我们需要让背景为黑色。

color ray_color(const Ray& r,int depth,const hittable& world) const{
    if(depth <= 0 ){
        return color(0,0,0);
    }
    hit_record rec;
    if(world.hit(r,interval(0.001,infinity),rec)){
        color attenuation;
        Ray scattered;
        if(rec.mat->scatter(r,rec,attenuation,scattered)){
            return attenuation*(ray_color(scattered,depth-1,world));
        }
        return color(0,0,0);
    }
    double a=0.5*(1.0+r.direction().y());
    return (1.0-a)*color(1.0,1.0,1.0)+a*color(0.5,0.7,1.0);
}
class material{
public:
virtual ~material() = default;
virtual color emitted(double u,double v,const Point3& p) const{
    return color(0,0,0);
}
virtual bool scatter(
const Ray& r_in,const hit_record& rec,color& attenuation,Ray& scattered
) const {
    return false;
}
};

现在我们需要让背景为清一色的黑色

class camera{
public:
    double aspect_ratio=16.0/9.0;
    int    image_width=400;
    int    samples_per_pixel=10;
    int    max_depth=10;
    double vfov = 90;
    Point3 lookfrom = Point3(0,0,0);
    Point3 lookat = Point3(0,0,-1);
    vec3 vup = vec3(0,1,0);
    double defocus_angle = 0;
    double focus_dist = 10;
    color background;
hit_record rec;
if(world.hit(r,interval(0.001,infinity),rec)){ return background; }

同时我们的光线还需要判断,如果击中的是光源,那么只需要返回其emmit的颜色,如果击中的不是光源,那么就需要一路的往下的传播,同时还需要判断一个东西,就是有可能某些光源它不仅能发光还能继续发散光线出去。

color ray_color(const Ray& r,int depth,const hittable& world) const{
    if(depth <= 0 ){
        return color(0,0,0);
    }
    hit_record rec;
    if(!world.hit(r,interval(0.001,infinity),rec)){ return background; }
    color attenuation;
    Ray scattered;
    color color_from_emission = rec.mat->emitted(rec.u,rec.v,rec.p);
    if(!rec.mat->scatter(r,rec,attenuation,scattered)){
        return color_from_emission;
    }
    color color_from_scatter = attenuation * ray_color(scattered,depth-1,world);
    return color_from_emission + color_from_scatter;
    // if(world.hit(r,interval(0.001,infinity),rec)){
    //     color attenuation;
    //     Ray scattered;
    //     if(rec.mat->scatter(r,rec,attenuation,scattered)){
    //         return attenuation*(ray_color(scattered,depth-1,world));
    //     }
    //     return color(0,0,0);
    // }
    // double a=0.5*(1.0+r.direction().y());
    // return (1.0-a)*color(1.0,1.0,1.0)+a*color(0.5,0.7,1.0);
}
#include "util/rtweekend.h"
#include "util/sphere.h"
#include "util/camera.h"
#include "util/hittable.h"
#include "util/hittable_list.h"
#include "util/bvh.h"
#include "util/texture.h"
#include "util/quad.h"
void bouncing_spheres(){
    hittable_list world;
    shared_ptr<check_texture> check = make_shared<check_texture>(0.32,color(.2,.3,.1),color(0.9,0.9,0.9));
    auto material_ground = make_shared<lambertian>(check);
    world.add(make_shared<sphere>(Point3(0,-1000,0),1000,material_ground));

    for(int a =-11;a<11;a++){
        for(int b=-11;b<11;b++){
            double choose_mat = random_double();
            Point3 center(a+0.9*random_double(),0.2,b+0.9*random_double());
            if((center - Point3(4,0.2,0)).length() > 0.9){
                shared_ptr<material> sphere_material;
                if(choose_mat < 0.8){
                    //diffuse
                    color albedo = color::random() * color::random();
                    sphere_material = make_shared<lambertian>(albedo);
                    Point3 center2 = center+vec3(0,random_double(0,0.5),0);
                    world.add(make_shared<sphere>(center,center2,0.2,sphere_material));
                }
                else if(choose_mat < 0.95){
                    //metal
                    color albedo = color::random(0.5,1);
                    double fuzz = random_double(0,0.5);
                    sphere_material =make_shared<metal>(albedo,fuzz);
                    world.add(make_shared<sphere>(center,0.2,sphere_material));
                }
                else{
                    //glass
                    sphere_material = make_shared<dielectric>(1.5);
                    world.add(make_shared<sphere>(center,0.2,sphere_material));
                }
            }
        }
    }

    auto material1 = make_shared<dielectric>(1.50);
    world.add(make_shared<sphere>(Point3(0,1,0),1.0,material1));
    auto material2 = make_shared<lambertian>(color(0.4,0.2,0.1));
    world.add(make_shared<sphere>(Point3(-4,1,0),1.0,material2));
    auto material3 = make_shared<metal>(color(0.7,0.6,0.5),0.0);
    world.add(make_shared<sphere>(Point3(4,1,0),1.0,material3));

    // double R = std::cos(pi/4);
    // auto material_left = make_shared<lambertian>(color(0,0,1));
    // auto material_right=make_shared<lambertian>(color(1,0,0));
    // world.add(make_shared<sphere>(Point3(-R , 0 , -1), R, material_left));
    // world.add(make_shared<sphere>(Point3(R,0,-1),R,material_right));
    bvh_node bvh_root(world.objects,0,world.objects.size()-1);
    camera  cam;
    cam.background        = color(0.70, 0.80, 1.00);
    cam.aspect_ratio=16.0/9.0;
    cam.image_width = 1200;
    cam.samples_per_pixel=100;
    cam.max_depth=50;
    cam.vfov = 20;
    cam.lookfrom = Point3(13,2,3);
    cam.lookat = Point3(0,0,0);
    cam.vup = vec3(0,1,0);
    cam.defocus_angle = 0.6;
    cam.focus_dist=10.0;
    cam.render(bvh_root);

}
void checkered_sphere(){
    hittable_list world;
    auto checker = make_shared<check_texture>(0.32,color(.2,.3,.1),color(.9,.9,.9));
    world.add(make_shared<sphere>(Point3(0,-10,0),10,make_shared<lambertian>(checker)));
    world.add(make_shared<sphere>(Point3(0,10,0),10,make_shared<lambertian>(checker)));
    camera cam;
    cam.background        = color(0.70, 0.80, 1.00);
    cam.aspect_ratio = 16.0 / 9.0;
    cam.image_width = 400;
    cam.samples_per_pixel = 100;
    cam.max_depth = 50;
    cam.vfov = 20;
    cam.lookfrom = Point3(13,2,3);
    cam.lookat = Point3(0,0,0);
    cam.vup = vec3(0,1,0);
    cam.defocus_angle = 0;
    cam.render(world);
}
void earth(){
    hittable_list world;
    shared_ptr<image_texture> earth_texture = make_shared<image_texture>("../images/earthmap.jpg");
    shared_ptr<lambertian> earth_surface = make_shared<lambertian>(earth_texture);
    shared_ptr<sphere> globe = make_shared<sphere>(Point3(0,0,0),2,earth_surface);
    world.add(globe);
    camera cam;
    cam.background        = color(0.70, 0.80, 1.00);
    cam.aspect_ratio = 16.0 / 9.0;
    cam.image_width = 400;
    cam.samples_per_pixel = 100;
    cam.max_depth = 50;
    cam.vfov = 20;
    cam.lookfrom = Point3(0,0,12);
    cam.lookat = Point3(0,0,0);
    cam.vup = vec3(0,1,0);
    cam.defocus_angle = 0;
    cam.render(world);
}
void perlin_spheres(){
    hittable_list world;
    shared_ptr<noise_texture> pertex = make_shared<noise_texture>(4);
    world.add(make_shared<sphere>(Point3(0,-1000,0),1000,make_shared<lambertian>(pertex)));
    world.add(make_shared<sphere>(Point3(0,2,0),2,make_shared<lambertian>(pertex)));
    camera cam;
    cam.background        = color(0.70, 0.80, 1.00);
    cam.aspect_ratio      = 16.0 / 9.0;
    cam.image_width       = 400;
    cam.samples_per_pixel = 100;
    cam.max_depth         = 50;

    cam.vfov     = 20;
    cam.lookfrom = Point3(13,2,3);
    cam.lookat   = Point3(0,0,0);
    cam.vup      = vec3(0,1,0);

    cam.defocus_angle = 0;

    cam.render(world);
}
void quads(){
    hittable_list world;

    // Materials
    auto left_red     = make_shared<lambertian>(color(1.0, 0.2, 0.2));
    auto back_green   = make_shared<lambertian>(color(0.2, 1.0, 0.2));
    auto right_blue   = make_shared<lambertian>(color(0.2, 0.2, 1.0));
    auto upper_orange = make_shared<lambertian>(color(1.0, 0.5, 0.0));
    auto lower_teal   = make_shared<lambertian>(color(0.2, 0.8, 0.8));

    // Quads
    world.add(make_shared<quad>(Point3(-3,-2, 5), vec3(0, 0,-4), vec3(0, 4, 0), left_red));
    world.add(make_shared<quad>(Point3(-2,-2, 0), vec3(4, 0, 0), vec3(0, 4, 0), back_green));
    world.add(make_shared<quad>(Point3( 3,-2, 1), vec3(0, 0, 4), vec3(0, 4, 0), right_blue));
    world.add(make_shared<quad>(Point3(-2, 3, 1), vec3(4, 0, 0), vec3(0, 0, 4), upper_orange));
    world.add(make_shared<quad>(Point3(-2,-3, 5), vec3(4, 0, 0), vec3(0, 0,-4), lower_teal));
    camera cam;
    cam.background        = color(0.70, 0.80, 1.00);
    cam.aspect_ratio      = 1.0;
    cam.image_width       = 400;
    cam.samples_per_pixel = 100;
    cam.max_depth         = 50;

    cam.vfov     = 80;
    cam.lookfrom = Point3(0,0,9);
    cam.lookat   = Point3(0,0,0);
    cam.vup      = vec3(0,1,0);
    cam.defocus_angle = 0;
    cam.render(world);
}
int main(){
    perlin_spheres();
    return 0;
}

Turning Objects into Lights(光照物体)

void simple_light(){
    hittable_list world;
    auto pertex = make_shared<noise_texture>(4);
    world.add(make_shared<sphere>(Point3(0,-1000,0),1000,make_shared<lambertian>(pertex)));
    world.add(make_shared<sphere>(Point3(0,2,0),2,make_shared<lambertian>(pertex)));

    auto difflight = make_shared<diffuse_light>(color(4,4,4));
    world.add(make_shared<quad>(Point3(3,1,-2),vec3(2,0,0),vec3(0,2,0),difflight));
    camera cam;
    cam.aspect_ratio = 16.0 / 9.0;
    cam.image_width = 400;
    cam.samples_per_pixel = 100;
    cam.max_depth = 50;
    cam.background = color(0,0,0);
    cam.vfov = 20;
    cam.lookfrom = Point3(26,3,6);
    cam.lookat = Point3(0,2,0);
    cam.vup = vec3(0,1,0);
    cam.defocus_angle = 0;
    cam.render(world);
}
int main(){
    simple_light();
    return 0;
}

光线比(1,1,1)更亮(4,4,4)。这使得它足够亮,可以照亮物体。也可以尝试将一些球体变成光源。

auto difflight = make_shared<diffuse_light>(color(4,4,4));
world.add(make_shared<quad>(Point3(3,1,-2),vec3(2,0,0),vec3(0,2,0),difflight));

Creating an Empty “Cornell Box”("创建一个空的“康奈尔盒子”)

图形学的一个非常经典的盒子空间。这里的“康奈尔盒子”(Cornell Box)是一个在计算机图形学中广泛使用的测试模型,用于研究光线在不同材质表面的反射和折射效果。它通常由几个不同颜色的平面组成,并且包含一个光源,用来模拟光线在封闭空间中的传播和交互。

void cornell_box(){
    hittable_list world;
    auto red   = make_shared<lambertian>(color(.65, .05, .05));
    auto white = make_shared<lambertian>(color(.73, .73, .73));
    auto green = make_shared<lambertian>(color(.12, .45, .15));
    auto light = make_shared<diffuse_light>(color(15, 15, 15));
    world.add(make_shared<quad>(Point3(555,0,0),vec3(0,555,0),vec3(0,0,555),green));
    world.add(make_shared<quad>(Point3(0,0,0),vec3(0,555,0),vec3(0,0,555),red));
    world.add(make_shared<quad>(Point3(343,544,332),vec3(-130,0,0),vec3(0,0,-105),light));
    world.add(make_shared<quad>(Point3(0,0,0),vec3(555,0,0),vec3(0,0,555),white));
    world.add(make_shared<quad>(Point3(555,555,555),vec3(-555,0,0),vec3(0,0,-555),white));
    world.add(make_shared<quad>(Point3(0,0,555),vec3(555,0,0),vec3(0,555,0),white));
    camera cam;

    cam.aspect_ratio      = 1.0;
    cam.image_width       = 600;
    cam.samples_per_pixel = 200;
    cam.max_depth         = 50;
    cam.background        = color(0,0,0);

    cam.vfov     = 40;
    cam.lookfrom = Point3(278, 278, -800);
    cam.lookat   = Point3(278, 278, 0);
    cam.vup      = vec3(0,1,0);

    cam.defocus_angle = 0;

    cam.render(world);
}

这里灯的y坐标写下来了一点。

图片看起来有很多的噪声点,因为灯非常小,大多数的随机射线没有打到灯光上。就会是背景色。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的C++代码示例,使用VTK实现类似CloudCompare中的Sun Light灯光效果: ```cpp #include <vtkSmartPointer.h> #include <vtkPolyDataReader.h> #include <vtkPolyDataMapper.h> #include <vtkActor.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkLight.h> #include <vtkCamera.h> int main(int argc, char* argv[]) { if (argc != 2) { std::cerr << "Usage: " << argv[0] << " inputPolyDataFile" << std::endl; return EXIT_FAILURE; } const char* inputFilename = argv[1]; vtkSmartPointer<vtkPolyDataReader> reader = vtkSmartPointer<vtkPolyDataReader>::New(); reader->SetFileName(inputFilename); vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputConnection(reader->GetOutputPort()); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddActor(actor); vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); interactor->SetRenderWindow(renderWindow); vtkSmartPointer<vtkLight> light = vtkSmartPointer<vtkLight>::New(); light->SetLightTypeToSceneLight(); light->SetPosition(-1.0, 0.0, 0.0); light->SetFocalPoint(0.0, 0.0, 0.0); light->SetColor(1.0, 1.0, 1.0); light->SetIntensity(1.0); renderer->AddLight(light); vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New(); camera->SetPosition(0.0, 0.0, 1.0); camera->SetFocalPoint(0.0, 0.0, 0.0); renderer->SetActiveCamera(camera); renderWindow->Render(); interactor->Start(); return EXIT_SUCCESS; } ``` 这个示例代码将一个PolyData文件加载到一个Actor中,并在场景中添加了一个Sun Light灯光和一个摄像机。你可以根据自己的需要修改灯光和摄像机的参数来获得更好的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值