Thursday, April 11, 2013

things I've learned about Source Filmmaker

I've been playing with Source Filmmaker a bit lately, and I wanted to document some of the things that I've learned.

The best source of information is the official SFM wiki.

There are also numerous video tutorials available on YouTube, including the official ones.

The up and down arrows take the playhead to the beginning and ending of a shot, respectively.

Audio should be in WAV format. And I recommend using a nice USB microphone for recording audio.

More models and props can be downloaded (subscribed) from the Steam Workshop. I was particularly interested in models with facial animations for lip-sync, and there are a number available there.

Attach a prop (e.g. a hat) to a character's head by locking it to the bip_head control in the character's animation set. Drag the character's bip_head control on to the hat's bip_head (or rootTransform) control, then select all of time in the Motion Editor (if it's not all green already), select the Body animation set of your prop and then under Procedural drag the Default control from left to right. You may need to adjust its position a little, especially if you used rootTransform because there was no bip_head.

Attach a prop to a character's hand by locking it to the weapon_bone under Unknown in the character's animation set. Similar to the above process.

In order to render 1080p videos, you need to start the program with the argument -sfm_resolution 1080 (either from your Steam library by right-clicking it and choosing Properties then SET LAUNCH OPTIONS... or by editing the desktop shortcut). This isn't recommended until you're ready to render, since working in 1080p makes things a little slow. Rendering 1080p videos takes a long time too, on my i7 desktop it took almost an hour and a half to render a one minute clip. If you're really adventurous you can render at 4K with -sfm_resolution 2160 but you'll need a decent computer a lot of time.

The basic process I go through to create videos (like the one below) is:
  1. launch Source Filmmaker
  2. name your session (or open an existing session)
  3. set the Framerate to 30 (although the default 24 is fine too)
  4. right-click the black part where it says "No Map Loaded!" and choose Load Map...
  5. decide where you'd like to film
    • you can move the camera around by holding down the mouse button where you'd just loaded a map (the viewport) while you use the keys WASD and ZX
  6. click the + sign right underneath Animation Set Editor to Create Animation Set for New Model
    • look in the categories player and survivors for good human models
  7. move the model to the appropriate place by selecting its name in the Animation Set Editor, the move tool  (near the bottom right of the map window) and either the Motion Editor (F3) or the Graph Editor (F4)
  8. add a camera by pressing c on the keyboard
    • or click the down arrow on the right of the active camera button (below the viewport), click Change Scene Camera, and click New Camera.
  9. click the + sign to Create Animation Set(s) for Existing Element(s) and choose camera1 so that you can animate that camera
  10. add any props and position them how you'd like
    • the same way that you added a new model in step 6
    • if you want them to move with a character, make sure you lock them to that character (e.g. their weapon_bone or bip_head)
  11. add your recorded voice clip by selecting the clip editor (F2), right clicking on Dialog (near the bottom), and choosing Add Clip to Track or Record Narration
    • when you are adding a clip to a track, any WAV files that are in the ...\steam\steamapps\common\sourcefilmmaker\game\usermod\sound file will show up
  12. to have your character move their lips along with the voice track, select the Dialog track, the character's Lower Face (and Tongue) in the Animation Set Editor, right-click in the Animation Set Editor, and choose Extract Phonemes
  13. I usually animate the camera by moving it around rather than using the fieldOfView control
So that is a very brief overview of some of the things I've done in Source Filmmaker so far. Here's an example of one I did recently:

Monday, April 8, 2013

installing Red5 in Ubuntu from the command line

First install the requirements for Red5:

sudo apt-get install java-package openjdk-7-jre openjdk-7-jdk ant subversion

Next download and untar Red5:

tar xvfz red5-1.0.0.tar.gz

Rename the folder:

mv red5-1.0.0 red5

And then run Red5:

cd red5
sh red5.sh

After scrolling through a lot of verbose information about the startup of Red5, you'll know it's running when you see the line that ends with Installer service created.


If you're browsing from the computer that it's installed on, you can see if the Red5 server is running by going to http://localhost:5080 .

Monday, January 28, 2013

Google script to email form data

I helped someone set up a Google Form with email notifications the other day. This morning they asked if they could be emailed the submitted data, rather than just a link to the spreadsheet. Since there's only one question on the form, that's an easy script:


function onSubmit(e) {
  var timestamp = e.values[0];
  var question1 = e.values[1];
  var address = "firstaddress@example.com, anotheraddress@example.com";
  var subject = "Feedback form submitted";
  var body = "Someone submitted the form at " + timestamp + " and said " + question1;
  MailApp.sendEmail(address, subject, body);
}


This script will send an email to the address(es) in quotes after the var address = . The body of the email will contain the string that is in quotes after var body =  , which includes the timestamp (from column A of the spreadsheet) and what the user submitted in the form (the contents of column B).

To get this to work for you, paste the above code into a new blank script that's associated with a form you've created, and then set up a trigger that runs the function onSubmit(e) when the form is submitted.

To set up the trigger, follow the instructions from this page:


  1. Open or a create a new form, then go to the results spreadsheet of that form.
  2. Click the Unsaved Spreadsheet dialog box and change the name.
  3. Choose Tools > Script Editor and write the function you want to run.
  4. Choose Resources > Current script's triggers. You see a panel with the message No triggers set up. Click here to add one now.
  5. Click the link.
  6. Under Run, select the function you want executed by the trigger.
  7. Under Events, select From Spreadsheet.
  8. From the next drop-down list, select On form submit.
  9. Click Save.
Of course if you have more than one question in your form, you'll need a variable for each of them (e.g. var question2 = e.values[2];) and you'll need to call those variables in the var body =  statement.

Let me know if this works for you.

Thursday, January 24, 2013

automatically adding column data to google form submissions with a script


I've often come across the issue of wanting to manipulate data that has been submitted with a Google Spreadsheets Form. For example, automatically marking and totaling formative quizzes where students submit their answers in a Google Form.

Unfortunately when a user submits a form, a new row with those data is inserted on the spreadsheet. This means any formulas that you've manually added to the Spreadsheet will be above or below that row.

To solve this issue, I wrote a Script that copies (to that inserted row) the contents of the columns you've added in the first row.


function addFormula() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var startRow = 2;
  var startColumn = 8;
  var numberRows = 1;
  var numberColumns = 15;
  var lastRow = sheet.getLastRow();
  var sourceRange = sheet.getRange(startRow, startColumn, numberRows, numberColumns);
  var destinationRange = sheet.getRange(lastRow, startColumn, numberRows, numberColumns);
  sourceRange.copyTo(destinationRange);
};


