Newer
Older
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"warning": "Needs bgl draw update",
CoDEmanX
committed
"description": "Display and edit motion trails in the 3D View",
"doc_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/Animation/Motion_Trail",
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
"category": "Animation",
}
import bgl
import blf
import bpy
from bpy_extras import view3d_utils
import math
import mathutils
from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
IntProperty,
StringProperty,
PointerProperty,
)
# fake fcurve class, used if no fcurve is found for a path
class fake_fcurve():
def __init__(self, object, index, rotation=False, scale=False):
# location
if not rotation and not scale:
self.loc = object.location[index]
# scale
elif scale:
self.loc = object.scale[index]
# rotation
elif rotation == 'QUATERNION':
self.loc = object.rotation_quaternion[index]
elif rotation == 'AXIS_ANGLE':
self.loc = object.rotation_axis_angle[index]
else:
self.loc = object.rotation_euler[index]
self.keyframe_points = []
def evaluate(self, frame):
return(self.loc)
def range(self):
return([])
# get location curves of the given object
def get_curves(object, child=False):
if object.animation_data and object.animation_data.action:
action = object.animation_data.action
if child:
# posebone
curves = [
fc for fc in action.fcurves if len(fc.data_path) >= 14 and
fc.data_path[-9:] == '.location' and
child.name in fc.data_path.split("\"")
]
curves = [fc for fc in action.fcurves if fc.data_path == 'location']
elif object.animation_data and object.animation_data.use_nla:
curves = []
strips = []
for track in object.animation_data.nla_tracks:
not_handled = [s for s in track.strips]
while not_handled:
current_strip = not_handled.pop(-1)
if current_strip.action:
strips.append(current_strip)
if current_strip.strips:
# meta strip
not_handled += [s for s in current_strip.strips]
for strip in strips:
if child:
# posebone
curves = [
fc for fc in strip.action.fcurves if
len(fc.data_path) >= 14 and fc.data_path[-9:] == '.location' and
child.name in fc.data_path.split("\"")
]
curves = [fc for fc in strip.action.fcurves if fc.data_path == 'location']
if curves:
# use first strip with location fcurves
break
else:
# should not happen?
curves = []
# ensure we have three curves per object
fcx = None
fcy = None
fcz = None
for fc in curves:
if fc.array_index == 0:
fcx = fc
elif fc.array_index == 1:
fcy = fc
elif fc.array_index == 2:
fcz = fc
fcz = fake_fcurve(object, 2)
return([fcx, fcy, fcz])
# turn screen coordinates (x,y) into world coordinates vector
def screen_to_world(context, x, y):
depth_vector = view3d_utils.region_2d_to_vector_3d(
context.region, context.region_data, [x, y]
)
vector = view3d_utils.region_2d_to_location_3d(
context.region, context.region_data, [x, y],
depth_vector
)
return(vector)
# turn 3d world coordinates vector into screen coordinate integers (x,y)
def world_to_screen(context, vector):
prj = context.region_data.perspective_matrix * \
mathutils.Vector((vector[0], vector[1], vector[2], 1.0))
width_half = context.region.width / 2.0
height_half = context.region.height / 2.0
x = int(width_half + width_half * (prj.x / prj.w))
y = int(height_half + height_half * (prj.y / prj.w))
# correction for corner cases in perspective mode
if prj.w < 0:
if x < 0:
x = context.region.width * 2
else:
x = context.region.width * -2
if y < 0:
y = context.region.height * 2
else:
y = context.region.height * -2
return(x, y)
# calculate location of display_ob in worldspace
def get_location(frame, display_ob, offset_ob, curves):
if offset_ob:
bpy.context.scene.frame_set(frame)
display_mat = getattr(display_ob, "matrix", False)
if not display_mat:
# posebones have "matrix", objects have "matrix_world"
display_mat = display_ob.matrix_world
if offset_ob:
loc = display_mat.to_translation() + \
offset_ob.matrix_world.to_translation()
else:
loc = display_mat.to_translation()
else:
fcx, fcy, fcz = curves
locx = fcx.evaluate(frame)
locy = fcy.evaluate(frame)
locz = fcz.evaluate(frame)
loc = mathutils.Vector([locx, locy, locz])
Loading
Loading full blame...