class CyberarmEngine::Transform
Basic 4x4 matrix operations
Attributes
elements[R]
Public Class Methods
concat(left, right)
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 88 def self.concat(left, right) matrix = Array.new(left.elements.size) rows = 4 matrix.size.times do |i| matrix[i] = 0 rows.times do |j| matrix[i] += left.elements[i / rows * rows + j] * right.elements[i % rows + j * rows] end end Transform.new(matrix) end
identity()
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 13 def self.identity Transform.new( [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] ) end
new(matrix)
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 6 def initialize(matrix) @elements = matrix raise "Transform is wrong size! Got #{@elements.size}, expected 16" if 16 != @elements.size raise "Invalid value for matrix, must all be numeric!" if @elements.any? { |e| e.nil? || !e.is_a?(Numeric) } end
orthographic(left, right, bottom, top, near, far)
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 200 def self.orthographic(left, right, bottom, top, near, far) s = Vector.new( 2 / (right - left.to_f), 2 / (top - bottom.to_f), -2 / (far - near.to_f) ) t = Vector.new( (right + left.to_f) / (right - left.to_f), (top + bottom.to_f) / (top - bottom.to_f), (far + near.to_f) / (far - near.to_f) ) Transform.new( [ s.x, 0.0, 0.0, t.x, 0.0, s.y, 0.0, t.y, 0.0, 0.0, s.z, t.z, 0.0, 0.0, 0.0, 1.0 ] ) end
perspective(fov_y, aspect_ratio, near, far)
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 185 def self.perspective(fov_y, aspect_ratio, near, far) f = 1.0 / Math.tan(fov_y.degrees_to_radians / 2.0) # cotangent zn = (far + near.to_f) / (near - far.to_f) zf = (2.0 * far * near.to_f) / (near - far.to_f) Transform.new( [ f / aspect_ratio, 0.0, 0.0, 0.0, 0.0, f, 0.0, 0.0, 0.0, 0.0, zn, zf, 0.0, 0.0, -1.0, 0.0 ] ) end
rotate(angle, rotate_around = nil)
click to toggle source
2d rotate operation, replicates Gosu's Gosu.rotate function
# File lib/cyberarm_engine/transform.rb, line 27 def self.rotate(angle, rotate_around = nil) double c = Math.cos(angle).degrees_to_radians double s = Math.sin(angle).degrees_to_radians matrix = [ +c, +s, 0, 0, -s, +c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] rotate_matrix = Transform.new(matrix, rows: 4, columns: 4) if rotate_around && (rotate_around.x != 0.0 || rotate_around.y != 0.0) negative_rotate_around = Vector.new(-rotate_around.x, -rotate_around.y, -rotate_around.z) rotate_matrix = concat( concat(translate(negative_rotate_around), rotate_matrix), translate(rotate_around) ) end rotate_matrix end
rotate_3d(vector, _order = "zyx")
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 117 def self.rotate_3d(vector, _order = "zyx") x, y, z = vector.to_a[0..2].map { |axis| axis * Math::PI / 180.0 } rotation_x = Transform.new( [ 1, 0, 0, 0, 0, Math.cos(x), -Math.sin(x), 0, 0, Math.sin(x), Math.cos(x), 0, 0, 0, 0, 1 ] ) rotation_y = Transform.new( [ Math.cos(y), 0, Math.sin(y), 0, 0, 1, 0, 0, -Math.sin(y), 0, Math.cos(y), 0, 0, 0, 0, 1 ] ) rotation_z = Transform.new( [ Math.cos(z), -Math.sin(z), 0, 0, Math.sin(z), Math.cos(z), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] ) rotation_z * rotation_y * rotation_x end
rotate_gl(angle, axis)
click to toggle source
Implements glRotatef www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml
# File lib/cyberarm_engine/transform.rb, line 152 def self.rotate_gl(angle, axis) radians = angle * Math::PI / 180.0 s = Math.sin(radians) c = Math.cos(radians) axis = axis.normalized x, y, z = axis.to_a[0..2] n = (1.0 - c) Transform.new( [ x * x * n + c, x * y * n - z * s, x * z * n + y * s, 0, y * x * n + z * s, y * y * n + c, y * z * n - x * s, 0, x * z * n - y * s, y * z * n + x * s, z * z * n + c, 0, 0, 0, 0, 1.0 ] ) end
scale(vector, center_around = nil)
click to toggle source
2d scale operation, replicates Gosu's Gosu.rotate function
# File lib/cyberarm_engine/transform.rb, line 65 def self.scale(vector, center_around = nil) scale_x, scale_y, scale_z = vector.to_a[0..2] matrix = [ scale_x, 0, 0, 0, 0, scale_y, 0, 0, 0, 0, scale_z, 0, 0, 0, 0, 1 ] scale_matrix = Transform.new(matrix) if center_around && (center_around.x != 0.0 || center_around.y != 0.0) negative_center_around = Vector.new(-center_around.x, -center_around.y, -center_around.z) scale_matrix = concat( concat(translate(negative_center_around), scale_matrix), translate(center_around) ) end scale_matrix end
scale_3d(vector)
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 172 def self.scale_3d(vector) x, y, z = vector.to_a[0..2] Transform.new( [ x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 ] ) end
translate(vector)
click to toggle source
2d translate operation, replicates Gosu's Gosu.translate function
# File lib/cyberarm_engine/transform.rb, line 52 def self.translate(vector) x, y, z = vector.to_a[0..2] matrix = [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 ] Transform.new(matrix) end
translate_3d(vector)
click to toggle source
3D Operations meant for OpenGL ###
# File lib/cyberarm_engine/transform.rb, line 105 def self.translate_3d(vector) x, y, z = vector.to_a[0..2] matrix = [ 1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1 ] Transform.new(matrix) end
view(eye, orientation)
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 223 def self.view(eye, orientation) # https://www.3dgep.com/understanding-the-view-matrix/#The_View_Matrix cosPitch = Math.cos(orientation.z * Math::PI / 180.0) sinPitch = Math.sin(orientation.z * Math::PI / 180.0) cosYaw = Math.cos(orientation.y * Math::PI / 180.0) sinYaw = Math.sin(orientation.y * Math::PI / 180.0) x_axis = Vector.new(cosYaw, 0, -sinYaw) y_axis = Vector.new(sinYaw * sinPitch, cosPitch, cosYaw * sinPitch) z_axis = Vector.new(sinYaw * cosPitch, -sinPitch, cosPitch * cosYaw) Transform.new( [ x_axis.x, y_axis.y, z_axis.z, 0, x_axis.x, y_axis.y, z_axis.z, 0, x_axis.x, y_axis.y, z_axis.z, 0, -x_axis.dot(eye), -y_axis.dot(eye), -z_axis.dot(eye), 1 ] ) end
Public Instance Methods
*(other)
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 244 def *(other) case other when CyberarmEngine::Vector matrix = @elements.clone list = other.to_a @elements.each_with_index do |e, i| matrix[i] = e + list[i % 4] end Transform.new(matrix) when CyberarmEngine::Transform multiply_matrices(other) else p other.class raise TypeError, "Expected CyberarmEngine::Vector or CyberarmEngine::Transform got #{other.class}" end end
get(x, y)
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 264 def get(x, y) width = 4 # puts "Transform|#{self.object_id} -> #{@elements[width * y + x].inspect} (index: #{width * y + x})" @elements[width * y + x] end
multiply_matrices(other)
click to toggle source
# File lib/cyberarm_engine/transform.rb, line 271 def multiply_matrices(other) matrix = Array.new(16, 0) 4.times do |x| 4.times do |y| 4.times do |k| matrix[4 * y + x] += get(x, k) * other.get(k, y) end end end Transform.new(matrix) end
to_gl()
click to toggle source
arranges Matrix in column major form
# File lib/cyberarm_engine/transform.rb, line 286 def to_gl e = @elements [ e[0], e[4], e[8], e[12], e[1], e[5], e[9], e[13], e[2], e[6], e[10], e[14], e[3], e[7], e[11], e[15] ] end