PhotoFlow like Effect

Moderators: Disciple, zlovatt

raju_sachania
Posts: 12
Joined: December 19th, 2006, 12:26 am

This was made in Flash using ActionScript. Can we get this done in After Effects using expressions?

http://www.flashloaded.com/flashcompone ... mple2.html
Paul Tuersley
Posts: 704
Joined: June 5th, 2004, 7:59 am
Location: London, UK

Someone asked about this on the adobe forums recently:
http://www.adobeforums.com/webx/.3c055512/0

And I knocked up this example project to show a fairly simple way to achieve it:
http://www.paul.tuersley.btinternet.co. ... ow.aep.zip
User avatar
Atomic
Posts: 157
Joined: April 30th, 2007, 5:55 am
Location: United States, Ohio

I like it Paul, nice work.

It is fairly easy to extend as well. Simply duplicate expression layers as needed and do a CTRL-ALT-/ to replace solid with footage.

I notice, in the "controllayer" you have some key frames that are animating the layers position and y-rotation. They don't seem to have any effect, is that just left over from development or do they serve a purpose?

Well, I got a little carried away with playing with your comp this morning.
I was working on a variation of import all images in a folder script last night. So I incorporated your expressions into the script.
Here it is:

Code: Select all

 //Import Section By Byron Nash 10/2004 
 //Revised 12/03/2007 Atom 

 /* 
  This script imports a folder of images and sequences them in a predestined comp. 
 It also sets ALL comps in the project to be the length of the new sequenced comp. 
 This is useful if you are versioning a bunch of images into the same graphic bed. 
  
 It also also animates the fade in and fade out for each layer. 
  
 Instructions: 
 1. Make sure you have a project with a comp at the very top. Put a "1" in front of the name if need be to keep it the first object in the list. 
 2. Run script 
 3. Choose a folder of files when prompted 
  
  Just to clarify, this script runs in passes, so it will import a series of image, then create layers from that import. 
  Because this script operates on an existing comp, it does no know the name of the comp, so it references the first object in the project window as the comp. 
  Consider this, you create default comp called "Comp 1" then you import a series of images froma folder. The folder contains an image called "blueprint.jpg". 
  Now blueprint.jpg is above Comp 1 in the project list and the script will try to operate on the JPG as if it were a comp. 
  This is what causes the error if you do not put a 1 in front of the comp name. You might want to put a zero. 
  If an image comes in with a 0 instead of a 1 as it's first character you could also error out. 
  It's not perfect, but it took me a while to figure this out so I thought I'd mention why it will error out and how to avoid this. 
  
  Limitation/ Flaws: 
   I already mentioned the naming of the comp flaw in this script. 
   I have hard coded the comp size and height to 720x480. 
   The duration of each imported image is given 5 seconds, you can adjust this by changing the variable, below. 
   The frame rate is calculated at 29.97 fps so if you are using another rate please change this value as well. 
   The import will also fail if the images in the folder have numbers prefixing their filename. 
 */ 
 { 
 // create undo group 
app.beginUndoGroup("Import and Sequence"); 

//Ask the user for a folder whose contents are to be imported 
var targetFolder = folderGetDialog("Import Items from Folder..."); //returns a folder or null 
if (targetFolder) 
{ 
   // if no project open, create a new project to toss the files into. [23839] 
   if (!app.project) {app.newProject();} 

   function processFile (theFile) 
   { 
      try { 
         var importOptions = new ImportOptions (theFile); //create a variable containing ImportOptions 
         importSafeWithError (importOptions); 
      } catch( error ) { 
         // eat errors. 
      } 
   } 
    
   function testForSequence (files) 
   { 
      var searcher = new RegExp ("[0-9]+"); 
      var movieFileSearcher = new RegExp ("(mov|avi|mpg)$", "i"); 
      var parseResults = new Array; 
       
      //test that we have a sequence, stop parsing after 10 files 
      for (x = 0; (x < files.length) & x < 10; x++) 
      { 
         var movieFileResult = movieFileSearcher.exec(files[x].name); 
         if (! movieFileResult) 
         { 
            var currentResult = searcher.exec(files[x].name); 
            //regular expressions return null if no match was found 
            //otherwise they return an array with the following information: 
            //array[0] = the matched string 
            //array[1..n] = the matched capturing parentheses 
          
            if (currentResult) { //we have a match - the string contains numbers 
               //the match of those numbers is stored in the array[1] 
               //take that number and save it into parseResults 
               parseResults[parseResults.length] = currentResult[0]; 
            } 
            else { 
               parseResults[parseResults.length] = null; 
            } 
         } 
         else { 
            parseResults[parseResults.length] = null; 
         } 
      } 
       
      //if all the files we just went through have a number in their file names, 
      //assume they are part of a sequence & return the first file 
      var result = null; 
      for (i = 0; i < parseResults.length; ++i) { 
         if (parseResults[i]) { 
            if (! result) { 
               result = files[i];       
            }    
         } else { 
            //case in which a file name did not contain a number 
            result = null; 
            break; 
         } 
      } 
      return result; 
   } 

   function importSafeWithError (importOptions) 
   { 
      try { 
         app.project.importFile (importOptions); 
      } catch (error) { 
         alert(error.toString() + importOptions.file.fsName); 
      } 
   } 

   function processFolder(theFolder) 
   { 
      var files = theFolder.getFiles(); //Get an array of files in the target folder 
          
      //test whether theFolder contains a sequence 
      var sequenceStartFile = false;	//testForSequence(files); 
       
      //if it does contain a sequence, import the sequence 
      if (sequenceStartFile) { 
         try { 
            var importOptions = new ImportOptions (sequenceStartFile); //create a variable containing ImportOptions 
             
            importOptions.sequence = true; 
            //importOptions.forceAlphabetical = true; //un-comment this if you want to force alpha order by default 
            importSafeWithError (importOptions); 
         } catch (error) { 
          
         } 
      } 
       
      //otherwise, import the files and recurse 
      //Go through the array and set each element to singleFile, then run the following 
      for (index in files) 
      { 
         if (files[index] instanceof File) { 
            if (! sequenceStartFile) { //if file is already part of a sequence, don't import it individually 
               processFile (files[index]); //calls the processFile function above 
            } 
         } 
         if (files[index] instanceof Folder) { 
            processFolder (files[index]); // recursion 
         } 
      } 
   } 
   processFolder(targetFolder); 
} 

//Script begins here. 
var logoSel = app.project.selection;            		//set selected import items to an array 
var logoComp = app.project.item(1);            		//select the logo comp 
var compW = 720;                     				// comp width 
var compH = 480;                      				// comp height 
var perImageDuration= 900;                  			//Frames divided by frame rate equals seconds. 
logoComp.duration = perImageDuration/29.97		//set comp length to 1 second 

//loop through and add layers to comp 
for (i=0; i < logoSel.length; i++) 
{          
	//Add to logo comp 
	if(logoSel[i] instanceof FootageItem) 
	{                        				//test to be sure it's not a comp or folder 
		var lcoll = logoComp.layers;        	//variable for collection of layer objects in logoComp 
		lcoll.add(logoSel[i]);            		//add layer 
		//alert (logoSel[i].name); 
	}    
} 
//At this point, all imported items are in the project window. 

//Now we must add them to the comp. 
var curIn = 0;						//initialize in point variable 
var i = 1; 							//collection items start at 1. 
//Loop through layers 
do 
{ 
	//Add footage layer. 
	var curLayer = lcoll[i]; 
	curLayer.threeDLayer = true;					//make 3d
	curLayer.startTime = curIn;					//set in point 
	var curOut = curLayer.outPoint;				//set out 
	/*
	//Auto animate the fade in and out for this layer. 
	myOpacity= curLayer.property("opacity"); 
	myOpacity.setValueAtTime(curIn,0); 
	myOpacity.setValueAtTime(curIn + 0.25,100); 
	myOpacity.setValueAtTime(curOut - 0.25,100);		//Effectively creates a hold frame, can cause problems on interlace footage. 
	myOpacity.setValueAtTime(curOut,0); 
	*/
	var position_expression = "timeOffset = thisComp.layer('control layer').effect('Slider Control')('Slider') / 10;\nthisComp.layer('control layer').transform.position.valueAtTime(timeOffset + (index * thisComp.frameDuration * 50));\n"
	var y_rotation_expression = "timeOffset = thisComp.layer('control layer').effect('Slider Control')('Slider') / 10;\nthisComp.layer('control layer').transform.yRotation.valueAtTime(timeOffset + (index * thisComp.frameDuration * 50));\n"
	curLayer.property("position").expression  = position_expression;
	curLayer.property("yRotation").expression  = y_rotation_expression;
	
	//curIn = curOut;							//new in point equals old out point. 
	//alert (curLayer.name); 
	i++; 
}while(i<=(lcoll.length-2)); //Expects light layer and control layer to be in the comp hence the -2 layers.
        
// Set Final Comp to correct length. 
logoComp.duration = (i-1) * logoComp.duration;		//set comp end to reflect the new length. 
compDur = logoComp.duration;            				//set variable for all comps 
var stuff = app.project.items;            				//get collection of project items 
for (i=1; i <= stuff.length; i++) 
{//loop through project looking for our original comp item that was selected before we ran this script. 
	if(stuff[i] instanceof CompItem) 
	{//check for comp 
	stuff[i].duration = compDur;					//set comp length 
	} 
} 
alert("Finished Importing and Sequencing of Images. Be sure to save the project as a new name.") 
app.endUndoGroup(); 
} 
CAVEAT:
This script expects the light and the control layer to be in place before you run it. Also you need to rename your comp so there is a #1 as the first character in the comp name.

