From 935d6e917800f20b2446a10d1dc302945951fdf0 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Sat, 7 Dec 2019 09:59:47 -0600 Subject: [PATCH] Added Transform.perspective and .view matrix helpers, fixed array index out of bounds for Transform * Vector --- lib/cyberarm_engine/shader.rb | 5 +-- lib/cyberarm_engine/transform.rb | 55 ++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/lib/cyberarm_engine/shader.rb b/lib/cyberarm_engine/shader.rb index 8e024f9..573a54b 100644 --- a/lib/cyberarm_engine/shader.rb +++ b/lib/cyberarm_engine/shader.rb @@ -189,7 +189,8 @@ module CyberarmEngine attr_loc = location ? location : attribute_location(variable) case value.class.to_s.split("::").last.downcase.to_sym - when :integer + when :integer, :falseclass, :trueclass + value = value ? 1 : 0 if value.is_a?(TrueClass) or value.is_a?(FalseClass) glUniform1i(attr_loc, value) when :float glUniform1f(attr_loc, value) @@ -197,7 +198,7 @@ module CyberarmEngine when :transform glUniformMatrix4fv(attr_loc, 1, GL_FALSE, value.elements.pack("F16")) when :vector - glUniformVec4f(attr_loc, *value.to_a) + glUniform4f(attr_loc, *value.to_a) else raise NotImplementedError, "Shader support for #{value.class.inspect} not implemented." end diff --git a/lib/cyberarm_engine/transform.rb b/lib/cyberarm_engine/transform.rb index 76fd202..fa2afa7 100644 --- a/lib/cyberarm_engine/transform.rb +++ b/lib/cyberarm_engine/transform.rb @@ -114,7 +114,7 @@ module CyberarmEngine end def self.rotate_3d(vector, order = "xyz") - x, y, z = vector.to_a[0..2] + x, y, z = vector.to_a[0..2].map { |axis| axis.degrees_to_radians } rotation_x = Transform.new( [ @@ -146,15 +146,64 @@ module CyberarmEngine rotation_x * rotation_y * rotation_z end + 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 + + 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 + + def self.view(eye, orientation) + # https://www.3dgep.com/understanding-the-view-matrix/#The_View_Matrix + cosPitch = Math.cos(orientation.z.degrees_to_radians) + sinPitch = Math.sin(orientation.z.degrees_to_radians) + cosYaw = Math.cos(orientation.y.degrees_to_radians) + sinYaw = Math.sin(orientation.y.degrees_to_radians) + + 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 + def *(other) case other when CyberarmEngine::Vector - matrix = Array.new(@elements.size) + matrix = @elements.clone list = other.to_a @elements.each_with_index do |e, i| - matrix[i] = e + list[i] + matrix[i] = e + list[i % 4] end Transform.new(matrix)