Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update object degradation tutorial; rename fouling_rating to distort_extent #185

Merged
merged 4 commits into from
Feb 16, 2022

Conversation

mabelzhang
Copy link
Contributor

I tagged @j-herman (because you've run this in the past) or @woensug-choi (because you're looking into this now) for review. Only one is needed.

  • Update object degradation tutorial to include 1. how to add more degradation methods to the Blender Python script, and 2. how to add more custom SDF tags.
    The current SDF tags are just dummy examples. @woensug-choi if you find more suitable terminology, feel free to update the example - remember to also update the Gazebo C++ plugin, see README section "To add new custom tags". Alternatively, just use whatever you like in the multibeam sonar plugin and the SDF it loads.
  • Rename fouling_rating variable in range [0, 100] to distort_extent, now in range [0, 1]. This follows the discussion that we don't care about actually adhering to the navy fouling scale. It's now just an arbitrary relative scale.

To test

Follow the mesh README to run the mesh modification script in Blender 2.92 and make sure it still works after the variable name change.

…gs. Rename fouling_rating in [0, 100] in mesh distortion to distort_extent in [0, 1].

Signed-off-by: Mabel Zhang <mabel@openrobotics.org>
@woensug-choi
Copy link
Collaborator

Is it correct that the current subdivision level from 0~4 is the number of operations to divide an edge into two with a mid vertex?

Are there methods we can define the density of the random vertexes generated by subdivision? Something like max edge lengths? (Still discussing what we need. No need to include in this PR :))

@mabelzhang
Copy link
Contributor Author

divide an edge into two with a mid vertex?

I played with it a bit on a cylinder and a cube, and it does look like what you described.

Blender's official description doesn't say too much about the mathematical operation. "The Subdivision Surface modifier (often shorten to “Subdiv”) is used to split the faces of a mesh into smaller faces, giving it a smooth appearance." For the "Simple" mode, which is the current mode in the script, it "Only subdivides the surfaces, without any smoothing."

For a cylinder, the top/bottom cap looks like this:

level 0
2022-01-31-185155_3706x2049_scrot_cylinderSubdiv0

level 1
2022-01-31-185150_3706x2049_scrot_cubeSubdiv1

level 2
2022-01-31-185146_3706x2049_scrot_cylinderSubdiv2
2022-01-31-184413_3706x2049_scrot_cylinderSubdiv2

@mabelzhang
Copy link
Contributor Author

mabelzhang commented Feb 1, 2022

density of the random vertexes generated by subdivision? Something like max edge lengths?

Hmm there might be a way to script that, although I don't know if edge length can be a parameter to easily control.
The Subdiv modifier doesn't seem to expose such a parameter. There might be a different way to do it.

References:
Subdiv modifier has these options: https://docs.blender.org/api/current/bpy.types.SubsurfModifier.html
The "Simple" mode we're using in the Subdivision modifier, Blender says is equivalent to the mesh operation Subdivide, which has these options https://docs.blender.org/api/current/bpy.ops.mesh.html#bpy.ops.mesh.subdivide

@mabelzhang
Copy link
Contributor Author

mabelzhang commented Feb 1, 2022

You didn't ask about this, but I guess you've already seen it and that's why you mentioned bump height in the meeting today:
Vertex randomization has a parameter offset for "Distance to offset"
https://docs.blender.org/api/current/bpy.ops.transform.html#bpy.ops.transform.vertex_random

bpy.ops.transform.vertex_random(offset=0.0, uniform=0.0, normal=0.0, seed=0, wait_for_input=True)
Randomize vertices

Parameters
offset (float in [-inf, inf], (optional)) – Amount, Distance to offset

uniform (float in [0, 1], (optional)) – Uniform, Increase for uniform offset distance

normal (float in [0, 1], (optional)) – Normal, Align offset direction to normals

seed (int in [0, 10000], (optional)) – Random Seed, Seed for the random number generator

wait_for_input (boolean, (optional)) – Wait for Input

@woensug-choi
Copy link
Collaborator

Yes, the script you've made can designate offset (=bump height) magnitude (while they are also random). but cannot control the density.

I was just asking for the density to calculate statistics for the minimum mesh edge length which would lead to average normal angles. Hmm

@mabelzhang
Copy link
Contributor Author

The edge length could vary a lot depending on where you are on the mesh. With a cylinder, the edges of the circles are very small, while the edges on the wall can be very long for e.g. a pipe.

Do you just want the normals? Blender has other ways to get the normals, e.g. https://docs.blender.org/api/current/bpy.types.Mesh.html

@woensug-choi
Copy link
Collaborator

woensug-choi commented Feb 3, 2022

