Add Advanced Objects: Bump to ver. 0.1.3, Cleanup, Fixes

Bump version to 0.1.3
Cleanup - some style and UI modifications
Improved Tooltips, add missing descriptions
Menu and Panel Listing in the preferences
Move scene props to init for proper reg - unreg
Translate comments into English

Fix several bugs with scripts:
- Drop to ground: add missing poll for Drop all
- Cubester: fix sound generation, missing checks for data
move properties to __init__ together with the update functions
- Make Struts: add a try block allows the global undo to be
restored, fix division by zero error, add missing poll
- rope_alpha: fix several crashes with hardcoded names on re-runs
make the similation work for new scenes
- Circle array: fix (flawed attempt) check for allowed types
- Copy2: add check for properties passed, error handling, division by 0
on non mesh copy objects, add a missing poll
- Unfold Transition: fix polls for active objects, division by 0
add a warning about selecting an another armature
- oscurart_constellation: add a try block, move the prop to init
- easy_lattice: simplify enumproperty, polling
- Laplacian Lightning: prints are optional, API change to obj.raycast,
UI refactor, move winmgr props to scene properties
- add_light_template - try block, fix crash with constraints
and no camera in the scene
This commit is contained in:
Vuk Gardašević 2017-05-24 18:31:25 +02:00
parent 97bf32a8b8
commit 331f2982d7
26 changed files with 3302 additions and 2523 deletions

View File

@ -20,19 +20,18 @@
# meta-androcto, Bill Currie, Jorge Hernandez - Melenedez Jacob Morris, Oscurart #
# Rebellion, Antonis Karvelas, Eleanor Howick, lijenstina, Daniel Schalla, Domlysz #
# Unnikrishnan(kodemax), Florian Meyer, Omar ahmed, Brian Hinton (Nichod), liero #
# Dannyboy, Mano-Wii, Kursad Karatas, teldredge
# Atom, Dannyboy, Mano-Wii, Kursad Karatas, teldredge, Phil Cote #
bl_info = {
"name": "Add Advanced Objects",
"author": "Meta Androcto,",
"version": (0, 1, 1),
"version": (0, 1, 3),
"blender": (2, 78, 0),
"location": "View3D > Add ",
"description": "Add Object & Camera extras",
"warning": "",
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6"
"/Py/Scripts",
"tracker_url": "",
"category": "Object"}
if "bpy" in locals():
@ -64,46 +63,54 @@ if "bpy" in locals():
importlib.reload(oscurart_chain_maker)
else:
from . import (
add_light_template,
scene_objects_bi,
scene_objects_cycles,
scene_texture_render,
trilighting,
pixelate_3d,
object_add_chain,
oscurart_chain_maker,
drop_to_ground,
circle_array,
unfold_transition,
copy2,
make_struts,
random_box_structure,
cubester,
rope_alpha,
add_mesh_aggregate,
object_mangle_tools,
arrange_on_curve,
object_laplace_lightning,
mesh_easylattice
)
from .delaunay_voronoi import (
DelaunayVoronoi,
delaunayVoronoiBlender,
oscurart_constellation
)
from . import add_light_template
from . import scene_objects_bi
from . import scene_objects_cycles
from . import scene_texture_render
from . import trilighting
from . import pixelate_3d
from . import object_add_chain
from . import oscurart_chain_maker
from . import drop_to_ground
from . import circle_array
from . import unfold_transition
from . import copy2
from . import make_struts
from . import random_box_structure
from . import cubester
from . import rope_alpha
from . import add_mesh_aggregate
from . import object_mangle_tools
from . import arrange_on_curve
from . import object_laplace_lightning
from . import mesh_easylattice
from .delaunay_voronoi import DelaunayVoronoi
from .delaunay_voronoi import delaunayVoronoiBlender
from .delaunay_voronoi import oscurart_constellation
import bpy
from bpy.types import (
Menu,
AddonPreferences,
PropertyGroup,
)
from bpy.props import (
BoolProperty,
BoolVectorProperty,
EnumProperty,
FloatProperty,
FloatVectorProperty,
IntProperty,
StringProperty,
PointerProperty,
)
# Define the "Scenes" menu
class INFO_MT_scene_elements_add(Menu):
# Define the "scenes" menu
bl_idname = "INFO_MT_scene_elements"
bl_label = "Test scenes"
bl_label = "Test Scenes"
def draw(self, context):
layout = self.layout
@ -116,8 +123,8 @@ class INFO_MT_scene_elements_add(Menu):
text="Scene_Textures_Cycles")
# Define the "Lights" menu
class INFO_MT_mesh_lamps_add(Menu):
# Define the "lights" menu
bl_idname = "INFO_MT_scene_lamps"
bl_label = "Lighting Sets"
@ -130,8 +137,8 @@ class INFO_MT_mesh_lamps_add(Menu):
text="Add Tri Lighting")
# Define the "Chains" menu
class INFO_MT_mesh_chain_add(Menu):
# Define the "Chains" menu
bl_idname = "INFO_MT_mesh_chain"
bl_label = "Chains"
@ -142,47 +149,45 @@ class INFO_MT_mesh_chain_add(Menu):
layout.operator("mesh.primitive_oscurart_chain_add", icon="LINKED")
# Define the "Array" Menu
class INFO_MT_array_mods_add(Menu):
# Define the "array" menu
bl_idname = "INFO_MT_array_mods"
bl_label = "Array Mods"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
self.layout.menu("INFO_MT_mesh_chain", icon="LINKED")
layout.menu("INFO_MT_mesh_chain", icon="LINKED")
layout.operator("objects.circle_array_operator",
text="Circle Array", icon='MOD_ARRAY')
text="Circle Array", icon="MOD_ARRAY")
layout.operator("object.agregate_mesh",
text="Aggregate Mesh", icon='MOD_ARRAY')
obj = context.object
if obj.type in ['MESH',]:
layout.operator("mesh.copy2",
text="Copy To Vert/Edge", icon='MOD_ARRAY')
text="Aggregate Mesh", icon="MOD_ARRAY")
layout.operator("mesh.copy2",
text="Copy To Vert/Edge", icon="MOD_ARRAY")
# Define the "Blocks" Menu
class INFO_MT_quick_blocks_add(Menu):
# Define the "Blocks" menu
bl_idname = "INFO_MT_quick_tools"
bl_label = "Block Tools"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator('object.pixelate', icon='MESH_GRID')
obj = context.object
if obj.type in ['MESH',]:
layout.operator("mesh.generate_struts",
text="Struts", icon='GRID')
layout.operator("object.easy_lattice",
text="Easy Lattice", icon='MOD_LATTICE')
layout.operator("object.make_structure",
text="Random Boxes", icon='SEQ_SEQUENCER')
layout.operator("object.pixelate", icon="MESH_GRID")
layout.operator("mesh.generate_struts",
text="Struts", icon="GRID")
layout.operator("object.make_structure",
text="Random Boxes", icon="SEQ_SEQUENCER")
layout.operator("object.easy_lattice",
text="Easy Lattice", icon="MOD_LATTICE")
# Define the "Phsysics Tools" Menu
class INFO_MT_Physics_tools_add(Menu):
# Define the "mesh objects" menu
bl_idname = "INFO_MT_physics_tools"
bl_label = "Physics Tools"
@ -190,7 +195,7 @@ class INFO_MT_Physics_tools_add(Menu):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("object.drop_on_active",
text="Drop To Ground")
text="Drop To Ground", icon="SORTSIZE")
layout.operator("ball.rope",
text="Wrecking Ball", icon='PHYSICS')
layout.operator("clot.rope",
@ -211,22 +216,551 @@ def menu(self, context):
# Addons Preferences
class AddonPreferences(AddonPreferences):
class AdvancedObjPreferences(AddonPreferences):
bl_idname = __name__
show_menu_list = BoolProperty(
name="Menu List",
description="Show/Hide the Add Menu items",
default=False
)
show_panel_list = BoolProperty(
name="Panels List",
description="Show/Hide the Panel items",
default=False
)
def draw(self, context):
layout = self.layout
layout.label(text="----Add Menu Advanced----")
layout.label(text="Quick Tools:")
layout.label(text="Drop, Pixelate & Wrecking Ball")
layout.label(text="Array Mods:")
layout.label(text="Circle Array, Chains, Vert to Edge, Aggregate")
icon_1 = "TRIA_RIGHT" if not self.show_menu_list else "TRIA_DOWN"
box = layout.box()
box.prop(self, "show_menu_list", emboss=False, icon=icon_1)
if self.show_menu_list:
box.label(text="Items located in the Add Menu (default shortcut Ctrl + A):",
icon="LAYER_USED")
box.label(text="Test Scenes:", icon="LAYER_ACTIVE")
box.label(text="Scene Objects BI, Scene Objects Cycles, Scene Textures Cycles",
icon="LAYER_USED")
box.label(text="Lighting Sets:", icon="LAYER_ACTIVE")
box.label(text="Add Light Template, Add Tri Lighting", icon="LAYER_USED")
box.label(text="Array Mods:", icon="LAYER_ACTIVE")
box.label(text="Circle Array, Chains submenu, Copy Vert/Edge and Aggregate Mesh",
icon="LAYER_ACTIVE")
box.label(text="Chains Submenu - Add Chain, Chain to Bones",
icon="LAYER_ACTIVE")
box.label(text="Block Tools:", icon="LAYER_ACTIVE")
box.label(text="Pixelate Object, Struts, Random Boxes, Easy Lattice",
icon="LAYER_USED")
box.label(text="Physics Tools:", icon="LAYER_ACTIVE")
box.label(text="Drop to Ground, Wrecking Ball and Cloth Rope", icon="LAYER_USED")
icon_2 = "TRIA_RIGHT" if not self.show_panel_list else "TRIA_DOWN"
box = layout.box()
box.prop(self, "show_panel_list", emboss=False, icon=icon_2)
if self.show_panel_list:
box.label(text="Panels located in 3D View Tools Region > Create",
icon="LAYER_ACTIVE")
box.label(text="Drop to Ground", icon="LAYER_USED")
box.label(text="Unfold Transition", icon="LAYER_USED")
box.label(text="CubeSter", icon="LAYER_USED")
box.label(text="Mangle tools", icon="LAYER_USED")
box.label(text="Laplacian Lighting", icon="LAYER_USED")
box.label(text="Delaunay Voronoi", icon="LAYER_USED")
box.label(text="Duplicate on Curve (Shown if an Active Curve Object is it the 3D View)",
icon="LAYER_USED")
# Cubester update functions
def find_audio_length(self, context):
adv_obj = context.scene.advanced_objects
audio_file = adv_obj.cubester_audio_path
length = 0
if audio_file != "":
# confirm that strip hasn't been loaded yet
get_sequence = getattr(context.scene.sequence_editor, "sequences_all", [])
for strip in get_sequence:
if type(strip) == bpy.types.SoundSequence and strip.sound.filepath == audio_file:
length = strip.frame_final_duration
if length == 0:
area = context.area
old_type = area.type
area.type = "SEQUENCE_EDITOR"
try:
bpy.ops.sequencer.sound_strip_add(filepath=audio_file)
adv_obj.cubester_check_audio = True
except Exception as e:
print("\n[Add Advanced Objects]\n Function: "
"find_audio_length\n {}\n".format(e))
adv_obj.cubester_check_audio = False
pass
area.type = old_type
# find audio file
for strip in context.scene.sequence_editor.sequences_all:
if type(strip) == bpy.types.SoundSequence and strip.sound.filepath == audio_file:
adv_obj.cubester_check_audio = True
length = strip.frame_final_duration
adv_obj.cubester_audio_file_length = length
# load image if possible
def adjust_selected_image(self, context):
scene = context.scene.advanced_objects
try:
image = bpy.data.images.load(scene.cubester_load_image)
scene.cubester_image = image.name
except Exception as e:
print("\n[Add Advanced Objects]\n Function: "
"adjust_selected_image\n {}\n".format(e))
# load color image if possible
def adjust_selected_color_image(self, context):
scene = context.scene.advanced_objects
try:
image = bpy.data.images.load(scene.cubester_load_color_image)
scene.cubester_color_image = image.name
except Exception as e:
print("\nAdd Advanced Objects]\n Function: "
"adjust_selected_color_image\n {}\n".format(e))
class AdvancedObjProperties(PropertyGroup):
# cubester
# main properties
cubester_check_audio = BoolProperty(
name="",
default=False
)
cubester_audio_image = EnumProperty(
name="Input Type",
items=(("image", "Image",
"Use an Image as input for generating Geometry", "IMAGE_COL", 0),
("audio", "Audio",
"Use a Sound Strip as input for generating Geometry", "FILE_SOUND", 1))
)
cubester_audio_file_length = IntProperty(
default=0
)
# audio
cubester_audio_path = StringProperty(
default="",
name="Audio File",
subtype="FILE_PATH",
update=find_audio_length
)
cubester_audio_min_freq = IntProperty(
name="Minimum Frequency",
min=20, max=100000,
default=20
)
cubester_audio_max_freq = IntProperty(
name="Maximum Frequency",
min=21, max=999999,
default=5000
)
cubester_audio_offset_type = EnumProperty(
name="Offset Type",
items=(("freq", "Frequency Offset", ""),
("frame", "Frame Offset", "")),
description="Type of offset per row of mesh"
)
cubester_audio_frame_offset = IntProperty(
name="Frame Offset",
min=0, max=10,
default=2
)
cubester_audio_block_layout = EnumProperty(
name="Block Layout",
items=(("rectangle", "Rectangular", ""),
("radial", "Radial", ""))
)
cubester_audio_width_blocks = IntProperty(
name="Width Block Count",
min=1, max=10000,
default=5
)
cubester_audio_length_blocks = IntProperty(
name="Length Block Count",
min=1, max=10000,
default=50
)
# image
cubester_load_type = EnumProperty(
name="Image Input Type",
items=(("single", "Single Image", ""),
("multiple", "Image Sequence", ""))
)
cubester_image = StringProperty(
default="",
name=""
)
cubester_load_image = StringProperty(
default="",
name="Load Image",
subtype="FILE_PATH",
update=adjust_selected_image
)
cubester_skip_images = IntProperty(
name="Image Step",
min=1, max=30,
default=1,
description="Step from image to image by this number"
)
cubester_max_images = IntProperty(
name="Max Number Of Images",
min=2, max=1000,
default=10,
description="Maximum number of images to be used"
)
cubester_frame_step = IntProperty(
name="Frame Step Size",
min=1, max=10,
default=4,
description="The number of frames each picture is used"
)
cubester_skip_pixels = IntProperty(
name="Skip # Pixels",
min=0, max=256,
default=64,
description="Skip this number of pixels before placing the next"
)
cubester_mesh_style = EnumProperty(
name="Mesh Type",
items=(("blocks", "Blocks", ""),
("plane", "Plane", "")),
description="Compose mesh of multiple blocks or of a single plane"
)
cubester_block_style = EnumProperty(
name="Block Style",
items=(("size", "Vary Size", ""),
("position", "Vary Position", "")),
description="Vary Z-size of block, or vary Z-position"
)
cubester_height_scale = FloatProperty(
name="Height Scale",
subtype="DISTANCE",
min=0.1, max=2,
default=0.2
)
cubester_invert = BoolProperty(
name="Invert Height",
default=False
)
# general adjustments
cubester_size_per_hundred_pixels = FloatProperty(
name="Size Per 100 Blocks/Points",
subtype="DISTANCE",
min=0.001, max=5,
default=1
)
# material based stuff
cubester_materials = EnumProperty(
name="Material",
items=(("vertex", "Vertex Colors", ""),
("image", "Image", "")),
description="Color with vertex colors, or uv unwrap and use an image"
)
cubester_use_image_color = BoolProperty(
name="Use Original Image Colors'?",
default=True,
description="Use original image colors, or replace with an another one"
)
cubester_color_image = StringProperty(
default="",
name=""
)
cubester_load_color_image = StringProperty(
default="",
name="Load Color Image",
subtype="FILE_PATH",
update=adjust_selected_color_image
)
cubester_vertex_colors = {}
# advanced
cubester_advanced = BoolProperty(
name="Advanced Options",
default=False
)
cubester_random_weights = BoolProperty(
name="Random Weights",
default=False
)
cubester_weight_r = FloatProperty(
name="Red",
subtype="FACTOR",
min=0.01, max=1.0,
default=0.25
)
cubester_weight_g = FloatProperty(
name="Green",
subtype="FACTOR",
min=0.01, max=1.0,
default=0.25
)
cubester_weight_b = FloatProperty(
name="Blue",
subtype="FACTOR",
min=0.01, max=1.0,
default=0.25
)
cubester_weight_a = FloatProperty(
name="Alpha",
subtype="FACTOR",
min=0.01, max=1.0,
default=0.25
)
# pixelate_3d properties
pixelate_3d_size = FloatProperty(
name="Size",
min=.05, max=5,
default=.25,
description="Size of the cube / grid"
)
pixelate_3d_gap = IntProperty(
name="Gap",
min=0, max=90,
default=10,
subtype='PERCENTAGE',
description="Separation - percent of size"
)
pixelate_3d_smooth = FloatProperty(
name="Smooth",
min=0, max=1,
default=.0,
description="Smooth factor when subdividing mesh"
)
# arrange_on_curve
arrange_c_use_selected = BoolProperty(
name="Use Selected",
description="Use the selected objects to duplicate",
default=True,
)
arrange_c_obj_arranjar = StringProperty(
name=""
)
arrange_c_select_type = EnumProperty(
name="Type",
description="Select object or group",
items=[
('O', "Object", "Make duplicates of a specific object"),
('G', "Group", "Make duplicates of the objects in a group"),
],
default='O',
)
# object_laplace_lighting props
ORIGIN = FloatVectorProperty(
name="Origin charge"
)
GROUNDZ = IntProperty(
name="Ground Z coordinate"
)
HORDER = IntProperty(
name="Secondary paths orders",
default=1
)
# object_laplace_lighting UI props
TSTEPS = IntProperty(
name="Iterations",
default=350,
description="Number of cells to create\n"
"Will end early if hits ground plane or cloud"
)
GSCALE = FloatProperty(
name="Grid unit size",
default=0.12,
description="scale of cells, .25 = 4 cells per blenderUnit"
)
BIGVAR = FloatProperty(
name="Straightness",
default=6.3,
description="Straightness/branchiness of bolt, \n"
"<2 is mush, >12 is staight line, 6.3 is good"
)
GROUNDBOOL = BoolProperty(
name="Use Ground object",
description="Use ground plane or not",
default=True
)
GROUNDC = IntProperty(
name="Ground charge",
default=-250,
description="Charge of the ground plane"
)
CLOUDBOOL = BoolProperty(
name="Use Cloud object",
default=False,
description="Use cloud object - attracts and terminates like ground but\n"
"any obj instead of z plane\n"
"Can slow down loop if obj is large, overrides ground"
)
CLOUDC = IntProperty(
name="Cloud charge",
default=-1,
description="Charge of a cell in cloud object\n"
"(so total charge also depends on obj size)"
)
VMMESH = BoolProperty(
name="Multi mesh",
default=True,
description="Output to multi-meshes for different materials on main/sec/side branches"
)
VSMESH = BoolProperty(
name="Single mesh",
default=False,
description="Output to single mesh for using build modifier and particles for effects"
)
VCUBE = BoolProperty(
name="Cubes",
default=False,
description="CTRL-J after run to JOIN\n"
"Outputs a bunch of cube objects, mostly for testing"
)
VVOX = BoolProperty(
name="Voxel (experimental)",
default=False,
description="Output to a voxel file to bpy.data.filepath\FSLGvoxels.raw\n"
"(doesn't work well right now)"
)
IBOOL = BoolProperty(
name="Use Insulator object",
default=False,
description="Use insulator mesh object to prevent growth of bolt in areas"
)
OOB = StringProperty(
name="Select",
default="",
description="Origin of bolt, can be an Empty\n"
"if object is a mesh will use all verts as charges")
GOB = StringProperty(
name="Select",
default="",
description="Object to use as ground plane, uses z coord only"
)
COB = StringProperty(
name="Select",
default="",
description="Object to use as cloud, best to use a cube"
)
IOB = StringProperty(
name="Select",
default="",
description="Object to use as insulator, 'voxelized'\n"
"before generating bolt (can be slow)"
)
# object_mangle_tools properties
mangle_constraint_vector = BoolVectorProperty(
name="Mangle Constraint",
default=(True, True, True),
subtype='XYZ',
description="Constrains Mangle Direction"
)
mangle_random_magnitude = IntProperty(
name="Mangle Severity",
default=5,
min=1, max=30,
description="Severity of mangling"
)
mangle_name = StringProperty(
name="Shape Key Name",
default="mangle",
description="Name given for mangled shape keys"
)
# unfold_transition properties
unfold_arm_name = StringProperty(
default=""
)
unfold_modo = EnumProperty(
name="",
items=[("cursor", "3D Cursor", "Use the Distance to 3D Cursor"),
("weight", "Weight Map", "Use a Painted Weight map"),
("index", "Mesh Indices", "Use Faces and Vertices index")],
description="How to Sort Bones for animation", default="cursor"
)
unfold_flip = BoolProperty(
name="Flipping Faces",
default=False,
description="Rotate faces around the Center and skip Scaling - "
"keep checked for both operators"
)
unfold_fold_duration = IntProperty(
name="Total Time",
min=5, soft_min=25,
max=10000, soft_max=2500,
default=200,
description="Total animation length"
)
unfold_sca_time = IntProperty(
name="Scale Time",
min=1,
max=5000, soft_max=500,
default=10,
description="Faces scaling time"
)
unfold_rot_time = IntProperty(
name="Rotation Time",
min=1, soft_min=5,
max=5000, soft_max=500,
default=15,
description="Faces rotation time"
)
unfold_rot_max = IntProperty(
name="Angle",
min=-180,
max=180,
default=135,
description="Faces rotation angle"
)
unfold_fold_noise = IntProperty(
name="Noise",
min=0,
max=500, soft_max=50,
default=0,
description="Offset some faces animation"
)
unfold_bounce = FloatProperty(
name="Bounce",
min=0,
max=10, soft_max=2.5,
default=0,
description="Add some bounce to rotation"
)
unfold_from_point = BoolProperty(
name="Point",
default=False,
description="Scale faces from a Point instead of from an Edge"
)
unfold_wiggle_rot = BoolProperty(
name="Wiggle",
default=False,
description="Use all Axis + Random Rotation instead of X Aligned"
)
# oscurart_constellation
constellation_limit = FloatProperty(
name="Inital Threshold",
description="Edges will be created only if the distance\n"
"between vertices is smaller than this value\n"
"This is a starting value on Operator Invoke",
default=2,
min=0
)
def register():
object_mangle_tools.register()
arrange_on_curve.register()
bpy.utils.register_module(__name__)
bpy.types.Scene.advanced_objects = PointerProperty(
type=AdvancedObjProperties
)
# Add "Extras" menu to the "Add" menu
bpy.types.INFO_MT_add.append(menu)
try:
@ -236,8 +770,6 @@ def register():
def unregister():
object_mangle_tools.unregister()
arrange_on_curve.unregister()
# Remove "Extras" menu from the "Add" menu.
bpy.types.INFO_MT_add.remove(menu)
try:
@ -246,6 +778,11 @@ def unregister():
pass
bpy.utils.unregister_module(__name__)
del bpy.types.Scene.advanced_objects
# cleanup Easy Lattice Scene Property if it was created
if hasattr(bpy.types.Scene, "activelatticeobject"):
del bpy.types.Scene.activelatticeobject
if __name__ == "__main__":

View File

@ -6,120 +6,129 @@ from bpy.props import BoolProperty
def add_lamps(self, context):
try:
if self.bKeyLight:
keyLight = bpy.data.lamps.new(name="Key_Light", type="SPOT")
ob = bpy.data.objects.new("Key_Light", keyLight)
constraint = ob.constraints.new(type='COPY_LOCATION')
constraint.use_offset = True
constraint.owner_space = 'LOCAL'
constraint.target = self.camera
constraint = ob.constraints.new(type='TRACK_TO')
constraint.target = self.target
constraint.track_axis = 'TRACK_NEGATIVE_Z'
constraint.up_axis = 'UP_X'
constraint.owner_space = 'LOCAL'
bpy.context.scene.objects.link(ob)
ob.rotation_euler[2] = -0.785398
if self.bFillLight:
fillLight = bpy.data.lamps.new(name="Fill_Light", type="SPOT")
ob = bpy.data.objects.new("Fill_Light", fillLight)
constraint = ob.constraints.new(type='COPY_LOCATION')
constraint.use_offset = True
constraint.owner_space = 'LOCAL'
constraint.target = self.camera
constraint = ob.constraints.new(type='TRACK_TO')
constraint.target = self.target
constraint.track_axis = 'TRACK_NEGATIVE_Z'
constraint.up_axis = 'UP_X'
constraint.owner_space = 'LOCAL'
bpy.context.scene.objects.link(ob)
ob.rotation_euler[2] = 0.785398
ob.data.energy = 0.3
if self.bKeyLight:
keyLight = bpy.data.lamps.new(name="Key_Light", type="SPOT")
ob = bpy.data.objects.new("Key_Light", keyLight)
constraint = ob.constraints.new(type='COPY_LOCATION')
constraint.use_offset = True
constraint.owner_space = 'LOCAL'
constraint.target = self.camera
constraint = ob.constraints.new(type='TRACK_TO')
constraint.target = self.target
constraint.track_axis = 'TRACK_NEGATIVE_Z'
constraint.up_axis = 'UP_X'
constraint.owner_space = 'LOCAL'
bpy.context.scene.objects.link(ob)
ob.rotation_euler[2] = -0.785398
if self.bBackLight:
backLight = bpy.data.lamps.new(name="Back_Light", type="SPOT")
ob = bpy.data.objects.new("Back_Light", backLight)
constraint = ob.constraints.new(type='COPY_LOCATION')
constraint.use_offset = True
constraint.owner_space = 'LOCAL'
constraint.target = self.camera
constraint = ob.constraints.new(type='TRACK_TO')
constraint.target = self.target
constraint.track_axis = 'TRACK_NEGATIVE_Z'
constraint.up_axis = 'UP_X'
constraint.owner_space = 'LOCAL'
bpy.context.scene.objects.link(ob)
ob.rotation_euler[2] = 3.14159
ob.data.energy = 0.2
if self.bFillLight:
fillLight = bpy.data.lamps.new(name="Fill_Light", type="SPOT")
ob = bpy.data.objects.new("Fill_Light", fillLight)
constraint = ob.constraints.new(type='COPY_LOCATION')
constraint.use_offset = True
constraint.owner_space = 'LOCAL'
constraint.target = self.camera
constraint = ob.constraints.new(type='TRACK_TO')
constraint.target = self.target
constraint.track_axis = 'TRACK_NEGATIVE_Z'
constraint.up_axis = 'UP_X'
constraint.owner_space = 'LOCAL'
bpy.context.scene.objects.link(ob)
ob.rotation_euler[2] = 0.785398
ob.data.energy = 0.3
if self.camera_constraint:
constraint = self.camera.constraints.new(type='TRACK_TO')
constraint.target = self.target
constraint.track_axis = 'TRACK_NEGATIVE_Z'
constraint.up_axis = 'UP_Y'
if self.bBackLight:
backLight = bpy.data.lamps.new(name="Back_Light", type="SPOT")
ob = bpy.data.objects.new("Back_Light", backLight)
constraint = ob.constraints.new(type='COPY_LOCATION')
constraint.use_offset = True
constraint.owner_space = 'LOCAL'
constraint.target = self.camera
constraint = ob.constraints.new(type='TRACK_TO')
constraint.target = self.target
constraint.track_axis = 'TRACK_NEGATIVE_Z'
constraint.up_axis = 'UP_X'
constraint.owner_space = 'LOCAL'
bpy.context.scene.objects.link(ob)
ob.rotation_euler[2] = 3.14159
ob.data.energy = 0.2
except Exception as e:
self.report({'WARNING'},
"Some operations could not be performed (See Console for more info)")
if self.camera_constraint and self.camera is not None and \
self.camera.type == "CAMERA":
print("\n[object.add_light_template]\nError: {}".format(e))
constraint = self.camera.constraints.new(type='TRACK_TO')
constraint.target = self.target
constraint.track_axis = 'TRACK_NEGATIVE_Z'
constraint.up_axis = 'UP_Y'
class OBJECT_OT_add_light_template(Operator):
bl_idname = "object.add_light_template"
bl_label = "Add Light Template"
bl_description = "Add Key, Fill & Back Lights"
bl_description = ("Add Key, Fill and Back Lights to the Scene\n"
"Needs an existing Active Object")
bl_options = {'REGISTER', 'UNDO'}
camera = None
target = None
bKeyLight = BoolProperty(
name="Key Light",
default=True
)
name="Key Light",
description="Enable Key Light in the Scene",
default=True
)
bFillLight = BoolProperty(
name="Fill Light",
default=True
)
name="Fill Light",
description="Enable Fill Light in the Scene",
default=True
)
bBackLight = BoolProperty(
name="Back Light",
default=True
)
name="Back Light",
description="Enable Back Light in the Scene",
default=True
)
camera_constraint = BoolProperty(
name="Camera Constraint",
default=False
)
name="Camera Constraint",
description="Add a Constraint to the Camera Object",
default=False
)
@classmethod
def poll(cls, context):
return context.active_object is not None
def execute(self, context):
objects = context.selected_objects
try:
objects = context.selected_objects
if len(objects) == 2:
for ob in objects:
if ob.type == 'CAMERA':
self.camera = ob
if len(objects) == 2:
for ob in objects:
if ob.type == 'CAMERA':
self.camera = ob
else:
self.target = ob
elif len(objects) == 1:
if objects[0].type == 'CAMERA':
self.camera = objects[0]
bpy.ops.object.empty_add()
self.target = context.active_object
else:
self.target = ob
elif len(objects) == 1:
if objects[0].type == 'CAMERA':
self.camera = objects[0]
self.camera = context.scene.camera
self.target = context.active_object
elif len(objects) == 0:
bpy.ops.object.empty_add()
self.target = context.active_object
else:
self.camera = context.scene.camera
self.target = context.active_object
elif len(objects) == 0:
bpy.ops.object.empty_add()
self.target = context.active_object
self.camera = context.scene.camera
add_lamps(self, context)
add_lamps(self, context)
except Exception as e:
self.report({'WARNING'},
"Some operations could not be performed (See Console for more info)")
print("\n[Add Advanced Objects]\nOperator: "
"object.add_light_template\nError: {}".format(e))
return {'FINISHED'}