USAGE:
Downlaod Paul's coverflow aep (above) and open the project.
Delete everything except the light and a single control layer.
Rename the comp to 1Coverflow
Run the script and browse to a folder with a bunch of footage items.

RESULTS:
The script will make a 3d layer out of each footage item in the folder and assign the two expressions to position and y rotation. After execution, you can scrub slider control to flip throught the images.

TODO:
Ideally, I would like the script to make the light and the control layer, but I am not that well versed at creating different layer types and assigning effects to them (yet!).

FALLOUT:
Does not support the reflection, but it may not be that hard to recreate once the import has been done.

Thanks again for the great AEP Paul!
Last edited by Atomic on December 4th, 2007, 8:28 am, edited 4 times in total.
Paul Tuersley
Posts: 704
Joined: June 5th, 2004, 7:59 am
Location: London, UK

Atomic wrote:I notice, in the "controllayer" you have some key frames that are animating the layers position and y-rotation. They don't seem to have any effect, is that just left over from development or do they serve a purpose?
The keyframes on the control layer contain all the animation. All the other layers are using "valueAtTime" expressions to copy that animation, with a time offset based on their layer index. You can make multiple copies of the control layer and try out different kinds of animation...whichever is the topmost layer will become the actual controlling layer.

Personally, I think you'd have to be nuts to try to do all the animation with some complicated expressions when it's so much easier to do it with keyframes.
raju_sachania
Posts: 12
Joined: December 19th, 2006, 12:26 am

Thanks Paul,

I will try this project later in this weekend.
raju_sachania
Posts: 12
Joined: December 19th, 2006, 12:26 am

Paul, you are magician. The effects just work right for me. Thanks a lot.
harico
Posts: 4
Joined: December 6th, 2007, 6:23 am

Too cool thanks for the pointers
will look into it tomorrow morning

h
pants
Posts: 22
Joined: October 8th, 2004, 8:35 am

How could you tweak this so instead of just having the images in a straight line, you could have a rotating cylinder in 3d space with all layers at a y rotation of 90º but when a layer is in the center/front it turns to 0º. and then back to 90º as it passes by?

thanks
User avatar
Atomic
Posts: 157
Joined: April 30th, 2007, 5:55 am
Location: United States, Ohio

There used to be a "wet floor" script here:

http://www.nabscripts.com/Downloads/downloads_en_1.php

But is seems to have been removed...?

The wet floor script would arrange them in a cricle like you mentioned.
"Up And Atom

No...No

Up And At Them!"
pants
Posts: 22
Joined: October 8th, 2004, 8:35 am

thanks atomic. here's where the wet floor script is.
http://www.nabscripts.com/Experiments/S ... pts_en.php

but it's not exactly what i was looking for.

Here's some screen shots and a short video of what i'm to do. if anyone has any tips I'd love to hear them.
video here: http://ptulipano.googlepages.com/Test.mov

thanks
Attachments
CircularFlow__0000_03.jpg
CircularFlow__0000_03.jpg (54.21 KiB) Viewed 79198 times
CircularFlow__0001_02.jpg
CircularFlow__0001_02.jpg (55.33 KiB) Viewed 79199 times
verydiscreet
Posts: 2
Joined: July 17th, 2005, 11:08 pm

Somebody got the project file that Paul posted? I've tried to use he script but getting nowhere. Been at it for the last two days, and no luck. Would really appreciate if someone can re-up the file.
Paul Tuersley
Posts: 704
Joined: June 5th, 2004, 7:59 am
Location: London, UK

You can download it from the link in my first reply. It wasn't working earlier but it is now.

Paul
kobyg
Posts: 128
Joined: December 7th, 2007, 10:11 am

Hi Guys !
I have managed to change the animation to a circle, instead of a straight line, just like pants asked !
I have tweaked the project file Paul uploaded, and added another Control Layers at the top, that does the job.
I added also a camera to show the scene a bit from above, and changed the location of the light source.

I made 2 options: one is a half circle, as in the link pants had sent, and the second one is a full circle !
You can download the project file here:
coverflow.zip
Circular_Cover_Flow
(13.75 KiB) Downloaded 3801 times
You can use that file, the same you used Pauls' file: the most upper Control Layer would control the motion.
(change the Control layer's Slider keyframes in order to flow the pictures, I've keyframed them to see the animation)

I managed to do it using a small script I wrote that changes the position and rotation keyframes of the Control layer, and replaces the keyframes needed for the circular motion.
If you find it interesting, here is the script:

Code: Select all

// Circular Cover Flow Animation - changing Contol Layer's keyframes
// Written by Koby Goldberg
// select one Control Layer, remove all it's keyframes and run the script.
// put: K = 1 for half circle, and K = 2 for a full circle

{
app.beginUndoGroup("CircularCoverFlowAnimation");                              // create an undo group 
var curItem = app.project.activeItem; 
if (curItem == null || !(curItem instanceof CompItem)){                        // check if comp is selected 
alert("Please establish a comp as the active item and run the script again");  // if no comp selected, display an alert
} else { 

var K = 1;  // K=1 - half circle , K=2 - full circle

var curLayer = curItem.selectedLayers[0];
var N = 9;                        // number of layers in a half circle
var T = curItem.frameDuration;
var T1 = 30*T;                    // duration time of static phase
var T2 = 20*T;                    // duration time of movement
var xo = 360;                     // center of circle - x
var yo = 288;                     // center of circle - y
var zo = 500;                     // center of circle - z
var dz = 100;                     // indent of middle picture
var R = 800;                      // radius of circle
var pi = Math.PI;
var x,y,z;
var m = 0;

N = N*K + (K-1);

for (var n=0; n<N; n++)
{
	if (n==((N-1)/2-1) || n==((N-1)/2+1))
	continue;
	x = xo + R*Math.cos(pi/K + K*pi*n/(N-1));
	z = zo + R*Math.sin(pi/K + K*pi*n/(N-1)) - (n==(N-1)/2 ? dz : 0);
	y = yo;
	Phiy = (n<(N-1)/2) ? (-n*K*180/(N-1)) : ( (n>(N-1)/2) ? (K*180*((N-n-1)/(N-1))-180*(K-1)) : -90*(K-1) ) ;
	
	curLayer.position.setValueAtTime(m*(T1+T2),[x,y,z]);
	curLayer.position.setValueAtTime(m*(T1+T2)+T1,[x,y,z]);
	curLayer.yRotation.setValueAtTime(m*(T1+T2),Phiy+ 90*(K-1));
	curLayer.yRotation.setValueAtTime(m*(T1+T2)+T1,Phiy+ 90*(K-1));
	m++;
}
}

app.endUndoGroup();                 // close the undo group
}

You can use the script on the original file Paul uploaded, to achieve the same result of the project file I've uploaded:
1. choose one Control Layer (or duplicate one, and make sure to rename it to the same original name)
2. remove all it's position and rotation keyframes (by clicking the stop-watch of each property)
3. make sure that layer is selected and run the script (the script will automatically work only on the selected layer)
4. in order to see it propely, add a camera and position it above the scene to show the circular path of the pictures.
(I reccommend using a 138mm Preset Camera or above, in order to avoid perspective distortion of the pictures)
5. move the light source to the center of the screen, and pull it back in Z depth, to light the pictures correctly.
6. In order to have the reflections correclty, operate the script again on the Control Layers in the Refelction composition.

In order to do a half circle, change in the script the value of the K variable to 1, and for a full circle change it's value to 2.
(you'll see it as the first variable in the script: "var K = 1;" . Do this before you run the script off course)

NOTE: You could still use the script atom & byron wrote, in order to import pictures to the project file I've uploaded. Thank you guys for the great job ! Note that if you use atom & byron 's script on my project file, don't delete the camera and the light, and you can leave all Control layers (make them inactive) so you can change the behavior of the animation easily later (by changing their order). Note that when I tried that, I just had to disable the expression the light got by mistake from the script (by clicking the [=] signs), and then it worked perfectly (except the script doesn't add the reflections).

Great thanks to Paul, for making this animation and the expressions in the first place !

Enjoy,
and let me know what you think.

Koby.
pants
Posts: 22
Joined: October 8th, 2004, 8:35 am

koby,

very cool. thanks for taking the time to do this. it looks great.
kobyg
Posts: 128
Joined: December 7th, 2007, 10:11 am

You could add an interesting motion effect to the animation if you space all the position & rotation keyframes a bit wider (by holding the ALT and then clicking & dragging the rightmost keyframe to the right something about 20-30 frames). That would create some kind of wave behaviour instead of all the pictures move together and then stand together (something reminding the wave effect a crowd sometimes makes in a soccer or a football game).

If you stretch all keyframes such that the last one is moved by exactly 50 frames to the right, you would get a constant movement wavy motion: Every picture would stand for the same amount of time, but there will be no time where nothing moves. You could try that operation on every Control layer that you want, but I think that with the full circle Control layer this would look best !

Lastly, you could try adding EaseIn/EaseOut (by using F9) to all position & rotation keyframes to get smoother and more natural motion.

Enjoy,
Koby.

p.s: You would have to increase the length of the composition (by using CTRL+K) to at least 36 seconds, in order to see all keyframes I made in the full circle control layer, and to be able to correctly choose ALL of them before you widen their spaces...
Post Reply