Created
November 24, 2011 14:49
-
-
Save miura1729/1391500 to your computer and use it in GitHub Desktop.
ao-render.rbの型推論結果
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # AO render benchmark | |
| # Original program (C) Syoyo Fujita in Javascript (and other languages) | |
| # http://lucille.atso-net.jp/blog/?p=642 | |
| # http://lucille.atso-net.jp/blog/?p=711 | |
| # Ruby(yarv2llvm) version by Hideki Miura | |
| # | |
| IMAGE_WIDTH = 256 | |
| IMAGE_HEIGHT = 256 | |
| NSUBSAMPLES = 2 | |
| NAO_SAMPLES = 8 | |
| =begin | |
| def rand | |
| 0.5 | |
| end | |
| =end | |
| # Vec | |
| # [] -> { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Vec>} | |
| # self { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Vec>} | |
| # block { BOXED NilClass} | |
| # | |
| class Vec | |
| # initialize | |
| # [{ UNBOXED Float}, { UNBOXED Float}, { UNBOXED Float}] -> { BOXED Vec} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def initialize(x, y, z) | |
| @x = x | |
| @y = y | |
| @z = z | |
| end | |
| # x= | |
| # [{ UNBOXED Float}] -> { UNBOXED Float} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def x=(v); @x = v; end | |
| # y= | |
| # [{ UNBOXED Float}] -> { UNBOXED Float} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def y=(v); @y = v; end | |
| # z= | |
| # [{ UNBOXED Float}] -> { UNBOXED Float} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def z=(v); @z = v; end | |
| # x | |
| # [] -> { UNBOXED Float} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def x; @x; end | |
| # y | |
| # [] -> { UNBOXED Float} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def y; @y; end | |
| # z | |
| # [] -> { UNBOXED Float} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def z; @z; end | |
| # vadd | |
| def vadd(b) | |
| Vec.new(@x + b.x, @y + b.y, @z + b.z) | |
| end | |
| # vsub | |
| # [{ BOXED Vec}] -> { BOXED Vec} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def vsub(b) | |
| Vec.new(@x - b.x, @y - b.y, @z - b.z) | |
| end | |
| # vcross | |
| # [{ BOXED Vec}] -> { BOXED Vec} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def vcross(b) | |
| Vec.new(@y * b.z - @z * b.y, | |
| @z * b.x - @x * b.z, | |
| @x * b.y - @y * b.x) | |
| end | |
| # vdot | |
| # [{ BOXED Vec}] -> { UNBOXED Float} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def vdot(b) | |
| @x * b.x + @y * b.y + @z * b.z | |
| end | |
| # vlength | |
| # [] -> { UNBOXED Float} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def vlength | |
| Math.sqrt(@x * @x + @y * @y + @z * @z) | |
| end | |
| # vnormalize | |
| # [] -> { BOXED Vec} | |
| # self { BOXED Vec} | |
| # block { BOXED NilClass} | |
| # | |
| def vnormalize | |
| len = vlength | |
| v = Vec.new(@x, @y, @z) | |
| if len > 1.0e-17 then | |
| v.x = v.x / len | |
| v.y = v.y / len | |
| v.z = v.z / len | |
| end | |
| v | |
| end | |
| end | |
| # Sphere | |
| # [] -> { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Sphere>} | |
| # self { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Sphere>} | |
| # block { BOXED NilClass} | |
| # | |
| class Sphere | |
| # initialize | |
| # [{ BOXED Vec}, { UNBOXED Float}] -> { BOXED Sphere} | |
| # self { BOXED Sphere} | |
| # block { BOXED NilClass} | |
| # | |
| def initialize(center, radius) | |
| @center = center | |
| @radius = radius | |
| end | |
| # center | |
| def center; @center; end | |
| # radius | |
| def radius; @radius; end | |
| # intersect | |
| # [{ BOXED Ray}, { BOXED Isect}] -> { BOXED Object} | |
| # self { BOXED Sphere} | |
| # block { BOXED NilClass} | |
| # | |
| def intersect(ray, isect) | |
| rs = ray.org.vsub(@center) | |
| b = rs.vdot(ray.dir) | |
| c = rs.vdot(rs) - (@radius * @radius) | |
| d = b * b - c | |
| if d > 0.0 then | |
| t = - b - Math.sqrt(d) | |
| if t > 0.0 and t < isect.t then | |
| isect.t = t | |
| isect.hit = true | |
| isect.pl = Vec.new(ray.org.x + ray.dir.x * t, | |
| ray.org.y + ray.dir.y * t, | |
| ray.org.z + ray.dir.z * t) | |
| n = isect.pl.vsub(@center) | |
| isect.n = n.vnormalize | |
| else | |
| 0.0 | |
| end | |
| end | |
| end | |
| end | |
| # Plane | |
| # [] -> { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Plane>} | |
| # self { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Plane>} | |
| # block { BOXED NilClass} | |
| # | |
| class Plane | |
| # initialize | |
| # [{ BOXED Vec}, { BOXED Vec}] -> { BOXED Plane} | |
| # self { BOXED Plane} | |
| # block { BOXED NilClass} | |
| # | |
| def initialize(p, n) | |
| @p = p | |
| @n = n | |
| end | |
| # intersect | |
| # [{ BOXED Ray}, { BOXED Isect}] -> { BOXED Vec} | |
| # self { BOXED Plane} | |
| # block { BOXED NilClass} | |
| # | |
| def intersect(ray, isect) | |
| d = [email protected](@n) | |
| v = ray.dir.vdot(@n) | |
| v0 = v | |
| if v < 0.0 then | |
| v0 = -v | |
| end | |
| if v0 < 1.0e-17 then | |
| return | |
| end | |
| t = -(ray.org.vdot(@n) + d) / v | |
| if t > 0.0 and t < isect.t then | |
| isect.hit = true | |
| isect.t = t | |
| isect.n = @n | |
| isect.pl = Vec.new(ray.org.x + t * ray.dir.x, | |
| ray.org.y + t * ray.dir.y, | |
| ray.org.z + t * ray.dir.z) | |
| end | |
| end | |
| end | |
| # Ray | |
| # [] -> { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Ray>} | |
| # self { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Ray>} | |
| # block { BOXED NilClass} | |
| # | |
| class Ray | |
| # initialize | |
| # [{ BOXED Vec}, { BOXED Vec}] -> { BOXED Ray} | |
| # self { BOXED Ray} | |
| # block { BOXED NilClass} | |
| # | |
| def initialize(org, dir) | |
| @org = org | |
| @dir = dir | |
| end | |
| # org | |
| # [] -> { BOXED Vec} | |
| # self { BOXED Ray} | |
| # block { BOXED NilClass} | |
| # | |
| def org; @org; end | |
| # org= | |
| def org=(v); @org = v; end | |
| # dir | |
| # [] -> { BOXED Vec} | |
| # self { BOXED Ray} | |
| # block { BOXED NilClass} | |
| # | |
| def dir; @dir; end | |
| # dir= | |
| def dir=(v); @dir = v; end | |
| end | |
| # Isect | |
| # [] -> { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Isect>} | |
| # self { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Isect>} | |
| # block { BOXED NilClass} | |
| # | |
| class Isect | |
| # initialize | |
| # [] -> { BOXED Isect} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| def initialize | |
| @t = 10000000.0 | |
| @hit = false | |
| @pl = Vec.new(0.0, 0.0, 0.0) | |
| @n = Vec.new(0.0, 0.0, 0.0) | |
| end | |
| # t | |
| # [] -> { UNBOXED Float} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| def t; @t; end | |
| # t= | |
| # [{ UNBOXED Float}] -> { UNBOXED Float} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| def t=(v); @t = v; end | |
| # hit | |
| # [] -> { BOXED TrueClass} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| def hit; @hit; end | |
| # hit= | |
| # [{ BOXED TrueClass}] -> { BOXED TrueClass} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| def hit=(v); @hit = v; end | |
| # pl | |
| # [] -> { BOXED Vec} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| def pl; @pl; end | |
| # pl= | |
| # [{ BOXED Vec}] -> { BOXED Vec} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| # [{ BOXED Object}] -> { BOXED Vec} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| def pl=(v); @pl = v; end | |
| # n | |
| # [] -> { BOXED Vec} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| def n; @n; end | |
| # n= | |
| # [{ BOXED Vec}] -> { BOXED Vec} | |
| # self { BOXED Isect} | |
| # block { BOXED NilClass} | |
| # | |
| def n=(v); @n = v; end | |
| end | |
| # clamp | |
| # [{ UNBOXED Float}] -> { UNBOXED Fixnum} | |
| # self { BOXED Object} | |
| # block { BOXED NilClass} | |
| # | |
| def clamp(f) | |
| i = f * 255.5 | |
| if i > 255.0 then | |
| i = 255.0 | |
| end | |
| if i < 0.0 then | |
| i = 0.0 | |
| end | |
| i.to_i | |
| end | |
| # otherBasis | |
| # [{ BOXED Array ({nil=>[{ BOXED Vec}], [2]=>[{ BOXED Vec}]})}, { BOXED Vec}] -> { BOXED Vec} | |
| # self { BOXED Object} | |
| # block { BOXED NilClass} | |
| # | |
| def otherBasis(basis, n) | |
| basis[2] = Vec.new(n.x, n.y, n.z) | |
| basis[1] = Vec.new(0.0, 0.0, 0.0) | |
| if n.x < 0.6 and n.x > -0.6 then | |
| basis[1].x = 1.0 | |
| elsif n.y < 0.6 and n.y > -0.6 then | |
| basis[1].y = 1.0 | |
| elsif n.z < 0.6 and n.z > -0.6 then | |
| basis[1].z = 1.0 | |
| else | |
| basis[1].x = 1.0 | |
| end | |
| basis[0] = basis[1].vcross(basis[2]) | |
| basis[0] = basis[0].vnormalize | |
| basis[1] = basis[2].vcross(basis[0]) | |
| basis[1] = basis[1].vnormalize | |
| end | |
| # Scene | |
| # [] -> { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Scene>} | |
| # self { BOXED #<Ytljit::ClassClassWrapper type=#<Class:Scene>} | |
| # block { BOXED NilClass} | |
| # | |
| class Scene | |
| # initialize | |
| # [] -> { BOXED Scene} | |
| # self { BOXED Scene} | |
| # block { BOXED NilClass} | |
| # | |
| def initialize | |
| @spheres = Array.new | |
| @spheres[0] = Sphere.new(Vec.new(-2.0, 0.0, -3.5), 0.5) | |
| @spheres[1] = Sphere.new(Vec.new(-0.5, 0.0, -3.0), 0.5) | |
| @spheres[2] = Sphere.new(Vec.new(1.0, 0.0, -2.2), 0.5) | |
| @plane = Plane.new(Vec.new(0.0, -0.5, 0.0), Vec.new(0.0, 1.0, 0.0)) | |
| end | |
| # ambient_occlusion | |
| # [{ BOXED Isect}] -> { BOXED Vec} | |
| # self { BOXED Object} | |
| # block { BOXED NilClass} | |
| # | |
| def ambient_occlusion(isect) | |
| basis = Array.new(3) | |
| otherBasis(basis, isect.n) | |
| ntheta = NAO_SAMPLES | |
| nphi = NAO_SAMPLES | |
| eps = 0.0001 | |
| occlusion = 0.0 | |
| p0 = Vec.new(isect.pl.x + eps * isect.n.x, | |
| isect.pl.y + eps * isect.n.y, | |
| isect.pl.z + eps * isect.n.z) | |
| nphi.times do |j| | |
| ntheta.times do |i| | |
| r = rand | |
| phi = 2.0 * 3.14159265 * rand | |
| x = Math.cos(phi) * Math.sqrt(1.0 - r) | |
| y = Math.sin(phi) * Math.sqrt(1.0 - r) | |
| z = Math.sqrt(r) | |
| rx = x * basis[0].x + y * basis[1].x + z * basis[2].x | |
| ry = x * basis[0].y + y * basis[1].y + z * basis[2].y | |
| rz = x * basis[0].z + y * basis[1].z + z * basis[2].z | |
| raydir = Vec.new(rx, ry, rz) | |
| ray = Ray.new(p0, raydir) | |
| occisect = Isect.new | |
| @spheres[0].intersect(ray, occisect) | |
| @spheres[1].intersect(ray, occisect) | |
| @spheres[2].intersect(ray, occisect) | |
| @plane.intersect(ray, occisect) | |
| if occisect.hit then | |
| occlusion = occlusion + 1.0 | |
| else | |
| 0.0 | |
| end | |
| end | |
| end | |
| occlusion = (ntheta.to_f * nphi.to_f - occlusion) / (ntheta.to_f * nphi.to_f) | |
| Vec.new(occlusion, occlusion, occlusion) | |
| end | |
| # render | |
| # [{ UNBOXED Fixnum}, { UNBOXED Fixnum}, { UNBOXED Fixnum}] -> { UNBOXED Fixnum} | |
| # self { BOXED Scene} | |
| # block { BOXED NilClass} | |
| # | |
| def render(w, h, nsubsamples) | |
| cnt = 0 | |
| nsf = nsubsamples.to_f | |
| h.times do |y| | |
| w.times do |x| | |
| rad = Vec.new(0.0, 0.0, 0.0) | |
| # Subsmpling | |
| nsubsamples.times do |v| | |
| nsubsamples.times do |u| | |
| cnt = cnt + 1 | |
| wf = w.to_f | |
| hf = h.to_f | |
| xf = x.to_f | |
| yf = y.to_f | |
| uf = u.to_f | |
| vf = v.to_f | |
| px = (xf + (uf / nsf) - (wf / 2.0)) / (wf / 2.0) | |
| py = -(yf + (vf / nsf) - (hf / 2.0)) / (hf / 2.0) | |
| eye = Vec.new(px, py, -1.0).vnormalize | |
| ray = Ray.new(Vec.new(0.0, 0.0, 0.0), eye) | |
| isect = Isect.new | |
| @spheres[0].intersect(ray, isect) | |
| @spheres[1].intersect(ray, isect) | |
| @spheres[2].intersect(ray, isect) | |
| @plane.intersect(ray, isect) | |
| if isect.hit then | |
| col = ambient_occlusion(isect) | |
| rad.x = rad.x + col.x | |
| rad.y = rad.y + col.y | |
| rad.z = rad.z + col.z | |
| else | |
| 0.0 | |
| end | |
| end | |
| end | |
| r = rad.x / (nsf * nsf) | |
| g = rad.y / (nsf * nsf) | |
| b = rad.z / (nsf * nsf) | |
| printf("%c", clamp(r)) | |
| printf("%c", clamp(g)) | |
| printf("%c", clamp(b)) | |
| end | |
| end | |
| end | |
| end | |
| # File.open("ao.ppm", "w") do |fp| | |
| printf("P6\n") | |
| printf("%d %d\n", IMAGE_WIDTH, IMAGE_HEIGHT) | |
| printf("255\n", IMAGE_WIDTH, IMAGE_HEIGHT) | |
| Scene.new.render(IMAGE_WIDTH, IMAGE_HEIGHT, NSUBSAMPLES) | |
| # Scene.new.render(256, 256, 2) | |
| # end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment