问题三十:《Ray Tracing In One Weekend》封面图形生成

本文详细介绍了使用光线追踪技术创建封面图片的过程,包括场景搭建、材质设置、相机参数调整等关键步骤,并分享了多种测试结果及改进方案。

30.1 封面图片

先完成封面图片。

Code如下:

----------------------------------------------main.cpp------------------------------------------

main.cpp

    hitable *random_scene() {
        int n = 500;
        hitable **list = new hitable *[n+1];
/*定义一个包含n+1个元素的数组,数组的每个元素是指向hitable对象的指针。然后将数组的指针赋值给list。所以,list是指针的指针。*/
        list[0] = new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5)));
/*先创建一个中心在(0,-1000,0)半径为1000的超大漫射球,将其指针保存在list的第一个元素中。*/
        int i = 1;
        for (int a = -11; a < 11; a++) {
            for (int b = -11; b < 11; b++) {
/*两个for循环中会产生(11+11)*(11+11)=484个随机小球*/
                float choose_mat = (rand()%(100)/(float)(100));
/*产生一个(0,1)的随机数,作为设置小球材料的阀值*/
                vec3 center(a+0.9*(rand()%(100)/(float)(100)), 0.2, 
b+0.9*(rand()%(100)/(float)(100)));
/*” a+0.9*(rand()%(100)/(float)(100))”配合[-11,11]产生(-11,11)之间的随机数,而不是[-11,11)之间的22个整数。使得球心的x,z坐标是(-11,11)之间的随机数*/
                if ((center-vec3(4,0.2,0)).length() > 0.9) {
/*避免小球的位置和最前面的大球的位置太靠近*/
                    if (choose_mat < 0.8) {     //diffuse
/*材料阀值小于0.8,则设置为漫反射球,漫反射球的衰减系数x,y,z都是(0,1)之间的随机数的平方*/
                        list[i++] = new sphere(center, 0.2,
                		new lambertian(vec3(
(rand()%(100)/(float)(100))*(rand()%(100)/(float)(100)),
(rand()%(100)/(float)(100))*(rand()%(100)/(float)(100)),
(rand()%(100)/(float)(100))*(rand()%(100)/(float)(100)))));
                    }
                    else if (choose_mat < 0.95) {
/*材料阀值大于等于0.8小于0.95,则设置为镜面反射球,镜面反射球的衰减系数x,y,z及模糊系数都是(0,1)之间的随机数加一再除以2*/
                        list[i++] = new sphere(center, 0.2,
                                    new metal(vec3(0.5*(1+(rand()%(100)/(float)(100))),
0.5*(1+(rand()%(100)/(float)(100))),
0.5*(1+(rand()%(100)/(float)(100)))),
0.5*(1+(rand()%(100)/(float)(100))));
                    }
                    else {
/*材料阀值大于等于0.95,则设置为介质球*/
                        list[i++] = new sphere(center, 0.2, new dielectric(1.5));
                    }
                }
            }
        }

        list[i++] = new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5));
        list[i++] = new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)));
        list[i++] = new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));
/*定义三个大球*/
        return new hitable_list(list, i);
    }

书上坑爹的是,没有给出相机参数,而是直接贴了张结果图。坑爹啊!我是根据三个大球在画面中的相对位置,调了一组参数,得到的图片和参考图片近似吧。

 

       vec3 lookfrom(11,2,3);

       vec3 lookat(0,0.6,0);

       float dist_to_focus = (lookfrom - lookat).length();

       float aperture = 0.0;

       camera cam(lookfrom, lookat, vec3(0,1,0), 20, float(nx)/float(ny), aperture,0.7*dist_to_focus);


调试过程中的几张图片

       vec3 lookfrom(11,1,4);

       vec3 lookat(0,1,0);

       float dist_to_focus = (lookfrom - lookat).length();

       float aperture = 0.0;

       camera cam(lookfrom, lookat, vec3(0,1,0), 20, float(nx)/float(ny), aperture,0.7*dist_to_focus);


        vec3 lookfrom(11,1,3.5);

       vec3 lookat(0,0.6,0);

       float dist_to_focus = (lookfrom - lookat).length();

       float aperture = 0.0;

       camera cam(lookfrom, lookat, vec3(0,1,0), 20, float(nx)/float(ny), aperture,0.7*dist_to_focus);



改变/增加大球后的code如下:

----------------------------------------------main.cpp------------------------------------------

