Class: Ra::Shape::Cylinder

Inherits:
Base
  • Object
show all
Defined in:
lib/ra/shape/cylinder.rb

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

#material

Instance Method Summary collapse

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

Parameters:

  • point (Vector)

Returns:



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>

Parameters:

Returns:

  • (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>.

Parameters:

  • point (Vector)

    <x, y, z, Tuple::POINT>

Returns:

  • (Vector)

    <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