Skip to content
Snippets Groups Projects
Commit 102ba8e6 authored by Bart Crouch's avatar Bart Crouch
Browse files

Added poll() function to fix crash with no selected objects. Grouped registration functions.

parent 7fa83667
No related branches found
No related tags found
No related merge requests found
# ##### BEGIN GPL LICENSE BLOCK ##### # ##### BEGIN GPL LICENSE BLOCK #####
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
bl_addon_info = { bl_addon_info = {
'name': 'Object: Cloud Generator', 'name': 'Object: Cloud Generator',
'author': 'Nick Keeline(nrk)', 'author': 'Nick Keeline(nrk)',
'version': '0.5', 'version': '0.6',
'blender': (2, 5, 3), 'blender': (2, 5, 3),
'location': 'Tool Shelf ', 'location': 'Tool Shelf ',
'description': 'Creates Volumetric Clouds', 'description': 'Creates Volumetric Clouds',
...@@ -41,6 +41,7 @@ Rev 0.2 Added Point Density turbulence and fixed degenerate ...@@ -41,6 +41,7 @@ Rev 0.2 Added Point Density turbulence and fixed degenerate
Rev 0.3 Fixed bug in degenerate Rev 0.3 Fixed bug in degenerate
Rev 0.4 updated for api change/changed to new apply modifier technique Rev 0.4 updated for api change/changed to new apply modifier technique
Rev 0.5 made particle count equation with radius so radius increases with cloud volume Rev 0.5 made particle count equation with radius so radius increases with cloud volume
Rev 0.6 added poll function to operator, fixing crash with no selected objects
""" """
import bpy import bpy
...@@ -48,9 +49,6 @@ import mathutils ...@@ -48,9 +49,6 @@ import mathutils
from math import * from math import *
from bpy.props import * from bpy.props import *
# Deselect All
bpy.ops.object.select_all(action='DESELECT')
# This routine takes an object and deletes all of the geometry in it # This routine takes an object and deletes all of the geometry in it
# and adds a bounding box to it. # and adds a bounding box to it.
...@@ -281,23 +279,6 @@ class VIEW3D_PT_tools_cloud(View3DPanel): ...@@ -281,23 +279,6 @@ class VIEW3D_PT_tools_cloud(View3DPanel):
col.label(text="a cloud.") col.label(text="a cloud.")
# col.label(active_obj["CloudMember"]) # col.label(active_obj["CloudMember"])
classes = [VIEW3D_PT_tools_cloud]
def register():
register = bpy.types.register
for cls in classes:
register(cls)
def unregister():
unregister = bpy.types.unregister
for cls in classes:
unregister(cls)
if __name__ == "__main__":
register()
class GenerateCloud(bpy.types.Operator): class GenerateCloud(bpy.types.Operator):
bl_idname = "cloud.generate_cloud" bl_idname = "cloud.generate_cloud"
...@@ -306,6 +287,12 @@ class GenerateCloud(bpy.types.Operator): ...@@ -306,6 +287,12 @@ class GenerateCloud(bpy.types.Operator):
bl_register = True bl_register = True
bl_undo = True bl_undo = True
def poll(self, context):
if not context.active_object:
return False
else:
return (context.active_object.type=='MESH')
def execute(self, context): def execute(self, context):
# Make variable that is the current .blend file main data blocks # Make variable that is the current .blend file main data blocks
main = context.main main = context.main
...@@ -316,323 +303,331 @@ class GenerateCloud(bpy.types.Operator): ...@@ -316,323 +303,331 @@ class GenerateCloud(bpy.types.Operator):
# Make variable scene that is current scene # Make variable scene that is current scene
scene = context.scene scene = context.scene
if active_object and active_object.type == 'MESH': # Parameters the user may want to change:
# Parameters the user may want to change: # Number of points this number is multiplied by the volume to get
# Number of points this number is multiplied by the volume to get # the number of points the scripts will put in the volume.
# the number of points the scripts will put in the volume. numOfPoints = 1.0
numOfPoints = 1.0 maxNumOfPoints = 100000
maxNumOfPoints = 100000 scattering = 2.5
scattering = 2.5 pointDensityRadiusFactor = 1.0
pointDensityRadiusFactor = 1.0 densityScale = 1.5
densityScale = 1.5
# Should we degnerate?
# Should we degnerate? degenerate = degenerateCloud(active_object)
degenerate = degenerateCloud(active_object)
if degenerate:
if degenerate: # Degenerate Cloud
if active_object is not None: mainObj = active_object
# Degenerate Cloud
mainObj = active_object cloudMembers = active_object.children
cloudMembers = active_object.children createdObjects = []
definitionObjects = []
createdObjects = [] for member in cloudMembers:
definitionObjects = [] applyScaleRotLoc(scene, member)
for member in cloudMembers: if (member["CloudMember"] == "CreatedObj"):
applyScaleRotLoc(scene, member) createdObjects.append(member)
if (member["CloudMember"] == "CreatedObj"): else:
createdObjects.append(member) definitionObjects.append(member)
else:
definitionObjects.append(member) for defObj in definitionObjects:
# @todo check if it wouldn't be better to remove this
for defObj in definitionObjects: # in the first place (see del() in degenerateCloud)
# @todo check if it wouldn't be better to remove this #totally agree didn't know how before now...thanks! done.
# in the first place (see del() in degenerateCloud) if "CloudMember" in defObj:
#totally agree didn't know how before now...thanks! done. del(defObj["CloudMember"])
if "CloudMember" in defObj:
del(defObj["CloudMember"]) for createdObj in createdObjects:
# Deselect All
for createdObj in createdObjects: bpy.ops.object.select_all(action='DESELECT')
# Deselect All
bpy.ops.object.select_all(action='DESELECT')
# Select the object and delete it. # Select the object and delete it.
createdObj.selected = True createdObj.selected = True
scene.objects.active = createdObj scene.objects.active = createdObj
bpy.ops.object.delete() bpy.ops.object.delete()
# Delete the main object # Delete the main object
# Deselect All # Deselect All
bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_all(action='DESELECT')
# Select the object and delete it. # Select the object and delete it.
mainObj.selected = True mainObj.selected = True
scene.objects.active = mainObj scene.objects.active = mainObj
# Delete all material slots in mainObj object # Delete all material slots in mainObj object
for i in range(len(mainObj.material_slots)): for i in range(len(mainObj.material_slots)):
mainObj.active_material_index = i - 1 mainObj.active_material_index = i - 1
bpy.ops.object.material_slot_remove() bpy.ops.object.material_slot_remove()
# Delete the Main Object # Delete the Main Object
bpy.ops.object.delete() bpy.ops.object.delete()
# Select all of the left over boxes so people can immediately # Select all of the left over boxes so people can immediately
# press generate again if they want. # press generate again if they want.
for eachMember in definitionObjects: for eachMember in definitionObjects:
eachMember.max_draw_type = 'SOLID' eachMember.max_draw_type = 'SOLID'
eachMember.selected = True eachMember.selected = True
scene.objects.active = eachMember scene.objects.active = eachMember
else: else:
# Generate Cloud # Generate Cloud
###############Create Combined Object bounds################## ###############Create Combined Object bounds##################
# Make a list of all Selected objects. # Make a list of all Selected objects.
selectedObjects = bpy.context.selected_objects selectedObjects = bpy.context.selected_objects
if not selectedObjects:
# Create a new object bounds selectedObjects = [bpy.context.active_object]
if selectedObjects is None:
bounds = addNewObject(scene, # Create a new object bounds
"CloudBounds", bounds = addNewObject(scene,
[]) "CloudBounds",
selectedObjects[0])
else:
bounds = addNewObject(scene, bounds.max_draw_type = 'BOUNDS'
"CloudBounds", bounds.restrict_render = False
selectedObjects[0])
# Just add a Definition Property designating this
bounds.max_draw_type = 'BOUNDS' # as the main object.
bounds.restrict_render = False bounds["CloudMember"] = "MainObj"
# Just add a Definition Property designating this # Since we used iteration 0 to copy with object we
# as the main object. # delete it off the list.
bounds["CloudMember"] = "MainObj" firstObject = selectedObjects[0]
del selectedObjects[0]
# Since we used iteration 0 to copy with object we
# delete it off the list. # Apply location Rotation and Scale to all objects involved.
firstObject = selectedObjects[0] applyScaleRotLoc(scene, bounds)
del selectedObjects[0] for each in selectedObjects:
applyScaleRotLoc(scene, each)
# Apply location Rotation and Scale to all objects involved.
applyScaleRotLoc(scene, bounds) # Let's combine all of them together.
for each in selectedObjects: combineObjects(scene, bounds, selectedObjects)
applyScaleRotLoc(scene, each)
# Let's add some property info to the objects.
# Let's combine all of them together. for selObj in selectedObjects:
combineObjects(scene, bounds, selectedObjects) selObj["CloudMember"] = "DefinitioinObj"
selObj.name = "DefinitioinObj"
# Let's add some property info to the objects. selObj.max_draw_type = 'WIRE'
for selObj in selectedObjects: selObj.restrict_render = True
selObj["CloudMember"] = "DefinitioinObj" makeParent(bounds, selObj, scene)
selObj.name = "DefinitioinObj"
selObj.max_draw_type = 'WIRE' # Do the same to the 1. object since it is no longer in list.
selObj.restrict_render = True firstObject["CloudMember"] = "DefinitioinObj"
makeParent(bounds, selObj, scene) firstObject.name = "DefinitioinObj"
firstObject.max_draw_type = 'WIRE'
# Do the same to the 1. object since it is no longer in list. firstObject.restrict_render = True
firstObject["CloudMember"] = "DefinitioinObj" makeParent(bounds, firstObject, scene)
firstObject.name = "DefinitioinObj"
firstObject.max_draw_type = 'WIRE' ###############Create Cloud for putting Cloud Mesh############
firstObject.restrict_render = True # Create a new object cloud.
makeParent(bounds, firstObject, scene) cloud = addNewObject(scene, "CloudMesh", bounds)
cloud["CloudMember"] = "CreatedObj"
###############Create Cloud for putting Cloud Mesh############ cloud.max_draw_type = 'WIRE'
# Create a new object cloud. cloud.restrict_render = True
cloud = addNewObject(scene, "CloudMesh", bounds)
cloud["CloudMember"] = "CreatedObj" makeParent(bounds, cloud, scene)
cloud.max_draw_type = 'WIRE'
cloud.restrict_render = True bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='SELECT')
makeParent(bounds, cloud, scene) bpy.ops.mesh.subdivide(number_cuts=2, fractal=0, smoothness=1)
bpy.ops.object.location_apply()
bpy.ops.object.editmode_toggle() bpy.ops.mesh.vertices_smooth(repeat=20)
bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.tris_convert_to_quads()
bpy.ops.mesh.subdivide(number_cuts=2, fractal=0, smoothness=1) bpy.ops.mesh.faces_shade_smooth()
bpy.ops.object.location_apply() bpy.ops.object.editmode_toggle()
bpy.ops.mesh.vertices_smooth(repeat=20)
bpy.ops.mesh.tris_convert_to_quads() ###############Create Particles in cloud obj##################
bpy.ops.mesh.faces_shade_smooth() # Turn off gravity.
bpy.ops.object.editmode_toggle() scene.use_gravity = False
###############Create Particles in cloud obj################## # Set time to 0.
# Turn off gravity. scene.frame_current = 0
scene.use_gravity = False
# Add a new particle system.
# Set time to 0. bpy.ops.object.particle_system_add()
scene.frame_current = 0
#Particle settings setting it up!
# Add a new particle system. cloudParticles = cloud.active_particle_system
bpy.ops.object.particle_system_add() cloudParticles.name = "CloudParticles"
cloudParticles.settings.frame_start = 0
#Particle settings setting it up! cloudParticles.settings.frame_end = 0
cloudParticles = cloud.active_particle_system cloudParticles.settings.emit_from = 'VOLUME'
cloudParticles.name = "CloudParticles" cloudParticles.settings.draw_as = 'DOT'
cloudParticles.settings.frame_start = 0 cloudParticles.settings.ren_as = 'NONE'
cloudParticles.settings.frame_end = 0 cloudParticles.settings.normal_factor = 0
cloudParticles.settings.emit_from = 'VOLUME' cloudParticles.settings.distribution = 'RAND'
cloudParticles.settings.draw_as = 'DOT'
cloudParticles.settings.ren_as = 'NONE' ####################Create Volume Material####################
cloudParticles.settings.normal_factor = 0 # Deselect All
cloudParticles.settings.distribution = 'RAND' bpy.ops.object.select_all(action='DESELECT')
####################Create Volume Material#################### # Select the object.
# Deselect All bounds.selected = True
bpy.ops.object.select_all(action='DESELECT') scene.objects.active = bounds
# Select the object. # Turn bounds object into a box.
bounds.selected = True makeObjectIntoBoundBox(bounds, .2)
scene.objects.active = bounds
# Delete all material slots in bounds object.
# Turn bounds object into a box. for i in range(len(bounds.material_slots)):
makeObjectIntoBoundBox(bounds, .2) bounds.active_material_index = i - 1
bpy.ops.object.material_slot_remove()
# Delete all material slots in bounds object.
for i in range(len(bounds.material_slots)): # Add a new material.
bounds.active_material_index = i - 1 cloudMaterial = main.materials.new("CloudMaterial")
bpy.ops.object.material_slot_remove() bpy.ops.object.material_slot_add()
bounds.material_slots[0].material = cloudMaterial
# Add a new material.
cloudMaterial = main.materials.new("CloudMaterial") # Set Up the Cloud Material
bpy.ops.object.material_slot_add() cloudMaterial.name = "CloudMaterial"
bounds.material_slots[0].material = cloudMaterial cloudMaterial.type = 'VOLUME'
mVolume = cloudMaterial.volume
# Set Up the Cloud Material mVolume.scattering = scattering
cloudMaterial.name = "CloudMaterial" mVolume.density = 0
cloudMaterial.type = 'VOLUME' mVolume.density_scale = densityScale
mVolume = cloudMaterial.volume mVolume.transmission_color = [3, 3, 3]
mVolume.scattering = scattering mVolume.step_size = 0.1
mVolume.density = 0 mVolume.light_cache = True
mVolume.density_scale = densityScale mVolume.cache_resolution = 75
mVolume.transmission_color = [3, 3, 3]
mVolume.step_size = 0.1 # Add a texture
mVolume.light_cache = True vMaterialTextureSlots = cloudMaterial.texture_slots
mVolume.cache_resolution = 75 cloudtex = main.textures.new("CloudTex")
cloudMaterial.add_texture(cloudtex, 'ORCO')
# Add a texture cloudtex.type = 'CLOUDS'
vMaterialTextureSlots = cloudMaterial.texture_slots cloudtex.noise_type = 'HARD_NOISE'
cloudtex = main.textures.new("CloudTex") cloudtex.noise_size = 2
cloudMaterial.add_texture(cloudtex, 'ORCO')
cloudtex.type = 'CLOUDS' # Add a texture
cloudtex.noise_type = 'HARD_NOISE' cloudPointDensity = main.textures.new("CloudPointDensity")
cloudtex.noise_size = 2 cloudPointDensity.type = 'POINT_DENSITY'
cloudMaterial.add_texture(cloudPointDensity, 'ORCO')
# Add a texture pDensity = vMaterialTextureSlots[1].texture
cloudPointDensity = main.textures.new("CloudPointDensity") vMaterialTextureSlots[1].map_density = True
cloudPointDensity.type = 'POINT_DENSITY' vMaterialTextureSlots[1].rgb_to_intensity = True
cloudMaterial.add_texture(cloudPointDensity, 'ORCO') vMaterialTextureSlots[1].texture_coordinates = 'GLOBAL'
pDensity = vMaterialTextureSlots[1].texture pDensity.pointdensity.vertices_cache = 'WORLD_SPACE'
vMaterialTextureSlots[1].map_density = True pDensity.pointdensity.turbulence = True
vMaterialTextureSlots[1].rgb_to_intensity = True pDensity.pointdensity.noise_basis = 'VORONOI_F2'
vMaterialTextureSlots[1].texture_coordinates = 'GLOBAL' pDensity.pointdensity.turbulence_depth = 3
pDensity.pointdensity.vertices_cache = 'WORLD_SPACE'
pDensity.pointdensity.turbulence = True pDensity.use_color_ramp = True
pDensity.pointdensity.noise_basis = 'VORONOI_F2' pRamp = pDensity.color_ramp
pDensity.pointdensity.turbulence_depth = 3 pRamp.interpolation = 'LINEAR'
pRampElements = pRamp.elements
pDensity.use_color_ramp = True #pRampElements[1].position = .9
pRamp = pDensity.color_ramp #pRampElements[1].color = [.18,.18,.18,.8]
pRamp.interpolation = 'LINEAR'
pRampElements = pRamp.elements # Estimate the number of particles for the size of bounds.
#pRampElements[1].position = .9 volumeBoundBox = (bounds.dimensions[0] * bounds.dimensions[1]* bounds.dimensions[2])
#pRampElements[1].color = [.18,.18,.18,.8] numParticles = int((2.4462 * volumeBoundBox + 430.4) * numOfPoints)
if numParticles > maxNumOfPoints:
# Estimate the number of particles for the size of bounds. numParticles = maxNumOfPoints
volumeBoundBox = (bounds.dimensions[0] * bounds.dimensions[1]* bounds.dimensions[2]) print(numParticles)
numParticles = int((2.4462 * volumeBoundBox + 430.4) * numOfPoints)
if numParticles > maxNumOfPoints:
numParticles = maxNumOfPoints
print(numParticles)
# Set the number of particles according to the volume # Set the number of particles according to the volume
# of bounds. # of bounds.
cloudParticles.settings.amount = numParticles cloudParticles.settings.amount = numParticles
pDensity.pointdensity.radius = (.00013764 * volumeBoundBox + .3989) * pointDensityRadiusFactor pDensity.pointdensity.radius = (.00013764 * volumeBoundBox + .3989) * pointDensityRadiusFactor
# Set time to 1. # Set time to 1.
scene.frame_current = 1 scene.frame_current = 1
###############Create CloudPnts for putting points in######### ###############Create CloudPnts for putting points in#########
# Create a new object cloudPnts # Create a new object cloudPnts
cloudPnts = addNewObject(scene, "CloudPoints", bounds) cloudPnts = addNewObject(scene, "CloudPoints", bounds)
cloudPnts["CloudMember"] = "CreatedObj" cloudPnts["CloudMember"] = "CreatedObj"
cloudPnts.max_draw_type = 'WIRE' cloudPnts.max_draw_type = 'WIRE'
cloudPnts.restrict_render = True cloudPnts.restrict_render = True
makeParent(bounds, cloudPnts, scene) makeParent(bounds, cloudPnts, scene)
bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.delete(type='ALL') bpy.ops.mesh.delete(type='ALL')
meshPnts = cloudPnts.data meshPnts = cloudPnts.data
listCloudParticles = cloudParticles.particles listCloudParticles = cloudParticles.particles
listMeshPnts = [] listMeshPnts = []
for pTicle in listCloudParticles: for pTicle in listCloudParticles:
listMeshPnts.append(pTicle.location) listMeshPnts.append(pTicle.location)
# Must be in object mode fro from_pydata to work. # Must be in object mode fro from_pydata to work.
bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='OBJECT')
# Add in the mesh data. # Add in the mesh data.
meshPnts.from_pydata(listMeshPnts, [], []) meshPnts.from_pydata(listMeshPnts, [], [])
# Update the mesh. # Update the mesh.
meshPnts.update() meshPnts.update()
# Add a modifier. # Add a modifier.
bpy.ops.object.modifier_add(type='DISPLACE') bpy.ops.object.modifier_add(type='DISPLACE')
cldPntsModifiers = cloudPnts.modifiers cldPntsModifiers = cloudPnts.modifiers
cldPntsModifiers[0].name = "CloudPnts" cldPntsModifiers[0].name = "CloudPnts"
cldPntsModifiers[0].texture = cloudtex cldPntsModifiers[0].texture = cloudtex
cldPntsModifiers[0].texture_coordinates = 'OBJECT' cldPntsModifiers[0].texture_coordinates = 'OBJECT'
cldPntsModifiers[0].texture_coordinate_object = cloud cldPntsModifiers[0].texture_coordinate_object = cloud
cldPntsModifiers[0].strength = -1.4 cldPntsModifiers[0].strength = -1.4
# Apply modifier # Apply modifier
bpy.ops.object.modifier_apply(apply_as='DATA', modifier=cldPntsModifiers[0].name) bpy.ops.object.modifier_apply(apply_as='DATA', modifier=cldPntsModifiers[0].name)
pDensity.pointdensity.point_source = 'OBJECT' pDensity.pointdensity.point_source = 'OBJECT'
pDensity.pointdensity.object = cloudPnts pDensity.pointdensity.object = cloudPnts
# Deselect All # Deselect All
bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_all(action='DESELECT')
# Select the object. # Select the object.
cloud.selected = True cloud.selected = True
scene.objects.active = cloud scene.objects.active = cloud
bpy.ops.object.particle_system_remove() bpy.ops.object.particle_system_remove()
# Deselect All # Deselect All
bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_all(action='DESELECT')
# Select the object. # Select the object.
bounds.selected = True bounds.selected = True
scene.objects.active = bounds scene.objects.active = bounds
# Add a force field to the points. # Add a force field to the points.
#cloudField = bounds.field #cloudField = bounds.field
#cloudField.type = 'TEXTURE' #cloudField.type = 'TEXTURE'
#cloudField.strength = 2 #cloudField.strength = 2
#cloudField.texture = cloudtex #cloudField.texture = cloudtex
# Set time # Set time
#for i in range(12): #for i in range(12):
# scene.current_frame = i # scene.current_frame = i
# scene.update() # scene.update()
#bpy.ops.ptcache.bake_all(bake=False) #bpy.ops.ptcache.bake_all(bake=False)
#self.report({'WARNING'}, "Generating Cloud")
return {'FINISHED'} return {'FINISHED'}
bpy.types.register(GenerateCloud)
classes = [VIEW3D_PT_tools_cloud,
GenerateCloud]
def register():
register = bpy.types.register
for cls in classes:
register(cls)
def unregister():
unregister = bpy.types.unregister
for cls in classes:
unregister(cls)
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.cloud.generate_cloud() register()
\ No newline at end of file \ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment