Previous Thread  Next Thread

chat icon Importing Keyframes?

Weajiin

Posted: Thu May 31, 2012 8:00 am
Joined: 31 May 2012
Posts: 8
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.
Reply with quote


CoDEmanX

Posted: Thu May 31, 2012 3:21 pm
Joined: 05 Apr 2009
Posts: 692
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/blender_python_api_2_63_7/info_quickstart.html#animation
_________________
I'm sitting, waiting, wishing, building Blender in superstition...
Reply with quote


CoDEmanX

Posted: Thu May 31, 2012 7:37 pm
Joined: 05 Apr 2009
Posts: 692
Here's some working code:


Code:
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...
Reply with quote


Weajiin

Posted: Fri Jun 01, 2012 7:49 am
Joined: 31 May 2012
Posts: 8
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:
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:
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]
Reply with quote


Weajiin

Posted: Fri Jun 01, 2012 8:32 am
Joined: 31 May 2012
Posts: 8
From what I can tell this does the trick.
Code:
# 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])
Reply with quote


Weajiin

Posted: Fri Jun 01, 2012 8:43 am
Joined: 31 May 2012
Posts: 8
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.
Reply with quote


CoDEmanX

Posted: Fri Jun 01, 2012 1:42 pm
Joined: 05 Apr 2009
Posts: 692
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...
Reply with quote


Weajiin

Posted: Fri Jun 01, 2012 7:07 pm
Joined: 31 May 2012
Posts: 8
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
Reply with quote


Weajiin

Posted: Fri Jun 01, 2012 7:08 pm
Joined: 31 May 2012
Posts: 8
On my computer, chunks of 10,000 would stop it for a second, but they would load properly.
Reply with quote


CoDEmanX

Posted: Sat Jun 02, 2012 3:14 am
Joined: 05 Apr 2009
Posts: 692
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:
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...
Reply with quote


Weajiin

Posted: Sat Jun 02, 2012 11:15 pm
Joined: 31 May 2012
Posts: 8
How long have you been scripting for blender? This works great by the way Smile
Reply with quote


Weajiin

Posted: Sun Jun 03, 2012 12:00 am
Joined: 31 May 2012
Posts: 8
Where was the bottleneck in that code?
Reply with quote


CoDEmanX

Posted: Sun Jun 03, 2012 1:51 am
Joined: 05 Apr 2009
Posts: 692
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...
Reply with quote


 
Jump to:  
Powered by phpBB © 2001, 2005 phpBB Group