[RT in One Weekend Series 13] Where Next? (번역)

목차: Series 1: Index and Overview (Link)
이전 글: Series 12: Defocus Blur (Link)

먼저 Random 하게 많은 Sphere(구)를 그려서 이번 글에 사용할 표지 이미지를 만들어본다. 아래 코드 1은 Random 하게 많은 구를 그리기 위한 Main 코드이다.

코드 1: 많은 수의 구를 그리기 위한 Main 코드

#include <iostream>
#include <fstream>
#include "mkray.h"
#include "mkhitablelist.h"
#include "float.h"
#include "mksphere.h"
#include "mkcamera.h"
#include "mkmaterial.h"

using namespace std;

vec3 color(const ray &r, hitable *world, int depth){
    hitRecord rec;
    if(world->hit(r, 0.001, MAXFLOAT, rec)){
        ray scattered;
        vec3 attenuation;
        if(depth < 50 && rec.matPtr->scatter(r, rec, attenuation, scattered)){
            return attenuation * color(scattered, world, depth + 1);
        }
        else{
            return vec3(0, 0, 0);
        }
    }
    else{
        vec3 unitDirection = unitVector(r.direction());
        float t = 0.5 * (unitDirection.y() + 1.0);
        return (1.0 - t)*vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0);
    }
}

//MK: 코드 1-1 여러개의 구를 그리기 위해서 Random하게 구를 생성하는 함수 코드 
hitable *randomScene(){
	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 chooseMat = drand48();
					vec3 center(a + 0.9 * drand48(), 0.2, b + 0.9 * drand48());
					if((center - vec3(4, 0.2, 0)).length() > 0.9){
							if(chooseMat < 0.8){
									list[i++] = new sphere(center, 0.2, new lambertian(vec3(drand48() * drand48(), drand48() * drand48(), drand48() * drand48())));
							}
							else if(chooseMat < 0.95){
									list[i++] =  new sphere(center, 0.2, 
													new metal(vec3(0.5*(1 + drand48()), 0.5*(1+drand48()), 0.5 *(1 + drand48())), 0.5 * drand48()));
							}
							else{
									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 hitableList(list, i);

}

int main(){
    int nx = 1200;
    int ny = 800;
    int ns = 10;
    string fileName = "Ch12_5.ppm";
    ofstream writeFile(fileName.data());
    if(writeFile.is_open()){
        writeFile.flush();
        writeFile << "P3\n" << nx << " " << ny << "\n255\n";
//MK: 코드 1-2 Random 하게 많은 구를 생성
	hitable *world = randomScene();
	vec3 lookfrom(13, 2, 3);
	vec3 lookat(0, 0, 0);
	float diskToFocus = (lookfrom - lookat).length();
	float aperture = 0.1;
        camera cam(lookfrom, lookat, vec3(0, 1, 0), 20, float(nx)/float(ny), aperture, diskToFocus);
        for(int j = ny - 1; j >= 0; j--){
            for(int i = 0; i < nx; i++){
                vec3 col(0.0, 0.0, 0.0);
                for(int s = 0; s < ns; s++){
                    float u = float(i + drand48()) / float(nx);
                    float v = float(j + drand48()) / float(ny);
                    ray r = cam.getRay(u, v);
                    col += color(r, world, 0);
                }
                col /= float(ns);
                col = vec3( sqrt(col[0]), sqrt(col[1]), sqrt(col[2]) );
                int ir = int(255.99 * col[0]);
                int ig = int(255.99 * col[1]);
                int ib = int(255.99 * col[2]);
                writeFile << ir << " " << ig << " " << ib << "\n";
            }
        }
        writeFile.close();
    }
    return 0;
}

위 코드를 실행하면 아래 그림 1과 같은 결과 이미지를 확인 할 수 있다 (뭔가 모르게 멋진 그림이다).

그림 1: 여러개의 구를 그린 결과 이미지

그림 1에서 Glass 구는 공중에 떠 있는 것처럼 보인다. 해당 부분은 버그가 아니라고 한다. 실제로 우리가 Glass 형태의 구를 본 적이 없어서 그렇다고 한다. 추가로 큰 Glass 구 아래에 있는 다른 구들은 Glass 구가 Ray를 굴절시키므으로 많은 Light를 받게 된다 (다른 큰 구는 Light를 차단함).

출처 1에서 제공하는 모든 코드를 작성하였다. 해당 글을 기반으로 추가로 할 수 있는 작업을 정리하였다.

  1. Lights: 특정 물체(Object)가 빛을 방출하는 등의 추가적인 구현
  2. Biasing Scattered Rays: 산란하는 Ray를 구현
  3. Triangle: 다양한 모델(Triangle로 구성된)을 그릴 수 있도록 구현
  4. Surface Textures: Wall Paper와 같은 그림을 물체에 추가할 수 있도록 구현
  5. Solid Textures: (추가 설명이 없음)
  6. Volumes and Media: Density에 따라 Ray의 Hit 여부를 결정하는 코드 구현 (해당 부분은 정확히 어떤 의미인지 잘 모르겠음)
  7. Parallelism: 병렬화 (출처 2에 CUDA를 사용한 병렬화 코드 설명이 있다)

MK: 드디어 Weekend 시리지를 마무리했다. 책 제목에 Weekend가 있어서 쉽게 마무리 할 수 있을 거로 생각했는데 거의 5개월이 넘게 걸린 것 같다. Weekend 다음 시리즈가 있음으로 다음 부분도 추가로 번역을 하면서 공부를 할 계획이다. 추가로 출처 2에 제공되는 CUDA 병렬화도 번역해볼 예정이다.

출처

  1. http://www.realtimerendering.com/raytracing/Ray%20Tracing%20in%20a%20Weekend.pdf
  2. https://devblogs.nvidia.com/accelerated-ray-tracing-cuda/
  3. http://www.jiniya.net/tt/528

Leave a Comment