Posted December 21, 2021 Welcome! Recently I've been keeping pretty busy. I started going back to school, and the holidays have kept me going; however, I found some free time and I wanted to do something modding related. I read a lot of questions about custom models on some of the discords I frequent. I felt this would be an awesome opportunity to expand our knowledge base on OC. C20 has a lot of extremely useful information, but my hope is to teach you a deeper understanding of how the engine handles creating and managing a model presented in a scene. A GBXModel is the pc variant for the tag used to define a model used as an asset for Halo. A GBXModel isn't just "a model" but instead it is a collection of models. These models define the objects state for a given instance or condition. These models can be broken down into Regions and assigned Permutations for some variation, defined Levels of Detail for proper optimization, bound to Nodes for animation, and assigned Markers for special effects. In order to create a GBXModel we need to use tool's Model command to compile the raw model (jms) into a GBXModel. Tool will take all of our different models and compile them all into the collection of models discussed above. Of course this is an oversimplification for the introduction to the concepts, there's a bit more that goes into it. I will discuss each of these ideas later in the post. Table Of Contents 1. Nodes 1-1: Summary 1-2: Example Hierarchy of Nodes 1-3: Creating a Node Newer Versions Of Max Older Versions Of Max 1-4: Other Node Information 1-5: Common Node Issues Tool Ghost JMS Exporter 2. Regions 2-1: Summary 2-2: Example Region Variations (Permutations) 2-3: Creating a Region Blitzkreig & Ghost JMS Exporter FBX-to-jms 2-4: Creating a Permutation 3. Markers 3-1: Summary 3-2: Example Markers 3-3: Creating a Marker 4. LODs 4-1: Summary 4-2: Example LODs 4-3: Creating LODs 5. Creating GBXModels 5-1: Exporting FBX-to-jms Ghost JMS Exporter 5-2: Compiling a Model Additional Information PLEASE If I missed anything, or could make anything more clear lemme know c: I would like for this to be as accurate and complete as possible. It took me 8 hours to write this up, I want to make sure it wasn't for waste! Happy modding Updates: 12/22/21 Markers : TY Galap/Mata for the suggestion to clarify markers aren't required to be spheres, and reemphasize that orientation matters. Regions : Updated network sync details 12/25/21 Markers : included example LODs : Wrote introduction 01/06/22 LODs: Wrote "Creating LODs" Formatting: Adjusted nodes to its own post setup TOC. 01/11/22 Formatting: Finished To Do Once I have time to update: Discuss GBXModel Importer by ghost Takka and swamp like this Specifications: S3dpak - format - Imeta/ipak - format - Fmeta - format Programs: H2a-inflate - SuP Share this post Link to post Share on other sites
Posted January 6, 2022 Nodes Nodes are anchor points for our 3d models. They are called nodes because they determine the object hierarchy like a graph. Every model requires at minimum a root node. This node must be prefixed with "frame" or "bip01". Beyond that nodes act like "bones". You anchor a portion of the mesh to a node, and when we animate; it's the nodes that we are animating. Each part of a mesh that moves during animation needs to be assigned to a node. It's worth noting that each vertex can only be influenced by up to two nodes in the case of a rigged model. There are other uses for nodes as well; however, I will cover those later in the collision_model. Nodes don't have any mesh data themselves, they represent a point in a hierarchy with a 3d coordinate and orientation. We typically represent them as a scene object such as a sphere; however, this is only used to interact with the node in the scene. Once we export the models to jms the 3d position, orientation, and position in the hierarchy are the only bits of information passed through to the GBXModel. It's also important to remember nodes need to remain consistent between permutations. (discussed later) Example Hierarchy of Nodes: Spoiler Notice how all of the children (frame chain, frame gun, and the gun its self) move when I move the parent node "frame gun mount base" None of the "frame" objects are actually spheres that appear in the final GBXModel, instead they link children objects to their parents and determine their location and rotation in 3d space. Creating a Node: Spoiler First we want to create a primitive that will be used as a handle for the node, I chose a sphere. Then I rename the sphere so the name starts with "frame ". After doing that we can either use the "Select and Link" tool for older versions of max, or on newer versions you can just drag the child object over the parent in the scene explorer panel on the left and it will adjust the hierarchy for you. When rigging a biped the skinning process will handle binding vertexes to bones. The "bones" of a biped rigging get interpreted as nodes and mapped accordingly by the engine. Once the nodes are mapped correctly, if you move or rotate your frame the object should reflect the changes are well. Nodes may contain more child nodes; however, there is a limit to how many nodes you can have. This depends on version. Check out C20 for more information on that. Newer Versions: Spoiler On Newer versions of max you can just click and drag the name over the "frame" object in the hierarchy panel Older Versions: Spoiler On older versions of max click the "Select and Link" tool in the top left corner. Then click and drag from your object onto the sphere named "frame" Other Node Information: Spoiler Your root node position influences the position of the bounding sphere for a model. The bounding sphere is responsible for optimizing out the mesh when you can't see it anymore. This will cause inappropriate culling (or not drawing the object to save resources) as the engine doesn't think you can see the item any more. This may also impact physics calculations. Keeping the position of your root node as close to "center" as possible will be the most optimal. An easy way to do this in 3DS Max is to use the align tool. Before you link the object to the frame, select the frame and use the align tool to align to the objects center. This will put the frame in the most optimal position for the bounding sphere. Common Node Issues Spoiler Tool: Spoiler "No actors to export. Actor root node must start with prefix 'frame' or 'bip01'." Seen when "tool fbx-to-jms" doesn't find a root node prefixed with "frame" "### ERROR this model has too many nodes." Seen when you exceed the node limit. Check this out for more technical information. Ghost JMS Exporter: Spoiler "There are no actors to export!" Seen when jms exporter doesnt find a root node prefixed with "frame". Specifications: S3dpak - format - Imeta/ipak - format - Fmeta - format Programs: H2a-inflate - SuP Share this post Link to post Share on other sites
Posted January 8, 2022 Regions Regions are named sections of a model. This allows you to create different versions for that section of model that can be selected randomly or assigned with scripting. These variations are called Permutations. There are other uses for regions; however, they are covered more in the collision_geometry section of the tutorial. Because these permutations can be selected randomly the region needs to be mapped to the same bones as the base mesh. Which means they require the same amount of nodes even if the vertices that those nodes bind to doesn't exist in this permutation. There are special case regions used by the engine when specific conditions are met: ~damaged : Gets chosen when the object's health reaches a certain threashold. ~shield_off : Gets chosen when the object's shields run out ( If it has shields ) ~primary_blur : Chosen when a weapon reaches a firing speed threshold with primary trigger pressed. ~secondary_blur : Chosen when a weapon reaches a firing speed threshold with secondary trigger pressed. ~blur : Chosen when vehicle reaches a speed threshold specified in a vehicle tag. These special permutations are completely optional; however, they add a lot of life to a object. They will make a bit more sense when we get to collision models, I will hold off on explaining them until I get around to making that tutorial. Something to notice is that these names all start with a "~" which is a special character used to tell the engine that this region isn't one that we want to get randomly chosen. We can use this naming convention for our own purposes if we like; however, the only way we can utilize a permutation like that is through scripting. For people making campaign/coop missions this may be desirable. Also any permutation selected randomly will not synchronize over a network. This means in order to use permutations as variations for objects online, and have each player see the same one, you MUST select it with a script at start up. If not each player can have a different random permutation set. For some scenery objects this is not that big a deal. For example halo 3 uses this concept to change the position of stickers on a barrel. For other objects though you need to be careful as it may cause inconsistencies between clients. My general rule of thumb for this is "if the collision stays the same it's ok". A random pile of papers on a table, or different labels on a barrel won't impact game play; though, a soda machine being there for some people and not others can be game breaking. Having permutations can add some variety to your maps, but try to keep it to smaller details for multiplayer, or force the permutation with a script for all clients. (optionally you can also create LODs once you're done creating regions and permutations) Example Region Variations (Permutations): Spoiler Left: Marine Base ----- Right: Marine [Sgt Johnson Head] [Long Sleves] Example Permutation: Example of how nodes must exist even when the remaining mesh isn't present for a specified region Creating A Region: Spoiler Defining regions depends on what tools you are using... For Ghost JMS Exporter and Blitzkreig you define a region by selecting the faces you want in a region and giving it a name in "Name Selection Set": Spoiler For tool fbx-to-jms you assign a region using the material name Spoiler The first half of the name is the material its self, the last half is the region. Then between the material name, and the region name there is "_atr_lpr_" This allows you to define regions with the same texture and different names, as well as regions with different textures in the same name. face_atr_lpr_head hair_atr_lpr_head Defines two materials, face and hair, they are both in the "head" region shirt_atr_lpr_torso shirt_atr_lpr_arms defines one material shirt, but it is split up between the region torso, and the region arms Creating a Permutation: Spoiler Creating a permutation is pretty simple. Once we've defined regions in our main model; we can isolate the regions that we wish to make a variation of, make the variation and then save it with a new name. When tool goes to compile the model it will find the other variants and create a permutation for each region we included. In our example I create a cork board which will have pieces of paper on it. The papers will pick a random permutation when it loads the level. I create a region named "base" with a material "cork" which contains the cork board it's self. This region is our default region. It will be chosen no matter what. This version has no paper on it. I bind this to a frame and export it with the name "base.fbx". Next I create a couple sheets of paper that will go "on" the cork board. These get their own regions called "papers" and their own texture called paper. I us the original model as a reference to place the papers, and then bind just the paper to the frame and export with the name "papers_1.fbx". I make a variation of the position of the papers and export it as "papers_2.fbx". Then I convert all the models to JMS using the fbx-to-jms command through tool. When tool compiles these models with the model command they will get combined into one model. The base model will always show, but the "papers" region will pick a random variation at load. I create an example scenery object to show you the end result. You could if you like add a "papers" region to the base mesh as well. Tool will find the matching regions and create a new permutation for paper called "base". The base permutation also has a chance of being randomly selected. (remember if you want you can add ~ to the front to avoid it being randomly selected) Create Board: Create "Cork" Material and "Base" Region: Use Board as a Reference To Place Papers: Create "Paper" material in "Papers" region: Delete Cork Board From This Permutation After Done as Reference and Bind to Frame: Export The File as Papers_1: Create Variation and bind to frame: Export as Papers_2: Create JMS File: (This is discussed further towards the end of the tutorial) Create Model: Final Product: Specifications: S3dpak - format - Imeta/ipak - format - Fmeta - format Programs: H2a-inflate - SuP Share this post Link to post Share on other sites
Posted January 9, 2022 Markers Markers are points relative to the mesh that can be used to define a position (and rotation) used for things like spawning special effects or attaching an object to another. For example we could have a marker at the end of a gun that emits smoke, or a marker used to attach the pipe to the Keyes' hand. Markers are created similar to nodes; however their names must start with a #. They are represented with a scene object, such as a sphere or other primitive. The object is just a handle used to adjust position and orientation of the marker relative to a node. None of it's mesh data will be included once we export. When creating tags that utilize the gbxmodel we can define the effects that spawn at the markers, or in scripts we can reference the marker names directly. Any markers that happen to have the same name will have the effect applied to both positions at once. For example if you have two marker called "#steam_emitter" and you attach a steam emitting effect to that marker name, both markers will emit steam. It's also worth noting that markers are owned by the permutation. This means that unlike nodes there don't have to be the same amount markers for all permutations. You can have a permutation that has two steam emitters, a perm that has one steam emitter, and a perm that has none if you like. There are a few special case markers as well. Halo uses these for certain functionality like head position so AI knows where to look, or hand locations. For more information on this check out the c20 page on markers; They do a great job explaining this, and I don't want to reinvent the wheel. Example Markers: Spoiler The pelican uses markers for many purposes. Each seat, seat's camera position, vehicle entry position, lights, thrusters, cargo position, etc. are all their own markers littered throughout the model. How these markers get utilized is determined by the tag that implements the object (the vehicle tag) and scripts that might be executed referencing against pelican as an object. Creating a Marker: Spoiler Creating a marker is similar to creating a node. I'm going to use a sphere to denote it's location in space and to give us a handle to modify it's position and rotation. (It is not required we use a sphere. Some people prefer using shapes that better presents it's orientation; such as a pyramid or asymmetrical cube) Next we're going to apply the special name to it, #steam. I'm going to make a few permutations of this model. A variation with 0, 1, and 2 steam emitters like mentioned above. Then compile and build an example scenery object to test the markers. Assigning effects to markers aren't going to be a part of this tutorial, as that's done outside of the gbxmodel its self. Create Markers and Name it #Steam: Link it to a Frame, Export, and Build (See Creating GBXModels at the end): Create a Test Scenery Object: Notice how the bottom one has no steam emitters, the middle one has one steam emitter, and the top one has two. The number of markers does not need to remain consistent between permutations. Specifications: S3dpak - format - Imeta/ipak - format - Fmeta - format Programs: H2a-inflate - SuP Share this post Link to post Share on other sites
Posted January 10, 2022 Levels Of Detail (LODs) LODs are (optional, but highly recommended) optimized versions of permutations that are chosen based off distance the object is from the camera. Your first instinct might be "My computer was built almost 20 years after this game has been made. It can handle high poly counts, let's crank up the detail."; however, I would like to temper your expectations. There are two main reasons for this: 1) High poly counts does not necessarily mean better detail (It may just be poorly optimized). It's better to say more with less. Not everyone has a high end system. We can't forget this is a game and people may wish to play competitively against each other. a versatile asset uses only the amount of detail necessary to say what it needs to say. 2) Something I call "Detail Dissonance"; When your mesh has more detail than surrounding meshes it contrasts more with the scene. Artistically this draws someone's eye more to that object. This this could be a good or bad thing depending on your desired outcome. It is in my opinion that high poly model surrounded by low poly models can break the cohesion, and unbalance a scene if not done properly. Using LODs will help prevent this for far away objects. Halo allows you to define 5 optional stages of LODs: super-high high medium low super-low Tool will remind you when compiling GBXModels to set the LOD cutoffs. These are set inside guerilla and determine the threshold where one switches to the other. (see below "Creating LODs") Something to note about LODs and markers and nodes. You still require all of the nodes to be in each LOD version; however, markers are only read from the Super-high LOD. This means if your mesh doesn't utilize a Super-high LOD your markers aren't going to be included. If you don't use any LODs the default option will be super-high, so this may not be an issue. Though, do keep it in mind. Example LODs: Spoiler Super-high, Medium, and Super-low LODs. Notice the variations in detail between the versions. LODs are chosen using the diameter of the object's bounding sphere in pixels. To see an object's bounding sphere in sapien press ~ to open your console and type these two commands: debug_objects true debug_objects_bounding_spheres true Creating LODs: Spoiler Creating LODs is pretty simple. For each permutation you make, take some time to create lower poly versions of the model (sometimes you can get away with using the optimize modifier). Then when you're happy with the mesh. Export the file (see below "Creating GBXModels") into your models folder like you would when creating a permutation; however, After we type the name of the permutation we're also going to type a space and the name of the LOD this model represents. We're going to do this for each permutation. After we create the GBXModel with tool it will remind us we need to set the LOD cutoffs. To do this after the model is created, we're going to open guerilla. Goto file>open and navigate to our new model (Remember tool reflects the naming convention you used in the data folder. So if the models are located data\scenery\object\models the GBXModel will be output in tags\scenery\object\object.gbxmodel.) Once open, right at the very top we see the 5 text boxes that hold the cutoff values measured in "pixels". The "pixels" is how many pixels the bounding sphere takes up on screen (see example LODs above). The further away the object is the fewer pixels it'll take up on screen. Every model is a little different so these values need to be played with until you get something you like. Something to note as it is slightly unintuitive. The bounding radius of the model is set in the tag that implements the GBXModel. So you need to be careful if you have separate tags that use the same GBXModel. (like the pelican for example has a vehicle tag and a scenery tag) you want to make sure you use consistent bounding radii between the two or the LODs will behave differently between the two (which may or may not be desirable). If this doesn't make any sense right now don't worry. We'll touch on this more in future tutorials. Specifications: S3dpak - format - Imeta/ipak - format - Fmeta - format Programs: H2a-inflate - SuP Share this post Link to post Share on other sites
Posted January 11, 2022 Creating GBXModels creating a GBXModel requires us to export our data from 3ds max in a format tool can utilize. This format is called .jms and to get a model in that format we have a few options: Ghost JMS Exporter, Blitzkrieg, and FBX using H1A-EK's tool. For this tutorial I will touch on Ghosts JMS Exporter, and tool's fbx-to-jms converter which are the more popular of the options. All jms files are expected to be inside of a folder named "models" and this folder is expected to be found inside your "data" directory. Beyond this it is up to you how you wish to organize your folders. Tool will mirror the naming convention you used with the "data" folder in your "tags" folder for compiled files. If you save your models in "data\scenery\new_thing\models" tool will compile your GBXModel to "tags\scenery\new_thing\new_thing.gbxmodel" and create the necessary folders to facilitate that. Exporting Spoiler Tool FBX-to-jms Spoiler Once you've read this tutorial and have your super awesome model you wish to export. we're going to go to "File>Export". This will open a file explorer dialog box. We want to select "Autodesk (.FBX)" as the type. We will navigate to our data directory and create a new folder with the name of our object. Inside we will create the "models" folder that our FBX file will sit inside. We'll name our model, and click save. After we have done that we will open a command prompt in our root chelan_1 directory and run the command: tool fbx-to-jms "data\new_model\models\new_model.fbx" "data\new_model\models\new_model.jms" This will convert our fbx model into a jms and let us move on to the next step of compiling our GBXModel (explained below) File>Export: Navigate to My Data Directory: (Notice the path data\gbxmodel\nodes\models and notice the save as type FBX) Convert the FBX to jms: Ghosts JMS Exporter: Spoiler Instalation: Spoiler To use the Ghost JMS Exporter we first need to download it from their website. After downloading I'm going to open my Downloads folder, and copy the script. Next we're going to open 3Ds Max and under "Scripting>Run Script.." I'm going to paste the downloaded script. It may ask you for administrator permission, this is because the scripts folder is part of the "program files" for some reason. Just go ahead and accept and you have the exporter installed! Copy the Script: Open the Run Script Dialog: Paste the Script Into the Scripts Folder: Using The Exporter: Spoiler Once you have your model you wish to export. we're going to go to "Scripting>Run Script.." and select the JMS Exporter we just installed. This will open up a minimalistic window. We're going to leave all the settings default and click export JMS Data. This will open a file explorer dialog box. We will navigate to our data directory and create a new folder with the name of our object. Inside we will create the "models" folder that our JMS file will sit inside. We'll name our model, and click save. Run Script: JMS Exporter: Exporter Window: Save the JMS: (Notice the path data\testing\gbxmodel\nodes\models) Compiling a Model: Spoiler Once we have the models organized in the "data/.../models" folder we will ask tool to compile the model. The way we do this is by opening a command shell in the modding directory and running "tool model data\root\new_thing\". Notice that this doesn't include the "models" folder. Tool expects there to be a models folder, and it will yell at you over it too. When we do this for the first time tool will ask you what type of shaders we wish to make for the model. It will ask you for each material assigned to the models (shaders aren't covered in this tutorial). After it does this it will say it failed, but you just need to run the command again now that the shaders were defined. After that, we've compiled our first gbxmodel! Open CMD In Chelan_1 Directory: Run Command and Assign Shaders: Run Command Again: Specifications: S3dpak - format - Imeta/ipak - format - Fmeta - format Programs: H2a-inflate - SuP Share this post Link to post Share on other sites