Can We Have Relative Paths Within 3DS Max?

So…

One of my problms moving fwd will be relative paths in 3D Max. I’ll describe the need:

Option 1:
Let’s say a group of artists will be working on say, an E3 demo or DLC content, and we want to separate their content for a period of time. The ideal way to do this would be to author the content with relative internal pathing for assets like textures, materials, xref’s/instances.

example: <branch> rees extures\oak_bark_001.tga
where branch could be: c:\gameBuild\E3Branch

Option 2:
The next best alternative I can think of is a substitution path: I can make a virtual drive on Joe Artists’ machine like say, X: and X: maps directly to c:\gameBuild\E3Branch, but, if we decide to change Joe Artists’ enlistment to say, DLC content then we can map X: to d:\gamebuild\DLC\

Option 3:
The final (and crappy) alternative is to run a batchscript on all the content and force a new path on the assets that you are branching, this sounds like a pain-in-the-ass.

I hope at least one of the tech-artists.org brainiacs knows of a way to make option 1 a reality.

Each artist can have a setting on their computer (I’d suggest a registry key as opposed to an environment variable) that determines their current project- they can modify this or it can be modified by TA/automatically/within a tool. Then you’d have some .NET code like this:

[highlight=c#]
public enum BranchType
{
NONE=0,
E3Branch,
NewExpansionPack,
DlcDownload
}

public static class BranchPathManager
{
public static BranchType GetCurrentBranchType()
{
return EnumParser<BranchType>(GetRegistryKey(myPathToSaidRegistryKey));
}

public static string GetBranchPath(BranchType brtype)
{
	string brpath;
	switch (brtype)
	{
		case E3Branch:
			brpath = "c:/gameBuild/E3/";
			break;
		case NewExpansionPack:
			brpath = "c:/gameBuild/ExpPack/";
			break;
		case DlcDownload:
			brpath = "c:/gameBuild/Dlc/";
			break;
		default:
			throw new Exception(brtype.ToString() + " is not a recognized BranchType!");
	}
	return brpath;	
}
public static string GetCurrentBranchPath()
{
	return GetBranchPath(GetCurrentBranchType());
}

}



We do this sort of thing pretty commonly (store values in the registry and use them to dynamically determine things such as tool deploys and paths).  So to use it in Max, you'd call:


(DotNetClass “MyNamespace.BranchPathManager”).GetCurrentBranchPath()) + “enemyCharacter\animation\walkForward.max”



or whatever.  I'd also suggest wrapping the DotNet stuff into a struct for easier use:

