Import_3ds: Improved distance cue node setup
[blender-addons.git] / add_mesh_extra_objects / add_mesh_menger_sponge.py
blobbffce48f4f8b393e0ac6428d7756a1092058de22
1 # SPDX-FileCopyrightText: 2015 Sugiany
3 # SPDX-License-Identifier: MIT
5 import bpy
7 from bpy_extras.object_utils import (
8 AddObjectHelper,
9 object_data_add,
12 from bpy.props import (
13 IntProperty,
14 BoolProperty,
15 BoolVectorProperty,
16 FloatVectorProperty,
17 FloatProperty,
20 import mathutils
21 import copy
24 class MengerSponge(object):
25 FACE_INDICES = [
26 [3, 7, 4, 0],
27 [5, 6, 2, 1],
28 [1, 2, 3, 0],
29 [7, 6, 5, 4],
30 [4, 5, 1, 0],
31 [2, 6, 7, 3],
34 def __init__(self, level):
35 self.__level = level
36 self.__max_point_number = 3 ** level
37 self.__vertices_map = {}
38 self.__indices = []
39 self.__face_visibility = {}
40 self.__faces = []
42 for x in range(3):
43 for y in range(3):
44 for z in range(3):
45 self.__face_visibility[(x, y, z)] = [
46 x == 0 or x == 2 and (y == 1 or z == 1),
47 x == 2 or x == 0 and (y == 1 or z == 1),
48 y == 0 or y == 2 and (x == 1 or z == 1),
49 y == 2 or y == 0 and (x == 1 or z == 1),
50 z == 0 or z == 2 and (y == 1 or x == 1),
51 z == 2 or z == 0 and (y == 1 or x == 1),
54 def create(self, width, height):
55 m = self.__max_point_number
56 points = [
57 (0, 0, 0),
58 (m, 0, 0),
59 (m, 0, m),
60 (0, 0, m),
61 (0, m, 0),
62 (m, m, 0),
63 (m, m, m),
64 (0, m, m),
66 self.__make_sub_sponge(points, None, self.__level)
67 vertices = self.__make_vertices(width, height)
68 return vertices, self.__faces
70 def __get_vindex(self, p):
71 if p in self.__vertices_map:
72 return self.__vertices_map[p]
73 index = len(self.__vertices_map)
74 self.__vertices_map[p] = index
75 return index
77 def __make_vertices(self, width, height):
78 vertices = [None] * len(self.__vertices_map)
79 w2 = width / 2
80 h2 = height / 2
81 w_step = width / self.__max_point_number
82 h_step = height / self.__max_point_number
83 for p, i in sorted(self.__vertices_map.items(), key=lambda x: x[1]):
84 vertices[i] = mathutils.Vector([
85 p[0] * w_step - w2,
86 p[1] * w_step - w2,
87 p[2] * h_step - h2,
89 return vertices
91 def __make_sub_sponge(self, cur_points, face_vis, depth):
92 if depth <= 0:
93 if not face_vis:
94 face_vis = [True] * 6
95 cur_point_indices = []
96 for p in cur_points:
97 cur_point_indices.append(self.__get_vindex(p))
98 for i, vis in enumerate(face_vis):
99 if vis:
100 f = []
101 for vi in self.FACE_INDICES[i]:
102 f.append(cur_point_indices[vi])
103 self.__faces.append(f)
104 return
106 base = cur_points[0]
107 width = (cur_points[1][0] - base[0]) / 3
108 local_vert_map = {}
109 for z in range(4):
110 for y in range(4):
111 for x in range(4):
112 local_vert_map[(x, y, z)] = (
113 width * x + base[0],
114 width * y + base[1],
115 width * z + base[2],
118 for x in range(3):
119 for y in range(3):
120 for z in range(3):
121 if [x, y, z].count(1) > 1:
122 continue
123 next_points = [
124 local_vert_map[(x, y, z)],
125 local_vert_map[(x + 1, y, z)],
126 local_vert_map[(x + 1, y, z + 1)],
127 local_vert_map[(x, y, z + 1)],
128 local_vert_map[(x, y + 1, z)],
129 local_vert_map[(x + 1, y + 1, z)],
130 local_vert_map[(x + 1, y + 1, z + 1)],
131 local_vert_map[(x, y + 1, z + 1)],
133 visibility = copy.copy(self.__face_visibility[(x, y, z)])
134 if face_vis:
135 visibility[0] = visibility[0] and (face_vis[0] or x != 0)
136 visibility[1] = visibility[1] and (face_vis[1] or x != 2)
137 visibility[2] = visibility[2] and (face_vis[2] or y != 0)
138 visibility[3] = visibility[3] and (face_vis[3] or y != 2)
139 visibility[4] = visibility[4] and (face_vis[4] or z != 0)
140 visibility[5] = visibility[5] and (face_vis[5] or z != 2)
141 self.__make_sub_sponge(
142 next_points,
143 visibility,
144 depth - 1)
147 class AddMengerSponge(bpy.types.Operator, AddObjectHelper):
148 bl_idname = "mesh.menger_sponge_add"
149 bl_label = "Menger Sponge"
150 bl_description = "Construct a menger sponge mesh"
151 bl_options = {'REGISTER', 'UNDO'}
153 level: IntProperty(
154 name="Level",
155 description="Sponge Level",
156 min=0, max=4,
157 default=1,
159 radius: FloatProperty(
160 name="Width",
161 description="Sponge Radius",
162 min=0.01, max=100.0,
163 default=1.0,
165 layers: BoolVectorProperty(
166 name="Layers",
167 size=20,
168 subtype='LAYER',
169 options={'HIDDEN', 'SKIP_SAVE'},
172 def execute(self, context):
173 sponger = MengerSponge(self.level)
174 vertices, faces = sponger.create(self.radius * 2, self.radius * 2)
175 del sponger
177 mesh = bpy.data.meshes.new(name='Sponge')
178 mesh.from_pydata(vertices, [], faces)
179 uvs = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)]
180 mesh.uv_layers.new()
181 for i, uvloop in enumerate(mesh.uv_layers.active.data):
182 uvloop.uv = uvs[i % 4]
184 object_data_add(context, mesh, operator=self)
186 return {'FINISHED'}