Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The .rig
file ("armature" or "skeleton") is what makes your mesh move in the game. You can find more information about that on the Meshes and Armatures: Rigging page.
Parts that require a .rig
file will not import the same. For example, the bumper’s 3D models are not positioned in-line with the body_01
object in blender. Bumpers are centered around the origin of the 3D space. The part is then lined up correctly with the .rig
file, which is linked in the .ent
file.
To model the front bumper, we’ll first export the base game bumper as .glb
, and import into our blender project. As you can see, the game model is positioned around the origin, unlike the custom bumper.
Move it with the move tool, so the corner of the bumper is at the origin and apply all transforms.
If you do not have the rig file already, you can now add it to the project. Open your vehicle’s .ent
file and open this path: RDTDataViewModel > components > deformation_rig > rig
Add the file to the project, and rename/move it.
Example: “boe6\mini_cooper\boe6_mini_cooper.rig
”
Update the .ent
rig path with the new file:
You can also update the .rig path in your vehicle’s .anims file, as well as the rig references here:
.ent file > RDTDataViewModel > resolvedDependencies > 0 > .anims file path
.ent file > RDTDataViewModel > components > vehicle_rig > animations > gameplay > 0 > animSet
.ent file > RDTDataViewModel > components > deformation_rig > animations > gameplay > 0 > animSet
Add it to your project, rename and move it as usual. Then in the .anims
file, set the rig path to the new one we just created:
Additionally update these paths to your .anims
file.
Open the .rig file and notice these 3 arrays:
These map all the position data of each .mesh
file.
boneNames
tells you which index value is each item, boneParentIndex
tells you what each bone’s parent is (example; wheel_back_left
is a child of suspension_back_left
. If you change suspension position, wheel will move with it.), and boneTransforms
is the positional and rotational values for each bone.
For a reference of where the bones are in a model, you can export the vehicle’s .anims
file to .glb
and import it into blender. You can select each bone to see their name and properties.
Example:
Your 0,0,0
position should be in the center of the vehicle. Here is the translation data for each of the suspension wheels of a vanilla car (porsche):
These are frontLeft
, frontRight
, backLeft
, and backRight
respectively. The Translation values are XYZ
values:
(-) x
= left of car, driver side
(+) x
= right of car, passenger side
(-) y
= back of car
(+) y
= front of car
(-) z
= bottom of car
(+) z
= top of car.
It may help to visualize the car as if from a top-down ariel view, left is -x
, right is +x
, up is +y
, down is -y
.
You’ll need to update the .mlmask
and .mlsetup
files in these .mesh
files as well, however they may show up at a different location. If they are not listed under “localMaterialBuffer
”, check under the “preloadLocalMaterialInstances
” array. The masks set should be in there instead.
Modify the existing X Y Z
values for the bumper, changing one value at a time to see the amount changed. I suggest starting with a value of +/- 0.1.
For moving parts, such as hoods and doors, we start by replacing the 3D model. Notice the rotation point in-game is a pivot along the origin in 3d space:
In my case, I have my hood aligned forward, as the axis should be further behind in the real vehicle.
Your part will not align at first. If it is a large distance, try to adjust the 3D model first. Keep in mind the pivot will be the origin, so only adjust in the axis you can edit without messing with how the part will move(left/right for hood/trunk, up/down for doors). Once it’s close, you can adjust the .rig
file as well to get it positioned correctly:
Swap the .mesh
’s .mlmask
and .mlsetup
to the same as your body_01
has set. (or to whatever other file you need)
You can also change how components are connected in the vehicle rig.
For components that don’t have their own movement or bones, they are attached to another component that does. This can be changed to attach a model to another model’s movement.
.app
file “RDTDataViewModel > appearances > 0 > components > entPhysicalMeshComponent > parentTransform > bindName
”
Example:
Components that do have their own bones are set to the bindName “vehicle_slots
”, and their slotName
is set to a boneName
value in the .rig
file.
Example of body_01
in .app
:
If a component is linked to another component, we cannot use the .rig
file to move it. Instead, in the .app
file is each component’s localTransform
. This can be used to change the position and orientation relative to the parent component.
Example:
Notice that the x,y,z position is saved as Bits
, instead of as a float
. To edit the positon data here, we need to convert from a float value to a fixed bit value.
The latest release of Wolvenkit nightly seems to do the conversion automatically for you now.
The code for this conversion was written by Loomy(Loomy#3375) on the modding discord, here.
This can be run in a python console:
int( ( n * pow(2,32) ) ) >> 15
Where “n” is a float value.
If you do not have python installed, you can try an online console, such as here. (paste the command into the “shell” side on the right, and hit enter)
Rigging wheels requires a 2nd .rig
file that is used for vehicle handling. It is referenced here:
.ent file > RDTDataViewModel > components > vehicle_rig > rig (path to wheelbase rig)
You can add this new rig to your project and rename/move it.
Notice that the new rig file only has wheel related bones:
This is the rig file that is referenced for vehicle wheel handling. It controls where the wheels/suspension are located. This file overwrites the values in the deformation_rig
created earlier.
To update the wheels, generally you want to modify the suspension bones. Since the wheel_front_left
, wingarm_front_left
, and break_front_left
are all parented to suspension_front_left
, updating the location for suspension also keeps the brakes and swingarms in the correct position relative to the wheel.
If the suspension values are updated/changed in the vehicle_rig
, the deformation_rig
may cause issues in some cases. To avoid this, rename the boneNames
in the deformation_rig
that are the same as the vehicle_rig
. This ensures that the vehicle only uses the vehicle_rig
values. Do not rename front wheel suspension in the deformation_rig
, as it will break wheel turning.
For the Mini Cooper, I edited all 4 suspension positions in the vehicle_rig
to update wheel positions, so I renamed the 2 front in the deformation_rig
(excluding the front, as described above):
To change the size of the wheel, you need to change both the 3D models and the rig files. You can update the wheels by first replacing all the wheel and tire meshes with ones to match your vehicle. This is similar to how the doors, windows, and hood work. Make sure to have the center of the wheel as the mesh’s origin. Example:
Once the wheel model is updated, you need to update the .rig
files.
In both the deformation_rig
and vehicle_rig
, find the wheel bones (wheel_back_left
, wheel_front_right
, etc.) and update the Scale
values.
Example:
Please note that this is a “bodge” solution, it’s not the proper way to set wheel sizes, but it works.
I go into as much detail as I can, but try to be familiar with the project explorer, asset browser, and other windows.
.ent
file is the base file of a vehicle. It contains all settings and child files.
.app
is the vehicle’s appearances settings.
.mesh
is a 3d file, used for vehicle body parts.
.xbm
are raw texture files.
.mlsetup
has settings for texture sets
.mlmask
is zipped mask texture/finish layers, normal maps, etc.
.inkatlas
contain reference texture information
.inkwidget
configures texture layering, position, & animations
.rig
has 3D information for how the .mesh
files are linked and move.
.yaml
files configure TweakDB items.
.json
files list string localization information.
.phys
is used to set vehicle collision/interaction bounds
Int/Integer : whole numbers
Float : fractional numbers, decimal places
String : sequence of characters
Boolean : true or false
Array : collection or list of items of the same data type
Nothing : “null”
Object/edit mode
Object management
Object edits
Joining and separating models
Know the difference between object origin, world origin, and the blender cursor
Must have support for .tga
files
Must have support for alpha channels
There are some python scripts and python commands to use.
Be able to edit and run a .py
script
Not necessary for most changes
Install these to your game before starting:
Have a 3D vehicle model ready to use for converting into cyberpunk.
Important features are details parts, doors, trunk, etc. and textures.
Higher face/vertice count is better. Modeled interiors are a must.
The proxy mesh can be created once the vehicle is complete or close to complete.
There are many ways of converting a high-res model to a low-res model, but for this guide the “Remesh” modifier in Blender will be used.
Set all the parts visible and positioned correctly relative to the body in Blender. In my case I also added the wheel shadow meshes, as the rim holes caused issues with remeshing details. Join all the objects into one and select the object. Example:
The Remesh Modifier is available in the properties menu, under modifier properties: It
It is recommended to save before adding or changing settings in the modifier, as unintended settings can crash blender fairly easily. Here are the settings to adjust in Remesh:
Try to create a final proxy mesh with a low amount of faces/triangles. The face current face count visible in blender can be seen in the top left of the viewer. Example:
Most use less than 2 thousand faces for a proxy mesh. You’ll also need to update the blender model to be correctly position, as the .rig
will modify it. Translate your model with the reverse values used to translate the initial proxy mesh.
Once the mesh is ready, a texture is needed. I recommend this guide for texture painting:
Once the texture is ready, you can export it from Blender under Image > Save As.. >
Save it as a .png
, and then import it into the project as an .xbm
In the proxy.mesh
, update the texture path:
.mesh > RDTDataViewModel > preloadLocalMaterialInstances > 0 values > baseColor
To import vehicles models from Wolvenkit into Blender, use THIS GUIDE .
This update method allows for import all components and rigs together as one model. I recommend following it before continuing with this guide, as it has more valuable information.
To add our models for the different parts, we’ll be looking mostly in the .app
file, under our main appearance.
Open the “AppearanceVisualController
” in the appearance’s item list. It should be the last item in the list. Then select the “meshProxy
” value.
Go ahead and add this mesh to the project by clicking the yellow arrow.
This mesh is used at distance, before your vehicle is loaded fully. We’ll be using it as a reference for our modeling in blender, as it is a low poly, complete model with wheels and all.
Open the Export Tool, under the Tools menu on the top of wkit.
Hit refresh to load all items, and select your proxy mesh you just added, then hit “Export Selected”. This should have created a .glb
and .json
file under the new “raw
” folder above the resources in the Project Explorer.
Example:
Open a new project in blender, delete the base cube. Hit File > Import > Cyberpunk GLTF
and load the proxymesh.glb
Your proxy mesh should now load in blender.
Example:
You can now import your source 3d models for your vehicle.
The proxy mesh will initially be positioned offset from other vanilla meshes. This is due to the vehicle’s .rig
file settings(will be discussed later).
Example showing the offset:
To get the exact offset, open the .rig
file located at this path in the .ent
file:
RDTDataViewModel > components > deformation_rig > rig
Open the boneNames
list and look for the index (number to the left) of “Base
”, in this case 2:
Then close boneNames
and open boneTransforms
. Open the same index value as “Base
” and look at the translation values:
(Values that are set at “_.___E-17
” are in scientific notation, and if the E
number is negative as they are here, the number is close to 0)
Look at the Z
value and noticee how it is 0.4399999
in the example. (~0.44) This is the number we will translate the proxy mesh by. Return to blender and select the proxymesh object. Translate it by the same value just found in the .rig
file by using the Transform Location
values in the Object Properties
menu: (positive to negative)
Repeat the translation for all objects in the proxymesh collection:
The proxy mesh can be used as a reference in blender for scale. Note the porsche is especially convenient, as it has real-world dimensions available online. If you don’t know your source car’s size, (length, wheelbase, width) You can compare in-game between it and the Porsche, then convert those numbers as appropriate.
Import the source 3D model for your mod into the same project.
Your model will likely be scaled incorrectly.
Find the correct scale of your vehicle in reference to the proxy mesh.
Example: A mini cooper has a wheelbase of 97.1”, and a porsche 911 has a wheelbase of 89.45”. So, Mini cooper wheelbase should be 8.55% longer in Blender once scaled correctly.
Fix positioning with the move, rotate, and scale tools. “Numpad 5” can be used for orthographic perspective, which is useful for comparing wheelbase accurately. I recommend matching the wheel bottoms at the same height, and matching the driver seat position as close as you can. This will save some steps later for poses.
Example with both rendered:
Apply all transformations to all objects in blender. This is required after any blender changes, if you skip this before exporting from Blender into WolvenKit, any positioning changes will not be saved.
Always Remember to apply all after modifying something in Blender.
Disable visibility on the proxy mesh for now, but leave it in the project as we’ll need it later.
Now we can setup the model so it can be converted into meshes for Cyberpunk.
Depending on your source model, you may need to either split or join your model into groups for different meshes in game. These “groups” are the components list/array in the .app
file.
Here’s a quick reference for the major groupings to look for:
2 tire models, one for font and back (left and right mirror the model)
2 wheel/rim models, see ↑
Body
Engine
Window front & window back
Chassis
Various lights, backleft, backright, body, reverse, break,
Wipers
Door left & door right, front/back
Window left & right, front/back
Hood
Trunk
Interior
Mirror
Steering wheel
License plate
Bumper front / back
May be more or less of different components. Depends on source model.
Make a backup of your blender project often while editing. I suggest keeping multiple copies as you work with your model. While splitting/joining objects you might not realize certain components need to be different until later on in the mod project, and an older project file will be very helpful.
I recommend creating “collections” or folders in blender, one for each component. Split and join the files as necessary to organize them together.
Example of Collection/Folder/Object structure in Blender:
For each component in the vehicle, you’ll want a separate collection to organize meshes together. Each mesh will need a separate object in Blender for each material layer.
Here are the major mesh groupings you will want in your project:
Split and join objects as needed to organize the Blender project structure.
Join objects by selecting multiple, and using Object > Join:
Now we’ll import our first mesh into Cyberpunk.
In wkit, open the .app
file and navigate to the default appearance. Open the components and find “body_01
” and expand it. Look for the “mesh
” value, and add it to your project.
Example:
Use the export tool as we did with the proxy mesh to convert it to a .glb
file.
Import this body.glb
file into the blender project.
Prepare your custom body mesh and ensure the replacement is one object. Join relevant objects together if needed.
Make sure your body mesh is less than 65,635 vertices
. If any .glb
file has more than this, the import into the game will fail.
You can check the face count in the top left of your blender window:
This number counts all visible objects in blender. Turning off an object’s visibility removes it from the count
As a general rule, keep the count low if you can to preserve performance in-game. Higher polygon count will increase quality, but decrease game performance.
Use the decimate modifier (or other methods) to reduce the face count if needed.
Example adding decimate modifier:
For simplicity, we’ll join all the parts of the body into one object for exporting. We can split them as submeshes later, when we want to indicate separate materials within a mesh.
With the body object selected, go to File > Export > Export Selection to GLB for Cyberpunk:
Save it to a new folder for your project’s .glb
files.
Copy the .glb
file into the folder with the original exported body mesh.
Copy the original file’s name, delete it, and rename your new part with the old file’s name.
Open the import tool in wkit, find the correct body .glb
and import it into the game.
Select the updated .mesh
file in the Project Explorer, and it will open in the File Information window. It should show your new mesh.
Example:
Rename your new .mesh
file to a project-specific name, and move it to a custom folder.
Example:
“boe6\mini_cooper\meshes\boe6_mini_cooper_body.mesh
”
Update your .app file with the path to the new body file. You’ll need to update it in 2 places:
RDTDataViewModel > appearances > 0 > components > body_01 > mesh
RDTDataViewModel > appearances > 0 > components > AppearanceVisualController > appearanceDependancy > body_01 > mesh
Test the mod in-game. It should look very wrong since we only replaced one mesh. Example:
Next, make all other visible components invisible while we’re modeling.
Easiest way to mark components as invisible is to break the entVisualControllerComponent
appearances path.
“RDTDataViewModel > appearances > 0 > components > entVisualControllerComponent > appearanceDependency > partname > mesh
”
I do this by renaming the file with an added “-disabled
” in the name. This breaks the file path, and notes that it is disabled for reference later. example:
TheSpliffz said : " Not sure if this is due to 2.0 but only adding '-disabled
' to the meshes name in the EntVisualControllerComponent
doesn't seem to work.
Adding '-disabled
' to "RDTDataViewModel > appearances > 0 > components > entMeshComponent/entPhysicalMeshComponent > meshname > mesh
" does seem to work. "
You will receive warning in the log when saving the .mesh if you use this method, be aware:
Save and test in-game. The renamed component should now not render in-game. Note that this only removes the visual mesh. The interactions still exist. Example:
Continue to change components until all except the modded body and wheels remain. Start with the major parts, bumpers, doors, etc. Test in-game frequently. Only disable parts that render in-game.
Once you have disabled all the other components, you can see your model clearly and notice any initial problems. Expect the textures to be broken. Opposite sides may not render as we still need to add an interior. Example:
Some model issues may show themselves at this point. Check out the “Fixing Body Glitches” section of this document below.
You can use the body_01
instructions for creating most non-moving parts. (engine, trim, chassis, etc)
For the non-moving windows, we’ll start by enabling the mesh in the entVisualController
, removing the “-disabled
”. Then we can add the mesh to our project. Move/rename is appropriate.
Example:
“boe6\mini_cooper\meshes\boe6_mini_cooper_window_f.mesh
”
Update the .app
file with both .mesh
paths for the component.
Export it to .glb
, replace it with your model’s window, and import it back.
Save and Test.
Repeat for each non-moving window. (door windows are done after doors)
Similar materials can be copy/pasted as meshes, and then import/exported, and entered into the .app
file. This is instead of importing from the original car that is being mirrored. This saves time on moving files.
Save and test.
To add a new component instead of replacing a default one, you can duplicate the entVisualControllerDependency
of the most similar component by right-clicking and selecting “Duplicate Item in Array/Buffer
”.
Example:
Edit the new component’s “componentName
”, here I use “body_02
”, as it is for exterior trim bodywork.
Edit the “mesh
” value to the correct new .mesh
file.
Example:
“boe6\mini_cooper\meshes\boe6_mini_cooper_body_trim.mesh
”
Duplicate the entPhysicalMeshComponent
of the part you are copying. Rename it with the “name
” value to the one you used earlier, (body_02
). Set the “mesh
” value to the same mesh path.
Example:
Start to finish guide to add a standalone vehicle, in steps that are as specific as I can be.
In this guide I’ll be bringing a Mini Cooper into Cyberpunk 2077. All methods should translate to whatever vehicle you add. The guide assumes you’ve generally followed along in order. The later steps will skip basic info covered in previous steps, unless its written otherwise.
If at any point you get stuck & have questions, DM me on discord @boe6, or ask in one of the MODDING sections of the Cyberpunk 2077 Modding Discord. https://discord.gg/Epkq79kd96
If you discover info or additional details that you figured out during this guide, please right-click and add a comment in the original document so the guide can be updated! (do not ask questions in comments, use discord please)
This guide may not cover all 2.0 changes. Most everything should be correct, let me know if you find any issues.
For the visual learners among us, you can find a youtube video series by boe6 here:
Interaction collider .phys files control the physics size for the vehicle. This controls how it hits/collides with walls, players, etc.
Add the .phys
file to your project, rename, and move the file as appropriate. It is linked through the .ent
file.
Path:
.ent file > RDTDataViewModel > components > chassis > collisionResource
Convert the .phys
to a JSON
file:
Now you’ll need 2 python scripts created by “The Magnificent Doctor Presto!”. They can be downloaded on github here:
https://github.com/DoctorPresto/Cyberpunk-Helper-Scripts
Download both export_phys.py and import_.phys.py
In Blender, open the “Scripting” workspace:
At the top of the text editor that just openned, use the folder icon to find the importing .py
file we just downloaded.
This should open the .py
file into the text editor. It should look like this:
Edit the “physJsonPath
” value to the converted phys.json
file.
Example:
Once you’ve run the script, you should have vertices that look close to the outline of the original car model. Notice the outline similar to the porsche:
.phys
files don’t like complex meshes, so they use only vertices without faces or edges. Each “submesh” is a small object shape, with no concave angles. Each submesh is then joined to create the overall collision mesh.
Switch back to the Layout workspace.
The easiest way to edit these in blender is to enable your vehicle’s body mesh, is to switch to Wireframe shading, by holding Z, and moving your mouse to “Wireframe”. Example:
This will allow you to see your body mesh, but also see vertices behind and around it. Example:
Once done editing, select all the vertices objects and run the export_phys.py, similar to the import script.
The .phys
file should now be finished. Import from json
, update path references, and test in-game. Make sure to update the physJsonPath
again, as this is the path it will save the new .json
to.
Once the script has been run, you should have a new file with the “new_
” prefix added in the same folder as the phys.json
.
Example:
This file can now be converted back from json and used in game. Example:
/ Wolvenkit resources plugin (View Options > plugins to install)
Photoshop (), , , and are good options
(required, without it you won't be able to load Vehicle tweak at all)
(unknown if required after 2077 version 2.0+)
is one great option for finding models, but is also useful.
Published: Nov 5, 2023 by Meta Pixel Last documented edit: Oct 15 2024 by manavortex
This guide is part of Boe6's Guide: new car from A to Z and covers the material part of it.
By default, cars use the multilayered shader. You can find guides about editing multilayered material linked at the top of the documenation page.
To learn more about materials, you can browse Cheat sheet: Materials and its sub-pages.
.mlmask
, .mlmaskset
& .masklist
To fix the odd textures that appear after importing your custom models, we have to edit the .mlmask
layers.
Find the .mlmask
corresponding file by opening a .mesh
in wkit to edit. Go to the path:
RDTDataViewModel > localMaterialBuffer > materials > 0 (...maskset) > values > 0 > value
Add the .mlmask
to the project.
Rename and move the .mlmask
file into your project filepath.
Example:
“boe6\mini_cooper\meshes\textures\boe6_mini_cooper_exterior_maskset.mlmask”
Export the .mlmask
file. It should result in a .masklist
file and a folder with .png
files inside:
Notice the first white image, and the remaining black images with white cutouts.
These textures don’t map onto the new vehicle’s mesh correctly. These can be edited to add more detail to your model.
As a temporary solution, we can edit the first image to be pure white, and the rest to be pure black. Example:
Import the .masklist
file
Update your .mesh
file with the new .mlmask
name/path file:
RDTDataViewModel > localMaterialBuffer > materials > 0 (...maskset) > values > 0 > value
Your vehicle should now be much smoother.
Note that you will need every .mesh file to have a corrected .mlmask path.
.mlsetup
& MLsetupBuilderTo change paint color, we need to edit the .mlsetup
file.
You will need the MLsetupBuilder plugin for editing these files. Install it in wkit:
HOME button (top left) > Plugins (left list) > MLsetupBuilder, right side, install.
Once installed, hit open. It will open a folder with a “MlsetupBuilder.exe” executable. Run it to open the program.
The .mlsetup
file we need is linked in the .mesh
file, similar to the .mlmask
:
RDTDataViewModel > localMaterialBuffer > materials > 0 / masksset > values > MultilayerSetup > Value
Add this .mlsetup
file to the project. Rename and move it.
Example:
“boe6\mini_cooper\meshes\textures\boe6_mini_cooper_exterior.mlsetup
”
Convert the .mlsetup
file into .json
by right clicking:
Open MlsetupBuilder.
Import the .mlsetup.json
file by hitting the arrow in the top left:
You can also right-click on the .mlsetup.json file and choose "Open in MlSetupbuilder". The file will be automatically loaded when it opens.
Once you open the file, a window will appear on the left with a list of materials. These are the texture layers of your mesh.
Note that layers 0,1,2,etc are linked the .mlmask layers.
At the top is a large orange button titled “Import the Multilayer Setup >>”. Click it to load the .mlsetup
file into the editor. It should populate the Layers list:
Now, assuming you created a .mlmask
file similar to our previous steps, with all but 1 black image (see below), we know only the first layer, Layer 0, is the only one that will currently render on our .mesh
Since Layer 0 is the visible layer, select it and it will load in the Material view:
This is where we edit the layer. If you only want to change the color to a common one, choose one from the lower color palette. Here I have chosen blue:
You can also change to another material texture here by clicking the preview ball:
This can be used to create different paint finishes, cloth texture, etc.
Once you have finished editing a layer, you can save it by clicking “Apply edits” at the top of the Layers panel:
Then you can select another layer and edit the next one if needed. If you select a new layer without applying the edits, the changes will be lost.
Once finished, you can Export to save it to your file explorer, and then load it in wkit by right clicking the .json
and selecting “convert from JSON”.
Example:
Save and Test in game
Working color:
Custom RGB value colors can be set with a custom .mltemplate
file. Here we will only set RGB values, but this file can control other material settings/textures as well.
Find the material you want to have a custom RGB value for in MlsetupBuilder, and click on the material name to show it’s file path. Example:
Add that file to the project, rename, and move it. Once it’s in place, you can copy it’s relative path and paste it into MlsetupBuilder for that layer:
Open the .mltemplate
file in wkit and navigate to the colorScale
array:
RDTDataViewModel > overrides > colorScale
This array contains all colors in the material. Open one of the Multilayers
and it’s “v
” values, which control the RGB values:
First, you can verify the color in . Copy the “n
” value here, and paste it into MlsetupBuilder in the Color filter:
Select the color, and it’s rgb values should match the values in the “v
” colorScale
in the .mltemplate
:
Edit the 0,1,2 (R,G,B) values to the color values needed and save. Make sure to save the .mlsetup as well with the layer set to the same color code as before.(“n” value, [00cf56_69039f])
Save and test.
To have multiple materials in a single .mesh file, the .glb export requires separate submeshes all selected in blender. Separate your blender .mesh into parts, and group them based on material.
First separate/split your meshes into small components, and then join them into groups:
For example, mine are grouped by body paint, silver trim, reflective black, matte black, and grey fabric. Take note, the order in your blender selection will be the order each submesh is called by the .mesh
file settings. This order is important.
With all the objects selected in blender, export it to .glb
and import it as you normally would.
You can save and test. If it worked properly, only the first object included in the blender export will render properly at the moment.
Example of a finished body mesh in blender:
Currently the other submeshes will not render properly. This is due to submesh materials being controlled by the chunkMaterials in your appearance settings (.app
file).
To correct this, start by duplicating an item in the chunkMaterials
list. Path:
.mesh > RDTDataViewModel > appearances > 0 > chunkMaterials
Make sure to edit the name to a unique name, as we are creating new materialEntries
. Repeat as needed. In my case I needed 6 extra layers:
Next, navigate to RDTDataViewModel > materialEntries
This list controls the names and index of each item in the localMaterialBuffer
, which we’ll edit soon. You’ll want to duplicate an item with similar qualities. If you are adding a plastic material, duplicate another plastic or solid material in the list. If you are adding glass, duplicate from a vehicle_lights
material, then edit as needed. Duplicate one for each new material.
Make sure to update the index values of each item in the materialEntries array. They must all be the same as their index in their current array. 4 to 4, and so on:
ALL items in the list update the index of both new items, and old ones that moved down the list
Next we’ll update the materialBuffer
with new .mlsetup
and .mlmask
files. Keep in mind the .mlmask
files can be edited to match the model to a texture. However we’ll be working around that by using the same method used previously, to have a .mlmask
file with one additional white layer.
Note the 0 layer will always be white.
Example:
Notice how I have a .mlmask
file dedicated to the 4th layer, so all other layers are muted. I have 20 (0 through 19) unique .mlmask
files, each selecting a different layer from a .mlsetup
file.
Speaking of .mlsetup
, I have created a .mlsetup
file with MlsetupBuilder. Layers 0 through 7 are used for the new materials:
Now to finish the materials setup, open the following .mesh
path:
.mesh > RDTDataViewModel > localMaterialBuffer > materials
This array contains every CMaterialInstance
for the .mesh
file. This array has it’s items named via the materialEntries
list we just edited. Since we added items to that list, those names now show in this localMaterialBuffer > materials
list. However the data in each item is still it’s original.
For example, in this picture, the array hasn’t been updated yet, however the names are updated. This means the index 1 item, …”masksset_texture
” has the properties of “reflector
”, which would normally be the 2nd item.
To fix this, duplicate the appropriate items, similar to before, once for each new material. Once done, the previous index 1 item will now be higher, but matched correctly. In my files, I duplicated “ml_v_sport2_porsche_911turbo_exterior_masksset
” 6 times, and they each pasted directly below the 1st.
You can tell if the materials are correct by opening them, and looking into the “values
” array. Each will have similar keyValuePairs
related to the material type. Glass
mentions GlassSpecular
, normal paint has many map layers, stickers dont have much, etc:
For each new material layer, update the paths:
CMaterialInstance > values > MultilayerMask > value
CMaterialInstance > values > MultilayerSetup > value
For mlsetup
, I use the previously mentioned file, with layers setup for individual materials.
For the mlmask
, use the “masksset_00
” for the layer you want to enable.
Submeshes should now load in order with matched materials.
Editing UV maps may be necessary for some meshes if they do not display correctly, or for custom editing. Broken & Fixed UV map example:
To edit UV maps in blender, select your object to modify and enter the UV Editing workspace:
The current UV map should display on the left:
In the right window in Edit Mode, select all vertices (“a” key in blender), and hit “U” for the UV mapping dialog. Select “Smart UV Project”, and hit OK:
This should update the UV mapping to an even spread map:
Save and test. Your meshes should have even material mapping now.
Some objects are better with different UV projection options. For example, a tire can be cleanly mapped by using the orthographic view and selecting Sphere Projection. Try some of these options to see what fits best for your use case.
Lights are still somewhat of a mystery to me. That said, there are a couple routes to take for lights, depending on how you would like them to look.
Lights are using emissive (glowing) and glass materials. For more documentation about that, you can check Material properties.
Many lights, such as the headlights on the porsche, are reflective lights, with headlight lenses. These lenses require lots of lighting settings, such as IOR
, RefractionDepth
, FresnelBias
, and more.
Example:
The other common option, is to use solid lights, as many modded cars do. These lights avoid using the complex light options, and instead opt to use block-style lights. These are done by creating a custom mesh, setting it as a light material, and covering it with blank normal map lenses or glass. (IOR=1.0 & RefractionDepth<0.2) Example:
Here is an explanation of some light options, based on my own experience. Note that these values are not fully understood currently. If you learn something about these values, please share!
IOR
: “Index of Refraction”. This seems to be an on/off switch for enabling refraction. Values greater than 1 enable refraction.
RefractionDepth
FresnelBias
: Unknown. (does nothing?)
NormalStrength
: Strength of normal map on the mesh
NormalMapAffectsSpecular
: Strength of normal map on reflected light
Normal
: Path to normal map
GlassRoughnessBias
: n/a
BlurRadius
: n/a
For the emitted light beam, there are “vehicleLightComponent
”s in the .app
file components list. The localTransform
can be edited by the position xyz
bit values. Orientation will control which direction the light is aimed.
Example LightComponent
localTransform values:
To create a new light in a mesh that doesn’t have one already, you can duplicate the material in the mesh settings. Make sure to update the localMaterialBuffer
or preloadLocalMaterialInstances
, materialEntries
, and appearance chunkMaterials
.
See:
Once the vehicle_lights material is linked in the mesh, it also need to be linked to a vehicleLightComponent
in the .app
file. You can use an existing lightComponent
or duplicate a new one. The component has a parentTransform
entry, and a bindName
value which is used to set what mesh it is a part of.
Example:
For lights like brakes, headlights, or reverse lights - you need to edit the vertex paint in Blender. Select the light emitting object in blender and switch to "Vertex Paint" mode. Example:
Set the color to one that enables the brake behavior, for brakes this is red in hex:
You must use these specific hex colors for lights to be activated properly:
Headlights: #7C0101
Taillights: #e7010
Reverse lights: #cb0000
Use the Draw tool in Vertex Paint mode to draw on the color to the entire part. Example:
Lights should now be fully working.
Headlight colors are controlled in your vehicle's tweak file. You need to add this entry to your main Vehicle
record:
The values are RGBA respectively so the above changes the headlight color to blue
Adjusting the tweak file from the previous section, here's how it should all look like:
This page will show you how to create the base files that will tell your game about the new car.
Make sure you installed TweakXL.
.yaml
fileThis file contains the which will register your car with the game's database.
After creation, you can find it in your Wolvenkit project's tab.
Create a new tweakXL file by going to “New File” in the top left of wkit, just next to the HOME button.
Select TweakDB and TweakXL file. Name it something specific to your mod.
example: “boe6_mini_cooper.yaml
”
Open the .yaml
file in your favorite text editor. I used notepad++.
Create a new tweak entry for your model.
$base
:This should be set to the most similar in-game vehicle to your project. This is the tweak record that your car will mirror unless you set your own. You can find tweak names in the wKit tweak browser, search for the source car in the search bar on top. Look for Vehicle.v_NAME
, it’s first entry should be “gamedataVehicle_Record
”
example: “Vehicle.v_sport2_porsche_911turbo
”
appearanceName
:Needs to be set to the appearance name in the vehicle’s .ent
file. The .ent
file can be found inside your source vehicle’s tweak records. Locate the vehicle’s tweaks like before, Vehicle.v_sport2_porsche_911turbo
for example, and scroll down for an entry titled “entityTemplatePath
”. It should have an entry similar to this:
“Base\vehicles\sport\v_sport2_porsche_911turbo__basic_01.ent
”
displayName:
Set with your json
file below.
player_audio_resource
:This line is not necessary yet. It can be swapped for another vehicle’s engine sound later with whichever sounds closest to your desired vehicle.
entityTemplatePath
:This is the file we just added in the appearanceName
step earlier. To easily get this: in the project explorer, right click on the file and hit rename, or press F2. In the open window you can copy the path starting at base/…
You can also copy the relative path by right clicking the file and selecting “copy relative path”. Now you can paste it into the .yaml
entry.
Add your new vehicle tweak to the vehicle_list
tweak, so the game can find it.
Note the 2 spaces, followed by a dash, followed by another space, then the !entry
. Syntax is very important for .yaml
files
.json
fileThis file contains the translation strings, such as your car's name and description.
Create a .json
file in your project, the same as creating the .yaml
. The option is about half way down the “CR2W Files” category. Name it the same as your vehicle (e.g. “boe6_mini_cooper.json
”)
You’ll want to create your own project path at this point. With your mouse over the new .json
file, on the right side hit the yellow “open in explorer” button to find the .json
file in your file explorer, you should see just your .json
file and a “base
” folder. Create a new folder/path for your project files here. I created “boe6/mini_cooper/
”. Now in wkit, move your .json
into the new folder.
Your project file structure should now be similar to this:\
Open the .json
in wKit by double clicking.
Under RDTDataViewModel
, click on “root
” : handle:ISerializable
.
“root.root
” will appear on the right side. Next to handle:ISerializable
, click the yellow “Create Handle” button.
In the window that opens, click on the bottom text box to type in the following:
“localizationPersistenceOnScreenEntries
”
You can use the autofill. Click “create”
Notice that you have to manually save items in this window. Ctrl+S works. Same rule applies for .ent
files, .app
files, and any other files edited directly in wkit.
Now under RDTDataViewModel
, “root
” is expandable. Click on the entries array under “root
”.
Now on the right side, click “Create Item In Array”
Now we'll customize the new entry. Expand the item options and complete it to these values:
“primaryKey
” can be left at 0
, and “maleVarient
” can be left blank.
“secondaryKey
” is what your .yaml
is referencing. This is the name given that will link to the .yaml
.
Example: “boe6_mini_cooper_name
”
“femaleVariant
” is the actual display string. In this case, the vehicle’s name as it should be shown in the menus. Example: “Mini Cooper S
”
Create 2 more entries in the array by right clicking the first array entry we just created, and hit “duplicate item in array/buffer” as shown:\
Swap the 2nd and 3rd string values for your vehicle’s year
and description
text.
example:
2nd:
secondaryKey: boe6_mini_cooper_info
femaleVariant: fancy description
3rd:
secondaryKey: boe6_mini_cooper_year
femaleVarient: 2003
\
Final .json
should look similar this:
Return to your .yaml
file and make sure your vehicle’s “displayName
” is your secondaryKey
entry. See earlier .yaml
screenshot.
At this point you can test your mod to see if it loads in-game correctly. In general, you’ll want to launch the game and test as often as you can. I recommend changing one file at a time and testing each along the way to easily diagnose issues.
In wKit, at the end of the same line as “New File”, there is an “Install” button. For ease of testing, click the down arrow to show options and switch to “Install and Launch”. Now press “Install and Launch” to test the mod in-game.
Command Example:
It should show up as “TEST” in the vehicle call menu, as we haven't linked the json file to our mod yet. Once you call it, it should drive up with the model you are mirroring.
If at any point the result is not the one expected you can find the TweakXL log in `(Game Dir)\red4ext\plugins\TweakXL` and the ArchiveXL log in `(Game Dir)\red4ext\plugins\ArchiveXL`. It may not tell you what's wrong in great detail, but it will help you narrow down and fix the issue, or verify that there is none.
If the command does not add your vehicle to the vehicle call list, check if the Tweak Records
have been saved correctly. To do this, open the TweakDB Editor in the CET overlay. Search for your vehicle’s name, and look for the Vehicle.name
Record.
Note that the vehicle’s scan details will not be correct yet. The vehicle model and description will display as loading.
Move your source vehicle’s .ent
file into the same file path as your .json
file. Copy the file’s new path starting after “archive/…
”, and update your .yaml
tweak record so entityTemplatePath
is showing your new path.
Example:
Save the file, and test again by using the Install and launch button. Load a save from before you’ve used the summon command in CET console.
Rename the .ent
file and update the tweak in .yaml
, like last step.
Example:
“boe6\mini_cooper\boe6_mini_cooper_basic.ent
”
Now we’ll clean up the .ent
file. Open it in wkit by double clicking. Under “RDTDataViewModel
”, open the “appearances
” array.
Find the appearance you’re currently mirroring and make note of it. Then select all the other appearances with ctrl+click, then right click and hit “Delete Selection in Array/Buffer”. This will leave you with one appearance. We’ll duplicate this later when we get to adding different paint colors.
Edit the “name
” value to edit the array item. In my case, I change it from “porsche_911turbo__basic_johnny
” to “boe6_mini_cooper_basic
”
Also update your .yaml
tweak to this for the appearanceName
value.
Save, Install and Launch, test that it still works.
.app
fileAdd the .app
file to your project. Find it by navigating to the appearanceResource
in your main appearance, which links to an .app
file. Hit the yellow “Add File to Mod” button.
You’ll want to clean the appearances from this file as well. In the .ent
file, note the appearanceName
value. Then look at the .app
file for the matching item in the list. That is the appearance we want to keep. The other appearances can be deleted as you did with the .ent
file.
Now we can edit the appearanceName to an appropriate value related to our car.
Example:
And update it in your .app
file as well in the “name
” value:
Save and test. Get in the habit of testing often!
Notice the “components
” list inside the appearance settings. These are the main parts of your vehicle, and all 3D model parts are referenced through here, with a .mesh
file.
Move your .app
file and rename it to a relevant name.
Example:
“boe6\mini_cooper\boe6_mini_cooper.app
”
Update your .ent
file so the appearanceResource
value matches the new file name & path.
Install & Test.
Open up your .yaml file.
We’ll start with adding a logo record for the vehicle’s brand/manufacturer. Add a UIIcon
Tweak Record, with a $type: UIIcon_Record
, atlasPartName
, and atlasResourcePath
.
Example:
\
Copy the part name and path from your mirror car’s UIIcon_Record
Tweak, which you can find in the tweak browser in wKit:
We’ll update these to custom file names/paths soon.
Next create a Tweak in the .yaml
for the vehicle’s brand. This needs $type: VehicleManufacturer_Record
, and an enumName
.
Example:
Now we need a gui data Tweak Record for our vehicle, with $type: VehicleUIData
, productionYear
, and info: LocKey#[vehicle]_info
.
Example:
The LocKey# references your entry in the .json
file.
\
Now we create a UIIcon Record
for the vehicle’s image in the call menu, titled vehicle_icon
or similar.
Example:
Now these items can be referenced in the main vehicle tweak record. Add:
icon: UIIcon.[your_vehicle]_icon
manufacturer: Vehicle.[brand]
Example:
\
Add Virtual Car Dealer Tweak Values. Main settings are dealerPrice
, dealerCred
, dealerAtlasPath
, and dealerPartName
. We’ll just do the first 2 for now until we create the images for Virtual Car Dealer. These are added to you main vehicle.
Example:
Note that Tweak record order is important. Those that are referenced by another record need to be defined earlier in the document.
Recommended order:
UIIcon.Brand_Logo:
Vehicle.Brand:
Vehicle.vehicle_data:
UIIcon.vehicle_icon:
Vehicle.vehicle:
Vehicle.vehicle.[dealer settings]
Vehicle.vehicle_list.list:
Example of currently finished .yaml
:
.xl
fileNow we will add our .xl
file.
This file lets the game know to use our .json
file as localization.
Create a new file in wkit as done before. Under the ArchiveXL category, select “ArchiveXL file”. It should automatically open in your default text editor. Edit it with just 3 lines, a file structure for the .json
file.
Example:
Save and test.
The vehicle’s call menu should now show the vehicle’s name as specified in the .json
, as well as the description info text.
Rename your .xl
file to something appropriate. Files can cause issues if you use the same file name as another mod. Example:
“resources\boe6_mini_cooper.xl
”
Note that any/all .xl
and .yaml
files in the resources folder of your project will automatically load in-game.
\
After creation, you can find it in your Wolvenkit project's tab.
Once in-game, you can use the console to add the vehicle to your inventory. Swap “boe6_mini_cooper
” for your vehicle’s Tweak Record.
This file contains your car's components for the individual appearances. You can read up about at the link.