paiza.ioでelixir その71

# 概要
paiza.ioでelixirやってみた。
Ray Tracerやってみた。

# 参考にしたページ

https://qiita.com/masatam81/items/eb638eee5a8a8c8589a4


# サンプルコード

```

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>
"""


```

# 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b42ce51f-d28f-c2aa-77f1-519b37353154.png)


# 成果物

https://paiza.io/projects/wtkZ8_RjrKlkzFP67A_5bQ?language=elixir


以上。