4
$\begingroup$

For my mesh I have two UV Maps. I'm importing the Blender file into an external program which requires the UVMaps to be in a certain order. In the UV Maps list there are no up/down arrows like there is in the Vertex Groups list to change the order of elements in the list. Is there a way to assign the order of UV Maps in Blender? Or could there be a Python script to do this?

$\endgroup$
5
$\begingroup$

Here is an add-on that does what Stefan Schindler mentioned (I can't say I didn't already know that trick, but he did mention it before I did...). I would recommend that you check it out at the GitHub page here so that you know that you have the most up-to-date version. It is also just fine to use this link if you'd prefer to copy/paste rather than download and unzip it.

Here is the original version of the code though (like I said, it is preferable to get a copy from GitHub because I won't be updating this).

# Copyright 2016 Jake Dube
#
# ### BEGIN GPL LICENSE BLOCK ###
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# ### END GPL LICENSE BLOCK ###

import bpy
from bpy.types import Operator

bl_info = {
    "name": "UV Tools",
    "author": "Jake Dube",
    "version": (1, 0),
    "blender": (2, 77, 0),
    "location": "UV maps in properties window",
    "description": "Some tools for uv maps that should already be in Blender.",
    "category": "UV"}


def make_active(name):
    uvs = bpy.context.scene.objects.active.data.uv_textures
    for uv in uvs:
        if uv.name == name:
            uvs.active = uv
            return
    print("Could not find:", name, "\n(this should never happen)")


def move_to_bottom(index):
    uvs = bpy.context.scene.objects.active.data.uv_textures
    uvs.active_index = index
    new_name = uvs.active.name

    bpy.ops.mesh.uv_texture_add()

    # delete the "old" one
    make_active(new_name)
    bpy.ops.mesh.uv_texture_remove()

    # set the name of the last one
    uvs.active_index = len(uvs) - 1
    uvs.active.name = new_name


class MoveUVMapDown(Operator):
    bl_idname = "uv_tools.move_uvmap_down"
    bl_label = "Move Down"
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):
        uvs = context.scene.objects.active.data.uv_textures

        # get the selected UV map
        orig_ind = uvs.active_index
        orig_name = uvs.active.name

        if orig_ind == len(uvs) - 1:
            return {'FINISHED'}

        # use "trick" on the one after it
        move_to_bottom(orig_ind + 1)

        # use the "trick" on the UV map
        move_to_bottom(orig_ind)

        # use the "trick" on the rest that are after where it was
        for i in range(orig_ind, len(uvs) - 2):
            move_to_bottom(orig_ind)

        make_active(orig_name)

        return {'FINISHED'}


class MoveUVMapUp(Operator):
    bl_idname = "uv_tools.move_uvmap_up"
    bl_label = "Move Up"
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):
        uvs = context.scene.objects.active.data.uv_textures

        if uvs.active_index == 0:
            return {'FINISHED'}

        original = uvs.active.name
        uvs.active_index -= 1
        bpy.ops.uv_tools.move_uvmap_down()
        make_active(original)

        return {'FINISHED'}


def uv_tools_addition(self, context):
    layout = self.layout
    col = layout.column(align=True)
    col.operator("uv_tools.move_uvmap_up", icon='TRIA_UP')
    col.operator("uv_tools.move_uvmap_down", icon='TRIA_DOWN')


def register():
    bpy.utils.register_class(MoveUVMapDown)
    bpy.utils.register_class(MoveUVMapUp)
    bpy.types.DATA_PT_uv_texture.append(uv_tools_addition)


def unregister():
    bpy.utils.unregister_class(MoveUVMapDown)
    bpy.utils.unregister_class(MoveUVMapUp)
    bpy.types.DATA_PT_uv_texture.remove(uv_tools_addition)


if __name__ == "__main__":
    register()

This add-on (at the time of this writing) simply adds two buttons below the uv maps list like this:

enter image description here

| improve this answer | |
$\endgroup$
  • $\begingroup$ Just tried it, and it's working great :) $\endgroup$ – Štefan Schindler Nov 16 '16 at 15:06
  • $\begingroup$ Thanks, this is very good. The ability to re-order the UVs is very useful for people who are importing the file into Unity. Some workflows require UVs in the following order: texture, baked lighting, realtime lighting. So the additional UVs can just be spare UVs for debugging. It's useful because the process of generating the light UVs involves a lot of trial-and-error to get right so it can be used by the lighting software, so this tools makes the process much easier. $\endgroup$ – TTTTTTa Nov 16 '16 at 15:18
  • $\begingroup$ @ŠtefanSchindler Thanks. TTTTTTa You're welcome! Please consider accepting Stefan's or my answer. I totally understand about Unity as I have done most of my Blender work for developing game assets. I don't know why I didn't do this originally as it would have been a big help rather than the messy way of doing it manually. $\endgroup$ – JakeD Nov 16 '16 at 15:30
  • $\begingroup$ So I'm pretty annoyed I needed to do this. 3 years later and no one can adjust the index of the uv maps. This seems like a must have feature when doing any sort of remapping with a game engine that looks at map index. However I'm very thankful this addon still works. Thank you! $\endgroup$ – Levitikon Jul 7 '19 at 18:58
  • 1
    $\begingroup$ @NoobCat No, Blender automatically will copy the currently selected UV map when you make a new one. No need to do that explicitly when using bpy.ops command as I did here. I've got to ask: have you tried this? I used it for years without issues. The "algorithm" is what is shown here if you are curious: blender.stackexchange.com/a/67268/28015 $\endgroup$ – JakeD Jul 16 at 20:38