The meanings of the variables are:
sheet is a shortcut so we don't have to keep typing SpreadsheetApp.getActiveSheet()
startRow is the row number that's the source of your formula that you want to copy
startColumn is the column number where your source formula starts
numberRows should usually be 1, it's the number of rows that you would like to copy each time
numberColumns is the number of columns that contain your source formula
lastRow is a shortcut so we don't have to type sheet.getLastRow() when we want to use it
sourceRange collects together the information to tell copyTo where to get the data
destinationRange collects together the the information to tell copyTo where to put it


If you prefer, this could also be done in a single line without all of the variable declarations:


function addFormula() {SpreadsheetApp.getActiveSheet().getRange(2, 8, 1, 15).copyTo(SpreadsheetApp.getActiveSheet().getRange(SpreadsheetApp.getActiveSheet().getLastRow(), 8, 1, 15))};


To add this script to your spreadsheet of data from a Google Form
  1. open the spreadsheet and under the Tools menu choose Script editor...
  2. under "Create script for" click Spreadsheet
  3. delete everything in the Code.gs pane and replace it with the script from this blog post
  4. if necessary, change the numbers for the variables to what they should be for your spreadsheet
  5. under the File menu click Save
  6. under the Resources menu click Current script's triggers...
  7. if you haven't already named your project, do so now in the box that comes up
  8. click No triggers set up. Click here to add one now.
  9. in the third drop-down list, select On form submit
  10. click the Save button
And you're done. The script will run whenever a user submits the form, and it will copy the formulas that you've set up on the first line of submitted data. Leave a comment below if this works for you or if you have any questions.

Monday, August 20, 2012

presenting at Destination Innovation 2012

Today I'm presenting at the Destination Innovation 2012 conference at the Banff Centre on "Makers and the DIY Revolution".

If you want to follow along with the conference, the Twitter hash tag is #Dest_2012.

Wednesday, June 27, 2012

ISTE12 Conference Closing Keynote

The closing keynote was by Dr. Willie Smits from DeforestACTION together with Liza Heavener and  Chris Gauthier about "global collaborative projects with, for, and by students around the world". Dr. Smits talked about some of the projects that they've been involved in, and some of the work of the foundation.


It wasn't particularly technology-focused, but it was somewhat interesting and applicable to education. It was good to hear about some of the things they are doing, and the tool Earthwatchers that crowdsources students to analyse satellite photos and watch for logging and other related activities to make a difference in the world.


There were many comments on Twitter that this should have been the opening keynote rather than the closing one. Unfortunately, as is often the case, many people had left the conference by the time the keynote started. I suppose the advantage was that there was more seating space and the Wi-Fi worked much better than at other keynote events this week.

A Balance Between Consuming and Sharing

As I've tried to blog about my experiences here at the ISTE conference, I've been forced to think about the balance between gathering or experiencing and making things public for others. It takes time and some effort to digest and to sit and write about what I'm seeing, hearing, and learning.

During this conference I've occasionally found myself writing about one topic while attending a session on something completely different. This has perhaps been detrimental in that I've probably missed some things when I've not been fully present. Task switching is a skill that I'm still working on developing futher.

Over all I think this process been helpful for me, though, to summarize things to help clarify my own thinking.


I'd certainly recommend blogging in general as a way to communicate ideas and share back what you've received. However I think blogging is almost essential when attending a conference that many people are unable to be at, or one as large as this with more sessions than one person could possibly attend.


As the conference winds down, I need to go back over my notes and see what hasn't made it into blog posts or Twitter posts to make sure that I'm sharing as much as I can. I've also realized that this is not just about sharing with others, but also sharing with the future me when I look back at these posts in September.