# "Scatter" Add-on
# Copyright (C) 2019 Dorian Borremans aka BD3D
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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
# 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, see <http://www.gnu.org/licenses/>.
# <pep8 compliant>
bl_info = {
"name" : "Scatter [BD3D]",
"author" : "BD3D",
"description" : "The scattering tool of 2.8",
"blender" : (2, 80, 0),
"location" : "Operator",
"warning" : "",
"category" : "Generic"
}
import bpy
import random
from bpy.types import Menu
import webbrowser
from bpy.types import Operator, AddonPreferences, PropertyGroup
from bpy.props import StringProperty, IntProperty, BoolProperty, FloatProperty
import rna_keymap_ui
context = bpy.context
def find_collection(context, item):
collections = item.users_collection
if len(collections) > 0:
return collections[0]
return context.scene.collection
def make_collection(collection_name, parent_collection):
if collection_name in bpy.data.collections:
return bpy.data.collections[collection_name]
else:
new_collection = bpy.data.collections.new(collection_name)
parent_collection.children.link(new_collection)
return new_collection
######################################################################################
######################################################################################
# # # # # # # # # # # # SCATTER ADDON PREF # # # # # # # # # # # #
######################################################################################
######################################################################################
class ScatterPref(AddonPreferences):
bl_idname = __name__
scatter_01_count = IntProperty(
name="Emission Number",
subtype='NONE',
default=1000,
min=0,
)#percentage couvert?
scatter_01_seed = IntProperty(
name="Emission Seed Value",
subtype='NONE',
default=5,
min=0,
)
scatter_01_seed_is_random = BoolProperty(
name="Emission Random Seed Value",
subtype='NONE',
default=True,
)
scatter_01_particle_size = FloatProperty(
name="Render Scale",
subtype='NONE',
default=0.25,
min=0.01,
max=3
)
scatter_01_size_random = FloatProperty(
name="Render Scale Randomness",
subtype='NONE',
default=0.35,
min=0,
max=1
)
scatter_01_phase_factor_random = FloatProperty(
name="Rotation Randomize Phase",
subtype='NONE',
default=2,
min=0,
max=2
)
scatter_01_display_percentage = IntProperty(
name="Viewport Display Percentage",
subtype='NONE',
default=100,
min=0,
max=100
)
scatter_01_open= bpy.props.BoolProperty(
name="Show Debug Tools",
description="Expand me senpai",
default=False
)
######################################################################################
def draw(self, context): #DRAWING HERE - DRAWING HERE - DRAWING HERE- DRAWING HERE
layout = self.layout
full= "------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
addon_prefs = context.preferences.addons[__name__].preferences
box = layout.box()
col = box.column()
row = col.row(align=True)
row.alignment = 'LEFT'
row.prop(self,
'scatter_01_open',
text="Custom Scattering Slot 01",
emboss=False,
icon="PLAY" if self.scatter_01_open else "PLAY")
if self.scatter_01_open:
col.prop(self,"scatter_01_count")
if addon_prefs.scatter_01_seed_is_random == True:
col.prop(self,"scatter_01_seed_is_random")
else:
col.prop(self,"scatter_01_seed_is_random")
col.prop(self,"scatter_01_seed")
col.prop(self,"scatter_01_particle_size")
col.prop(self,"scatter_01_size_random")
col.prop(self,"scatter_01_phase_factor_random")
col.prop(self,"scatter_01_display_percentage")
######################################################################################
######################################################################################
# # # # # # # # # # # # SCATTER OPERATOR # # # # # # # # # # # #
######################################################################################
######################################################################################
class Scatter_OT_Custom01(bpy.types.Operator):
bl_idname = "scatter.custom01"
bl_label = "custom scattering operator 01"
bl_description = ""
def execute(self, context):
context = bpy.context
addon_prefs = context.preferences.addons[__name__].preferences
scene = context.scene
A = context.object
### ### Naming
slotname = "Custom1"
if len(bpy.context.selected_objects) > 2:
particlename = bpy.context.selected_objects[1].name + " ..."
else:
particlename = bpy.context.selected_objects[1].name #BUG why the f does the name change when multiple execution ???
pref = "SCATTER: ["+slotname+"] ["+particlename+"] v."
i = 1
name = "%s%d" % (pref, i)
while A.modifiers.get(name):
i += 1
name = "%s%d" % (pref, i)
### ### add particle system + rename and add selection in new coll
m = A.modifiers.new(name, type='PARTICLE_SYSTEM')
A.select_set(state=False)
for o in bpy.context.selected_objects:
o_collection = find_collection(bpy.context, o)
new_collection = make_collection(name , o_collection)
new_collection.objects.link(o)
o_collection.objects.unlink(o)
A.select_set(state=True)
### ### particle parameters
ps = m.particle_system
ps.name = name
ps.settings.name = name
ps.settings.type = 'HAIR'
ps.settings.render_type = 'COLLECTION'
ps.settings.instance_collection = bpy.data.collections[name]
ps.settings.particle_size = addon_prefs.scatter_01_particle_size
ps.settings.hair_length = 4
ps.settings.size_random = addon_prefs.scatter_01_size_random
ps.settings.count = addon_prefs.scatter_01_count
if addon_prefs.scatter_01_seed_is_random == True:
bpy.context.object.particle_systems[name].seed = random.randint(0,10000)
else:
bpy.context.object.particle_systems[name].seed = addon_prefs.scatter_01_seed
ps.settings.display_percentage = addon_prefs.scatter_01_display_percentage
ps.settings.use_advanced_hair = True
ps.settings.use_rotations = True
ps.settings.rotation_factor_random = 1
ps.settings.phase_factor = 1
ps.settings.phase_factor_random = addon_prefs.scatter_01_phase_factor_random
### ### texture parameters
bpy.ops.texture.new()
texturename = name
bpy.data.textures[-1].name = texturename
bpy.data.textures[texturename].type = 'CLOUDS' #LATER SUPPORT OTHER NOISE TYPE AND OPTIONS
bpy.data.textures[texturename].noise_scale = 0.45 #FUTURE PARAMETERS = Scattering noise scale #LATER GIVE VARIATION RANDOMNESS ON RANGE
bpy.data.textures[texturename].noise_depth = 0 #FUTURE PARAMETERS = Scattering noise depth #LATER GIVE VARIATION RANDOMNESS ON RANGE
bpy.data.textures[texturename].contrast = 3 #FUTURE PARAMETERS = Scattering border (contrast) #LATER GIVE VARIATION RANDOMNESS ON RANGE
bpy.data.textures[texturename].intensity = 1 #FUTURE PARAMETERS = Scattering range (brightness) #LATER GIVE VARIATION RANDOMNESS ON RANGE
ps.settings.texture_slots.add().texture = bpy.data.textures[texturename]
ps.settings.texture_slots[0].blend_type = 'MULTIPLY'
ps.settings.texture_slots[0].use_map_time = False
ps.settings.texture_slots[0].use_map_density = True
ps.settings.texture_slots[0].density_factor = 1 #FUTURE PARAMETERS = Scattering density Influence
ps.settings.texture_slots[0].use_map_length = True
ps.settings.texture_slots[0].length_factor = 0.3 #FUTURE PARAMETERS = Scattering size Influence
ps.settings.texture_slots[0].scale[1] = 1 #FUTURE PARAMETERS = scalex #LATER GIVE VARIATION RANDOMNESS ON RANGE
ps.settings.texture_slots[0].scale[2] = 1 #FUTURE PARAMETERS = scaley #LATER GIVE VARIATION RANDOMNESS ON RANGE
ps.settings.texture_slots[0].scale[0] = 1 #FUTURE PARAMETERS = scalez #LATER GIVE VARIATION RANDOMNESS ON RANGE
ps.settings.texture_slots[0].offset[1] = 0 #FUTURE PARAMETERS = offsetx #LATER GIVE VARIATION RANDOMNESS ON RANGE
ps.settings.texture_slots[0].offset[2] = 0 #FUTURE PARAMETERS = offsety #LATER GIVE VARIATION RANDOMNESS ON RANGE
ps.settings.texture_slots[0].offset[0] = 0 #FUTURE PARAMETERS = offsetz #LATER GIVE VARIATION RANDOMNESS ON RANGE
ps.settings.texture_slots[0].texture_coords = 'GLOBAL'
return {'FINISHED'}
######################################################################################
######################################################################################
# # # # # # # # # # # # N MENU # # # # # # # # # # # #
######################################################################################
######################################################################################
class Scatter_PT_ScatteringPanel(bpy.types.Panel):
bl_idname = "Scatter_PT_ScatteringPanel"
bl_label = "Scatter"
bl_category = "Scatter"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
def draw(self, context):
layout = self.layout
bigbutton = layout.column()
bigbutton.scale_y=2
bigbutton.operator('scatter.custom01', text="SCATTER", icon='PLAY')
######################################################################################
######################################################################################
# # # # # # # # # # # # REG # # # # # # # # # # # #
######################################################################################
######################################################################################
def register():
bpy.utils.register_class(ScatterPref)
bpy.utils.register_class(Scatter_OT_Custom01)
bpy.utils.register_class(Scatter_PT_ScatteringPanel)
def unregister():
bpy.utils.unregister_class(ScatterPref)
bpy.utils.unregister_class(Scatter_OT_Custom01)
bpy.utils.unregister_class(Scatter_PT_ScatteringPanel)
if __name__ == "__main__":
register()
#write ops to do on script exec
Scatter_v01.py (12.3 KB)
Okay the script is now in an addon form.
in the N panel you will find a little operator scattering button.
on the properties panel you will find some customization options for the only custom skattering slot we have yet.