0
$\begingroup$

I have a textured mesh that I have bisected and the mesh now only contains the parts that I want (the rest has been deleted).

The result is, in my limited understanding, that the parts of the mesh which used to refer to parts of the texture no longer exist.

This leaves a texture with only about 50% in use and the rest is junk as far as I'm concerned.

I want to get rid of the junk; the stuff that falls outside of the UV coordinates, as seen in the image:

UV cordinates referencing only part of the image

I've tried baking the texture and replacing, packing islands, packing UV, and anything else half obvious in the UV Editor window. Nothing I've tried is having the desired result.

I suppose I could texture paint really coarsly outside of the UV coordinates, but this is something I'd rather avoid if possible, especially if there is an automatic way to do it.

Can anyone give an advise?

Thanks.

$\endgroup$
1
  • $\begingroup$ The fastest way to do this is to create a copy of your object in the same .blend file, delete the material and the UV layout, delete all parts of the mesh you want to delete, create a new UV layout and then bake the new texture from your old material. $\endgroup$ Commented Apr 1, 2019 at 22:30

2 Answers 2

1
$\begingroup$

My answer to this similar question: "How to delete unwanted/unused parts of texture?" may help, specifically the YouTube tutorials I mention. I used them to learn how to perform the operation of Texture Unwrapping and Baking, which results in the output you desire: keeping only the referenced parts of the texture and efficiently island-packing the remaining texture file.

For anyone else who doesn't understand the lingo of "unwrapping" and "baking" or how to accomplish doing these operations in Blender (like me 2 months ago) hopefully this will help:

Check out these tutorials:

  1. Bake Textures From one UV Map to Another UV Map (Blender Tutorial) By: YouTube channel "Ryan King Art"

  2. How to Unwrap and Bake Textures in Blender 2.8, 2.9, 3.0, 3.1, and 3.2? By: "One Wheel Studio"

  3. Bake Multiple Materials to One Texture Map (Blender Tutorial) By: "Ryan King Art"

  4. I myself had to perform such operation in Blender, where I received a cropped .obj mesh as input which was referencing a texture file that contained extraneous data that was no longer needed in the cropped mesh. To decrease the size of the texture file such that it contained only the needed textures, I followed the above tutorials. In the process, I wrote down the steps I took in the Blender GUI to accomplish the Texture Unwrapping and Baking task, as well as automated the laborious process by using the Blender Python API. In case it helps, the detailed steps I took and their Python counterparts can be found in this Github repo file which I reproduce below in case the link breaks.