4
$\begingroup$

There is a little trick to it. When you have selected one UV Map and hit the plus button it duplicates the currently selected UV Map and puts it at the end.

So here are steps needed in order to reorder the order of UV Maps :

  1. Select the first UV Map.
  2. Click on the Plus button.
  3. Delete the first UV map.
  4. Rename the last UV Map to not contain the .001 suffix.

enter image description here

| improve this answer | |
$\endgroup$
  • $\begingroup$ OK, thanks. That's a nifty trick. I wonder why there isn't just an up/down arrow on the GUI. One question: Why do you recommend to remove the ".001" suffix? Is there a reason? $\endgroup$ – TTTTTTa Nov 15 '16 at 14:29
  • 2
    $\begingroup$ I wonder too why there isn't up/down arrow, maybe because only few users need it. If you would leave the name as "UVMap.001" it would be a new UV map and all places where it was previously referenced as "UV Map" would be marked as the UV Map is missing. If you rename it to the same name as the original then all references are kept. $\endgroup$ – Štefan Schindler Nov 15 '16 at 14:35
  • $\begingroup$ @ŠtefanSchindler I think I'll write an add-on that solves this problem :-) $\endgroup$ – JakeD Nov 15 '16 at 15:12
  • $\begingroup$ @pycoder nice, good luck :) $\endgroup$ – Štefan Schindler Nov 15 '16 at 15:30
  • 1
    $\begingroup$ @ŠtefanSchindler Thanks, take a look. $\endgroup$ – JakeD Nov 16 '16 at 4:59
1
$\begingroup$

Modified for 2.8

import bpy
from bpy.types import Operator

bl_info = {
    "name": "UV Tools",
    "author": "Jake Dube (modified by Denis Khomenko for 2.8)",
    "version": (1, 0),
    "blender": (2, 80, 75),
    "location": "UV maps in properties window",
    "description": "Some tools for uv maps that should already be in Blender.",
    "category": "UV"}


def make_active(name):
    uvs = bpy.context.active_object.data.uv_layers  #bpy.context.scene.objects.active.data.uv_textures
    for uv in uvs:
        if uv.name == name:
            uvs.active = uv
            return
    print("Could not find:", name, "\n(this should never happen)")


def move_to_bottom(index):
    uvs = bpy.context.active_object.data.uv_layers #bpy.context.scene.objects.active.data.uv_textur
    uvs.active_index = index
    new_name = uvs.active.name

    bpy.ops.mesh.uv_texture_add()

    # delete the "old" one
    make_active(new_name)
    bpy.ops.mesh.uv_texture_remove()

    # set the name of the last one
    uvs.active_index = len(uvs) - 1
    uvs.active.name = new_name


class MoveUVMapDown(Operator):
    bl_idname = "uv_tools.move_uvmap_down"
    bl_label = "Move Down"
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):
        uvs = bpy.context.active_object.data.uv_layers #context.scene.objects.active.data.uv_textures

        # get the selected UV map
        orig_ind = uvs.active_index
        orig_name = uvs.active.name

        if orig_ind == len(uvs) - 1:
            return {'FINISHED'}

        # use "trick" on the one after it
        move_to_bottom(orig_ind + 1)

        # use the "trick" on the UV map
        move_to_bottom(orig_ind)

        # use the "trick" on the rest that are after where it was
        for i in range(orig_ind, len(uvs) - 2):
            move_to_bottom(orig_ind)

        make_active(orig_name)

        return {'FINISHED'}


class MoveUVMapUp(Operator):
    bl_idname = "uv_tools.move_uvmap_up"
    bl_label = "Move Up"
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):
        uvs = bpy.context.active_object.data.uv_layers  #context.scene.objects.active.data.uv_textures

        if uvs.active_index == 0:
            return {'FINISHED'}

        original = uvs.active.name
        uvs.active_index -= 1
        bpy.ops.uv_tools.move_uvmap_down()
        make_active(original)

        return {'FINISHED'}


def uv_tools_addition(self, context):
    layout = self.layout
    col = layout.column(align=True)
    col.operator("uv_tools.move_uvmap_up", icon='TRIA_UP')
    col.operator("uv_tools.move_uvmap_down", icon='TRIA_DOWN')


def register():
    bpy.utils.register_class(MoveUVMapDown)
    bpy.utils.register_class(MoveUVMapUp)
    bpy.types.DATA_PT_uv_texture.append(uv_tools_addition)


def unregister():
    bpy.utils.unregister_class(MoveUVMapDown)
    bpy.utils.unregister_class(MoveUVMapUp)
    bpy.types.DATA_PT_uv_texture.remove(uv_tools_addition)


if __name__ == "__main__":
    register()
| improve this answer | |
$\endgroup$
  • $\begingroup$ just go to the GitHub repo like I said in my answer...that's what will get updated $\endgroup$ – JakeD Jul 17 at 20:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.