Mass Effect 3: Camera Modding, From Noob to Not So Noob - ME3Tweaks/LegendaryExplorer GitHub Wiki

Hello there,
The goal of this guide is to help you understand the basics and not so basics of camera modding for Mass Effect 3.

This guide has been written and tested with Mass Effect 3, but it's probably also applicable to the Legendary Edition version, and for the other games as well. However, more testing is required.

Content

The Basic Concepts

Before we begin, let's clear some basic concepts to get a general idea of what is what.

Types of Cameras

In the games, cameras appear in two types of situations: Animcutscenes and BioConversations.
Animcutscenes are cinematic situations, done in-game, where the player has no control or interaction. Editing them is not covered by this guide.
BioConversations, on the other hand, are cinematic situations where conversations happen and the user may have input either in the form of dialogue choices or paragon/renegade interrupts. Sometimes no interaction happens, but generally this a sign of them. These can be Ambient conversations, where no camera work happens, or enter into Conversation mode, where camera work does happen.

In BioConversations there are three types of cameras:

  1. Switch Cameras: These are pre-built cameras with their position and other values already set in the BioStage. Think of them as premade cameras you can choose from. These can not be directly manipulated, but you can select which "angles" to use, so they provide a quick and simple solution for camera work.
  2. Matinee Cameras: These are cameras for which you can control their position, rotation, and FOV. Given that you can control them manually, these are the ones you can get the most out of, but take the most effort out of the cameras we've discussed.
  3. Behavior cameras: If in a conversation there is no BioStage (more on them later), or the BioStage has no valid Switch Camera, or there is no BioStage nor Matinee Camera, Behavior cameras will be used. These are cameras automatically created by the game to show the appropriate things. We have no control over them at all.

Opening the InterpData

To do anything with the switch or matinee cameras you need to open the InterpData that is played during the piece of dialogue you want to edit. To put it in simple terms, an InterpData is a container that can hold the controls for stuff related to the dialogue, cameras included.

To know which file contains the dialogue, start the conversation, then type profile conversation into the console. This will display information related to the conversation. Then take a note of the first piece of text after Kismet Action:

Figure 0
Figure 0

That is the name of the file that triggers the dialogue sequence. The actual dialogue is in a file of that name, plus LOC_INT at the end. In our case, the dialogue will be in BioD_End001_481HubGeth_LOC_INT.pcc. Now open this file with the Dialogue Editor tool, and you'll find a screen like the following:

Figure 1 Figure 1
A more in-depth explanation of the Dialogue Editor can be found in the Overview of the Dialogue Editor guide, by beccatoria.

From there, select the dialogue node you want to edit, and then click on the marked icon in the image above, which will open its associated InterpData in the Interp Viewer tool. You'll end up with a window that will look like the following, minus or plus some extra elements:

Figure 2 Figure 2

There you can see the following:

  1. The InterpGroups area. This area displays the InterpGroups that the InterpData references. An InterpGroup is like a sub-container inside the InterpData for different related InterpTracks.
  2. The Conversation InterpGroup. For our purposes, this InterpGroup is where you'll be able to switch between switch cameras, but it's also used to play audio lines, and/or control actor animations and related things.
  3. The InterpGroupDirector. This group is responsible for controlling which matinee camera is active, switching between matinee cameras and the Conversation group, and controlling the Depth of Field (DOF).
  4. The Camera InterpGroup. Every one of these (there can be multiple) controls one camera actor, which is what we call a matinee camera. Inside this group, you can control the position, movement, and Field of View (FOV) of the matinee camera.
  5. The Interpreter. This area displays the InterpDatas, InterpGroups, and Tracks' properties. What is displayed depends on what you have selected. When launching from the Dialogue Editor, you'll see the InterpData's properties.
  6. The InterpData list. A list of all the InterpDatas contained in the file, which you can use to quickly switch between them if you know their number.

UPDATE: In the newest versions of the tools the Interpreter tab has been renamed to Properties, but I ain't taking literally around 100 new screenshots, so keep that change in mind xD.

A lot of the time, InterpDatas will only have the Conversation group, which means that only switch cameras are being used in them. You can go to the Other Topics section to learn how to add the InterpGroupDirector and matinee camera groups if you don't want to just rely on switch cameras.

Add/Remove/Reorder Keys/Items in a Track

Through this guide we'll find multiple arrays that hold the Items that control things like which camera is active, their position, rotation, and other similar things, like these:

Figure 3
Figure 3

In order to not repeat the same concept multiple times, let's learn how to add, remove, and reorder array items. If you don't completely understand this right now don't worry, you can always come back later to take another look.

To add a key, click on your desired array, and then in the Interpreter's toolbar, you should see an option that says "Add Array Element", click on it.

Figure 4
Figure 4

This will add a new array element to the end of the array, with the same values as the last element. You can then edit it to the values you want it to have.

To reorder the array items, click on the element, and then on the toolbar click on the up and down arrows.
To remove an item, click on the item, and from the toolbar click on "Remove Array Element".

Figure 5
Figure 5

Changing Values

If you find a value that you want to tweak, changing it is pretty simple.

Figure 6
Figure 6

  1. Click on the property you want to change.
  2. Input the new value in the toolbar, or select it from the dropdown.
  3. Click on set.

Pay special attention to the Index. In this example, a camera group named Cam1 is not the same as Cam, with index 2, which is displayed as Cam_1 (the index is 0-based).

The InterpGroupDirector

This is the InterpGroup where you switch between matinee cameras, go back and forth between them and the Conversation group, and control the DOF.

If you expand this group, the following InterpTracks will be displayed:

Figure 7
Figure 7

  1. The InterpTrackDirector track: This is where you control which camera is active and when.
  2. The BioEvtSysTrackDOF track: Here is where the Depth of Field (DOF) is controlled.
  3. The track's keys: These are the points in the timeline where values are set to happen. Multiple keys allow for different values to be set.
  4. The InterpTrackEvent: These, along with other tracks, are tracks that may or may not be present in your group. They allow for more specific effects like fades, rumbles, opening doors, and others.

Camera Switching

Clicking on the InterpTrackDirector track will reveal the following properties in the interpreter area:

Figure 8
Figure 8

The important part here the CutTrack array, which is where you can set the keys to control the camera switching. Inside an Item of the CutTrack you'll find:

  1. TargetCamGroup: Here you have to input the exact name of the matinee camera group that you want to be active at that key in time (the group should be in the same InterpData). Alternatively, if you want to display the switch camera selected in the Conversation group, you can set the property to "Conversation".
  2. Time: Controls when the game is gonna switch to the given camera.
  3. TransitionTime: This sets the length of the transition between the previous camera and the current one. A value of 0 seconds makes the change instantaneous, while a higher number of seconds makes the transition longer. This transition is done by moving the previous position of the camera until it matches the current one, rather than by a fade in/out or a blend.
  4. bSkipcameraReset: Setting this property to true makes it so that the camera actor won't return to its default position once the InterpData is over. Most of the time it's better to leave this as false to avoid weird bugs or not knowing why the camera is in X or Y position.

Now you can change or add new items and the game will activate those cameras at the appropriate times.

Depth of Field

The Depth of Field controls the area in focus and the area out of focus.
This can be edited from the BioEvtSysTrackDOF track.

Figure 9
Figure 9

From here you can add and edit any of the DOF items inside the m_aDOFData array.
The properties you can control are the following:

Figure 10
Figure 10

  1. fFocusDistance: The distance from the camera to the center of the focused area. A higher value pushes the focused area away from the camera.
  2. fFocusInnerRadius: The radius of the area in focus. A higher value makes the area bigger.
  3. fFallofExponent: In theory it controls how abrupt or gradual the focused area extends/ends at the edge of its area. However, its effects are either not entirely clear or a bit too subtle, but lower values seem to reduce the focused area.
  4. fMaxNearBlurAmount: The amount of blur between the center of the focused area and the camera. It can go from 0 to 1, where 0 is no blur and 1 is max blur.
  5. fMaxFarBlurAmount: Similar to fMaxNearBlurAmount, but it affects the area from the center of the focused area and away from the camera.
  6. fBlurKernelSize: Controls how strong the blur is in the affected areas.
  7. fInterpolateSeconds: Controls how long it takes for the item's values to be at full effect. It serves as a transition from the previous DOF item to the current one. A value of 0 seconds will make the change instantaneous, while a bigger number of seconds allows for a transition. Keep in mind that the transition will begin before the item, and end at the item's time. So a value of 2 seconds will start transitioning 2 seconds before the item.
  8. bEnableDOF: Enables/disables the DOF for that key.
  9. vFocusPosition: In theory it should control the position, in the X, Y, and Z-axis, of the focused area from the center of it. However, changes to these don't seem to show any change.
  10. cModulateBlurColor: Its effects are unknown.

Here's a visual help for the effects of these values:

Figure 11
Figure 11

Figure 12
Figure 12

Switch Cameras

These are the easiest cameras to use because their information is already set, and all you need to do is select the proper one. However, this advantage is also their drawback, they are already prebuilt in the BioStage, so you can't change their values. But, in order to truly get all of this, let's first understand what a BioStage is.

What is a BioStage?

When dialogue occurs between actors, either in an ambient conversation or in conversation mode, the game can have them perform the dialogue where they stand, and create automatic behavior cameras (in conversation mode), or it can have a BioStage.
This, like the name suggests, is a sort of stage that contains Nodes and switch cameras. These nodes are predetermined locations where actors can stand and be set at. The switch cameras are cameras set at specific angles to focus on the nodes.
In-game we do not have a way of visualizing where the nodes or switch cameras are, aside from trial and error, but here is how a BioStage looks like when exported and viewed in a 3D modeling program like Blender:

Figure 13
Figure 13

The blue triangles are a representation of the nodes (not all nodes have them), and the brown bones are the nodes themselves and switch cameras. A BioStage can contain more than two nodes, either to have more actors set at specific places or because through an animation you want the actors to reach those nodes and be set in them with switch cameras ready to focus on them.
The red rectangle is the boundary area of the stage, which can sometimes lead to collision issues if it clashes with a blocking volume, but more on that in the Adding a BioStage section.

To figure out what BioStage your dialogue is using and what nodes your actors are into, in-game start the conversation you want to edit, open the console and input the playersonly command to freeze the game (this is not really required, but it is helpful to have things frozen). Then open the console again and input profile conversation. This will display on-screen information related to the conversation like the following:

Figure 14
Figure 14

The information we care about is the one surrounded in colored boxes after Kismet Action:

  1. Light-blue box: This is the name of the file that contains the BioStage. Most of the time it's the "base" file of the conversation, meaning that if the conversation is in the BioD_Something_LOC_INT.pcc file, then the BioStage will be in BioD_Something.pcc one.
  2. Green box: The location of the sequence in the file. If you open it with the Package Editor tool this is the exact package path, but if you open it via the Sequence Editor you can ignore the TheWorld.PersistentLevel part.
  3. Blue box: The nested sequence that has the relevant elements.
  4. Purple box: The name of the sequence object that starts the conversation.
  5. Red box: The nodes in which the actors are placed. Keep these in mind for choosing which cameras to use, which we'll talk about in the next point.

Now that you know in what sequence your BioStage is, search for it in the Package Editor and then open it in the Sequence Editor, or more easily, open the file with it directly and look for the StartConversation object.
Once you find it you will have something like the following:

Figure 15
Figure 15

The colored boxes are referring to the same things as in Figure 14. And surrounded by black and numbered are:

  1. The BioStage's tag name. ST_citpres_tali_talk1_d in this case.
  2. The BioStage's object name (click on the object from point 1 to get this). The previous thing was the tag name, which we'll use later, but this is the name of BioStage object itself.

After getting this information, open the file in the Package Editor and go into the Tree View tab.

Let's first take a look at the BioStage object, which is located inside TheWorld.PeristentLevel, so find it and then click on it. You should see something like this:

Figure 16
Figure 16

On the Interpreter, you can see the BioStage's location and rotation. This dictates where it is located in the level. You can also see the tag, which is what was used in the Sequence Editor.

Now let's take a look at the BioStage itself. The easiest way to find it is, from the Tree View, to type the tag's name into the search box and click "Search". This should directly take you to the BioStage.

Figure 17
Figure 17

On the Interpreter you can see the BioStage's properties. From which m_aCameraList is the one we care about since it contains the list of available switch cameras and their properties. You can safely ignore any other properties since we won't be messing with them.

Also, on the left, right under (Exp) 780 ST_citprs_tali_talk1(BioStage) is the SkeletalMesh, which is the 3D mesh that has the nodes and bones that were shown in Figure 13. If you click on it, go to the Binary Interpreter tab, and expand its RefSkeleton part, you can see the name of the nodes and cameras it contains.

Figure 17.5
Figure 17.5

Now that you know what the BioStage elements look like, in the future, you can look for it directly in the Package Editor without having to go into the Sequence Editor, but we've gone through the longer route to show all the basics.

Choosing a Switch Camera

Having learned what a BioStage is, we can talk about how to choose the switch cameras and switch between them.

Operations on switch cameras are done in the BioEvtSysTrackSwitchCamera track inside the Conversation InterpGroup. Expanding one and clicking on the proper track will reveal its properties:

Figure 18
Figure 18

  1. The m_aCameras array: An array that contains the Items that decide which switch camera is used.
  2. **The m_aTrackKeysarray:** An array whose items control when the items in them_aCameras`array occur in time. The number of items in this array must correspond to the one in the previous one, in the same order.
  3. nmStageSpecificCam: Here's where you write which switch camera to use for that item.
  4. bForceCrossingLineOfAction: Setting this to true should, in theory, allow the camera to cross the action line between the characters, but its exact behavior is unknown to me at the time of writing this guide.
  5. bUseForNextCamera: Setting this to true will queue the switch camera to take effect after the InterpData ends. Why would one want to enable this behavior is covered in the Controlling Dialogue Wheel Cameras section.

You may be wondering how can you know which switch cameras you have available, what do their names mean, and how to know how they look.

To know which ones are available you have to check the items in the m_aCameraList array, which are part BioStage object. After getting to the object and expanding the list in the Package Editor, as seen in the BioStage section, you'll see their following properties:

Figure 19
Figure 19

  1. tDOFData: The DOF values for this camera. Inside of it, you can find the fFocusInnerRadius and fFocusDistance values.
  2. nmCameraTag: The name tag of the camera. This is what you want to input into the BioEvtSysTrackSwitchCamera. Do note that the last number of the tag is set via the index, rather than the name itself.
    Figure 19a
  3. fFov: The FOV value of the camera.
  4. fNearPlane: Determines the radius around the camera that will erode (clips) other objects that may obstruct it. The lower the value the fewer objects that will be affected. Usually, this value will be set to 0 or a very low value, but if it has a higher one and it's affecting your scene in undesired ways, check the Dealing with Camera Clipping section. By the way, actors are also affected by this setting, including Shepard.
  5. bDisableHeightAdjustment: Usually switch cameras adjust for the height of the actors, but you can use this property to disable that behavior.

An important note: While it's certainly possible to edit all of these properties, due to how the game handles memory and clones of the same object, it's better to leave them as-is if you don't want to be surprised by the changes affecting other conversations as well unless you change the name of the BioStage in all of its occurrences in the file, which would make it unique. We won't be covering this since for the situations where you'd want to edit them, it's probably better to just use a matinee camera.

Knowing which switch cameras are available, let's proceed to understand what their name means.
A switch camera' name follows a name pattern of camX_Y_Z, where X is the node number at which the camera is looking, Y is the node number from which the camera is looking, and Z is a number (set by the index) to differentiate between multiple cameras looking at the same node from the same node.
To give an example, cam2_1_4 would be a camera looking at node 2 from node 1, and possibly being the fourth one set with this configuration. We say possibly because sometimes for some reason you'll have non-consecutive numbers, like cam2_1_1, cam2_1_2, cam2_1_3, and cam2_1_21.

So far we know which switch cameras area available, and how to know which ones you may be interested in based on their name and the nodes your actors are set into. However, to know how the angles will actually look like there's no other option than to try them in-game.
A very simple way to do this is to set keys for all the available switch cameras in a single InterpData, and then run it in-game and take screenshots/videos of how they look.

Before concluding this section, one last thing that you need to know is that if you just want to use one switch camera, your InterpData does not have a BioEvtSysTrackSwitchCamera in the conversation group, and you don't want to bother adding one, you can choose a switch camera by using the Camera Intimacy setting of the dialogue nodes in the Dialogue Editor:

Figure 20
Figure 20

Here you have to set the last number of the switch camera name, with the caveat that the node from which it looks and the one it looks at (the first two numbers in the switch camera) will be decided by what node the dialogue bit happens in.
Usually, a Reply Node will look from the BioStage node of whoever is the owner of the conversation, to the BioStage node of whoever is the listener (usually the Player); while an Entry Node will usually look from the BioStage node of whoever is the listener (usually the Player), to the BioStage node of whoever is the owner.

Matinee Cameras

This type of camera is the one for which you can control their position, rotation, and FOV.
To get a bit more of a technical understanding, matinee cameras are actors, just like the player or any of the actors that appear in a conversation, but without a visible mesh. So, you can control their position and rotation and then "look through their eyes".
What we're gonna explore is how to control them from and during our InterpDatas (their position, rotation, and FOV, get reset after the InterpData ends).

While you can switch to different switch cameras (pun intended) from a single track in the Conversation InterpGroup, for each matinee camera you want to use you'll need a new Camera InterpGroup. We'll cover how to add new ones in the Ading a new Matinee Camera section, and right now will limit ourselves to work with only existing Camera InterpGroups.

Opening an InterpData that contains a matinee camera and its group, the following elements will be displayed:

Figure 21
Figure 21

  1. m_nmSFXFindActor: The matinee camera actor's tag name. In simple words, the name of the matinee camera to control.
  2. GroupName: The name of the InterpGroup. It's good practice to keep it the same as the matinee camera name to avoid future confusion, but it can be different from the actor.
  3. The InterpTrackMove track: The track that controls the position and rotation of the camera.
  4. The FOVAngle track: The track that controls the Field of View (FOV) of the camera.

Remember that both the m_nmSFXFindActor and the GroupName can have indexes reflected in the name, so Cam1 is not the same as Cam, with index 2.

Position and Rotation

Click on the InterpTrackMove track of your chosen camera, and you'll see the following:

Figure 22
Figure 22

  1. PosTrack: This track contains the controls for the camera's position.

Figure 23
Figure 23

As with most other arrays, each key in the timeline maps to an item in the Points array. Expanding an Item reveals the controls for the camera's position:

  • The InVal controls when the item happens on the timeline.
  • The OutVal contains the X, Y, and Z positional values. X or Y control the position to the right or to the left, while the other controls how far or near the camera is; which is which depends on the point you're looking at the plane at, but using the profile camera command (more on that later) and looking at the value changes in-game will give you the answer. The Z value controls the vertical position of the camera.
    We'll discuss the ArriveTangent, LeaveTangent, and InterpMode in the Controlling Interpolation section, but these control how change between values happens.
  1. EulerTrack: This track controls the camera's rotation.

Figure 24
Figure 24

  • The InVal controls when the Item happens in the timeline.
  • The Outval contains the X, Y, and Z rotational values. The X value is the rotation along the Roll axis, the Y value is the rotation along the Pitch axis, and the Z value is the rotation along the Yaw axis.

Figure 25
Figure 25

  1. LookupTrack: This track adds the keys to the timeline.

Figure 26
Figure 26

  • Time is where you set at what time to add the key.
    Without the keys in this track, you won't see any keys. For every key in the PosTrack or EulerTrack there must be a corresponding one here. Make sure the number of them and times match with each other.

Important note: DO NOT, I repeat, DO NOT add a name in the GroupName property of an Item in the LookupTrack. This will impede the controls to take effect and you'll spend hours debugging why it isn't working. Totally not talking from experience...

Make sure that if you add a new array key in the InterpTrackMove, that is, to either the PosTrack, EulerTrack, or LookupTrack, you also add a new key to the other ones, or else the game will crash. Also, remember that if you make a change of the InVal (the time) of any of these tracks, or you reorder its elements, you should do the same in the other tracks as well. The FOV, DoF, and InterpTrackDirector tracks are not subject to these observations.

If you want to have your camera move or rotate from one point to another, simply add an item where you want your movement/rotation to start, and one where you want it to end, and set the appropriate values. The game will then move the camera from one position to the other one.

A small caveat about rotation: If you're trying to set a small rotation from something like 355° to 5°, which should be a 10° turn, tweak it to be from -5° to 5°. A turn from 355° to 5° will actually translate to a 350° turn, which is probably not what you want.

Getting Precise Camera Position and Rotation

When editing the matinee camera's position and rotation, you could try setting it by trial and error, but there's a better way to get the position and rotation coordinates in-game that also allows you to see how your changes will look.

First of all, make sure you have tweaked your Coalesced file to allow for mouse control during conversation mode, as explained in the Setting Up the Coalesced for Camera Editing section.

With that set-up, go into the conversation you want to edit.
You'd probably want to pause the conversation with playersonly when the camera you want to edit is active.
With the game paused, type toggleflycam into the console, and then profile camera. Now the game is paused, you have control of the flycam, and you are able to see the camera's position and rotation in the HUD:

Figure 27
Figure 27

Surrounded by colored boxes, you have the following information:

  • Rotation: The rotation of the camera in Y, Z, X form. The first value is the Y value, the second the Z, and the third the X. These values are in unreal degrees, where 1 degree equals 182.04 unreal degrees, so it's easy to convert them back and forth. You can also use the Hex Converter tool, which has a built-in converter between degrees and unreal degrees.
    If when trying to find the rotation of a camera, you convert the unreal degrees to normal degrees and find that the values go outside the 360/-360 range, take that value, divide it by 360, and use the remainder as the value. This is the same as doing yourVal modulo 360. This happens sometimes when the rotation displayed in-game does not account for whether or not you've rotated the camera more than once and leads to crazy spinning, which in this case is not a good trick.
  • Position: The position of the camera in X, Y, Z form.
  • FOV: The current FOV. You can change the camera's FOV by typing fov [0-n] into the console. Sadly, this does not display the proper value when in flycam mode, so you need to write down which value you changed the FOV to.
    To reset the FOV to be controlled by the game, type fov 0.

It may be the case that you'll get positional values from the flycam that are much higher than what's displayed by the InterpTrackMove, like in this case:

Figure 28
Figure 28

This happens because the Interp (a sequence object to which the InterpData is connected) has something as its anchor. So, the camera profiler displays the absolute values, that is, the anchor's position plus the local value set in the InterpTrackMove, while the Interpreter only displays the local values.
To figure out what the anchor is, from the Dialogue Editor click on the dialogue node and then on the marked icon:

Figure 29
Figure 29

This will open the Sequence Editor and display the appropriate Interp. (You could skip the previous step by opening the file in the Sequence Editor, but you then have to figure out which Interp is the relevant one).

Figure 30
Figure 30

Now follow the line coming into the Anchor link to its source object, which in this case is the ST_End001_Shuttle_Down_M BioStage, then search for the object in the pcc file, get its position, and add/subtract it to the values displayed by the profiler. You could also just unlink the anchor and the Interp, but keep an eye out for unintended results.

Field of View

The Field of View controls how much area the camera is able to capture.
Clicking on the FOVAngle track reveals the following:

Figure 31
Figure 31

  1. PropertyName: This tells the game that this track controls the FOV. The name must be FOVAngle without typos, or it won't have any effect.
  2. TrackTitle: The name displayed for the track, keep it to FOVAngle to keep things consistent.
  3. FloatTrack: The property containing the array holding the items that control the FOV. Expanding this property you'll see the following:

Figure 32
Figure 32

  1. InVal: The time at which the item takes place.
  2. OutVal: The FOV value.
  3. InterpMode: The interpolation mode for the item. We'll discuss them in the Controlling Interpolation section.

Do note that the number of items in the FOVAngle track don't necessarily need to match those in the InterpTrackMove, neither do they need to occur at the same time. You can have the same FOV through multiple cameras, or have multiple FOVs through the same camera.

A low FOV value will result in less area being captured by the camera, while a high one will make the camera capture a bigger area.

Figure 33
Figure 33

Without any change in the camera position, this gives the impression that it has made the camera be farther away from the subject, but if you check the position values or move the camera closer to the subject, you'll see that what has changed is, in fact, the area captured by the camera.

Figure 34
Figure 34

As you can see, an effect of a higher FOV value is that the elements closer to the camera seem to become thinner and stretched back, while a smaller FOV value makes the elements appear wider. This is an effect that you can use to your advantage depending on what you want to do, but usually, for face close-ups, a value between 23 to 33 FOV works the best.

To compare the FOV to real-life lenses, a high FOV value is similar to using a short lens, while a low FOV value is similar to using a long lens, minus the depth of field effects.

Other Topics

Here are topics that are beyond the basics that were covered before, but very important for camera modding.

Controlling Interpolation

When you have multiple keys in the InterpTrackDirector or BioEvtSysTrackDOF the game changes to them automatically, without transition, unless you manually set a transition time. However, for the FOVAngle and InterpTrackMove tracks, the game changes between them in a progressive linear fashion, but how this happens is something that can be controlled for each item in them through the InterpMode property. Pay attention to the fact that items in the InterpTrackMove also have the ArriveTangent and LeaveTangent properties.

Figure 35
Figure 35

Items of the PosTrack and EulerTrack of the InterpTrackMove track by default have their InterpMode set to either CIM_CurveAutoClamped or CIM_Linear, meaning they'll progressively change from one item to another in a linear fashion, while items of the FloatTrack of the FOVAngle track are set to CIM_Constant, meaning changes will occur only once the key is reached, and then remain until the next one.

The real power of these interpolation modes lies in the Curve Editor, where you can visualize and easily manually control how they interpolate.
To access the Curve Editor click on it under the Interpreter tab.

Figure 36
Figure 36

The x-axis of this graph corresponds to the time, while the y-axis corresponds to the value of the keys. Numbered in Figure 36 we have:

  1. The Tracks' arrays: Clicking on any of them will display in the graph the keys contained in that array.
  2. The Interpolation modes: From here you can change between interpolation modes.
  3. The Keys: These are the individual keys set by the track, with the added bonus of having handles that control the arrive and leave tangents of the key. Moving a key up/down in the viewer will increase/decrease its value while moving it right/left will change its placement on the timeline.
  4. The Key's Value: Here you can see and edit the actual value of the key.

The available interpolation modes are:

Figure 37 Figure 37

  • Constant: Keep the value constant until it reaches the next key, at which moment it will instantly change the values.
  • Linear: Makes the change between values be linear without any ease-in or ease-out.
  • Auto: Makes the key's arrive and leave tangents smoother. Usually, Auto/Clamped works better.
  • Auto/Clamped: Makes the key's arrive and leave tangents smoother.
  • User: Allows for a custom-made curve. The mode will automatically switch to this whenever you manually tweak the handles of the key.
  • Break: Allows you to control the arrive and leave tangents independently with the handles. Other modes have the tangents linked to each other.

Changes to a key's handles are reflected in the ArriveTangent and LeaveTangent properties of the Item (for PosTrack and EulerTracK ones) in the Interpreter, which gives you finer control over them. However, it's usually easier to modify them from the Curve Editor.

To change the interpolation mode of an item, select the appropriate one from the InterpMode property in the Interpreter, or click on the key and then on the mode in the Curve Editor. The selected interpolation mode will affect the part of the curve ahead of the key.

Identifying Available Matinee Cameras

Before being able to add a new matinee camera, you need to know which camera actors are available to assume direct control of. The idea is to go through the pcc files that are loaded at the time of the conversation and look for the tags of CameraActors that are in them.

The easiest way to know which cameras are available is to go check the InterpDatas in the same dialogue and see if any uses a matinee camera, then write down the name of the camera actor. Take into account that the group name and the camera actor names may sometimes not be the same.

Figure 38
Figure 38

If there are no matinee cameras in the conversation, or you need to use an extra one, to know which files are loaded you can use the Streaming Levels HUD ASI mod, which you can install via the ASI Manager tool.

Figure 39
Figure 39
You can toggle this HUD by pressing Ctrl + T.

Camera actors are usually located in the more general files. If your conversation is in BioD_CitHub_WardsFluxP3_LOC_INT.pcc, chances are that the cameras will be in either BioD_CitHub.pcc or BioD_CitHubWardsFlux.pcc.

Figure 40
Figure 40

Now, an even easier way once you get the hang of it (although not as easy as the first method) is using the LiveLevelEditor (LLE) tool. I won't go into much detail since this is not a guide about it, but the following should get you to what you need:

Figure 41
Figure 41

  1. Open the LLE before starting the game. You may be asked to install extra files if it's the first time you use it.
  2. Open the game and load the conversation.
  3. Go back to the LLE and click on "Initialize Editor". It will take a couple of seconds for any change to happen, but if it doesn't work repeat steps 1 to 3.
  4. Click on "Regenerate Actors List", which will make the tool display the list of loaded files. This may take a couple of seconds to work, but if it doesn't, click "Cancel" and repeat this step.
  5. Click on a file on the left, then on the right a list of actors contained in that file and active in-game will be displayed.
  6. Look through them for any CameraActor_n, or check through other files.
  7. With a camera found, right-click on it, and then click on "Open in Package Editor".
  8. Now you just need to write down the name tag. Remember to check the index value too.

And there you have it, now you know how to figure out which camera actors are available to use as a matinee camera. All you have left is to test it in-game.
If you load into a different level while the LLE is open, you'll need to repeat steps 3 through 8.

Adding a New Matinee Camera

Technically, "adding" is the wrong term to use here, since what we'll do is just add the InterpGroup and InterpTracks to control a camera actor, but let's roll with "adding".

To add the controls for a matinee camera, follow these steps:

  1. Open the InterpData you want to add the controls to in the InterpViewer.
  2. On the top left, click on "Add InterpGroup".
  3. A prompt will be launched asking you for a name for the InterpGroup. Input the name you want to give it, best practice being that of the camera actor, and click "Ok". If the name has an index, write it without the index and then tweak the GroupName property for the index.

Figure 42
Figure 42

  1. With the InterpGroup selected, click on "Add Property" from the Interpreter toolbar.
  2. In the new window select the m_nmSFXFindActor property, and then click "Add Property".

Figure 43
Figure 43

  1. Change the added property to be the camera actor you want to target.

Figure 44
Figure 44

  1. Right-click on the newly created camera InterpGroup, select "Add New InterpTrack".
  2. Search for "InterpTrackMove" in the window that will pop up, and then click "Add". Don't confuse it with "BioInterpTrackMove".

Figure 45
Figure 45

  1. Repeat steps 7 through 8, but this time select "InterpTrackFloatProp".

Figure 46
Figure 46

  1. Select the newly added InterpTrackFloatProp track, and add the PropertyName property from the "InterpTrackFloatProp" class.

Figure 47
Figure 47

  1. Set that property to "FOVAngle". Make sure it is exactly that, or else the game won't recognize the track.
  2. Add the TrackTitle property from the "InterpTrack" class and set it to "FOVAngle".

Figure 48
Figure 48

If you've done everything correctly the result will look like this:

Figure 49
Figure 49

The InterpTrackFloatProp track will change its name to "FOVAngle" after you save the file.

Adding the InterpGroupDirector

If your InterpData does not have an InterpGroupDirector, follow these steps to add it:

  1. Open the InterpData you want to add the director to in the InterpViewer.
  2. On the top left, click on the "Add InterpGroupDirector".

Figure 50
Figure 50

  1. Right-click on the newly created InterpGroupDirector interpgroup, then click on "Add New InterpTrack".
  2. From the pop-up window select the "InterpTrackDirector" track, then click "Add".

Figure 51
Figure 51

  1. Repeat steps 3 and *4, but this time add the "BioEvtSysTrackDOF" track.

Figure 52
Figure 52

And there you go, it's that easy! The end result should look like this:

Figure 53
Figure 53

Adding the Conversation InterpGroup

If your InterpData does not have a Conversation InterpGroup, follow these steps. If you just want to add the track that controls the switch cameras, jump to step 4.

  1. Open the InterpData you want to add the director to in the InterpViewer.
  2. On the top left, click on "Add InterpGroup".
  3. A prompt will be launched asking you for a name for the InterpGroup. Input "Conversation" as the name.
  4. Right-click the newly created Conversation InterpGroup, select "Add New InterpTrack".
  5. Search for "BioEvtSysTrackSwitchCamera" in the window that will pop up, and then click "Add".

Figure 54
Figure 54

The result will look like this:

Figure 55
Figure 55

Controlling Dialogue Wheel Cameras

You've set your beautiful matinee camera shots, used the right switch cameras, and created a nice flow and pacing of the shots. However, as soon as your conversation hits a dialogue wheel everything goes down the drain with an ugly camera angle. How can you fix this? This is the question we'll be answering in this section.

The basic gist of how dialogue wheels work is that, for example, you have Dialogue Node A (DNA), which plays InterpData A. This DNA then has 3 branches that branch into other dialogue nodes. The game will set a dialogue wheel right after the end of InterpData A and will be in this state until you select a dialogue choice, in which case it will proceed to play the InterpData associated with your dialogue choice.
While it's waiting for you to choose, the game will automatically select an available switch camera that it thinks will work the best.
Here's a visual explanation viewed in the Dialogue Editor:

Figure 56
Figure 56

To control the camera that plays during the dialogue wheel limbo there are two options:

  • Use switch cameras, which is the simplest method, but again, you're limited by the preset cameras.
  • Use a matinee camera, which is a bit more involved, but gives you the most control.

Dialogue Wheel with Switch Camera

This method is very simple: Go to InterpData A, add a switch camera right at the end of it, and then set its bUseForNextCamera property to true.

Figure 57
Figure 57

This tells the game to use that camera for whatever it does next, which in our case is the dialogue wheel. Setting the bUseForNextCamera to true also makes it so the game ignores that key for the InterpData it's inside of. So if you placed it a bit before the ending of it or earlier, the game will not switch to it. However, setting it at the end makes it easier to know what it's for just by looking at the timeline.

If you want to use a custom angle though, or for some reason this method is not taking effect (which happens sometimes for some reason, and the solution is to create a whole new InterpData), you can use a matinee camera for the dialogue wheel.

Dialogue Wheel with Matinee Camera

Since this method is a bit more involved, let's put hands to work and the explanation of what exactly it is doing will come a bit later.

  1. From the Dialogue Editor open in the Sequence Editor the dialogue node that triggers the wheel or just open the file directly in the Sequence Editor and look for the appropriate Interp.
  2. From the Sequence Object Toolbox add 2 SeqAct_Interp and 2 InterpData objects (double click on them in the toolbox).

Figure 58
Figure 58

  1. Connect the created InterpData objects into the Data Variable Links of the Interps.
  2. Click on one of the Interps, then on Interpreter add a new array element to the VariableLinks array.
  3. Go to the newly added array element, and set its LinkDesc to the name of the matinee camera you're gonna use.

Figure 59
Figure 59

  1. In the same Interp, add the bClientSideOnly, bLooping, and bRewindOnPlay properties from the SeqAct_Interp class.

Figure 60
Figure 60

  1. Set the newly added properties to true.

Figure 61
Figure 61

  • OPTIONAL: Remove the OutputLinks property to get a neater look since we won't need it.
  1. Repeat steps 4 to 7 for the other Interp.
  2. Add the InterpLength property from the InterpData class to both InterpDatas, and then set said properties to how long you want them to last. They will loop and restart after the end.

Figure 61.5
Figure 61.5

  1. Add to both Interps a m_aObjComment property from the SequenceObject class, and add a new array element to the property of both afterward.
  2. Set the comment of one of the Interps to something like "WheelDirector", and set the other one to "WheelCam" or something more distinctive, if you plan to use different cameras for different wheels. This is merely for visual purposes.

Figure 62
Figure 62

  1. Right-click the InterpData linked to the "WheelDirector" and select "Open in InterpViewer".
  2. Inside the InterpData add an InterpGroupDirector with its respective tracks.
  3. Add a new Camera InterpGroup, using the same camera name as in step 5. DO NOT add any track to it. This group will be empty.
  4. Add a key in the InterpTrackDirector to target the _Camera InterpGroup` you created. You can also add and set the DOF.

