all_textures resize uses the first material's light resolution for all materials #74

Open
opened 2026-06-14 20:51:35 +00:00 by fallcuse · 0 comments

While testing atlas generation in all_textures mode, I noticed that texture resizing uses the first detected light texture resolution as the target resolution for all materials in the mesh.

This becomes problematic when a mesh contains materials with different light texture resolutions.

Example

  • Body Light: 4096×4096
  • Face Light: 4096×4096
  • Eyeline Light: 128×128

Current behavior

The resize target is determined by the first material with a light texture found in the object.

For example:

  • If the first detected material is Body, all normal/detail-related textures are resized to 4096×4096.
  • If the first detected material is Eyeline, all normal/detail-related textures are resized to 128×128.

As a result, the resize target depends on the first material found in the object rather than the material currently being processed.

Cause

The resize target is determined from the first light texture found in the object and is then reused for every material processed during atlas generation.

Current code location:

Inside Combiner.execute(), in the material processing loop, immediately before:

            for type in bake_types:
                #replace all images
                for material in [mat_slot.material for mat_slot in object.material_slots if mat_slot.material.get('name')]:

Current implementation:

            target_resolution = None
            if bpy.context.scene.kkbp.atlas_dropdown == 'all_textures':
                if any(t in bake_types for t in ['normal', 'detail', 'detailnormal', 'alphamask', 'colormask']):
                    for mat_slot in object.material_slots:
                        if mat_slot.material and mat_slot.material.get('name'):
                            light_node = mat_slot.material.node_tree.nodes.get(get_image_node('light'))
                            if light_node and light_node.image:
                                target_resolution = tuple(light_node.image.size[:])
                                c.kklog(f"Target resolution for normal and detail textures: {target_resolution}")
                                break

The resize target is calculated before entering the material processing loop and is then reused for all materials.

As a result:

  • target_resolution is determined only once.
  • The selected resolution is not tied to the material currently being processed.
  • Every material uses the same resize target during atlas generation.
  • Materials with different light texture resolutions cannot be resized independently.

For example:

Body Light     : 4096×4096
Face Light     : 4096×4096
Eyeline Light  : 128×128

If the Body material is encountered first, all normal/detail-related textures will be resized to 4096×4096.

If the Eyeline material is encountered first, all normal/detail-related textures will be resized to 128×128.

This means the resize target depends on which material appears first in object.material_slots, rather than the light texture resolution belonging to the material currently being processed.

The resize operation itself works correctly; the issue is that the wrong target resolution is selected before the resize occurs.

Proposed fix

The resize target should be determined from the material currently being processed instead of reusing a resolution selected from another material.

Current implementation:

target_resolution = None

if bpy.context.scene.kkbp.atlas_dropdown == 'all_textures':
    for mat_slot in object.material_slots:
        if mat_slot.material and mat_slot.material.get('name'):
            light_node = mat_slot.material.node_tree.nodes.get(
                get_image_node('light')
            )

            if light_node and light_node.image:
                target_resolution = tuple(
                    light_node.image.size[:]
                )
                break

Suggested change:

Remove the lookup above and determine target_resolution immediately before the resize operation using the material currently being processed:

                    target_resolution = None
                    if bpy.context.scene.kkbp.atlas_dropdown == 'all_textures':
                        if any(t in bake_types for t in ['normal', 'detail', 'detailnormal', 'alphamask', 'colormask']):
                            light_node = material.node_tree.nodes.get(get_image_node('light'))
                            if light_node and light_node.image:
                                target_resolution = tuple(light_node.image.size[:])

                    # Origin Code Part
                    # Resize texture to match target resolution if needed
                    if image and target_resolution and image.size[:] != target_resolution:
                        image = resize_texture_to_resolution(image, target_resolution)

This allows each material to use its own light texture resolution when resizing normal/detail-related textures.

While testing atlas generation in `all_textures` mode, I noticed that texture resizing uses the first detected light texture resolution as the target resolution for all materials in the mesh. This becomes problematic when a mesh contains materials with different light texture resolutions. ### Example * Body Light: 4096×4096 * Face Light: 4096×4096 * Eyeline Light: 128×128 ### Current behavior The resize target is determined by the first material with a light texture found in the object. For example: * If the first detected material is Body, all normal/detail-related textures are resized to 4096×4096. * If the first detected material is Eyeline, all normal/detail-related textures are resized to 128×128. As a result, the resize target depends on the first material found in the object rather than the material currently being processed. ### Cause The resize target is determined from the first light texture found in the object and is then reused for every material processed during atlas generation. Current code location: Inside `Combiner.execute()`, in the material processing loop, immediately before: ```python for type in bake_types: #replace all images for material in [mat_slot.material for mat_slot in object.material_slots if mat_slot.material.get('name')]: ``` Current implementation: ```python target_resolution = None if bpy.context.scene.kkbp.atlas_dropdown == 'all_textures': if any(t in bake_types for t in ['normal', 'detail', 'detailnormal', 'alphamask', 'colormask']): for mat_slot in object.material_slots: if mat_slot.material and mat_slot.material.get('name'): light_node = mat_slot.material.node_tree.nodes.get(get_image_node('light')) if light_node and light_node.image: target_resolution = tuple(light_node.image.size[:]) c.kklog(f"Target resolution for normal and detail textures: {target_resolution}") break ``` The resize target is calculated before entering the material processing loop and is then reused for all materials. As a result: - `target_resolution` is determined only once. - The selected resolution is not tied to the material currently being processed. - Every material uses the same resize target during atlas generation. - Materials with different light texture resolutions cannot be resized independently. For example: ```text Body Light : 4096×4096 Face Light : 4096×4096 Eyeline Light : 128×128 ``` If the Body material is encountered first, all normal/detail-related textures will be resized to 4096×4096. If the Eyeline material is encountered first, all normal/detail-related textures will be resized to 128×128. This means the resize target depends on which material appears first in `object.material_slots`, rather than the light texture resolution belonging to the material currently being processed. The resize operation itself works correctly; the issue is that the wrong target resolution is selected before the resize occurs. ### Proposed fix The resize target should be determined from the material currently being processed instead of reusing a resolution selected from another material. Current implementation: ```python target_resolution = None if bpy.context.scene.kkbp.atlas_dropdown == 'all_textures': for mat_slot in object.material_slots: if mat_slot.material and mat_slot.material.get('name'): light_node = mat_slot.material.node_tree.nodes.get( get_image_node('light') ) if light_node and light_node.image: target_resolution = tuple( light_node.image.size[:] ) break ``` Suggested change: Remove the lookup above and determine `target_resolution` immediately before the resize operation using the material currently being processed: ```python target_resolution = None if bpy.context.scene.kkbp.atlas_dropdown == 'all_textures': if any(t in bake_types for t in ['normal', 'detail', 'detailnormal', 'alphamask', 'colormask']): light_node = material.node_tree.nodes.get(get_image_node('light')) if light_node and light_node.image: target_resolution = tuple(light_node.image.size[:]) # Origin Code Part # Resize texture to match target resolution if needed if image and target_resolution and image.size[:] != target_resolution: image = resize_texture_to_resolution(image, target_resolution) ``` This allows each material to use its own light texture resolution when resizing normal/detail-related textures.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kkbp-dev/KKBP_Importer#74
No description provided.