1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # Another Noise Tool - Functions
23 # Michel Anders, Ian Huish
27 from bpy
.props
import (
38 from .ant_noise
import noise_gen
40 # ------------------------------------------------------------
41 # Create a new mesh (object) from verts/edges/faces.
42 # verts/edges/faces ... List of vertices/edges/faces for the
43 # new mesh (as used in from_pydata).
44 # name ... Name of the new mesh (& object)
46 from bpy_extras
import object_utils
48 def create_mesh_object(context
, verts
, edges
, faces
, name
):
50 mesh
= bpy
.data
.meshes
.new(name
)
51 # Make a mesh from a list of verts/edges/faces.
52 mesh
.from_pydata(verts
, [], faces
)
53 # Update mesh geometry after adding stuff.
55 return object_utils
.object_data_add(context
, mesh
, operator
=None)
59 def grid_gen(sub_d_x
, sub_d_y
, tri
, meshsize_x
, meshsize_y
, props
, water_plane
, water_level
):
62 for i
in range (0, sub_d_x
):
63 x
= meshsize_x
* (i
/ (sub_d_x
- 1) - 1 / 2)
64 for j
in range(0, sub_d_y
):
65 y
= meshsize_y
* (j
/ (sub_d_y
- 1) - 1 / 2)
69 z
= noise_gen((x
, y
, 0), props
)
74 for i
in range (0, sub_d_y
* (sub_d_x
- 1)):
75 if count
< sub_d_y
- 1 :
81 faces
.append((A
, B
, D
))
82 faces
.append((B
, C
, D
))
84 faces
.append((A
, B
, C
, D
))
93 def sphere_gen(sub_d_x
, sub_d_y
, tri
, meshsize
, props
, water_plane
, water_level
):
98 for i
in range(0, sub_d_x
):
99 for j
in range(0, sub_d_y
):
100 u
= sin(j
* pi
* 2 / (sub_d_y
- 1)) * cos(-pi
/ 2 + i
* pi
/ (sub_d_x
- 1)) * meshsize
/ 2
101 v
= cos(j
* pi
* 2 / (sub_d_y
- 1)) * cos(-pi
/ 2 + i
* pi
/ (sub_d_x
- 1)) * meshsize
/ 2
102 w
= sin(-pi
/ 2 + i
* pi
/ (sub_d_x
- 1)) * meshsize
/ 2
106 h
= noise_gen((u
, v
, w
), props
) / meshsize
107 verts
.append(((u
+ u
* h
), (v
+ v
* h
), (w
+ w
* h
)))
110 for i
in range (0, sub_d_y
* (sub_d_x
- 1)):
111 if count
< sub_d_y
- 1 :
115 D
= (i
+ sub_d_y
) + 1
117 faces
.append((A
, B
, D
))
118 faces
.append((B
, C
, D
))
120 faces
.append((A
, B
, C
, D
))
128 # ------------------------------------------------------------
129 # Do refresh - redraw
130 class AntLandscapeRefresh(bpy
.types
.Operator
):
131 bl_idname
= "mesh.ant_landscape_refresh"
133 bl_description
= "Refresh landscape with current settings"
134 bl_options
= {'REGISTER', 'UNDO'}
138 def poll(cls
, context
):
139 ob
= bpy
.context
.active_object
140 return (ob
.ant_landscape
and not ob
.ant_landscape
['sphere_mesh'])
143 def execute(self
, context
):
145 undo
= bpy
.context
.user_preferences
.edit
.use_global_undo
146 bpy
.context
.user_preferences
.edit
.use_global_undo
= False
149 obj
= bpy
.context
.active_object
151 bpy
.ops
.object.mode_set(mode
= 'EDIT')
152 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
154 if obj
and obj
.ant_landscape
.keys():
155 ob
= obj
.ant_landscape
158 for i
in range(len(obi
)):
159 prop
.append(obi
[i
][1])
164 if ob
['vert_group'] != "" and ob
['vert_group'] in obj
.vertex_groups
:
165 vertex_group
= obj
.vertex_groups
[ob
['vert_group']]
166 gi
= vertex_group
.index
167 for v
in mesh
.vertices
:
171 v
.co
[2] = vertex_group
.weight(v
.index
) * noise_gen(v
.co
, prop
)
173 for v
in mesh
.vertices
:
175 v
.co
[2] = noise_gen(v
.co
, prop
)
180 # restore pre operator undo state
181 context
.user_preferences
.edit
.use_global_undo
= undo
185 # ------------------------------------------------------------
187 class AntLandscapeRegenerate(bpy
.types
.Operator
):
188 bl_idname
= "mesh.ant_landscape_regenerate"
189 bl_label
= "Regenerate"
190 bl_description
= "Regenerate landscape with current settings"
191 bl_options
= {'REGISTER', 'UNDO'}
195 def poll(cls
, context
):
196 ob
= bpy
.context
.active_object
197 if ob
.mode
== 'EDIT':
199 return ob
.ant_landscape
202 def execute(self
, context
):
205 undo
= bpy
.context
.user_preferences
.edit
.use_global_undo
206 bpy
.context
.user_preferences
.edit
.use_global_undo
= False
208 scene
= bpy
.context
.scene
210 obj
= bpy
.context
.active_object
212 if obj
and obj
.ant_landscape
.keys():
213 ob
= obj
.ant_landscape
216 for i
in range(len(obi
)):
217 ant_props
.append(obi
[i
][1])
221 # Main function, create landscape mesh object
222 if ob
['sphere_mesh']:
224 verts
, faces
= sphere_gen(
233 new_ob
= create_mesh_object(context
, verts
, [], faces
, new_name
).object
234 if ob
['remove_double']:
236 bpy
.ops
.object.mode_set(mode
= 'EDIT')
237 bpy
.ops
.mesh
.remove_doubles(threshold
=0.0001, use_unselected
=False)
238 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
241 verts
, faces
= grid_gen(
251 new_ob
= create_mesh_object(context
, verts
, [], faces
, new_name
).object
255 if ob
['smooth_mesh']:
256 bpy
.ops
.object.shade_smooth()
259 if ob
['land_material'] != "" and ob
['land_material'] in bpy
.data
.materials
:
260 mat
= bpy
.data
.materials
[ob
['land_material']]
261 bpy
.context
.object.data
.materials
.append(mat
)
264 if ob
['water_plane']:
265 if ob
['sphere_mesh']:
267 verts
, faces
= sphere_gen(
276 wobj
= create_mesh_object(context
, verts
, [], faces
, new_name
+"_plane").object
277 if ob
['remove_double']:
279 bpy
.ops
.object.mode_set(mode
= 'EDIT')
280 bpy
.ops
.mesh
.remove_doubles(threshold
=0.0001, use_unselected
=False)
281 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
284 verts
, faces
= grid_gen(
294 wobj
= create_mesh_object(context
, verts
, [], faces
, new_name
+"_plane").object
298 if ob
['smooth_mesh']:
299 bpy
.ops
.object.shade_smooth()
302 if ob
['water_material'] != "" and ob
['water_material'] in bpy
.data
.materials
:
303 mat
= bpy
.data
.materials
[ob
['water_material']]
304 bpy
.context
.object.data
.materials
.append(mat
)
307 if ob
['water_plane']:
308 wobj
.location
= obj
.location
309 wobj
.rotation_euler
= obj
.rotation_euler
310 wobj
.scale
= obj
.scale
313 new_ob
.location
= obj
.location
314 new_ob
.rotation_euler
= obj
.rotation_euler
315 new_ob
.scale
= obj
.scale
318 new_ob
= store_properties(ob
, new_ob
)
321 new_ob
.select
= False
324 scene
.objects
.active
= obj
325 bpy
.ops
.object.delete(use_global
=False)
327 # Select landscape and make active
329 scene
.objects
.active
= new_ob
331 # restore pre operator undo state
332 context
.user_preferences
.edit
.use_global_undo
= undo
337 # ------------------------------------------------------------
338 # Z normal value to vertex group (Slope map)
339 class AntVgSlopeMap(bpy
.types
.Operator
):
340 bl_idname
= "mesh.ant_slope_map"
341 bl_label
= "Weight from Slope"
342 bl_description
= "A.N.T. Slope Map - z normal value to vertex group weight"
343 bl_options
= {'REGISTER', 'UNDO'}
345 z_method
= EnumProperty(
349 ('SLOPE_Z', "Z Slope", "Slope for planar mesh"),
350 ('SLOPE_XYZ', "Sphere Slope", "Slope for spherical mesh")
352 group_name
= StringProperty(
353 name
="Vertex Group Name:",
357 select_flat
= BoolProperty(
360 description
="Select vertices on flat surface"
362 select_range
= FloatProperty(
363 name
="Vert Select Range:",
367 description
="Increase to select more vertices on slopes"
371 def poll(cls
, context
):
373 return (ob
and ob
.type == 'MESH')
376 def invoke(self
, context
, event
):
377 wm
= context
.window_manager
378 return wm
.invoke_props_dialog(self
)
381 def execute(self
, context
):
382 message
= "Popup Values: %d, %f, %s, %s" % \
383 (self
.select_flat
, self
.select_range
, self
.group_name
, self
.z_method
)
384 self
.report({'INFO'}, message
)
386 bpy
.ops
.object.mode_set(mode
='OBJECT')
387 ob
= bpy
.context
.active_object
391 bpy
.ops
.object.mode_set(mode
='EDIT')
392 bpy
.ops
.mesh
.select_all(action
='DESELECT')
393 bpy
.context
.tool_settings
.mesh_select_mode
= [True, False, False]
394 bpy
.ops
.object.mode_set(mode
='OBJECT')
396 bpy
.ops
.object.vertex_group_add()
397 vg_normal
= ob
.vertex_groups
.active
399 for v
in ob
.data
.vertices
:
400 if self
.z_method
== 'SLOPE_XYZ':
401 zval
= (v
.co
.normalized() * v
.normal
.normalized()) * 2 - 1
405 vg_normal
.add([v
.index
], zval
, 'REPLACE')
408 if zval
>= (1.0 - self
.select_range
):
411 vg_normal
.name
= self
.group_name
413 bpy
.ops
.paint
.weight_paint_toggle()
417 # ------------------------------------------------------------
420 def draw_ant_refresh(self
, context
):
422 if self
.auto_refresh
is False:
424 elif self
.auto_refresh
is True:
426 row
= layout
.box().row()
429 split
.prop(self
, "auto_refresh", toggle
=True, icon_only
=True, icon
='AUTO')
430 split
.prop(self
, "refresh", toggle
=True, icon_only
=True, icon
='FILE_REFRESH')
433 def draw_ant_main(self
, context
, generate
=True):
436 box
.prop(self
, "show_main_settings", toggle
=True)
437 if self
.show_main_settings
:
439 row
= box
.row(align
=True)
440 split
= row
.split(align
=True)
441 split
.prop(self
, "at_cursor", toggle
=True, icon_only
=True, icon
='CURSOR')
442 split
.prop(self
, "smooth_mesh", toggle
=True, icon_only
=True, icon
='SOLID')
443 split
.prop(self
, "tri_face", toggle
=True, icon_only
=True, icon
='MESH_DATA')
445 if not self
.sphere_mesh
:
446 row
= box
.row(align
=True)
447 row
.prop(self
, "sphere_mesh", toggle
=True)
449 row
= box
.row(align
=True)
450 split
= row
.split(0.5, align
=True)
451 split
.prop(self
, "sphere_mesh", toggle
=True)
452 split
.prop(self
, "remove_double", toggle
=True)
454 box
.prop(self
, "ant_terrain_name")
455 box
.prop_search(self
, "land_material", bpy
.data
, "materials")
457 col
= box
.column(align
=True)
458 col
.prop(self
, "subdivision_x")
459 col
.prop(self
, "subdivision_y")
460 col
= box
.column(align
=True)
462 col
.prop(self
, "mesh_size")
464 col
.prop(self
, "mesh_size_x")
465 col
.prop(self
, "mesh_size_y")
468 def draw_ant_noise(self
, context
, generate
=True):
471 box
.prop(self
, "show_noise_settings", toggle
=True)
472 if self
.show_noise_settings
:
473 box
.prop(self
, "noise_type")
474 if self
.noise_type
== "blender_texture":
475 box
.prop_search(self
, "texture_block", bpy
.data
, "textures")
477 box
.prop(self
, "basis_type")
479 col
= box
.column(align
=True)
480 col
.prop(self
, "random_seed")
481 col
= box
.column(align
=True)
482 col
.prop(self
, "noise_offset_x")
483 col
.prop(self
, "noise_offset_y")
484 if self
.sphere_mesh
== True or generate
== False:
485 col
.prop(self
, "noise_offset_z")
486 col
.prop(self
, "noise_size_x")
487 col
.prop(self
, "noise_size_y")
488 if self
.sphere_mesh
== True or generate
== False:
489 col
.prop(self
, "noise_size_z")
491 col
= box
.column(align
=True)
492 col
.prop(self
, "noise_size")
494 col
= box
.column(align
=True)
495 if self
.noise_type
== "multi_fractal":
496 col
.prop(self
, "noise_depth")
497 col
.prop(self
, "dimension")
498 col
.prop(self
, "lacunarity")
499 elif self
.noise_type
== "ridged_multi_fractal":
500 col
.prop(self
, "noise_depth")
501 col
.prop(self
, "dimension")
502 col
.prop(self
, "lacunarity")
503 col
.prop(self
, "offset")
504 col
.prop(self
, "gain")
505 elif self
.noise_type
== "hybrid_multi_fractal":
506 col
.prop(self
, "noise_depth")
507 col
.prop(self
, "dimension")
508 col
.prop(self
, "lacunarity")
509 col
.prop(self
, "offset")
510 col
.prop(self
, "gain")
511 elif self
.noise_type
== "hetero_terrain":
512 col
.prop(self
, "noise_depth")
513 col
.prop(self
, "dimension")
514 col
.prop(self
, "lacunarity")
515 col
.prop(self
, "offset")
516 elif self
.noise_type
== "fractal":
517 col
.prop(self
, "noise_depth")
518 col
.prop(self
, "dimension")
519 col
.prop(self
, "lacunarity")
520 elif self
.noise_type
== "turbulence_vector":
521 col
.prop(self
, "noise_depth")
522 col
.prop(self
, "amplitude")
523 col
.prop(self
, "frequency")
525 row
= col
.row(align
=True)
526 row
.prop(self
, "hard_noise", expand
=True)
527 elif self
.noise_type
== "variable_lacunarity":
528 box
.prop(self
, "vl_basis_type")
529 box
.prop(self
, "distortion")
530 elif self
.noise_type
== "marble_noise":
531 box
.prop(self
, "marble_shape")
532 box
.prop(self
, "marble_bias")
533 box
.prop(self
, "marble_sharp")
534 col
= box
.column(align
=True)
535 col
.prop(self
, "distortion")
536 col
.prop(self
, "noise_depth")
538 row
= col
.row(align
=True)
539 row
.prop(self
, "hard_noise", expand
=True)
540 elif self
.noise_type
== "shattered_hterrain":
541 col
.prop(self
, "noise_depth")
542 col
.prop(self
, "dimension")
543 col
.prop(self
, "lacunarity")
544 col
.prop(self
, "offset")
545 col
.prop(self
, "distortion")
546 elif self
.noise_type
== "strata_hterrain":
547 col
.prop(self
, "noise_depth")
548 col
.prop(self
, "dimension")
549 col
.prop(self
, "lacunarity")
550 col
.prop(self
, "offset")
551 col
.prop(self
, "distortion", text
="Strata")
552 elif self
.noise_type
== "ant_turbulence":
553 col
.prop(self
, "noise_depth")
554 col
.prop(self
, "amplitude")
555 col
.prop(self
, "frequency")
556 col
.prop(self
, "distortion")
558 row
= col
.row(align
=True)
559 row
.prop(self
, "hard_noise", expand
=True)
560 elif self
.noise_type
== "vl_noise_turbulence":
561 col
.prop(self
, "noise_depth")
562 col
.prop(self
, "amplitude")
563 col
.prop(self
, "frequency")
564 col
.prop(self
, "distortion")
566 box
.prop(self
, "vl_basis_type")
568 row
= col
.row(align
=True)
569 row
.prop(self
, "hard_noise", expand
=True)
570 elif self
.noise_type
== "vl_hTerrain":
571 col
.prop(self
, "noise_depth")
572 col
.prop(self
, "dimension")
573 col
.prop(self
, "lacunarity")
574 col
.prop(self
, "offset")
575 col
.prop(self
, "distortion")
577 box
.prop(self
, "vl_basis_type")
578 elif self
.noise_type
== "distorted_heteroTerrain":
579 col
.prop(self
, "noise_depth")
580 col
.prop(self
, "dimension")
581 col
.prop(self
, "lacunarity")
582 col
.prop(self
, "offset")
583 col
.prop(self
, "distortion")
585 box
.prop(self
, "vl_basis_type")
586 elif self
.noise_type
== "double_multiFractal":
587 col
.prop(self
, "noise_depth")
588 col
.prop(self
, "dimension")
589 col
.prop(self
, "lacunarity")
590 col
.prop(self
, "offset")
591 col
.prop(self
, "gain")
593 box
.prop(self
, "vl_basis_type")
594 elif self
.noise_type
== "rocks_noise":
595 col
.prop(self
, "noise_depth")
596 col
.prop(self
, "distortion")
598 row
= col
.row(align
=True)
599 row
.prop(self
, "hard_noise", expand
=True)
600 elif self
.noise_type
== "slick_rock":
601 col
.prop(self
, "noise_depth")
602 col
.prop(self
, "dimension")
603 col
.prop(self
, "lacunarity")
604 col
.prop(self
, "gain")
605 col
.prop(self
, "offset")
606 col
.prop(self
, "distortion")
608 box
.prop(self
, "vl_basis_type")
609 elif self
.noise_type
== "planet_noise":
610 col
.prop(self
, "noise_depth")
612 row
= col
.row(align
=True)
613 row
.prop(self
, "hard_noise", expand
=True)
616 col
= box
.column(align
=False)
617 box
.prop(self
, "fx_type")
618 if self
.fx_type
!= "0":
619 if int(self
.fx_type
) <= 12:
620 box
.prop(self
, "fx_bias")
622 box
.prop(self
, "fx_mix_mode")
623 col
= box
.column(align
=True)
624 col
.prop(self
, "fx_mixfactor")
626 col
= box
.column(align
=True)
627 col
.prop(self
, "fx_loc_x")
628 col
.prop(self
, "fx_loc_y")
629 col
.prop(self
, "fx_size")
631 col
= box
.column(align
=True)
632 col
.prop(self
, "fx_depth")
633 if self
.fx_depth
!= 0:
634 col
.prop(self
, "fx_frequency")
635 col
.prop(self
, "fx_amplitude")
636 col
.prop(self
, "fx_turb")
638 col
= box
.column(align
=True)
639 row
= col
.row(align
=True).split(0.92, align
=True)
640 row
.prop(self
, "fx_height")
641 row
.prop(self
, "fx_invert", toggle
=True, text
="", icon
='ARROW_LEFTRIGHT')
642 col
.prop(self
, "fx_offset")
645 def draw_ant_displace(self
, context
, generate
=True):
648 box
.prop(self
, "show_displace_settings", toggle
=True)
649 if self
.show_displace_settings
:
651 col
= box
.column(align
=False)
652 col
.prop(self
, "direction", toggle
=True)
654 col
= box
.column(align
=True)
655 row
= col
.row(align
=True).split(0.92, align
=True)
656 row
.prop(self
, "height")
657 row
.prop(self
, "height_invert", toggle
=True, text
="", icon
='ARROW_LEFTRIGHT')
658 col
.prop(self
, "height_offset")
659 col
.prop(self
, "maximum")
660 col
.prop(self
, "minimum")
662 if not self
.sphere_mesh
:
664 col
.prop(self
, "edge_falloff")
665 if self
.edge_falloff
is not "0":
666 col
= box
.column(align
=True)
667 col
.prop(self
, "edge_level")
668 if self
.edge_falloff
in ["2", "3"]:
669 col
.prop(self
, "falloff_x")
670 if self
.edge_falloff
in ["1", "3"]:
671 col
.prop(self
, "falloff_y")
674 col
.prop(self
, "strata_type")
675 if self
.strata_type
is not "0":
677 col
.prop(self
, "strata")
680 col
= box
.column(align
=False)
681 col
.prop_search(self
, "vert_group", bpy
.context
.object, "vertex_groups")
684 def draw_ant_water(self
, context
):
688 col
.prop(self
, "water_plane", toggle
=True)
690 col
= box
.column(align
=True)
691 col
.prop_search(self
, "water_material", bpy
.data
, "materials")
693 col
.prop(self
, "water_level")
697 def store_properties(operator
, ob
):
698 ob
.ant_landscape
.ant_terrain_name
= operator
.ant_terrain_name
699 ob
.ant_landscape
.at_cursor
= operator
.at_cursor
700 ob
.ant_landscape
.smooth_mesh
= operator
.smooth_mesh
701 ob
.ant_landscape
.tri_face
= operator
.tri_face
702 ob
.ant_landscape
.sphere_mesh
= operator
.sphere_mesh
703 ob
.ant_landscape
.land_material
= operator
.land_material
704 ob
.ant_landscape
.water_material
= operator
.water_material
705 ob
.ant_landscape
.texture_block
= operator
.texture_block
706 ob
.ant_landscape
.subdivision_x
= operator
.subdivision_x
707 ob
.ant_landscape
.subdivision_y
= operator
.subdivision_y
708 ob
.ant_landscape
.mesh_size_x
= operator
.mesh_size_x
709 ob
.ant_landscape
.mesh_size_y
= operator
.mesh_size_y
710 ob
.ant_landscape
.mesh_size
= operator
.mesh_size
711 ob
.ant_landscape
.random_seed
= operator
.random_seed
712 ob
.ant_landscape
.noise_offset_x
= operator
.noise_offset_x
713 ob
.ant_landscape
.noise_offset_y
= operator
.noise_offset_y
714 ob
.ant_landscape
.noise_offset_z
= operator
.noise_offset_z
715 ob
.ant_landscape
.noise_size_x
= operator
.noise_size_x
716 ob
.ant_landscape
.noise_size_y
= operator
.noise_size_y
717 ob
.ant_landscape
.noise_size_z
= operator
.noise_size_z
718 ob
.ant_landscape
.noise_size
= operator
.noise_size
719 ob
.ant_landscape
.noise_type
= operator
.noise_type
720 ob
.ant_landscape
.basis_type
= operator
.basis_type
721 ob
.ant_landscape
.vl_basis_type
= operator
.vl_basis_type
722 ob
.ant_landscape
.distortion
= operator
.distortion
723 ob
.ant_landscape
.hard_noise
= operator
.hard_noise
724 ob
.ant_landscape
.noise_depth
= operator
.noise_depth
725 ob
.ant_landscape
.amplitude
= operator
.amplitude
726 ob
.ant_landscape
.frequency
= operator
.frequency
727 ob
.ant_landscape
.dimension
= operator
.dimension
728 ob
.ant_landscape
.lacunarity
= operator
.lacunarity
729 ob
.ant_landscape
.offset
= operator
.offset
730 ob
.ant_landscape
.gain
= operator
.gain
731 ob
.ant_landscape
.marble_bias
= operator
.marble_bias
732 ob
.ant_landscape
.marble_sharp
= operator
.marble_sharp
733 ob
.ant_landscape
.marble_shape
= operator
.marble_shape
734 ob
.ant_landscape
.height
= operator
.height
735 ob
.ant_landscape
.height_invert
= operator
.height_invert
736 ob
.ant_landscape
.height_offset
= operator
.height_offset
737 ob
.ant_landscape
.maximum
= operator
.maximum
738 ob
.ant_landscape
.minimum
= operator
.minimum
739 ob
.ant_landscape
.edge_falloff
= operator
.edge_falloff
740 ob
.ant_landscape
.edge_level
= operator
.edge_level
741 ob
.ant_landscape
.falloff_x
= operator
.falloff_x
742 ob
.ant_landscape
.falloff_y
= operator
.falloff_y
743 ob
.ant_landscape
.strata_type
= operator
.strata_type
744 ob
.ant_landscape
.strata
= operator
.strata
745 ob
.ant_landscape
.water_plane
= operator
.water_plane
746 ob
.ant_landscape
.water_level
= operator
.water_level
747 ob
.ant_landscape
.vert_group
= operator
.vert_group
748 ob
.ant_landscape
.remove_double
= operator
.remove_double
749 ob
.ant_landscape
.fx_mixfactor
= operator
.fx_mixfactor
750 ob
.ant_landscape
.fx_mix_mode
= operator
.fx_mix_mode
751 ob
.ant_landscape
.fx_type
= operator
.fx_type
752 ob
.ant_landscape
.fx_bias
= operator
.fx_bias
753 ob
.ant_landscape
.fx_turb
= operator
.fx_turb
754 ob
.ant_landscape
.fx_depth
= operator
.fx_depth
755 ob
.ant_landscape
.fx_frequency
= operator
.fx_frequency
756 ob
.ant_landscape
.fx_amplitude
= operator
.fx_amplitude
757 ob
.ant_landscape
.fx_size
= operator
.fx_size
758 ob
.ant_landscape
.fx_loc_x
= operator
.fx_loc_x
759 ob
.ant_landscape
.fx_loc_y
= operator
.fx_loc_y
760 ob
.ant_landscape
.fx_height
= operator
.fx_height
761 ob
.ant_landscape
.fx_offset
= operator
.fx_offset
762 ob
.ant_landscape
.fx_invert
= operator
.fx_invert
766 # ------------------------------------------------------------
768 # "author": "Michel Anders, Ian Huish"
770 from random
import random
as rand
771 from math
import tan
, radians
772 from .eroder
import Grid
773 from .stats
import Stats
774 from .utils
import numexpr_available
777 def availableVertexGroupsOrNone(self
, context
):
778 groups
= [ ('None', 'None', 'None', 1) ]
779 return groups
+ [(name
, name
, name
, n
+1) for n
,name
in enumerate(context
.active_object
.vertex_groups
.keys())]
782 class Eroder(bpy
.types
.Operator
):
783 bl_idname
= "mesh.eroder"
784 bl_label
= "ErosionR"
785 bl_description
= "Apply various kinds of erosion to a square ANT-Landscape grid. Also available in Weight Paint mode > Weights menu"
786 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
788 Iterations
= IntProperty(
790 description
="Number of overall iterations",
795 IterRiver
= IntProperty(
796 name
="River Iterations",
797 description
="Number of river iterations",
802 IterAva
= IntProperty(
803 name
="Avalanche Iterations",
804 description
="Number of avalanche iterations",
809 IterDiffuse
= IntProperty(
810 name
="Diffuse Iterations",
811 description
="Number of diffuse iterations",
817 name
="Rain on Plains",
818 description
="1 gives equal rain across the terrain, 0 rains more at the mountain tops",
825 description
="Thermal diffusion rate (1.0 is a fairly high rate)",
832 description
="Maximum stable talus angle",
840 description
="Total Rain amount",
847 name
="Rain variance",
848 description
="Rain variance (0 is constant, 1 is uniform)",
853 userainmap
= BoolProperty(
855 description
="Use active vertex group as a rain map",
859 name
="Soil solubility",
860 description
="Soil solubility - how quickly water quickly reaches saturation point",
865 Kdep
= FloatProperty(
866 name
="Deposition rate",
867 description
="Sediment deposition rate - how quickly silt is laid down once water stops flowing quickly",
872 Kz
= FloatProperty(name
="Fluvial Erosion Rate",
873 description
="Amount of sediment moved each main iteration - if 0, then rivers are formed but the mesh is not changed",
879 name
="Carrying capacity",
880 description
="Base sediment carrying capacity",
886 name
="Slope dependence",
887 description
="Slope dependence of carrying capacity (not used)",
894 description
="Evaporation Rate per grid square in % - causes sediment to be dropped closer to the hills",
899 numexpr
= BoolProperty(
901 description
="Use numexpr module (if available)",
905 name
="Diffusion Amount",
906 description
="Diffusion probability",
912 name
="Avalanche Amount",
913 description
="Avalanche amount",
920 description
="Water erosion probability",
925 smooth
= BoolProperty(
927 description
="Set smooth shading",
930 showiterstats
= BoolProperty(
931 name
="Iteration Stats",
932 description
="Show iteraration statistics",
935 showmeshstats
= BoolProperty(name
="Mesh Stats",
936 description
="Show mesh statistics",
943 def execute(self
, context
):
945 ob
= context
.active_object
949 vgActive
= ob
.vertex_groups
.active
.name
951 vgActive
= "capacity"
952 print("ActiveGroup", vgActive
)
954 vg
=ob
.vertex_groups
["rainmap"]
956 vg
=ob
.vertex_groups
.new("rainmap")
958 vgscree
=ob
.vertex_groups
["scree"]
960 vgscree
=ob
.vertex_groups
.new("scree")
962 vgavalanced
=ob
.vertex_groups
["avalanced"]
964 vgavalanced
=ob
.vertex_groups
.new("avalanced")
966 vgw
=ob
.vertex_groups
["water"]
968 vgw
=ob
.vertex_groups
.new("water")
970 vgscour
=ob
.vertex_groups
["scour"]
972 vgscour
=ob
.vertex_groups
.new("scour")
974 vgdeposit
=ob
.vertex_groups
["deposit"]
976 vgdeposit
=ob
.vertex_groups
.new("deposit")
978 vgflowrate
=ob
.vertex_groups
["flowrate"]
980 vgflowrate
=ob
.vertex_groups
.new("flowrate")
982 vgsediment
=ob
.vertex_groups
["sediment"]
984 vgsediment
=ob
.vertex_groups
.new("sediment")
986 vgsedimentpct
=ob
.vertex_groups
["sedimentpct"]
988 vgsedimentpct
=ob
.vertex_groups
.new("sedimentpct")
990 vgcapacity
=ob
.vertex_groups
["capacity"]
992 vgcapacity
=ob
.vertex_groups
.new("capacity")
994 g
= Grid
.fromBlenderMesh(me
, vg
, self
.Ef
)
996 me
= bpy
.data
.meshes
.new(me
.name
)
998 self
.counts
['diffuse'] = 0
999 self
.counts
['avalanche'] = 0
1000 self
.counts
['water'] = 0
1001 for i
in range(self
.Iterations
):
1002 if self
.IterRiver
> 0:
1003 for i
in range(self
.IterRiver
):
1004 g
.rivergeneration(self
.Kr
, self
.Kv
, self
.userainmap
, self
.Kc
, self
.Ks
, self
.Kdep
, self
.Ka
, self
.Kev
/100, 0,0,0,0, self
.numexpr
)
1007 for k
in range(self
.IterDiffuse
):
1008 g
.diffuse(self
.Kd
/ 5, self
.IterDiffuse
, self
.numexpr
)
1009 self
.counts
['diffuse']+=1
1011 if self
.Kt
< radians(90) and self
.Pa
> 0:
1012 for k
in range(self
.IterAva
):
1013 # since dx and dy are scaled to 1, tan(Kt) is the height for a given angle
1014 g
.avalanche(tan(self
.Kt
), self
.IterAva
, self
.Pa
, self
.numexpr
)
1015 self
.counts
['avalanche']+=1
1017 g
.fluvial_erosion(self
.Kr
, self
.Kv
, self
.userainmap
, self
.Kc
, self
.Ks
, self
.Kz
*50, self
.Ka
, 0,0,0,0, self
.numexpr
)
1018 self
.counts
['water']+=1
1024 for row
in range(g
.rainmap
.shape
[0]):
1025 for col
in range(g
.rainmap
.shape
[1]):
1026 i
= row
* g
.rainmap
.shape
[1] + col
1027 vg
.add([i
],g
.rainmap
[row
,col
],'ADD')
1029 for row
in range(g
.rainmap
.shape
[0]):
1030 for col
in range(g
.rainmap
.shape
[1]):
1031 i
= row
* g
.rainmap
.shape
[1] + col
1032 vgscree
.add([i
],g
.avalanced
[row
,col
],'ADD')
1034 for row
in range(g
.rainmap
.shape
[0]):
1035 for col
in range(g
.rainmap
.shape
[1]):
1036 i
= row
* g
.rainmap
.shape
[1] + col
1037 vgavalanced
.add([i
],-g
.avalanced
[row
,col
],'ADD')
1039 for row
in range(g
.rainmap
.shape
[0]):
1040 for col
in range(g
.rainmap
.shape
[1]):
1041 i
= row
* g
.rainmap
.shape
[1] + col
1042 vgw
.add([i
],g
.water
[row
,col
]/g
.watermax
,'ADD')
1044 for row
in range(g
.rainmap
.shape
[0]):
1045 for col
in range(g
.rainmap
.shape
[1]):
1046 i
= row
* g
.rainmap
.shape
[1] + col
1047 vgscour
.add([i
],g
.scour
[row
,col
]/max(g
.scourmax
, -g
.scourmin
),'ADD')
1049 for row
in range(g
.rainmap
.shape
[0]):
1050 for col
in range(g
.rainmap
.shape
[1]):
1051 i
= row
* g
.rainmap
.shape
[1] + col
1052 vgdeposit
.add([i
],g
.scour
[row
,col
]/min(-g
.scourmax
, g
.scourmin
),'ADD')
1054 for row
in range(g
.rainmap
.shape
[0]):
1055 for col
in range(g
.rainmap
.shape
[1]):
1056 i
= row
* g
.rainmap
.shape
[1] + col
1057 vgflowrate
.add([i
],g
.flowrate
[row
,col
],'ADD')
1059 for row
in range(g
.rainmap
.shape
[0]):
1060 for col
in range(g
.rainmap
.shape
[1]):
1061 i
= row
* g
.rainmap
.shape
[1] + col
1062 vgsediment
.add([i
],g
.sediment
[row
,col
],'ADD')
1064 for row
in range(g
.rainmap
.shape
[0]):
1065 for col
in range(g
.rainmap
.shape
[1]):
1066 i
= row
* g
.rainmap
.shape
[1] + col
1067 vgsedimentpct
.add([i
],g
.sedimentpct
[row
,col
],'ADD')
1069 for row
in range(g
.rainmap
.shape
[0]):
1070 for col
in range(g
.rainmap
.shape
[1]):
1071 i
= row
* g
.rainmap
.shape
[1] + col
1072 vgcapacity
.add([i
],g
.capacity
[row
,col
],'ADD')
1074 vg
= ob
.vertex_groups
["vgActive"]
1077 ob
.vertex_groups
.active
= vg
1080 bpy
.ops
.object.shade_smooth()
1083 if self
.showmeshstats
:
1084 self
.stats
.meshstats
= g
.analyze()
1089 def draw(self
,context
):
1090 layout
= self
.layout
1092 layout
.operator('screen.repeat_last', text
="Repeat", icon
='FILE_REFRESH' )
1094 layout
.prop(self
, 'Iterations')
1097 col
= box
.column(align
=True)
1098 col
.label("Thermal (Diffusion)")
1099 col
.prop(self
, 'Kd')
1100 col
.prop(self
, 'IterDiffuse')
1103 col
= box
.column(align
=True)
1104 col
.label("Avalanche (Talus)")
1105 col
.prop(self
, 'Pa')
1106 col
.prop(self
, 'IterAva')
1107 col
.prop(self
, 'Kt')
1110 col
= box
.column(align
=True)
1111 col
.label("River erosion")
1112 col
.prop(self
, 'IterRiver')
1113 col
.prop(self
, 'Kz')
1114 col
.prop(self
, 'Ks')
1115 col
.prop(self
, 'Kc')
1116 col
.prop(self
, 'Kdep')
1117 col
.prop(self
, 'Kr')
1118 col
.prop(self
, 'Kv')
1119 col
.prop(self
, 'Kev')
1121 col
.prop(self
, 'Ef')
1123 layout
.prop(self
,'smooth')