Importing Keyframes?

Animation tools, character animation, non linear animation

Moderators: jesterKing, stiv

Weajiin
Posts: 8
Joined: Thu May 31, 2012 8:53 am

Importing Keyframes?

Postby Weajiin » Thu May 31, 2012 9:00 am

First off, I want to thank you for your time. A little overview: I play a game called League of Legends. Using a program called LOLReplay, I can have replay any match and record it with Frapps. The LOLReplay program doesn't save the positioning of my mouse and button presses though. So I wrote a program to save that information as I play. The output of that program looks something like this for the mouse positions: 254,12;254,14;269,23;. In the format x,y; x,y; My eventual goal is to load these positions into blender and render the mouse movement with something fancy like a glowing cloud cursor or something and then overlay that onto my video from Frapps. My problem is, I don't know how to load the "keyframes" for the cursor into Blender.

CoDEmanX
Posts: 894
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Postby CoDEmanX » Thu May 31, 2012 4:21 pm

so you want to:
- read cursor data from file
- keyframe an object with this data in blender

there are a lot import scripts, you should have a look at them

keyframing example:
http://www.blender.org/documentation/bl ... #animation
I'm sitting, waiting, wishing, building Blender in superstition...

CoDEmanX
Posts: 894
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Postby CoDEmanX » Thu May 31, 2012 8:37 pm

Here's some working code:


Code: Select all

import bpy


def create_cursor(context, filepath):
   
    if context.object and context.object.mode != 'OBJECT':
        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
       
    #for ob in bpy.data.objects:
    #    ob.select = False
    bpy.ops.object.select_all(action='DESELECT')
       
    # Add empty object
    ob = bpy.data.objects.new("Cursor", None)
    context.scene.objects.link(ob)
    #ob.location.y = context.scene.cursor_location.y
    context.scene.objects.active = ob
    ob.select = True
   
    f = open(filepath, 'r')
    data = f.read()
    f.close()

    data = data.replace(" ", "").strip(",;")
   
    #x, y = [pairs.split(",") for pairs in data.split(";")]
   
    pairs = data.split(";")
   
    for frame, pair in enumerate(pairs, context.scene.frame_current):
       
        # Cast coords from string to int
        pair = [int(pair) for pair in pair.split(",")]
       
        # Keyframe xz locations to be viewed from front view
        ob.location.x = pair[0]
        ob.keyframe_insert("location", index=0, frame=frame)
        ob.location.z = pair[1]
        ob.keyframe_insert("location", index=2, frame=frame)
       
    context.scene.update()
       
    return {'FINISHED'}


# ImportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ImportHelper
from bpy.props import StringProperty
from bpy.types import Operator


class ImportCursor(Operator, ImportHelper):
    '''Import X and Z values in the format: x1,y1;x2,y2; etc.'''
    bl_idname = "import_anim.cursor"
    bl_label = "Import Cursor animation"

    # ImportHelper mixin class uses this
    filename_ext = ".txt"

    filter_glob = StringProperty(
            default="*.txt",
            options={'HIDDEN'},
            )

    def execute(self, context):
        return create_cursor(context, self.filepath)


# Only needed if you want to add into a dynamic menu
def menu_func_import(self, context):
    self.layout.operator(ImportCursor.bl_idname)


def register():
    bpy.utils.register_class(ImportCursor)
    bpy.types.INFO_MT_file_import.append(menu_func_import)


def unregister():
    bpy.utils.unregister_class(ImportCursor)
    bpy.types.INFO_MT_file_import.remove(menu_func_import)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.import_anim.cursor('INVOKE_DEFAULT')
I'm sitting, waiting, wishing, building Blender in superstition...

Weajiin
Posts: 8
Joined: Thu May 31, 2012 8:53 am

Postby Weajiin » Fri Jun 01, 2012 8:49 am

I stayed up late last night fixing a few of the issues. I had found the link you just gave me and hacked up what I thought would work. Unfortunately there was an issue that needed to be addressed. My fix changes my mouse programs output. It used to just grab mouse position and save it each time there was a change in x or y coordinates. System performance would effect the "resolution" of my mouse position sampling and the output did not adhere to any kind of time structure.

So I rewrote the sampling loop. It now takes samples based on a limited "frame rate". Right now that number is set to 30 frames per second. So each second I get 30 mouse positions spaced evenly over that second. Also I keep a frame count. The new output structure looks like this:

Code: Select all

xPostion,yPosition,Frame;


At the time I was unsure of how to interface a file with blender so I wrote a separate script to convert the output file into a blender readable script. Unfortunately this option loses viability with large file types as it has a 1:16 size ratio per each mouse sample.

Code: Select all

listX = []
listY = []
listT = []
listZ = []

fps = 29.99
iterator = 0

for line in open("mousedump.csv", "r"):
    listZ = line.split(",")
    listX.append(int(listZ[0]))
    listY.append(int(listZ[1]))
    listT.append(float(listZ[2].strip(";\n")))

output = open("keyframe.py", "w")
output.write("import bpy\n")
output.write("obj = bpy.context.object\n")

print len(listX)
print len(listY)
print len(listT)

while(iterator < len(listX)):
    output.write("obj.location[0]=")
    output.write(str(listX[iterator]))
    output.write("\n")
    output.write("obj.location[1]=")
    output.write(str(listY[iterator]))
    output.write("\n")
    output.write("obj.keyframe_insert(data_path=\"location\", frame=")
    output.write((str(listT[iterator])))
    output.write(", index=2)\n")
    iterator += 1
       
output.close()


When I ran the output from the above program in Blender with the default cube selected it would shoot of into space. This was a design oversight by me. How can I convert my mouse position data so that it stay on the grid? I will keep track of my screen resolution and set the render resolution to the same value, but I need the empty object to move around in front of the camera.

Once again, you helped is greatly appreciated.[/b][/list]

Weajiin
Posts: 8
Joined: Thu May 31, 2012 8:53 am

Postby Weajiin » Fri Jun 01, 2012 9:32 am

From what I can tell this does the trick.

Code: Select all

# Keyframe xz locations to be viewed from front view
        ob.location.x = pair[0]
        ob.keyframe_insert("location", index=0, frame=[2])
        ob.location.z = pair[1]
        ob.keyframe_insert("location", index=2, frame=[2])

Weajiin
Posts: 8
Joined: Thu May 31, 2012 8:53 am

Postby Weajiin » Fri Jun 01, 2012 9:43 am

Your method works for me at a small scale; however, my files have upwards of 60,000 entries. When I run a sample file through it, containing 60,281 individual frames, my blender is just left hanging for a long time. I'm unsure if it is completing the operation slowly or it is out of memory. Keep in mind it is only really about 1MB worth of data.

CoDEmanX
Posts: 894
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Postby CoDEmanX » Fri Jun 01, 2012 2:42 pm

could you provide this 1mb file so i can test?

i don't really understand why you added a frame counter, isn't it just 1,2,3,4,... ?
I'm sitting, waiting, wishing, building Blender in superstition...

Weajiin
Posts: 8
Joined: Thu May 31, 2012 8:53 am

Postby Weajiin » Fri Jun 01, 2012 8:07 pm

I am a new to programming so sometimes I don't fully think things through. I didn't realize I could go without including the frames. Anyway, here is the file.
https://docs.google.com/open?id=0B5VXpPSW8occZ0FJOVJINm5zQ2c

Weajiin
Posts: 8
Joined: Thu May 31, 2012 8:53 am

Postby Weajiin » Fri Jun 01, 2012 8:08 pm

On my computer, chunks of 10,000 would stop it for a second, but they would load properly.

CoDEmanX
Posts: 894
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Postby CoDEmanX » Sat Jun 02, 2012 4:14 am

ya, same here. This loads 60k positions in less than 5 seconds

http://www.pasteall.org/32512/python
NOTE: this expects txt input like:

Code: Select all

12,34
56,78
9,0

So each coord in a new line, x and y separated by a comma, no whitespace

you shouldn't go to Animation screen, lags like hell.

Set sync mode to frame dropping for playback.

I added a random x / 100 to limit the movements, you should be able to limit to actual bounds with some extra math
I'm sitting, waiting, wishing, building Blender in superstition...

Weajiin
Posts: 8
Joined: Thu May 31, 2012 8:53 am

Postby Weajiin » Sun Jun 03, 2012 12:15 am

How long have you been scripting for blender? This works great by the way :)

Weajiin
Posts: 8
Joined: Thu May 31, 2012 8:53 am

Postby Weajiin » Sun Jun 03, 2012 1:00 am

Where was the bottleneck in that code?

CoDEmanX
Posts: 894
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Postby CoDEmanX » Sun Jun 03, 2012 2:51 am

I started to learn Python and Blender API 1 year ago.

Bottleneck is mostly operators, as they implicitly update scene or stuff, which means extra memory consumption and decreasing speed for each loop iteration:

run op, update object 1
run op, update object 1, 2
run op, update object 1, 2, 3
etc.

using "low-level" functions is way faster but more difficult


you could improve performance if you skipped subsequent duplicates, like x coord:
1, 2, 2, 2, 2, 3, 3

no need to store all two's, first and last would be just fine:
1, 2, skip frames, 2, 3, 3

should be done in your mouse recording script already to keep filesize down (required frame counter)
I'm sitting, waiting, wishing, building Blender in superstition...


Return to “Animation”

Who is online

Users browsing this forum: No registered users and 1 guest