Skip to content

Commit

Permalink
Merge branch 'storage-optimization-merge'
Browse files Browse the repository at this point in the history
  • Loading branch information
dreadpon committed Dec 18, 2022
2 parents 05b9b00 + 9fb955f commit 1469998
Show file tree
Hide file tree
Showing 38 changed files with 3,260 additions and 54,587 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,4 +1,5 @@
*.backup
default_env.tres

# Godot 4+ specific ignores
.godot/
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

<br/><br/>

## [v1.2.0](https://github.com/dreadpon/godot_spatial_gardener/releases/tag/v1.2.0) - 2022-12-18

### Changed

#### Gardener
- Optimize Gardener storage to use less space in a .tscn file (up to 50% less) (suggested by [@rick551a](https://github.com/rick551a))
- This change breaks compatability with previous versions. Refer [here](reference/TUTORIAL_SCENE_CONVERSION.md) for a conversion guide

<br/><br/>

## [v1.1.1](https://github.com/dreadpon/godot_spatial_gardener/releases/tag/v1.1.1) - 2022-12-13
### Added

Expand Down
50 changes: 26 additions & 24 deletions addons/dreadpon.spatial_gardener/arborist/arborist.gd
Expand Up @@ -30,7 +30,6 @@ const SH_Single = preload("stroke_handler/sh_single.gd")
const SH_Reapply = preload("stroke_handler/sh_reapply.gd")
const SH_Manual = preload("stroke_handler/sh_manual.gd")


var MMI_container:Spatial = null
var octree_managers:Array

Expand Down Expand Up @@ -76,16 +75,18 @@ func _init():


func _ready():
#print(self)

# see https://github.com/godotengine/godot/issues/16478
# Workaround below fixes the problem of instanced nodes "sharing" exported arrays (and resources inside them)
# When instanced in the editor
# See https://github.com/godotengine/godot/issues/16478
# This fix is needed, so we can have multiple instances of same terrain with same plant placement
# But have LOD switch independently for each of these terrains
if octree_managers == null:
octree_managers = []
else:
var octree_managers_copy = octree_managers.duplicate()
octree_managers = []
for octree_manager in octree_managers_copy:
octree_managers.append(octree_manager.deep_copy())
octree_managers.append(octree_manager.duplicate_tree())


logger = Logger.get_for(self, name)
Expand Down Expand Up @@ -394,11 +395,11 @@ func apply_stroke_update_changes(changes:PaintingChanges):

match change.change_type:
0:
octree_manager.queue_members_add(change.new_val)
octree_manager.queue_placeforms_add(change.new_val)
1:
octree_manager.queue_members_remove(change.new_val)
octree_manager.queue_placeforms_remove(change.new_val)
2:
octree_manager.queue_members_set(change.new_val)
octree_manager.queue_placeforms_set(change.new_val)

if !affected_octree_managers.has(change.at_index):
affected_octree_managers.append(change.at_index)
Expand All @@ -413,7 +414,7 @@ func apply_stroke_update_changes(changes:PaintingChanges):


func emit_member_count(octree_index:int):
emit_signal("member_count_updated", octree_index, octree_managers[octree_index].root_octree_node.get_member_count())
emit_signal("member_count_updated", octree_index, octree_managers[octree_index].root_octree_node.get_nested_member_count())


func _process(delta):
Expand Down Expand Up @@ -477,20 +478,20 @@ func import_instance_transforms(file_path: String, plant_idx: int):
var json_result = JSON.parse(file.get_as_text())
if json_result.error != OK:
logger.error("Could not parse json at '%s', error %s!" % [file_path, Globals.get_err_message(json_result.error)])
var placement_transform_dicts = json_result.result
var placeform_dicts = json_result.result
file.close()

active_painting_changes = PaintingChanges.new()
active_stroke_handler = SH_Manual.new()

for placement_transform_dict in placement_transform_dicts:
for placeform_dict in placeform_dicts:
active_stroke_handler.add_instance(
FunLib.str_to_vec3(placement_transform_dict.placement), FunLib.str_to_vec3(placement_transform_dict.surface_normal),
FunLib.str_to_transform(placement_transform_dict.transform), plant_idx, active_painting_changes)
FunLib.str_to_vec3(placeform_dict.placement), FunLib.str_to_vec3(placeform_dict.surface_normal),
FunLib.str_to_transform(placeform_dict.transform), plant_idx, active_painting_changes)

apply_stroke_update_changes(active_painting_changes)
on_stroke_finished()
logger.info("Successfully imported %d PlacementTransforms from '%s' to index %d" % [placement_transform_dicts.size(), file_path, plant_idx])
logger.info("Successfully imported %d Placeform(s) from '%s' to index %d" % [placeform_dicts.size(), file_path, plant_idx])


func export_instance_transforms(file_path: String, plant_idx: int):
Expand All @@ -500,20 +501,21 @@ func export_instance_transforms(file_path: String, plant_idx: int):
if err != OK:
logger.error("Could not export '%s', error %s!" % [file_path, Globals.get_err_message(err)])

var members: Array = octree_managers[plant_idx].get_all_members()
var placement_transform_dicts := []
for member in members:
placement_transform_dicts.append({
'placement': member.placement,
'surface_normal': member.surface_normal,
'transform': member.transform,
'octree_octant': member.octree_octant,
var placeforms: Array = []
octree_managers[plant_idx].get_all_placeforms(placeforms)
var placeform_dicts := []
for placeform in placeforms:
placeform_dicts.append({
'placement': placeform[0],
'surface_normal': placeform[1],
'transform': placeform[2],
'octree_octant': placeform[3],
})

var json_string = JSON.print(placement_transform_dicts)
var json_string = JSON.print(placeform_dicts)
file.store_string(json_string)
file.close()
logger.info("Successfully exported %d PlacementTransforms to '%s' at index %d" % [placement_transform_dicts.size(), file_path, plant_idx])
logger.info("Successfully exported %d Placeform(s) to '%s' at index %d" % [placeform_dicts.size(), file_path, plant_idx])



Expand Down
40 changes: 20 additions & 20 deletions addons/dreadpon.spatial_gardener/arborist/brush_placement_area.gd
Expand Up @@ -72,8 +72,8 @@ var placement_grid:Array = []
var diagonal_dilation:float = 1.0

var placement_overlaps:Array = []
var overlapped_octree_members:Array = []
var overdense_octree_members:Array = []
var overlapped_member_data:Array = []
var overdense_member_data:Array = []

var raycast_positions:Array = []
var max_placements_allowed:int = 0
Expand Down Expand Up @@ -184,55 +184,55 @@ func init_placement_grid():
# And happen to be outside our sphere_radius, but still belong to overlapped grid cells
func init_placement_overlaps(octree_manager:MMIOctreeManager, edge_extension:int = 0):
placement_overlaps = []
overlapped_octree_members = []
overlapped_member_data = []

var max_dist = sphere_radius + point_distance * edge_extension
get_overlap_members(octree_manager.root_octree_node, max_dist)
get_overlap_member_data(octree_manager.root_octree_node, max_dist)


# Recursively calculate placement overlaps in an octree
func get_overlap_members(octree_node:MMIOctreeNode, max_dist:float):
func get_overlap_member_data(octree_node:MMIOctreeNode, max_dist:float):
var max_bounds_to_center_dist = octree_node.max_bounds_to_center_dist
var dist_node := clamp((octree_node.center_pos - sphere_pos).length() - max_bounds_to_center_dist - sphere_radius, 0.0, INF)
if dist_node >= max_dist: return

if !octree_node.is_leaf:
for child_node in octree_node.child_nodes:
get_overlap_members(child_node, max_dist)
get_overlap_member_data(child_node, max_dist)
else:
var max_dist_squared = pow(max_dist, 2.0)
var node_address = octree_node.get_address()
for member_index in range(0, octree_node.members.size()):
var member = octree_node.members[member_index]
var placement = member.placement - sphere_pos
for member_idx in range(0, octree_node.member_count()):
var placeform = octree_node.get_placeform(member_idx)
var placement = placeform[0] - sphere_pos
var dist_squared = placement.length_squared()
if dist_squared <= max_dist_squared:
placement_overlaps.append(placement)
overlapped_octree_members.append({"node_address": node_address, "member_index": member_index})
overlapped_member_data.append({"node_address": node_address, "member_idx": member_idx})


# Get all overlaps that don't fit into the density grid
func get_members_for_deletion():
if overdense_octree_members.size() <= 0: return []
func get_placeforms_for_deletion():
if overdense_member_data.size() <= 0: return []

var members_for_deletion := []
var placeforms_for_deletion := []
# Don't delete more than is exessive or actually overdense
var deletion_count := min(overlapped_octree_members.size() - max_placements_allowed, overdense_octree_members.size())
var deletion_increment := float(deletion_count) / float(overdense_octree_members.size())
var deletion_count := min(overlapped_member_data.size() - max_placements_allowed, overdense_member_data.size())
var deletion_increment := float(deletion_count) / float(overdense_member_data.size())
var deletion_progress := 0.0

if deletion_increment <= 0: return []

# # This part picks every [N]th member for deletion
# # [N] is defined by deletion_increment and can be fractional
# # E.g. we can delete an approximation of every 0.3th, 0.75th, etc. element
for index in range(0, overdense_octree_members.size()):
for index in range(0, overdense_member_data.size()):
deletion_progress += deletion_increment
if deletion_progress >= 1.0:
deletion_progress -= 1.0
members_for_deletion.append(overdense_octree_members[index])
placeforms_for_deletion.append(overdense_member_data[index])

return members_for_deletion
return placeforms_for_deletion


# Mark grid coordinates as invalid if they are already occupied
Expand All @@ -248,7 +248,7 @@ func invalidate_occupied_points():
if placement_grid.size() > 0 && placement_grid[grid_coord.x][grid_coord.y]:
invalidate_self_or_neighbor(grid_coord)
else:
overdense_octree_members.append(overlapped_octree_members[placement_index])
overdense_member_data.append(overlapped_member_data[placement_index])



Expand Down Expand Up @@ -309,7 +309,7 @@ func generate_raycast_positions():

# Compensating a floating point error by padding the value a bit
if centered_UV.length_squared() > 0.999:
centered_UV = centered_UV.clamped(0.999)
centered_UV = centered_UV.limit_length(0.999)

var UV_distance_to_surface:Vector3 = sqrt(1.0 - (pow(centered_UV.x, 2) + pow(centered_UV.y, 2))) * plane_axis_vectors[0]
var UV_point_on_plane:Vector3 = centered_UV.x * plane_axis_vectors[1] + centered_UV.y * plane_axis_vectors[2]
Expand Down

0 comments on commit 1469998

Please sign in to comment.