forked from blender/blender-addons
-
Notifications
You must be signed in to change notification settings - Fork 0
/
export_uv_png.py
119 lines (91 loc) · 3.35 KB
/
export_uv_png.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# SPDX-FileCopyrightText: 2011-2023 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
import gpu
from mathutils import Matrix
from mathutils.geometry import tessellate_polygon
from gpu_extras.batch import batch_for_shader
# Use OIIO if available, else Blender for writing the image.
try:
import OpenImageIO as oiio
except ImportError:
oiio = None
def export(filepath, tile, face_data, colors, width, height, opacity):
offscreen = gpu.types.GPUOffScreen(width, height)
offscreen.bind()
try:
fb = gpu.state.active_framebuffer_get()
fb.clear(color=(0.0, 0.0, 0.0, 0.0))
draw_image(tile, face_data, opacity)
pixel_data = fb.read_color(0, 0, width, height, 4, 0, 'UBYTE')
pixel_data.dimensions = width * height * 4
save_pixels(filepath, pixel_data, width, height)
finally:
offscreen.unbind()
offscreen.free()
def draw_image(tile, face_data, opacity):
gpu.state.blend_set('ALPHA')
with gpu.matrix.push_pop():
gpu.matrix.load_matrix(get_normalize_uvs_matrix(tile))
gpu.matrix.load_projection_matrix(Matrix.Identity(4))
draw_background_colors(face_data, opacity)
draw_lines(face_data)
gpu.state.blend_set('NONE')
def get_normalize_uvs_matrix(tile):
'''matrix maps x and y coordinates from [0, 1] to [-1, 1]'''
matrix = Matrix.Identity(4)
matrix.col[3][0] = -1 - (tile[0] * 2)
matrix.col[3][1] = -1 - (tile[1] * 2)
matrix[0][0] = 2
matrix[1][1] = 2
# OIIO writes arrays from the left-upper corner.
if oiio:
matrix.col[3][1] *= -1.0
matrix[1][1] *= -1.0
return matrix
def draw_background_colors(face_data, opacity):
coords = [uv for uvs, _ in face_data for uv in uvs]
colors = [(*color, opacity) for uvs, color in face_data for _ in range(len(uvs))]
indices = []
offset = 0
for uvs, _ in face_data:
triangles = tessellate_uvs(uvs)
indices.extend([index + offset for index in triangle] for triangle in triangles)
offset += len(uvs)
shader = gpu.shader.from_builtin('FLAT_COLOR')
batch = batch_for_shader(
shader, 'TRIS',
{"pos": coords, "color": colors},
indices=indices,
)
batch.draw(shader)
def tessellate_uvs(uvs):
return tessellate_polygon([uvs])
def draw_lines(face_data):
coords = []
for uvs, _ in face_data:
for i in range(len(uvs)):
start = uvs[i]
end = uvs[(i + 1) % len(uvs)]
coords.append((start[0], start[1]))
coords.append((end[0], end[1]))
shader = gpu.shader.from_builtin('POLYLINE_UNIFORM_COLOR')
shader.uniform_float("viewportSize", gpu.state.viewport_get()[2:])
shader.uniform_float("lineWidth", 1.0)
shader.uniform_float("color", (0.0, 0.0, 0.0, 1.0))
batch = batch_for_shader(shader, 'LINES', {"pos": coords})
batch.draw(shader)
def save_pixels(filepath, pixel_data, width, height):
if oiio:
spec = oiio.ImageSpec(width, height, 4, "uint8")
image = oiio.ImageOutput.create(filepath)
image.open(filepath, spec)
image.write_image(pixel_data)
image.close()
return
image = bpy.data.images.new("temp", width, height, alpha=True)
image.filepath = filepath
image.pixels = [v / 255 for v in pixel_data]
image.save()
bpy.data.images.remove(image)