2
$\begingroup$

I am trying to make point light displays (an example: https://www.youtube.com/watch?v=r0kLC-pridI). So far, I have used c3d files from Carnegie Mellon University, Motion Capture Database (link:http://mocap.cs.cmu.edu/search.php?subjectnumber=%&motion=%). The c3d files contain the XYZ coordinates of the markers across time.

I import the c3d file into Blender. And Blender creates an empty for each marker. Then, I create materials for each empty and set their attributes. In this way, there will be a flat white little square on each marker. And I render the animation and something similar to the YouTube video will be the output.

Now, I need to create the same stimulus but the empties' locations would be scrambled. In this case, only XYZ coordinates of the markers would be changed but their motion vector would stay the same. The output will be some random moving dots that do not have the shape of a person moving.

Here, the intact and scrambled stimuli are motion-matched. Meaning, they both have the same motion properties. But they are different in the position of their markers.

Now my question is that; is there any option in Blender to scramble the XYZ of the empties?

My not-an-easy option is to add a random constant to my XYZ coordinates for each empty for each frame.

Sorry if this is not clear. My goal is to use these stimuli in an fMRI experiment to see how the human brain perceive motion.

$\endgroup$
  • 3
    $\begingroup$ Welcome to Blender Stack Exchange! I think you will need to provide more details for the community to help or even understand what you're trying to do. "Motion-matched but scrambled..." I can sort of maybe imagine/guess what you mean, but without visual references I have no way of knowing. Also, your question assumes knowledge of other software without explaining what the software does or what the nature of the data is. I don't think many will be willing to go on a scavenger hunt across the web trying to figure it out, so I recommend explaining a bit more if you hope to get answers. $\endgroup$ – Mentalist Apr 19 '17 at 5:56
  • $\begingroup$ Thank you. I updated my question. Hopefully it's more clear now. $\endgroup$ – Fibonacci Apr 20 '17 at 16:07
  • $\begingroup$ Thanks for providing more details. I think I have a more clear idea now of what you want to do. Basically you want to add some randomness to the XYZ coordinates of a bunch of Empties? Do you have a .blend file you can post to Blend Exchange that I can experiment with? If not I'll try to answer generally how to randomize Empty locations over time. $\endgroup$ – Mentalist Apr 20 '17 at 23:46
  • $\begingroup$ Thank you @Mentalist. Please look below. Lemon has responded perfectly. $\endgroup$ – Fibonacci Apr 23 '17 at 2:15
2
$\begingroup$

Here is an addon to do that (if my comprehension of the question is good).

enter image description here

To make it work, you need to associate the wanted objects (empties) in an object's group.

Then:

  • Choose the group in the UI
  • Set min and max values (the scramble part will take 3 random values in between and shift x, y, z with them)
  • Choose a seed if you want to repeat it with the same random sequence
  • Use the scramble button.

The scramble function is commented in the code below (other parts are simple UI):

bl_info = {
    "name": "Scramble animation locations",
    "author": "lemon",
    "version": (1, 0),
    "blender": (2, 78, 0),
    "location": "",
    "description": "",
    "warning": "",
    "wiki_url": "",
    "category": "Animation"}

import bpy
from random import Random

def ScrambleObjectAnimation( object, scrambleMin, scrambleMax, rnd ):
    #If there is an animation
    if object.animation_data:
        #Get random values to shift/scramble x y and z
        dx = rnd.uniform( scrambleMin, scrambleMax )
        dy = rnd.uniform( scrambleMin, scrambleMax )
        dz = rnd.uniform( scrambleMin, scrambleMax )
        delta = [dx, dy, dz]
        #Loop on the animation curves that correspond to the location
        for curve in [c for c in object.animation_data.action.fcurves if c.data_path.endswith( 'location' )]:
            #Shift all control points of the curve
            for key in curve.keyframe_points:
                key.co[1] += delta[curve.array_index]

def ScrambleObjectsAnimation( objects, scrambleMin, scrambleMax, seed ):
    rnd = Random()
    if seed > 0:
        rnd.seed( seed )
    for object in objects:
        ScrambleObjectAnimation( object, scrambleMin, scrambleMax, rnd )

def SettingsAreOK( context ):
    return True

class ScrambleObjectAnimationOperator( bpy.types.Operator ):
    bl_idname = "lemon.scrambleobjectanimationoperator"
    bl_label = "Scramble objects animation"
    bl_options = {'REGISTER','UNDO'}

    @classmethod
    def poll(self, context):
        return context.mode == 'OBJECT' and SettingsAreOK( context )

    def invoke(self, context, event):
        scn = context.scene
        settings = scn.scrambleObjectAnimation

        #try:
        objects = bpy.data.groups[settings.group_name].objects
        scrambleMin = settings.scramble_min
        scrambleMax = settings.scramble_max
        seed = settings.seed
        ScrambleObjectsAnimation( objects, scrambleMin, scrambleMax, seed )
        #except:
            #pass

        return { 'FINISHED' }

class ScrambleObjectAnimationPanel( bpy.types.Panel ):
    bl_idname = 'lemon.scrambleobjectanimationpanel'
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_label = "Scramble objects animation"

    @classmethod
    def poll(self, context):
        return context.mode == 'OBJECT'

    def draw(self, context):
        layout = self.layout
        scn = context.scene

        settings = scn.scrambleObjectAnimation

        layout.row().prop_search( settings, "group_name", bpy.data, "groups", text="Object group" )
        layout.row().prop( settings, "scramble_min" )
        layout.row().prop( settings, "scramble_max" )
        layout.row().prop( settings, "seed" )
        layout.row().operator( ScrambleObjectAnimationOperator.bl_idname, text="Scramble" )

class ScrambleObjectAnimationProps( bpy.types.PropertyGroup ):
    group_name = bpy.props.StringProperty()
    scramble_min = bpy.props.FloatProperty( name="Scramble min", default=-1.0, soft_min=-10, soft_max=0, step=2, precision=2 )
    scramble_max = bpy.props.FloatProperty( name="Scramble max", default=1.0, soft_min=0, soft_max=10, step=2, precision=2 )
    seed = bpy.props.IntProperty( name="Seed", default=0, min=0)

def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.scrambleObjectAnimation = bpy.props.PointerProperty( type = ScrambleObjectAnimationProps )

def unregister():
    del bpy.types.Scene.scrambleObjectAnimation
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()

$\endgroup$
  • $\begingroup$ THANK YOU! Thank you so much! This is exactly what I wanted. I have downloaded your Add-on and it perfectly works when I pick Group2 or Group2.001 but not Group. Also when I import another C3D file, I cannot get the scramble works. I run the script and then do the steps that you mentioned. I will try to get it work. Thank you again. $\endgroup$ – Fibonacci Apr 23 '17 at 2:13
  • $\begingroup$ @Fibonacci, 'Group' is not assigned in the file, so this is normal. You have to set the empties to an objects group. To do that, select the empties (all) then ctrl+G. That creates a group to which empty will belong so that you can use this group in the addon $\endgroup$ – lemon Apr 23 '17 at 5:10
  • $\begingroup$ @Fibonacci, there is another 'detail' you need to know (if you don't already): some c3D files are not processed to be consistent. By that I mean an given empty from a frame to another does not correspond to the same part of the body. In this case, the script won't correct that (of course) and the result may be weird. You should provide a sample file to check that. $\endgroup$ – lemon Apr 23 '17 at 5:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.