Skip to content

Commit

Permalink
Merge pull request #89 from UCL/ruaridhg-patch-1
Browse files Browse the repository at this point in the history
Update README.md
  • Loading branch information
ruaridhg authored Oct 20, 2023
2 parents 884f596 + 791f8fa commit aff9ba0
Show file tree
Hide file tree
Showing 8 changed files with 415 additions and 88 deletions.
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Blender Randomiser is a Blender add-on that allows different scene properties to
## Purpose

The add-on was originally developed to render a highly diverse and (near) photo-realistic synthetic dataset of laparoscopic surgery camera views. To replicate the different camera positions used in surgery as well as the shape and appearance of the tissues involved with surgery, we focused on three main components to randomise:
- **Camera transforms** (location and Euler rotation with toggle for randomising in absolute or relative i.e. delta terms)
- **Camera transforms** (location and Euler rotation with toggle for randomising in absolute or relative i.e. delta terms) ![camera_transforms](/docs/images/Transforms_panel.png)
- **Geometry** ([see further details](/docs/Materials_geometry_panel.md))
- **Materials**([see further details](/docs/Materials_geometry_panel.md))

Expand All @@ -22,6 +22,9 @@ In the add-on, these three components appear as separate UI panels.
- Capability to randomise the desired properties at every frame of an animation
- [Save Parameter panel](/docs/input_output.md) with outputs saved to `.json` [file](/output_randomisations_per_frame1697116725.310647.json) with a timestamp

The add-on panel called "Randomiser" is located in the Geometry Nodes tab on Blender:
![Addon_location](/docs/images/Addon_location.png)


## Installation via command line
1. First, clone the repository in your desired directory
Expand All @@ -37,6 +40,9 @@ git clone https://github.com/UCL/Blender_Randomiser.git
- This will zip the `randomiser` subdirectory, open the `sample.blend` file with Blender, and use Blender's Python interpreter to execute the `install_and_enable_addons.py` script.
- The `install_and_enable_addons.py` script installs and enables any add-ons that are passed as command line arguments (add-ons can be passed as a path to a single Python file, or as a zip file)

> [!NOTE] `source ~/.bash_profile` is used in the bash script to create an alias for blender with the following line in the bash_profile:
> `alias blender=/Applications/Blender.app/Contents/MacOS/Blender`
> **Advanced Usage**
> In step 3, run the [randomisation_seed.sh](/randomisation_seed.sh) bash script instead which has optional inputs:
> - `--seed 32` which is an input to Blender
Expand Down Expand Up @@ -78,3 +84,24 @@ Alternatively, install [manually](/docs/Install_addon_manually.md) via Blender s
## Contributions

Please see [Dev Notes](./docs/Dev_notes.md) if you wish to contribute. Feel free to submit suggestions via issues and/or PRs.

It can be helpful to use different `.blend` files for prototyping as it can preload certain features you're testing.

There are a few outstanding issues for enhancements:
- Not able to currently export materials colour default value for save params button
- Materials colour min-max can only be set to the same values in the 4D matrix using the [input file](/input_bounds.json)
- No functionality for reading in min-max input boundaries for user defined panel
- Not able to currently handle an empty UIlist in the user defined panel which causes issues for other funtionality in the add-on (which are resolved by adding at least one UD prop to UIlist)
- Can randomise all panels and save the output parameters, however the functionality to toggle on/off selection of individual parameters is only available for camera transforms and user defined properties currently, but not geometry and materials panels where all these properties will be randomised and exported when this functionality is used.
- General refactoring for repeated code for example [for the geometry and materials issue mentioned above](/randomiser/utils/list_props_to_randomise.py)


## Authors