Figure 63
Figure 63

  1. Right-click on the InterData linked to the "WheelCam" and open it with the InterpViewer.
  2. Add a new Camera InterpGroup, using the same camera name as in steps 5 and 14. This time do add all its required InterpTracks and properties.

Figure 64

  1. Set any of the position and rotation values you want, but make sure that if you add movement, said movement ends in the same position it began, or else the camera is gonna jump since this movement will be looping.

Alright, we're almost done and so far so good. Why we've placed the InterpGroupDirector and the camera InterpGroup in separate places will come at the end.

Before we proceed to the next steps, allow me to explain what the sequence for a conversation Interp is:

Figure 65
Figure 65

When a dialogue node in the conversation (as seen in the Dialogue Editor) is reached, it triggers the BioSeqEvt_ConvNode that references it in the sequence, this is marked by "Start" in Figure 65. This in turn triggers the Play input of an Interp, which starts playing whatever is in its related InterpData. Then, when the InterpData ends, the BioSeqAct_EndCurrentConvNode is triggered, marked by "End" in Figure 65, which ends the dialogue node so the game can proceed to the next thing, which in our case is the dialogue wheel.

What we are going to do to tell the game to use our matinee camera for the wheel is to start playing the Interps we set before right after the InterpData that triggers the wheel ends, and then stop them whenever a branch starts:

  1. Select the EndCurrentConvNode of the Interp that triggers the branches (not the one from the branches themselves), and add the OutputLinks property from the SequenceOp class.

Figure 66
Figure 66

  1. Add a new array element to the OutputLinks property, and connect it to the "Play" input of both the "WheelDirector" and "WheelCam1".

Figure 67
Figure 67

  1. Now you need to look for the Interps that correspond to each of the branches that occur from the dialogue wheel, and then connect the output of their ConvNode to the "Stop" input of both the "WheelDirector" and "WheelCam1". While on the following image I placed them close to each other for visual purposes, most of the time they will be far from each other, so you'll have to play a bit with the zoom.

Figure 68
Figure 68

And that's it! Now your dialogue wheel will use your matinee camera. This does look like quite a lot of steps, but once you get the hang of it it's not too difficult.

Going back to answering why the InterpGroupDirector and the actual camera InterpGroup are in separate InterpDatas, it is so that if later you want to have a different camera angle for another wheel, you can create a new InterpData as in steps 4-8 and 17, while reusing the same director InterpData.
The director is always targeting the same camera group, in our example Cam1, but the actual values of that camera are in a "remote" InterpData. So which values get used just depends on which camera InterpData you trigger in step 20, as long as it has the camera group name.
Basically, you get a universal director, and multiple separate "remote" cameras you can trigger at will.

Remember, you need to start them by with the end of the branching Interp, and you need to stop them with each start of the different branches.

Dealing with Camera Clipping

You are casually going through your conversation and then you get scared the heck out of by this:

Figure 69
Figure 69

This happens because of the NearPlane property of switch cameras. As explained in the section related to them, they have a radius that erodes/clips what's inside in order to clear any obstacles, which is the NearPlane value. Usually, it is either low or 0, which means little to no clipping, but sometimes it is higher, which leads to the problem in question.
This can happen with a matinee camera during the dialogue wheel, or during a switch camera at any point.

Clipping During Matinee Cameras

If clipping happens during a matinee camera at the dialogue wheel, the solution is to go to the InterpData that triggers the dialogue wheel and add a switch camera that has a low NearPlane to it, with the bUseForNextCamera property set to true.
You can go to the Choosing a Switch Camera section to learn how to know the NearPlane values of the cameras.

You don't need to switch to the Conversation group in the InterpGroupDirector, this will not change your camera but will take care of the clipping.

Clipping During Switch Cameras

If the clipping happens during a normal InterpData or the dialogue wheel, and the camera you have set is a switch camera, the solution is to:

  1. Add a SFXInterpTrackSetPlayerNearClipPlane track into the Conversation InterpGroup.
  2. Add an element to the m_aNearClipKeyData array. Its m_fValue default value will be 0, which is what we want in order to override the switch camera's NearPlane property. Don't forget to also add an array element to the m_aTrackKeys array.

Figure 70
Figure 70

Adding a BioStage

If you've found out that your conversation lacks a BioStage, follow these steps to add one:

  1. First you gotta figure out which stage to use, so open the Asset Database. You may need to generate a new database if this is your first time using the tool.
  2. Go to the "Meshes" tab, and look into the meshes that begin with "ST_", these are the BioStages. Make sure to toggle on Wireframe and Toggle Mesh Rendering.
  3. Once you've found a BioStage you think will work, right-click any of the files listed on the "Usages" column on the right, and select "Open Usage". This will open the pcc file that contains the BioStage in the Package Editor.

Figure 71
Figure 71

  1. In the opened filed, look for the BioStage object inside TheWorld.PersistentLevel.
  2. Open the pcc file that contains the StartConversation object that triggers the dialogue in the *Package Editor, and go to its PersistentLevel.

Figure 72
Figure 72

  1. Drag and drop the BioStage object from the "donor" file into the PersistenLevel of the file you want to add it to.
  2. In the "Package porting options" window that will pop up, click "Clone All References (Experimental)".

Figure 73
Figure 73

If everything went well, your file should look something like this (remember the export number of the BioStage object):

Figure 74
Figure 74

  1. Open the file's sequence in the Sequence Editor, and look for the StartConversation object that triggers the dialogue.
  2. From the "Sequence Object Toolbox" add a SeqVar_Object.
  3. Add an ObjValue property to it from the SeqVar_Object class.
  4. Set the value of this property to the export number of the added BioStage object.
  5. Connect the SeqVar_Object to the Stage link of the StartConversation object.
  6. Make sure that the Player and your other actors are connected to nodes. If you need more nodes or want to change the name of one so it matches the ones in the BioStage (you'll probably figure this after trial and error), go to the VarLinks property of the StartConversation object.

Figure 75
Figure 75

At this point, we've added the BioStage to the file and added it to the sequence so it gets used by the conversation. We still need to place it in the correct location, and make sure it doesn't clash with any Blocking Volumes.

  1. Open the game, go where the conversation takes place, then type showlocation into the console. This will display the player coordinates, which is where we'll place the BioStage, so write down the coordinates. If you can't physically go to where you'll place the BioStage, use the flycam with profile camera and use the camera position values.

Figure 76
Figure 76

  1. Go back to the newly added BioStage object in the Package Editor, and change the values inside its Location property to match the coordinates you got. If it doesn't have a Rotation you may want to add it to change its orientation if needs be. Note that this time the rotation values are inputted in normal degrees.

Figure 77
Figure 77

  1. Load the conversation and make any necessary adjustments to the BioStage's location and rotation. You may also try placing the actors in different nodes, as mentioned in step 13.

Many times this will be the end of the story. Things should be in place and working. However, it may be the case that you find your actors stepping over other meshes or having weird clashes with objects and stuff. The solution for this is to disable their collisions or blocking volumes, which is discussed in the next section.

Disabling Blocking Volumes

The steps to identify the involved meshes/volumes and disable them is as follow:

  1. Go right beside the mesh/are that's causing trouble, then type profile pawn self into the console. This will display information related to the player pawn, but most importantly, what you are standing on. If it says anything besides "BlockingVolume..." you can ignore it, but if it is a blocking volume write down its name.

Figure 78
Figure 78

  1. Finding which file contains the blocking volume takes a little bit of patience. They are usually located under TheWorld.PersistentLevel in BioA files that refer to the place where the conversation takes place, and are kinda similar to the dialogue file name. For example, our conversation happens in BioD_End001_481HubQuarians.pcc in the command room, and BlockingVolume_0 happens to be inside BioA_End001_460Command.pcc.
  2. With your target found, add a UniqueTag property from the Actor class to ALL the blocking volumes present in the file, EXCEPT the one you found in step 1, then give them unique names. You'll be asked if you want to add the new names, click "Yes".

Figure 80
Figure 80

  1. Go to the sequence that triggers the StartConversation of your dialogue.
  2. Add 2 SeqAct_Toggle objects (from the "Actions" tab), and a BioSeqVar_ObjectFindByTag object (from the "Variables" tab).
  3. Connect the ObjectFindByTag object (same number as unique tags) to one the Toggles.
  4. Add the m_bSearchUniqueTag and m_sObjectTagToFind properties from the BioSeqVar_ObjectFindByTag class to the ObjectFindByTag object. Set the m_bSearchUniqueTag property to true.
  5. Clone the ObjectFindByTag objects to have one per blocking volume to disable.
  6. Set the m_sObjectTagToFind properties to the unique tags you added to the blocking volumes. You'll be asked if you want to add the new names, click "Yes".
  7. Clone each of all the ObjectFindByTag objects once, resulting in having two sets.
  8. Connect one set to one of the Toggles and the other set to the other one.

Figure 81
Figure 81

Right now what we've done is prepare 2 toggles that are going to disable and then reenable all the blocking volumes we need.

  1. Connect the Out link of the StartConversation object to the Turn on input of one of the toggles.

Figure 82
Figure 82

In the next steps, we're gonna reroute whatever objects trigger the conversation.

  1. Break the Output links of all the nodes that hit the Play input of the StartConversation object.

Figure 83
Figure 83

  1. Link the Ouput links of the nodes you just modified to the Turn off input of the free toggle.

Figure 84
Figure 84

  1. Finally, link the Out link of the toggle to the Play input link of the StartConversation object.

Figure 85
Figure 85

You can now test if you had success with the toggledebugcamera command during the conversation, and then trying to go through the areas. If it goes right through them it means you had success.
The reason we are disabling almost all the blocking volumes is because aside from trial and error, we have no reliable way to know which blocking volumes are the ones that do the trick, so we just do disable almost all of them. Sometimes the problematic volumes may be in a different file than what you thought, so you may need to repeat some of the steps. With patience, blood, and tears, this is doable and worth it.

Small note: Using the debug camera makes it so that you'll need to close and open the game again before being able to load a file, otherwise, the game will crash.

Creating Linear Camera Motion Across Multiple InterpDatas

During your camera modding journey you may come across a situation where you'll want a linear camera movement to span multiple InterpDatas. There are two solutions to have it be precise and smooth.

Linear Camera Motion with Dedicated Tool

One method is to use the Mass Effect Camera Motion Calculator tool. It is a small external tool I built that asks you for information regarding what you want to do, and then calculates and tells you where and what values to set.
You can download it from the GitHub repo: https://github.com/Exkywor/MECamMotionCalc/releases.

After downloading it, double-click MECamCalc.exe and a terminal window will launch. There you'll be prompted to input the required information to calculate the values.
This is what a normal example usage will look like:

How many InterpDatas does the camera movement span? 4
InterpData 1 length in seconds: 5 
At what time in InterpData 1 does the movement begin? 3.75
InterpData 2 length in seconds: 4.16 
InterpData 3 length in seconds: 2.1 
InterpData 4 length in seconds: 7.212 
At what time in InterpData 4 does the movement end? 4.4
Starting position as comma separated values (x,y,z): -2391.71, -51000.11, 1431.7
Starting rotation as comma separated values (x,y,z): 0, 19.1693, -117.4392
Ending position as comma separated values (x,y,z): -2408.41, -51032.3, 1444.4
Ending rotation as comma separated values (x,y,z): 0, 25.35, -113.74
For how many time points do you want to calculate values? 3
In which InterpData (1 to n) does time point 1 happen? 1
At what time of it does time point 1 happen? 5
In which InterpData (1 to n) does time point 2 happen? 3
At what time of it does time point 2 happen? 0.75
In which InterpData (1 to n) does time point 3 happen? 4
At what time of it does time point 3 happen? 0

After this, the results will be:

STARTING POINT
InterpData 1, at time 3.75
----------------------------
Position: -2391.71 -51000.11 1431.70
Rotation: 0.00 19.17 -117.44

TIME POINT 1:
InterpData 1, at time 5.00
----------------------------
Position: -2393.46 -51003.49 1433.03
Rotation: 0.00 19.82 -117.05

TIME POINT 2:
InterpData 3, at time 0.75
----------------------------
Position: -2400.35 -51016.76 1438.27
Rotation: 0.00 22.37 -115.53

TIME POINT 3:
InterpData 4, at time 0.00
----------------------------
Position: -2402.24 -51020.41 1439.71
Rotation: 0.00 23.07 -115.11

ENDING POINT
InterpData 4, at time 4.40
----------------------------
Position: -2408.41 -51032.30 1444.40
Rotation: 0.00 25.35 -113.74

Press Enter to exit the program

Then it is just a matter of adding the resulting values in the indicated places.

Important note: As of version 1.0.2, I haven't built input validation into it. However, there should be no issues as long as you input numerical values when prompted.

Linear Camera Motion with Remote Camera

The other method is doing something similar to the technique used in the Dialogue Wheel with Matinee Camera section, so we'll assume you're familiar with it.

First, create empty camera groups in all the InterpDatas the motion will span, and then target them with their InterpTrackDirectors.

Figure 86
Figure 86

Then, open the sequence containing the InterpData, and add a new SeqAct_Interp and InterpData objects. Add the appropriate properties, minus bLooping. The InterpLength should that of the sum of the lengths of all the InterpDatas you want the movement to span.

Figure 87
Figure 87

Open the newly created InterpData, add a new camera group with the same name as the one you're targeting inside your normal InterpDatas, and then add the appropriate tracks and the motion you want it to do.

Figure 88
Figure 88

The last thing to do is to connect the ConvNode of the first Interp of the motion to the Play input of the remote camera Interp, and the Completed and Reversed outputs of the last Interp of the motion to the Stop input of the remote camera Interp. This sets the remote camera to start playing at the first Interp, continue playing, and only stop once you reach the end of the last Interp that you want the motion to span.

Figure 89
Figure 89

Alternate Method for Targeting Matinee Cameras

When learning how to control cameras, the way we did it was by creating an InterpGroup with some GroupName property, usually that of the matinee camera actor, and then targeting the camera via the m_nmSFXFindActor property.

Figure 90
Figure 90

However, there is an alternate method that does not involve the find actor property but requires a bit of sequence editing. The steps are as follow:

  1. Open the Interp corresponding to your InterpData in the Sequence Editor.
  2. Add a new VariableLink with the same name as the GroupName property, if it's not there already.
  3. Add a BioSeqVar_ObjectFindByTag object.
  4. Add a m_sObjectTagToFind property to the object, and make it target the tag of your matinee camera.
  5. Connect the object to the VarLink.

Figure 91
Figure 91

Here's the relationship between properties:

Figure 92
Figure 92

In simple terms, we have an InterpGroup named something containing the camera controls. Then there's an "input" in the Interp, matching that InterpGroup. And finally, we add an object to be affected by that group.

Now, given that this process takes a couple more steps than a simple property, the question arises of why would one want to follow this method. The answer to that would that in Mass Effect 3 there's no real need to target cameras this way. However, in Mass Effect 2 this is THE way to do it. In ME2 there is no m_nmSFXFindActor property for InterpGroups, so all actors (which include matinee cameras) are controlled this way. Besides that, since this technique applies to all actors, you can combine it with some sequence editing to get some pretty flexible options regarding which actor is targeted by some controls.

EXPERIMENTAL: BioStage Editing

When talking about BioStages and switch cameras I mentioned that they cannot be edited. This is not 100% true. The truth is that BioStages cannot be directly edited with the LegendaryExplorer tools, and you can only control switch cameras' rotation, FOV, and a bit of their DOF, but not without the risk of having unforeseen effects somewhere else if the files are still in memory.

However, after running some experiments, I've found out that it is possible to edit a BioStage to move around its nodes and cameras, and also later refine the camera position. All of this without causing issues, in theory, to other scenes. A big caveat though: This requires more testing, so I can't say it will work 100% of the time, but in theory, it should.

Making It Unique

The first thing we'll need to do is clone, rename, and relink the BioStage so that no other part of the game gets theoretically affected by our changes.

  1. Clone (the clone tree option) the BioStage object inside PersistenLevel.
  2. Set its tag property to a unique name.
  3. Clone (the clone tree option) the BioStage and SkeletalMesh.
  4. In the "Metadata" tab, set their names to something unique. Then set their indexes to 0, including the two Components inside the BioStage.

Figure 93
Figure 93

  1. Go to the BioStage object inside PersistentLevel, and in the "Metadata" tab set its Archetype to be the BioStage.
  2. Repeat the same process for the CylinderComponent and SkeletalMeshComponent inside the BioStage.

Figure 94
Figure 94
Figure 94
Figure 94

  1. Go to the BioWorldInfo and add an array element pointing to the BioStage in its ClientDestroyedActorContent property.

Figure 95
Figure 95

  1. Go to the SkeletalMeshComponent inside the BioStage and set its SkeletalMesh property to your cloned SkeletalMesh.

Figure 96
Figure 96

With that done, we can tweak the BioStage without the risk of it affecting other things.

Moving Nodes and Switch Cameras

We're gonna get the BioStage out of the game and into a 3D editing program, in this case, Blender, then edit the mesh and bring it back into the game.

If you plan to use Blender, you'll need the following scripts:

To convert an fbx file to upk to bring back into the game, you'll need these too:

With that done, find the PCC file containing your BioStage and open it in Mesh Explorer. Then right-click the BioStage mesh and select "Export Mesh to PSK with UModel".

Figure 97
Figure 97

Open Blender, press N to open the sidebar, then in the "PSK/PSA" tab click "Import PSK" and select the mesh you exported.

Figure 98
Figure 98

You'll see the BioStage mesh and its skeleton. The skeleton is all the little lines you see, which are the bones. Each bone is used by the game as either a node or a switch camera.

With the skeleton selected, press Tab to go into "Edit Mode", where you'll be able to select individual bones and see their names.

Figure 99
Figure 99

Now you can inspect which bones correspond to what to move them around and place the nodes and cameras wherever you want.
My suggestion is to move them with their axis constrained. That is, with a bone selected, press g to start moving it or r to start rotating it, and immediately after press x/y/z to constrain the movement to that axis.
Given that when importing meshes into packages the mesh cannot have more bones, we cannot add new nodes or cameras, but just being able to move them to custom positions should be more than enough.

After you're done with your changes, go to File > Export > FBX and export your file, making sure to disable the "Add Leaf Bones" option under "Armature".

Figure 100
Figure 100

To get the fbx into upk, which is the format Meshplorer requires, open the FBX Converter, add your fbx file, and click convert. Open the UDK Editor, and import the converted fbx into the "Content Browser". Then right-click the package and hit "Save".

Figure 101
Figure 101

Now go back to Mesh Explorer, right-click the BioStage mesh, and select "Replace MEsh from UDK".
If you get a message saying that the rotation has changed, open the mesh in the Package Editor, go to the "Binary Interpreter" tab, then click on Rotation Origin. This will show you the relevant hex code part, set all the highlighted code to zeros. Then hit "Save Hex Changes".

Figure 102
Figure 102

And we're done with the main bulk of editing a BioStage! Now go in-game and see the result of your changes.

Refining the Switch Cameras

The last step is setting the proper rotation, FOV, and DOF values for the switch cameras you moved around. Simply go to the BioStage, find the Camera item in the m_aCameraList array, and tweak the values to what you need.

Figure 103
Figure 103

Here's a before and after of a tweaked switch camera and a node moved around (where Raan stands):

Figure 104 Figure 104

Miscellaneous

Here are some topics that are useful for the camera modding process, but are definitely tangential.

Setting up the Coalesced for Camera Editing

By default, the game lacks certain QoL features for camera modding, like moving the flycam up or down or controlling its view with the mouse. We'll add the needed functionality via editing the BioInput of the Coalesced file, and then I'll suggest some keybindings I also find useful to add.

If you've never edited the Coalesced files, you can do so with the Coalesced Editor tool from ME3Explorer. The basic process is as follows:

  1. Launch the tool.
  2. Next to "Source", click "Browse", and navigate to and select your game's Coalesced.bin. It should be under [GAME INSTALL FOLDER]\BIOGame\CookedPCConsole\Coalesced.bin
  3. Click on "Convert".
  4. Go to the folder where the Coalesced was converted, if you didn't change anything it should be [GAME INSTALL FOLDER]\BIOGame\CookedPCConsole\Coalesced, and open the BioInput.xml file.
  5. HERE'S WHERE YOU ADD THE THINGS WE'LL SEE IN A BIT.
  6. Save the file.
  7. Go back to the Coalesced Editor, click "Browse" next to Source again and navigate to and select Coalesced.xml. It's inside the same folder as BioInput.xml.
  8. For "Destination", choose the path where the original Coalesced.bin was. [GAME INSTALL FOLDER]\BIOGame\CookedPCConsole\.
  9. Click "Convert".

You can leave the coalesced folder that was created, or you can delete it if you want. DO NOT delete the Coalesced.bin file that you just created.

The basic QoL lines we're gonna add in step 5 are these:

  • In <Section name="sfxgame.sfxgamemodeconversation"> paste the following:
<Value type="2">( Name="A", Command="PC_StrafeLeft" )</Value>
<Value type="2">( Name="D", Command="PC_StrafeRight" )</Value>
<Value type="2">( Name="W", Command="PC_MoveForward" )</Value>
<Value type="2">( Name="S", Command="PC_MoveBackward" )</Value>
<Value type="2">( Name="MouseX", Command="PC_LookX" )</Value>
<Value type="2">( Name="MouseY", Command="PC_LookY" )</Value>
<Value type="2">( Name="E", Command="MoveDown" )</Value>
<Value type="2">( Name="Q", Command="MoveUp" )</Value>
  • In <Section name="sfxgame.sfxgamemodebase"> paste the following:
<Value type="2">( Name="MoveUp", Command="Axis aUp Speed=0.75" )</Value>
<Value type="2">( Name="MoveDown", Command="Axis aUp Speed=-0.75" )</Value>
  • In <Section name="sfxgame.sfxgamemodeflycam"> paste the following:
<Value type="2">( Name="Q", Command="MoveDown" )</Value>
<Value type="2">( Name="E", Command="MoveUp" )</Value>

In the end, it should look like this:

Figure 105
Figure 105

What we've set up allows you to move the camera freely with the flycam during a conversation, and move it up and down with the E and Q keys.

I also like to add the following key bindings for my most used commands in <Section name="sfxgame.sfxgamemodebase">:

<Value type="2">( Name="p", Command="playersonly", Control=True )</Value>
<Value type="2">( Name="o", Command="toggleflycam", Control=True )</Value>
<Value type="2">( Name="o", Command="toggledebugcamera", Alt=True )</Value>
<Value type="2">( Name="i", Command="profile conversation", Control=True )</Value>
<Value type="2">( Name="i", Command="profile camera", Alt=True )</Value>
<Value type="2">( Name="i", Command="profile none", Shift=True )</Value>
<Value type="2">( Name="l", Command="showlocation", Control=True )</Value>
<Value type="2">( Name="NumPadZero", Command="fov 0" )</Value>
<Value type="2">( Name="NumPadOne", Command="fov 23" )</Value>
<Value type="2">( Name="NumPadTwo", Command="fov 33" )</Value>
<Value type="2">( Name="NumPadThree", Command="fov 40" )</Value>
<Value type="2">( Name="NumPadFour", Command="fov 60" )</Value>
<Value type="2">( Name="NumPadFive", Command="fov 15" )</Value>
<Value type="2">( Name="NumPadSix", Command="fov 35" )</Value>
<Value type="2">( Name="NumPadSeven", Command="fov 45" )</Value>
<Value type="2">( Name="NumPadEight", Command="fov 80" )</Value>
<Value type="2">( Name="NumPadNine", Command="fov 100" )</Value>
<Value type="2">( Name="One",Command="slomo 0.1", Control=True )</Value>
<Value type="2">( Name="Two",Command="slomo 0.2", Control=True )</Value>
<Value type="2">( Name="Three",Command="slomo 0.3", Control=True )</Value>
<Value type="2">( Name="Four",Command="slomo 0.4", Control=True )</Value>
<Value type="2">( Name="Five",Command="slomo 0.5", Control=True )</Value>
<Value type="2">( Name="Six",Command="slomo 0.6", Control=True )</Value>
<Value type="2">( Name="Seven",Command="slomo 0.7", Control=True )</Value>
<Value type="2">( Name="Eight",Command="slomo 0.8", Control=True )</Value>
<Value type="2">( Name="Nine",Command="slomo 0.9", Control=True )</Value>
<Value type="2">( Name="Zero",Command="slomo 0", Control=True )</Value>
<Value type="2">( Name="One",Command="slomo 1", Alt=True )</Value>
<Value type="2">( Name="Two",Command="slomo 2", Alt=True )</Value>
<Value type="2">( Name="Three",Command="slomo 3", Alt=True )</Value>
<Value type="2">( Name="Four",Command="slomo 4", Alt=True )</Value>
<Value type="2">( Name="Five",Command="slomo 5", Alt=True )</Value>
<Value type="2">( Name="Six",Command="slomo 6", Alt=True )</Value>
<Value type="2">( Name="Seven",Command="slomo 7", Alt=True )</Value>
<Value type="2">( Name="Eight",Command="slomo 8", Alt=True )</Value>
<Value type="2">( Name="Nine",Command="slomo 9", Alt=True )</Value>
<Value type="2">( Name="Zero",Command="slomo 10", Alt=True )</Value>

Editing While the Game is Running

Camera modding is a process that requires a lot of trial and error. If you had to close and reopen the game every time you did an edit, that would be horrible, but thanks to the amazing developers of these tools, that's not the case!

All you need to do is install the AutoTOC ASI v2 ASI mod through the *ASI Manager. Then, as long as you are directly editing PCC files inside the game installation folder, you can save the files and you'll see the changes after you load a save.

Figure 106
Figure 106

Loading a Save While in a Conversation

There will be moments where you are editing only the start of a conversation, but it is a long one and maybe also leads to a long cutscene, so stopping midway to reload is not possible and it takes so long. What do you do? Simple! Open the in-game console and input open biop_nor. This will load you right away into the Normandy. From there you can just reload your save to continue editing. This paired with the previous advice will make your modding life way more efficient and painless.

Related Guides

These are some guides that you'll probably be interested in for conversation and camera modding:

Final Words

Before ending this, I want to give special thanks to Lunk/Lunkensko/Linkenski for teaching me pretty much all I know about camera modding. All this knowledge I've shared is just what I've been able to learn from him through what have probably been too many questions. I'm extremely thankful for his help and patience in getting me this far.

Camera editing is a process that can be frustrating and requires a lot of patience at times, but the results are worth it. My only hope is that this guide helps you accomplish whatever vision you've set for your mod.
Happy modding!

⚠️ **GitHub.com Fallback** ⚠️