main.cpp

    hitable *random_scene() {
        int n = 500;
        hitable **list = new hitable *[n+1];
        list[0] = new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5)));
        int i = 1;
        for (int a = -11; a < 11; a++) {
            for (int b = -11; b < 11; b++) {
                float choose_mat = (rand()%(100)/(float)(100));
                vec3 center(a+0.9*(rand()%(100)/(float)(100)), 0.2, 
b+0.9*(rand()%(100)/(float)(100)));
                if ((center-vec3(4,0.2,0)).length() > 0.9) {
                    if (choose_mat < 0.8) {     //diffuse
                        list[i++] = new sphere(center, 0.2,
                		new lambertian(vec3(
(rand()%(100)/(float)(100))*(rand()%(100)/(float)(100)),
(rand()%(100)/(float)(100))*(rand()%(100)/(float)(100)),
(rand()%(100)/(float)(100))*(rand()%(100)/(float)(100)))));
                    }
                    else if (choose_mat < 0.95) {
                        list[i++] = new sphere(center, 0.2,
                                    new metal(vec3(0.5*(1+(rand()%(100)/(float)(100))),
0.5*(1+(rand()%(100)/(float)(100))),
0.5*(1+(rand()%(100)/(float)(100)))),
0.5*(1+(rand()%(100)/(float)(100))));
                    }
                    else {
                        list[i++] = new sphere(center, 0.2, new dielectric(1.5));
                    }
                }
            }
        }

        list[i++] = new sphere(vec3(-6, 2, -6), 2.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));
        list[i++] = new sphere(vec3(6, 2, -6), 2.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));

        list[i++] = new sphere(vec3(0, 2, -7), 2.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));

        list[i++] = new sphere(vec3(-2, 1, -4), 1.0, new dielectric(1.5));
        list[i++] = new sphere(vec3(2, 1, -4), 1.0, new dielectric(1.5));
        list[i++] = new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5));

        list[i++] = new sphere(vec3(-4, 1, -2), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)));
        list[i++] = new sphere(vec3(4, 1, -2), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)));

        list[i++] = new sphere(vec3(-6, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));
        list[i++] = new sphere(vec3(6, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));

        return new hitable_list(list, i);
    }

 不同的观测角度,得到不同的几张图片:

       vec3 lookfrom(0,1,8);

       vec3 lookat(0,3,-8);

       float dist_to_focus = (lookfrom - lookat).length();

       float aperture = 0.0;

       camera cam(lookfrom, lookat, vec3(0,1,0), 40, float(nx)/float(ny), aperture,0.7*dist_to_focus);


        vec3 lookfrom(0,8,8);

       vec3 lookat(0,0,-4);

       float dist_to_focus = (lookfrom - lookat).length();

       float aperture = 0.0;

       camera cam(lookfrom, lookat, vec3(0,1,0), 40, float(nx)/float(ny), aperture,0.7*dist_to_focus);


30.2 What next?

1. Lights. You can do this explicitly, bysending shadow rays to lights. Or it can be done implicitly by making someobjects emit light.

2. biasing scattered rays toward them, andthen downweighting those rays to cancel out the bias. Both work. I am in theminority in favoring the latter approach.

3. Triangles. Most cool models are intriangles form. The model I/O is the worst and almost everybody tries to getsomebody else’s code to do this.

4. Surface textures. This lets you pasteimages on like wall paper. Pretty easy and a good thing to do.

5. Solid textures. Ken Perlin has his codeonline. Andrew Kensler has some very cool info at his blog.

6. Volumes and media. Cool stuff and willchallenge your software architecture. I favor making volumes have the hitableinterface and probabilistically have intersections based on density. Yourrendering code doesn’t even have to know it has volumes with that method.

7. Parallelism. Run N copies of your codeon N cores with different random seeds. Average the N runs. This averaging canalso be done hierarchically where N/2 pairs can be averaged to get N/4 images,and pairs of those can be averaged. That method of parallelism should extendwell into the thousands of cores with very little coding.

 

30.3 补充封面图片标准答案

在第二本书《ray tracing the next week》(还没买,只能试读一章)的第一章中看到了这个标准答案。

       vec3 lookfrom(13,2,3);

       vec3 lookat(0,0,0);

       float dist_to_focus = (lookfrom - lookat).length();

       float aperture = 0.0;

       camera cam(lookfrom, lookat, vec3(0,1,0), 20, float(nx)/float(ny), aperture, 0.7*dist_to_focus);


其实之前已经调到(11,2,3)(0,0.6,0)已经很接近了。

 

 

------------------------------------《Ray TracingIn One Weekend》学习完毕------------------------------------



Ray Tracing光线追踪)是一种在计算机图形学中使用的技术,用于生成高度逼真的图像。它通过跟踪光线从视点开始的路径,来模拟光在场景中的运动,计算出光线与物体的交点以及光线在经过物体时的反射、折射等效果,并最终生成图像。 以下是光线追踪的基本步骤[^1]: 1. 从相机位置发出一条光线。 2. 确定该光线与场景中物体的交点。 3. 计算该交点处的光照强度,包括直接光照和间接光照。 4. 根据物体的表面特性,计算反射或折射光线的方向和强度。 5. 递归计算反射或折射光线的路径,直到达到最大递归深度或光线不再与物体相交。 6. 将所有光线的颜色值组合在一起,得到最终的图像。 下面是一个简单的 Python 代码示例,演示了如何使用 Pygame 和 PyOpenGL 库实现简单的光线追踪效果[^2]: ```python import pygame from OpenGL.GL import * # 初始化 Pygame 和 PyOpenGL pygame.init() display = (800, 600) pygame.display.set_mode(display, pygame.DOUBLEBUF | pygame.OPENGL) # 设置相机位置和方向 glMatrixMode(GL_MODELVIEW) glLoadIdentity() gluLookAt(0, 0, 0, 0, 0, -1, 0, 1, 0) # 设置场景中的物体 glColor3f(1, 1, 1) glBegin(GL_TRIANGLES) glVertex3f(-1, -1, -5) glVertex3f(1, -1, -5) glVertex3f(0, 1, -5) glEnd() # 定义光线追踪函数 def raytrace(x, y): glReadBuffer(GL_BACK) color = glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT) return color # 创建主循环 while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() # 绘制场景和光线 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glBegin(GL_LINES) glVertex3f(0, 0, 0) glVertex3f(0, 0, -5) glEnd() # 调用光线追踪函数 x, y = pygame.mouse.get_pos() w, h = display color = raytrace(w - x, h - y) # 输出光线追踪结果 print("Color at (%d, %d): %s" % (x, y, color)) # 更新 Pygame 显示窗口 pygame.display.flip() ```
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值