[Tom Dowrick](https://github.com/tdowrick)

[Ruaridh Gollifer](https://github.com/ruaridhg)

[Sofía Miñano](https://github.com/sfmig)

[Harvey Mannering](https://github.com/harveymannering)
15 changes: 14 additions & 1 deletion docs/Materials_geometry_panel.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## Materials
![Materials_panel](/docs/images/Materials_panel.png)
- A panel to randomise properties relative to the material nodes:
- nodes and node groups are aggregated based on the material they belong to.
- only materials with use_nodes=True are added to the panel. By default, use_nodes is set to True, but this is a convenient way to add/remove materials from the panel.
Expand All @@ -10,12 +11,24 @@
Clicking the name of the material in a subpanel header shows its node graph. If a material is clicked and it has no slot assigned, a new slot will be created for it



## Geometry
![Geometry_panel](/docs/images/Geometry_panel.png)

- A panel to randomise properties relative to the geometry nodes:
- nodes are aggregated based on the node group they belong to.
- Same functionalities as in material nodes panel: new or deleted nodes are automatically added, recursive node groups are accepted,etc.


An example of a cube object:
![Geometry_cube_example](/docs/images/Geometry_cube_example.png)

An example of a sphere object with recursive node groups:
![Geometry_sphere_recursive_example](/docs/images/Geometry_SPHERE_node_group_within_node_group.png)

>[!NOTE]
> Only the geometry linked to the current active selective object is visible via the node graph view
### When is a new modifier automatically added to an object’s geometry?
If a geometry node group is not inside another node group, and is not linked to a modifier of the currently active object, a new modifier is created and the geometry node group is linked to it.

This example panel set-up for geometry and materials can produce an [output_file](/output_randomisations_per_frame1697817956.010714_mat_geom_example.json)
6 changes: 6 additions & 0 deletions docs/user_defined_panel.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## User Defined Properties Panel

![UD_props_panel](/docs/images/UD_panel.png)

This example panel set-up can produce an [output_file](/output_randomisations_per_frame1697817657.502794_UD_example.json)

Some examples of useful user-defined properties could be:
- bpy.data.objects["Cube"].location (Float 3D)
- bpy.context.scene.frame_current (int 1D)
Expand Down
2 changes: 1 addition & 1 deletion randomisation_seed.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ source ~/.bash_profile

# zip randomiser, launch blender and install+enable, set seed and input bounds
zip randomiser.zip -FS -r randomiser/
blender random_all.blend --python install_and_enable_addons.py -- ./randomiser.zip --seed 32 --input ./input_bounds.json --output ./output_randomisations_per_frame1697116725.310647.json
blender sample.blend --python install_and_enable_addons.py -- ./randomiser.zip --seed 32 --input ./input_bounds.json --output ./output_randomisations_per_frame1697116725.310647.json
10 changes: 5 additions & 5 deletions randomiser/define_prop/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ def attr_set_val(obj, path, min_val, max_val, UD_type):
# print("Property does not exist")
pass

print("obj = ", path_attr)
# print("obj = ", path_attr)
if UD_type == float:
value = random.uniform(min_val, max_val)
print("1D float = ", value)
# print("1D float = ", value)
elif UD_type == Vector:
value = random.uniform(min_val, max_val)
print("3D Vector float = ", value)
# print("3D Vector float = ", value)
elif UD_type == Euler:
deg2rad = np.pi / 180
value = random.uniform(min_val, max_val)
value = value * deg2rad
print("Euler = ", value)
# print("Euler = ", value)
else:
value = random.randint(min_val, max_val)
print("Integer = ", value)
# print("Integer = ", value)

setattr(prop, path_attr, value)

Expand Down
97 changes: 49 additions & 48 deletions randomiser/define_prop/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ def get_attr_only_str(full_str):
len_path = len(full_str.rsplit(".", config.MAX_NUMBER_OF_SUBPANELS)) - mod
list_parent_nodes_str = full_str.rsplit(".", len_path - 3)
attribute_only_str = full_str.replace(list_parent_nodes_str[0] + ".", "")

return attribute_only_str


Expand Down Expand Up @@ -395,13 +394,13 @@ def poll(cls, context):
if "Camera" in current_obj:
action = attr_get_type(
bpy.data.cameras[idx],
get_attr_only_str(attribute_only_str),
attribute_only_str,
)[1]

else:
action = attr_get_type(
bpy.data.objects[idx],
get_attr_only_str(attribute_only_str),
attribute_only_str,
)[1]

elif "bpy.context.scene" in full_str:
Expand Down Expand Up @@ -455,51 +454,53 @@ def draw(self, context):
full_str = sockets_props_collection.name
attribute_only_str = get_attr_only_str(full_str)

list_all_UD_props = []
for UD_str in bpy.context.scene.custom:
objects_in_scene = []
for key in bpy.data.objects:
objects_in_scene.append(key.name)

if "[" in UD_str.name:
obj_str = get_obj_str(UD_str.name)

for i, obj in enumerate(objects_in_scene):
if obj in obj_str:
current_obj = obj
idx = i

if "Camera" in current_obj:
if (
attr_get_type(
bpy.data.cameras[idx],
get_attr_only_str(UD_str.name),
)[1]
!= "dummy"
):
list_all_UD_props.append(UD_str)

else:
if (
attr_get_type(
bpy.data.objects[idx],
get_attr_only_str(UD_str.name),
)[1]
!= "dummy"
):
list_all_UD_props.append(UD_str)

elif (
attr_get_type(
bpy.context.scene, get_attr_only_str(UD_str.name)
)[1]
!= "dummy"
):
list_all_UD_props.append(UD_str)

list_current_UD_props = list_all_UD_props[
bpy.context.scene.custom_index
].name
# list_all_UD_props = []
# for UD_str in bpy.context.scene.custom:
# objects_in_scene = []
# for key in bpy.data.objects:
# objects_in_scene.append(key.name)

# if "[" in UD_str.name:
# obj_str = get_obj_str(UD_str.name)

# for i, obj in enumerate(objects_in_scene):
# if obj in obj_str:
# current_obj = obj
# idx = i

# if "Camera" in current_obj:
# if (
# attr_get_type(
# bpy.data.cameras[idx],
# get_attr_only_str(UD_str.name),
# )[1]
# != "dummy"
# ):
# list_all_UD_props.append(UD_str)

# else:
# if (
# attr_get_type(
# bpy.data.objects[idx],
# get_attr_only_str(UD_str.name),
# )[1]
# != "dummy"
# ):
# list_all_UD_props.append(UD_str)

# elif (
# attr_get_type(
# bpy.context.scene, get_attr_only_str(UD_str.name)
# )[1]
# != "dummy"
# ):
# list_all_UD_props.append(UD_str)

# list_current_UD_props = list_all_UD_props[
# bpy.context.scene.custom_index
# ].name

list_current_UD_props = sockets_props_collection.name

# Draw UD props to randomise including their
# min/max boundaries
Expand Down
Loading

0 comments on commit aff9ba0

Please sign in to comment.