Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support exporting animation frames and scenery to OBJ with textures #158

Open
wants to merge 16 commits into
base: d/new-load
Choose a base branch
from

Conversation

Almamu
Copy link

@Almamu Almamu commented Apr 10, 2023

This PR adds the following featurers

  • Exporting individual Scenery entries
  • Exporting individual Animation frame entries
  • Exporting all geometry available in one NSF file
  • Exporting all the frames of an animation into separate files

Once the OBJ is exported it can be imported in any 3D software. Due to the OBJ format being a bit lacking, there's some minor adjustements that need to happen once imported into your 3D tool of choice. I'd recommend using blender and this script to get the best results possible:

import bpy

# apply the node tree changes to the material
def update_material (materialRef):
    image = materialRef.node_tree.nodes['Image Texture']
    bsdf = materialRef.node_tree.nodes['Principled BSDF']
    # remove the output links for the image
    for link in image.outputs['Color'].links:
        materialRef.node_tree.links.remove (link)
    # connect the image's alpha to the principled's alpha
    materialRef.node_tree.links.new (image.outputs['Alpha'], bsdf.inputs['Alpha'])
    # add the color attribute
    color = materialRef.node_tree.nodes.new ('ShaderNodeVertexColor')
    # set the layer name, use hardcoded value for now
    color.layer_name = 'Color'
    # add the color mix
    mix = materialRef.node_tree.nodes.new ('ShaderNodeMix')
    # setup settings
    mix.data_type = 'RGBA'
    materialRef.blend_method = 'BLEND'
    materialRef.show_transparent_back = False
    # now link inputs, depending on the blending mode these have to be performed differently
    if image.image.name.endswith("b0.bmp"):
        mix.inputs[0].default_value = 1
        mix.blend_type = 'MULTIPLY'
        materialRef.node_tree.links.new (image.outputs['Color'], mix.inputs[6])
        materialRef.node_tree.links.new (color.outputs['Color'], mix.inputs[7])
    elif image.image.name.endswith("b1.bmp"):
        mix.inputs[0].default_value = 0
        mix.blend_type = 'ADD'
        materialRef.node_tree.links.new (image.outputs['Color'], mix.inputs[6])
        materialRef.node_tree.links.new (color.outputs['Color'], mix.inputs[7])
        materialRef.node_tree.links.new (color.outputs['Color'], bsdf.inputs['Alpha'])
    elif image.image.name.endswith("b2.bmp"):
        mix.inputs[0].default_value = 0
        mix.blend_type = 'SUBTRACT'
        materialRef.node_tree.links.new (image.outputs['Color'], mix.inputs[6])
        materialRef.node_tree.links.new (color.outputs['Color'], mix.inputs[7])
    else:
        mix.inputs[0].default_value = 1
        mix.blend_type = 'MULTIPLY'
        materialRef.node_tree.links.new (image.outputs['Color'], mix.inputs[6])
        materialRef.node_tree.links.new (color.outputs['Color'], mix.inputs[7])
        
    materialRef.node_tree.links.new (mix.outputs[2], bsdf.inputs[0])
    image.interpolation = 'Closest'
    return

def can_update_material (materialRef):
    if not materialRef:
        return False
    if not materialRef.node_tree:
        return False
    if not materialRef.node_tree.nodes:
        return False
    if not len(materialRef.node_tree.nodes) == 3:
        return False
    if not 'Image Texture' in materialRef.node_tree.nodes:
        return False
    if not 'Material Output' in materialRef.node_tree.nodes:
        return False
    if not 'Principled BSDF' in materialRef.node_tree.nodes:
        return False

for material in bpy.data.materials:
    if can_update_material (material) is False:
        continue
    
    update_material (material)

The script will update all the materials in use and create the proper Color Attribute and color mixing required for everything to display properly.

It might be possible to improve the export in the future, like using object groups for exporting all frames of an animation as one single obj file, instead of multiple, or pack the textures into one texture atlas to make better usage of the texture space, but it should be a good starting point for anyone looking to export animations and scenery.

Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
…o d/new-load

# Conflicts:
#	CrashEdit/Controllers/Animation/OldFrameController.cs
Added OBJ export to normal scenery entries

Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
…o d/new-load

# Conflicts:
#	Crash/Formats/Crash Formats/Animation/OldFrame.cs
#	Crash/Formats/Crash Formats/Scenery/SceneryEntry.cs
Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
This enabled 3D software with scripting capabilities (like blender) to display textures properly

Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
Frame export should keep filename length the same regardless of the amount of frames
Added eid to texture export to prevent textures being overriden when they were indeed different

Signed-off-by: Alexis Maiquez Murcia <almamu@almamu.com>
@Almamu Almamu mentioned this pull request May 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant