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