概要
paiza.ioでelixirやってみた。
Ray Tracerやってみた。
参考にしたページ
サンプルコード
defmodule Vector do
defmodule Vec3 do
defstruct x: 0.0, y: 0.0, z: 0.0
alias Vector.Vec3, as: Vec3
def vec3(list) when is_list(list) do
[x | rest] = list
[y | [z]] = rest
%Vec3{x: x, y: y, z: z}
end
def ones() do
%Vec3{x: 1.0, y: 1.0, z: 1.0}
end
def add(vec1, vec2) do
%Vec3{x: vec1.x + vec2.x, y: vec1.y + vec2.y, z: vec1.z + vec2.z }
end
def dot(vec1, vec2) do
vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z
end
def mult(vec1, vec2) do
%Vec3{x: vec1.x * vec2.x, y: vec1.y * vec2.y, z: vec1.z * vec2.z }
end
def scale(vec, s) do
%Vec3{x: vec.x * s, y: vec.y * s, z: vec.z * s }
end
def sub(vec1, vec2) when is_map vec2 do
%Vec3{x: vec1.x - vec2.x, y: vec1.y - vec2.y, z: vec1.z - vec2.z }
end
def sub(vec, s) do
%Vec3{x: vec.x - s, y: vec.y - s, z: vec.z - s}
end
def len(vec) do
:math.sqrt(lengthSqr(vec))
end
def lengthSqr(vec) do
vec.x * vec.x + vec.y * vec.y + vec.z * vec.z
end
def div(vec, scalar) do
%Vec3{x: vec.x / scalar, y: vec.y / scalar, z: vec.z / scalar}
end
def unit_vector(vec) do
s = len(vec)
Vec3.div(vec, s)
end
def cross(vec1, vec2) do
x = vec1.y * vec2.z - vec1.z * vec2.y
y = vec1.z * vec2.x - vec1.x * vec2.z
z = vec1.x * vec2.y - vec1.y * vec2.x
%Vec3{x: x, y: y, z: z}
end
def to_list(vec3) do
[vec3.x, vec3.y, vec3.z]
end
end
end
defmodule Ray do
alias Vector.Vec3, as: Vec3
defstruct pos: %Vec3{}, dir: %Vec3{}
def at(vec, t), do: Vec3.add(vec.pos, (Vec3.scale(vec.dir, t)))
end
IO.puts """
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="lib/style.css">
</head>
<body>
<canvas id="canvas" width="80" height="60"></canvas>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = ctx.createImageData(80, 60);
var data = img.data;
var v = [
"""
defmodule Main do
require Vector
require Ray
alias Vector.Vec3, as: Vec3
def hit_sphere(center, radius, ray) do
oc = Vec3.sub(ray.pos, center)
a = Vec3.dot(ray.dir, ray.dir)
b = Vec3.dot(oc, ray.dir) * 2.0
c = Vec3.dot(oc, oc) - radius * radius
discriminant = b * b - 4 * a * c
discriminant > 0.0
end
def sphere_color(ray) do
if hit_sphere(Vec3.vec3([0.0, 0.0, -1.0]), 0.5, ray) do
Vec3.vec3([1.0, 0.0, 0.0])
else
unit_vec = Vec3.unit_vector(ray.dir)
t = 0.5 * (unit_vec.y + 1.0)
Vec3.scale(Vec3.ones(), (1.0 - t))
|> Vec3.add(Vec3.scale(Vec3.vec3([0.5, 0.7, 1.0]), t))
end
end
def main do
nx = 80
ny = 60
low_left = Vec3.vec3([-2.0, -1.0, -1.0])
horizontal = Vec3.vec3([4.0, 0.0, 0.0])
vertical = Vec3.vec3([0.0, 2.0, 0.0])
origin = Vec3.vec3([0.0, 0.0, 0.0])
for y <- ny - 1..0 do
for x <- 0..nx - 1 do
u = x / nx
v = y / ny
ray = %Ray{
pos: origin,
dir: Vec3.scale(horizontal, u)
|> Vec3.add(Vec3.scale(vertical, v))
|> Vec3.add(low_left)
}
unit_vec = Vec3.unit_vector(ray.dir)
t = 0.5 * (unit_vec.y + 1.0)
color = sphere_color(ray)
[color.x, color.y, color.z]
|> Enum.map(fn n ->
255 * n
|> floor
|> IO.write
IO.write ","
end)
IO.write "255,"
end
end
end
end
Main.main
IO.puts """
0];
for (var i = 0; i < 80 * 60 * 4; i++)
{
data[i] = v[i];
}
ctx.putImageData(img, 0, 0);
//alert(v[2]);
</script>
</body>
</html>
"""
実行結果
成果物
以上。