Steps for using the Blender GUI for creating (i.e. baking) a texture map from a textured 3D obj model. The steps were created from following tutorials.

  1. Begin by importing your obj file, delete default cube, then open 3 windows/editors inside Blender by hovering mouse over bottom black line, right click, 'split view': a) Open UV editor, b) shader editor, and c) "normal" view (not render, to save RAM)

  2. Select your object and click Object data properties tab on right.

  3. Open UV Map menu on right, Create new UV map called uv map 2

  4. Open Object Data Properties tab on right > UV Maps > Click on UV Map 2

  5. Go to Edit Mode (tab)

  6. With UV map 2 selected: UV smart unwrap with island padding of 0.001

  7. Inspect and check that UV map 2 doesn't have overlapping triangles ctrl+p to re-pack islands?, if they dont fill up the image?

  8. In shader view, to create new node: shift+a > search > image texture > new > name: test_texture (4096 x 4096) (Reqs 7-9 GB RAM). Maybe try something smaller like 2K (2048x2048) (reqs 4-6 GB RAM during baking)

  9. In shader view, shift+a > search > uv map > connect "UV" to "vector" of test_texture node After connecting, Select uv map 2 from the drop down menu of the uv map node

  10. In shader view, create another uv map > connect it to existing texture, and select the exisiting UV map from the drop down menu to show blender that the current texture uses the current uv map. At this point, there should be 3 new nodes in the shader view

  11. Repeat above steps 8-10 for each of the materials (the active material can be selected on the right from the material properties tab)

  12. On right, select render tab > Render Engine: Cycles

  13. For max samples select 10 and 10 for viewport and renderer.

  14. Click bake dropdown panel > diffuse. Uncheck boxes direct & indirect light.

  15. In shader view, for each material, Select the new texture image node

  16. Click Bake (being in Object Mode doesn't seem neccessary like in tutorial) (Requires 5-6Gb RAM for 2k, 8-9GB RAM for 4k) Takes 10+ seconds

  17. In shader view, for each material, attach the new texture image node to the BDSF node in place of the previous UV map

  18. Save baked texture: Image > Save As...

  19. File > External Data > Pack Resources

  20. File > External Data > Unpack Resources > Use Files in Current Directory (create if not found)

  21. File > Export obj

  22. Check that the new texture is specified in the outputted .mtl file

import bpy
import os
import sys

# Argument parsing assumes this file was called from terminal in this format:
# ./blender --background --python ~/Code/blender_code.py -- arg1 arg2 arg3
# "--" is Blender specific for passing in arguments (i.e. arg1, arg2, etc.) to Blender python scripts
# https://blender.stackexchange.com/questions/6817/how-to-pass-command-line-arguments-to-a-blender-python-script
args = sys.argv[sys.argv.index("--") + 1:]
print("ARGS:",args)
INPUT_PATH = args[0]
OUTPUT_PATH = args[1]
RESOLUTION = int(args[2])
print('Input Path:', INPUT_PATH)
print('Output Path:', OUTPUT_PATH)
print('Resolution:', RESOLUTION)
print()

input_path = INPUT_PATH
export_filepath = OUTPUT_PATH 


# delete the default cube at blender startup
objs = bpy.data.objects
if 'Cube' in objs:
    objs.remove(objs["Cube"])

# Load obj
imported_object = bpy.ops.import_scene.obj(filepath=input_path)
obj = bpy.context.selected_objects[0] 
print('Imported name: ', obj.name)
objs[obj.name].select_set(True) # obj should already be selected, but just in case
# sets our mesh to be active
bpy.context.view_layer.objects.active = objs[obj.name] 

bpy.ops.object.mode_set(mode='EDIT') # Go to Edit mode
new_uv_map_name = 'UVMap_2'
obj.data.uv_layers.new(name=new_uv_map_name) # create and name new UV Map
# Set new UV map to active
bpy.data.meshes[obj.name].uv_layers[new_uv_map_name].active = True 
# UV Unwrap the mesh textures
bpy.ops.uv.smart_project(angle_limit=1.15192, island_margin=0.001)


# Working in shader view now...
obj = bpy.context.active_object 
# You can choose your texture size (This will be the baked image)
image_name = obj.name + '_BakedTexture'
img = bpy.data.images.new(image_name, RESOLUTION, RESOLUTION)



texture_node_name = 'Bake_node'
old_uv_map_node_name = 'UV1_node'
new_uv_map_node_name = 'UV2_node'

print("Creating nodes for each material...")
for mat in obj.data.materials:
    node_tree = mat.node_tree
    nodes = node_tree.nodes

    orig_img_tex_node = nodes['Image Texture']

    # Creates uv map node in shader view and sets its uv map to current uv map
    uv_map_node = nodes.new('ShaderNodeUVMap')
    uv_map_node.name = old_uv_map_node_name 
    uv_map_node.uv_map = obj.data.uv_layers[0].name
    node_tree.links.new(uv_map_node.outputs['UV'], orig_img_tex_node.inputs['Vector'])

    # Create image texture node in shader view and sets its image
    texture_node = nodes.new('ShaderNodeTexImage') # Creates node in shader view
    texture_node.name = texture_node_name
    texture_node.select = True
    nodes.active = texture_node
    texture_node.image = img #Assign the image to the node

    # Creates another uv map node in shader view and sets its uv map to new uv map
    new_uv_map_node = nodes.new('ShaderNodeUVMap')
    new_uv_map_node.name = new_uv_map_node_name
    new_uv_map_node.uv_map = obj.data.uv_layers[new_uv_map_name].name  
    node_tree.links.new(new_uv_map_node.outputs['UV'], texture_node.inputs['Vector'])

    # Make texture_node the only one selected. Make it active, as required for baking 
    for n in nodes:
        n.select = False
    nodes[texture_node.name].select = True
    nodes.active = nodes[texture_node.name]


# Set render engine to cycles and set settings
# This changes things in the Render Properties tab on the right-hand-side (Camera icon)
bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.cycles.samples =  10
bpy.context.scene.cycles.preview_samples = 10 # Takes a few seconds to update GUI
bpy.context.scene.cycles.bake_type = 'DIFFUSE'
bpy.context.scene.render.bake.use_pass_direct = False
bpy.context.scene.render.bake.use_pass_indirect = False

print("Baking...")
bpy.ops.object.bake(type='DIFFUSE', save_mode='EXTERNAL', filepath='/home/nitz/Downloads/8_8_22')



# This tells Blender what textures belong to the model during export
# In shader view, for each material, link new texture image node to BDSF node
# And delete the original image texture and old uv map nodes
for mat in obj.data.materials:
    node_tree = mat.node_tree
    nodes = node_tree.nodes

    texture_node = nodes[texture_node_name]
    old_texture_node = nodes['Image Texture']
    old_uv_map_node = nodes[old_uv_map_node_name]
    BSDF_node = nodes['Principled BSDF']

    # Link new texture node to model
    node_tree.links.new(texture_node.outputs['Color'], BSDF_node.inputs['Base Color'])

    # Delete old texture and uv map nodes
    nodes.remove(old_texture_node)
    nodes.remove(old_uv_map_node)

# Remove old UV Map layer, which essentially makes the new UV Map used during export
uv_textures = obj.data.uv_layers
uv_textures.remove(uv_textures['UVMap'])

output_dir = os.path.dirname(export_filepath)
print("OUTPUT PATH:", output_dir)
if not os.path.exists(output_dir):
    os.mkdir(output_dir)

# Textures will be saved to path where blender file is saved to.
# The saving of the blend file has no other purpose. File is deleted.
blend_file_name = 'temp.blend'
blend_file_path = os.path.join(output_dir, blend_file_name)
bpy.ops.wm.save_as_mainfile(filepath=blend_file_path)
# Packing and unpacking is used for exported files to include textures 
bpy.data.images[image_name].pack()
bpy.ops.file.unpack_all(method='USE_ORIGINAL') # USE_ORIGINAL saves textures in curr dir
bpy.ops.export_scene.obj(filepath=export_filepath, path_mode='RELATIVE')
os.remove(blend_file_path) # remove temp blend file
print('Exported to:', export_filepath)
print('Finished! \nBlender quitting...')
$\endgroup$
0
0
$\begingroup$

The geometry is reflected on the UV. If you mention it is junk, probably delete the mesh junk park associated with it as well. Otherwise, re-unwrap Uvs.

I read this question 3 times. I know what you´re having: shadow uvs. Yeah, bisecting is a special boolean case. I´d strongly recomend you re-unwrap. It will only take a second. Baking textures: yes, you can do that as well, you´ll also get the old UV set. Got to object properties> vertex groups> Uv coordinates, delete them both vertex groups and coordinates. Then Un-wrap. Then bake old bisected to new unwrapped. Should work out of the box.

$\endgroup$
1
  • $\begingroup$ And would that be a case of exporting the bisected mesh, reimporting the image and reapplying the texture. I don't fully understand because the parts of the mesh I bisected have been deleted. $\endgroup$
    – Fiddy Bux
    Commented Apr 1, 2019 at 20:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .