Class: Bvh::Motion::ChannelData
- Inherits:
-
Hash
- Object
- Hash
- Bvh::Motion::ChannelData
- Defined in:
- lib/bvh/motion/channel_data.rb
Instance Attribute Summary collapse
-
#bone ⇒ Object
readonly
The bone that is related to this channel data.
Instance Method Summary collapse
-
#arithmetic_proc(target) ⇒ Object
call-seq: channel_data + channel_data => new_channel_data channel_data - channel_data => new_channel_data channel_data / channel_data => new_channel_data channel_data * channel_data => new_channel_data channel_data + number => new_channel_data channel_data - number => new_channel_data channel_data / number => new_channel_data channel_data * number => new_channel_data.
-
#get_channel(channel) ⇒ Object
Retrieves and returns the specified channel datum, raising an error if its key is not found.
-
#initialize(bone, *args, &block) ⇒ ChannelData
constructor
A new instance of ChannelData.
-
#relative_transform_matrix ⇒ Object
(also: #local_transform_matrix)
Returns the transform matrix for this bone’s channel data.
-
#rotate!(channel, theta) ⇒ Object
Modifies the specified channel datum, resulting in a rotation around the specified channel.
-
#set_channel(channel, theta) ⇒ Object
Sets the specified channel to a value of theta, and then returns self.
-
#translate!(x, y, z) ⇒ Object
Adds x, y and z to the X, Y and Z position channels, resulting in a “movement” or translation.
Constructor Details
#initialize(bone, *args, &block) ⇒ ChannelData
Returns a new instance of ChannelData.
7 8 9 10 |
# File 'lib/bvh/motion/channel_data.rb', line 7 def initialize(bone, *args, &block) @bone = bone super(*args, &block) end |
Instance Attribute Details
#bone ⇒ Object (readonly)
The bone that is related to this channel data.
5 6 7 |
# File 'lib/bvh/motion/channel_data.rb', line 5 def bone @bone end |
Instance Method Details
#arithmetic_proc(target) ⇒ Object
call-seq:
channel_data + channel_data => new_channel_data
channel_data - channel_data => new_channel_data
channel_data / channel_data => new_channel_data
channel_data * channel_data => new_channel_data
channel_data + number => new_channel_data
channel_data - number => new_channel_data
channel_data / number => new_channel_data
channel_data * number => new_channel_data
Performs arithmetic on this frame with the target. The second operand may be either a number or another ChannelData. If the target is a number, then that number is added to, subtracted from, multiplied with, or divided against each channel of this ChannelData.
If the target is another ChannelData, the arithmetic looks something like this:
return_value['Xposition'] = channel_data_one['Xposition'] * channel_data_two['Xposition']
return_value['Yposition'] = channel_data_one['Yposition'] * channel_data_two['Yposition']
return_value['Zposition'] = channel_data_one['Zposition'] * channel_data_two['Zposition']
. . .
Both objects must contain the same number of channels, and must also reference the same bone.
Returns a new instance of ChannelData containing the result.
36 37 38 |
# File 'lib/bvh/motion/channel_data.rb', line 36 def arithmetic_proc(target) # Fooled you again! I metaprogrammed it to save some typing! end |
#get_channel(channel) ⇒ Object
Retrieves and returns the specified channel datum, raising an error if its key is not found. If the channel key is a symbol, it is converted to a string before the lookup is performed.
66 67 68 69 70 |
# File 'lib/bvh/motion/channel_data.rb', line 66 def get_channel(channel) channel = channel.to_s if channel.kind_of?(Symbol) raise "Channel not found: #{channel} (expected one of #{self.keys.inspect})" unless self.keys.include?(channel) self[channel] end |
#relative_transform_matrix ⇒ Object Also known as: local_transform_matrix
Returns the transform matrix for this bone’s channel data. See also Frame#relative_transform_matrix and Frame#absolute_transform_matrix.
The resultant matrix needs to be multiplied against the parent bone’s transform matrix in order to be accurate to worldspace. Otherwise it’s only accurate in local space. If you’re not sure what that means, then use Frame#absolute_transform_matrix instead.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/bvh/motion/channel_data.rb', line 95 def relative_transform_matrix() # theta is retrieved from the set of numbers loaded from the BVH file, or is supplied directly # # R is the matrix calculated for a rotation of theta degrees around the vector V # This is performed on right, view and up vectors, multiplying the three matrices together # to construct the rotation matrix for this bone. Since the calculations are done in world # space, the right, up and view vectors are [1,0,0]; [0,1,0]; [0,0,1], respectively. No reason # we couldn't attach a Camera object to this bone and figure it out that way, but it'd actually # be more work to create and maintain the camera than to just calculate the matrix. Obviously, # the resultant matrix needs to be multiplied against the parent bone's rotation matrix in order # to be accurate to worldspace. Otherwise it's only accurate in local space. # # R = [tx^2 + c, txy - sz, txz + sy, 0] # [txy + sz, ty^2 + c, tyz - sx, 0] # [txz - sy, tyz + sx, tz^2 + c, 0] # [ 0, 0, 0, 1] # # where c = cos theta, # s = sin theta, # t = 1 - c # [x,y,z] = a unit vector on the axis of rotation # bone.channels.each so that we don't lose order of operation r = Matrix.identity(4) bone.channels.each do |chan| v = nil case chan when 'Xrotation' then v = [1,0,0] # right vector when 'Yrotation' then v = [0,1,0] # up vector when 'Zrotation' then v = [0,0,1] # view vector else next # ignore nonrotational values. To my knowledge, this includes only position values. end theta = self[chan] x, y, z = v c, s, t = Math.cos(theta), Math.sin(theta), 1 - Math.cos(theta) mat = Matrix.identity(4) mat[0,0], mat[0,1], mat[0,2] = t*(x**2) + c, t*x*y - s*z, t*x*z + s*y mat[1,0], mat[1,1], mat[1,2] = t*x*y + s*z, t*(y**2) + c, t*y*z - s*x mat[2,0], mat[2,1], mat[2,2] = t*x*z - s*y, t*y*z + s*x, t*(z**2) + c r *= mat end # Finally, the last row is simply set to the translation and/or bone offset. r[0,3] = bone.offset[0] + (self.key?("Xposition") ? self['Xposition'] : 0) r[1,3] = bone.offset[1] + (self.key?("Yposition") ? self['Yposition'] : 0) r[2,3] = bone.offset[2] + (self.key?("Zposition") ? self['Zposition'] : 0) r end |
#rotate!(channel, theta) ⇒ Object
Modifies the specified channel datum, resulting in a rotation around the specified channel.
73 74 75 76 77 78 79 80 |
# File 'lib/bvh/motion/channel_data.rb', line 73 def rotate!(channel, theta) theta = get_channel(channel)+theta # this doesn't really have an effect, but may help keep the file from getting junked. if theta >= 360 then theta %= 360 elsif theta <= -360 then theta %= -360 end set_channel(channel, theta) end |
#set_channel(channel, theta) ⇒ Object
Sets the specified channel to a value of theta, and then returns self.
58 59 60 61 62 |
# File 'lib/bvh/motion/channel_data.rb', line 58 def set_channel(channel, theta) channel = channel.to_s if channel.kind_of? Symbol raise "Channel not found: #{channel} (expected one of #{self.keys.inspect})" unless self.keys.include? channel self[channel] = theta end |
#translate!(x, y, z) ⇒ Object
Adds x, y and z to the X, Y and Z position channels, resulting in a “movement” or translation.
83 84 85 86 87 |
# File 'lib/bvh/motion/channel_data.rb', line 83 def translate!(x, y, z) set_channel('Xposition', get_channel('Xposition')+x) set_channel('Yposition', get_channel('Yposition')+y) set_channel('Zposition', get_channel('Zposition')+z) end |