View File

@ -72,107 +72,108 @@ class OBJECT_OT_agregate_mesh(Operator):
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
volX = FloatProperty(
name="Volume X",
min=0.1, max=25,
default=3,
description="The cloud around cursor"
)
name="Volume X",
min=0.1, max=25,
default=3,
description="The cloud around cursor"
)
volY = FloatProperty(
name="Volume Y",
min=0.1, max=25,
default=3,
description="The cloud around cursor"
)
name="Volume Y",
min=0.1, max=25,
default=3,
description="The cloud around cursor"
)
volZ = FloatProperty(
name="Volume Z",
min=0.1, max=25,
default=3,
description="The cloud around cursor"
)
name="Volume Z",
min=0.1, max=25,
default=3,
description="The cloud around cursor"
)
baseSca = FloatProperty(
name="Scale",
min=0.01, max=5,
default=.25,
description="Particle Scale"
)
name="Scale",
min=0.01, max=5,
default=.25,
description="Particle Scale"
)
varSca = FloatProperty(
name="Var",
min=0, max=1,
default=0,
description="Particle Scale Variation"
)
name="Var",
min=0, max=1,
default=0,
description="Particle Scale Variation"
)
rotX = FloatProperty(
name="Rot Var X",
min=0, max=2,
default=0,
description="X Rotation Variation"
)
name="Rot Var X",
min=0, max=2,
default=0,
description="X Rotation Variation"
)
rotY = FloatProperty(
name="Rot Var Y",
min=0, max=2,
default=0,
description="Y Rotation Variation"
)
name="Rot Var Y",
min=0, max=2,
default=0,
description="Y Rotation Variation"
)
rotZ = FloatProperty(
name="Rot Var Z",
min=0, max=2,
default=1,
description="Z Rotation Variation"
)
name="Rot Var Z",
min=0, max=2,
default=1,
description="Z Rotation Variation"
)
rSeed = IntProperty(
name="Random seed",
min=0, max=999999,
default=1,
description="Seed to feed random values"
)
name="Random seed",
min=0, max=999999,
default=1,
description="Seed to feed random values"
)
numP = IntProperty(
name="Number",
min=1,
max=9999, soft_max=500,
default=50,
description="Number of particles"
)
name="Number",
min=1,
max=9999, soft_max=500,
default=50,
description="Number of particles"
)
nor = BoolProperty(
name="Normal Oriented",
default=False,
description="Align Z axis with Faces normals"
)
name="Normal Oriented",
default=False,
description="Align Z axis with Faces normals"
)
cent = BoolProperty(
name="Use Face Center",
default=False,
description="Center on Faces"
)
name="Use Face Center",
default=False,
description="Center on Faces"
)
track = BoolProperty(
name="Cursor Follows",
default=False,
description="Cursor moves as structure grows / more compact results"
)
name="Cursor Follows",
default=False,
description="Cursor moves as structure grows / more compact results"
)
anim = BoolProperty(
name="Animatable",
default=False,
description="Sort faces so you can regrow with Build Modifier, materials are lost"
)
refresh = bpy.props.BoolProperty(
name="Update",
default=False
)
auto_refresh = bpy.props.BoolProperty(
name="Auto",
description="Auto update spline",
default=False
)
name="Animatable",
default=False,
description="Sort faces so you can regrow with Build Modifier, materials are lost"
)
refresh = BoolProperty(
name="Update",
default=False
)
auto_refresh = BoolProperty(
name="Auto",
description="Auto update spline",
default=False
)
def draw(self, context):
layout = self.layout
col = layout.column(align=True)
row = col.row(align=True)
if self.auto_refresh is False:
self.refresh = False
elif self.auto_refresh is True:
self.refresh = True
row.prop(self, 'auto_refresh', toggle=True, icon='AUTO')
row.prop(self, 'refresh', toggle=True, icon='FILE_REFRESH')
row.prop(self, "auto_refresh", toggle=True, icon="AUTO")
row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH")
col = layout.column(align=True)
col.separator()
@ -194,18 +195,20 @@ class OBJECT_OT_agregate_mesh(Operator):
col = layout.column(align=True)
col.prop(self, "rSeed", slider=False)
col.prop(self, "numP")
col = layout.column(align=True)
col.prop(self, "nor")
col.prop(self, "cent")
col.prop(self, "track")
col.prop(self, "anim")
row = layout.row(align=True)
row.prop(self, "nor")
row.prop(self, "cent")
col.prop(self, 'numP')
row = layout.row(align=True)
row.prop(self, "track")
row.prop(self, "anim")
@classmethod
def poll(cls, context):
return(len(bpy.context.selected_objects) > 1 and bpy.context.object.type == 'MESH')
return (len(bpy.context.selected_objects) > 1 and
bpy.context.object.type == 'MESH')
def invoke(self, context, event):
self.refresh = True
@ -227,8 +230,10 @@ class OBJECT_OT_agregate_mesh(Operator):
(0, 0, 0, 1))
)
if obj.matrix_world != mat:
self.report({'WARNING'}, "Apply transformations to Active Object first!")
self.report({'WARNING'},
"Please, Apply transformations to Active Object first")
return{'FINISHED'}
par = [o for o in bpy.context.selected_objects if o.type == 'MESH' and o != obj]
if not par:
return{'FINISHED'}
@ -296,9 +301,8 @@ class OBJECT_OT_agregate_mesh(Operator):
bme.to_mesh(obj.data)
remover(True)
newobj.data.user_clear()
bpy.data.meshes.remove(newobj.data)
# Note: foo.user_clear() is deprecated use do_unlink=True instead
bpy.data.meshes.remove(newobj.data, do_unlink=True)
else:
scn.objects.active = obj
@ -318,8 +322,6 @@ class OBJECT_OT_agregate_mesh(Operator):
if self.auto_refresh is False:
self.refresh = False
#elif self.auto_refresh is True:
# self.refresh = True
return{'FINISHED'}
@ -333,4 +335,4 @@ def unregister():
if __name__ == '__main__':
register()
register()

View File

@ -9,10 +9,12 @@ bl_info = {
"description": "Arrange objects along a curve",
"warning": "Select curve",
"wiki_url": "",
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
"category": "3D View"
}
# Note: scene properties are moved into __init__
# search for patterns advanced_objects and adv_obj
import bpy
import mathutils
from bpy.types import (
@ -20,11 +22,9 @@ from bpy.types import (
Panel,
)
from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
IntProperty,
StringProperty,
)
FLT_MIN = 0.004
@ -44,82 +44,90 @@ class PanelDupliCurve(Panel):
def draw(self, context):
layout = self.layout
layout.prop(context.scene, "use_selected")
if not context.scene.use_selected:
layout.prop(context.scene, "select_type", expand=True)
if context.scene.select_type == 'O':
adv_obj = context.scene.advanced_objects
layout.prop(adv_obj, "arrange_c_use_selected")
if not adv_obj.arrange_c_use_selected:
layout.prop(adv_obj, "arrange_c_select_type", expand=True)
if adv_obj.arrange_c_select_type == 'O':
layout.column(align=True).prop_search(
context.scene, "objeto_arranjar",
bpy.data, "objects"
)
elif context.scene.select_type == 'G':
adv_obj, "arrange_c_obj_arranjar",
bpy.data, "objects"
)
elif adv_obj.arrange_c_select_type == 'G':
layout.column(align=True).prop_search(
context.scene, "objeto_arranjar",
bpy.data, "groups"
)
adv_obj, "arrange_c_obj_arranjar",
bpy.data, "groups"
)
if context.object.type == 'CURVE':
layout.operator("object.arranjar_numa_curva", text="Arrange Objects")
class DupliCurve(Operator):
bl_idname = "object.arranjar_numa_curva"
bl_label = "Arrange Objects"
bl_label = "Arrange Objects along a Curve"
bl_description = "Arange chosen / selected objects along the Active Curve"
bl_options = {'REGISTER', 'UNDO'}
use_distance = EnumProperty(
items=[
("D", "Distance", "Objects are arranged depending on the distance", 0),
("Q", "Quantity", "Objects are arranged depending on the quantity", 1),
("R", "Range", "Objects are arranged uniformly between the corners", 2)
]
)
name="Arrangement",
items=[
("D", "Distance", "Objects are arranged depending on the distance", 0),
("Q", "Quantity", "Objects are arranged depending on the quantity", 1),
("R", "Range", "Objects are arranged uniformly between the corners", 2)
]
)
distance = FloatProperty(
name="Distance",
description="Distancia entre objetos",
default=1.0,
min=FLT_MIN,
soft_min=0.1,
unit='LENGTH',
)
name="Distance",
description="Distance between Objects",
default=1.0,
min=FLT_MIN,
soft_min=0.1,
unit='LENGTH',
)
object_qt = IntProperty(
name="Quantity",
description="Object amount.",
default=2,
min=0,
)
name="Quantity",
description="Object amount",
default=2,
min=0,
)
scale = FloatProperty(
name="Scale",
description="Object Scale",
default=1.0,
min=FLT_MIN,
unit='LENGTH',
name="Scale",
description="Object Scale",
default=1.0,
min=FLT_MIN,
unit='LENGTH',
)
Yaw = FloatProperty(
default=0.0,
name="X",
unit='ROTATION'
)
name="X",
description="Rotate around the X axis (Yaw)",
default=0.0,
unit='ROTATION'
)
Pitch = FloatProperty(
default=0.0,
name="Y",
unit='ROTATION'
)
default=0.0,
description="Rotate around the Y axis (Pitch)",
name="Y",
unit='ROTATION'
)
Roll = FloatProperty(
default=0.0,
name="Z",
unit='ROTATION'
)
default=0.0,
description="Rotate around the Z axis (Roll)",
name="Z",
unit='ROTATION'
)
max_angle = FloatProperty(
default=1.57079,
max=3.141592,
name="Angle",
unit='ROTATION'
)
default=1.57079,
max=3.141592,
name="Angle",
unit='ROTATION'
)
offset = FloatProperty(
default=0.0,
name="offset",
unit='LENGTH'
)
default=0.0,
name="Offset",
unit='LENGTH'
)
@classmethod
def poll(cls, context):
@ -191,7 +199,8 @@ class DupliCurve(Operator):
tmp_Gpoints.append(tuple(sp2))
sp2 = [lp]
except Exception as e:
print(e)
print("\n[Add Advanced Objects]\nOperator: "
"object.arranjar_numa_curva\nError: {}".format(e))
pass
sp2.append(p)
v1 = v2
@ -216,21 +225,25 @@ class DupliCurve(Operator):
curve = context.active_object
Gpoints, lengs = self.Glpoints(curve)
adv_obj = context.scene.advanced_objects
if context.scene.use_selected:
if adv_obj.arrange_c_use_selected:
G_Objeto = context.selected_objects
G_Objeto.remove(curve)
if not G_Objeto:
return {'CANCELLED'}
elif context.scene.select_type == 'O':
G_Objeto = bpy.data.objects[context.scene.objeto_arranjar],
elif context.scene.select_type == 'G':
G_Objeto = bpy.data.groups[context.scene.objeto_arranjar].objects
elif adv_obj.arrange_c_select_type == 'O':
G_Objeto = bpy.data.objects[adv_obj.arrange_c_obj_arranjar],
elif adv_obj.arrange_c_select_type == 'G':
G_Objeto = bpy.data.groups[adv_obj.arrange_c_obj_arranjar].objects
yawMatrix = mathutils.Matrix.Rotation(self.Yaw, 4, 'X')
pitchMatrix = mathutils.Matrix.Rotation(self.Pitch, 4, 'Y')
rollMatrix = mathutils.Matrix.Rotation(self.Roll, 4, 'Z')
max_angle = self.max_angle # is this used?
max_angle = self.max_angle # max_angle is called in Glpoints
if self.use_distance == "D":
dist = self.distance
@ -331,31 +344,11 @@ class DupliCurve(Operator):
def register():
bpy.utils.register_class(PanelDupliCurve)
bpy.utils.register_class(DupliCurve)
bpy.types.Scene.use_selected = BoolProperty(
name='Use Selected',
description='Use the selected objects to duplicate',
default=True,
)
bpy.types.Scene.objeto_arranjar = StringProperty(
name=""
)
bpy.types.Scene.select_type = EnumProperty(
name="Type",
description="Select object or group",
items=[
('O', "OBJECT", "make duplicates of a specific object"),
('G', "GROUP", "make duplicates of the objects in a group"),
],
default='O',
)
def unregister():
bpy.utils.unregister_class(PanelDupliCurve)
bpy.utils.unregister_class(DupliCurve)
del bpy.types.Scene.objeto_arranjar
del bpy.types.Scene.use_selected
del bpy.types.Scene.select_type
if __name__ == "__main__":

View File

@ -5,14 +5,13 @@
bl_info = {
"name": "Circle Array",
"author": "Antonis Karvelas",
"version": (1, 0),
"version": (1, 0, 1),
"blender": (2, 6, 7),
"location": "View3D > Object > Circle_Array",
"description": "Uses an existing array and creates an empty, "
"rotates it properly and makes a Circle Array",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Mesh"
}
@ -26,7 +25,10 @@ class Circle_Array(Operator):
bl_label = "Circle Array"
bl_idname = "objects.circle_array_operator"
bl_description = ("Creates an Array Modifier with offset empty object\n"
"Works with Mesh, Curve, Text & Surface")
"Works with Mesh, Curve, Text and Surface\n"
"Use an object with an existing Array modifier\n"
"or rotate the newly created Empty with the name pattern\n"
"EMPTY_C_Array_ if the Array doesn't exist (angle: 360/Count)")
@classmethod
def poll(cls, context):
@ -53,27 +55,52 @@ class Circle_Array(Operator):
return None
def execute(self, context):
is_allowed = True
try:
allowed_obj = ['MESH', 'CURVE', 'SURFACE', 'FONT']
if context.active_object.type not in allowed_obj:
for obj in context.selected_objects:
if obj.type not in allowed_obj:
is_allowed = False
break
if not is_allowed:
self.report(
{"WARNING"},
"Operation Cancelled. The active object is not of "
"Mesh, Curve, Surface or Font type"
"The Active/Selected objects are not of "
"Mesh, Curve, Surface or Font type. Operation Cancelled"
)
return {'CANCELLED'}
default_name = self.check_empty_name(context) or "EMPTY_C_Array"
bpy.ops.object.modifier_add(type='ARRAY')
if len(bpy.context.selected_objects) == 2:
list = bpy.context.selected_objects
active = list[0]
if len(context.selected_objects) == 2:
selected = context.selected_objects
lists = [obj for obj in selected if obj != context.active_object]
active = lists[0]
# check if the list object has a modifier
check_mod = None
for mod in active.modifiers[:]:
if mod.type == "ARRAY":
check_mod = mod
break
if check_mod:
check_mod.use_object_offset = True
check_mod.use_relative_offset = False
else:
# fallback
bpy.context.scene.objects.active = active
bpy.ops.object.modifier_add(type='ARRAY')
active.modifiers[0].use_object_offset = True
active.modifiers[0].use_relative_offset = False
active.modifiers[0].use_object_offset = True
active.modifiers[0].use_relative_offset = False
active.select = False
bpy.context.scene.objects.active = list[0]
bpy.context.scene.objects.active = context.active_object
bpy.ops.view3d.snap_cursor_to_selected()
if active.modifiers[0].offset_object is None:
bpy.ops.object.add(type='EMPTY')
empty_name = bpy.context.active_object
@ -98,6 +125,7 @@ class Circle_Array(Operator):
active.modifiers[0].use_object_offset = True
active.modifiers[0].use_relative_offset = False
bpy.ops.view3d.snap_cursor_to_selected()
if active.modifiers[0].offset_object is None:
bpy.ops.object.add(type='EMPTY')
empty_name = bpy.context.active_object
@ -116,6 +144,7 @@ class Circle_Array(Operator):
active.select = True
return {'FINISHED'}
except Exception as e:
self.report({'WARNING'},
"Circle Array operator could not be executed (See the console for more info)")
@ -125,18 +154,12 @@ class Circle_Array(Operator):
# Register
def circle_array_menu(self, context):
self.layout.operator(Circle_Array.bl_idname, text="Circle_Array")
def register():
bpy.utils.register_class(Circle_Array)
bpy.types.VIEW3D_MT_object.append(circle_array_menu)
def unregister():
bpy.utils.unregister_class(Circle_Array)
bpy.types.VIEW3D_MT_object.remove(circle_array_menu)
if __name__ == "__main__":

View File

@ -1,4 +1,4 @@
# ***** BEGIN GPL LICENSE BLOCK *****
# ##### 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
@ -15,12 +15,12 @@
# or write to the Free Software Foundation, Inc., 51 Franklin Street,
# Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENSE BLOCK *****
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "Copy2 vertices, edges or faces",
"name": "Copy2 Vertices, Edges or Faces",
"author": "Eleanor Howick (elfnor.com)",
"version": (0, 1),
"version": (0, 1, 1),
"blender": (2, 71, 0),
"location": "3D View > Object > Copy 2",
"description": "Copy one object to the selected vertices, edges or faces of another object",
@ -29,13 +29,23 @@ bl_info = {
}
import bpy
from mathutils import Vector, Matrix
from bpy.types import Operator
from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
)
from mathutils import (
Vector,
Matrix,
)
class Copy2(bpy.types.Operator):
class Copy2(Operator):
bl_idname = "mesh.copy2"
bl_label = "Copy 2"
bl_description = ("Copy Vertices, Edges or Faces to the Selected object\n"
"Needs an existing Active Mesh Object")
bl_options = {"REGISTER", "UNDO"}
obj_list = None
@ -45,84 +55,126 @@ class Copy2(bpy.types.Operator):
def sec_axes_list_cb(self, context):
if self.priaxes == 'X':
sec_list = [('Y', 'Y', 'Y'), ('Z', 'Z', 'Z')]
sec_list = [('Y', "Y", "Secondary axis Y"),
('Z', "Z", "Secondary axis Z")]
if self.priaxes == 'Y':
sec_list = [('X', 'X', 'X'), ('Z', 'Z', 'Z')]
sec_list = [('X', "X", "Secondary axis X"),
('Z', "Z", "Secondary axis Z")]
if self.priaxes == 'Z':
sec_list = [('X', 'X', 'X'), ('Y', 'Y', 'Y')]
sec_list = [('X', "X", "Secondary axis X"),
('Y', "Y", "Secondary axis Y")]
return sec_list
copytype = bpy.props.EnumProperty(items=(('V', '', 'paste to vertices', 'VERTEXSEL', 0),
('E', '', 'paste to edges', 'EDGESEL', 1),
('F', '', 'paste to faces', 'FACESEL', 2)),
description='where to paste to')
copytype = EnumProperty(
items=(('V', "Vertex",
"Paste the Copied Geometry to Vertices of the Active Object", 'VERTEXSEL', 0),
('E', "Edge",
"Paste the Copied Geometry to Edges of the Active Object", 'EDGESEL', 1),
('F', "Face",
"Paste the Copied Geometry to Faces of the Active Object", 'FACESEL', 2)),
)
copyfromobject = EnumProperty(
name="Copy from",
description="Copy an Object from the list",
items=obj_list_cb
)
priaxes = EnumProperty(
description="Primary axes used for Copied Object orientation",
items=(('X', "X", "Along X"),
('Y', "Y", "Along Y"),
('Z', "Z", "Along Z")),
)
edgescale = BoolProperty(
name="Scale to fill edge",
default=False
)
secaxes = EnumProperty(
name="Secondary Axis",
description="Secondary axis used for Copied Object orientation",
items=sec_axes_list_cb
)
scale = FloatProperty(
name="Scale",
default=1.0,
min=0.0,
)
copyfromobject = bpy.props.EnumProperty(items=obj_list_cb, name='Copy from:')
priaxes = bpy.props.EnumProperty(items=(('X', 'X', 'along X'),
('Y', 'Y', 'along Y'),
('Z', 'Z', 'along Z')),
)
edgescale = bpy.props.BoolProperty(name='Scale to fill edge?')
secaxes = bpy.props.EnumProperty(items=sec_axes_list_cb, name='Secondary Axis')
scale = bpy.props.FloatProperty(default=1.0, min=0.0, name='Scale')
@classmethod
def poll(cls, context):
obj = context.active_object
return obj and obj.type == "MESH"
def draw(self, context):
layout = self.layout
layout.prop(self, 'copyfromobject')
layout.prop(self, "copyfromobject")
layout.label("to:")
layout.prop(self, 'copytype', expand=True)
layout.label("primary axis:")
layout.prop(self, 'priaxes', expand=True)
layout.label("secondary axis:")
layout.prop(self, 'secaxes', expand=True)
if self.copytype == 'E':
layout.prop(self, 'edgescale')
layout.prop(self, "copytype", expand=True)
layout.label("Primary axis:")
layout.prop(self, "priaxes", expand=True)
layout.label("Secondary axis:")
layout.prop(self, "secaxes", expand=True)
if self.copytype == "E":
layout.prop(self, "edgescale")
if self.edgescale:
layout.prop(self, 'scale')
layout.prop(self, "scale")
return
def execute(self, context):
copytoobject = context.active_object.name
axes = self.priaxes + self.secaxes
copy_list = copy_to_from(context.scene,
bpy.data.objects[copytoobject],
bpy.data.objects[self.copyfromobject],
self.copytype,
axes,
self.edgescale,
self.scale)
# check if there is a problem with the strings related to some chars
copy_to_object = bpy.data.objects[copytoobject] if \
copytoobject in bpy.data.objects else None
copy_from_object = bpy.data.objects[self.copyfromobject] if \
self.copyfromobject in bpy.data.objects else None
if copy_to_object is None or copy_from_object is None:
self.report({"WARNING"},
"There was a problem with retrieving Object data. Operation Cancelled")
return {"CANCELLED"}
try:
copy_to_from(
context.scene,
copy_to_object,
copy_from_object,
self.copytype,
axes,
self.edgescale,
self.scale
)
except Exception as e:
self.report({"WARNING"},
"Copy2 could not be completed (Check the Console for more info)")
print("\n[Add Advanced Objects]\nOperator: mesh.copy2\n{}\n".format(e))
return {"CANCELLED"}
return {"FINISHED"}
def invoke(self, context, event):
Copy2.obj_list = [(obj.name, obj.name, obj.name) for obj in bpy.data.objects]
return {"FINISHED"}
# end Copy2 class
#---------------------------------------------------------------------------------------
def add_to_menu(self, context):
self.layout.operator(Copy2.bl_idname)
return
#-----------------------------------------------------------------
def copy_to_from(scene, to_obj, from_obj, copymode, axes, edgescale, scale):
if copymode == 'V':
copy_list = vertex_copy(scene, to_obj, from_obj, axes)
vertex_copy(scene, to_obj, from_obj, axes)
if copymode == 'E':
copy_list = edge_copy(scene, to_obj, from_obj, axes, edgescale, scale)
# don't pass edgescalling to object types that cannot be scaled
if from_obj.type in ["CAMERA", "LAMP", "EMPTY", "ARMATURE", "SPEAKER", "META"]:
edgescale = False
edge_copy(scene, to_obj, from_obj, axes, edgescale, scale)
if copymode == 'F':
copy_list = face_copy(scene, to_obj, from_obj, axes)
return copy_list
face_copy(scene, to_obj, from_obj, axes)
axes_dict = {'XY': (1, 2, 0),
'XZ': (2, 1, 0),
@ -133,9 +185,9 @@ axes_dict = {'XY': (1, 2, 0),
def copyto(scene, source_obj, pos, xdir, zdir, axes, scale=None):
"""
copy the source_obj to pos, so its primary axis points in zdir and its
secondary axis points in xdir
"""
copy the source_obj to pos, so its primary axis points in zdir and its
secondary axis points in xdir
"""
copy_obj = source_obj.copy()
scene.objects.link(copy_obj)
@ -161,7 +213,7 @@ def copyto(scene, source_obj, pos, xdir, zdir, axes, scale=None):
copy_obj.location = pos
# scale object
if scale != None:
if scale is not None:
copy_obj.scale = scale
return copy_obj
@ -171,8 +223,9 @@ def vertex_copy(scene, obj, source_obj, axes):
# vertex select mode
sel_verts = []
copy_list = []
for v in obj.data.vertices:
if v.select == True:
if v.select is True:
sel_verts.append(v)
# make a set for each vertex. The set contains all the connected vertices
@ -198,20 +251,22 @@ def vertex_copy(scene, obj, source_obj, axes):
copy = copyto(scene, source_obj, pos, xdir, zdir, axes)
copy_list.append(copy)
# select all copied objects
for copy in copy_list:
copy.select = True
obj.select = False
return copy_list
def edge_copy(scene, obj, source_obj, axes, es, scale):
# edge select mode
sel_edges = []
copy_list = []
for e in obj.data.edges:
if e.select == True:
if e.select is True:
sel_edges.append(e)
for e in sel_edges:
# pos is average of two edge vertexs
v0 = obj.data.vertices[e.vertices[0]].co * obj.matrix_world.transposed()
@ -222,10 +277,10 @@ def edge_copy(scene, obj, source_obj, axes, es, scale):
xlen = xdir.magnitude
xdir = xdir.normalized()
# project each edge vertex normal onto plane normal to xdir
vn0 = (obj.data.vertices[e.vertices[0]].co * obj.matrix_world.transposed()
+ obj.data.vertices[e.vertices[0]].normal) - v0
vn1 = (obj.data.vertices[e.vertices[1]].co * obj.matrix_world.transposed()
+ obj.data.vertices[e.vertices[1]].normal) - v1
vn0 = (obj.data.vertices[e.vertices[0]].co * obj.matrix_world.transposed() +
obj.data.vertices[e.vertices[0]].normal) - v0
vn1 = (obj.data.vertices[e.vertices[1]].co * obj.matrix_world.transposed() +
obj.data.vertices[e.vertices[1]].normal) - v1
vn0p = vn0 - vn0.dot(xdir) * xdir
vn1p = vn1 - vn1.dot(xdir) * xdir
# the mean of the two projected normals is the zdir
@ -239,20 +294,22 @@ def edge_copy(scene, obj, source_obj, axes, es, scale):
copy = copyto(scene, source_obj, pos, xdir, zdir, axes, scale=escale)
copy_list.append(copy)
# select all copied objects
for copy in copy_list:
copy.select = True
obj.select = False
return copy_list
def face_copy(scene, obj, source_obj, axes):
# face select mode
sel_faces = []
copy_list = []
for f in obj.data.polygons:
if f.select == True:
if f.select is True:
sel_faces.append(f)
for f in sel_faces:
fco = f.center * obj.matrix_world.transposed()
# get first vertex corner of transformed object
@ -263,25 +320,19 @@ def face_copy(scene, obj, source_obj, axes):
copy = copyto(scene, source_obj, fco, vco - fco, fn, axes)
copy_list.append(copy)
# select all copied objects
for copy in copy_list:
copy.select = True
obj.select = False
return copy_list
#-------------------------------------------------------------------
def register():
bpy.utils.register_module(__name__)
bpy.types.VIEW3D_MT_object.append(add_to_menu)
bpy.utils.register_class(Copy2)
def unregister():
bpy.types.VIEW3D_MT_object.remove(add_to_menu)
bpy.utils.unregister_module(__name__)
bpy.utils.unregister_class(Copy2)
if __name__ == "__main__":

View File

@ -19,10 +19,13 @@
# Original Author = Jacob Morris
# URL = blendingjacob.blogspot.com
# Note: scene properties are moved into __init__ together with the 3 update functions
# for properties search for the name patterns adv_obj and advanced_objects
bl_info = {
"name": "CubeSter",
"author": "Jacob Morris",
"version": (0, 7),
"version": (0, 7, 1),
"blender": (2, 78, 0),
"location": "View 3D > Toolbar > CubeSter",
"description": "Takes image, image sequence, or audio file and converts it "
@ -32,13 +35,6 @@ bl_info = {
import bpy
import bmesh
from bpy.props import (
BoolProperty,
IntProperty,
FloatProperty,
StringProperty,
EnumProperty,
)
from bpy.types import (
Operator,
Panel,
@ -53,29 +49,9 @@ from os import (
)
# load image if possible
def adjust_selected_image(self, context):
scene = context.scene
try:
image = bpy.data.images.load(scene.cubester_load_image)
scene.cubester_image = image.name
except RuntimeError:
self.report({"ERROR"}, "CubeSter: '{}' could not be loaded".format(scene.cubester_load_image))
# load color image if possible
def adjust_selected_color_image(self, context):
scene = context.scene
try:
image = bpy.data.images.load(scene.cubester_load_color_image)
scene.cubester_color_image = image.name
except RuntimeError:
self.report({"ERROR"}, "CubeSter: '{}' could not be loaded".format(scene.cubester_load_color_image))
# crate block at center position x, y with block width 2 * hx and 2 * hy and height of h
# create block at center position x, y with block width 2 * hx and 2 * hy and height of h
def create_block(x, y, hw, h, verts: list, faces: list):
if bpy.context.scene.cubester_block_style == "size":
if bpy.context.scene.advanced_objects.cubester_block_style == "size":
z = 0.0
else:
z = h
@ -134,12 +110,20 @@ def create_f_curves(mesh, frames, frame_step_size, style):
# create material with given name, apply to object
def create_material(scene, ob, name):
mat = bpy.data.materials.new("CubeSter_" + name)
adv_obj = scene.advanced_objects
image = None
# image
if not scene.cubester_use_image_color and scene.cubester_color_image in bpy.data.images:
image = bpy.data.images[scene.cubester_color_image]
if not adv_obj.cubester_use_image_color and adv_obj.cubester_color_image in bpy.data.images:
try:
image = bpy.data.images[adv_obj.cubester_color_image]
except:
pass
else:
image = bpy.data.images[scene.cubester_image]
try:
image = bpy.data.images[adv_obj.cubester_image]
except:
pass
if scene.render.engine == "CYCLES":
mat.use_nodes = True
@ -150,16 +134,17 @@ def create_material(scene, ob, name):
att.location = (-200, 300)
att = nodes.new("ShaderNodeTexImage")
att.image = image
if image:
att.image = image
if scene.cubester_load_type == "multiple":
if adv_obj.cubester_load_type == "multiple":
att.image.source = "SEQUENCE"
att.location = (-200, 700)
att = nodes.new("ShaderNodeTexCoord")
att.location = (-450, 600)
if scene.cubester_materials == "image":
if adv_obj.cubester_materials == "image":
mat.node_tree.links.new(
nodes["Image Texture"].outputs[0],
nodes["Diffuse BSDF"].inputs[0]
@ -174,9 +159,10 @@ def create_material(scene, ob, name):
nodes["Diffuse BSDF"].inputs[0]
)
else:
if scene.cubester_materials == "image" or scene.render.engine != "BLENDER_RENDER":
if adv_obj.cubester_materials == "image" or scene.render.engine != "BLENDER_RENDER":
tex = bpy.data.textures.new("CubeSter_" + name, "IMAGE")
tex.image = image
if image:
tex.image = image
slot = mat.texture_slots.add()
slot.texture = tex
else:
@ -187,10 +173,11 @@ def create_material(scene, ob, name):
# generate mesh from audio
def create_mesh_from_audio(self, scene, verts, faces):
audio_filepath = scene.cubester_audio_path
width = scene.cubester_audio_width_blocks
length = scene.cubester_audio_length_blocks
size_per_hundred = scene.cubester_size_per_hundred_pixels
adv_obj = scene.advanced_objects
audio_filepath = adv_obj.cubester_audio_path
width = adv_obj.cubester_audio_width_blocks
length = adv_obj.cubester_audio_length_blocks
size_per_hundred = adv_obj.cubester_size_per_hundred_pixels
size = size_per_hundred / 100
@ -213,8 +200,8 @@ def create_mesh_from_audio(self, scene, verts, faces):
ob.select = True
# inital vertex colors
if scene.cubester_materials == "image":
picture = bpy.data.images[scene.cubester_color_image]
if adv_obj.cubester_materials == "image" and adv_obj.cubester_color_image != "":
picture = bpy.data.images[adv_obj.cubester_color_image]
pixels = list(picture.pixels)
vert_colors = []
@ -228,22 +215,25 @@ def create_mesh_from_audio(self, scene, verts, faces):
vert_colors += [(r, g, b) for i in range(24)]
bpy.ops.mesh.vertex_color_add()
i = 0
vert_colors_size = len(vert_colors)
for c in ob.data.vertex_colors[0].data:
c.color = vert_colors[i]
i += 1
if i < vert_colors_size:
c.color = vert_colors[i]
i += 1
# image sequence handling
if scene.cubester_load_type == "multiple":
if adv_obj.cubester_load_type == "multiple":
images = find_sequence_images(self, bpy.context)
frames_vert_colors = []
max_images = scene.cubester_max_images + 1 if \
len(images[0]) > scene.cubester_max_images else len(images[0])
max_images = adv_obj.cubester_max_images + 1 if \
len(images[0]) > adv_obj.cubester_max_images else len(images[0])
# goes through and for each image for each block finds new height
for image_index in range(0, max_images, scene.cubester_skip_images):
for image_index in range(0, max_images, adv_obj.cubester_skip_images):
filepath = images[0][image_index]
name = images[1][image_index]
picture = fetch_image(self, name, filepath)
@ -258,9 +248,10 @@ def create_mesh_from_audio(self, scene, verts, faces):
frames_vert_colors.append(frame_colors)
scene.cubester_vertex_colors[ob.name] = {"type": "vertex", "frames": frames_vert_colors,
"frame_skip": scene.cubester_frame_step,
"total_images": max_images}
adv_obj.cubester_vertex_colors[ob.name] = \
{"type": "vertex", "frames": frames_vert_colors,
"frame_skip": adv_obj.cubester_frame_step,
"total_images": max_images}
# either add material or create
if ("CubeSter_" + "Vertex") in bpy.data.materials:
@ -285,14 +276,14 @@ def create_mesh_from_audio(self, scene, verts, faces):
for i in fcurves:
i.select = False
max_images = scene.cubester_audio_max_freq
min_freq = scene.cubester_audio_min_freq
freq_frame = scene.cubester_audio_offset_type
max_images = adv_obj.cubester_audio_max_freq
min_freq = adv_obj.cubester_audio_min_freq
freq_frame = adv_obj.cubester_audio_offset_type
freq_step = (max_images - min_freq) / length
freq_sub_step = freq_step / width
frame_step = scene.cubester_audio_frame_offset
frame_step = adv_obj.cubester_audio_frame_offset
# animate each block with a portion of the frequency
for c in range(length):
@ -314,8 +305,10 @@ def create_mesh_from_audio(self, scene, verts, faces):
for i in range(index, index + 4):
curve = i * 3 + 2 # fcurve location
fcurves[curve].select = True
bpy.ops.graph.sound_bake(filepath=bpy.path.abspath(audio_filepath), low=l, high=h)
try:
bpy.ops.graph.sound_bake(filepath=bpy.path.abspath(audio_filepath), low=l, high=h)
except:
pass
# deselect curves
for i in range(index, index + 4):
@ -328,7 +321,7 @@ def create_mesh_from_audio(self, scene, verts, faces):
create_uv_map(bpy.context, width, length)
# if radial apply needed modifiers
if scene.cubester_audio_block_layout == "radial":
if adv_obj.cubester_audio_block_layout == "radial":
# add bezier curve of correct width
bpy.ops.curve.primitive_bezier_circle_add()
curve = bpy.context.object
@ -358,14 +351,15 @@ def create_mesh_from_audio(self, scene, verts, faces):
# generate mesh from image(s)
def create_mesh_from_image(self, scene, verts, faces):
context = bpy.context
picture = bpy.data.images[scene.cubester_image]
adv_obj = scene.advanced_objects
picture = bpy.data.images[adv_obj.cubester_image]
pixels = list(picture.pixels)
x_pixels = picture.size[0] / (scene.cubester_skip_pixels + 1)
y_pixels = picture.size[1] / (scene.cubester_skip_pixels + 1)
x_pixels = picture.size[0] / (adv_obj.cubester_skip_pixels + 1)
y_pixels = picture.size[1] / (adv_obj.cubester_skip_pixels + 1)
width = x_pixels / 100 * scene.cubester_size_per_hundred_pixels
height = y_pixels / 100 * scene.cubester_size_per_hundred_pixels
width = x_pixels / 100 * adv_obj.cubester_size_per_hundred_pixels
height = y_pixels / 100 * adv_obj.cubester_size_per_hundred_pixels
step = width / x_pixels
half_width = step / 2
@ -376,18 +370,18 @@ def create_mesh_from_image(self, scene, verts, faces):
weights = [uniform(0.0, 1.0) for i in range(4)] # random weights
rows = 0
# go through each row of pixels stepping by scene.cubester_skip_pixels + 1
for row in range(0, picture.size[1], scene.cubester_skip_pixels + 1):
# go through each row of pixels stepping by adv_obj.cubester_skip_pixels + 1
for row in range(0, picture.size[1], adv_obj.cubester_skip_pixels + 1):
rows += 1
x = -width / 2 + half_width # reset to left edge of mesh
# go through each column, step by appropriate amount
for column in range(0, picture.size[0] * 4, 4 + scene.cubester_skip_pixels * 4):
for column in range(0, picture.size[0] * 4, 4 + adv_obj.cubester_skip_pixels * 4):
r, g, b, a = get_pixel_values(picture, pixels, row, column)
h = find_point_height(r, g, b, a, scene)
# if not transparent
if h != -1:
if scene.cubester_mesh_style == "blocks":
if adv_obj.cubester_mesh_style == "blocks":
create_block(x, y, half_width, h, verts, faces)
vert_colors += [(r, g, b) for i in range(24)]
else:
@ -399,11 +393,11 @@ def create_mesh_from_image(self, scene, verts, faces):
# if plane not blocks, then remove last 4 items from vertex_colors
# as the faces have already wrapped around
if scene.cubester_mesh_style == "plane":
if adv_obj.cubester_mesh_style == "plane":
del vert_colors[len(vert_colors) - 4:len(vert_colors)]
# create faces if plane based and not block based
if scene.cubester_mesh_style == "plane":
if adv_obj.cubester_mesh_style == "plane":
off = int(len(verts) / rows)
for r in range(rows - 1):
for c in range(off - 1):
@ -417,20 +411,21 @@ def create_mesh_from_image(self, scene, verts, faces):
ob.select = True
# uv unwrap
if scene.cubester_mesh_style == "blocks":
if adv_obj.cubester_mesh_style == "blocks":
create_uv_map(context, rows, int(len(faces) / 6 / rows))
else:
create_uv_map(context, rows - 1, int(len(faces) / (rows - 1)))
# material
# determine name and if already created
if scene.cubester_materials == "vertex": # vertex color
if adv_obj.cubester_materials == "vertex": # vertex color
image_name = "Vertex"
elif not scene.cubester_use_image_color and scene.cubester_color_image in bpy.data.images and \
scene.cubester_materials == "image": # replaced image
image_name = scene.cubester_color_image
elif not adv_obj.cubester_use_image_color and \
adv_obj.cubester_color_image in bpy.data.images and \
adv_obj.cubester_materials == "image": # replaced image
image_name = adv_obj.cubester_color_image
else: # normal image
image_name = scene.cubester_image
image_name = adv_obj.cubester_image
# either add material or create
if ("CubeSter_" + image_name) in bpy.data.materials:
@ -449,15 +444,15 @@ def create_mesh_from_image(self, scene, verts, faces):
frames = []
# image sequence handling
if scene.cubester_load_type == "multiple":
if adv_obj.cubester_load_type == "multiple":
images = find_sequence_images(self, context)
frames_vert_colors = []
max_images = scene.cubester_max_images + 1 if \
len(images[0]) > scene.cubester_max_images else len(images[0])
max_images = adv_obj.cubester_max_images + 1 if \
len(images[0]) > adv_obj.cubester_max_images else len(images[0])
# goes through and for each image for each block finds new height
for image_index in range(0, max_images, scene.cubester_skip_images):
for image_index in range(0, max_images, adv_obj.cubester_skip_images):
filepath = images[0][image_index]
name = images[1][image_index]
picture = fetch_image(self, name, filepath)
@ -466,45 +461,50 @@ def create_mesh_from_image(self, scene, verts, faces):
frame_heights = []
frame_colors = []
for row in range(0, picture.size[1], scene.cubester_skip_pixels + 1):
for column in range(0, picture.size[0] * 4, 4 + scene.cubester_skip_pixels * 4):
for row in range(0, picture.size[1], adv_obj.cubester_skip_pixels + 1):
for column in range(0, picture.size[0] * 4, 4 + adv_obj.cubester_skip_pixels * 4):
r, g, b, a = get_pixel_values(picture, pixels, row, column)
h = find_point_height(r, g, b, a, scene)
if h != -1:
frame_heights.append(h)
if scene.cubester_mesh_style == "blocks":
if adv_obj.cubester_mesh_style == "blocks":
frame_colors += [(r, g, b) for i in range(24)]
else:
frame_colors += [(r, g, b) for i in range(4)]
if scene.cubester_mesh_style == "plane":
if adv_obj.cubester_mesh_style == "plane":
del vert_colors[len(vert_colors) - 4:len(vert_colors)]
frames.append(frame_heights)
frames_vert_colors.append(frame_colors)
# determine what data to use
if scene.cubester_materials == "vertex" or scene.render.engine == "BLENDER_ENGINE":
scene.cubester_vertex_colors[ob.name] = {
"type": "vertex", "frames": frames_vert_colors,
"frame_skip": scene.cubester_frame_step,
"total_images": max_images
}
if adv_obj.cubester_materials == "vertex" or scene.render.engine == "BLENDER_ENGINE":
adv_obj.cubester_vertex_colors[ob.name] = {
"type": "vertex", "frames": frames_vert_colors,
"frame_skip": adv_obj.cubester_frame_step,
"total_images": max_images
}
else:
scene.cubester_vertex_colors[ob.name] = {
"type": "image", "frame_skip": scene.cubester_frame_step,
"total_images": max_images
}
adv_obj.cubester_vertex_colors[ob.name] = {
"type": "image", "frame_skip": scene.cubester_frame_step,
"total_images": max_images
}
att = get_image_node(ob.data.materials[0])
att.image_user.frame_duration = len(frames) * scene.cubester_frame_step
att.image_user.frame_duration = len(frames) * adv_obj.cubester_frame_step
# animate mesh
create_f_curves(mesh, frames, scene.cubester_frame_step, scene.cubester_mesh_style)
create_f_curves(
mesh, frames,
adv_obj.cubester_frame_step,
adv_obj.cubester_mesh_style
)
# generate uv map for object
def create_uv_map(context, rows, columns):
adv_obj = context.scene.advanced_objects
mesh = context.object.data
mesh.uv_textures.new("cubester")
bm = bmesh.new()
@ -521,7 +521,7 @@ def create_uv_map(context, rows, columns):
count = columns - 1 # hold current count to compare to if need to go to next row
# if blocks
if context.scene.cubester_mesh_style == "blocks":
if adv_obj.cubester_mesh_style == "blocks":
for fa in range(int(len(bm.faces) / 6)):
for i in range(6):
pos = (fa * 6) + i
@ -555,33 +555,6 @@ def create_uv_map(context, rows, columns):
bm.to_mesh(mesh)
# returns length in frames
def find_audio_length(self, context):
audio_file = context.scene.cubester_audio_path
length = 0
if audio_file != "":
# confirm that strip hasn't been loaded yet
for strip in context.scene.sequence_editor.sequences_all:
if type(strip) == bpy.types.SoundSequence and strip.sound.filepath == audio_file:
length = strip.frame_final_duration
if length == 0:
area = context.area
old_type = area.type
area.type = "SEQUENCE_EDITOR"
bpy.ops.sequencer.sound_strip_add(filepath=audio_file)
area.type = old_type
# find audio file
for strip in context.scene.sequence_editor.sequences_all:
if type(strip) == bpy.types.SoundSequence and strip.sound.filepath == audio_file:
length = strip.frame_final_duration
context.scene.cubester_audio_file_length = str(length)
# if already loaded return image, else load and return
def fetch_image(self, name, load_path):
if name in bpy.data.images:
@ -597,19 +570,20 @@ def fetch_image(self, name, load_path):
# find height for point
def find_point_height(r, g, b, a, scene):
adv_obj = scene.advanced_objects
if a: # if not completely transparent
normalize = 1
# channel weighting
if not scene.cubester_advanced:
if not adv_obj.cubester_advanced:
composed = 0.25 * r + 0.25 * g + 0.25 * b + 0.25 * a
else:
# user defined weighting
if not scene.cubester_random_weights:
composed = scene.cubester_weight_r * r + scene.cubester_weight_g * g + \
scene.cubester_weight_b * b + scene.cubester_weight_a * a
total = scene.cubester_weight_r + scene.cubester_weight_g + scene.cubester_weight_b + \
scene.cubester_weight_a
if not adv_obj.cubester_random_weights:
composed = adv_obj.cubester_weight_r * r + adv_obj.cubester_weight_g * g + \
adv_obj.cubester_weight_b * b + adv_obj.cubester_weight_a * a
total = adv_obj.cubester_weight_r + adv_obj.cubester_weight_g + adv_obj.cubester_weight_b + \
adv_obj.cubester_weight_a
normalize = 1 / total
# random weighting
@ -619,10 +593,10 @@ def find_point_height(r, g, b, a, scene):
total = weights[0] + weights[1] + weights[2] + weights[3]
normalize = 1 / total
if scene.cubester_invert:
h = (1 - composed) * scene.cubester_height_scale * normalize
if adv_obj.cubester_invert:
h = (1 - composed) * adv_obj.cubester_height_scale * normalize
else:
h = composed * scene.cubester_height_scale * normalize
h = composed * adv_obj.cubester_height_scale * normalize
return h
else:
@ -634,8 +608,8 @@ def find_sequence_images(self, context):
scene = context.scene
images = [[], []]
if scene.cubester_image in bpy.data.images:
image = bpy.data.images[scene.cubester_image]
if scene.advanced_objects.cubester_image in bpy.data.images:
image = bpy.data.images[scene.advanced_objects.cubester_image]
main = image.name.split(".")[0]
# first part of name to check against other files
@ -685,15 +659,16 @@ def get_pixel_values(picture, pixels, row, column):
# frame change handler for materials
def material_frame_handler(scene):
frame = scene.frame_current
adv_obj = scene.advanced_objects
keys = list(scene.cubester_vertex_colors.keys())
keys = list(adv_obj.cubester_vertex_colors.keys())
# get keys and see if object is still in scene
for i in keys:
# if object is in scene then update information
if i in bpy.data.objects:
ob = bpy.data.objects[i]
data = scene.cubester_vertex_colors[ob.name]
data = adv_obj.advanced_objects.cubester_vertex_colors[ob.name]
skip_frames = data["frame_skip"]
# update materials using vertex colors
@ -716,183 +691,7 @@ def material_frame_handler(scene):
# if the object is no longer in the scene then delete then entry
else:
del scene.cubester_vertex_colors[i]
# main properties
bpy.types.Scene.cubester_audio_image = EnumProperty(
name="Input Type",
items=(("image", "Image", ""),
("audio", "Audio", ""))
)
bpy.types.Scene.cubester_audio_file_length = StringProperty(
default=""
)
# audio
bpy.types.Scene.cubester_audio_path = StringProperty(
default="",
name="Audio File",
subtype="FILE_PATH",
update=find_audio_length
)
bpy.types.Scene.cubester_audio_min_freq = IntProperty(
name="Minimum Frequency",
min=20, max=100000,
default=20
)
bpy.types.Scene.cubester_audio_max_freq = IntProperty(
name="Maximum Frequency",
min=21, max=999999,
default=5000
)
bpy.types.Scene.cubester_audio_offset_type = EnumProperty(
name="Offset Type",
items=(("freq", "Frequency Offset", ""),
("frame", "Frame Offset", "")),
description="Type of offset per row of mesh"
)
bpy.types.Scene.cubester_audio_frame_offset = IntProperty(
name="Frame Offset",
min=0, max=10,
default=2
)
bpy.types.Scene.cubester_audio_block_layout = EnumProperty(
name="Block Layout",
items=(("rectangle", "Rectangular", ""),
("radial", "Radial", ""))
)
bpy.types.Scene.cubester_audio_width_blocks = IntProperty(
name="Width Block Count",
min=1, max=10000,
default=5
)
bpy.types.Scene.cubester_audio_length_blocks = IntProperty(
name="Length Block Count",
min=1, max=10000,
default=50
)
# image
bpy.types.Scene.cubester_load_type = EnumProperty(
name="Image Input Type",
items=(("single", "Single Image", ""),
("multiple", "Image Sequence", ""))
)
bpy.types.Scene.cubester_image = StringProperty(
default="",
name=""
)
bpy.types.Scene.cubester_load_image = StringProperty(
default="",
name="Load Image",
subtype="FILE_PATH",
update=adjust_selected_image
)
bpy.types.Scene.cubester_skip_images = IntProperty(
name="Image Step",
min=1, max=30,
default=1,
description="Step from image to image by this number"
)
bpy.types.Scene.cubester_max_images = IntProperty(
name="Max Number Of Images",
min=2, max=1000,
default=10,
description="Maximum number of images to be used"
)
bpy.types.Scene.cubester_frame_step = IntProperty(
name="Frame Step Size",
min=1, max=10,
default=4,
description="The number of frames each picture is used"
)
bpy.types.Scene.cubester_skip_pixels = IntProperty(
name="Skip # Pixels",
min=0, max=256,
default=64,
description="Skip this number of pixels before placing the next"
)
bpy.types.Scene.cubester_mesh_style = EnumProperty(
name="Mesh Type",
items=(("blocks", "Blocks", ""),
("plane", "Plane", "")),
description="Compose mesh of multiple blocks or of a single plane"
)
bpy.types.Scene.cubester_block_style = EnumProperty(
name="Block Style",
items=(("size", "Vary Size", ""),
("position", "Vary Position", "")),
description="Vary Z-size of block, or vary Z-position"
)
bpy.types.Scene.cubester_height_scale = FloatProperty(
name="Height Scale",
subtype="DISTANCE",
min=0.1, max=2,
default=0.2
)
bpy.types.Scene.cubester_invert = BoolProperty(
name="Invert Height?",
default=False
)
# general adjustments
bpy.types.Scene.cubester_size_per_hundred_pixels = FloatProperty(
name="Size Per 100 Blocks/Points",
subtype="DISTANCE",
min=0.001, max=5,
default=1
)
# material based stuff
bpy.types.Scene.cubester_materials = EnumProperty(
name="Material",
items=(("vertex", "Vertex Colors", ""),
("image", "Image", "")),
description="Color with vertex colors, or uv unwrap and use an image"
)
bpy.types.Scene.cubester_use_image_color = BoolProperty(
name="Use Original Image Colors'?",
default=True,
description="Use original image colors, or replace with other"
)
bpy.types.Scene.cubester_color_image = StringProperty(
default="", name=""
)
bpy.types.Scene.cubester_load_color_image = StringProperty(
default="",
name="Load Color Image",
subtype="FILE_PATH",
update=adjust_selected_color_image
)
bpy.types.Scene.cubester_vertex_colors = {}
# advanced
bpy.types.Scene.cubester_advanced = BoolProperty(
name="Advanced Options?"
)
bpy.types.Scene.cubester_random_weights = BoolProperty(
name="Random Weights?"
)
bpy.types.Scene.cubester_weight_r = FloatProperty(
name="Red",
subtype="FACTOR",
min=0.01, max=1.0,
default=0.25
)
bpy.types.Scene.cubester_weight_g = FloatProperty(
name="Green",
subtype="FACTOR",
min=0.01, max=1.0,
default=0.25
)
bpy.types.Scene.cubester_weight_b = FloatProperty(
name="Blue",
subtype="FACTOR",
min=0.01, max=1.0,
default=0.25
)
bpy.types.Scene.cubester_weight_a = FloatProperty(
name="Alpha",
subtype="FACTOR",
min=0.01, max=1.0,
default=0.25
)
del adv_obj.advanced_objects.cubester_vertex_colors[i]
class CubeSterPanel(Panel):
@ -907,127 +706,123 @@ class CubeSterPanel(Panel):
def draw(self, context):
layout = self.layout.box()
scene = bpy.context.scene
adv_obj = scene.advanced_objects
images_found = 0
rows = 0
columns = 0
layout.prop(scene, "cubester_audio_image", icon="IMAGE_COL")
layout.separator()
layout.prop(adv_obj, "cubester_audio_image")
if scene.cubester_audio_image == "image":
if adv_obj.cubester_audio_image == "image":
box = layout.box()
box.prop(scene, "cubester_load_type")
box.prop(adv_obj, "cubester_load_type")
box.label("Image To Convert:")
box.prop_search(scene, "cubester_image", bpy.data, "images")
box.prop(scene, "cubester_load_image")
layout.separator()
box.prop_search(adv_obj, "cubester_image", bpy.data, "images")
box.prop(adv_obj, "cubester_load_image")
# find number of approriate images if sequence
if scene.cubester_load_type == "multiple":
if adv_obj.cubester_load_type == "multiple":
box = layout.box()
# display number of images found there
images = find_sequence_images(self, context)
images_found = len(images[0]) if len(images[0]) <= scene.cubester_max_images \
else scene.cubester_max_images
images_found = len(images[0]) if len(images[0]) <= adv_obj.cubester_max_images \
else adv_obj.cubester_max_images
if len(images[0]):
box.label(str(len(images[0])) + " Images Found", icon="PACKAGE")
box.prop(scene, "cubester_max_images")
box.prop(scene, "cubester_skip_images")
box.prop(scene, "cubester_frame_step")
layout.separator()
box.prop(adv_obj, "cubester_max_images")
box.prop(adv_obj, "cubester_skip_images")
box.prop(adv_obj, "cubester_frame_step")
box = layout.box()
box.prop(scene, "cubester_skip_pixels")
box.prop(scene, "cubester_size_per_hundred_pixels")
box.prop(scene, "cubester_height_scale")
box.prop(scene, "cubester_invert", icon="FILE_REFRESH")
col = box.column(align=True)
col.prop(adv_obj, "cubester_skip_pixels")
col.prop(adv_obj, "cubester_size_per_hundred_pixels")
col.prop(adv_obj, "cubester_height_scale")
box.prop(adv_obj, "cubester_invert", icon="FILE_REFRESH")
layout.separator()
box = layout.box()
box.prop(scene, "cubester_mesh_style", icon="MESH_GRID")
box.prop(adv_obj, "cubester_mesh_style", icon="MESH_GRID")
if scene.cubester_mesh_style == "blocks":
box.prop(scene, "cubester_block_style")
# audio file
if adv_obj.cubester_mesh_style == "blocks":
box.prop(adv_obj, "cubester_block_style")
else:
layout.prop(scene, "cubester_audio_path")
layout.separator()
# audio file
layout.prop(adv_obj, "cubester_audio_path")
box = layout.box()
col = box.column(align=True)
col.prop(adv_obj, "cubester_audio_min_freq")
col.prop(adv_obj, "cubester_audio_max_freq")
box.prop(scene, "cubester_audio_min_freq")
box.prop(scene, "cubester_audio_max_freq")
box.separator()
box.prop(scene, "cubester_audio_offset_type")
box.prop(adv_obj, "cubester_audio_offset_type")
if scene.cubester_audio_offset_type == "frame":
box.prop(scene, "cubester_audio_frame_offset")
if adv_obj.cubester_audio_offset_type == "frame":
box.prop(adv_obj, "cubester_audio_frame_offset")
box.prop(adv_obj, "cubester_audio_block_layout")
box.separator()
box.prop(scene, "cubester_audio_block_layout")
box.prop(scene, "cubester_audio_width_blocks")
box.prop(scene, "cubester_audio_length_blocks")
col = box.column(align=True)
col.prop(adv_obj, "cubester_audio_width_blocks")
col.prop(adv_obj, "cubester_audio_length_blocks")
rows = scene.cubester_audio_width_blocks
columns = scene.cubester_audio_length_blocks
rows = adv_obj.cubester_audio_width_blocks
columns = adv_obj.cubester_audio_length_blocks
box.prop(scene, "cubester_size_per_hundred_pixels")
col.prop(adv_obj, "cubester_size_per_hundred_pixels")
# materials
layout.separator()
box = layout.box()
box.prop(adv_obj, "cubester_materials", icon="MATERIAL")
box.prop(scene, "cubester_materials", icon="MATERIAL")
if scene.cubester_materials == "image":
box.prop(scene, "cubester_load_type")
if adv_obj.cubester_materials == "image":
box.prop(adv_obj, "cubester_load_type")
# find number of approriate images if sequence
if scene.cubester_load_type == "multiple":
if adv_obj.cubester_load_type == "multiple":
# display number of images found there
images = find_sequence_images(self, context)
images_found = len(images[0]) if len(images[0]) <= scene.cubester_max_images \
else scene.cubester_max_images
images_found = len(images[0]) if len(images[0]) <= adv_obj.cubester_max_images \
else adv_obj.cubester_max_images
if len(images[0]):
box.label(str(len(images[0])) + " Images Found", icon="PACKAGE")
box.prop(scene, "cubester_max_images")
box.prop(scene, "cubester_skip_images")
box.prop(scene, "cubester_frame_step")
box.prop(adv_obj, "cubester_max_images")
box.prop(adv_obj, "cubester_skip_images")
box.prop(adv_obj, "cubester_frame_step")
box.separator()
if scene.cubester_audio_image == "image":
box.prop(scene, "cubester_use_image_color", icon="COLOR")
if adv_obj.cubester_audio_image == "image":
box.prop(adv_obj, "cubester_use_image_color", icon="COLOR")
if not scene.cubester_use_image_color or scene.cubester_audio_image == "audio":
if not adv_obj.cubester_use_image_color or adv_obj.cubester_audio_image == "audio":
box.label("Image To Use For Colors:")
box.prop_search(scene, "cubester_color_image", bpy.data, "images")
box.prop(scene, "cubester_load_color_image")
box.prop_search(adv_obj, "cubester_color_image", bpy.data, "images")
box.prop(adv_obj, "cubester_load_color_image")
if scene.cubester_image in bpy.data.images:
rows = int(bpy.data.images[scene.cubester_image].size[1] / (scene.cubester_skip_pixels + 1))
columns = int(bpy.data.images[scene.cubester_image].size[0] / (scene.cubester_skip_pixels + 1))
if adv_obj.cubester_image in bpy.data.images:
rows = int(bpy.data.images[adv_obj.cubester_image].size[1] /
(adv_obj.cubester_skip_pixels + 1))
columns = int(bpy.data.images[adv_obj.cubester_image].size[0] /
(adv_obj.cubester_skip_pixels + 1))
layout.separator()
box = layout.box()
if scene.cubester_mesh_style == "blocks":
if adv_obj.cubester_mesh_style == "blocks":
box.label("Approximate Cube Count: " + str(rows * columns))
box.label("Expected # Verts/Faces: " + str(rows * columns * 8) + " / " + str(rows * columns * 6))
box.label("Expected Verts/Faces: " + str(rows * columns * 8) + " / " + str(rows * columns * 6))
else:
box.label("Approximate Point Count: " + str(rows * columns))
box.label("Expected # Verts/Faces: " + str(rows * columns) + " / " + str(rows * (columns - 1)))
box.label("Expected Verts/Faces: " + str(rows * columns) + " / " + str(rows * (columns - 1)))
# blocks and plane generation time values
if scene.cubester_mesh_style == "blocks":
if adv_obj.cubester_mesh_style == "blocks":
slope = 0.0000876958
intercept = 0.02501
block_infl, frame_infl, intercept2 = 0.0025934, 0.38507, -0.5840189
else:
slope = 0.000017753
intercept = 0.04201
@ -1035,21 +830,22 @@ class CubeSterPanel(Panel):
# if creating image based mesh
points = rows * columns
if scene.cubester_audio_image == "image":
if scene.cubester_load_type == "single":
if adv_obj.cubester_audio_image == "image":
if adv_obj.cubester_load_type == "single":
time = rows * columns * slope + intercept # approximate time count for mesh
else:
time = (points * slope) + intercept + (points * block_infl) + \
(images_found / scene.cubester_skip_images * frame_infl) + intercept2
(images_found / adv_obj.cubester_skip_images * frame_infl) + intercept2
box.label("Images To Be Used: " + str(int(images_found / scene.cubester_skip_images)))
# audio based mesh
box.label("Images To Be Used: " + str(int(images_found / adv_obj.cubester_skip_images)))
else:
box.label("Audio Track Length: " + scene.cubester_audio_file_length + " frames")
# audio based mesh
box.label("Audio Track Length: " + str(adv_obj.cubester_audio_file_length) + " frames")
block_infl, frame_infl, intercept = 0.0948, 0.0687566, -25.85985
time = (points * block_infl) + (int(scene.cubester_audio_file_length) * frame_infl) + intercept
time = (points * block_infl) + (adv_obj.cubester_audio_file_length * frame_infl) + intercept
if time < 0.0: # usually no audio loaded
time = 0.0
time_mod = "s"
if time > 60: # convert to minutes if needed
@ -1060,29 +856,31 @@ class CubeSterPanel(Panel):
box.label("Expected Time: " + str(time) + " " + time_mod)
# advanced
if scene.cubester_audio_image == "image":
layout.separator()
if adv_obj.cubester_audio_image == "image":
icon_1 = "TRIA_DOWN" if adv_obj.cubester_advanced else "TRIA_RIGHT"
# layout.separator()
box = layout.box()
box.prop(scene, "cubester_advanced", icon="TRIA_DOWN")
if bpy.context.scene.cubester_advanced:
box.prop(scene, "cubester_random_weights", icon="RNDCURVE")
box.separator()
box.prop(adv_obj, "cubester_advanced", icon=icon_1)
if not bpy.context.scene.cubester_random_weights:
if adv_obj.cubester_advanced:
box.prop(adv_obj, "cubester_random_weights", icon="RNDCURVE")
if not adv_obj.cubester_random_weights:
box.label("RGBA Channel Weights", icon="COLOR")
box.prop(scene, "cubester_weight_r")
box.prop(scene, "cubester_weight_g")
box.prop(scene, "cubester_weight_b")
box.prop(scene, "cubester_weight_a")
col = box.column(align=True)
col.prop(adv_obj, "cubester_weight_r")
col.prop(adv_obj, "cubester_weight_g")
col.prop(adv_obj, "cubester_weight_b")
col.prop(adv_obj, "cubester_weight_a")
# generate mesh
layout.separator()
layout.operator("mesh.cubester", icon="OBJECT_DATA")
class CubeSter(Operator):
bl_idname = "mesh.cubester"
bl_label = "Generate Mesh"
bl_description = "Generate a mesh from an Image or Sound File"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
@ -1090,18 +888,31 @@ class CubeSter(Operator):
start = timeit.default_timer()
scene = bpy.context.scene
adv_obj = scene.advanced_objects
if scene.cubester_audio_image == "image":
create_mesh_from_image(self, scene, verts, faces)
frames = find_sequence_images(self, context)
created = len(frames[0])
if adv_obj.cubester_audio_image == "image":
if adv_obj.cubester_image != "":
create_mesh_from_image(self, scene, verts, faces)
frames = find_sequence_images(self, context)
created = len(frames[0])
else:
self.report({'WARNING'},
"Please add an Image for Object generation. Operation Cancelled")
return {"CANCELLED"}
else:
create_mesh_from_audio(self, scene, verts, faces)
created = int(scene.cubester_audio_file_length)
if (adv_obj.cubester_audio_path != "" and
path.isfile(adv_obj.cubester_audio_path) and adv_obj.cubester_check_audio is True):
create_mesh_from_audio(self, scene, verts, faces)
created = adv_obj.cubester_audio_file_length
else:
self.report({'WARNING'},
"Please add an Sound File for Object generation. Operation Cancelled")
return {"CANCELLED"}
stop = timeit.default_timer()
if scene.cubester_mesh_style == "blocks" or scene.cubester_audio_image == "audio":
if adv_obj.cubester_mesh_style == "blocks" or adv_obj.cubester_audio_image == "audio":
self.report({"INFO"},
"CubeSter: {} blocks and {} frame(s) "
"in {}s".format(str(int(len(verts) / 8)),

View File

@ -61,13 +61,11 @@
import bpy
import math
import sys
import getopt
# Globals
TOLERANCE = 1e-9
BIG_FLOAT = 1e38
# TODO : Licence, prints, imports, autorship
class Context(object):
@ -295,14 +293,14 @@ class Context(object):
def outTriple(self, s1, s2, s3):
self.triangles.append((s1.sitenum, s2.sitenum, s3.sitenum))
if(self.debug):
if (self.debug):
print("circle through left=%d right=%d bottom=%d" % (s1.sitenum, s2.sitenum, s3.sitenum))
elif(self.triangulate and self.doPrint):
elif (self.triangulate and self.doPrint):
print("%d %d %d" % (s1.sitenum, s2.sitenum, s3.sitenum))
def outBisector(self, edge):
self.lines.append((edge.a, edge.b, edge.c))
if(self.debug):
if (self.debug):
print("line(%d) %gx+%gy=%g, bisecting %d %d" % (edge.edgenum, edge.a, edge.b,
edge.c, edge.reg[0].sitenum,
edge.reg[1].sitenum)
@ -328,8 +326,8 @@ class Context(object):
self.edges.append((edge.edgenum, sitenumL, sitenumR))
if(not self.triangulate):
if(self.doPrint):
if (not self.triangulate):
if (self.doPrint):
print("e %d" % edge.edgenum)
print(" %d " % sitenumL)
print("%d" % sitenumR)

View File

@ -21,14 +21,13 @@
bl_info = {
"name": "Delaunay Voronoi",
"description": "Points cloud Delaunay triangulation in 2.5D "
"(suitable for terrain modelling) or Voronoi diagram in 2D",
"(suitable for terrain modelling) or Voronoi diagram in 2D",
"author": "Domlysz, Oscurart",
"version": (1, 3),
"blender": (2, 7, 0),
"location": "View3D > Tools > GIS",
"warning": "",
"wiki_url": "https://github.com/domlysz/BlenderGIS/wiki",
"tracker_url": "",
"category": ""
}

View File

@ -2,9 +2,9 @@
import bpy
from .DelaunayVoronoi import (
computeVoronoiDiagram,
computeDelaunayTriangulation,
)
computeVoronoiDiagram,
computeDelaunayTriangulation,
)
from bpy.types import (
Operator,
Panel,
@ -12,6 +12,17 @@ from bpy.types import (
from bpy.props import EnumProperty
# Globals
# set to True to enable debug_prints
DEBUG = False
def debug_prints(text=""):
global DEBUG
if DEBUG and text:
print(text)
class Point:
def __init__(self, x, y, z):
self.x, self.y, self.z = x, y, z
@ -56,45 +67,56 @@ class ToolsPanelDelaunay(Panel):
def draw(self, context):
layout = self.layout
layout.label('Constellation')
self.layout.operator("delaunay.triangulation")
self.layout.operator("voronoi.tesselation")
layout.label('Constellation')
layout.operator("mesh.constellation", text="Cross Section")
adv_obj = context.scene.advanced_objects
box = layout.box()
col = box.column(align=True)
col.label("Point Cloud:")
col.operator("delaunay.triangulation")
col.operator("voronoi.tesselation")
box = layout.box()
col = box.column(align=True)
col.label("Constellation:")
col.operator("mesh.constellation", text="Cross Section")
col.prop(adv_obj, "constellation_limit")
class OBJECT_OT_TriangulateButton(Operator):
bl_idname = "delaunay.triangulation"
bl_label = "Triangulation"
bl_description = "Terrain points cloud Delaunay triangulation in 2.5D"
bl_options = {"UNDO"}
bl_description = ("Terrain points cloud Delaunay triangulation in 2.5D\n"
"Needs an existing Active Mesh Object")
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
obj = context.active_object
return (obj is not None and obj.type == "MESH")
def execute(self, context):
# Get selected obj
objs = bpy.context.selected_objects
if len(objs) == 0 or len(objs) > 1:
self.report({'INFO'}, "Selection is empty or too much object selected")
return {'FINISHED'}
obj = objs[0]
if obj.type != 'MESH':
self.report({'INFO'}, "Selection isn't a mesh")
return {'FINISHED'}
# move the check into the poll
obj = context.active_object
# Get points coodinates
r = obj.rotation_euler
s = obj.scale
mesh = obj.data
vertsPts = [vertex.co for vertex in mesh.vertices]
# Remove duplicate
verts = [[vert.x, vert.y, vert.z] for vert in vertsPts]
nDupli, nZcolinear = unique(verts)
nVerts = len(verts)
print(str(nDupli) + " duplicates points ignored")
print(str(nZcolinear) + " z colinear points excluded")
debug_prints(text=str(nDupli) + " duplicate points ignored")
debug_prints(str(nZcolinear) + " z colinear points excluded")
if nVerts < 3:
self.report({'ERROR'}, "Not enough points")
return {'FINISHED'}
self.report({"WARNING"},
"Not enough points to continue. Operation Cancelled")
return {"CANCELLED"}
# Check colinear
xValues = [pt[0] for pt in verts]
@ -105,59 +127,63 @@ class OBJECT_OT_TriangulateButton(Operator):
return {'FINISHED'}
# Triangulate
print("Triangulate " + str(nVerts) + " points...")
debug_prints(text="Triangulate " + str(nVerts) + " points...")
vertsPts = [Point(vert[0], vert[1], vert[2]) for vert in verts]
triangles = computeDelaunayTriangulation(vertsPts)
# reverse point order --> if all triangles are specified anticlockwise then all faces up
triangles = [tuple(reversed(tri)) for tri in triangles]
print(str(len(triangles)) + " triangles")
debug_prints(text=str(len(triangles)) + " triangles")
# Create new mesh structure
print("Create mesh...")
debug_prints(text="Create mesh...")
tinMesh = bpy.data.meshes.new("TIN") # create a new mesh
tinMesh.from_pydata(verts, [], triangles) # Fill the mesh with triangles
tinMesh.update(calc_edges=True) # Update mesh with new data
# Create an object with that mesh
tinObj = bpy.data.objects.new("TIN", tinMesh)
# Place object
tinObj.location = obj.location.copy()
tinObj.rotation_euler = r
tinObj.scale = s
# Update scene
bpy.context.scene.objects.link(tinObj) # Link object to scene
bpy.context.scene.objects.active = tinObj
tinObj.select = True
obj.select = False
# Report
self.report({'INFO'}, "Mesh created (" + str(len(triangles)) + " triangles)")
self.report({"INFO"},
"Mesh created (" + str(len(triangles)) + " triangles)")
return {'FINISHED'}
class OBJECT_OT_VoronoiButton(Operator):
bl_idname = "voronoi.tesselation"
bl_label = "Diagram"
bl_description = "Points cloud Voronoi diagram in 2D"
bl_description = ("Points cloud Voronoi diagram in 2D\n"
"Needs an existing Active Mesh Object")
bl_options = {"REGISTER", "UNDO"}
meshType = EnumProperty(
items=[("Edges", "Edges", ""), ("Faces", "Faces", "")],
name="Mesh type",
description=""
)
items=[('Edges', "Edges", "Edges Only - do not fill Faces"),
('Faces', "Faces", "Fill Faces in the new Object")],
name="Mesh type",
description="Type of geometry to generate"
)
@classmethod
def poll(cls, context):
obj = context.active_object
return (obj is not None and obj.type == "MESH")
def execute(self, context):
# Get selected obj
objs = bpy.context.selected_objects
if len(objs) == 0 or len(objs) > 1:
self.report({'INFO'}, "Selection is empty or too much object selected")
return {'FINISHED'}
obj = objs[0]
if obj.type != 'MESH':
self.report({'INFO'}, "Selection isn't a mesh")
return {'FINISHED'}
# move the check into the poll
obj = context.active_object
# Get points coodinates
r = obj.rotation_euler
@ -170,28 +196,36 @@ class OBJECT_OT_VoronoiButton(Operator):
nDupli, nZcolinear = unique(verts)
nVerts = len(verts)
print(str(nDupli) + " duplicates points ignored")
print(str(nZcolinear) + " z colinear points excluded")
debug_prints(text=str(nDupli) + " duplicates points ignored")
debug_prints(text=str(nZcolinear) + " z colinear points excluded")
if nVerts < 3:
self.report({'ERROR'}, "Not enough points")
return {'FINISHED'}
self.report({"WARNING"},
"Not enough points to continue. Operation Cancelled")
return {"CANCELLED"}
# Check colinear
xValues = [pt[0] for pt in verts]
yValues = [pt[1] for pt in verts]
if checkEqual(xValues) or checkEqual(yValues):
self.report({'ERROR'}, "Points are colinear")
return {'FINISHED'}
self.report({"WARNING"},
"Points are colinear. Operation Cancelled")
return {"CANCELLED"}
# Create diagram
print("Tesselation... (" + str(nVerts) + " points)")
debug_prints(text="Tesselation... (" + str(nVerts) + " points)")
xbuff, ybuff = 5, 5
zPosition = 0
vertsPts = [Point(vert[0], vert[1], vert[2]) for vert in verts]
if self.meshType == "Edges":
pts, edgesIdx = computeVoronoiDiagram(
vertsPts, xbuff, ybuff, polygonsOutput=False, formatOutput=True
vertsPts, xbuff, ybuff,
polygonsOutput=False, formatOutput=True
)
else:
pts, polyIdx = computeVoronoiDiagram(
@ -227,8 +261,8 @@ class OBJECT_OT_VoronoiButton(Operator):
# Report
if self.meshType == "Edges":
self.report({'INFO'}, "Mesh created (" + str(len(edgesIdx)) + " edges)")
self.report({"INFO"}, "Mesh created (" + str(len(edgesIdx)) + " edges)")
else:
self.report({'INFO'}, "Mesh created (" + str(len(polyIdx)) + " polygons)")
self.report({"INFO"}, "Mesh created (" + str(len(polyIdx)) + " polygons)")
return {'FINISHED'}

View File

@ -19,15 +19,17 @@
bl_info = {
"name": "Mesh: Constellation",
"author": "Oscurart",
"version": (1, 0),
"version": (1, 1, 1),
"blender": (2, 67, 0),
"location": "Add > Mesh > Constellation",
"description": "Adds a new Mesh From Selected",
"description": "Create a new Mesh From Selected",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Add Mesh"}
# Note the setting is moved to __init__ search for
# the adv_obj and advanced_objects patterns
import bpy
from bpy.types import Operator
from bpy.props import FloatProperty
@ -56,51 +58,66 @@ def OscConstellation(limit):
edgei += 2
mesh = bpy.data.meshes.new("rsdata")
object = bpy.data.objects.new("rsObject", mesh)
bpy.context.scene.objects.link(object)
obj = bpy.data.objects.new("rsObject", mesh)
bpy.context.scene.objects.link(obj)
mesh.from_pydata(vertlist, edgelist, [])
class Oscurart_Constellation (Operator):
class Oscurart_Constellation(Operator):
bl_idname = "mesh.constellation"
bl_label = "Constellation"
bl_description = "Create a Constellation Mesh"
bl_description = ("Create a Constellation Mesh - Cloud of Vertices\n"
"Note: can produce a lot of geometry\n"
"Needs an existing Active Mesh Object")
bl_options = {'REGISTER', 'UNDO'}
limit = FloatProperty(
name='Limit',
default=2,
min=0
)
name="Threshold",
description="Edges will be created only if the distance\n"
"between vertices is smaller than this value",
default=2,
min=0
)
@classmethod
def poll(cls, context):
return(bpy.context.active_object.type == "MESH")
obj = context.active_object
return (obj and obj.type == "MESH")
def invoke(self, context, event):
adv_obj = context.scene.advanced_objects
self.limit = adv_obj.constellation_limit
return self.execute(context)
def draw(self, context):
layout = self.layout
layout.prop(self, "limit")
def execute(self, context):
OscConstellation(self.limit)
try:
OscConstellation(self.limit)
except Exception as e:
print("\n[Add Advanced Objects]\nOperator: mesh.constellation\n{}".format(e))
self.report({"WARNING"},
"Constellation Operation could not be Completed (See Console for more Info)")
return {"CANCELLED"}
return {'FINISHED'}
# Register
def add_osc_constellation_button(self, context):
self.layout.operator(
Oscurart_Constellation.bl_idname,
text="Constellation",
icon="PLUGIN")
def register():
bpy.utils.register_class(Oscurart_Constellation)
bpy.types.INFO_MT_mesh_add.append(add_osc_constellation_button)
def unregister():
bpy.utils.unregister_class(Oscurart_Constellation)
bpy.types.INFO_MT_mesh_add.remove(add_osc_constellation_button)
if __name__ == '__main__':
if __name__ == "__main__":
register()

View File

@ -19,14 +19,13 @@
bl_info = {
"name": "Drop to Ground1",
"author": "Unnikrishnan(kodemax), Florian Meyer(testscreenings)",
"version": (1, 2),
"version": (1, 2, 1),
"blender": (2, 71, 0),
"location": "3D View > Toolshelf > Tools Tab",
"description": "Drop selected objects on active object",
"warning": "",
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/Object/Drop_to_ground",
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
"category": "Object"}
@ -59,6 +58,7 @@ def transform_ground_to_world(sc, ground):
tmp_ground = bpy.data.objects.new('tmpGround', tmpMesh)
sc.objects.link(tmp_ground)
sc.update()
return tmp_ground
@ -120,12 +120,16 @@ def drop_objectsall(self, context):
lowest_world_co = ob.location
else:
lowest_world_co = get_lowest_world_co(context, ob)
if not lowest_world_co:
print(ob.type, 'is not supported. Failed to drop', ob.name)
message = "Type {} is not supported. Failed to drop {}".format(ob.type, ob.name)
self.reported.append(message)
continue
is_hit, hit_location, hit_normal, hit_index = tmp_ground.ray_cast(lowest_world_co, down)
if not is_hit:
print(ob.name, 'didn\'t hit the ground')
message = ob.name + " did not hit the Ground"
self.reported.append(message)
continue
# simple drop down
@ -169,12 +173,16 @@ def drop_objects(self, context):
lowest_world_co = ob.location
else:
lowest_world_co = get_lowest_world_co(context, ob)
if not lowest_world_co:
print(ob.type, 'is not supported. Failed to drop', ob.name)
message = "Type {} is not supported. Failed to drop {}".format(ob.type, ob.name)
self.reported.append(message)
continue
is_hit, hit_location, hit_normal, hit_index = tmp_ground.ray_cast(lowest_world_co, down)
if not is_hit:
print(ob.name, 'didn\'t hit the ground')
message = ob.name + " did not hit the Ground"
self.reported.append(message)
continue
# simple drop down
@ -209,8 +217,8 @@ def drop_objects(self, context):
class OBJECT_OT_drop_to_ground(Operator):
bl_idname = "object.drop_on_active"
bl_label = "Drop to Ground"
bl_description = "Drop selected objects on the active object"
bl_options = {'REGISTER', 'UNDO'}
bl_description = "Drop selected objects on active object"
align = BoolProperty(
name="Align to ground",
@ -220,22 +228,31 @@ class OBJECT_OT_drop_to_ground(Operator):
name="Use Center",
description="Drop to objects origins",
default=False)
reported = []
@classmethod
def poll(cls, context):
return len(context.selected_objects) >= 2
def execute(self, context):
print('\nDropping Objects')
drop_objects(self, context)
if self.reported:
self.report({"INFO"},
"Operation failed on some objects. See the Console for more Info")
report_items = " \n".join(self.reported)
print("\n[Drop to Ground Report]\n{}\n".format(report_items))
self.reported = []
return {'FINISHED'}
class OBJECT_OT_drop_all_ground(Operator):
bl_idname = "object.drop_all_active"
bl_label = "Drop to Ground"
bl_options = {'REGISTER', 'UNDO'}
bl_label = "Drop All to Ground (Active Object)"
bl_description = "Drop selected objects on active object"
bl_options = {'REGISTER', 'UNDO'}
align = BoolProperty(
name="Align to ground",
@ -245,33 +262,45 @@ class OBJECT_OT_drop_all_ground(Operator):
name="Use Center",
description="Drop to objects origins",
default=False)
reported = []
@classmethod
def poll(cls, context):
return context.active_object is not None
def execute(self, context):
print('\nDropping Objects')
drop_objectsall(self, context)
if self.reported:
self.report({"INFO"},
"Operation failed on some objects. See the Console for more Info")
report_items = " \n".join(self.reported)
print("\n[Drop All to Ground Report]\n{}\n".format(report_items))
self.reported = []
return {'FINISHED'}
class drop_help(Operator):
class Drop_help(Operator):
bl_idname = "help.drop"
bl_label = ""
is_all = BoolProperty(
default=True,
options={"HIDDEN"}
)
def draw(self, context):
layout = self.layout
layout.label("To use:")
layout.label("___________________________")
layout.label("Drop selected :-")
layout.label("Name the base object 'Ground'")
layout.label("Select the object/s to drop")
layout.label("Then Shift Select 'Ground'")
layout.label("___________________________")
layout.label("Drop all :-")
layout.label("select the ground mesh , and press Drop all")
if self.is_all is False:
layout.label("Name the base object 'Ground'")
layout.label("Select the object's to drop")
layout.label("Then Shift Select 'Ground'")
else:
layout.label("Select the ground mesh and press Drop all")
def execute(self, context):
return {'FINISHED'}
@ -290,25 +319,31 @@ class Drop_Operator_Panel(Panel):
def draw(self, context):
layout = self.layout
row = layout.row()
row = layout.split(0.80)
row = layout.split(percentage=0.8, align=True)
row.operator(OBJECT_OT_drop_to_ground.bl_idname,
text="Drop Selected")
row = layout.row()
row.operator("help.drop", icon="LAYER_USED").is_all = False
row = layout.split(percentage=0.8, align=True)
row.operator(OBJECT_OT_drop_all_ground.bl_idname,
text="Drop All")
row.operator('help.drop', icon='INFO')
row.operator("help.drop", icon="LAYER_USED").is_all = True
# Register
def register():
bpy.utils.register_module(__name__)
pass
bpy.utils.register_class(OBJECT_OT_drop_all_ground)
bpy.utils.register_class(OBJECT_OT_drop_to_ground)
bpy.utils.register_class(Drop_Operator_Panel)
bpy.utils.register_class(Drop_help)
def unregister():
bpy.utils.unregister_module(__name__)
pass
bpy.utils.unregister_class(OBJECT_OT_drop_all_ground)
bpy.utils.unregister_class(OBJECT_OT_drop_to_ground)
bpy.utils.unregister_class(Drop_Operator_Panel)
bpy.utils.unregister_class(Drop_help)
if __name__ == "__main__":

View File

@ -21,22 +21,9 @@
# <pep8 compliant>
"""
bl_info = {
"name": "Strut Generator",
"author": "Bill Currie",
"blender": (2, 6, 3),
"api": 35622,
"location": "View3D > Add > Mesh > Struts",
"description": "Add struts meshes based on selected truss meshes",
"warning": "can get very high-poly",
"wiki_url": "",
"tracker_url": "",
"category": "Add Mesh"}
"""
import bpy
import bmesh
from bpy.types import Operator
from bpy.props import (
FloatProperty,
IntProperty,
@ -48,8 +35,7 @@ from mathutils import (
Quaternion,
)
from math import (
pi,
cos,
pi, cos,
sin,
)
@ -71,6 +57,7 @@ def build_cossin(n):
def select_up(axis):
# if axis.length != 0 and (abs(axis[0] / axis.length) < 1e-5 and abs(axis[1] / axis.length) < 1e-5):
if (abs(axis[0] / axis.length) < 1e-5 and abs(axis[1] / axis.length) < 1e-5):
up = Vector((-1, 0, 0))
else:
@ -109,21 +96,21 @@ def select_up(axis):
# vertices for the created strut.
def make_strut(v1, v2, id, od, n, solid, loops):
def make_strut(v1, v2, ind, od, n, solid, loops):
v1 = Vector(v1)
v2 = Vector(v2)
axis = v2 - v1
pos = [(0, od / 2)]
if loops:
pos += [((od - id) / 2, od / 2),
(axis.length - (od - id) / 2, od / 2)]
pos += [((od - ind) / 2, od / 2),
(axis.length - (od - ind) / 2, od / 2)]
pos += [(axis.length, od / 2)]
if solid:
pos += [(axis.length, id / 2)]
pos += [(axis.length, ind / 2)]
if loops:
pos += [(axis.length - (od - id) / 2, id / 2),
((od - id) / 2, id / 2)]
pos += [(0, id / 2)]
pos += [(axis.length - (od - ind) / 2, ind / 2),
((od - ind) / 2, ind / 2)]
pos += [(0, ind / 2)]
vps = len(pos)
fps = vps
if not solid:
@ -156,7 +143,7 @@ def make_strut(v1, v2, id, od, n, solid, loops):
for j in range(fps):
f = (i - 1) * fps + j
faces[f] = [base + j, j, (j + 1) % vps, base + (j + 1) % vps]
# print(verts,faces)
return verts, faces
@ -452,7 +439,7 @@ def make_manifold_struts(truss_obj, od, segments):
return verts, faces
def make_simple_struts(truss_mesh, id, od, segments, solid, loops):
def make_simple_struts(truss_mesh, ind, od, segments, solid, loops):
vps = 2
if solid:
vps *= 2
@ -466,10 +453,11 @@ def make_simple_struts(truss_mesh, id, od, segments, solid, loops):
faces = [None] * len(truss_mesh.edges) * segments * fps
vbase = 0
fbase = 0
for e in truss_mesh.edges:
v1 = truss_mesh.vertices[e.vertices[0]]
v2 = truss_mesh.vertices[e.vertices[1]]
v, f = make_strut(v1.co, v2.co, id, od, segments, solid, loops)
v, f = make_strut(v1.co, v2.co, ind, od, segments, solid, loops)
for fv in f:
for i in range(len(fv)):
fv[i] += vbase
@ -481,14 +469,13 @@ def make_simple_struts(truss_mesh, id, od, segments, solid, loops):
# print (base * 100 / len(verts))
vbase += vps * segments
fbase += fps * segments
# print(verts,faces)
return verts, faces
def create_struts(self, context, id, od, segments, solid, loops, manifold):
def create_struts(self, context, ind, od, segments, solid, loops, manifold):
build_cossin(segments)
bpy.context.user_preferences.edit.use_global_undo = False
for truss_obj in bpy.context.scene.objects:
if not truss_obj.select:
continue
@ -499,7 +486,7 @@ def create_struts(self, context, id, od, segments, solid, loops, manifold):
if manifold:
verts, faces = make_manifold_struts(truss_obj, od, segments)
else:
verts, faces = make_simple_struts(truss_mesh, id, od, segments,
verts, faces = make_simple_struts(truss_mesh, ind, od, segments,
solid, loops)
mesh = bpy.data.meshes.new("Struts")
mesh.from_pydata(verts, [], faces)
@ -509,58 +496,92 @@ def create_struts(self, context, id, od, segments, solid, loops, manifold):
obj.location = truss_obj.location
bpy.context.scene.objects.active = obj
mesh.update()
bpy.context.user_preferences.edit.use_global_undo = True
return {'FINISHED'}
class Struts(bpy.types.Operator):
"""Add one or more struts meshes based on selected truss meshes"""
class Struts(Operator):
bl_idname = "mesh.generate_struts"
bl_label = "Struts"
bl_description = """Add one or more struts meshes based on selected truss meshes"""
bl_description = ("Add one or more struts meshes based on selected truss meshes \n"
"Note: can get very high poly\n"
"Needs an existing Active Mesh Object")
bl_options = {'REGISTER', 'UNDO'}
id = FloatProperty(name="Inside Diameter",
description="diameter of inner surface",
min=0.0,
soft_min=0.0,
max=100,
soft_max=100,
default=0.04)
od = FloatProperty(name="Outside Diameter",
description="diameter of outer surface",
min=0.001,
soft_min=0.001,
max=100,
soft_max=100,
default=0.05)
manifold = BoolProperty(name="Manifold",
description="Connect struts to form a single solid.",
default=False)
solid = BoolProperty(name="Solid",
description="Create inner surface.",
default=False)
loops = BoolProperty(name="Loops",
description="Create sub-surf friendly loops.",
default=False)
segments = IntProperty(name="Segments",
description="Number of segments around strut",
min=3, soft_min=3,
max=64, soft_max=64,
default=12)
ind = FloatProperty(
name="Inside Diameter",
description="Diameter of inner surface",
min=0.0, soft_min=0.0,
max=100, soft_max=100,
default=0.04
)
od = FloatProperty(
name="Outside Diameter",
description="Diameter of outer surface",
min=0.001, soft_min=0.001,
max=100, soft_max=100,
default=0.05
)
manifold = BoolProperty(
name="Manifold",
description="Connect struts to form a single solid",
default=False
)
solid = BoolProperty(
name="Solid",
description="Create inner surface",
default=False
)
loops = BoolProperty(
name="Loops",
description="Create sub-surf friendly loops",
default=False
)
segments = IntProperty(
name="Segments",
description="Number of segments around strut",
min=3, soft_min=3,
max=64, soft_max=64,
default=12
)
def draw(self, context):
layout = self.layout
col = layout.column(align=True)
col.prop(self, "ind")
col.prop(self, "od")
col.prop(self, "segments")
col.separator()
col.prop(self, "manifold")
col.prop(self, "solid")
col.prop(self, "loops")
@classmethod
def poll(cls, context):
obj = context.active_object
return obj is not None and obj.type == "MESH"
def execute(self, context):
store_undo = bpy.context.user_preferences.edit.use_global_undo
bpy.context.user_preferences.edit.use_global_undo = False
keywords = self.as_keywords()
return create_struts(self, context, **keywords)
try:
create_struts(self, context, **keywords)
bpy.context.user_preferences.edit.use_global_undo = store_undo
def menu_func(self, context):
self.layout.operator(Struts.bl_idname, text="Struts", icon='PLUGIN')
return {"FINISHED"}
except Exception as e:
bpy.context.user_preferences.edit.use_global_undo = store_undo
self.report({"WARNING"},
"Make Struts could not be performed. Operation Cancelled")
print("\n[mesh.generate_struts]\n{}".format(e))
return {"CANCELLED"}
def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_mesh_add.append(menu_func)
def unregister():

View File

@ -16,11 +16,12 @@
#
# ##### END GPL LICENSE BLOCK #####
# TODO: find a better solution for allowing more than one lattice per scene
bl_info = {
"name": "Easy Lattice Object",
"author": "Kursad Karatas",
"version": (0, 5),
"version": (0, 5, 1),
"blender": (2, 66, 0),
"location": "View3D > Easy Lattice",
"description": "Create a lattice for shape editing",
@ -35,9 +36,11 @@ from mathutils import (
Matrix,
Vector,
)
from bpy.types import Operator
from bpy.props import (
EnumProperty,
IntProperty,
StringProperty,
)
@ -86,7 +89,8 @@ def createLattice(obj, size, pos, props):
# the size from bbox
ob.scale = size
# the rotation comes from the combined obj world matrix which was converted to euler pairs
# the rotation comes from the combined obj world
# matrix which was converted to euler pairs
ob.rotation_euler = buildRot_World(obj)
ob.show_x_ray = True
@ -263,10 +267,11 @@ def run(lat_props):
if obj.type == "MESH":
# set global property for the currently active latticed object
bpy.types.Scene.activelatticeobject = bpy.props.StringProperty(
name="currentlatticeobject",
default=""
)
# removed in __init__ on unregister if created
bpy.types.Scene.activelatticeobject = StringProperty(
name="currentlatticeobject",
default=""
)
bpy.types.Scene.activelatticeobject = obj.name
modifiersDelete(obj)
@ -311,70 +316,85 @@ def main(context, latticeprops):
run(latticeprops)
class EasyLattice(bpy.types.Operator):
"""Adds a Lattice modifier ready to edit"""
class EasyLattice(Operator):
bl_idname = "object.easy_lattice"
bl_label = "Easy Lattice Creator"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_description = ("Create a Lattice modifier ready to edit\n"
"Needs an existing Active Mesh Object\n"
"Note: Works only with one lattice per scene")
lat_u = IntProperty(
name="Lattice u",
default=3
)
name="Lattice u",
description="Points in u direction",
default=3
)
lat_w = IntProperty(
name="Lattice w",
default=3
)
name="Lattice w",
description="Points in w direction",
default=3
)
lat_m = IntProperty(
name="Lattice m",
default=3
name="Lattice m",
description="Points in m direction",
default=3
)
lat_types = (('KEY_LINEAR', "Linear", "Linear Interpolation type"),
('KEY_CARDINAL', "Cardinal", "Cardinal Interpolation type"),
('KEY_BSPLINE', "BSpline", "Key BSpline Interpolation Type")
)
lat_types = (('0', 'KEY_LINEAR', '0'),
('1', 'KEY_CARDINAL', '1'),
('2', 'KEY_BSPLINE', '2'))
lat_type = EnumProperty(
name="Lattice Type",
items=lat_types,
default='0'
)
name="Lattice Type",
description="Choose Lattice Type",
items=lat_types,
default='KEY_LINEAR'
)
@classmethod
def poll(cls, context):
return context.active_object is not None
obj = context.active_object
return obj is not None and obj.type == "MESH"
def draw(self, context):
layout = self.layout
col = layout.column(align=True)
col.prop(self, "lat_u")
col.prop(self, "lat_w")
col.prop(self, "lat_m")
layout.prop(self, "lat_type")
def execute(self, context):
lat_u = self.lat_u
lat_w = self.lat_w
lat_m = self.lat_m
# this is a reference to the "items" used to generate the
# enum property
lat_type = self.lat_types[int(self.lat_type)][1]
# enum property no need to complicate things
lat_type = self.lat_type
lat_props = [lat_u, lat_w, lat_m, lat_type]
try:
main(context, lat_props)
main(context, lat_props)
except Exception as e:
print("\n[Add Advanced Objects]\nOperator:object.easy_lattice\n{}\n".format(e))
self.report({'WARNING'},
"Easy Lattice Creator could not be completed (See Console for more info)")
return {'FINISHED'}
return {"CANCELLED"}
return {"FINISHED"}
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self)
def menu_draw(self, context):
self.layout.operator_context = 'INVOKE_REGION_WIN'
self.layout.operator(EasyLattice.bl_idname, "Easy Lattice")
def register():
bpy.utils.register_class(EasyLattice)
bpy.types.VIEW3D_MT_edit_mesh_specials.append(menu_draw)
def unregister():
bpy.utils.unregister_class(EasyLattice)
bpy.types.VIEW3D_MT_edit_mesh_specials.remove(menu_draw)
if __name__ == "__main__":

View File

@ -30,20 +30,18 @@ bl_info = {
}
import bpy
from bpy.types import (
Operator,
Panel,
)
from bpy.types import Operator
def Add_Chain():
# Adds Empty to scene
bpy.ops.object.add(type='EMPTY',
view_align=False,
enter_editmode=False,
location=(0, 0, 0),
rotation=(0, 0, 0),
)
bpy.ops.object.add(
type='EMPTY',
view_align=False,
enter_editmode=False,
location=(0, 0, 0),
rotation=(0, 0, 0),
)
# Changes name of Empty to rot_link adds variable emp
emp = bpy.context.object
@ -53,24 +51,26 @@ def Add_Chain():
emp.rotation_euler = [1.570796, 0, 0]
# Adds Curve Path to scene
bpy.ops.curve.primitive_nurbs_path_add(view_align=False,
enter_editmode=False,
location=(0, 0, 0),
rotation=(0, 0, 0),
)
bpy.ops.curve.primitive_nurbs_path_add(
view_align=False,
enter_editmode=False,
location=(0, 0, 0),
rotation=(0, 0, 0),
)
# Change Curve name to deform adds variable curv
curv = bpy.context.object
curv.name = "deform"
# Inserts Torus primitive
bpy.ops.mesh.primitive_torus_add(major_radius=1,
minor_radius=0.25,
major_segments=12,
minor_segments=4,
abso_major_rad=1,
abso_minor_rad=0.5,
)
bpy.ops.mesh.primitive_torus_add(
major_radius=1,
minor_radius=0.25,
major_segments=12,
minor_segments=4,
abso_major_rad=1,
abso_minor_rad=0.5,
)
# Positions Torus primitive to center of scene
bpy.context.active_object.location = 0.0, 0.0, 0.0
@ -98,22 +98,23 @@ def Add_Chain():
# Toggle into editmode
bpy.ops.object.editmode_toggle()
# TODO, may be better to move objects directly.
# TODO, may be better to move objects directly
# Translate curve object
bpy.ops.transform.translate(value=(2, 0, 0),
constraint_axis=(True, False, False),
constraint_orientation='GLOBAL',
mirror=False,
proportional='DISABLED',
proportional_edit_falloff='SMOOTH',
proportional_size=1,
snap=False,
snap_target='CLOSEST',
snap_point=(0, 0, 0),
snap_align=False,
snap_normal=(0, 0, 0),
release_confirm=False,
)
bpy.ops.transform.translate(
value=(2, 0, 0),
constraint_axis=(True, False, False),
constraint_orientation='GLOBAL',
mirror=False,
proportional='DISABLED',
proportional_edit_falloff='SMOOTH',
proportional_size=1,
snap=False,
snap_target='CLOSEST',
snap_point=(0, 0, 0),
snap_align=False,
snap_normal=(0, 0, 0),
release_confirm=False,
)
# Toggle into objectmode
bpy.ops.object.editmode_toggle()
@ -151,19 +152,27 @@ class AddChain(Operator):
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
Add_Chain()
try:
Add_Chain()
except Exception as e:
self.report({'WARNING'},
"Some operations could not be performed (See Console for more info)")
print("\n[Add Advanced Objects]\nOperator: "
"mesh.primitive_chain_add\nError: {}".format(e))
return {'CANCELLED'}
return {'FINISHED'}
def register():
bpy.utils.register_module(__name__)
pass
bpy.utils.register_class(AddChain)
def unregister():
bpy.utils.unregister_module(__name__)
pass
bpy.utils.unregister_class(AddChain)
if __name__ == "__main__":

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
# mangle_tools.py (c) 2011 Phil Cote (cotejrp1)
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# ###### 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
@ -10,36 +9,43 @@
#
# 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
# 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, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ***** END GPL LICENCE BLOCK *****
# ###### END GPL LICENCE BLOCK ######
# Note: properties are moved into __init__
bl_info = {
"name": "Mangle Tools",
"author": "Phil Cote",
"version": (0, 2),
"version": (0, 2, 2),
"blender": (2, 71, 0),
"location": "View3D > Toolshelf > Tools Tab",
"description": "Set of tools to mangle curves, meshes, and shape keys",
"warning": "", # used for warning icon and text in addons panel
"warning": "",
"wiki_url": "",
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
"category": "Object"}
import bpy
import random
from bpy.types import (
Operator,
Panel,
)
import time
from math import pi
import bmesh
def move_coordinate(context, co, is_curve=False):
xyz_const = context.scene.constraint_vector
advanced_objects = context.scene.advanced_objects
xyz_const = advanced_objects.mangle_constraint_vector
random.seed(time.time())
multiplier = 1
@ -47,95 +53,100 @@ def move_coordinate(context, co, is_curve=False):
# This helps make curve changes more noticable.
if is_curve:
multiplier = 2 * pi
random_mag = context.scene.random_magnitude
random_mag = advanced_objects.mangle_random_magnitude
if xyz_const[0]:
co.x += .01 * random.randrange( -random_mag, random_mag ) * multiplier
co.x += .01 * random.randrange(-random_mag, random_mag) * multiplier
if xyz_const[1]:
co.y += .01 * random.randrange( -random_mag, random_mag ) * multiplier
co.y += .01 * random.randrange(-random_mag, random_mag) * multiplier
if xyz_const[2]:
co.z += .01 * random.randrange( -random_mag, random_mag ) * multiplier
co.z += .01 * random.randrange(-random_mag, random_mag) * multiplier
class MeshManglerOperator(bpy.types.Operator):
"""Push vertices on the selected object around in random """ \
"""directions to create a crumpled look"""
class MeshManglerOperator(Operator):
bl_idname = "ba.mesh_mangler"
bl_label = "Mangle Mesh"
bl_options = { "REGISTER", "UNDO" }
bl_description = ("Push vertices on the selected object around in random\n"
"directions to create a crumpled look")
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
ob = context.active_object
return ob != None and ob.type == 'MESH'
return ob is not None and ob.type == 'MESH'
def execute(self, context):
mesh = context.active_object.data
bm = bmesh.new()
bm.from_mesh(mesh)
verts, faces = bm.verts, bm.faces
randomMag = context.scene.random_magnitude
random.seed( time.time() )
verts = bm.verts
advanced_objects = context.scene.advanced_objects
randomMag = advanced_objects.mangle_random_magnitude
random.seed(time.time())
if mesh.shape_keys != None:
self.report({'INFO'}, "Cannot mangle mesh: Shape keys present")
if mesh.shape_keys is not None:
self.report({'INFO'},
"Cannot mangle mesh: Shape keys present. Operation Cancelled")
return {'CANCELLED'}
for vert in verts:
xVal = .01 * random.randrange( -randomMag, randomMag )
yVal = .01 * random.randrange( -randomMag, randomMag)
zVal = .01 * random.randrange( -randomMag, randomMag )
xVal = .01 * random.randrange(-randomMag, randomMag)
yVal = .01 * random.randrange(-randomMag, randomMag)
zVal = .01 * random.randrange(-randomMag, randomMag)
vert.co.x = vert.co.x + xVal
vert.co.y = vert.co.y + yVal
vert.co.z = vert.co.z + zVal
del verts
bm.to_mesh(mesh)
mesh.update()
return {'FINISHED'}
class AnimanglerOperator(bpy.types.Operator):
"""Make a shape key and pushes the verts around on it """ \
"""to set up for random pulsating animation"""
class AnimanglerOperator(Operator):
bl_idname = "ba.ani_mangler"
bl_label = "Mangle Shape Key"
bl_description = ("Make a shape key and pushes the verts around on it\n"
"to set up for random pulsating animation")
@classmethod
def poll(cls, context):
ob = context.active_object
return ob != None and ob.type in [ 'MESH', 'CURVE' ]
return ob is not None and ob.type in ['MESH', 'CURVE']
def execute(self, context):
scn = context.scene
scn = context.scene.advanced_objects
mangleName = scn.mangle_name
ob = context.object
shapeKey = ob.shape_key_add( name=mangleName )
shapeKey = ob.shape_key_add(name=mangleName)
verts = shapeKey.data
for vert in verts:
move_coordinate(context, vert.co, is_curve=ob.type=='CURVE')
move_coordinate(context, vert.co, is_curve=ob.type == 'CURVE')
return {'FINISHED'}
class CurveManglerOp(bpy.types.Operator):
"""Mangle a curve to the degree the user specifies"""
class CurveManglerOp(Operator):
bl_idname = "ba.curve_mangler"
bl_label = "Mangle Curve"
bl_options = { 'REGISTER', 'UNDO' }
bl_description = "Mangle a curve to the degree the user specifies"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
ob = context.active_object
return ob != None and ob.type == "CURVE"
return ob is not None and ob.type == "CURVE"
def execute(self, context):
ob = context.active_object
if ob.data.shape_keys != None:
self.report({'INFO'}, "Cannot mangle curve. Shape keys present")
if ob.data.shape_keys is not None:
self.report({'INFO'},
"Cannot mangle curve. Shape keys present. Operation Cancelled")
return {'CANCELLED'}
splines = context.object.data.splines
for spline in splines:
@ -150,56 +161,43 @@ class CurveManglerOp(bpy.types.Operator):
return {'FINISHED'}
class MangleToolsPanel(bpy.types.Panel):
class MangleToolsPanel(Panel):
bl_label = "Mangle Tools"
bl_space_type = "VIEW_3D"
bl_context = "objectmode"
bl_region_type="TOOLS"
bl_region_type = "TOOLS"
bl_category = "Create"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
scn = context.scene
scn = context.scene.advanced_objects
obj = context.object
if obj.type in ['MESH',]:
if obj and obj.type in ['MESH']:
layout = self.layout
row = layout.row(align=True)
row.prop(scn, "mangle_constraint_vector", toggle=True)
col = layout.column()
col.prop(scn, "constraint_vector")
col.prop(scn, "random_magnitude")
col.prop(scn, "mangle_random_magnitude")
col.operator("ba.mesh_mangler")
col.separator()
col.prop(scn, "mangle_name")
col.operator("ba.ani_mangler")
else:
layout = self.layout
col = layout.column()
col.label("Please Select Mesh Object")
layout.label(text="Please select a Mesh Object", icon="INFO")
IntProperty = bpy.props.IntProperty
StringProperty = bpy.props.StringProperty
BoolVectorProperty = bpy.props.BoolVectorProperty
def register():
bpy.utils.register_class(AnimanglerOperator)
bpy.utils.register_class(MeshManglerOperator)
bpy.utils.register_class(CurveManglerOp)
bpy.utils.register_class(MangleToolsPanel)
scnType = bpy.types.Scene
scnType.constraint_vector = BoolVectorProperty(name="Mangle Constraint",
default=(True,True,True),
subtype='XYZ',
description="Constrains Mangle Direction")
scnType.random_magnitude = IntProperty( name = "Mangle Severity",
default = 5, min = 1, max = 30,
description = "Severity of mangling")
scnType.mangle_name = StringProperty(name="Shape Key Name",
default="mangle",
description="Name given for mangled shape keys")
def unregister():
bpy.utils.unregister_class(AnimanglerOperator)
bpy.utils.unregister_class(MeshManglerOperator)

View File

@ -16,7 +16,7 @@
#
# ##### END GPL LICENSE BLOCK #####
# TODO: translate the comments into English
# TODO: find English versions of created object names
bl_info = {
"name": "Oscurart Chain Maker",
@ -27,7 +27,6 @@ bl_info = {
"description": "Create chain links from armatures",
"warning": "",
"wiki_url": "oscurart.blogspot.com",
"tracker_url": "",
"category": "Object"}
@ -52,7 +51,7 @@ def makeChain(self, context, mult, curverig):
def creahuesocero(hueso):
# create data to link
mesh = bpy.data.meshes.new("objectData" + str(hueso.name))
object = bpy.data.objects.new("EslabonCero" + str(hueso.name), mesh)
object = bpy.data.objects.new("HardLink" + str(hueso.name), mesh)
mesh.from_pydata(
[(-0.04986128956079483, -0.6918092370033264, -0.17846597731113434),
(-0.04986128956079483, -0.6918091773986816, 0.17846640944480896),
@ -93,18 +92,18 @@ def makeChain(self, context, mult, curverig):
mesh.validate()
bpy.context.scene.objects.link(object)
# scale to the bone
bpy.data.objects['EslabonCero' + str(hueso.name)].scale = (hueso.length * mult,
hueso.length * mult,
hueso.length * mult)
bpy.data.objects["HardLink" + str(hueso.name)].scale = (hueso.length * mult,
hueso.length * mult,
hueso.length * mult)
# Parent Objects
bpy.data.objects['EslabonCero' + str(hueso.name)].parent = ARMATURE
bpy.data.objects['EslabonCero' + str(hueso.name)].parent_type = 'BONE'
bpy.data.objects['EslabonCero' + str(hueso.name)].parent_bone = hueso.name
bpy.data.objects["HardLink" + str(hueso.name)].parent = ARMATURE
bpy.data.objects["HardLink" + str(hueso.name)].parent_type = 'BONE'
bpy.data.objects["HardLink" + str(hueso.name)].parent_bone = hueso.name
def creahuesonoventa(hueso):
# create data to link
mesh = bpy.data.meshes.new("objectData" + str(hueso.name))
object = bpy.data.objects.new("EslabonNov" + str(hueso.name), mesh)
object = bpy.data.objects.new("NewLink" + str(hueso.name), mesh)
mesh.from_pydata(
[(0.1784660965204239, -0.6918091773986816, -0.049861203879117966),
(-0.1784662902355194, -0.6918091773986816, -0.04986126348376274),
@ -145,13 +144,13 @@ def makeChain(self, context, mult, curverig):
mesh.validate()
bpy.context.scene.objects.link(object)
# scale to the bone
bpy.data.objects['EslabonNov' + str(hueso.name)].scale = (hueso.length * mult,
bpy.data.objects["NewLink" + str(hueso.name)].scale = (hueso.length * mult,
hueso.length * mult,
hueso.length * mult)
# Parent objects
bpy.data.objects['EslabonNov' + str(hueso.name)].parent = ARMATURE
bpy.data.objects['EslabonNov' + str(hueso.name)].parent_type = 'BONE'
bpy.data.objects['EslabonNov' + str(hueso.name)].parent_bone = hueso.name
bpy.data.objects["NewLink" + str(hueso.name)].parent = ARMATURE
bpy.data.objects["NewLink" + str(hueso.name)].parent_type = 'BONE'
bpy.data.objects["NewLink" + str(hueso.name)].parent_bone = hueso.name
for hueso in bpy.context.active_object.pose.bones:
if VAR_SWITCH == 1:
@ -182,18 +181,16 @@ def makeChain(self, context, mult, curverig):
# create the list of tail and head coordinates
LISTA_POINTC.append((
ACTARM.data.bones[0].head_local[0],
ACTARM.data.bones[0].head_local[1],
ACTARM.data.bones[0].head_local[2],
1
))
ACTARM.data.bones[0].head_local[0],
ACTARM.data.bones[0].head_local[1],
ACTARM.data.bones[0].head_local[2], 1
))
for hueso in ACTARM.data.bones:
LISTA_POINTC.append((
hueso.tail_local[0],
hueso.tail_local[1],
hueso.tail_local[2],
1
hueso.tail_local[2], 1
))
# create the Spline
@ -249,14 +246,14 @@ class MESH_OT_primitive_oscurart_chain_add(Operator):
bl_options = {'REGISTER', 'UNDO'}
curverig = BoolProperty(
name="Curve Rig",
default=False
)
name="Curve Rig",
default=False
)
multiplier = FloatProperty(
name="Scale",
default=1,
min=0.01, max=100.0
)
name="Scale",
default=1,
min=0.01, max=100.0
)
@classmethod
def poll(cls, context):
@ -264,7 +261,18 @@ class MESH_OT_primitive_oscurart_chain_add(Operator):
return (obj is not None and obj.type == "ARMATURE")
def execute(self, context):
makeChain(self, context, self.multiplier, self.curverig)
try:
makeChain(self, context, self.multiplier, self.curverig)
except Exception as e:
self.report({'WARNING'},
"Some operations could not be performed (See Console for more info)")
print("\n[Add Advanced Objects]\nOperator: "
"mesh.primitive_oscurart_chain_add\nError: {}".format(e))
return {'CANCELLED'}
return {'FINISHED'}

View File

@ -1,28 +1,25 @@
#######################################################
# gpl author: liero
# very simple 'pixelization' or 'voxelization' engine #
#######################################################
bl_info = {
"name": "3D Pix",
"name": "3D Pixelate",
"author": "liero",
"version": (0, 5, 1),
"version": (0, 5, 2),
"blender": (2, 74, 0),
"location": "View3D > Tool Shelf",
"description": "Creates a 3d pixelated version of the object.",
"description": "Creates a 3d pixelated version of the object",
"category": "Object"}
import bpy
import mathutils
from mathutils import Vector
# Note: winmgr properties are moved into __init__
# search for patterns advanced_objects and adv_obj
bpy.types.WindowManager.size = bpy.props.FloatProperty(name='Size', min=.05, max=5, default=.25, description='Size of the cube / grid')
bpy.types.WindowManager.gap = bpy.props.IntProperty(name='Gap', min=0, max=90, default=10, subtype='PERCENTAGE', description='Separation - percent of size')
bpy.types.WindowManager.smooth = bpy.props.FloatProperty(name='Smooth', min=0, max=1, default=.0, description='Smooth factor when subdividing mesh')
import bpy
from bpy.types import Operator
def pix(obj):
sce = bpy.context.scene
wm = bpy.context.window_manager
props = sce.advanced_objects
obj.hide = obj.hide_render = True
mes = obj.to_mesh(sce, True, 'RENDER')
mes.transform(obj.matrix_world)
@ -37,12 +34,12 @@ def pix(obj):
fin = True
for i in dup.data.edges:
d = ver[i.vertices[0]].co - ver[i.vertices[1]].co
if d.length > wm.size:
if d.length > props.pixelate_3d_size:
ver[i.vertices[0]].select = True
ver[i.vertices[1]].select = True
fin = False
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.subdivide(number_cuts=1, smoothness=wm.smooth)
bpy.ops.mesh.subdivide(number_cuts=1, smoothness=props.pixelate_3d_smooth)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.editmode_toggle()
if fin:
@ -50,55 +47,68 @@ def pix(obj):
for i in ver:
for n in range(3):
i.co[n] -= (.001 + i.co[n]) % wm.size
i.co[n] -= (.001 + i.co[n]) % props.pixelate_3d_size
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.remove_doubles(threshold=0.0001)
bpy.ops.mesh.delete(type='EDGE_FACE')
bpy.ops.object.mode_set()
sca = wm.size * (100 - wm.gap) * .005
sca = props.pixelate_3d_size * (100 - props.pixelate_3d_gap) * .005
bpy.ops.mesh.primitive_cube_add(layers=[True] + [False] * 19)
bpy.ops.transform.resize(value=[sca] * 3)
bpy.context.scene.objects.active = dup
bpy.ops.object.parent_set(type='OBJECT')
class Pixelate(bpy.types.Operator):
bl_idname = 'object.pixelate'
bl_label = 'Pixelate Object'
bl_description = 'Create a 3d pixelated version of the object.'
class Pixelate(Operator):
bl_idname = "object.pixelate"
bl_label = "Pixelate Object"
bl_description = ("Create a 3d pixelated version of the object\n"
"using a Duplivert Box around each copied vertex\n"
"With high poly objects, it can take some time\n"
"Needs an existing Active Mesh Object")
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return (context.active_object and context.active_object.type == 'MESH' and context.mode == 'OBJECT')
return (context.active_object and
context.active_object.type == 'MESH' and
context.mode == 'OBJECT')
def draw(self, context):
layout = self.layout
adv_obj = context.scene.advanced_objects
column = layout.column(align=True)
column.prop(context.window_manager, "size")
column.prop(context.window_manager, "gap")
layout.prop(context.window_manager, "smooth")
col = layout.column(align=True)
col.prop(adv_obj, "pixelate_size")
col.prop(adv_obj, "pixelate_gap")
layout.prop(adv_obj, "pixelate_smooth")
def execute(self, context):
objeto = bpy.context.object
pix(objeto)
objeto = context.active_object
try:
pix(objeto)
except Exception as e:
self.report({'WARNING'},
"Some operations could not be performed (See Console for more info)")
print("\n[Add Advanced Objects]\nOperator: "
"object.pixelate\nError: {}".format(e))
return {'CANCELLED'}
return {'FINISHED'}
classes = (
Pixelate,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.utils.register_class(Pixelate)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
bpy.utils.unregister_class(Pixelate)
if __name__ == '__main__':
register()

View File

@ -1,9 +1,11 @@
# gpl: author Dannyboy
bl_info = {
"name": "Add Random Box Structure",
"author": "Dannyboy",
"version": (1, 0),
"version": (1, 0, 1),
"location": "View3D > Add > Make Box Structure",
"description": "Fill selected box shaped meshes with randomly sized cubes.",
"description": "Fill selected box shaped meshes with randomly sized cubes",
"warning": "",
"wiki_url": "",
"tracker_url": "dannyboypython.blogspot.com",
@ -23,45 +25,70 @@ from bpy.props import (
class makestructure(Operator):
bl_idname = "object.make_structure"
bl_label = "Add Random Box Structure"
bl_description = ("Create a randomized structure made of boxes\n"
"with various control parameters\n"
"Needs an existing Active Mesh Object")
bl_options = {'REGISTER', 'UNDO'}
dc = BoolProperty(
name="Delete Base Mesh(s)?",
default=True
)
name="Delete Base Mesh(es)",
default=True
)
wh = BoolProperty(
name="Stay Within Base Mesh(s)?",
description="Keeps cubes from exceeding base mesh bounds",
default=True
)
name="Stay Within Bounds",
description="Keeps cubes from exceeding base mesh bounds",
default=True
)
uf = BoolProperty(
name="Uniform Cube Quantity",
default=False
)
name="Uniform Cube Quantity",
default=False
)
qn = IntProperty(
name="Cube Quantity",
default=10,
min=1, max=1500
)
name="Cube Quantity",
default=10,
min=1, max=1500
)
mn = FloatVectorProperty(
name="Min Scales",
default=(0.1, 0.1, 0.1),
subtype='XYZ'
)
name="Min Scales",
default=(0.1, 0.1, 0.1),
subtype='XYZ'
)
mx = FloatVectorProperty(
name="Max Scales",
default=(2.0, 2.0, 2.0),
subtype='XYZ'
)
name="Max Scales",
default=(2.0, 2.0, 2.0),
subtype='XYZ'
)
lo = FloatVectorProperty(
name="XYZ Offset",
default=(0.0, 0.0, 0.0),
subtype='XYZ'
)
name="XYZ Offset",
default=(0.0, 0.0, 0.0),
subtype='XYZ'
)
rsd = FloatProperty(
name="Random Seed",
default=1
)
name="Random Seed",
default=1
)
@classmethod
def poll(cls, context):
obj = context.active_object
return obj is not None and obj.type == "MESH" and obj.mode == "OBJECT"
def draw(self, context):
layout = self.layout
box = layout.box()
box.label(text="Options:")
box.prop(self, "dc")
box.prop(self, "wh")
box.prop(self, "uf")
box = layout.box()
box.label(text="Parameters:")
box.prop(self, "qn")
box.prop(self, "mn")
box.prop(self, "mx")
box.prop(self, "lo")
box.prop(self, "rsd")
def execute(self, context):
rsdchange = self.rsd
@ -69,8 +96,10 @@ class makestructure(Operator):
uvyes = 0
bpy.ops.group.create(name='Cubagrouper')
bpy.ops.group.objects_remove()
for ob in bpy.context.selected_objects:
oblst.append(ob)
for obj in oblst:
bpy.ops.object.select_pattern(pattern=obj.name) # Select base mesh
bpy.context.scene.objects.active = obj
@ -85,18 +114,19 @@ class makestructure(Operator):
area = dim.x * dim.y * dim.z
else:
area = 75
for cube in range(round((area / 75) * self.qn)):
random.seed(rsdchange)
pmn = self.mn # Proxy values
pmx = self.mx
if self.wh is True:
if dim.x < pmx.x: # Keeping things from exceeding proper size.
if dim.x < pmx.x: # Keeping things from exceeding proper size
pmx.x = dim.x
if dim.y < pmx.y:
pmx.y = dim.y
if dim.z < pmx.z:
pmx.z = dim.z
if 0.0 > pmn.x: # Keeping things from going under zero.
if 0.0 > pmn.x: # Keeping things from going under zero
pmn.x = 0.0
if 0.0 > pmn.y:
pmn.y = 0.0
@ -105,7 +135,7 @@ class makestructure(Operator):
sx = (random.random() * (pmx.x - pmn.x)) + pmn.x # Just changed self.mx and .mn to pmx.
sy = (random.random() * (pmx.y - pmn.y)) + pmn.y
sz = (random.random() * (pmx.z - pmn.z)) + pmn.z
if self.wh is True: # This keeps the cubes within the base mesh.
if self.wh is True: # This keeps the cubes within the base mesh
ex = (random.random() * (dim.x - sx)) - ((dim.x - sx) / 2) + obj.location.x
wy = (random.random() * (dim.y - sy)) - ((dim.y - sy) / 2) + obj.location.y
ze = (random.random() * (dim.z - sz)) - ((dim.z - sz) / 2) + obj.location.z
@ -119,74 +149,52 @@ class makestructure(Operator):
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.transform.resize(
value=(sx, sy, sz), constraint_axis=(True, True, True),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
)
value=(sx, sy, sz), constraint_axis=(True, True, True),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
)
bpy.ops.object.mode_set(mode='OBJECT')
select = bpy.context.object # This is used to keep something selected for poll().
select = bpy.context.object # This is used to keep something selected for poll()
bpy.ops.object.group_link(group='Cubagrouper')
rsdchange += 3
bpy.ops.object.select_grouped(type='GROUP')
bpy.ops.transform.rotate(
value=rot[0], axis=(1, 0, 0), constraint_axis=(False, False, False),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
)
value=rot[0], axis=(1, 0, 0), constraint_axis=(False, False, False),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
)
bpy.ops.transform.rotate(
value=rot[1], axis=(0, 1, 0), constraint_axis=(False, False, False),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
)
value=rot[1], axis=(0, 1, 0), constraint_axis=(False, False, False),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
)
bpy.ops.transform.rotate(
value=rot[2], axis=(0, 0, 1), constraint_axis=(False, False, False),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
)
bpy.context.scene.objects.active = obj # Again needed to avoid poll() taking me down.
value=rot[2], axis=(0, 0, 1), constraint_axis=(False, False, False),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1, release_confirm=True
)
bpy.context.scene.objects.active = obj # Again needed to avoid poll() taking me down
bpy.ops.object.make_links_data(type='MODIFIERS')
bpy.ops.object.make_links_data(type='MATERIAL')
if uvyes == 1:
bpy.ops.object.join_uvs()
bpy.ops.group.objects_remove()
bpy.context.scene.objects.active = select
if self.dc is True:
bpy.context.scene.objects.unlink(obj)
return {'FINISHED'}
@classmethod
def poll(cls, context):
ob = context.active_object
return ob is not None and ob.mode == 'OBJECT'
def draw(self, context):
layout = self.layout
box = layout.box()
box.label(text="Options")
box.prop(self, "dc")
box.prop(self, "wh")
box.prop(self, "uf")
box = layout.box()
box.label(text="Parameters")
box.prop(self, "qn")
box.prop(self, "mn")
box.prop(self, "mx")
box.prop(self, "lo")
box.prop(self, "rsd")
def add_object_button(self, context):
self.layout.operator(makestructure.bl_idname, text="Add Random Box structure", icon='PLUGIN')
def register():
bpy.utils.register_class(makestructure)
bpy.types.INFO_MT_add.append(add_object_button)
def unregister():
bpy.utils.unregister_class(makestructure)
bpy.types.INFO_MT_add.remove(add_object_button)
if __name__ == "__main__":

File diff suppressed because it is too large Load Diff

View File

@ -7,179 +7,189 @@ from bpy.types import Operator
class add_BI_scene(Operator):
bl_idname = "bi.add_scene"
bl_label = "Create test scene"
bl_description = "BI Scene with Objects"
bl_description = "Blender Internal renderer Scene with Objects"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
blend_data = context.blend_data
# ob = bpy.context.active_object
try:
blend_data = context.blend_data
# ob = bpy.context.active_object
# add new scene
bpy.ops.scene.new(type="NEW")
scene = bpy.context.scene
scene.name = "scene_materials"
# add new scene
bpy.ops.scene.new(type="NEW")
scene = bpy.context.scene
scene.name = "scene_materials"
# render settings
render = scene.render
render.resolution_x = 1920
render.resolution_y = 1080
render.resolution_percentage = 50
# render settings
render = scene.render
render.resolution_x = 1920
render.resolution_y = 1080
render.resolution_percentage = 50
# add new world
world = bpy.data.worlds.new("Materials_World")
scene.world = world
world.use_sky_blend = True
world.use_sky_paper = True
world.horizon_color = (0.004393, 0.02121, 0.050)
world.zenith_color = (0.03335, 0.227, 0.359)
world.light_settings.use_ambient_occlusion = True
world.light_settings.ao_factor = 0.25
# add new world
world = bpy.data.worlds.new("Materials_World")
scene.world = world
world.use_sky_blend = True
world.use_sky_paper = True
world.horizon_color = (0.004393, 0.02121, 0.050)
world.zenith_color = (0.03335, 0.227, 0.359)
world.light_settings.use_ambient_occlusion = True
world.light_settings.ao_factor = 0.25
# add camera
bpy.ops.object.camera_add(
# add camera
bpy.ops.object.camera_add(
location=(7.48113, -6.50764, 5.34367),
rotation=(1.109319, 0.010817, 0.814928)
)
cam = bpy.context.active_object.data
cam.lens = 35
cam.draw_size = 0.1
bpy.ops.view3d.viewnumpad(type='CAMERA')
cam = bpy.context.active_object.data
cam.lens = 35
cam.draw_size = 0.1
bpy.ops.view3d.viewnumpad(type='CAMERA')
# add point lamp
bpy.ops.object.lamp_add(
# add point lamp
bpy.ops.object.lamp_add(
type="POINT", location=(4.07625, 1.00545, 5.90386),
rotation=(0.650328, 0.055217, 1.866391)
)
lamp1 = bpy.context.active_object.data
lamp1.name = "Point_Right"
lamp1.energy = 1.0
lamp1.distance = 30.0
lamp1.shadow_method = "RAY_SHADOW"
lamp1.use_sphere = True
lamp1 = bpy.context.active_object.data
lamp1.name = "Point_Right"
lamp1.energy = 1.0
lamp1.distance = 30.0
lamp1.shadow_method = "RAY_SHADOW"
lamp1.use_sphere = True
# add point lamp2
bpy.ops.object.lamp_add(
# add point lamp2
bpy.ops.object.lamp_add(
type="POINT", location=(-0.57101, -4.24586, 5.53674),
rotation=(1.571, 0, 0.785)
)
lamp2 = bpy.context.active_object.data
lamp2.name = "Point_Left"
lamp2.energy = 1.0
lamp2.distance = 30.0
lamp2 = bpy.context.active_object.data
lamp2.name = "Point_Left"
lamp2.energy = 1.0
lamp2.distance = 30.0
# Add cube
bpy.ops.mesh.primitive_cube_add()
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.subdivide(number_cuts=2)
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
# Add cube
bpy.ops.mesh.primitive_cube_add()
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.subdivide(number_cuts=2)
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
cube = bpy.context.active_object
# add new material
cubeMaterial = blend_data.materials.new("Cube_Material")
bpy.ops.object.material_slot_add()
cube.material_slots[0].material = cubeMaterial
# Diffuse
cubeMaterial.preview_render_type = "CUBE"
cubeMaterial.diffuse_color = (1.000, 0.373, 0.00)
cubeMaterial.diffuse_shader = 'OREN_NAYAR'
cubeMaterial.diffuse_intensity = 1.0
cubeMaterial.roughness = 0.09002
# Specular
cubeMaterial.specular_color = (1.000, 0.800, 0.136)
cubeMaterial.specular_shader = "PHONG"
cubeMaterial.specular_intensity = 1.0
cubeMaterial.specular_hardness = 511.0
# Shading
cubeMaterial.ambient = 1.00
cubeMaterial.use_cubic = False
# Transparency
cubeMaterial.use_transparency = False
cubeMaterial.alpha = 0
# Mirror
cubeMaterial.raytrace_mirror.use = True
cubeMaterial.mirror_color = (1.000, 0.793, 0.0)
cubeMaterial.raytrace_mirror.reflect_factor = 0.394
cubeMaterial.raytrace_mirror.fresnel = 2.0
cubeMaterial.raytrace_mirror.fresnel_factor = 1.641
cubeMaterial.raytrace_mirror.fade_to = "FADE_TO_SKY"
cubeMaterial.raytrace_mirror.gloss_anisotropic = 1.0
# Shadow
cubeMaterial.use_transparent_shadows = True
cube = bpy.context.active_object
# add new material
cubeMaterial = blend_data.materials.new("Cube_Material")
bpy.ops.object.material_slot_add()
cube.material_slots[0].material = cubeMaterial
# Diffuse
cubeMaterial.preview_render_type = "CUBE"
cubeMaterial.diffuse_color = (1.000, 0.373, 0.00)
cubeMaterial.diffuse_shader = 'OREN_NAYAR'
cubeMaterial.diffuse_intensity = 1.0
cubeMaterial.roughness = 0.09002
# Specular
cubeMaterial.specular_color = (1.000, 0.800, 0.136)
cubeMaterial.specular_shader = "PHONG"
cubeMaterial.specular_intensity = 1.0
cubeMaterial.specular_hardness = 511.0
# Shading
cubeMaterial.ambient = 1.00
cubeMaterial.use_cubic = False
# Transparency
cubeMaterial.use_transparency = False
cubeMaterial.alpha = 0
# Mirror
cubeMaterial.raytrace_mirror.use = True
cubeMaterial.mirror_color = (1.000, 0.793, 0.0)
cubeMaterial.raytrace_mirror.reflect_factor = 0.394
cubeMaterial.raytrace_mirror.fresnel = 2.0
cubeMaterial.raytrace_mirror.fresnel_factor = 1.641
cubeMaterial.raytrace_mirror.fade_to = "FADE_TO_SKY"
cubeMaterial.raytrace_mirror.gloss_anisotropic = 1.0
# Shadow
cubeMaterial.use_transparent_shadows = True
# Add a texture
cubetex = blend_data.textures.new("CloudTex", type='CLOUDS')
cubetex.noise_type = 'SOFT_NOISE'
cubetex.noise_scale = 0.25
mtex = cubeMaterial.texture_slots.add()
mtex.texture = cubetex
mtex.texture_coords = 'ORCO'
mtex.scale = (0.800, 0.800, 0.800)
mtex.use_map_mirror = True
mtex.mirror_factor = 0.156
mtex.use_map_color_diffuse = True
mtex.diffuse_color_factor = 0.156
mtex.use_map_normal = True
mtex.normal_factor = 0.010
mtex.blend_type = "ADD"
mtex.use_rgb_to_intensity = True
mtex.color = (1.000, 0.207, 0.000)
# Add a texture
cubetex = blend_data.textures.new("CloudTex", type='CLOUDS')
cubetex.noise_type = 'SOFT_NOISE'
cubetex.noise_scale = 0.25
mtex = cubeMaterial.texture_slots.add()
mtex.texture = cubetex
mtex.texture_coords = 'ORCO'
mtex.scale = (0.800, 0.800, 0.800)
mtex.use_map_mirror = True
mtex.mirror_factor = 0.156
mtex.use_map_color_diffuse = True
mtex.diffuse_color_factor = 0.156
mtex.use_map_normal = True
mtex.normal_factor = 0.010
mtex.blend_type = "ADD"
mtex.use_rgb_to_intensity = True
mtex.color = (1.000, 0.207, 0.000)
# Add monkey
bpy.ops.mesh.primitive_monkey_add(location=(-0.1, 0.08901, 1.505))
bpy.ops.transform.rotate(value=(1.15019), axis=(0, 0, 1))
bpy.ops.transform.rotate(value=(-0.673882), axis=(0, 1, 0))
bpy.ops.transform.rotate(value=-0.055, axis=(1, 0, 0))
bpy.ops.object.modifier_add(type='SUBSURF')
bpy.ops.object.shade_smooth()
monkey = bpy.context.active_object
# add new material
monkeyMaterial = blend_data.materials.new("Monkey_Material")
bpy.ops.object.material_slot_add()
monkey.material_slots[0].material = monkeyMaterial
# Material settings
monkeyMaterial.preview_render_type = "MONKEY"
monkeyMaterial.diffuse_color = (0.239, 0.288, 0.288)
monkeyMaterial.specular_color = (0.604, 0.465, 0.136)
monkeyMaterial.diffuse_shader = 'LAMBERT'
monkeyMaterial.diffuse_intensity = 1.0
monkeyMaterial.specular_intensity = 0.3
monkeyMaterial.ambient = 0
monkeyMaterial.type = 'SURFACE'
monkeyMaterial.use_cubic = True
monkeyMaterial.use_transparency = False
monkeyMaterial.alpha = 0
monkeyMaterial.use_transparent_shadows = True
monkeyMaterial.raytrace_mirror.use = True
monkeyMaterial.raytrace_mirror.reflect_factor = 0.65
monkeyMaterial.raytrace_mirror.fade_to = "FADE_TO_MATERIAL"
# Add monkey
bpy.ops.mesh.primitive_monkey_add(location=(-0.1, 0.08901, 1.505))
bpy.ops.transform.rotate(value=(1.15019), axis=(0, 0, 1))
bpy.ops.transform.rotate(value=(-0.673882), axis=(0, 1, 0))
bpy.ops.transform.rotate(value=-0.055, axis=(1, 0, 0))
bpy.ops.object.modifier_add(type='SUBSURF')
bpy.ops.object.shade_smooth()
monkey = bpy.context.active_object
# add new material
monkeyMaterial = blend_data.materials.new("Monkey_Material")
bpy.ops.object.material_slot_add()
monkey.material_slots[0].material = monkeyMaterial
# Material settings
monkeyMaterial.preview_render_type = "MONKEY"
monkeyMaterial.diffuse_color = (0.239, 0.288, 0.288)
monkeyMaterial.specular_color = (0.604, 0.465, 0.136)
monkeyMaterial.diffuse_shader = 'LAMBERT'
monkeyMaterial.diffuse_intensity = 1.0
monkeyMaterial.specular_intensity = 0.3
monkeyMaterial.ambient = 0
monkeyMaterial.type = 'SURFACE'
monkeyMaterial.use_cubic = True
monkeyMaterial.use_transparency = False
monkeyMaterial.alpha = 0
monkeyMaterial.use_transparent_shadows = True
monkeyMaterial.raytrace_mirror.use = True
monkeyMaterial.raytrace_mirror.reflect_factor = 0.65
monkeyMaterial.raytrace_mirror.fade_to = "FADE_TO_MATERIAL"
# Add plane
bpy.ops.mesh.primitive_plane_add(
radius=50, view_align=False, enter_editmode=False, location=(0, 0, -1)
)
bpy.ops.object.editmode_toggle()
bpy.ops.transform.rotate(
value=-0.8, axis=(0, 0, 1), constraint_axis=(False, False, True),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1
)
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
plane = bpy.context.active_object
# add new material
planeMaterial = blend_data.materials.new("Plane_Material")
bpy.ops.object.material_slot_add()
plane.material_slots[0].material = planeMaterial
# Material settings
planeMaterial.preview_render_type = "CUBE"
planeMaterial.diffuse_color = (0.2, 0.2, 0.2)
planeMaterial.specular_color = (0.604, 0.465, 0.136)
planeMaterial.specular_intensity = 0.3
planeMaterial.ambient = 0
planeMaterial.use_cubic = True
planeMaterial.use_transparency = False
planeMaterial.alpha = 0
planeMaterial.use_transparent_shadows = True
# Add plane
bpy.ops.mesh.primitive_plane_add(
radius=50, view_align=False, enter_editmode=False, location=(0, 0, -1)
)
bpy.ops.object.editmode_toggle()
bpy.ops.transform.rotate(
value=-0.8, axis=(0, 0, 1), constraint_axis=(False, False, True),
constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED',
proportional_edit_falloff='SMOOTH', proportional_size=1
)
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
plane = bpy.context.active_object
# add new material
planeMaterial = blend_data.materials.new("Plane_Material")
bpy.ops.object.material_slot_add()
plane.material_slots[0].material = planeMaterial
# Material settings
planeMaterial.preview_render_type = "CUBE"
planeMaterial.diffuse_color = (0.2, 0.2, 0.2)
planeMaterial.specular_color = (0.604, 0.465, 0.136)
planeMaterial.specular_intensity = 0.3
planeMaterial.ambient = 0
planeMaterial.use_cubic = True
planeMaterial.use_transparency = False
planeMaterial.alpha = 0
planeMaterial.use_transparent_shadows = True
except Exception as e:
self.report({'WARNING'},
"Some operations could not be performed (See Console for more info)")
print("\n[Add Advanced Objects]\nOperator: "
"bi.add_scene\nError: {}".format(e))
return {'CANCELLED'}
return {"FINISHED"}

View File

@ -7,124 +7,136 @@ from bpy.types import Operator
class add_cycles_scene(Operator):
bl_idname = "objects_cycles.add_scene"
bl_label = "Create test scene"
bl_description = "Cycles Scene with Objects"
bl_description = "Cycles renderer Scene with Objects"
bl_options = {'REGISTER'}
def execute(self, context):
blend_data = context.blend_data
# ob = bpy.context.active_object
try:
blend_data = context.blend_data
# add new scene
bpy.ops.scene.new(type="NEW")
scene = bpy.context.scene
bpy.context.scene.render.engine = 'CYCLES'
scene.name = "scene_object_cycles"
# add new scene
bpy.ops.scene.new(type="NEW")
scene = bpy.context.scene
bpy.context.scene.render.engine = 'CYCLES'
scene.name = "scene_object_cycles"
# render settings
render = scene.render
render.resolution_x = 1920
render.resolution_y = 1080
render.resolution_percentage = 50
# render settings
render = scene.render
render.resolution_x = 1920
render.resolution_y = 1080
render.resolution_percentage = 50
# add new world
world = bpy.data.worlds.new("Cycles_Object_World")
scene.world = world
world.use_sky_blend = True
world.use_sky_paper = True
world.horizon_color = (0.004393, 0.02121, 0.050)
world.zenith_color = (0.03335, 0.227, 0.359)
world.light_settings.use_ambient_occlusion = True
world.light_settings.ao_factor = 0.25
# add new world
world = bpy.data.worlds.new("Cycles_Object_World")
scene.world = world
world.use_sky_blend = True
world.use_sky_paper = True
world.horizon_color = (0.004393, 0.02121, 0.050)
world.zenith_color = (0.03335, 0.227, 0.359)
world.light_settings.use_ambient_occlusion = True
world.light_settings.ao_factor = 0.25
# add camera
bpy.ops.object.camera_add(
location=(7.48113, -6.50764, 5.34367),
rotation=(1.109319, 0.010817, 0.814928)
)
cam = bpy.context.active_object.data
cam.lens = 35
cam.draw_size = 0.1
bpy.ops.view3d.viewnumpad(type='CAMERA')
# add camera
bpy.ops.object.camera_add(
location=(7.48113, -6.50764, 5.34367),
rotation=(1.109319, 0.010817, 0.814928)
)
cam = bpy.context.active_object.data
cam.lens = 35
cam.draw_size = 0.1
bpy.ops.view3d.viewnumpad(type='CAMERA')
# add point lamp
bpy.ops.object.lamp_add(
type="POINT", location=(4.07625, 1.00545, 5.90386),
rotation=(0.650328, 0.055217, 1.866391)
)
lamp1 = bpy.context.active_object.data
lamp1.name = "Point_Right"
lamp1.energy = 1.0
lamp1.distance = 30.0
lamp1.shadow_method = "RAY_SHADOW"
lamp1.use_sphere = True
# add point lamp
bpy.ops.object.lamp_add(
type="POINT", location=(4.07625, 1.00545, 5.90386),
rotation=(0.650328, 0.055217, 1.866391)
)
lamp1 = bpy.context.active_object.data
lamp1.name = "Point_Right"
lamp1.energy = 1.0
lamp1.distance = 30.0
lamp1.shadow_method = "RAY_SHADOW"
lamp1.use_sphere = True
# add point lamp2
bpy.ops.object.lamp_add(
type="POINT", location=(-0.57101, -4.24586, 5.53674),
rotation=(1.571, 0, 0.785)
)
lamp2 = bpy.context.active_object.data
lamp2.name = "Point_Left"
lamp2.energy = 1.0
lamp2.distance = 30.0
# add point lamp2
bpy.ops.object.lamp_add(
type="POINT", location=(-0.57101, -4.24586, 5.53674),
rotation=(1.571, 0, 0.785)
)
lamp2 = bpy.context.active_object.data
lamp2.name = "Point_Left"
lamp2.energy = 1.0
lamp2.distance = 30.0
# Add cube
bpy.ops.mesh.primitive_cube_add()
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.subdivide(number_cuts=2)
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
cube = bpy.context.active_object
# Add cube
bpy.ops.mesh.primitive_cube_add()
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.subdivide(number_cuts=2)
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
cube = bpy.context.active_object
# add cube material
cubeMaterial = blend_data.materials.new("Cycles_Cube_Material")
bpy.ops.object.material_slot_add()
cube.material_slots[0].material = cubeMaterial
# Diffuse
cubeMaterial.preview_render_type = "CUBE"
cubeMaterial.diffuse_color = (1.000, 0.373, 0.00)
# Cycles
cubeMaterial.use_nodes = True
# add cube material
cubeMaterial = blend_data.materials.new("Cycles_Cube_Material")
bpy.ops.object.material_slot_add()
cube.material_slots[0].material = cubeMaterial
# Diffuse
cubeMaterial.preview_render_type = "CUBE"
cubeMaterial.diffuse_color = (1.000, 0.373, 0.00)
# Cycles
cubeMaterial.use_nodes = True
# Add monkey
bpy.ops.mesh.primitive_monkey_add(location=(-0.1, 0.08901, 1.505))
bpy.ops.transform.rotate(value=(1.15019), axis=(0, 0, 1))
bpy.ops.transform.rotate(value=(-0.673882), axis=(0, 1, 0))
bpy.ops.transform.rotate(value=-0.055, axis=(1, 0, 0))
# Add monkey
bpy.ops.mesh.primitive_monkey_add(location=(-0.1, 0.08901, 1.505))
bpy.ops.transform.rotate(value=(1.15019), axis=(0, 0, 1))
bpy.ops.transform.rotate(value=(-0.673882), axis=(0, 1, 0))
bpy.ops.transform.rotate(value=-0.055, axis=(1, 0, 0))
bpy.ops.object.modifier_add(type='SUBSURF')
bpy.ops.object.shade_smooth()
monkey = bpy.context.active_object
bpy.ops.object.modifier_add(type='SUBSURF')
bpy.ops.object.shade_smooth()
monkey = bpy.context.active_object
# add monkey material
monkeyMaterial = blend_data.materials.new("Cycles_Monkey_Material")
bpy.ops.object.material_slot_add()
monkey.material_slots[0].material = monkeyMaterial
# Diffuse
monkeyMaterial.preview_render_type = "MONKEY"
monkeyMaterial.diffuse_color = (0.239, 0.288, 0.288)
# Cycles
monkeyMaterial.use_nodes = True
# add monkey material
monkeyMaterial = blend_data.materials.new("Cycles_Monkey_Material")
bpy.ops.object.material_slot_add()
monkey.material_slots[0].material = monkeyMaterial
# Diffuse
monkeyMaterial.preview_render_type = "MONKEY"
monkeyMaterial.diffuse_color = (0.239, 0.288, 0.288)
# Cycles
monkeyMaterial.use_nodes = True
# Add plane
bpy.ops.mesh.primitive_plane_add(
radius=50, view_align=False,
enter_editmode=False, location=(0, 0, -1)
)
bpy.ops.object.editmode_toggle()
bpy.ops.transform.rotate(value=-0.8, axis=(0, 0, 1), constraint_axis=(False, False, True))
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
plane = bpy.context.active_object
# Add plane
bpy.ops.mesh.primitive_plane_add(
radius=50, view_align=False,
enter_editmode=False, location=(0, 0, -1)
)
bpy.ops.object.editmode_toggle()
bpy.ops.transform.rotate(
value=-0.8, axis=(0, 0, 1),
constraint_axis=(False, False, True)
)
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
plane = bpy.context.active_object
# add plane material
planeMaterial = blend_data.materials.new("Cycles_Plane_Material")
bpy.ops.object.material_slot_add()
plane.material_slots[0].material = planeMaterial
# Diffuse
planeMaterial.preview_render_type = "FLAT"
planeMaterial.diffuse_color = (0.2, 0.2, 0.2)
# Cycles
planeMaterial.use_nodes = True
# add plane material
planeMaterial = blend_data.materials.new("Cycles_Plane_Material")
bpy.ops.object.material_slot_add()
plane.material_slots[0].material = planeMaterial
# Diffuse
planeMaterial.preview_render_type = "FLAT"
planeMaterial.diffuse_color = (0.2, 0.2, 0.2)
# Cycles
planeMaterial.use_nodes = True
except Exception as e:
self.report({'WARNING'},
"Some operations could not be performed (See Console for more info)")
print("\n[Add Advanced Objects]\nOperator: "
"objects_cycles.add_scene\nError: {}".format(e))
return {'CANCELLED'}
return {'FINISHED'}

View File

@ -7,60 +7,72 @@ from bpy.types import Operator
class add_texture_scene(Operator):
bl_idname = "objects_texture.add_scene"
bl_label = "Create test scene"
bl_description = "Cycles Scene: Camera aligned to plane"
bl_description = "Cycles renderer Scene: Camera aligned to a plane"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
blend_data = context.blend_data
# ob = bpy.context.active_object
try:
blend_data = context.blend_data
# add new scene
bpy.ops.scene.new(type="NEW")
scene = bpy.context.scene
bpy.context.scene.render.engine = 'CYCLES'
scene.name = "scene_texture_cycles"
# add new scene
bpy.ops.scene.new(type="NEW")
scene = bpy.context.scene
bpy.context.scene.render.engine = 'CYCLES'
scene.name = "scene_texture_cycles"
# render settings
render = scene.render
render.resolution_x = 1080
render.resolution_y = 1080
render.resolution_percentage = 100
# render settings
render = scene.render
render.resolution_x = 1080
render.resolution_y = 1080
render.resolution_percentage = 100
# add new world
world = bpy.data.worlds.new("Cycles_Textures_World")
scene.world = world
world.use_sky_blend = True
world.use_sky_paper = True
world.horizon_color = (0.004393, 0.02121, 0.050)
world.zenith_color = (0.03335, 0.227, 0.359)
world.light_settings.use_ambient_occlusion = True
world.light_settings.ao_factor = 0.5
# add new world
world = bpy.data.worlds.new("Cycles_Textures_World")
scene.world = world
world.use_sky_blend = True
world.use_sky_paper = True
world.horizon_color = (0.004393, 0.02121, 0.050)
world.zenith_color = (0.03335, 0.227, 0.359)
world.light_settings.use_ambient_occlusion = True
world.light_settings.ao_factor = 0.5
# add camera
bpy.ops.view3d.viewnumpad(type='TOP')
bpy.ops.object.camera_add(location=(0, 0, 2.1850), rotation=(0, 0, 0), view_align=True)
cam = bpy.context.active_object.data
cam.lens = 35
cam.draw_size = 0.1
# add camera
bpy.ops.view3d.viewnumpad(type='TOP')
bpy.ops.object.camera_add(
location=(0, 0, 2.1850), rotation=(0, 0, 0), view_align=True
)
cam = bpy.context.active_object.data
cam.lens = 35
cam.draw_size = 0.1
# add plane
bpy.ops.mesh.primitive_plane_add(enter_editmode=True, location=(0, 0, 0))
bpy.ops.mesh.subdivide(number_cuts=10, smoothness=0)
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
plane = bpy.context.active_object
# add plane
bpy.ops.mesh.primitive_plane_add(enter_editmode=True, location=(0, 0, 0))
bpy.ops.mesh.subdivide(number_cuts=10, smoothness=0)
bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001)
bpy.ops.object.editmode_toggle()
plane = bpy.context.active_object
# add plane material
planeMaterial = blend_data.materials.new("Cycles_Plane_Material")
bpy.ops.object.material_slot_add()
plane.material_slots[0].material = planeMaterial
# Diffuse
planeMaterial.preview_render_type = "FLAT"
planeMaterial.diffuse_color = (0.2, 0.2, 0.2)
# Cycles
planeMaterial.use_nodes = True
# add plane material
planeMaterial = blend_data.materials.new("Cycles_Plane_Material")
bpy.ops.object.material_slot_add()
plane.material_slots[0].material = planeMaterial
# Diffuse
planeMaterial.preview_render_type = "FLAT"
planeMaterial.diffuse_color = (0.2, 0.2, 0.2)
# Cycles
planeMaterial.use_nodes = True
# Back to Scene
sc = bpy.context.scene
bpy.ops.view3d.viewnumpad(type='CAMERA')
except Exception as e:
self.report({'WARNING'},
"Some operations could not be performed (See Console for more info)")
print("\n[Add Advanced Objects]\nOperator: "
"objects_texture.add_scene\nError: {}".format(e))
return {'CANCELLED'}
# Back to Scene
sc = bpy.context.scene
bpy.ops.view3d.viewnumpad(type='CAMERA')
return {'FINISHED'}

View File

@ -8,8 +8,7 @@ from bpy.props import (
IntProperty,
)
from math import (
sin,
cos,
sin, cos,
radians,
sqrt,
)
@ -19,67 +18,69 @@ class TriLighting(Operator):
bl_idname = "object.trilighting"
bl_label = "Tri-Lighting Creator"
bl_description = ("Add 3 Point Lighting to Selected / Active Object\n"
"Needs an active object in the scene")
"Needs an existing Active Object")
bl_options = {'REGISTER', 'UNDO'}
height = FloatProperty(
name="Height",
default=5
)
name="Height",
default=5
)
distance = FloatProperty(
name="Distance",
default=5,
min=0.1,
subtype="DISTANCE"
)
name="Distance",
default=5,
min=0.1,
subtype="DISTANCE"
)
energy = IntProperty(
name="Base Energy",
default=3,
min=1
)
name="Base Energy",
default=3,
min=1
)
contrast = IntProperty(
name="Contrast",
default=50,
min=-100, max=100,
subtype="PERCENTAGE"
)
name="Contrast",
default=50,
min=-100, max=100,
subtype="PERCENTAGE"
)
leftangle = IntProperty(
name="Left Angle",
default=26,
min=1, max=90,
subtype="ANGLE"
)
name="Left Angle",
default=26,
min=1, max=90,
subtype="ANGLE"
)
rightangle = IntProperty(
name="Right Angle",
default=45,
min=1, max=90,
subtype="ANGLE"
)
name="Right Angle",
default=45,
min=1, max=90,
subtype="ANGLE"
)
backangle = IntProperty(
name="Back Angle",
default=235,
min=90, max=270,
subtype="ANGLE"
)
Light_Type_List = [('POINT', 'Point', 'Point Light'),
('SUN', 'Sun', 'Sun Light'),
('SPOT', 'Spot', 'Spot Light'),
('HEMI', 'Hemi', 'Hemi Light'),
('AREA', 'Area', 'Area Light')]
name="Back Angle",
default=235,
min=90, max=270,
subtype="ANGLE"
)
Light_Type_List = [
('POINT', "Point", "Point Light"),
('SUN', "Sun", "Sun Light"),
('SPOT', "Spot", "Spot Light"),
('HEMI', "Hemi", "Hemi Light"),
('AREA', "Area", "Area Light")
]
primarytype = EnumProperty(
attr='tl_type',
name="Key Type",
description="Choose the type off Key Light you would like",
items=Light_Type_List,
default='HEMI'
)
attr='tl_type',
name="Key Type",
description="Choose the types of Key Lights you would like",
items=Light_Type_List,
default='HEMI'
)
secondarytype = EnumProperty(
attr='tl_type',
name="Fill + Back Type",
description="Choose the type off secondary Light you would like",
items=Light_Type_List,
default="POINT"
)
attr='tl_type',
name="Fill + Back Type",
description="Choose the types of secondary Lights you would like",
items=Light_Type_List,
default="POINT"
)
@classmethod
def poll(cls, context):
@ -111,115 +112,127 @@ class TriLighting(Operator):
col.prop(self, "secondarytype", text="")
def execute(self, context):
scene = context.scene
view = context.space_data
if view.type == 'VIEW_3D' and not view.lock_camera_and_layers:
camera = view.camera
else:
camera = scene.camera
try:
scene = context.scene
view = context.space_data
if view.type == 'VIEW_3D' and not view.lock_camera_and_layers:
camera = view.camera
else:
camera = scene.camera
if (camera is None):
cam_data = bpy.data.cameras.new(name='Camera')
cam_obj = bpy.data.objects.new(name='Camera', object_data=cam_data)
scene.objects.link(cam_obj)
scene.camera = cam_obj
bpy.ops.view3d.camera_to_view()
camera = cam_obj
bpy.ops.view3d.viewnumpad(type='TOP')
if (camera is None):
cam_data = bpy.data.cameras.new(name='Camera')
cam_obj = bpy.data.objects.new(name='Camera', object_data=cam_data)
scene.objects.link(cam_obj)
scene.camera = cam_obj
bpy.ops.view3d.camera_to_view()
camera = cam_obj
bpy.ops.view3d.viewnumpad(type='TOP')
obj = bpy.context.scene.objects.active
obj = bpy.context.scene.objects.active
# Calculate Energy for each Lamp
if(self.contrast > 0):
keyEnergy = self.energy
backEnergy = (self.energy / 100) * abs(self.contrast)
fillEnergy = (self.energy / 100) * abs(self.contrast)
else:
keyEnergy = (self.energy / 100) * abs(self.contrast)
backEnergy = self.energy
fillEnergy = self.energy
# Calculate Energy for each Lamp
if(self.contrast > 0):
keyEnergy = self.energy
backEnergy = (self.energy / 100) * abs(self.contrast)
fillEnergy = (self.energy / 100) * abs(self.contrast)
else:
keyEnergy = (self.energy / 100) * abs(self.contrast)
backEnergy = self.energy
fillEnergy = self.energy
# Calculate Direction for each Lamp
# Calculate Direction for each Lamp
# Calculate current Distance and get Delta
obj_position = obj.location
cam_position = camera.location
# Calculate current Distance and get Delta
obj_position = obj.location
cam_position = camera.location
delta_position = cam_position - obj_position
vector_length = sqrt(
(pow(delta_position.x, 2) +
pow(delta_position.y, 2) +
pow(delta_position.z, 2))
)
if not vector_length:
# division by zero most likely
self.report({'WARNING'},
"Operation Cancelled. No viable object in the scene")
return {'CANCELLED'}
single_vector = (1 / vector_length) * delta_position
# Calc back position
singleback_vector = single_vector.copy()
singleback_vector.x = cos(radians(self.backangle)) * single_vector.x + \
(-sin(radians(self.backangle)) * single_vector.y)
singleback_vector.y = sin(radians(self.backangle)) * single_vector.x + \
(cos(radians(self.backangle)) * single_vector.y)
backx = obj_position.x + self.distance * singleback_vector.x
backy = obj_position.y + self.distance * singleback_vector.y
backData = bpy.data.lamps.new(name="TriLamp-Back", type=self.secondarytype)
backData.energy = backEnergy
backLamp = bpy.data.objects.new(name="TriLamp-Back", object_data=backData)
scene.objects.link(backLamp)
backLamp.location = (backx, backy, self.height)
trackToBack = backLamp.constraints.new(type="TRACK_TO")
trackToBack.target = obj
trackToBack.track_axis = "TRACK_NEGATIVE_Z"
trackToBack.up_axis = "UP_Y"
# Calc right position
singleright_vector = single_vector.copy()
singleright_vector.x = cos(radians(self.rightangle)) * single_vector.x + \
(-sin(radians(self.rightangle)) * single_vector.y)
singleright_vector.y = sin(radians(self.rightangle)) * single_vector.x + \
(cos(radians(self.rightangle)) * single_vector.y)
rightx = obj_position.x + self.distance * singleright_vector.x
righty = obj_position.y + self.distance * singleright_vector.y
rightData = bpy.data.lamps.new(name="TriLamp-Fill", type=self.secondarytype)
rightData.energy = fillEnergy
rightLamp = bpy.data.objects.new(name="TriLamp-Fill", object_data=rightData)
scene.objects.link(rightLamp)
rightLamp.location = (rightx, righty, self.height)
trackToRight = rightLamp.constraints.new(type="TRACK_TO")
trackToRight.target = obj
trackToRight.track_axis = "TRACK_NEGATIVE_Z"
trackToRight.up_axis = "UP_Y"
# Calc left position
singleleft_vector = single_vector.copy()
singleleft_vector.x = cos(radians(-self.leftangle)) * single_vector.x + \
(-sin(radians(-self.leftangle)) * single_vector.y)
singleleft_vector.y = sin(radians(-self.leftangle)) * single_vector.x + \
(cos(radians(-self.leftangle)) * single_vector.y)
leftx = obj_position.x + self.distance * singleleft_vector.x
lefty = obj_position.y + self.distance * singleleft_vector.y
leftData = bpy.data.lamps.new(name="TriLamp-Key", type=self.primarytype)
leftData.energy = keyEnergy
leftLamp = bpy.data.objects.new(name="TriLamp-Key", object_data=leftData)
scene.objects.link(leftLamp)
leftLamp.location = (leftx, lefty, self.height)
trackToLeft = leftLamp.constraints.new(type="TRACK_TO")
trackToLeft.target = obj
trackToLeft.track_axis = "TRACK_NEGATIVE_Z"
trackToLeft.up_axis = "UP_Y"
except Exception as e:
self.report({'WARNING'},
"Some operations could not be performed (See Console for more info)")
print("\n[Add Advanced Objects]\nOperator: "
"object.trilighting\nError: {}".format(e))
delta_position = cam_position - obj_position
vector_length = sqrt(
(pow(delta_position.x, 2) +
pow(delta_position.y, 2) +
pow(delta_position.z, 2))
)
if not vector_length:
# division by zero most likely
self.report({'WARNING'}, "Operation Cancelled. No viable object in the scene")
return {'CANCELLED'}
single_vector = (1 / vector_length) * delta_position
# Calc back position
singleback_vector = single_vector.copy()
singleback_vector.x = cos(radians(self.backangle)) * single_vector.x + \
(-sin(radians(self.backangle)) * single_vector.y)
singleback_vector.y = sin(radians(self.backangle)) * single_vector.x + \
(cos(radians(self.backangle)) * single_vector.y)
backx = obj_position.x + self.distance * singleback_vector.x
backy = obj_position.y + self.distance * singleback_vector.y
backData = bpy.data.lamps.new(name="TriLamp-Back", type=self.secondarytype)
backData.energy = backEnergy
backLamp = bpy.data.objects.new(name="TriLamp-Back", object_data=backData)
scene.objects.link(backLamp)
backLamp.location = (backx, backy, self.height)
trackToBack = backLamp.constraints.new(type="TRACK_TO")
trackToBack.target = obj
trackToBack.track_axis = "TRACK_NEGATIVE_Z"
trackToBack.up_axis = "UP_Y"
# Calc right position
singleright_vector = single_vector.copy()
singleright_vector.x = cos(radians(self.rightangle)) * single_vector.x + \
(-sin(radians(self.rightangle)) * single_vector.y)
singleright_vector.y = sin(radians(self.rightangle)) * single_vector.x + \
(cos(radians(self.rightangle)) * single_vector.y)
rightx = obj_position.x + self.distance * singleright_vector.x
righty = obj_position.y + self.distance * singleright_vector.y
rightData = bpy.data.lamps.new(name="TriLamp-Fill", type=self.secondarytype)
rightData.energy = fillEnergy
rightLamp = bpy.data.objects.new(name="TriLamp-Fill", object_data=rightData)
scene.objects.link(rightLamp)
rightLamp.location = (rightx, righty, self.height)
trackToRight = rightLamp.constraints.new(type="TRACK_TO")
trackToRight.target = obj
trackToRight.track_axis = "TRACK_NEGATIVE_Z"
trackToRight.up_axis = "UP_Y"
# Calc left position
singleleft_vector = single_vector.copy()
singleleft_vector.x = cos(radians(-self.leftangle)) * single_vector.x + \
(-sin(radians(-self.leftangle)) * single_vector.y)
singleleft_vector.y = sin(radians(-self.leftangle)) * single_vector.x + \
(cos(radians(-self.leftangle)) * single_vector.y)
leftx = obj_position.x + self.distance * singleleft_vector.x
lefty = obj_position.y + self.distance * singleleft_vector.y
leftData = bpy.data.lamps.new(name="TriLamp-Key", type=self.primarytype)
leftData.energy = keyEnergy
leftLamp = bpy.data.objects.new(name="TriLamp-Key", object_data=leftData)
scene.objects.link(leftLamp)
leftLamp.location = (leftx, lefty, self.height)
trackToLeft = leftLamp.constraints.new(type="TRACK_TO")
trackToLeft.target = obj
trackToLeft.track_axis = "TRACK_NEGATIVE_Z"
trackToLeft.up_axis = "UP_Y"
return {'FINISHED'}

View File

@ -1,18 +1,18 @@
# gpl: authors Liero, Atom
bl_info = {
"name": "Unfold transition",
"version": (0, 1, 0),
"author": "Liero, Atom",
"version": (0, 1, 2),
"location": "Tool bar > Animation tab > UnFold Transition",
"description": "Simple unfold transition / animation, will separate faces and set up an armature",
"description": "Simple unfold transition / animation, will "
"separate faces and set up an armature",
"category": "Animation"}
# Note the properties are moved to __init__
# search for patterns advanced_objects, adv_obj
import bpy
from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
IntProperty,
# PointerProperty,
)
from bpy.types import (
Operator,
Panel,
@ -25,87 +25,22 @@ from mathutils import Vector
from mathutils.geometry import intersect_point_line
bpy.types.WindowManager.modo = EnumProperty(
name="",
items=[("cursor", "3D Cursor", "Use the Distance to 3D Cursor"),
("weight", "Weight Map", "Use a Painted Weight map"),
("index", "Mesh Indices", "Use Faces and Vertices index")],
description="How to Sort Bones for animation", default="cursor"
)
bpy.types.WindowManager.flip = BoolProperty(
name="Flipping Faces",
default=False,
description="Rotate faces around the Center & skip Scaling - "
"keep checked for both operators"
)
bpy.types.WindowManager.fold_duration = IntProperty(
name="Total Time",
min=5, soft_min=25,
max=10000, soft_max=2500,
default=200,
description="Total animation length"
)
bpy.types.WindowManager.sca_time = IntProperty(
name="Scale Time",
min=1,
max=5000, soft_max=500,
default=10,
description="Faces scaling time"
)
bpy.types.WindowManager.rot_time = IntProperty(
name="Rotation Time",
min=1, soft_min=5,
max=5000, soft_max=500,
default=15,
description="Faces rotation time"
)
bpy.types.WindowManager.rot_max = IntProperty(
name="Angle",
min=-180,
max=180,
default=135,
description="Faces rotation angle"
)
bpy.types.WindowManager.fold_noise = IntProperty(
name="Noise",
min=0,
max=500, soft_max=50,
default=0,
description="Offset some faces animation"
)
bpy.types.WindowManager.bounce = FloatProperty(
name="Bounce",
min=0,
max=10, soft_max=2.5,
default=0,
description="Add some bounce to rotation"
)
bpy.types.WindowManager.from_point = BoolProperty(
name="Point",
default=False,
description="Scale faces from a Point instead of from an Edge"
)
bpy.types.WindowManager.wiggle_rot = BoolProperty(
name="Wiggle",
default=False,
description="Use all Axis + Random Rotation instead of X Aligned"
)
class Set_Up_Fold(Operator):
bl_idname = "object.set_up_fold"
bl_label = "Set Up Unfold"
bl_description = "Set up Faces and Bones for animation"
bl_description = ("Set up Faces and Bones for animation\n"
"Needs an existing Active Mesh Object")
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return (bpy.context.object.type == "MESH")
obj = context.active_object
return (obj is not None and obj.type == "MESH")
def execute(self, context):
bpy.ops.object.mode_set()
wm = context.window_manager
scn = bpy.context.scene
adv_obj = scn.advanced_objects
obj = bpy.context.object
dat = obj.data
fac = dat.polygons
@ -118,6 +53,7 @@ class Set_Up_Fold(Operator):
old_vg = [vg for vg in obj.vertex_groups if vg.name.startswith("bone.")]
for vg in old_vg:
obj.vertex_groups.remove(vg)
if "UnFold" in obj.modifiers:
arm = obj.modifiers["UnFold"].object
rig = arm.data
@ -130,7 +66,7 @@ class Set_Up_Fold(Operator):
obj.modifiers.remove(obj.modifiers["UnFold"])
# try to obtain the face sequence from the vertex weights
if wm.modo == "weight":
if adv_obj.unfold_modo == "weight":
if len(obj.vertex_groups):
i = obj.vertex_groups.active.index
W = []
@ -154,6 +90,7 @@ class Set_Up_Fold(Operator):
S = [x[1:] for x in W]
else:
self.report({"INFO"}, "First paint a Weight Map for this object")
return {"FINISHED"}
# separate the faces and sort them
@ -161,14 +98,17 @@ class Set_Up_Fold(Operator):
bpy.ops.mesh.select_all(action="SELECT")
bpy.ops.mesh.edge_split()
bpy.ops.mesh.select_all(action="SELECT")
if wm.modo == "cursor":
if adv_obj.unfold_modo == "cursor":
bpy.context.tool_settings.mesh_select_mode = [True, True, True]
bpy.ops.mesh.sort_elements(type="CURSOR_DISTANCE", elements={"VERT", "EDGE", "FACE"})
bpy.ops.mesh.sort_elements(
type="CURSOR_DISTANCE", elements={"VERT", "EDGE", "FACE"}
)
bpy.context.tool_settings.mesh_select_mode = [False, False, True]
bpy.ops.object.mode_set()
# Get sequence of faces and edges from the face / vertex indices
if wm.modo != "weight":
if adv_obj.unfold_modo != "weight":
S = []
for f in fac:
E = list(f.edge_keys)
@ -183,6 +123,9 @@ class Set_Up_Fold(Operator):
# create the armature and the modifier
arm = bpy.data.armatures.new("arm")
rig = bpy.data.objects.new("rig_" + obj.name, arm)
# store the name for checking the right rig
adv_obj.unfold_arm_name = rig.name
rig.matrix_world = obj.matrix_world
scn.objects.link(rig)
scn.objects.active = rig
@ -203,10 +146,11 @@ class Set_Up_Fold(Operator):
for fb in S:
f = fac[fb[0]]
b = arm.edit_bones.new("bone.000")
if wm.flip:
if adv_obj.unfold_flip:
b.tail, b.head = fb[2], fb[1]
else:
b.tail, b.head = fb[1], fb[2]
b.align_roll(f.normal)
b.select = False
b.layers = vis
@ -215,7 +159,8 @@ class Set_Up_Fold(Operator):
vg.add(f.vertices, 1, "ADD")
bpy.ops.object.mode_set()
if wm.modo == "weight":
if adv_obj.unfold_modo == "weight":
obj.vertex_groups.active_index = 0
scn.objects.active = rig
obj.select = False
@ -226,66 +171,120 @@ class Set_Up_Fold(Operator):
class Animate_Fold(Operator):
bl_idname = "object.animate_fold"
bl_label = "Animate Unfold"
bl_description = "Animate bones to simulate unfold... Starts on current frame"
bl_description = ("Animate bones to simulate unfold. Starts on current frame\n"
"Needs an existing Active Armature Object created in the previous step")
bl_options = {"REGISTER", "UNDO"}
is_not_undo = False
@classmethod
def poll(cls, context):
obj = context.active_object
return (obj is not None and obj.type == "ARMATURE" and obj.is_visible(bpy.context.scene))
def draw(self, context):
layout = self.layout
adv_obj = context.scene.advanced_objects
if self.is_not_undo is True:
layout.label(text="Warning:", icon="INFO")
layout.label(text="The generated Armature was not selected or it was renamed")
layout.label(text="The animation can fail if it is not generated by the previous step")
layout.separator()
layout.label(text="Expected Armature name:", icon="BONE_DATA")
layout.label(text=str(adv_obj.unfold_arm_name), icon="TRIA_RIGHT")
layout.label(text="To Continue press OK, to Cancel click Outside the Pop-up")
layout.separator()
else:
return
def invoke(self, context, event):
obj = bpy.context.object
return (obj.type == "ARMATURE" and obj.is_visible(bpy.context.scene))
scn = bpy.context.scene
adv_obj = scn.advanced_objects
if obj.name != adv_obj.unfold_arm_name:
self.is_not_undo = True
return context.window_manager.invoke_props_dialog(self, width=400)
else:
return self.execute(context)
def execute(self, context):
obj = bpy.context.object
scn = bpy.context.scene
adv_obj = scn.advanced_objects
fra = scn.frame_current
wm = context.window_manager
if obj.name != adv_obj.unfold_arm_name:
self.report({"INFO"},
"The generated rig was not selected or renamed. The animation can fail")
# clear the animation and get the list of bones
if obj.animation_data:
obj.animation_data_clear()
bpy.ops.object.mode_set(mode="POSE")
bones = obj.pose.bones[0].children_recursive
if wm.flip:
if adv_obj.unfold_flip:
rot = -3.141592
else:
rot = wm.rot_max / 57.3
extra = wm.rot_time * wm.bounce
ruido = max(wm.rot_time + extra, wm.sca_time) + wm.fold_noise
vel = (wm.fold_duration - ruido) / len(bones)
rot = adv_obj.unfold_rot_max / 57.3
extra = adv_obj.unfold_rot_time * adv_obj.unfold_bounce
ruido = max(adv_obj.unfold_rot_time + extra,
adv_obj.unfold_sca_time) + adv_obj.unfold_fold_noise
len_bones = len(bones) if len(bones) != 0 else 1 # possible division by zero
vel = (adv_obj.unfold_fold_duration - ruido) / len_bones
# introduce scale and rotation keyframes
for a, b in enumerate(bones):
t = fra + a * vel + randint(0, wm.fold_noise)
if wm.flip:
t = fra + a * vel + randint(0, adv_obj.unfold_fold_noise)
if adv_obj.unfold_flip:
b.scale = (1, 1, 1)
elif wm.from_point:
elif adv_obj.unfold_from_point:
b.scale = (0, 0, 0)
else:
b.scale = (1, 0, 0)
if not wm.flip:
if not adv_obj.unfold_flip:
b.keyframe_insert("scale", frame=t)
b.scale = (1, 1, 1)
b.keyframe_insert("scale", frame=t + wm.sca_time)
if wm.rot_max:
b.keyframe_insert("scale", frame=t + adv_obj.unfold_sca_time)
if adv_obj.unfold_rot_max:
b.rotation_mode = "XYZ"
if wm.wiggle_rot:
if adv_obj.unfold_wiggle_rot:
euler = (uniform(-rot, rot), uniform(-rot, rot), uniform(-rot, rot))
else:
euler = (rot, 0, 0)
b.rotation_euler = euler
b.keyframe_insert("rotation_euler", frame=t)
if wm.bounce:
val = wm.bounce * -.10
if adv_obj.unfold_bounce:
val = adv_obj.unfold_bounce * -.10
b.rotation_euler = (val * euler[0], val * euler[1], val * euler[2])
b.keyframe_insert("rotation_euler", frame=t + wm.rot_time + .25 * extra)
val = wm.bounce * .05
b.keyframe_insert(
"rotation_euler", frame=t + adv_obj.unfold_rot_time + .25 * extra
)
val = adv_obj.unfold_bounce * .05
b.rotation_euler = (val * euler[0], val * euler[1], val * euler[2])
b.keyframe_insert("rotation_euler", frame=t + wm.rot_time + .50 * extra)
val = wm.bounce * -.025
b.keyframe_insert(
"rotation_euler", frame=t + adv_obj.unfold_rot_time + .50 * extra
)
val = adv_obj.unfold_bounce * -.025
b.rotation_euler = (val * euler[0], val * euler[1], val * euler[2])
b.keyframe_insert("rotation_euler", frame=t + wm.rot_time + .75 * extra)
b.keyframe_insert(
"rotation_euler", frame=t + adv_obj.unfold_rot_time + .75 * extra
)
b.rotation_euler = (0, 0, 0)
b.keyframe_insert("rotation_euler", frame=t + wm.rot_time + extra)
b.keyframe_insert(
"rotation_euler", frame=t + adv_obj.unfold_rot_time + extra
)
self.is_not_undo = False
return {"FINISHED"}
@ -299,26 +298,34 @@ class PanelFOLD(Panel):
bl_options = {"DEFAULT_CLOSED"}
def draw(self, context):
wm = context.window_manager
layout = self.layout
column = layout.column()
column.operator("object.set_up_fold", text="1. Set Up Unfold")
column.prop(wm, "modo")
column.prop(wm, "flip")
layout.separator()
column = layout.column()
column.operator("object.animate_fold", text="2. Animate Unfold")
column.prop(wm, "fold_duration")
column.prop(wm, "sca_time")
column.prop(wm, "rot_time")
column.prop(wm, "rot_max")
row = column.row(align=True)
row.prop(wm, "fold_noise")
row.prop(wm, "bounce")
row = column.row(align=True)
row.prop(wm, "wiggle_rot")
if not wm.flip:
row.prop(wm, "from_point")
adv_obj = context.scene.advanced_objects
box = layout.box()
col = box.column()
col.operator("object.set_up_fold", text="1. Set Up Unfold")
col.separator()
col.label("Unfold Mode:")
col.prop(adv_obj, "unfold_modo")
col.prop(adv_obj, "unfold_flip")
box = layout.box()
col = box.column(align=True)
col.operator("object.animate_fold", text="2. Animate Unfold")
col.separator()
col.prop(adv_obj, "unfold_fold_duration")
col.prop(adv_obj, "unfold_sca_time")
col.prop(adv_obj, "unfold_rot_time")
col.prop(adv_obj, "unfold_rot_max")
row = col.row(align=True)
row.prop(adv_obj, "unfold_fold_noise")
row.prop(adv_obj, "unfold_bounce")
row = col.row(align=True)
row.prop(adv_obj, "unfold_wiggle_rot")
if not adv_obj.unfold_flip:
row.prop(adv_obj, "unfold_from_point")
def register():