lib/mittsu/extras/geometries/cylinder_geometry.rb
require 'mittsu/core'
require 'mittsu/math'
module Mittsu
class CylinderGeometry < Geometry
def initialize(radius_top = 20.0, radius_bottom = 20.0, height = 100.0, radial_segments = 8, height_segments = 1, open_ended = false, theta_start = 0.0, theta_length = (::Math::PI * 2.0))
super()
@type = 'CylinderGeometry'
@parameters = {
radius_top: radius_top,
radius_bottom: radius_bottom,
height: height,
radial_segments: radial_segments,
height_segments: height_segments,
open_ended: open_ended,
theta_start: theta_start,
theta_length: theta_length
}
height_half = height / 2.0
index_rows = []
uv_rows = []
for y in 0..height_segments do
index_row = []
uv_row = []
v = y.to_f / height_segments.to_f
radius = v * (radius_bottom - radius_top) + radius_top
for x in 0..radial_segments do
u = x.to_f / radial_segments
vertex = Vector3.new
vertex.x = radius * ::Math.sin(u * theta_length + theta_start)
vertex.y = -v * height + height_half
vertex.z = radius * ::Math.cos(u * theta_length + theta_start)
@vertices << vertex
index_row << (vertices.length - 1)
uv_row << Vector2.new(u, 1.0 - v)
end
index_rows << index_row
uv_rows << uv_row
end
tan_theta = (radius_bottom - radius_top) / height
na = nil
nb = nil
for x in 0...radial_segments do
if radius_top != 0
na = @vertices[index_rows[0][x]].clone
nb = @vertices[index_rows[0][x + 1]].clone
else
na = @vertices[index_rows[1][x]].clone
nb = @vertices[index_rows[1][x + 1]].clone
end
na.y = ::Math.sqrt(na.x * na.x + na.z * na.z) * tan_theta
na.normalize
nb.y = ::Math.sqrt(nb.x * nb.x + nb.z * nb.z) * tan_theta
nb.normalize
for y in 0...height_segments do
v1 = index_rows[y][x]
v2 = index_rows[y + 1][x]
v3 = index_rows[y + 1][x + 1]
v4 = index_rows[y][x + 1]
n1 = na.clone
n2 = na.clone
n3 = nb.clone
n4 = nb.clone
uv1 = uv_rows[y][x].clone
uv2 = uv_rows[y + 1][x].clone
uv3 = uv_rows[y + 1][x + 1].clone
uv4 = uv_rows[y][x + 1].clone
@faces << Face3.new(v1, v2, v4, [n1, n2, n4])
@face_vertex_uvs[0] << [uv1, uv2, uv4]
@faces << Face3.new(v2, v3, v4, [n2.clone, n3, n4.clone])
@face_vertex_uvs[0] << [uv2.clone, uv3, uv4.clone]
end
end
# top cap
if !open_ended && radius_top > 0.0
@vertices << Vector3.new(0, height_half, 0)
for x in 0...radial_segments do
v1 = index_rows[0][x]
v2 = index_rows[0][x + 1]
v3 = @vertices.length - 1
n1 = Vector3.new(0, 1, 0)
n2 = Vector3.new(0, 1, 0)
n3 = Vector3.new(0, 1, 0)
uv1 = uv_rows[0][x].clone
uv2 = uv_rows[0][x + 1].clone
uv3 = Vector2.new(uv2.x, 0)
@faces << Face3.new(v1, v2, v3, [n1, n2, n3])
@face_vertex_uvs[0] << [uv1, uv2, uv3]
end
end
# bottom cap
if !open_ended && radius_bottom > 0.0
@vertices << Vector3.new(0, -height_half, 0)
for x in 0...radial_segments do
v1 = index_rows[height_segments][x + 1]
v2 = index_rows[height_segments][x]
v3 = @vertices.length - 1
n1 = Vector3.new(0, -1, 0)
n2 = Vector3.new(0, -1, 0)
n3 = Vector3.new(0, -1, 0)
uv1 = uv_rows[height_segments][x].clone
uv2 = uv_rows[height_segments][x + 1].clone
uv3 = Vector2.new(uv2.x, 0)
@faces << Face3.new(v1, v2, v3, [n1, n2, n3])
@face_vertex_uvs[0] << [uv1, uv2, uv3]
end
end
compute_face_normals
end
end
end