Instantly share code, notes, and snippets.

# yhara/ray.rb Created Feb 21, 2017

 # 1. とりあえず色を出す IMAGE_WIDTH = 256 IMAGE_HEIGHT = 256 IMAGE_DEPTH = 256 class Vec def initialize(x, y, z) @x, @y, @z = x, y, z end attr_reader :x, :y, :z def vnormalize! len = vlength() if len > 1.0e-17 r_len = 1.0 / len @x *= r_len @y *= r_len @z *= r_len end self end def vlength Math.sqrt(@x * @x + @y * @y + @z * @z) end end class Ray def initialize(origin, dir) @origin, @dir = origin, dir end attr_reader :dir end puts("P3") puts("#{IMAGE_WIDTH} #{IMAGE_HEIGHT}") puts("#{IMAGE_DEPTH-1}") # t: 0 ~ 1 def color(t) t = 0 if t < 0 t = 1 if t > 1 ret = IMAGE_DEPTH * t.to_f return (ret == IMAGE_DEPTH ? (IMAGE_DEPTH-1) : ret).to_i end IMAGE_HEIGHT.times do |row| IMAGE_WIDTH.times do |col| x = col.to_f / (IMAGE_WIDTH / 2) - 1.0 y = (IMAGE_HEIGHT-row).to_f / (IMAGE_HEIGHT / 2) - 1.0 ray = Ray.new(Vec.new(0.0, 0.0, 5.0), Vec.new(x, y, -1.0).vnormalize!) #p x: x, y: y, dir: ray.dir r, g, b = color(ray.dir.x), color(ray.dir.y), color(ray.dir.z) print("#{r} #{g} #{b} ") end end
 # 2. 白い円を出す IMAGE_WIDTH = 256 IMAGE_HEIGHT = 256 IMAGE_DEPTH = 256 class Vec def initialize(x, y, z) @x, @y, @z = x, y, z end attr_reader :x, :y, :z def vsub(b) Vec.new(@x - b.x, @y - b.y, @z - b.z) end def vdot(b) @x * b.x + @y * b.y + @z * b.z end def vnormalize! len = vlength() if len > 1.0e-17 r_len = 1.0 / len @x *= r_len @y *= r_len @z *= r_len end self end def vlength Math.sqrt(@x * @x + @y * @y + @z * @z) end end class Ray def initialize(origin, dir) @origin, @dir = origin, dir end attr_reader :origin, :dir end class Sphere def initialize(radius, position, color) @radius, @position, @color = radius, position, color end attr_reader :radius, :position, :color def intersect?(ray) rs = ray.origin.vsub(@position) b = rs.vdot(ray.dir) c = rs.vdot(rs) - @radius * @radius d = b * b - c return d > 0 && (-b - Math.sqrt(d)) > 0 end end puts("P3") puts("#{IMAGE_WIDTH} #{IMAGE_HEIGHT}") puts("#{IMAGE_DEPTH-1}") # t: 0 ~ 1 def color(t) t = 0 if t < 0 t = 1 if t > 1 ret = IMAGE_DEPTH * t.to_f return (ret == IMAGE_DEPTH ? (IMAGE_DEPTH-1) : ret).to_i end def print_col(c) print("#{color(c.x)} #{color(c.y)} #{color(c.z)} ") end BLACK = Vec.new(0, 0, 0) sphere = Sphere.new(1.0, Vec.new(0, 0, 0), Vec.new(1, 1, 1)) IMAGE_HEIGHT.times do |row| IMAGE_WIDTH.times do |col| x = col.to_f / (IMAGE_WIDTH / 2) - 1.0 y = (IMAGE_HEIGHT-row).to_f / (IMAGE_HEIGHT / 2) - 1.0 ray = Ray.new(Vec.new(0.0, 0.0, 5.0), Vec.new(x, y, -1.0).vnormalize!) c = if sphere.intersect?(ray) sphere.color else BLACK end print_col(c) end end