mirror of
https://github.com/ApfelTeeSaft/lightspeed64.git
synced 2026-08-26 19:33:24 +00:00
Armatures can now be scaled without breaking geolayouts. Updated README and some error messages.
This commit is contained in:
@@ -37,6 +37,15 @@ Thanks to anonymous_moose, Cheezepin, Rovert, and especially InTheBeef for testi
|
||||
### Installation
|
||||
Unzip and drag the entire folder into your blender addons folder (usually at C:\Program Files\Blender Foundation\Blender\2.80\scripts\addons). Note that you must drag the ENTIRE folder, not just the 'fast64_internal' folder. Then in Blender, go to Edit -> Preferences -> Add-Ons and find/check the 'Fast64' plugin. If it does not show up, go to Edit -> Preferences -> Save&Load and make sure 'Auto Run Python Scripts' is enabled.
|
||||
|
||||
### F3D Materials
|
||||
Any exported mesh must use an F3D Material, which can be added by the 'Create F3D Material' button in the material inspector window. You CANNOT use regular blender materials, and you must remove any blender materials / empty materials slots from any mesh.
|
||||
|
||||
### ROM File Settings
|
||||
When importing from a ROM, the plugin will import from the ROM at filepath 'Import ROM', When exporting to a ROM, the plugin will make a copy of the file at 'Export ROM', modify it, and save the file to 'Output ROM'. The ROM must be expanded.
|
||||
|
||||
### Where Can I Export To?
|
||||
By default, when exporting to ROM, the plugin will copy the contents of bank 4 to the range (0x11A35B8 - 0x11FFF00). This will leave you with free space to export assets to range (0x11D8930 - 0x11FFF00).
|
||||
|
||||
### Tool Locations
|
||||
The tools can be found in the properties sidebar under the 'Tools' tab (toggled by pressing N).
|
||||
The F3D material inspector can be found in the properties editor under the material tab.
|
||||
@@ -48,6 +57,75 @@ The RDP default settings can be found in the properties editor under the world t
|
||||
### C Exporting
|
||||
When exporting data to C, a folder will be created (if it does not yet exist) and will be named after the object/armature it is based off of. The C files will be saved within this new folder. Any previous C files of the same name will be overwritten.
|
||||
|
||||
### Vertex Colors
|
||||
To use vertex colors, select the "Vertex Colored Texture" preset and add two vertex color layers to your mesh named 'Col' and 'Alpha'. The alpha layer will use the greyscale value of the vertex color to determine alpha.
|
||||
|
||||
### RDP State Optimization
|
||||
A material will not set every single geometry mode / other mode option. Instead, each property will be checked against the default settings located in the world tab in the properties sidebar. If the values are the same, then the code to change it is not added.
|
||||
|
||||
### Geolayouts (Armature)
|
||||
There are many different geolayout node types. In Blender, each node type is represented by a bone group. Imported geolayouts will already have these bone groups, but if you want to add them to your own armature use the 'Add Bone Groups' operator in the SM64 Armature Tools header. All regular bones (aka 0x13 commands) and 0x15 command bones are placed on armature layer 0. All other geolayout commands are placed on layer 1. Metarig generated bones are placed on layers 3 and 4 (see 'Animating Existing Geolayouts'). If you change a bone's geolayout command type and it dissapears, it might have been moved to a different layer. Make sure to go to the armature properties editor and set both layers 0 and 1 to be visible. Geolayout command types can be edited in the properties editor under the bone tab in pose mode.
|
||||
|
||||
### Geolayouts (Object)
|
||||
Alternatively, for simple static geolayouts you can export object hierarchies. Geolayout properties such as draw layer can be located in the object properties tab.
|
||||
|
||||
### Exporting Geolayouts and Skinned Meshes
|
||||
The N64 supports binary skinning, meaning each vertex will be influenced by one bone only. When skinning an exported geolayout, do NOT use automatic skinning, as this results in a smooth weight falloff. Instead, when weight painting set the weight to either 1 or 0, and set the brush Falloff to square. Skinning can only occur between an immediate parent and a child deform bone, not between siblings / across ancestors.
|
||||
|
||||
### Importing/Exporting SM64 Geolayouts
|
||||
Download these documents:
|
||||
|
||||
[SM64MainLevelScripts.txt](http://qubedstudios.rustedlogic.net/SM64MainLevelScripts.txt)
|
||||
|
||||
[SM64GeoLayoutPtrsByLevels.txt](http://qubedstudios.rustedlogic.net/SM64GeoLayoutPtrsByLevels.txt)
|
||||
|
||||
For importing/exporting geolayouts:
|
||||
|
||||
- In SM64GeoLayoutPtrsByLevels.txt, search the name of the model.
|
||||
- There you can get the modelID (Obj) and geolayout start (ROM Address start + offset)
|
||||
- Note that these are decimal values, and must be converted to hex when used as inputs for fast64.
|
||||
- In SM64MainLevelScripts, search '22 08 00 MM' where MM = modelID.
|
||||
- There may be multiple instances, in which case you must use the offset field from before and check if it matches the last 3 bytes of the line.
|
||||
- There you can get the level command, which is the first number before the slash on that line.
|
||||
|
||||
Plug these values into the SM64 Geolayout Exporter/Importer panels.
|
||||
|
||||
### Replacing Existing SM64 Geolayout Geometry
|
||||
SM64 geolayouts are often in strange rest poses, which makes it hard to modify their geometry. It often helps to import an animation belonging to that geolayout to see what the idle pose of a geolayout should be. Once you know, you can rotate the bones of the armature in pose mode to a usable position and then use the 'Apply as Rest Pose' operator under the SM64 Armature Tools header. Skin your new mesh to that armature, then rotate the bones back to the original position and use 'Apply as Rest Pose' again. You can now export the geolayout to SM64 and it will be able to use existing animations.
|
||||
|
||||
### Importing/Exporting SM64 Animations (Not Mario)
|
||||
|
||||
- Download Quad64, open the desired level, and go to Misc -> Script Dumps.
|
||||
- Go to the objects header, find the object you want, and view the Behaviour Script tab.
|
||||
- For most models with animation, you can will see a 27 command, and optionally a 28 command.
|
||||
|
||||
For importing:
|
||||
- The last 4 bytes of the 27 command will be the animation list pointer.
|
||||
- Make sure 'Is DMA Animation' is unchecked, 'Is Anim List' is checked, and 'Is Segmented Pointer' is checked.
|
||||
- Set the animation importer start address as those 4 bytes.
|
||||
- If a 28 command exists, then the second byte will be the anim list index.
|
||||
- Otherwise, the anim list index is usually 0.
|
||||
|
||||
For exporting:
|
||||
- Copy the addresses of the 27 command, which is the first number before the slash on that line.
|
||||
- Optionally do the same for the 28 command, which may not exist.
|
||||
|
||||
Select an armature for the animation, and press 'Import/Export animation'. Note that the armature's root 0x13 (i.e. regular) bone must be named 'root'.
|
||||
|
||||
### Importing/Exporting Mario Animations
|
||||
Mario animations use a DMA table, which contains 8 byte entries of (offset from table start, animation size). Documentation about this table is here:
|
||||
https://dudaw.webs.com/sm64docs/sm64_marios_animation_table.txt.
|
||||
Basically, Mario's DMA table starts at 0x4EC000. There is an 8 byte header, and then the animation entries afterward. Thus the 'climb up ledge' DMA entry is at 0x4EC008. The first 4 bytes at that address indicate the offset from 0x4EC000 at which the actual animation exists. Thus the 'climb up ledge' animation address is at 0x4EC690. Using this table you can find animations you want to overwrite. Make sure the 'Is DMA Animation' option is checked and 'Is Segmented Pointer' is unchecked when importing/exporting.
|
||||
|
||||
### Animating Existing Geolayouts
|
||||
Often times it is hard to rig an existing SM64 geolayout, as there are many intermediate non-deform bones and bones don't point to their children. To make this easier you can use the 'Create Animatable Metarig' operator in the SM64 Armature Tools header. This will generate a metarig which can be used with IK. The metarig bones will be placed on armature layers 3 and 4.
|
||||
|
||||
### Exporting Geolayouts to C
|
||||
To replace an actor model in decomp, replace its geo.inc.c and model.inc.c contents with the geolayout file and the dl file respectively. Use the contents of the header file to replace existing extern declarations in one of the group header files (ex. mario is in group0.h). Make sure that the name of your geolayout is the same the name of the geolayout you're replacing.
|
||||
|
||||
### Switch Statements
|
||||
To add a switch mesh node, duplicate your switch bone and move it off to the side. Set the bone geolayout command to be Switch Option. Any nodes in this switch option must be children of this bone. Add any other bones to this bone. Add your switch geometry into your existing mesh in the correct position and skin it.
|
||||
|
||||
### Insertable Binary Exporting
|
||||
Insertable Binary exporting will generate a binary file, with a header containing metadata about pointer locations. It is formatted as such:
|
||||
|
||||
@@ -77,79 +155,6 @@ To resolve pointer addresses, for each pointer address,
|
||||
### Decomp vs Homebrew Compatibility
|
||||
There may occur cases where code is formatted differently based on the code use case. In the tools panel under the SM64 File Settings subheader, you can toggle decomp compatibility.
|
||||
|
||||
### ROM File Settings
|
||||
When importing from a ROM, the plugin will import from the ROM at filepath 'Import ROM', When exporting to a ROM, the plugin will make a copy of the file at 'Export ROM', modify it, and save the file to 'Output ROM'. The ROM must be expanded.
|
||||
|
||||
### Where Can I Export To?
|
||||
By default, when exporting to ROM, the plugin will copy the contents of bank 4 to the range (0x11A35B8 - 0x11FFF00). This will leave you with free space to export assets to range (0x11D8930 - 0x11FFF00).
|
||||
|
||||
### Vertex Colors
|
||||
To use vertex colors, select the "Vertex Colored Texture" preset and add two vertex color layers to your mesh named 'Col' and 'Alpha'. The alpha layer will use the greyscale value of the vertex color to determine alpha.
|
||||
|
||||
### F3D Materials
|
||||
Any exported meshes must have an F3D Material, which can be added by the 'Create F3D Material' button in the material inspector window.
|
||||
|
||||
### RDP State Optimization
|
||||
A material will not set every single geometry mode / other mode option. Instead, each property will be checked against the default settings located in the world tab in the properties sidebar. If the values are the same, then the code to change it is not added.
|
||||
|
||||
### Geolayouts (Armature)
|
||||
There are many different geolayout node types. In Blender, each node type is represented by a bone group. Imported geolayouts will already have these bone groups, but if you want to add them to your own armature use the 'Add Bone Groups' operator in the SM64 Armature Tools header. All regular bones (aka 0x13 commands) and 0x15 command bones are placed on armature layer 0. All other geolayout commands are placed on layer 1. Metarig generated bones are placed on layers 3 and 4 (see 'Animating Existing Geolayouts'). If you change a bone's geolayout command type and it dissapears, it might have been moved to a different layer. Make sure to go to the armature properties editor and set both layers 0 and 1 to be visible. Geolayout command types can be edited in the properties editor under the bone tab in pose mode.
|
||||
|
||||
### Geolayouts (Object)
|
||||
Alternatively, for simple static geolayouts you can export object hierarchies. Geolayout properties such as draw layer can be located in the object properties tab.
|
||||
|
||||
### Exporting Geolayouts and Skinned Meshes
|
||||
The N64 supports binary skinning, meaning each vertex will be influenced by one bone only. When skinning an exported geolayout, do NOT use automatic skinning, as this results in a smooth weight falloff. Instead, when weight painting set the weight to either 1 or 0, and set the brush Falloff to square. Skinning can only occur between an immediate parent and a child deform bone, not between siblings / across ancestors.
|
||||
|
||||
### Importing/Exporting SM64 Geolayouts
|
||||
Download these documents:
|
||||
|
||||
[SM64MainLevelScripts.txt](http://qubedstudios.rustedlogic.net/SM64MainLevelScripts.txt)
|
||||
|
||||
[SM64GeoLayoutPtrsByLevels.txt](http://qubedstudios.rustedlogic.net/SM64GeoLayoutPtrsByLevels.txt)
|
||||
|
||||
For importing/exporting geolayouts:
|
||||
|
||||
- In SM64GeoLayoutPtrsByLevels.txt, search the name of the model.
|
||||
- There you can get the modelID (Obj) and geolayout start (ROM Address start + offset)
|
||||
- Note that these are decimal values, and must be converted to hex when used as inputs for fast64.
|
||||
- In SM64MainLevelScripts, search '22 08 00 MM' where MM = modelID.
|
||||
- There may be multiple instances, in which case you must use the offset field from before and check if it matches the last 3 bytes of the line.
|
||||
- There you can get the level command.
|
||||
|
||||
Plug these values into the SM64 Geolayout Exporter/Importer panels.
|
||||
|
||||
### Replacing Existing SM64 Geolayout Geometry
|
||||
SM64 geolayouts are often in strange rest poses, which makes it hard to modify their geometry. It often helps to import an animation belonging to that geolayout to see what the idle pose of a geolayout should be. Once you know, you can rotate the bones of the armature in pose mode to a usable position and then use the 'Apply as Rest Pose' operator under the SM64 Armature Tools header. Skin your new mesh to that armature, then rotate the bones back to the original position and use 'Apply as Rest Pose' again. You can now export the geolayout to SM64 and it will be able to use existing animations.
|
||||
|
||||
### Importing/Exporting SM64 Animations (Not Mario)
|
||||
For importing/exporting animations:
|
||||
|
||||
- Download Quad64, open the desired level, and go to Misc -> Script Dumps.
|
||||
- Go to the objects header, find the object you want, and view the Behaviour Script tab.
|
||||
- For most models with animation, you can will see a 27 command, and optionally a 28 command.
|
||||
- The last 4 bytes of the 27 command will be the animation list pointer.
|
||||
- Make sure 'Is DMA Animation' is unchecked, 'Is Anim List' is checked, and 'Is Segmented Pointer' is checked.
|
||||
- Set the animation importer start address as those 4 bytes.
|
||||
- If a 28 command exists, then the second byte will be the anim list index.
|
||||
- Otherwise, the anim list index is usually 0.
|
||||
|
||||
Select an armature for the animation to be exported to, and press 'Import animation'. Note that the armature's root 0x13 (i.e. regular) bone must be named 'root'.
|
||||
|
||||
### Importing/Exporting Mario Animations
|
||||
Mario animations use a DMA table, which contains 8 byte entries of (offset from table start, animation size). Documentation about this table is here:
|
||||
https://dudaw.webs.com/sm64docs/sm64_marios_animation_table.txt.
|
||||
Basically, Mario's DMA table starts at 0x4EC000. There is an 8 byte header, and then the animation entries afterward. Thus the 'climb up ledge' DMA entry is at 0x4EC008. The first 4 bytes at that address indicate the offset from 0x4EC000 at which the actual animation exists. Thus the 'climb up ledge' animation address is at 0x4EC690. Using this table you can find animations you want to overwrite. Make sure the 'Is DMA Animation' option is checked and 'Is Segmented Pointer' is unchecked when importing/exporting.
|
||||
|
||||
### Animating Existing Geolayouts
|
||||
Often times it is hard to rig an existing SM64 geolayout, as there are many intermediate non-deform bones and bones don't point to their children. To make this easier you can use the 'Create Animatable Metarig' operator in the SM64 Armature Tools header. This will generate a metarig which can be used with IK. The metarig bones will be placed on armature layers 3 and 4.
|
||||
|
||||
### Exporting Geolayouts to C
|
||||
To replace an actor model in decomp, replace its geo.inc.c and model.inc.c contents with the geolayout file and the dl file respectively. Use the contents of the header file to replace existing extern declarations in one of the group header files (ex. mario is in group0.h). Make sure that the name of your geolayout is the same the name of the geolayout you're replacing.
|
||||
|
||||
### Switch Statements
|
||||
To add a switch mesh node, duplicate your switch bone and move it off to the side. Set the bone geolayout command to be Switch Option. Any nodes in this switch option must be children of this bone. Add any other bones to this bone. Add your switch geometry into your existing mesh in the correct position and skin it.
|
||||
|
||||
### Common Issues
|
||||
Inivisible Mesh : Bone is not set to deform, or geometry is skinned to more than one bone.
|
||||
|
||||
|
||||
+17
-4
@@ -229,10 +229,19 @@ class SM64_ImportGeolayout(bpy.types.Operator):
|
||||
|
||||
armatureObj = None
|
||||
|
||||
# Get segment data
|
||||
levelParsed = parseLevelAtPointer(romfileSrc,
|
||||
level_pointers[levelGeoImport])
|
||||
segmentData = levelParsed.segmentData
|
||||
geoStart = int(geoImportAddr, 16)
|
||||
if context.scene.geoIsSegPtr:
|
||||
geoStart = decodeSegmentedAddr(
|
||||
geoStart.to_bytes(4, 'big'), segmentData)
|
||||
|
||||
# Armature mesh groups includes armatureObj.
|
||||
armatureMeshGroups, armatureObj = parseGeoLayout(romfileSrc,
|
||||
int(geoImportAddr, 16),
|
||||
context.scene, levelGeoImport,
|
||||
geoStart,
|
||||
context.scene, segmentData,
|
||||
finalTransform, generateArmature,
|
||||
ignoreSwitch, True, context.scene.f3d_type,
|
||||
context.scene.isHWv1)
|
||||
@@ -289,6 +298,7 @@ class SM64_ImportGeolayoutPanel(bpy.types.Panel):
|
||||
#col.prop(context.scene, 'rotationAxis')
|
||||
#col.prop(context.scene, 'rotationAngle')
|
||||
prop_split(col, context.scene, 'geoImportAddr', 'Start Address')
|
||||
col.prop(context.scene, 'geoIsSegPtr')
|
||||
col.prop(context.scene, 'levelGeoImport')
|
||||
col.prop(context.scene, 'generateArmature')
|
||||
col.prop(context.scene, 'ignoreSwitch')
|
||||
@@ -501,7 +511,7 @@ class SM64_ExportGeolayoutArmature(bpy.types.Operator):
|
||||
obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
bpy.ops.object.transform_apply(location = False, rotation = True,
|
||||
scale = False, properties = False)
|
||||
scale = True, properties = False)
|
||||
if context.scene.geoExportType == 'C':
|
||||
exportGeolayoutArmatureC(armatureObj, obj, finalTransform,
|
||||
context.scene.f3d_type, context.scene.isHWv1,
|
||||
@@ -1610,6 +1620,8 @@ def register():
|
||||
name = 'Save texture.inc.c separately')
|
||||
bpy.types.Scene.geoInsertableBinaryPath = bpy.props.StringProperty(
|
||||
name = 'Filepath', subtype = 'FILE_PATH')
|
||||
bpy.types.Scene.geoIsSegPtr = bpy.props.BoolProperty(
|
||||
name = 'Is Segmented Address')
|
||||
|
||||
# Level
|
||||
bpy.types.Scene.levelLevel = bpy.props.EnumProperty(items = level_enums,
|
||||
@@ -1644,7 +1656,7 @@ def register():
|
||||
bpy.types.Scene.animInsertableBinaryPath = bpy.props.StringProperty(
|
||||
name = 'Filepath', subtype = 'FILE_PATH')
|
||||
bpy.types.Scene.animIsSegPtr = bpy.props.BoolProperty(
|
||||
name = 'Is Segmented Pointer', default = False)
|
||||
name = 'Is Segmented Address', default = False)
|
||||
bpy.types.Scene.animIsAnimList = bpy.props.BoolProperty(
|
||||
name = 'Is Anim List', default = True)
|
||||
bpy.types.Scene.animListIndex = bpy.props.IntProperty(
|
||||
@@ -1722,6 +1734,7 @@ def unregister():
|
||||
del bpy.types.Scene.geoSaveTextures
|
||||
del bpy.types.Scene.geoSeparateTextureDef
|
||||
del bpy.types.Scene.geoInsertableBinaryPath
|
||||
del bpy.types.Scene.geoIsSegPtr
|
||||
|
||||
# Animation
|
||||
del bpy.types.Scene.animStartImport
|
||||
|
||||
@@ -276,7 +276,7 @@ def checkForF3DMaterial(obj):
|
||||
if materialSlot.material is None or \
|
||||
not materialSlot.material.is_f3d:
|
||||
raise ValueError(obj.name + " has either empty material slots " +\
|
||||
'or non-Fast3D materials.')
|
||||
'or non-Fast3D materials. Remove any regular blender materials / empty slots.')
|
||||
|
||||
def revertMatAndEndDraw(gfxList):
|
||||
gfxList.commands.extend([
|
||||
@@ -1276,24 +1276,24 @@ def saveLightsDefinition(fModel, material, lightsName):
|
||||
int(ambientColor[2] * 255)])
|
||||
|
||||
if material.f3d_light1 is not None:
|
||||
addLightDefinition(material.f3d_light1, lights)
|
||||
addLightDefinition(material, material.f3d_light1, lights)
|
||||
if material.f3d_light2 is not None:
|
||||
addLightDefinition(material.f3d_light2, lights)
|
||||
addLightDefinition(material, material.f3d_light2, lights)
|
||||
if material.f3d_light3 is not None:
|
||||
addLightDefinition(material.f3d_light3, lights)
|
||||
addLightDefinition(material, material.f3d_light3, lights)
|
||||
if material.f3d_light4 is not None:
|
||||
addLightDefinition(material.f3d_light4, lights)
|
||||
addLightDefinition(material, material.f3d_light4, lights)
|
||||
if material.f3d_light5 is not None:
|
||||
addLightDefinition(material.f3d_light5, lights)
|
||||
addLightDefinition(material, material.f3d_light5, lights)
|
||||
if material.f3d_light6 is not None:
|
||||
addLightDefinition(material.f3d_light6, lights)
|
||||
addLightDefinition(material, material.f3d_light6, lights)
|
||||
if material.f3d_light7 is not None:
|
||||
addLightDefinition(material.f3d_light7, lights)
|
||||
addLightDefinition(material, material.f3d_light7, lights)
|
||||
|
||||
fModel.lights[lightsName] = lights
|
||||
return lights
|
||||
|
||||
def addLightDefinition(f3d_light, fLights):
|
||||
def addLightDefinition(mat, f3d_light, fLights):
|
||||
lightObj = None
|
||||
for obj in bpy.context.scene.objects:
|
||||
if obj.data == f3d_light:
|
||||
@@ -1301,7 +1301,7 @@ def addLightDefinition(f3d_light, fLights):
|
||||
break
|
||||
if lightObj is None:
|
||||
raise ValueError(
|
||||
"You are referencing a light that is no longer in the scene.")
|
||||
"The material \"" + mat.name + "\" is referencing a light that is no longer in the scene (i.e. has been deleted).")
|
||||
|
||||
#spaceRot = blenderToSM64Rotation.to_4x4().to_quaternion()
|
||||
spaceRot = mathutils.Euler((-pi / 2, 0, 0)).to_quaternion()
|
||||
|
||||
@@ -20,16 +20,12 @@ blender_modes = {'OBJECT', 'BONE'}
|
||||
# It will only handle transform/mesh related commands.
|
||||
# For switch cases, only the first option will be chosen.
|
||||
|
||||
def parseGeoLayout(romfile, startAddress, scene, level,
|
||||
def parseGeoLayout(romfile, startAddress, scene, segmentData,
|
||||
convertTransformMatrix, useArmature, ignoreSwitch, shadeSmooth,
|
||||
f3dType, isHWv1):
|
||||
currentAddress = startAddress
|
||||
romfile.seek(currentAddress)
|
||||
|
||||
# Get segment data
|
||||
levelParsed = parseLevelAtPointer(romfile, level_pointers[level])
|
||||
segmentData = levelParsed.segmentData
|
||||
|
||||
# Create new skinned mesh
|
||||
#bpy.ops.object.mode_set(mode = 'OBJECT')
|
||||
mesh = bpy.data.meshes.new('skinnned-mesh')
|
||||
|
||||
@@ -121,7 +121,7 @@ def applyRotation(objList, angle, axis):
|
||||
bpy.context.view_layer.objects.active = objList[0]
|
||||
bpy.ops.transform.rotate(value = angle, orient_axis = axis)
|
||||
bpy.ops.object.transform_apply(location = False,
|
||||
rotation = True, scale = False, properties = False)
|
||||
rotation = True, scale = True, properties = False)
|
||||
|
||||
def getAddressFromRAMAddress(RAMAddress):
|
||||
addr = RAMAddress - 0x80000000
|
||||
|
||||
Reference in New Issue
Block a user