]> git.mxchange.org Git - flightgear.git/blob - utils/Modeller/uv_pack.py
Blender 2.46 box packer script. Allows to unwrap objects individually, and
[flightgear.git] / utils / Modeller / uv_pack.py
1 #!BPY
2
3 # """
4 # Name: 'Pack selected objects on a square'
5 # Blender: 245
6 # Group: 'UV'
7 # Tooltip: 'Pack UV maps of all selected objects onto an empty square texture'
8 # """
9
10 __author__ = "Melchior FRANZ < mfranz # aon : at >"
11 __url__ = "http://members.aon.at/mfranz/flightgear/"
12 __version__ = "0.1"
13 __bpydoc__ = """\
14 Script for mapping multiple objects onto one square texture.
15
16 Usage:
17 (1) create new square texture in the UV editor
18 (2) map all objects individually, choosing the most appropriate technique
19 (3) scale each of the mappings to the appropriate size, relative to the
20     other object mappings
21 (4) select all objects and switch to edit mode (consider to use
22     Select->Linked->Material or similar methods)
23 (5) start this script with UVs->Scripts->Pack objects on a square
24
25     [now the texture image will first be erased, then colored rectangles
26     will appear for each object]
27
28 (6) rescale and/or remap objects that you aren't happy with (the
29     relative size of a mapping will be kept)
30
31     [continue with (5) until you like the result]
32
33 (7) export UV layout to SVG (UVs->Scripts->Save UV Face Layout)
34 """
35
36 MARGIN = 10 # px
37 GAP = 10    # px
38
39
40 import Blender, math, random
41
42
43 class Abort(Exception):
44         def __init__(self, msg):
45                 self.msg = msg
46
47
48 def pack():
49         image = Blender.Image.GetCurrent()
50         if not image:
51                 raise Abort('No texture image selected')
52
53         imagesize = image.getSize()
54         if imagesize[0] != imagesize[1]:
55                 Blender.Draw.PupMenu("Warning%t|Image isn't a square!")
56         gap = (float(GAP) / imagesize[0], float(GAP) / imagesize[1])
57         margin = (float(MARGIN) / imagesize[0] - gap[0] * 0.5, float(MARGIN) / imagesize[1] - gap[1] * 0.5)
58
59
60         def drawrect(x0, y0, x1, y1, color = (255, 255, 255, 255)):
61                 x0 *= imagesize[0]
62                 y0 *= imagesize[1]
63                 x1 *= imagesize[0]
64                 y1 *= imagesize[1]
65                 for u in range(int(x0 + 0.5), int(x1 - 0.5)):
66                         for v in range(int(y0 + 0.5), int(y1 - 0.5)):
67                                 image.setPixelI(u, v, color)
68
69         boxes = []
70         meshes = {}
71
72         Blender.Window.DrawProgressBar(0.0, "packing")
73         for o in Blender.Scene.GetCurrent().objects.selected:
74                 if o.type != "Mesh":
75                         continue
76
77                 mesh = o.getData(mesh = 1)
78                 if not mesh.faceUV:
79                         continue
80                 if mesh.name in meshes:
81                         #print "dropping duplicate mesh", mesh.name, "of object", o.name
82                         continue
83                 meshes[mesh.name] = True
84
85                 print "\tobject '%s'" % o.name
86                 xmin = ymin = 1000.0
87                 xmax = ymax = -1000.0
88                 for f in mesh.faces:
89                         for p in f.uv:
90                                 xmin = min(xmin, p[0])
91                                 xmax = max(xmax, p[0])
92                                 ymin = min(ymin, p[1])
93                                 ymax = max(ymax, p[1])
94
95                 width = xmax - xmin
96                 height = ymax - ymin
97                 boxes.append([0, 0, width + gap[0], height + gap[1], xmin, ymin, mesh, o.name])
98
99         if not boxes:
100                 raise Abort('No mesh objects selected')
101
102
103         boxsize = Blender.Geometry.BoxPack2D(boxes)
104         xscale = (1.0 - 2.0 * margin[0]) / max(boxsize[0], boxsize[1])
105         yscale = (1.0 - 2.0 * margin[1]) / max(boxsize[0], boxsize[1])
106
107         Blender.Window.DrawProgressBar(0.2, "Erasing texture")
108         drawrect(0, 0, 1, 1) # erase texture
109         for box in boxes:
110                 xmin = ymin = 1000.0
111                 xmax = ymax = -1000.0
112                 for f in box[6].faces:
113                         for p in f.uv:
114                                 p[0] = (p[0] - box[4] + box[0] + gap[0] * 0.5 + margin[0]) * xscale
115                                 p[1] = (p[1] - box[5] + box[1] + gap[1] * 0.5 + margin[1]) * yscale
116
117                                 xmin = min(xmin, p[0])
118                                 xmax = max(xmax, p[0])
119                                 ymin = min(ymin, p[1])
120                                 ymax = max(ymax, p[1])
121
122                 drawrect(xmin, ymin, xmax, ymax, (random.randint(128, 255), random.randint(128, 255),
123                                 random.randint(128, 255), 255))
124         Blender.Window.DrawProgressBar(1.0, "Finished")
125
126
127
128 editmode = Blender.Window.EditMode()
129 if editmode:
130         Blender.Window.EditMode(0)
131
132 try:
133         print "box packing ..."
134         pack()
135         print "done\n"
136 except Abort, e:
137         Blender.Draw.PupMenu("Error%t|" + e.msg)
138         print "Error:", e.msg, " -> aborting ...\n"
139
140 if editmode:
141         Blender.Window.EditMode(1)
142
143