```mxs

struct branchPathManagerDef
(
	branchPathManagerClass = DotNetClass "MyNamespace.BranchPathManager",
	fn getCurrentBranchPath =
	(
		brachPathManagerClass.GetCurrentBranchPath()
	)
)

branchPathManager.getCurrentBranchPath() + "enemyCharacter\\animation\\walkForward.max"

They may have added something recently for relative paths, but as of a couple releases ago, Max had a very specific, hard-coded means of finding external texture/xref files.

I also wanted to say that, in my experience, there’s never been a need to re-path all paths inside your Max scenes. It’s designed to do that for you, in a sense, although how it does that isn’t very obvious…

I did some testing a couple years back, and here’s the search order Max used for each texture/shader used in a scene:

  1. Disk location the texture was originally assigned from.
  2. Folder the .max file being loaded resides in.
  3. Every subdirectory under the one the max file resides in (recursive)
  4. Folders in the user’s External Files list, in order from top-to-bottom.

If it gets through all four and cannot find a texture with the base filename it’s after, it’s added to the list of missing files shown in the customary warning dialog.

Now #1 is a quick check, since it’s only looking in one specific place per texture. So is #2, but #3 is where texture searching can really kill your users. For instance, if you’re loading a max file from the root of D:, once it gets to #3 it’s now recursively searching every subdirectory on that whole drive before giving up. Repeated for every texture not found in 1 or 2.

Now you can manually re-path all your max files to point to new locations when they move, or the user changes his workspace, but there’s really no need to do that. The External Files list is there to lean on.

At Volition we have a script that runs when Max is launched. It looks at the user’s current “workspace” or branch root directory, then builds a list of all texture-related subdirectories under it. It then takes that list, sorts it and forces it as the current External Files list (found in 3dsmax.ini), prior to starting Max.

This ensures that every scene loaded that can’t find its textures in the original location quickly finds them, no matter what workspace/branch location they’re currently using. It’s also repeated for the XRefs directory list, which works the same way but for XRef files.

There’s only two lingering gotchas with this. First is that #3 above is still in play. Users have to be mindful not to save max files in directories with lots of subdirectories underneath. Generally our source control structure for storing max files takes care of that.

Second is just an inconvenience for the sync-paths script, in that #4 cannot be made to be recursive. Every single subdir you want it to search in has to be explicitly listed in the External Files list. I’ve often wished Autodesk would just move the recursive part from #3 to #4, solving both of the above, but alas.

Again, this may also not reflect current behavior in 3ds Max 2010+, since I last tested it on Max 9 or 2008 I think. Although I’d be somewhat surprised if this has changed.

I have permission to post our sync-paths script, but I need to make a pass at removing any unannounced project titles from it. I’ll try to do that in the next day or two.

Pak,

You can do what you want using the Asset Tracking System (or ATSOPs Interface) for your option #1. ATSOPs allows you to get the current branch and use it as your ‘current project’. All the commands needed can be looked up quickly using the 3dsmaxscript help by searching for atsops

Using the ATSOP interface, you should ensure all your materials are set up as relative on load. Once the information is relative you can obviously change the branch to whatever you want.

Using a callback, the directory that contains the the max file is now the project folder name – and max can therefore repath the files on the fly. The users will never know.

A couple of pitfalls / notes:

  1. Using a project folder means that the default directories are changed. I would suggest hard coding the backup directory and the others to use their default state. Its just cleaner – and it will make things easier for your people to know where their backup directory is located no matter what branch they are in.

  2. I did find one small bug, to ensure that all the commands are properly picked up – you should unhide/hide the Asset Tracking dialogue when max starts. I’ve searched a few forums for a fix for this – and others have done the same thing.

  3. If you have artists who copy their work to their desktop or some other workspace to test things out – they will not be able to find the textures. This is because the paths won’t exist relative to the desktop. If this becomes a problem, you may want to have some rules about converting to an absolute path (an option through the ATSOPs interface) if the file is opened outside your branch directory.

This will work as far back as Max 9 and will still work with max 2010 – but i haven’t tested it with anything earlier.

J.

Thx for all the great suggestions. I’m gunna try them all and see what suggestion to make to my pipeline team.

Hey Adam,

What happens if you have a user that has two branches – a release branch and a test branch.

The user opens the file from the test branch.

As you’ve described below, won’t the script still find the release branch textures? How do you ensure that your script is now pointing to the test branch if the user has both branches on their drive?

J.

[QUOTE=Adam Pletcher;4648]At Volition we have a script that runs when Max is launched. It looks at the user’s current “workspace” or branch root directory, then builds a list of all texture-related subdirectories under it. It then takes that list, sorts it and forces it as the current External Files list (found in 3dsmax.ini), prior to starting Max.

This ensures that every scene loaded that can’t find its textures in the original location quickly finds them, no matter what workspace/branch location they’re currently using. It’s also repeated for the XRefs directory list, which works the same way but for XRef files.[/QUOTE]

The users can have locally synced files from as many branches as they want, but they can only have one active branch at a time. Each time Max starts it rebuilds the external files paths based on that active project/branch, ensuring it grabs the right textures/shaders/xrefs.

[QUOTE=Adam Pletcher;4648]
I have permission to post our sync-paths script, but I need to make a pass at removing any unannounced project titles from it. I’ll try to do that in the next day or two.[/QUOTE]

Hi Adam,

Is this offer still standing? I’d be interrested!

Thanks,
-Johan

Definitely, I started cleaning it up but didn’t get around to finishing it. I’ll try to squeeze it in this weekend.

I think it is possible to have relative path, I have seen max files with textures stored in subdirectories, which are not fixed path.

Its seems good and I hope you will keep it up