Don't understand how the screenshot you've shown is possible. Maybe because it went through the process subdivide->offset->subdivide->offset order? What if finish subdivide and offset?

What I would like to have is some statistics on how much the mean normals have deviated from the original object shape. I was imagining the vertex density that are produced out of subdivision could provide information about mean normal deviation.

Or maybe we could ditch subdivision function called to the whole object and use a manual loop for each mesh element and give custom subdivision density. Maybe https://docs.blender.org/api/current/bpy.types.Mesh.html#bpy.types.Mesh.split_faces?

I think calculate_normals does not output anything. It's internal function to calculate normals.

@mabelzhang
Copy link
Contributor Author

mabelzhang commented Feb 4, 2022

To clarify, the screenshot I showed in the meeting came straight from a single operation of vertex randomization. Nothing else. There's no subdivide happening. I made a short video below to show exactly what I mean.

Blender's documentation doesn't talk about exactly how they do the randomization - that's beyond an artist's interest. We'd have to look at the source code to see how they do it. Judging from the result though, it seems it's a randomized offset of existing vertices. So if you have one vertex offset 0.1 m in one direction, and a consecutive vertex 0.1 m in the opposite direction, then you can get a 180 degree angle.

Let's move the normals discussion to a separate issue, since it's turning out to be a longer thread. You or I can open an issue (update: issue opened #187). I'll look more into what data it can give us.

Let's get this PR reviewed and merged first. It's pretty minimal code change, mostly documentation. Do you have the setup to review it? If not, I could re-tag Jessica for the review.

Video of just vertex randomization on a stock cylinder object (radius 1 m, height 1 m), no other modifications:
I show normal = 1.0, then normal = 0.0:

2022-02-03-21-36_Blender_cylinder_randomVertices.mp4

The ones I showed in the meeting for reference:

Original cylinder
2022-01-31-191548_3706x2049_scrot_cylinderSubdiv0

vertex randomization offset 0.1:
2022-01-31-194943_3706x2049_scrot_vertRand0 1

offset 0.3:
2022-01-31-194947_3706x2049_scrot

offset 0.7:
2022-01-31-194958_3706x2049_scrot

offset 1 m (same magnitude as cylinder radius and height, 1 m):
2022-01-31-195015_3706x2049_scrot_vertRand1

@j-herman
Copy link
Contributor

j-herman commented Feb 4, 2022

@mabelzhang I have time this morning - I'll get the review done. I accidentally updated Blender so I can check if it works on version 3.x and downgrade my computer afterwards for the review... whoops!

Copy link
Contributor

@j-herman j-herman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mabelzhang One thing I'd recommend fixing: When running the tutorial as written, blender crashes (both 3.x and 2.92) - the issue is with passing the distort_extent value of 20 with 'subdiv_mod' as the method. Could you change the tutorial to read "distort_extent = 0.2"? It was a little hard to troubleshoot because the crash happens without any feedback, so it might also be good to do a value check on the input.
A few other tiny things that I tripped over - the method variable has to be specified as an array, even if it's only one item, which would be helpful to note for non-Python users, and when you specify the path, it shouldn't have a leading '/' - at least, on my computer. Change or ignore at your discretion :)

Signed-off-by: Mabel Zhang <mabel@openrobotics.org>
@mabelzhang
Copy link
Contributor Author

mabelzhang commented Feb 5, 2022

When running the tutorial as written, blender crashes (both 3.x and 2.92)

Yes! Thank you for retesting and finding that crash. I'm always looking to make my code as robust as possible, but I had not done enough checks in this prototype. Updated in e176ffd

method variable has to be specified as an array

Updated in README and in code in e176ffd

path, it shouldn't have a leading '/'

Are you using a relative path? I use absolute path for mine with a leading / and it works. I have not tried relative paths. Looks like if I do os.getcwd() in the Blender Python prompt, it prints the path of where the Blender executable is. That's pretty far from where DAVE is on my machine, so I've been using absolute paths. I updated the README to say "full" path, if that addresses it. Let me know if that isn't enough.

Signed-off-by: Mabel Zhang <mabel@openrobotics.org>
@j-herman
Copy link
Contributor

j-herman commented Feb 7, 2022

Looks good at first review - I'll run it once more when I get back to the other computer and approve. Now there's no way for me to get it wrong... :)
Yeah, I was using relative path and had just been staring at errors for too long to remember that I didn't need to do that. Whoops.

Copy link
Collaborator

@woensug-choi woensug-choi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I think we should change fouling_rating to distort_extent at coke_template.erb


<surface_props:biofouling_rating><%= fouling_rating %></surface_props:biofouling_rating>
<surface_props:roughness><%= fouling_rating * 0.01 %></surface_props:roughness>

Another minor suggestion is add a link to 2.92 blender downloads: https://download.blender.org/release/Blender2.92/

So, at the current state, a distorted mesh obj file is created when the python script for a blender is performed. Then, Ruby erb script is used to make an sdf. Could we link these procedures into one? (this may be another PR or an issue).

I've used python script and template to produce a complete set of a model object by putting all necessary files into a separate model directory with mesh, texture, and sdf when generating dissected bathymetry tiles. I may be able to reconstruct and link two procedures into one using the python console on the blender. (S-size task) This maybe useful when linking the distort extent to automatically calculate and write a custom SDF tag for plugins.
If you want to give it a peek about how it's done (uses linux sed function with os.system),

urdf/scripts/mesh_distortion/README.md Show resolved Hide resolved
method = ['subdiv_mod', 'vert_rand', 'edge_subdiv']
```

Put the args into the input array:
```
import sys
sys.argv = ['distort.py', file_path, object_prefix, fouling_rating, method]
sys.argv = ['distort.py', file_path, object_prefix, distort_extent, method]
```

Run the script, replacing its path with the one on your machine:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path description in the distorted mesh's mtl file uses absolute path. The original coke.mtl wrote map_Kd ../materials/coke.png . The distorted file produced by the distort.py script writes map_Kd C:\\Users\\woens\\Downloads\\MeshDistortion\\Coke\\materials\\coke.png. I think it would be better to keep to the relative.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I added a path_mode='RELATIVE' for the OBJ export, which exposed that in the API https://docs.blender.org/api/current/bpy.ops.export_scene.html#bpy.ops.export_scene.obj 5f7030b

Side note: The COLLADA export (bpy.ops.wm.collada_export) though doesn't have that in the API. We aren't using that right now, as it doesn't export textures correctly, so it shouldn't affect the instructions. I added a TODO item above that line.

urdf/scripts/mesh_distortion/README.md Show resolved Hide resolved
@j-herman
Copy link
Contributor

j-herman commented Feb 8, 2022

@mabelzhang I ran the code again and couldn't break it! Looks good from the script perspective. @woensug-choi made a good point about updating the demo erb and the custom_surface_properties_plugin to match the new terminology and ranges here - do you want to add those updates to this PR or are they coming separately?

…export relative path for OBJ material file; clarify README

Signed-off-by: Mabel Zhang <mabel@openrobotics.org>
@mabelzhang
Copy link
Contributor Author

I believe 5f7030b addresses the comments.

I debated when I opened the PR whether to rename the fouling parameter in sdf_custom_properties, since we weren't entirely sure whether to go the biofouling way for both the mesh modification and the Gazebo side. Now I guess we might as well. It adds a few more files to the diff - the SDF file and the Gazebo plugin.

add a link to 2.92 blender downloads

I added the link. I also reworded the README to clarify this, because the link looks like a raw folder that users shouldn't go to. They don't necessarily need 2.92. It is not a LTS, so I don't want to recommend that specific version; it's just the version I've tested in. 2.93 is LTS but I haven't tested there. The instructions should work for newer versions. The mentioning of 2.92 is because the Blender UI changed significantly in 2.92, so item locations, shortcuts, etc. as written might not work for older versions. They should work for newer versions though.

Could we link these procedures into one?

I don't know if that's possible, because the Blender Python script is executed from a Python interpreter within the Blender GUI, whereas the Ruby script is run on the command line, outside Python.

I also don't know whether it's desirable to couple the two scripts. They take different parameters. The mesh distortion script is an artistic process for a general model file, whereas the SDF Ruby template is a physical process specific to parameters that will affect results in Gazebo.

We happen to have the biofouling rating in both, but you can see they weren't the same name (now they are, but) as the two scripts weren't intended to be coupled. Somebody could add any custom SDF tags to their file, like material properties, with or without distortion. The fouling / distort SDF tag is just an example to illustrate the users can add whatever they want. If the user doesn't have any distortion, then there's really no relation between the two scripts to warrant linking them.

Right now, it doesn't take too much effort for us to put in the same distort value for both. I don't know if it'll be worth the effort to link them. I also think that's something we can leave up to the user to do, as opposed to handling in DAVE.

Less relevant, but when we upstream these two scripts, they will live in different repos. One will be in an SDF repo, and the other will be in ign-common, precisely because they do such separate things.

@woensug-choi
Copy link
Collaborator

FYI, @mabelzhang I've updated the multibeam sonar repo for the duplicate model directory. It's not in SDF file structure but a bare OBJ and MTL files now in the coke_can_example directory. I think it's better for the sonar tutorial perspective that all SDF custom tags can be seen in a single world file to play with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants