Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
B
blender-addons
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
blender
blender-addons
Commits
fe8cbeae
Commit
fe8cbeae
authored
13 years ago
by
Campbell Barton
Browse files
Options
Downloads
Patches
Plain Diff
update the script to remove UI hack and use dialog
parent
37242333
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
object_grease_scatter.py
+99
-91
99 additions, 91 deletions
object_grease_scatter.py
with
99 additions
and
91 deletions
object_grease_scatter.py
+
99
−
91
View file @
fe8cbeae
...
@@ -16,7 +16,7 @@
...
@@ -16,7 +16,7 @@
#
#
# ##### END GPL LICENSE BLOCK #####
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
# <pep8
-80
compliant>
# Script copyright (C) Campbell Barton
# Script copyright (C) Campbell Barton
...
@@ -42,41 +42,35 @@ from random import uniform, shuffle
...
@@ -42,41 +42,35 @@ from random import uniform, shuffle
import
bpy
import
bpy
def
_main
(
self
,
DENSITY
=
1.0
,
SCALE
=
0.6
,
RAND_LOC
=
0.8
,
RAND_ALIGN
=
0.75
):
def
_main
(
self
,
from
math
import
radians
obj
,
group
,
DENSITY
=
1.0
,
SCALE
=
0.6
,
RAND_LOC
=
0.8
,
RAND_ALIGN
=
0.75
,
):
C
=
bpy
.
context
from
math
import
radians
,
pi
o
=
C
.
object
# print(o.ray_cast(Vector(), Vector(0,0,0.2)))
OFS
=
0.2
#
OFS = 0.2
SEEK
=
2.0
# distance for ray to seek
SEEK
=
2.0
# distance for ray to seek
BAD_NORMAL
=
Vector
((
0.0
,
0.0
,
-
1.0
))
BAD_NORMAL
=
Vector
((
0.0
,
0.0
,
-
1.0
))
WALL_LIMIT
=
radians
(
45.0
)
WALL_LIMIT
=
radians
(
45.0
)
mats
=
[
Matrix
.
Rotation
(
radians
(
-
45
),
3
,
'
X
'
),
mats
=
(
Matrix
.
Rotation
(
radians
(
-
45
),
3
,
'
X
'
),
Matrix
.
Rotation
(
radians
(
+
45
),
3
,
'
X
'
),
Matrix
.
Rotation
(
radians
(
+
45
),
3
,
'
X
'
),
Matrix
.
Rotation
(
radians
(
-
45
),
3
,
'
Y
'
),
Matrix
.
Rotation
(
radians
(
-
45
),
3
,
'
Y
'
),
Matrix
.
Rotation
(
radians
(
+
45
),
3
,
'
Y
'
),
Matrix
.
Rotation
(
radians
(
+
45
),
3
,
'
Y
'
),
Matrix
.
Rotation
(
radians
(
-
45
),
3
,
'
Z
'
),
Matrix
.
Rotation
(
radians
(
-
45
),
3
,
'
Z
'
),
Matrix
.
Rotation
(
radians
(
+
45
),
3
,
'
Z
'
),
Matrix
.
Rotation
(
radians
(
+
45
),
3
,
'
Z
'
),
]
)
Z_UP
=
Vector
((
0.0
,
0.0
,
1.0
))
Z_UP
=
Vector
((
0.0
,
0.0
,
1.0
))
dirs
=
[
Vector
((
0.0
,
0.0
,
OFS
)),
Y_UP
=
Vector
((
0.0
,
1.0
,
0.0
))
Vector
((
0.0
,
0.0
,
-
OFS
)),
]
'''
Vector(0,OFS,0),
Vector(0,-OFS,0),
Vector(OFS,0,0),
Vector(-OFS,0,0)
'''
group
=
bpy
.
data
.
groups
.
get
(
o
.
name
)
if
not
group
:
if
not
group
:
self
.
report
({
'
WARNING
'
},
"
Group
'
%s
'
not found
, must match object name
"
%
o
.
name
)
self
.
report
({
'
WARNING
'
},
"
Group
'
%s
'
not found
"
%
o
bj
.
name
)
return
return
def
faces_from_hits
(
hit_list
):
def
faces_from_hits
(
hit_list
):
...
@@ -115,14 +109,13 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
...
@@ -115,14 +109,13 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
obj_new
=
bpy
.
data
.
objects
.
new
(
"
Torus
"
,
mesh
)
obj_new
=
bpy
.
data
.
objects
.
new
(
"
Torus
"
,
mesh
)
scene
.
objects
.
link
(
obj_new
)
scene
.
objects
.
link
(
obj_new
)
ray
=
o
.
ray_cast
ray
=
obj
.
ray_cast
closest_point
=
o
.
closest_point_on_mesh
closest_point_on_mesh
=
obj
.
closest_point_on_mesh
#ray = C.scene.ray_cast
DEBUG
=
False
DEBUG
=
False
def
fix_point
(
p
):
def
fix_point
(
p
):
hit
,
no
,
ind
=
closest_point
(
p
)
hit
,
no
,
ind
=
closest_point
_on_mesh
(
p
)
if
ind
!=
-
1
:
if
ind
!=
-
1
:
if
DEBUG
:
if
DEBUG
:
return
[
p
,
no
,
None
]
return
[
p
,
no
,
None
]
...
@@ -196,7 +189,8 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
...
@@ -196,7 +189,8 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
pt
[
2
]
=
best_nor
pt
[
2
]
=
best_nor
#scene.cursor_location[:] = best_hitnyway
#scene.cursor_location[:] = best_hitnyway
# bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
# bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP',
# iterations=1)
# debug_edge(p, best_hit)
# debug_edge(p, best_hit)
# p[:] = best_hit
# p[:] = best_hit
...
@@ -206,11 +200,13 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
...
@@ -206,11 +200,13 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
nors
=
[]
nors
=
[]
oris
=
[]
oris
=
[]
for
s
in
splines
:
for
s
in
splines
:
for
p
,
n
,
n_other
in
s
:
# point, normal, n_other the closest hit normal
# point, normal, n_other the closest hit normal
for
p
,
n
,
n_other
in
s
:
if
n
is
BAD_NORMAL
:
if
n
is
BAD_NORMAL
:
continue
continue
if
n_other
:
if
n_other
:
# cast vectors twice as long as the distance needed just incase.
# cast vectors twice as long as the distance
# needed just incase.
n_down
=
(
n
*
-
SEEK
)
n_down
=
(
n
*
-
SEEK
)
l
=
n_down
.
length
l
=
n_down
.
length
n_other
.
length
=
l
n_other
.
length
=
l
...
@@ -249,14 +245,14 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
...
@@ -249,14 +245,14 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
#oris.append(n_other)
#oris.append(n_other)
if
0
:
if
0
:
mesh
=
bpy
.
data
.
meshes
.
new
(
"
Retopo
"
)
mesh
=
bpy
.
data
.
meshes
.
new
(
"
ScatterDupliFace
"
)
mesh
.
from_pydata
(
hits
,
[],
[])
mesh
.
from_pydata
(
hits
,
[],
[])
scene
=
bpy
.
context
.
scene
scene
=
bpy
.
context
.
scene
mesh
.
update
()
mesh
.
update
()
obj_new
=
bpy
.
data
.
objects
.
new
(
"
Torus
"
,
mesh
)
obj_new
=
bpy
.
data
.
objects
.
new
(
"
ScatterPar
"
,
mesh
)
scene
.
objects
.
link
(
obj_new
)
scene
.
objects
.
link
(
obj_new
)
obj_new
.
layers
[:]
=
o
.
layers
obj_new
.
layers
[:]
=
o
bj
.
layers
# Now setup dupli-faces
# Now setup dupli-faces
obj_new
.
dupli_type
=
'
VERTS
'
obj_new
.
dupli_type
=
'
VERTS
'
...
@@ -274,28 +270,33 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
...
@@ -274,28 +270,33 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
tot_div
=
int
(
len
(
triples
)
/
tot
)
tot_div
=
int
(
len
(
triples
)
/
tot
)
for
inst_ob
in
obs
:
for
inst_ob
in
obs
:
triple_sub
set
=
triples
[
0
:
tot_div
]
triple_sub
=
triples
[
0
:
tot_div
]
triples
[
0
:
tot_div
]
=
[]
triples
[
0
:
tot_div
]
=
[]
vv
=
[
tuple
(
v
)
for
f
in
triple_sub
set
for
v
in
f
]
vv
=
[
tuple
(
v
)
for
f
in
triple_sub
for
v
in
f
]
mesh
=
bpy
.
data
.
meshes
.
new
(
"
Retopo
"
)
mesh
=
bpy
.
data
.
meshes
.
new
(
"
ScatterDupliFace
"
)
mesh
.
from_pydata
(
vv
,
[],
[(
i
*
3
,
i
*
3
+
1
,
i
*
3
+
2
)
for
i
in
range
(
len
(
triple_subset
))])
mesh
.
from_pydata
(
vv
,
[],
[(
i
*
3
,
i
*
3
+
1
,
i
*
3
+
2
)
for
i
in
range
(
len
(
triple_sub
))])
scene
=
bpy
.
context
.
scene
scene
=
bpy
.
context
.
scene
mesh
.
update
()
mesh
.
update
()
obj_new
=
bpy
.
data
.
objects
.
new
(
"
Torus
"
,
mesh
)
obj_new
=
bpy
.
data
.
objects
.
new
(
"
ScatterPar
"
,
mesh
)
scene
.
objects
.
link
(
obj_new
)
scene
.
objects
.
link
(
obj_new
)
obj_new
.
layers
[:]
=
o
.
layers
obj_new
.
layers
[:]
=
o
bj
.
layers
# Now setup dupli-faces
# Now setup dupli-faces
obj_new
.
dupli_type
=
'
FACES
'
obj_new
.
dupli_type
=
'
FACES
'
obj_new
.
use_dupli_faces_scale
=
True
obj_new
.
use_dupli_faces_scale
=
True
obj_new
.
dupli_faces_scale
=
100.0
obj_new
.
dupli_faces_scale
=
100.0
inst_ob
.
location
=
obj_new
.
location
inst_ob
.
location
=
0.0
,
0.0
,
0.0
inst_ob
.
parent
=
obj_new
inst_ob
.
parent
=
obj_new
# important to set last
obj_new
.
matrix_world
=
obj
.
matrix_world
# BGE settings for testiing
# BGE settings for testiing
'''
'''
inst_ob.game.physics_type =
'
RIGID_BODY
'
inst_ob.game.physics_type =
'
RIGID_BODY
'
...
@@ -319,100 +320,107 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
...
@@ -319,100 +320,107 @@ def _main(self, DENSITY=1.0, SCALE=0.6, RAND_LOC=0.8, RAND_ALIGN=0.75):
quat
=
no
.
to_track_quat
(
'
X
'
,
'
Z
'
)
quat
=
no
.
to_track_quat
(
'
X
'
,
'
Z
'
)
# make 2 angles and blend
# make 2 angles and blend
angle
=
radians
(
uniform
(
-
180
,
180.0
)
)
angle
=
uniform
(
-
pi
,
pi
)
angle_aligned
=
-
(
ori
.
angle
(
quat
*
Vector
((
0.0
,
1.0
,
0.0
)),
radians
(
180.0
)
))
angle_aligned
=
-
(
ori
.
angle
(
quat
*
Y_UP
,
pi
))
quat
=
Quaternion
(
no
,
(
angle
*
(
1.0
-
RAND_ALIGN
))
+
(
angle_aligned
*
RAND_ALIGN
)).
cross
(
quat
)
quat
=
Quaternion
(
no
,
(
angle
*
(
1.0
-
RAND_ALIGN
))
+
(
angle_aligned
*
RAND_ALIGN
)
).
cross
(
quat
)
f
=
uniform
(
0.1
,
1.2
)
*
SCALE
f
=
uniform
(
0.1
,
1.2
)
*
SCALE
coords
.
append
([
co
+
(
quat
*
(
tri
[
0
]
*
f
)),
co
+
(
quat
*
(
tri
[
1
]
*
f
)),
co
+
(
quat
*
(
tri
[
2
]
*
f
))])
coords
.
append
([
co
+
(
quat
*
(
tri
[
0
]
*
f
)),
# face_ind.append([i*3, i*3+1, i*3+2])
co
+
(
quat
*
(
tri
[
1
]
*
f
)),
co
+
(
quat
*
(
tri
[
2
]
*
f
)),
])
apply_faces
(
coords
)
apply_faces
(
coords
)
main
()
main
()
from
bpy.props
import
FloatProperty
from
bpy.props
import
FloatProperty
,
StringProperty
class
Scatter
(
bpy
.
types
.
Operator
):
class
Scatter
(
bpy
.
types
.
Operator
):
''''''
''''''
bl_idname
=
"
object.scatter
"
bl_idname
=
"
object.scatter
"
bl_label
=
"
Scatter
"
bl_label
=
"
Grease Pencil Scatter
"
bl_options
=
{
'
REGISTER
'
}
density
=
FloatProperty
(
name
=
"
Density
"
,
density
=
FloatProperty
(
name
=
"
Density
"
,
description
=
"
Multiplier for the density of items
"
,
description
=
"
Multiplier for the density of items
"
,
default
=
1.0
,
min
=
0.01
,
max
=
10.0
)
default
=
1.0
,
min
=
0.01
,
max
=
10.0
,
)
scale
=
FloatProperty
(
name
=
"
Scale
"
,
scale
=
FloatProperty
(
name
=
"
Scale
"
,
description
=
"
Size multiplier for duplifaces
"
,
description
=
"
Size multiplier for duplifaces
"
,
default
=
1.0
,
min
=
0.01
,
max
=
10.0
)
default
=
1.0
,
min
=
0.01
,
max
=
10.0
,
)
rand_align
=
FloatProperty
(
name
=
"
Random Align
"
,
rand_align
=
FloatProperty
(
name
=
"
Random Align
"
,
description
=
"
Randomize alignmet with the walls
"
,
description
=
"
Randomize alignmet with the walls
"
,
default
=
0.75
,
min
=
0.0
,
max
=
1.0
)
default
=
0.75
,
min
=
0.0
,
max
=
1.0
,
)
rand_loc
=
FloatProperty
(
name
=
"
Random Loc
"
,
rand_loc
=
FloatProperty
(
name
=
"
Random Loc
"
,
description
=
"
Randomize Placement
"
,
description
=
"
Randomize Placement
"
,
default
=
0.75
,
min
=
0.0
,
max
=
1.0
)
default
=
0.75
,
min
=
0.0
,
max
=
1.0
,
)
_parent
=
None
# XXX, should not be a string - TODO, add a way for scritps to select ID's
group
=
StringProperty
(
name
=
"
Group
"
,
description
=
(
"
Group name to use for object placement,
"
"
defaults to object name when that matches a group
"
))
def
execute
(
self
,
context
):
def
execute
(
self
,
context
):
#self.properties.density = self.__class__._parent.properties.density # XXX bad way to copy args.
obj
=
bpy
.
context
.
object
#self.properties.scale = self.__class__._parent.properties.scale # XXX bad way to copy args.
group
=
bpy
.
data
.
groups
.
get
(
self
.
group
)
for
attr
in
self
.
__class__
.
__dict__
[
"
order
"
]:
if
not
group
:
if
not
attr
.
startswith
(
"
_
"
):
self
.
report
({
'
ERROR
'
},
"
Group %r not found
"
,
self
.
group
)
try
:
return
{
'
CANCELLED
'
}
setattr
(
self
.
properties
,
attr
,
getattr
(
self
.
__class__
.
_parent
.
properties
,
attr
))
except
:
pass
_main
(
self
,
_main
(
self
,
DENSITY
=
self
.
properties
.
density
,
obj
,
SCALE
=
self
.
properties
.
scale
,
group
,
RAND_LOC
=
self
.
properties
.
rand_loc
,
DENSITY
=
self
.
density
,
RAND_ALIGN
=
self
.
properties
.
rand_align
,
SCALE
=
self
.
scale
,
RAND_LOC
=
self
.
rand_loc
,
RAND_ALIGN
=
self
.
rand_align
,
)
)
return
{
'
FINISHED
'
}
return
{
'
FINISHED
'
}
def
invoke
(
self
,
context
,
event
):
def
check
(
self
,
context
):
wm
=
context
.
window_manager
if
self
.
group
not
in
bpy
.
data
.
groups
:
wm
.
invoke_popup
(
self
,
width
=
180
)
self
.
group
=
""
return
{
'
RUNNING_MODAL
'
}
return
True
return
False
def
draw
(
self
,
context
):
def
invoke
(
self
,
context
,
event
):
self
.
__class__
.
_parent
=
self
layout
=
self
.
layout
for
attr
in
self
.
__class__
.
__dict__
[
"
order
"
]:
# useful to initialize, take a guess
if
not
attr
.
startswith
(
"
_
"
):
if
not
self
.
group
and
context
.
object
.
name
in
bpy
.
data
.
groups
:
try
:
self
.
group
=
context
.
object
.
name
layout
.
prop
(
self
.
properties
,
attr
)
except
:
pass
layout
.
operator_context
=
'
EXEC_DEFAULT
'
wm
=
context
.
window_manager
layout
.
operator
(
self
.
bl_idname
)
wm
.
invoke_props_dialog
(
self
,
width
=
180
)
return
{
'
RUNNING_MODAL
'
}
# Add to the menu
def
menu_func
(
self
,
context
):
menu_func
=
(
lambda
self
,
context
:
self
.
layout
.
operator
(
Scatter
.
bl_idname
,
self
.
layout
.
operator
(
Scatter
.
bl_idname
,
icon
=
'
AUTO
'
)
text
=
"
Scatter
"
,
icon
=
'
AUTO
'
))
def
register
():
def
register
():
bpy
.
utils
.
register_class
(
Scatter
)
bpy
.
utils
.
register_class
(
Scatter
)
bpy
.
types
.
VIEW3D_PT_tools_objectmode
.
append
(
menu_func
)
bpy
.
types
.
INFO_MT_mesh_add
.
append
(
menu_func
)
def
unregister
():
def
unregister
():
bpy
.
utils
.
unregister_class
(
Scatter
)
bpy
.
utils
.
unregister_class
(
Scatter
)
bpy
.
types
.
VIEW3D_PT_tools_objectmode
.
remove
(
menu_func
)
bpy
.
types
.
INFO_MT_mesh_add
.
remove
(
menu_func
)
#if __name__ == "__main__":
#if __name__ == "__main__":
# _main()
# _main()
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment