Skip to content

Instantly share code, notes, and snippets.

@astellon
Created May 22, 2019 12:31
Show Gist options
  • Save astellon/1617cc2ae00c7967825d352f1f7194c9 to your computer and use it in GitHub Desktop.
Save astellon/1617cc2ae00c7967825d352f1f7194c9 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Ray Tracing in One Weekend (in Julia)\n",
"\n",
"Ray Tracing in One WeekendをJuliaで実装します。\n",
"\n",
"This is an implementation of \"Ray Tracing in One Weekend\" using Julia\n",
"\n",
"Peter Shirley, Ray Tracing in One Weekend, Version 1.54, 2018"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ソースコードについてはQiitaの記事\n",
"「[レイトレーシング入門1「光線の基本と反射](https://qiita.com/mebiusbox2/items/89e2db3b24e4c39502fe)」も参考にしています。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 環境"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Julia Version 1.1.0\n",
"Commit 80516ca202 (2019-01-21 21:24 UTC)\n",
"Platform Info:\n",
" OS: Linux (x86_64-pc-linux-gnu)\n",
" CPU: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz\n",
" WORD_SIZE: 64\n",
" LIBM: libopenlibm\n",
" LLVM: libLLVM-6.0.1 (ORCJIT, skylake)\n",
"Environment:\n",
" JULIA_DEPOT_PATH = /opt/julia\n",
" JULIA_PKGDIR = /opt/julia\n",
" JULIA_VERSION = 1.1.0\n"
]
}
],
"source": [
"versioninfo()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ベクトルを扱うために`LinearAlgebra.jl`を使います。画像に関する型を使いたいので`Image.jl`、出力用に`FileIO`を使います。また、画像表示等に`ImageMagick.jl`が使われるのでインストール(usingは必要ない)しておく必要があります。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"using LinearAlgebra, FileIO, Images"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Chapter 1: Output an image"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"画像は配列で表現できます。ただし、表示は縦横逆になるので転置する。"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAABkAQAAAADr/UKmAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAd2KE6QAAAAZSURBVEjH7cGBAAAAAMOg+VMf4ApVAQDAGwooAAFK+upgAAAAAElFTkSuQmCC",
"text/plain": [
"100×200 Adjoint{RGB{Float32},Array{RGB{Float32},2}}:\n",
" RGB{Float32}(0.0,0.0,0.0) … RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) … RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) … RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" ⋮ ⋱ \n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) … RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) … RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)\n",
" RGB{Float32}(0.0,0.0,0.0) RGB{Float32}(0.0,0.0,0.0)"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nx = 200\n",
"ny = 100\n",
"image = zeros(RGB{Float32}, nx, ny)\n",
"image'"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"for j in ny:-1:1\n",
" for i in 1:nx\n",
" r = i / nx\n",
" g = j / ny\n",
" b = 0.2\n",
" image[i, ny - j + 1] = RGB{Float32}(r, g, b)\n",
" end\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAIAAABM5OhcAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAABSUlEQVR42u3VOwrCUBRF0fskM3L+Q/NT2aUQdJMoa2EhIiHFYd+1HtfLzHp9dr+//+MZ/vBbjz3ti3342G1uA1+3zf3oV+AfKRYJxSKhWCQUi4RikVAsEopFQrFIKBYJwyLhFJJQLBKKRUKxSCgWCcUioVgkFIuEYZFwCkkoFgnFIqFYJBSLhGKRUCwSikXCsEg4hSQUi4RikVAsEopFQrFIKBYJxSKhWCQUi4RhkXAKSSgWCcUioVgkFIuEYpFQLBKKRUKxSCgWCcMi4RSSUCwSikVCsUgoFgnFIqFYJBSLhGGRcApJKBYJxSKhWCQUi4RikVAsEopFwrBIOIUkFIuEYpFQLBKKRUKxSCgWCcUioVgkFIuEYZFwCkkoFgnFIqFYJBSLhGKRUCwSikVCsUgoFgnDIuEUklAsEopFQrFIKBYJxSKhWCSe4Jllw4JQBKkAAAAASUVORK5CYII=",
"text/plain": [
"100×200 Adjoint{RGB{Float32},Array{RGB{Float32},2}}:\n",
" RGB{Float32}(0.005,1.0,0.2) … RGB{Float32}(1.0,1.0,0.2) \n",
" RGB{Float32}(0.005,0.99,0.2) RGB{Float32}(1.0,0.99,0.2)\n",
" RGB{Float32}(0.005,0.98,0.2) RGB{Float32}(1.0,0.98,0.2)\n",
" RGB{Float32}(0.005,0.97,0.2) RGB{Float32}(1.0,0.97,0.2)\n",
" RGB{Float32}(0.005,0.96,0.2) RGB{Float32}(1.0,0.96,0.2)\n",
" RGB{Float32}(0.005,0.95,0.2) … RGB{Float32}(1.0,0.95,0.2)\n",
" RGB{Float32}(0.005,0.94,0.2) RGB{Float32}(1.0,0.94,0.2)\n",
" RGB{Float32}(0.005,0.93,0.2) RGB{Float32}(1.0,0.93,0.2)\n",
" RGB{Float32}(0.005,0.92,0.2) RGB{Float32}(1.0,0.92,0.2)\n",
" RGB{Float32}(0.005,0.91,0.2) RGB{Float32}(1.0,0.91,0.2)\n",
" RGB{Float32}(0.005,0.9,0.2) … RGB{Float32}(1.0,0.9,0.2) \n",
" RGB{Float32}(0.005,0.89,0.2) RGB{Float32}(1.0,0.89,0.2)\n",
" RGB{Float32}(0.005,0.88,0.2) RGB{Float32}(1.0,0.88,0.2)\n",
" ⋮ ⋱ \n",
" RGB{Float32}(0.005,0.12,0.2) RGB{Float32}(1.0,0.12,0.2)\n",
" RGB{Float32}(0.005,0.11,0.2) RGB{Float32}(1.0,0.11,0.2)\n",
" RGB{Float32}(0.005,0.1,0.2) … RGB{Float32}(1.0,0.1,0.2) \n",
" RGB{Float32}(0.005,0.09,0.2) RGB{Float32}(1.0,0.09,0.2)\n",
" RGB{Float32}(0.005,0.08,0.2) RGB{Float32}(1.0,0.08,0.2)\n",
" RGB{Float32}(0.005,0.07,0.2) RGB{Float32}(1.0,0.07,0.2)\n",
" RGB{Float32}(0.005,0.06,0.2) RGB{Float32}(1.0,0.06,0.2)\n",
" RGB{Float32}(0.005,0.05,0.2) … RGB{Float32}(1.0,0.05,0.2)\n",
" RGB{Float32}(0.005,0.04,0.2) RGB{Float32}(1.0,0.04,0.2)\n",
" RGB{Float32}(0.005,0.03,0.2) RGB{Float32}(1.0,0.03,0.2)\n",
" RGB{Float32}(0.005,0.02,0.2) RGB{Float32}(1.0,0.02,0.2)\n",
" RGB{Float32}(0.005,0.01,0.2) RGB{Float32}(1.0,0.01,0.2)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"image'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"画像の保存には`FileIO`を使う。"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"save(\"helloworld.png\", image)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Chapter 2: The vec3 class\n",
"\n",
"配列で表現することとする。`LinearAlgebra.jl`に必要な関数は揃っている。"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3-element Array{Int64,1}:\n",
" 2\n",
" 3\n",
" 4"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v = [1, 2, 3]\n",
"w = [2, 3, 4]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Chapter 3: Rays, a simple camera, and background"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`Ray`のクラスを作ります。`Ray`は始点と方向のベクトルを持ちます。"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"struct Ray\n",
" origin\n",
" direction\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"長さに関するファクター`t`によって、ベクトルが決まります。"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"at (generic function with 1 method)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"at(ray::Ray, t) = ray.origin + ray.direction * t"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"color (generic function with 1 method)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function color(ray::Ray)\n",
" d = normalize(ray.direction)\n",
" t = 0.5 * (d[2] .+ 1)\n",
" return (1-t)*[1, 1, 1] + t*[0.5, 0.7, 1.0]\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"100×200 Adjoint{RGB{Float32},Array{RGB{Float32},2}}:\n",
" RGB{Float32}(0.647254,0.788352,1.0) … RGB{Float32}(0.647938,0.788763,1.0)\n",
" RGB{Float32}(0.648971,0.789382,1.0) RGB{Float32}(0.649647,0.789788,1.0)\n",
" RGB{Float32}(0.650704,0.790423,1.0) RGB{Float32}(0.651374,0.790824,1.0)\n",
" RGB{Float32}(0.652455,0.791473,1.0) RGB{Float32}(0.653117,0.79187,1.0) \n",
" RGB{Float32}(0.654223,0.792534,1.0) RGB{Float32}(0.654877,0.792926,1.0)\n",
" RGB{Float32}(0.656008,0.793605,1.0) … RGB{Float32}(0.656654,0.793993,1.0)\n",
" RGB{Float32}(0.65781,0.794686,1.0) RGB{Float32}(0.658448,0.795069,1.0)\n",
" RGB{Float32}(0.659629,0.795777,1.0) RGB{Float32}(0.660258,0.796155,1.0)\n",
" RGB{Float32}(0.661464,0.796878,1.0) RGB{Float32}(0.662084,0.79725,1.0) \n",
" RGB{Float32}(0.663316,0.79799,1.0) RGB{Float32}(0.663926,0.798356,1.0)\n",
" RGB{Float32}(0.665184,0.79911,1.0) … RGB{Float32}(0.665785,0.799471,1.0)\n",
" RGB{Float32}(0.667069,0.800241,1.0) RGB{Float32}(0.667659,0.800596,1.0)\n",
" RGB{Float32}(0.668969,0.801381,1.0) RGB{Float32}(0.669549,0.80173,1.0) \n",
" ⋮ ⋱ \n",
" RGB{Float32}(0.831031,0.898619,1.0) RGB{Float32}(0.830451,0.89827,1.0) \n",
" RGB{Float32}(0.832931,0.899759,1.0) RGB{Float32}(0.832341,0.899404,1.0)\n",
" RGB{Float32}(0.834816,0.90089,1.0) … RGB{Float32}(0.834215,0.900529,1.0)\n",
" RGB{Float32}(0.836684,0.90201,1.0) RGB{Float32}(0.836074,0.901644,1.0)\n",
" RGB{Float32}(0.838536,0.903122,1.0) RGB{Float32}(0.837916,0.90275,1.0) \n",
" RGB{Float32}(0.840371,0.904223,1.0) RGB{Float32}(0.839742,0.903845,1.0)\n",
" RGB{Float32}(0.84219,0.905314,1.0) RGB{Float32}(0.841552,0.904931,1.0)\n",
" RGB{Float32}(0.843992,0.906395,1.0) … RGB{Float32}(0.843346,0.906007,1.0)\n",
" RGB{Float32}(0.845777,0.907466,1.0) RGB{Float32}(0.845123,0.907074,1.0)\n",
" RGB{Float32}(0.847545,0.908527,1.0) RGB{Float32}(0.846883,0.90813,1.0) \n",
" RGB{Float32}(0.849296,0.909577,1.0) RGB{Float32}(0.848626,0.909176,1.0)\n",
" RGB{Float32}(0.851029,0.910618,1.0) RGB{Float32}(0.850353,0.910212,1.0)"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# screen\n",
"lowerleft = [-2, -1, -1]\n",
"horizontal = [4, 0, 0]\n",
"vertical = [0, 2, 0]\n",
"\n",
"origin = [0, 0, 0]\n",
"\n",
"for j in ny:-1:1\n",
" for i in 1:nx\n",
" u = i / nx\n",
" v = j / ny\n",
" ray = Ray(origin, lowerleft + u*horizontal + v*vertical)\n",
" c = color(ray)\n",
" image[i, ny - j + 1] = RGB{Float32}(c[1], c[2], c[3])\n",
" end\n",
"end\n",
"\n",
"image'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Chapter 4: Adding a sphere"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"hitsphere (generic function with 1 method)"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function hitsphere(center, radius, ray::Ray)\n",
" oc = ray.origin - center\n",
" a = dot(ray.direction, ray.direction)\n",
" b = 2.0 * dot(oc, ray.direction)\n",
" c = dot(oc, oc) - radius^2\n",
" discriminant = b^2 - 4 * a * c\n",
" return discriminant > 0\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"color (generic function with 1 method)"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function color(ray::Ray)\n",
" if hitsphere([0, 0, -1], 0.5, ray)\n",
" return [1, 0, 0]\n",
" end\n",
" d = normalize(ray.direction)\n",
" t = 0.5*(d[2] + 1)\n",
" return (1-t)*[1, 1, 1] + t*[0.5, 0.7, 1.0]\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"100×200 Adjoint{RGB{Float32},Array{RGB{Float32},2}}:\n",
" RGB{Float32}(0.647254,0.788352,1.0) … RGB{Float32}(0.647938,0.788763,1.0)\n",
" RGB{Float32}(0.648971,0.789382,1.0) RGB{Float32}(0.649647,0.789788,1.0)\n",
" RGB{Float32}(0.650704,0.790423,1.0) RGB{Float32}(0.651374,0.790824,1.0)\n",
" RGB{Float32}(0.652455,0.791473,1.0) RGB{Float32}(0.653117,0.79187,1.0) \n",
" RGB{Float32}(0.654223,0.792534,1.0) RGB{Float32}(0.654877,0.792926,1.0)\n",
" RGB{Float32}(0.656008,0.793605,1.0) … RGB{Float32}(0.656654,0.793993,1.0)\n",
" RGB{Float32}(0.65781,0.794686,1.0) RGB{Float32}(0.658448,0.795069,1.0)\n",
" RGB{Float32}(0.659629,0.795777,1.0) RGB{Float32}(0.660258,0.796155,1.0)\n",
" RGB{Float32}(0.661464,0.796878,1.0) RGB{Float32}(0.662084,0.79725,1.0) \n",
" RGB{Float32}(0.663316,0.79799,1.0) RGB{Float32}(0.663926,0.798356,1.0)\n",
" RGB{Float32}(0.665184,0.79911,1.0) … RGB{Float32}(0.665785,0.799471,1.0)\n",
" RGB{Float32}(0.667069,0.800241,1.0) RGB{Float32}(0.667659,0.800596,1.0)\n",
" RGB{Float32}(0.668969,0.801381,1.0) RGB{Float32}(0.669549,0.80173,1.0) \n",
" ⋮ ⋱ \n",
" RGB{Float32}(0.831031,0.898619,1.0) RGB{Float32}(0.830451,0.89827,1.0) \n",
" RGB{Float32}(0.832931,0.899759,1.0) RGB{Float32}(0.832341,0.899404,1.0)\n",
" RGB{Float32}(0.834816,0.90089,1.0) … RGB{Float32}(0.834215,0.900529,1.0)\n",
" RGB{Float32}(0.836684,0.90201,1.0) RGB{Float32}(0.836074,0.901644,1.0)\n",
" RGB{Float32}(0.838536,0.903122,1.0) RGB{Float32}(0.837916,0.90275,1.0) \n",
" RGB{Float32}(0.840371,0.904223,1.0) RGB{Float32}(0.839742,0.903845,1.0)\n",
" RGB{Float32}(0.84219,0.905314,1.0) RGB{Float32}(0.841552,0.904931,1.0)\n",
" RGB{Float32}(0.843992,0.906395,1.0) … RGB{Float32}(0.843346,0.906007,1.0)\n",
" RGB{Float32}(0.845777,0.907466,1.0) RGB{Float32}(0.845123,0.907074,1.0)\n",
" RGB{Float32}(0.847545,0.908527,1.0) RGB{Float32}(0.846883,0.90813,1.0) \n",
" RGB{Float32}(0.849296,0.909577,1.0) RGB{Float32}(0.848626,0.909176,1.0)\n",
" RGB{Float32}(0.851029,0.910618,1.0) RGB{Float32}(0.850353,0.910212,1.0)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# screen\n",
"lowerleft = [-2, -1, -1]\n",
"horizontal = [4, 0, 0]\n",
"vertical = [0, 2, 0]\n",
"\n",
"origin = [0, 0, 0]\n",
"\n",
"for j in ny:-1:1\n",
" for i in 1:nx\n",
" u = i / nx\n",
" v = j / ny\n",
" ray = Ray(origin, lowerleft + u*horizontal + v*vertical)\n",
" c = color(ray)\n",
" image[i, ny - j + 1] = RGB{Float32}(c[1], c[2], c[3])\n",
" end\n",
"end\n",
"\n",
"image'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Chapter 5: Surface normals and multiple objects."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"hitsphere (generic function with 1 method)"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function hitsphere(center, radius, ray::Ray)\n",
" oc = ray.origin - center\n",
" a = dot(ray.direction, ray.direction)\n",
" b = 2.0 * dot(oc, ray.direction)\n",
" c = dot(oc, oc) - radius^2\n",
" discriminant = b^2 - 4 * a * c\n",
" if discriminant < 0\n",
" return -1\n",
" else\n",
" return (-b - sqrt(discriminant)) / (2a)\n",
" end\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"color (generic function with 1 method)"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function color(ray::Ray)\n",
" center = [0, 0, -1]\n",
" t = hitsphere(center, 0.5, ray)\n",
" if t > 0 \n",
" N = normalize(at(ray, t) - center)\n",
" return 0.5*(N .+ 1)\n",
" end\n",
" d = normalize(ray.direction)\n",
" t = 0.5*(d[2] + 1)\n",
" return (1-t)*[1, 1, 1] + t*[0.5, 0.7, 1.0]\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"100×200 Adjoint{RGB{Float32},Array{RGB{Float32},2}}:\n",
" RGB{Float32}(0.647254,0.788352,1.0) … RGB{Float32}(0.647938,0.788763,1.0)\n",
" RGB{Float32}(0.648971,0.789382,1.0) RGB{Float32}(0.649647,0.789788,1.0)\n",
" RGB{Float32}(0.650704,0.790423,1.0) RGB{Float32}(0.651374,0.790824,1.0)\n",
" RGB{Float32}(0.652455,0.791473,1.0) RGB{Float32}(0.653117,0.79187,1.0) \n",
" RGB{Float32}(0.654223,0.792534,1.0) RGB{Float32}(0.654877,0.792926,1.0)\n",
" RGB{Float32}(0.656008,0.793605,1.0) … RGB{Float32}(0.656654,0.793993,1.0)\n",
" RGB{Float32}(0.65781,0.794686,1.0) RGB{Float32}(0.658448,0.795069,1.0)\n",
" RGB{Float32}(0.659629,0.795777,1.0) RGB{Float32}(0.660258,0.796155,1.0)\n",
" RGB{Float32}(0.661464,0.796878,1.0) RGB{Float32}(0.662084,0.79725,1.0) \n",
" RGB{Float32}(0.663316,0.79799,1.0) RGB{Float32}(0.663926,0.798356,1.0)\n",
" RGB{Float32}(0.665184,0.79911,1.0) … RGB{Float32}(0.665785,0.799471,1.0)\n",
" RGB{Float32}(0.667069,0.800241,1.0) RGB{Float32}(0.667659,0.800596,1.0)\n",
" RGB{Float32}(0.668969,0.801381,1.0) RGB{Float32}(0.669549,0.80173,1.0) \n",
" ⋮ ⋱ \n",
" RGB{Float32}(0.831031,0.898619,1.0) RGB{Float32}(0.830451,0.89827,1.0) \n",
" RGB{Float32}(0.832931,0.899759,1.0) RGB{Float32}(0.832341,0.899404,1.0)\n",
" RGB{Float32}(0.834816,0.90089,1.0) … RGB{Float32}(0.834215,0.900529,1.0)\n",
" RGB{Float32}(0.836684,0.90201,1.0) RGB{Float32}(0.836074,0.901644,1.0)\n",
" RGB{Float32}(0.838536,0.903122,1.0) RGB{Float32}(0.837916,0.90275,1.0) \n",
" RGB{Float32}(0.840371,0.904223,1.0) RGB{Float32}(0.839742,0.903845,1.0)\n",
" RGB{Float32}(0.84219,0.905314,1.0) RGB{Float32}(0.841552,0.904931,1.0)\n",
" RGB{Float32}(0.843992,0.906395,1.0) … RGB{Float32}(0.843346,0.906007,1.0)\n",
" RGB{Float32}(0.845777,0.907466,1.0) RGB{Float32}(0.845123,0.907074,1.0)\n",
" RGB{Float32}(0.847545,0.908527,1.0) RGB{Float32}(0.846883,0.90813,1.0) \n",
" RGB{Float32}(0.849296,0.909577,1.0) RGB{Float32}(0.848626,0.909176,1.0)\n",
" RGB{Float32}(0.851029,0.910618,1.0) RGB{Float32}(0.850353,0.910212,1.0)"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# screen\n",
"lowerleft = [-2, -1, -1]\n",
"horizontal = [4, 0, 0]\n",
"vertical = [0, 2, 0]\n",
"\n",
"origin = [0, 0, 0]\n",
"\n",
"for j in ny:-1:1\n",
" for i in 1:nx\n",
" u = i / nx\n",
" v = j / ny\n",
" ray = Ray(origin, lowerleft + u*horizontal + v*vertical)\n",
" c = color(ray)\n",
" image[i, ny - j + 1] = RGB{Float32}(c[1], c[2], c[3])\n",
" end\n",
"end\n",
"\n",
"image'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"原著では、非constの参照渡しをしていますが、結果を返すようにします。"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"abstract type HitRecord end"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"struct Hit <: HitRecord\n",
" t\n",
" p\n",
" n\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"struct NotHit <: HitRecord end"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ishit (generic function with 2 methods)"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ishit(h::Hit) = true\n",
"ishit(h::NotHit) = false"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"hit (generic function with 1 method)"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"abstract type Hitable end\n",
"hit(obj::Hitable, ray::Ray, tmin, tmax) = 0"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"struct Sphere <: Hitable\n",
" center\n",
" radius\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"hit (generic function with 2 methods)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function hit(sphere::Sphere, ray::Ray, tmin, tmax)\n",
" oc = ray.origin - sphere.center\n",
" a = dot(ray.direction, ray.direction)\n",
" b = 2.0 * dot(oc, ray.direction)\n",
" c = dot(oc, oc) - sphere.radius^2\n",
" \n",
" discriminant = b^2 - 4 * a * c\n",
" \n",
" if discriminant > 0\n",
" t = (-b - sqrt(discriminant)) / (2a)\n",
" if tmin < t < tmax\n",
" p = at(ray, t)\n",
" n = (p - sphere.center) / sphere.radius\n",
" return Hit(t, p, n)\n",
" end\n",
" \n",
" t = (-b + sqrt(discriminant)) / (2a)\n",
" if tmin < t < tmax\n",
" p = at(ray, t)\n",
" n = (p - sphere.center) / sphere.radius\n",
" return Hit(t, p, n)\n",
" end\n",
" end\n",
" \n",
" return NotHit()\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"struct HitableList <: Hitable\n",
" list::Array{Hitable, 1}\n",
" HitableList() = new(Array{Hitable, 1}())\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"Base.push!(l::HitableList, h::Hitable) = push!(l.list, h)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"hit (generic function with 3 methods)"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function hit(hits::HitableList, ray::Ray, tmin, tmax)\n",
" closesthit = NotHit()\n",
" closest = tmax\n",
" foreach(hits.list) do h\n",
" rec = hit(h, ray, tmin, closest)\n",
" if ishit(rec)\n",
" closesthit = rec\n",
" closest = rec.t\n",
" end\n",
" end\n",
"\n",
" return closesthit\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"color (generic function with 2 methods)"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function color(ray::Ray, world::Hitable)\n",
" rec = hit(world, ray, 0, typemax(Float64))\n",
" if ishit(rec)\n",
" return 0.5*(rec.n .+ 1)\n",
" else\n",
" d = normalize(ray.direction)\n",
" t = 0.5*(d[2] + 1)\n",
" return (1-t)*[1, 1, 1] + t*[0.5, 0.7, 1.0]\n",
" end\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"100×200 Adjoint{RGB{Float32},Array{RGB{Float32},2}}:\n",
" RGB{Float32}(0.647254,0.788352,1.0) … RGB{Float32}(0.647938,0.788763,1.0) \n",
" RGB{Float32}(0.648971,0.789382,1.0) RGB{Float32}(0.649647,0.789788,1.0) \n",
" RGB{Float32}(0.650704,0.790423,1.0) RGB{Float32}(0.651374,0.790824,1.0) \n",
" RGB{Float32}(0.652455,0.791473,1.0) RGB{Float32}(0.653117,0.79187,1.0) \n",
" RGB{Float32}(0.654223,0.792534,1.0) RGB{Float32}(0.654877,0.792926,1.0) \n",
" RGB{Float32}(0.656008,0.793605,1.0) … RGB{Float32}(0.656654,0.793993,1.0) \n",
" RGB{Float32}(0.65781,0.794686,1.0) RGB{Float32}(0.658448,0.795069,1.0) \n",
" RGB{Float32}(0.659629,0.795777,1.0) RGB{Float32}(0.660258,0.796155,1.0) \n",
" RGB{Float32}(0.661464,0.796878,1.0) RGB{Float32}(0.662084,0.79725,1.0) \n",
" RGB{Float32}(0.663316,0.79799,1.0) RGB{Float32}(0.663926,0.798356,1.0) \n",
" RGB{Float32}(0.665184,0.79911,1.0) … RGB{Float32}(0.665785,0.799471,1.0) \n",
" RGB{Float32}(0.667069,0.800241,1.0) RGB{Float32}(0.667659,0.800596,1.0) \n",
" RGB{Float32}(0.668969,0.801381,1.0) RGB{Float32}(0.669549,0.80173,1.0) \n",
" ⋮ ⋱ \n",
" RGB{Float32}(0.493365,0.999953,0.501649) RGB{Float32}(0.506704,0.999952,0.501648)\n",
" RGB{Float32}(0.49354,0.999955,0.501737) RGB{Float32}(0.506527,0.999954,0.501736)\n",
" RGB{Float32}(0.493706,0.999957,0.501821) … RGB{Float32}(0.506359,0.999956,0.50182) \n",
" RGB{Float32}(0.493864,0.999959,0.501901) RGB{Float32}(0.5062,0.999958,0.5019) \n",
" RGB{Float32}(0.494013,0.99996,0.501976) RGB{Float32}(0.506049,0.99996,0.501976) \n",
" RGB{Float32}(0.494156,0.999962,0.502048) RGB{Float32}(0.505905,0.999961,0.502048)\n",
" RGB{Float32}(0.494292,0.999963,0.502117) RGB{Float32}(0.505768,0.999962,0.502116)\n",
" RGB{Float32}(0.494421,0.999964,0.502182) … RGB{Float32}(0.505637,0.999963,0.502182)\n",
" RGB{Float32}(0.494545,0.999965,0.502245) RGB{Float32}(0.505512,0.999965,0.502244)\n",
" RGB{Float32}(0.494663,0.999966,0.502304) RGB{Float32}(0.505392,0.999966,0.502304)\n",
" RGB{Float32}(0.494776,0.999967,0.502362) RGB{Float32}(0.505278,0.999967,0.502361)\n",
" RGB{Float32}(0.494884,0.999968,0.502416) RGB{Float32}(0.505168,0.999967,0.502416)"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# screen\n",
"lowerleft = [-2, -1, -1]\n",
"horizontal = [4, 0, 0]\n",
"vertical = [0, 2, 0]\n",
"\n",
"origin = [0, 0, 0]\n",
"\n",
"world = HitableList()\n",
"push!(world, Sphere([0, 0, -1], 0.5))\n",
"push!(world, Sphere([0, -100.5, -1], 100))\n",
"\n",
"for j in ny:-1:1\n",
" for i in 1:nx\n",
" u = i / nx\n",
" v = j / ny\n",
" ray = Ray(origin, lowerleft + u*horizontal + v*vertical)\n",
" c = color(ray, world)\n",
" image[i, ny - j + 1] = RGB{Float32}(c[1], c[2], c[3])\n",
" end\n",
"end\n",
"\n",
"image'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Chapter 6: Antialiasing"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"struct Camera\n",
" origin\n",
" lowerleft\n",
" horizontal\n",
" vertical\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"getray (generic function with 1 method)"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function getray(camera::Camera, u, v)\n",
" d = camera.lowerleft + u*camera.horizontal + v*vertical - camera.origin\n",
" return Ray(camera.origin, d)\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"100×200 Adjoint{RGB{Float32},Array{RGB{Float32},2}}:\n",
" RGB{Float32}(0.646074,0.787645,1.0) … RGB{Float32}(0.647489,0.788493,1.0) \n",
" RGB{Float32}(0.647804,0.788682,1.0) RGB{Float32}(0.649108,0.789465,1.0) \n",
" RGB{Float32}(0.649522,0.789713,1.0) RGB{Float32}(0.650906,0.790544,1.0) \n",
" RGB{Float32}(0.651284,0.79077,1.0) RGB{Float32}(0.652651,0.791591,1.0) \n",
" RGB{Float32}(0.653085,0.791851,1.0) RGB{Float32}(0.654356,0.792614,1.0) \n",
" RGB{Float32}(0.654747,0.792848,1.0) … RGB{Float32}(0.65616,0.793696,1.0) \n",
" RGB{Float32}(0.656698,0.794019,1.0) RGB{Float32}(0.657868,0.794721,1.0) \n",
" RGB{Float32}(0.658474,0.795085,1.0) RGB{Float32}(0.65963,0.795778,1.0) \n",
" RGB{Float32}(0.660175,0.796105,1.0) RGB{Float32}(0.661501,0.796901,1.0) \n",
" RGB{Float32}(0.662132,0.797279,1.0) RGB{Float32}(0.663302,0.797981,1.0) \n",
" RGB{Float32}(0.663864,0.798319,1.0) … RGB{Float32}(0.66514,0.799084,1.0) \n",
" RGB{Float32}(0.66578,0.799468,1.0) RGB{Float32}(0.666921,0.800153,1.0) \n",
" RGB{Float32}(0.667778,0.800667,1.0) RGB{Float32}(0.668893,0.801336,1.0) \n",
" ⋮ ⋱ \n",
" RGB{Float32}(0.493302,0.999953,0.501602) RGB{Float32}(0.506838,0.999951,0.501599)\n",
" RGB{Float32}(0.493479,0.999955,0.501689) RGB{Float32}(0.506645,0.999953,0.501695)\n",
" RGB{Float32}(0.493653,0.999957,0.501778) … RGB{Float32}(0.506472,0.999955,0.501781)\n",
" RGB{Float32}(0.493819,0.999958,0.501862) RGB{Float32}(0.506311,0.999957,0.50186) \n",
" RGB{Float32}(0.493971,0.99996,0.50194) RGB{Float32}(0.506149,0.999958,0.50194) \n",
" RGB{Float32}(0.494121,0.999961,0.502016) RGB{Float32}(0.505999,0.99996,0.502014) \n",
" RGB{Float32}(0.494252,0.999963,0.502081) RGB{Float32}(0.505871,0.999961,0.50208) \n",
" RGB{Float32}(0.494384,0.999964,0.50215) … RGB{Float32}(0.505731,0.999963,0.50215) \n",
" RGB{Float32}(0.494521,0.999965,0.502217) RGB{Float32}(0.505598,0.999964,0.502214)\n",
" RGB{Float32}(0.494629,0.999966,0.502274) RGB{Float32}(0.505478,0.999965,0.502275)\n",
" RGB{Float32}(0.494752,0.999967,0.502335) RGB{Float32}(0.505355,0.999966,0.502335)\n",
" RGB{Float32}(0.494862,0.999968,0.502391) RGB{Float32}(0.50525,0.999967,0.50239) "
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"lowerleft = [-2, -1, -1]\n",
"horizontal = [4, 0, 0]\n",
"vertical = [0, 2, 0]\n",
"origin = [0, 0, 0]\n",
"\n",
"cam = Camera(origin, lowerleft, horizontal, vertical)\n",
"\n",
"ns = 100 # number of sampling\n",
"\n",
"world = HitableList()\n",
"push!(world, Sphere([0, 0, -1], 0.5))\n",
"push!(world, Sphere([0, -100.5, -1], 100))\n",
"\n",
"for j in ny:-1:1\n",
" for i in 1:nx\n",
" \n",
" c = [0, 0, 0]\n",
" for _ in 1:ns\n",
" u = (i + rand(Float64)) / nx\n",
" v = (j + rand(Float64)) / ny\n",
" ray = getray(cam, u, v)\n",
" c += color(ray, world)\n",
" end\n",
" \n",
" c /= ns\n",
" image[i, ny - j + 1] = RGB{Float32}(c[1], c[2], c[3])\n",
" end\n",
"end\n",
"\n",
"image'"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"randinsphere (generic function with 1 method)"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function randinsphere()\n",
" while true\n",
" p = 2 * [rand(Float64), rand(Float64), rand(Float64)] .- 1\n",
" mapreduce(x->x^2, +, p) < 1 && return p\n",
" end\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"color (generic function with 2 methods)"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function color(ray::Ray, world::Hitable)\n",
" rec = hit(world, ray, 0.0000001, typemax(Float64))\n",
" if ishit(rec)\n",
" target = rec.p + rec.n + randinsphere()\n",
" return 0.5 * color(Ray(rec.p, target - rec.p), world)\n",
" else\n",
" d = normalize(ray.direction)\n",
" t = 0.5*(d[2] + 1)\n",
" return (1-t)*[1, 1, 1] + t*[0.5, 0.7, 1.0]\n",
" end\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"100×200 Adjoint{RGB{Float32},Array{RGB{Float32},2}}:\n",
" RGB{Float32}(0.819795,0.897115,1.0) … RGB{Float32}(0.820569,0.897532,1.0) \n",
" RGB{Float32}(0.820961,0.897743,1.0) RGB{Float32}(0.82164,0.898109,1.0) \n",
" RGB{Float32}(0.821827,0.89821,1.0) RGB{Float32}(0.822718,0.898691,1.0) \n",
" RGB{Float32}(0.822894,0.898786,1.0) RGB{Float32}(0.823635,0.899186,1.0) \n",
" RGB{Float32}(0.823887,0.899322,1.0) RGB{Float32}(0.824669,0.899744,1.0) \n",
" RGB{Float32}(0.82494,0.899891,1.0) … RGB{Float32}(0.825722,0.900314,1.0) \n",
" RGB{Float32}(0.826003,0.900466,1.0) RGB{Float32}(0.826636,0.900808,1.0) \n",
" RGB{Float32}(0.827077,0.901047,1.0) RGB{Float32}(0.827683,0.901375,1.0) \n",
" RGB{Float32}(0.828022,0.901558,1.0) RGB{Float32}(0.828636,0.901891,1.0) \n",
" RGB{Float32}(0.829004,0.902091,1.0) RGB{Float32}(0.829701,0.902469,1.0) \n",
" RGB{Float32}(0.830227,0.902754,1.0) … RGB{Float32}(0.830789,0.903059,1.0) \n",
" RGB{Float32}(0.831117,0.903238,1.0) RGB{Float32}(0.83197,0.9037,1.0) \n",
" RGB{Float32}(0.832257,0.903857,1.0) RGB{Float32}(0.832933,0.904224,1.0) \n",
" ⋮ ⋱ \n",
" RGB{Float32}(0.553466,0.630332,0.728079) RGB{Float32}(0.553749,0.631268,0.72974) \n",
" RGB{Float32}(0.553574,0.630388,0.728079) RGB{Float32}(0.557266,0.632287,0.728079)\n",
" RGB{Float32}(0.552624,0.627918,0.723907) … RGB{Float32}(0.555411,0.629751,0.724744)\n",
" RGB{Float32}(0.552937,0.628079,0.723907) RGB{Float32}(0.556939,0.630935,0.72558) \n",
" RGB{Float32}(0.552223,0.629298,0.727247) RGB{Float32}(0.556495,0.63189,0.728079) \n",
" RGB{Float32}(0.553374,0.629097,0.72558) RGB{Float32}(0.547374,0.623624,0.720549)\n",
" RGB{Float32}(0.545593,0.619492,0.713775) RGB{Float32}(0.554845,0.63025,0.726414) \n",
" RGB{Float32}(0.550582,0.62806,0.726414) … RGB{Float32}(0.547771,0.625027,0.723069)\n",
" RGB{Float32}(0.554514,0.63008,0.726414) RGB{Float32}(0.557676,0.63171,0.726414) \n",
" RGB{Float32}(0.551234,0.625609,0.720549) RGB{Float32}(0.554143,0.629097,0.724744)\n",
" RGB{Float32}(0.545323,0.62177,0.718863) RGB{Float32}(0.545846,0.622038,0.718863)\n",
" RGB{Float32}(0.551205,0.628479,0.726622) RGB{Float32}(0.553996,0.630604,0.728079)"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"lowerleft = [-2, -1, -1]\n",
"horizontal = [4, 0, 0]\n",
"vertical = [0, 2, 0]\n",
"origin = [0, 0, 0]\n",
"\n",
"cam = Camera(origin, lowerleft, horizontal, vertical)\n",
"\n",
"ns = 100 # number of sampling\n",
"\n",
"world = HitableList()\n",
"push!(world, Sphere([0, 0, -1], 0.5))\n",
"push!(world, Sphere([0, -100.5, -1], 100))\n",
"\n",
"for j in ny:-1:1\n",
" for i in 1:nx\n",
" \n",
" c = [0, 0, 0]\n",
" for _ in 1:ns\n",
" u = (i + rand(0.0:1.0)) / nx\n",
" v = (j + rand(0.0:1.0)) / ny\n",
" ray = getray(cam, u, v)\n",
" c += color(ray, world)\n",
" end\n",
" \n",
" c /= ns\n",
" map!(x->x^(1/2.2), c, c) # linear to gamma\n",
" image[i, ny - j + 1] = RGB{Float32}(c[1], c[2], c[3])\n",
" end\n",
"end\n",
"\n",
"image'"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
"abstract type Material end"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [],
"source": [
"struct Lambertian <: Material\n",
" albedo\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"ename": "UndefVarError",
"evalue": "UndefVarError: scatter not defined",
"output_type": "error",
"traceback": [
"UndefVarError: scatter not defined",
"",
"Stacktrace:",
" [1] top-level scope at In[38]:1"
]
}
],
"source": [
"function scatter(lmabert::Lambertian, rec::Hit, att)\n",
" target = rec.p + rec.n + randinsphere\n",
" ray(rec.p, target - rec.p), albedo\n",
"end"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.1.0",
"language": "julia",
"name": "julia-1.1"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.1.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment