class ArcBall attr_reader :center_x, :center_y, :v_down, :v_drag, :q_now, :q_drag, :q_down, :axis, :axis_set, :radius def initialize(cx, cy, radius) @center_x = cx @center_y = cy @radius = radius @v_down = AVector.new @v_drag = AVector.new @q_now = Quaternion.new @q_down = Quaternion.new @q_drag = Quaternion.new @axis_set = [AVector.new(1.0, 0.0, 0.0), AVector.new(0.0, 1.0, 0.0), AVector.new(0.0, 0.0, 1.0)] @axis = -1 end def select_axis(axis) @axis = axis end def mouse2sphere(x, y) v = AVector.new((x - center_x) / radius, (y - center_y) / radius, 0) mag = v.x * v.x + v.y * v.y if (mag > 1.0) v.normalize else v.z = Math.sqrt(1.0 - mag) end v = constrain(v, axis_set[axis]) unless (axis == -1) return v end def mouse_pressed(x, y) @v_down = mouse2sphere(x, y) @q_down.copy(q_now) @q_drag.reset end def mouse_dragged(x, y) @v_drag = mouse2sphere(x, y) @q_drag.set(AVector.dot(v_down, v_drag), v_down.cross(v_drag)) end def constrain(vector, axis) res = AVector.sub(vector, AVector.mult(axis, AVector.dot(axis, vector))) res.normalize end def update @q_now = Quaternion.mult(q_drag, q_down) quat2matrix(q_now) end def quat2matrix(q) q.get_value end end class Quaternion attr_reader :w, :x, :y, :z def initialize(w = 1.0, x = 0, y = 0, z = 0) @w, @x, @y, @z = w, x, y, z end def reset @w = 1.0 @x = 0.0 @y = 0.0 @z = 0.0 end def set(w, v) @w = w @x = v.x @y = v.y @z = v.z end def copy(q) @w = q.w @x = q.x @y = q.y @z = q.z end def self.mult(q1, q2) # class method x0 = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y y0 = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z z0 = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x w0 = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z Quaternion.new(w0, x0, y0, z0) end def get_value sa = Math.sqrt(1.0 - w * w) sa = 1.0 unless (sa >= Java::processing::core::PConstants::EPSILON) [Math.acos(w) * 2, x / sa, y / sa, z / sa] end end class AVector attr_accessor :x, :y, :z def initialize(x = 0, y = 0, z = 0) @x, @y, @z = x, y, z end def add(vector) AVector.new(vector.x + x, vector.y + y, vector.z + z) end def normalize orig_dist = Math.sqrt(x * x + y * y + z * z) @x /= orig_dist @y /= orig_dist @z /= orig_dist self end def self.dot(v1, v2) v1.x * v2.x + v1.y * v2.y + v1.z * v2.z end def self.mult(v, scalar) AVector.new(v.x * scalar, v.y * scalar, v.z * scalar) end def self.sub(v1, v2) AVector.new(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z) end def cross(v) AVector.new(y * v.z - v.y * z, z * v.x - v.z * x, x * v.y - v.x * y) end end
This is the test class test_arcball.rb:-
load_libraries 'arcball', 'opengl' import "arcball" import "opengl" X = 0 Y = 1 Z = 2 attr_reader :my_ball def setup size(600, 600, OPENGL) setup_opengl @my_ball = ArcBall.new(width/2.0, height/2.0, min(width - 20, height - 20) * 0.5) end def draw background(50, 50, 100) translate(width/2.0, height/2.0) # @todo add zoom via z, using control_panel define_lights update lights stroke(0) cube(my_ball.radius) end def setup_opengl hint ENABLE_OPENGL_4X_SMOOTH # optional hint DISABLE_OPENGL_ERROR_REPORT # optional end def update theta, x, y, z = my_ball.update rotate(theta, x, y, z) end def mouse_pressed my_ball.mouse_pressed(mouse_x, mouse_y) end def mouse_dragged my_ball.mouse_dragged(mouse_x, mouse_y) end def define_lights ambient(20, 20, 20) ambient_light(50, 50, 50) point_light(30, 30, 30, 200, -150, 0) directional_light(0, 30, 50, 1, 0, 0) spot_light(30, 30, 30, 0, 40, 200, 0, -0.5, -0.5, PI / 2, 2) end def key_pressed # @todo select via control_panel instead case(key) when 'x': my_ball.select_axis(X) when 'y': my_ball.select_axis(Y) when 'z': my_ball.select_axis(Z) end end def key_released my_ball.select_axis(-1) end def cube(sz) sz *= 0.5 fill(200, 200, 200, 255) begin_shape(QUADS) vertex(-sz, -sz, -sz) vertex(+sz, -sz, -sz) vertex(+sz, +sz, -sz) vertex(-sz, +sz, -sz) vertex(-sz, -sz, +sz) vertex(+sz, -sz, +sz) vertex(+sz, +sz, +sz) vertex(-sz, +sz, +sz) vertex(-sz, -sz, -sz) vertex(-sz, -sz, +sz) vertex(-sz, +sz, +sz) vertex(-sz, +sz, -sz) vertex(+sz, -sz, -sz) vertex(+sz, -sz, +sz) vertex(+sz, +sz, +sz) vertex(+sz, +sz, -sz) vertex(-sz, -sz, -sz) vertex(+sz, -sz, -sz) vertex(+sz, -sz, +sz) vertex(-sz, -sz, +sz) vertex(-sz, +sz, -sz) vertex(+sz, +sz, -sz) vertex(+sz, +sz, +sz) vertex(-sz, +sz, +sz) end_shape end
No comments:
Post a Comment