diff --git a/README.md b/README.md index b220122..e06c78b 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,20 @@ Non-ASCII version: ![Screenshot](documentation/wire_skin_demo1.png?raw=true "Screenshot") +## Installation + +This software works with Blender 2.8 and earlier versions too. + +Check out the repository and look in the demo directory. + +This software may also be installed via pip: + +python3 -m pip install wire_skin + +or + +pip3 install wire_skin + ## Motivation Blender has a skin modifier that does great things for a lot of meshes. It doesn't seem to do the right thing for some of the sorts of meshes I want 3D printed (usually the caps where the vertices are have an asymmetry that is displeasing to me). The meshes I am trying to create are typically geometric cages for presenting other 3D objects. diff --git a/wire_skin_demo.blend b/demo/wire_skin_demo.blend similarity index 95% rename from wire_skin_demo.blend rename to demo/wire_skin_demo.blend index 9b91702..1445d62 100644 Binary files a/wire_skin_demo.blend and b/demo/wire_skin_demo.blend differ diff --git a/demo/wire_skin_demo.py b/demo/wire_skin_demo.py new file mode 100644 index 0000000..152becf --- /dev/null +++ b/demo/wire_skin_demo.py @@ -0,0 +1,182 @@ +# Don't run me directly! +# Take a look at wire_skin_demo.blend + +import bpy +import sys +from importlib import reload + +# Get wire_skin from current directory +sys.path.append(bpy.path.abspath("//")) + +import wire_skin +reload(wire_skin) + +from wire_skin import WireSkin + +def main(): + # A bunch of layers have demos + + # Generic mesh + layer1() + + # Creased mesh + layer2() + + # Spiky mesh + layer3() + + # Generating multiple from same wire + layer4() + + # Displace with booleans + layer5() + + # Torus made of hexagons + layer6() + + # Torus made of hexagons, proportial scale + layer7() + + # 'Edges without poles' option + layer8() + +def wire_to_skin(in_name, out_name, **kwargs): + input_object = bpy.data.objects[in_name] + output_object = bpy.data.objects[out_name] + output_materials = output_object.data.materials + + wire_skin = \ + WireSkin(input_object.data, **kwargs) + + me = wire_skin.create_mesh() + for material in output_materials: + me.materials.append(material) + output_object.data = me + +def layer1(): + options = { + 'width': 0.15, + 'height': 0.1, + 'inside_radius': 0.3, + 'outside_radius': 0.8, + 'dist': 0.4 + } + wire_to_skin("Wire1", "WireSkin1", **options) + +def layer2(): + options = { + 'width': 0.1, + 'height': 0.2, + 'inside_radius': 0.1, + 'outside_radius': 0.1, + 'dist': 0.2, + 'crease': 1.0 + } + wire_to_skin("Wire2", "WireSkin2", **options) + +def layer3(): + options = { + 'width': 0.1, + 'height': 0.2, + 'inside_radius': 0.1, + 'outside_radius': 0.8, + 'dist': 0.2, + } + wire_to_skin("Wire3", "WireSkin3", **options) + +def layer4(): + options = { + 'width': 0.5, + 'height': 0.2, + 'inside_radius': 0.1, + 'outside_radius': 0.1, + 'dist': 0.8, + } + wire_to_skin("Wire4", "WireSkin4", **options) + + options = { + 'width': 0.3, + 'height': 0.3, + 'inside_radius': 0.1, + 'outside_radius': 0.1, + 'dist': 0.8, + } + wire_to_skin("Wire4", "WireSkin4a", **options) + + options = { + 'width': 0.1, + 'height': 0.4, + 'inside_radius': 0.1, + 'outside_radius': 0.1, + 'dist': 0.8, + } + wire_to_skin("Wire4", "WireSkin4b", **options) + +def layer5(): + options = { + 'width': 0.5, + 'height': 0.3, + 'inside_radius': 0.1, + 'outside_radius': 0.1, + 'dist': 1.0, + 'crease': 1.0 + } + wire_to_skin("Wire5", "WireSkin5", **options) + + # This one is on layer 15 + # It is subtracted from previous object + options = { + 'width': 0.3, + 'height': 0.3, + 'inside_radius': 0.1, + 'outside_radius': 0.1, + 'dist': 0.8, + 'crease': 1.0, + 'displace': 0.15 + } + wire_to_skin("Wire5", "WireSkin5a", **options) + + options = { + 'width': 0.05, + 'height': 0.3, + 'inside_radius': 0.1, + 'outside_radius': 0.1, + 'dist': 0.8, + 'crease': 1.0, + } + wire_to_skin("Wire5", "WireSkin5b", **options) + +def layer6(): + options = { + 'width': 0.07, + 'height': 0.05, + 'inside_radius': 0.04, + 'outside_radius': 0.02, + 'dist': 0.025 + } + wire_to_skin("Wire6", "WireSkin6", **options) + +def layer7(): + options = { + 'width': 0.3, + 'height': 0.3, + 'inside_radius': 0.2, + 'outside_radius': 0.1, + 'dist': 0.3, + 'proportional_scale': True + } + wire_to_skin("Wire7", "WireSkin7", **options) + +def layer8(): + options = { + 'width': 0.15, + 'height': 0.1, + 'inside_radius': 0.3, + 'outside_radius': 0.8, + 'dist': 0.4 + } + wire_to_skin("Wire8", "WireSkin8", **options) + options['edges_without_poles'] = True + wire_to_skin("Wire8", "WireSkin8a", **options) + +main() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..c73f235 --- /dev/null +++ b/setup.py @@ -0,0 +1,43 @@ +from setuptools import setup, find_packages + +long_description = ''' +======================================================================= +wire_skin: construct a simple skin around a wire frame mesh in Blender. +======================================================================= + +Please visit the Github repository for documentation: + +``_ + +Either checkout the code from the Github project, or install via pip:: + + python3 -m pip install wire_skin + +or:: + + pip3 install wire_skin + +'''[1:-1] + +setup( + name='wire_skin', + version='0.3', + description='Construct a simple skin around a wire frame mesh in Blender.', + long_description=long_description, + url='https://github.com/cwant/wire_skin', + author='Chris Want', + classifiers=['Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'Intended Audience :: Manufacturing', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Programming Language :: Python :: 3 :: Only', + 'Topic :: Artistic Software', + 'Topic :: Multimedia :: Graphics :: 3D Modeling', + 'Topic :: Scientific/Engineering :: Mathematics', + 'Topic :: Scientific/Engineering :: Visualization'], + keywords='skin wire frame modeling blender', + packages=find_packages(exclude=['tests', 'demo']), + python_requires='~=3.5' +) diff --git a/wire_skin/__init__.py b/wire_skin/__init__.py new file mode 100644 index 0000000..9fd9775 --- /dev/null +++ b/wire_skin/__init__.py @@ -0,0 +1 @@ +from .wire_skin import WireSkin diff --git a/wire_skin.py b/wire_skin/wire_skin.py similarity index 97% rename from wire_skin.py rename to wire_skin/wire_skin.py index 40329ea..82459d2 100644 --- a/wire_skin.py +++ b/wire_skin/wire_skin.py @@ -60,6 +60,19 @@ def __init__(self, v, bm, **kwargs): self.creased_edges = [] + # Gee whiz, I can't believe I have to do this ... + blender_version = float(bpy.app.version_string.split()[0]) + if (blender_version < 2.8): + self.mult = self.mult_27 + else: + self.mult = self.mult_28 + + def mult_27(self, x, y): + return x * y + + def mult_28(self, x, y): + return x @ y + def add_edge_vert(self, edge, v): vec = Vector(v.co) edge_vert = { 'v': vec, @@ -115,7 +128,7 @@ def least_squares_normal(self, vave, diffs): a = (yz*xy - xz*yy) / det_z b = (xz*xy - yz*xx) / det_z normal = Vector((a, b, 1.0)) - if vave * normal < 0.0: + if self.mult(vave, normal) < 0.0: return -normal return normal @@ -207,7 +220,7 @@ def reorder_edge_verts(self): theta_edge_verts = {} for i in range(1, len(self.input_edge_verts)): edge_vert = self.input_edge_verts[i]['v'] - v = mat * (edge_vert - self.input_vert) + v = self.mult(mat, edge_vert - self.input_vert) theta = atan2(v[1], v[0]) if theta < 0.0: theta += 2 * pi