Tutorial Frame by frame animations in Orbiter

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
2,021
Reaction score
623
Points
128
Location
Sparta
In case you haven't seen any of these SC4 animations. here is the latest video:


Unfortunately my Orbiter allocated time wasn't enough to create a fully detailed tutorial.

What I can do, is give you an outline of the process and come back the soonest I have time, to include a more detailed version.

So here is the outline:

1. Create a humanoid mesh in .obj format, preferably with a single group and a single texture. (In the videos, I used a modified version of Kara.msh from the XR2Ravenstar addon). A "standard" T pose is perfect for this, but if you don't have one, it's fine.

2. Go to Mixamo https://www.mixamo.com/#/, sign up and upload the .obj file.

3. Go through the auto-rigger process. (it's quite simple and doesn't take long).

4. Select an animation for your mesh and download it. Make a note of the number of animation frames.

5. Import the .fbx file into blender 2.82 - Use scale 100 during the import.

6. Select the Start / End frames of the animation and export from blender as an .obj with the animation box ticked. This will create an .obj file for all the selected frames in the animation.

7. Install a batch obj import addon in blender and create a new project (File→New→General).
(Batch .obj import addon here: https://blender.stackexchange.com/questions/5064/how-to-batch-import-wavefront-obj-files

8. Press File→Import→Wavefront Batch (.obj) and select all the obj files you exported in step 6. (not the .mtl files). This will import all the animation frames in a single file.

9. Export as .obj and run ObjToAn8.
(ObjToAn8 link here: https://github.com/jombo23/N64-Tools/tree/master/objtoan8

10. Import the .obj file from step 9 and export as .an8. You'll need to uncheck all the boxes.

11. Open the an8 file with a text editor and delete all the material entries, except the first.

12. Run the an8 file with anim8or, delete the remaining materials and create a new one with your original texture.

13. Select all the groups with CTRL-A and apply the new material. Export as an Orbiter mesh file.
(Orbiter mesh export addon for anim8or here: https://www.orbithangar.com/showAddon.php?id=5ce8e256-08bd-4410-a4cc-f5c5b3cad2d5. It works with the latest anim8or version and the previous ones up to 0.95b

14. Open the mesh file with a text editor. Press CTRL-H and replace all of the following
GEOM with MATERIAL 1\nTEXTURE 1\nGEOM
^LABEL.* with [blank]

15. Go to the top of the mesh file and delete the double MATERIAL 1 TEXTURE 1 entry (lines 3 and 4)

16. Finally Press Edit→Line Operations→Remove Empty Lines. Save the file wherever you want in your Orbiter\Meshes directory.

Whew! Done! You have an Orbiter mesh file with its texture UV preserved, with all the animation frames as separate groups.

[To be continued, in the mean time, I'll answer whatever questions might pop up here]
 
I'm pretty sure you might get contacted by AMSO- and/or NASSP-developer(s) to do something for them :thumbup:
 
This is cool. In Japan, there is a huge demand for these dancing 3DCG figures... for… um… scientific purposes.

It would be nice if astronauts can perform some simple gestures (such as waving their hands, thumbs up, kneeling down and standing up, etc).
These simple body languages might add a little drama to my orbiter videos.
 
Uhm, what? I thought Orbiter had to split animations strictly into mesh groups, and vertex weighting wasn't possible. That's not what those animations look like at all, though.
Quick, somebody go tell Dan!

Oh, post is from July? How did I not see it earlier, and why did it crop up now?
 
YESSSS!!!!!! this is AMAZING.
Is there a way to do this in Blender only? So import the mesh file from mixamo to blender and then export with the animation to orbiter.
 
Last edited:
I believe I had written this part before we had the Blender addon for Orbiter. The main idea was that you got your mesh as a single group with a single texture, animated it in mixamo and then got all the frames of the animation as separate groups of the mesh. After that you load the mesh in Orbiter and display one group per frame to show the animation.
I'll have to retrace my steps and adapt this for the new tools that are available now. I will get to it eventually, but it will take some time because I these next 2-3 months are really busy in current work.
 

In this video, I use Spacecraft4 to bring 30-FPS humanoid animations to Orbiter Space Flight Simulator. I cover the entire pipeline: from Mixamo rigging and Blender to generating custom .ini components in a few minutes.

Here are the scripts that I used in the video:

Script for blender to extract each animation frame as a separate object (meshgroup)
Code:
import bpy

# Ensure the animated mesh is selected
obj = bpy.context.active_object
scene = bpy.context.scene

# Set the start and end frames based on your animation
start_frame = 1
end_frame = 29

# Create a new collection to keep things organized
new_col = bpy.data.collections.new("Orbiter_Frames")
scene.collection.children.link(new_col)

for f in range(start_frame, end_frame + 1):
    scene.frame_set(f)
  
    # Get the "evaluated" mesh (the mesh with the armature modifier applied)
    depsgraph = bpy.context.evaluated_depsgraph_get()
    obj_eval = obj.evaluated_get(depsgraph)
    mesh_from_eval = bpy.data.meshes.new_from_object(obj_eval)
  
    # Create the new object
    new_obj = bpy.data.objects.new(f"Frame_{f:02d}", mesh_from_eval)
    new_col.objects.link(new_obj)
  
    # Match the location/rotation of the original
    new_obj.matrix_world = obj.matrix_world

print("Done! 29 frames created in the Orbiter_Frames collection.")

Script for Google Spreadsheets to autocreate the animation components:

Code:
/**
 * Orbiter Spacecraft4 Anim + Pulse Teleportation Generator
 * Logic: Move all groups to Z=5000, then snap individuals to origin and back.
 */
function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Orbiter Tools')
      .addItem('Create Components', 'showFramePrompt')
      .addToUi();
}

function showFramePrompt() {
  var ui = SpreadsheetApp.getUi();
  var frameResponse = ui.prompt('Spacecraft4 Staging Logic', 'How many frames?', ui.ButtonSet.OK_CANCEL);
  if (frameResponse.getSelectedButton() !== ui.Button.OK) return;
  var numFrames = parseInt(frameResponse.getResponseText());

  var dirResponse = ui.alert('Direction', 'Play in REVERSE?', ui.ButtonSet.YES_NO);
  var isReverse = (dirResponse == ui.Button.YES);

  if (!isNaN(numFrames) && numFrames > 1) {
    generateStagedPulseComponents(numFrames, isReverse);
  }
}

function generateStagedPulseComponents(numFrames, isReverse) {
  var sheet = SpreadsheetApp.getActiveSheet();
  sheet.clear();
 
  var output = [];
  var step = 1.0 / numFrames;
  var duration = numFrames / 30.0;
  var pulseWidth = 0.000001; // Instantaneous snap

  // 1. Sequence Header
  output.push(["[ANIM_SEQ_0]"]);
  output.push(["KEY=K"]);
  output.push(["DURATION=" + duration.toFixed(15)]);
  output.push(["REPEAT=1"]);
  output.push(["INIT_POS=0"]);
  output.push([""]);

  var compIdx = 0;

  // 2. THE STAGING COMPONENT: Move all groups to Z=5000 immediately
  var allGroups = [];
  for (var g = 0; g < numFrames; g++) allGroups.push(g);
 
  output.push(["[ANIM_COMP_" + compIdx + "]"]);
  output.push(["SEQ=0"]);
  output.push(["GROUPS=" + allGroups.join(",")]);
  output.push(["RANGE=(0,0.000001)"]); // Active for the whole animation
  output.push(["TYPE=TRANSLATE"]);
  output.push(["SHIFT=(0,0,5000)"]);
  output.push([""]);
  compIdx++;

  // 3. THE PULSE COMPONENTS: Pull individual frames to origin and return them
  for (var i = 0; i < numFrames; i++) {
    var frameStart = i * step;
    var frameEnd = (i + 1) * step;
    var activeGroup = isReverse ? (numFrames - 1 - i) : i;

    // Component: Snap In (Move -5000 to bring to Z=0)
    output.push(["[ANIM_COMP_" + compIdx + "]"]);
    output.push(["SEQ=0"]);
    output.push(["GROUPS=" + activeGroup]);
    output.push(["RANGE=(" + frameStart.toFixed(7) + "," + (frameStart + pulseWidth).toFixed(7) + ")"]);
    output.push(["TYPE=TRANSLATE"]);
    output.push(["SHIFT=(0,0,-5000)"]);
    output.push([""]);
    compIdx++;

    // Component: Snap Out (Move +5000 to return to Z=5000)
    output.push(["[ANIM_COMP_" + compIdx + "]"]);
    output.push(["SEQ=0"]);
    output.push(["GROUPS=" + activeGroup]);
    output.push(["RANGE=(" + (frameEnd - pulseWidth).toFixed(7) + "," + frameEnd.toFixed(7) + ")"]);
    output.push(["TYPE=TRANSLATE"]);
    output.push(["SHIFT=(0,0,5000)"]);
    output.push([""]);
    compIdx++;
  }

  sheet.getRange(1, 1, output.length, 1).setValues(output);
  SpreadsheetApp.getUi().alert('Generated ' + compIdx + ' components. Pulse logic active.');
}

Try to follow along with the video and the scripts and I'll answer any questions you may have here.

:cheers:
 
Last edited:
Nice video :)
This should work with Vesselbuilder too.
Once you have the mesh with all the frames as separate groups, you can use whatever method you want to display them sequentially.
Spacecraft3/4 shown in the vid, Vesselbuilder, Lua and of course a c++ module.
IMO a dll would be best, using oapiEditMeshGroup to edit the flag to render the group or not.
You can also add more animations in the same mesh. For example groups 0 to x for the walking animation and x+1 to z for running. Tie them to the speed and you have both walking and running animations for the same character.
You can also speed it up or slow it down according to the speed if you make the timing variable.

It doesn't have to be only mixamo animations either. For example you can animate in blender a parachute deployment, use the script from the post above to extract the frames as groups and orient it the appropriate way. You'll have a much more realistic parachute deployment for your shuttles/payloads/whatever.
Same goes for inflatable habitats, etc. If it doesn't look good with the traditional scale/translation/rotation, you can try this instead.

I wonder if a way to do it with Ani8or?
It should but why it would take some additional "hoop jumping". I don't see the reason for it. Blender with Blake's mesh tools works great for this.
 
Some thoughts:

30 fps is quite high, you could probably get away with half that with no visual deficit.

For Orbiter24 a script could be written for LUA, and instead of the teleport hack use MshGrp Material property Alpha (each group would need a seperate material)?
Also a C++ template might be welcome.
 
Nice guitar! Nice animation! Nice city! (GTA port?). Here comes Rocket Cat!:)
 
Back
Top