Class: Ra::Shape::Cylinder
Overview
A cylinder at origin <0,0,0> with a radius 1. A cylinder surface is defined:
(x² + z² = radius² AND y BETWEEN ±1) OR (y = ±1 AND x² + z² < radius)
A ray ‘x` / `y` / `z` values at `t` use the `origin` and `direction`:
x = origin.x + direction.x * t
y = origin.y + direction.y * t
z = origin.z + direction.z * t
Substituting ‘x` / `y` / `z` allows for solving for `t`:
(origin.x + direction.x * t)² + (origin.z + direction.z * t)² = 1
Simplifying gives a quadratic formula with terms defined as:
a = direction.x² + direction.z²
b = 2 * ((origin.x * direction.x) + (origin.z * direction.z))
c = origin.x² + origin.z² - 1
discriminant = b² - 4ac
t = (-b ± √discriminant) / (2a)
A discriminant <0 indicates the ray does not intersect the sphere.
Constant Summary collapse
- MIN_Y =
-1
- MAX_Y =
+1
- RADIUS =
1
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
- #l_normal(point:) ⇒ Ra::Tuple
- #t_intersect(ray:) ⇒ Array<Numeric>
-
#uv_point(point:) ⇒ Vector
<u = 0.0..1.0, v = 0.0..1.0>.
Methods inherited from Base
#color, #initialize, #intersect, #normal
Constructor Details
This class inherits a constructor from Ra::Shape::Base
Instance Method Details
#l_normal(point:) ⇒ Ra::Tuple
57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/ra/shape/cylinder.rb', line 57 def l_normal(point:) x = point[0] y = point[1] z = point[2] distance = (x * x) + (z * z) if distance < 1 return Vector[0, +1, 0, Tuple::VECTOR] if y >= MAX_Y - EPSILON return Vector[0, -1, 0, Tuple::VECTOR] if y <= MIN_Y + EPSILON end Vector[point[0], 0, point[2], Tuple::VECTOR] end |
#t_intersect(ray:) ⇒ Array<Numeric>
50 51 52 53 |
# File 'lib/ra/shape/cylinder.rb', line 50 def t_intersect(ray:) t_intersect_caps(ray:) + t_intersect_side(ray:).filter { |t| ray.y(t:) > MIN_Y && ray.y(t:) < MAX_Y } end |
#uv_point(point:) ⇒ Vector
Returns <u = 0.0..1.0, v = 0.0..1.0>.
35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/ra/shape/cylinder.rb', line 35 def uv_point(point:) x = point[0] y = point[1] z = point[2] theta = Math.atan2(x, z) u = 1 - ((theta / (2 * Math::PI)) + 0.5) v = y % 1.0 Vector[u, v] end |