├── .github └── workflows │ └── go.yml ├── LICENSE ├── README.md ├── ci ├── check_gofmt.sh └── check_large_files.sh ├── cli ├── inch_to_mm │ └── main.go ├── off_to_stl │ └── main.go ├── pan_pointcloud │ └── main.go ├── ply_to_obj │ └── main.go ├── profile_mesh │ └── main.go └── render_stl │ └── main.go ├── codegen.go ├── examples ├── _deprecated │ ├── apis │ │ ├── collider │ │ │ └── main.go │ │ ├── gears │ │ │ └── main.go │ │ ├── screw │ │ │ ├── README.md │ │ │ └── main.go │ │ ├── solid_collider │ │ │ ├── main.go │ │ │ └── rendering.png │ │ └── solids │ │ │ └── main.go │ ├── box │ │ ├── README.md │ │ ├── heart.png │ │ └── main.go │ ├── castle_tower │ │ ├── main.go │ │ └── rendering.png │ └── pine_tree │ │ ├── main.go │ │ └── rendering.png ├── check_build_errors.sh ├── decoration │ ├── apple │ │ ├── README.md │ │ ├── half_apple.png │ │ ├── main.go │ │ ├── rendering.png │ │ └── turing_signature.png │ ├── banana │ │ ├── README.md │ │ ├── cross_section.svg │ │ ├── curve.go │ │ ├── main.go │ │ └── rendering.png │ ├── cactus │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── corgi │ │ ├── README.md │ │ ├── colors.go │ │ ├── main.go │ │ ├── rendering.png │ │ └── smooth_join.go │ ├── covid_jail │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── cube_stack │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── curvy_thing │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── cut_cube │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── decision_tree │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── diamond │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering.png │ │ └── rendering_stand.png │ ├── donut │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── dragon_egg │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── globe │ │ ├── README.md │ │ ├── main.go │ │ ├── map.png │ │ ├── rendering_bottom.png │ │ └── rendering_top.png │ ├── gopher │ │ ├── README.md │ │ ├── base.go │ │ ├── body.go │ │ ├── ears.go │ │ ├── eyes.go │ │ ├── feet.go │ │ ├── hands.go │ │ ├── main.go │ │ ├── nose.go │ │ ├── rendering.png │ │ └── teeth.go │ ├── impossible_mug │ │ ├── README.md │ │ ├── hole.go │ │ ├── main.go │ │ ├── mug.go │ │ └── rendering.png │ ├── lamp │ │ ├── README.md │ │ ├── light.go │ │ ├── main.go │ │ ├── plant.go │ │ └── rendering.png │ ├── lockbagel │ │ ├── README.md │ │ ├── main.go │ │ ├── printed_lockbagel.jpg │ │ └── rendering.png │ ├── makeup_brush │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── neural_network │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── orange_slices │ │ ├── README.md │ │ ├── main.go │ │ ├── peel.go │ │ ├── real.jpg │ │ ├── rendering.png │ │ └── wedge.go │ ├── pickle │ │ ├── README.md │ │ ├── inscription.png │ │ ├── main.go │ │ ├── pickle.png │ │ ├── rendering_color.png │ │ └── rendering_etched.png │ ├── pumpkin │ │ ├── README.md │ │ ├── etching.png │ │ ├── main.go │ │ └── rendering.png │ ├── pumpkin_v2 │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── rock │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── rose │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── rubiks_cube │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── sand_castle │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering.png │ │ └── text_imprint.png │ ├── snake_table │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── starfish │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── three_axis_chain │ │ ├── main.go │ │ └── rendering.png │ ├── tiffany_tree │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── tree │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── tree_ornament │ │ ├── README.md │ │ ├── hanger.go │ │ ├── main.go │ │ ├── rendering_hanger.png │ │ ├── rendering_star.png │ │ └── star.go │ ├── vase │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── wall_flower │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering.png │ │ └── rendering_shape.svg │ ├── wall_sun │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── xmas_tree │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ └── zigzag_egg │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering.png │ │ └── zig_zag.png ├── experiments │ ├── convex_globe │ │ ├── README.md │ │ ├── main.go │ │ ├── map.png │ │ └── rendering.png │ ├── decimation │ │ └── main.go │ ├── disc_with_cutout │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering1.png │ │ └── rendering2.png │ ├── fix_mask │ │ ├── README.md │ │ └── main.go │ ├── geneva_drive │ │ ├── README.md │ │ ├── board.go │ │ ├── gear_body.go │ │ ├── main.go │ │ ├── profiles.go │ │ ├── rendering.png │ │ └── rendering_profiles.svg │ ├── hemisphere_param │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── interlocking │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── pillow │ │ ├── README.md │ │ ├── pillow_ellipses │ │ │ ├── README.md │ │ │ ├── main.go │ │ │ └── rendering.png │ │ ├── pillow_medial │ │ │ ├── README.md │ │ │ ├── main.go │ │ │ └── rendering.png │ │ ├── pillow_sdf │ │ │ ├── README.md │ │ │ ├── main.go │ │ │ └── rendering.png │ │ └── pillow_sphere │ │ │ ├── README.md │ │ │ ├── main.go │ │ │ └── rendering.png │ ├── plot_2d_sdf │ │ ├── README.md │ │ ├── example.png │ │ └── main.go │ ├── plot_polar_shape │ │ ├── README.md │ │ └── main.go │ ├── shadow_text │ │ ├── README.md │ │ ├── draw_path.html │ │ ├── main.go │ │ ├── paths │ │ │ ├── hello.json.gz │ │ │ └── nug.json.gz │ │ ├── rendering.png │ │ └── rendering_direct.png │ ├── smooth_bezier │ │ └── main.go │ ├── smooth_join_2d │ │ ├── README.md │ │ ├── images │ │ │ ├── easy_case_input.png │ │ │ ├── easy_case_v1.png │ │ │ ├── easy_case_v2.png │ │ │ ├── middle_case_input.png │ │ │ ├── middle_case_v1.png │ │ │ ├── middle_case_v2.png │ │ │ ├── parallel_case_input.png │ │ │ ├── parallel_case_v1.png │ │ │ └── parallel_case_v2.png │ │ └── main.go │ ├── smooth_shape │ │ ├── README.md │ │ ├── input.png │ │ ├── main.go │ │ └── output.png │ ├── telescoping │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ └── topology_puzzle │ │ ├── README.md │ │ ├── main.go │ │ └── renderings │ │ ├── board.png │ │ ├── board_bottom.png │ │ ├── bottom_holder.png │ │ └── other_holder.png ├── parody │ ├── cable_car │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering.png │ │ └── text.png │ ├── dumbell │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering_bar.png │ │ └── rendering_side.png │ ├── flag_statue │ │ ├── README.md │ │ ├── base.go │ │ ├── flag.go │ │ ├── main.go │ │ ├── person.go │ │ └── rendering.png │ ├── gl_inet │ │ ├── README.md │ │ ├── body.go │ │ ├── ethernet.go │ │ ├── fanhole.go │ │ ├── glinet.jpg │ │ ├── lid.go │ │ ├── main.go │ │ └── rendering.png │ ├── golden_gate │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── place_setting │ │ ├── README.md │ │ ├── fork.go │ │ ├── main.go │ │ ├── rendering_fork.png │ │ ├── rendering_wine_glass.png │ │ └── wine_glass.go │ └── swiss_cheese │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png ├── renderings │ ├── ball_physics │ │ ├── README.md │ │ ├── diff_eq.go │ │ ├── fields.go │ │ ├── main.go │ │ └── scene.go │ ├── bezier_fit │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.gif │ ├── cornell_box │ │ ├── README.md │ │ ├── diamond.stl │ │ ├── main.go │ │ ├── output.png │ │ └── output_hd.png │ ├── deformation │ │ ├── README.md │ │ ├── main.go │ │ └── output.gif │ ├── egg_2d │ │ ├── README.md │ │ ├── egg.png │ │ └── main.go │ ├── fog │ │ ├── README.md │ │ ├── main.go │ │ └── output.png │ ├── golf_balls │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── rope_indent │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── showcase │ │ ├── README.md │ │ ├── constants.go │ │ ├── main.go │ │ ├── models.go │ │ ├── models │ │ │ ├── curvy_thing.stl.gz │ │ │ ├── pumpkin_inside.stl.gz │ │ │ ├── pumpkin_outside.stl.gz │ │ │ ├── pumpkin_stem.stl.gz │ │ │ ├── rocks.stl.gz │ │ │ ├── rose.stl.gz │ │ │ ├── vase.stl.gz │ │ │ └── wine_glass.stl.gz │ │ ├── output.png │ │ ├── output_hd.png │ │ └── room.go │ ├── smooth_shading │ │ ├── README.md │ │ ├── labels │ │ │ ├── flat.png │ │ │ └── smooth.png │ │ ├── main.go │ │ └── rendering.png │ ├── tiffany │ │ ├── README.md │ │ ├── globe.go │ │ ├── lights.go │ │ ├── main.go │ │ ├── output.png │ │ ├── output_hd.png │ │ └── walls.go │ └── yt_banner │ │ ├── README.md │ │ ├── assets │ │ ├── corgi.zip │ │ ├── letters.png │ │ └── marble.jpg │ │ ├── corgi.go │ │ ├── floor.go │ │ ├── letters.go │ │ ├── main.go │ │ └── output.png ├── romantic │ ├── coin │ │ ├── README.md │ │ ├── example.png │ │ ├── main.go │ │ └── rendering.png │ ├── floral_arrangement │ │ ├── README.md │ │ ├── flower_pot.go │ │ ├── flowers.go │ │ ├── main.go │ │ ├── rendering.png │ │ └── stem.go │ ├── heart_arrow │ │ ├── README.md │ │ ├── main.go │ │ ├── original.png │ │ └── rendering.png │ ├── heart_box │ │ ├── README.md │ │ ├── main.go │ │ ├── outline.png │ │ ├── rendering_box.png │ │ ├── rendering_lid.png │ │ └── sections.png │ ├── heart_pizza │ │ ├── README.md │ │ ├── heart.png │ │ ├── main.go │ │ └── rendering.png │ ├── heart_ring │ │ ├── README.md │ │ ├── heart.png │ │ ├── letters.png │ │ ├── main.go │ │ └── rendering.png │ ├── heart_statue │ │ ├── README.md │ │ ├── heart.go │ │ ├── heart.png │ │ ├── letter_1.png │ │ ├── letter_2.png │ │ ├── main.go │ │ └── rendering.png │ ├── key │ │ ├── README.md │ │ ├── engraving.png │ │ ├── main.go │ │ ├── outline.png │ │ ├── rendering_2d.png │ │ └── rendering_3d.png │ ├── kisses │ │ ├── README.md │ │ ├── hershey_kiss.go │ │ ├── main.go │ │ ├── rendering.png │ │ └── text.png │ ├── love_graph │ │ ├── README.md │ │ ├── heart.png │ │ ├── label1.png │ │ ├── label2.png │ │ ├── label3.png │ │ ├── main.go │ │ └── rendering.png │ ├── my_home │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering.png │ │ └── text.png │ ├── my_world │ │ ├── README.md │ │ ├── base.png │ │ ├── main.go │ │ ├── map.png │ │ └── rendering.png │ ├── necklace │ │ ├── README.md │ │ ├── main.go │ │ ├── manifold.go │ │ └── rendering.png │ ├── necklace_2 │ │ ├── README.md │ │ ├── attachments.go │ │ ├── example_attachments │ │ │ ├── chanel.png │ │ │ └── chanel_engraving.png │ │ ├── main.go │ │ └── renderings │ │ │ ├── chanel.png │ │ │ └── heart.png │ ├── otter_love │ │ ├── README.md │ │ ├── line_1.png │ │ ├── line_2.png │ │ ├── main.go │ │ ├── otter.png │ │ └── rendering.png │ ├── pendant │ │ ├── README.md │ │ ├── examples │ │ │ ├── earth_engraving.png │ │ │ ├── earth_outline.png │ │ │ ├── love_key.png │ │ │ └── love_key_engraving.png │ │ ├── main.go │ │ └── rendering.png │ ├── pill │ │ ├── README.md │ │ ├── heart.png │ │ ├── main.go │ │ └── rendering.png │ ├── ring_display │ │ ├── README.md │ │ ├── box.go │ │ ├── diamond_ring.go │ │ ├── main.go │ │ ├── metal_ring.go │ │ └── rendering.png │ ├── tiffany_box │ │ ├── README.md │ │ ├── main.go │ │ └── rendering_both.png │ └── wedding_cake │ │ ├── dots_layer.go │ │ ├── flower_layer.go │ │ ├── letter_circle.go │ │ ├── letters │ │ ├── 1.png │ │ ├── H.png │ │ ├── a.png │ │ ├── p.png │ │ ├── s.png │ │ ├── t.png │ │ └── y.png │ │ ├── main.go │ │ ├── marble_hexagon.go │ │ └── rough_layer.go ├── toys │ ├── ball_spiral │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── dreidel │ │ ├── README.md │ │ ├── main.go │ │ └── rendering.png │ ├── fidget_spinner │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering.png │ │ ├── side_1.png │ │ ├── side_2.png │ │ └── side_3.png │ ├── jigsaw │ │ ├── README.md │ │ ├── generate_image.go │ │ ├── generate_mesh.go │ │ ├── main.go │ │ ├── rendering_holder.png │ │ └── rendering_pieces.png │ ├── maze │ │ ├── README.md │ │ ├── main.go │ │ ├── maze.png │ │ └── rendering.png │ ├── number_puzzle │ │ ├── README.md │ │ ├── args.go │ │ ├── layout.go │ │ ├── layout_test.go │ │ ├── main.go │ │ ├── rendering.png │ │ ├── search.go │ │ ├── solid.go │ │ └── templates.go │ └── puzzle │ │ ├── README.md │ │ ├── main.go │ │ ├── rendering_board.png │ │ └── rendering_piece.png └── usable │ ├── bracket │ ├── README.md │ ├── main.go │ └── rendering.png │ ├── chip_clip │ ├── README.md │ ├── main.go │ ├── pictures.jpg │ └── rendering.png │ ├── cubby_drawer │ ├── README.md │ ├── main.go │ ├── rendering_bin.png │ ├── rendering_knob.png │ └── rendering_nut.png │ ├── dog_tag │ ├── README.md │ ├── body.png │ ├── main.go │ ├── rendering.png │ └── text.png │ ├── drawer │ ├── README.md │ ├── drawer.go │ ├── frame.go │ ├── knob.go │ ├── main.go │ └── renderings │ │ ├── drawer.png │ │ ├── frame.png │ │ ├── knob.png │ │ └── nut.png │ ├── fan │ ├── README.md │ ├── constants.go │ ├── crank_bolt.go │ ├── crank_gear.go │ ├── main.go │ ├── pictures │ │ ├── assembled.jpg │ │ └── parts.jpg │ ├── propeller.go │ ├── small_gear.go │ └── spine.go │ ├── hanging_hook │ ├── README.md │ ├── main.go │ ├── rendering_dip.png │ └── rendering_no_dip.png │ ├── hole_measure │ ├── README.md │ ├── main.go │ └── rendering.png │ ├── kindle_holder │ ├── README.md │ ├── main.go │ └── rendering.png │ ├── menorah │ ├── README.md │ ├── main.go │ └── rendering.png │ ├── milkshake_ringholder │ ├── README.md │ ├── cherry.go │ ├── cream.go │ ├── cup.go │ ├── main.go │ ├── rendering.png │ ├── straw.go │ └── text.png │ ├── napkin_holder │ ├── README.md │ ├── image.png │ ├── main.go │ └── rendering.png │ ├── pencil_holder │ ├── README.md │ ├── main.go │ ├── rendering.png │ └── schematic.png │ ├── penguin_calendar │ ├── README.md │ ├── body.go │ ├── labels │ │ ├── dates │ │ │ ├── 1.png │ │ │ ├── 10.png │ │ │ ├── 11.png │ │ │ ├── 12.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ ├── 8.png │ │ │ └── 9.png │ │ └── numbers │ │ │ ├── 0.png │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ ├── 8.png │ │ │ └── 9.png │ ├── main.go │ ├── rendering_blocks.png │ ├── rendering_penguin.png │ └── text_block.go │ ├── phone_booth │ ├── README.md │ ├── images │ │ └── telephone.png │ ├── main.go │ ├── rendering_bottom.png │ └── rendering_top.png │ ├── pitcher │ ├── README.md │ ├── main.go │ └── rendering.png │ ├── quarter_case │ ├── README.md │ ├── main.go │ ├── rendering_body.png │ └── rendering_lid.png │ ├── razor_holder │ ├── README.md │ ├── main.go │ └── rendering.png │ ├── recycle_bin │ ├── README.md │ ├── main.go │ ├── rendering.png │ └── wikipedia_image.png │ ├── ruler │ ├── README.md │ ├── main.go │ └── rendering.png │ ├── shoe_rack │ ├── README.md │ ├── main.go │ └── rendering.png │ ├── table │ ├── README.md │ ├── cone_stand.png │ ├── leg.png │ ├── main.go │ ├── stand.png │ └── top.png │ ├── trash_can │ ├── README.md │ ├── main.go │ ├── rendering_bulge.png │ └── rendering_swirl.png │ ├── treat_box │ ├── README.md │ ├── bone.png │ ├── main.go │ ├── rendering_box.png │ ├── rendering_handle.png │ └── rendering_lid.png │ ├── tripod │ ├── README.md │ ├── cradle.go │ ├── foot.go │ ├── main.go │ ├── rendering_cradle.png │ ├── rendering_foot.png │ ├── rendering_tripod.png │ └── tripod.go │ ├── umbrella_brace │ ├── README.md │ ├── main.go │ └── rendering.png │ ├── wall_basket │ ├── README.md │ ├── main.go │ ├── rendering_bin.png │ └── rendering_mount.png │ └── watch_holder │ ├── README.md │ ├── main.go │ └── rendering.png ├── fileformats ├── 3mf.go ├── off.go ├── ply.go ├── ply_test.go ├── ply_value.go ├── segment_csv.go ├── stl.go ├── stl_test.go ├── svg.go └── wavefront_obj.go ├── go.mod ├── go.sum ├── model2d ├── bezier_fit.go ├── bezier_fit_test.go ├── bitmap.go ├── bitmap_test.go ├── bounder.go ├── bvh.go ├── collisions.go ├── collisions_test.go ├── coord_tree.go ├── coord_tree_test.go ├── coords.go ├── curves.go ├── curves_test.go ├── doc.go ├── export.go ├── export_test.go ├── fast_maps.go ├── fast_maps_test.go ├── import.go ├── interp.go ├── marching.go ├── marching_test.go ├── matrix.go ├── matrix_test.go ├── measurements.go ├── measurements_test.go ├── medial_axis.go ├── mesh.go ├── mesh_hierarchy.go ├── mesh_hierarchy_test.go ├── mesh_ops.go ├── mesh_ops_test.go ├── mesh_test.go ├── metaball.go ├── metaball_test.go ├── polytope.go ├── polytope_test.go ├── primitives.go ├── primitives_test.go ├── ptr_mesh.go ├── rasterize.go ├── rasterize_test.go ├── sdf.go ├── sdf_test.go ├── shapes.go ├── shapes_test.go ├── smooth.go ├── solid.go ├── surface_estimator.go ├── surface_estimator_test.go ├── test_data │ ├── test_bitmap.png │ ├── test_bitmap_small.png │ ├── triangulate_breaker.txt │ ├── triangulate_breaker_2.txt │ └── triangulate_breaker_2_simple.txt ├── transform.go ├── triangulate.go ├── triangulate_test.go └── util_test.go ├── model3d ├── bounder.go ├── bvh.go ├── collisions.go ├── collisions_test.go ├── coord_tree.go ├── coord_tree_test.go ├── coords.go ├── coords_test.go ├── dc.go ├── dc_test.go ├── decimate.go ├── decimate_test.go ├── deformation.go ├── doc.go ├── export.go ├── fast_maps.go ├── fast_maps_test.go ├── import.go ├── import_test.go ├── matrix.go ├── matrix_test.go ├── mc.go ├── mc_test.go ├── measurements.go ├── measurements_test.go ├── mesh.go ├── mesh_hierarchy.go ├── mesh_hierarchy_test.go ├── mesh_ops.go ├── mesh_ops_test.go ├── mesh_test.go ├── metaball.go ├── metaball_test.go ├── parameterization.go ├── parameterization_test.go ├── polytope.go ├── polytope_test.go ├── primitives.go ├── primitives_test.go ├── ptr_mesh.go ├── sdf.go ├── sdf_test.go ├── shapes.go ├── shapes_test.go ├── smooth.go ├── solid.go ├── solid_test.go ├── subdivision.go ├── subdivision_test.go ├── surface_estimator.go ├── surface_estimator_test.go ├── test_data │ ├── cube.off │ ├── hierarchy_test.stl.gz │ └── non_intersecting_hook.stl ├── transform.go ├── triangulate.go ├── triangulate_test.go └── util_test.go ├── numerical ├── cg.go ├── cg_test.go ├── dense_search.go ├── dense_search_test.go ├── gss.go ├── k_means.go ├── least_squares.go ├── least_squares_test.go ├── matrix2.go ├── matrix2_test.go ├── matrix3.go ├── matrix3_test.go ├── matrix4.go ├── matrix4_test.go ├── polynomial.go ├── polynomial_test.go ├── sparse_cholesky.go ├── sparse_cholesky_test.go ├── sparse_matrix.go ├── sparse_matrix_test.go ├── test_data │ └── sparse_mat.json.gz ├── vecs.go └── vecs_test.go ├── render3d ├── bidir.go ├── bidir_test.go ├── camera.go ├── concurrency.go ├── doc.go ├── focus_point.go ├── focus_point_test.go ├── helpers.go ├── image.go ├── light.go ├── material.go ├── material_test.go ├── object.go ├── ray_renderer.go ├── raycast.go ├── raytrace.go └── transform.go ├── templates ├── bounder.template ├── bvh.template ├── coord_tree.template ├── coord_tree_test.template ├── fast_maps.template ├── fast_maps_test.template ├── mesh.template ├── mesh_hierarchy.template ├── mesh_hierarchy_test.template ├── metaball.template ├── metaball_test.template ├── polytope.template ├── polytope_test.template ├── sdf.template ├── shapes.template ├── solid.template ├── surface_estimator.template ├── surface_estimator_test.template ├── transform.template └── util_test.template └── toolbox3d ├── angles.go ├── clamp.go ├── color_func.go ├── doc.go ├── equirect.go ├── flags.go ├── flags_test.go ├── gear.go ├── height_map.go ├── height_map_test.go ├── line_join.go ├── min_max.go ├── min_max_test.go ├── radial_curve.go ├── radial_curve_test.go ├── ramp.go ├── rect_set.go ├── rect_set_test.go ├── screw.go ├── singularities.go ├── slice.go ├── squeeze.go ├── squeeze_test.go └── teardrop.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | test: 12 | name: Test 13 | runs-on: ubuntu-latest 14 | steps: 15 | 16 | - name: Set up Go 1.x 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: ^1.18 20 | id: go 21 | 22 | - name: Check out code into the Go module directory 23 | uses: actions/checkout@v2 24 | 25 | - name: Get dependencies 26 | run: | 27 | go get -v -t -d ./... 28 | 29 | - name: Test 30 | run: go test -v ./... 31 | 32 | - name: Codegen Check 33 | run: go run . -check 34 | 35 | - name: gofmt 36 | run: ./ci/check_gofmt.sh 37 | 38 | - name: gofmt 39 | run: ./ci/check_large_files.sh 40 | -------------------------------------------------------------------------------- /ci/check_gofmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | found=0 4 | while read -r path; do 5 | out=$(gofmt -l $path) 6 | if [ "$out" != "" ]; then 7 | echo "reformatted $path" >&2 8 | found=$((found+1)) 9 | fi 10 | done <<<$(find . -name '*.go') 11 | 12 | if [ $found -ne 0 ]; then 13 | echo "gofmt reformatted $found files!" >&2 14 | exit 1 15 | else 16 | echo "no files were reformatted by gofmt" 17 | fi -------------------------------------------------------------------------------- /ci/check_large_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find . | while read line; do 4 | # Exclude list (is there a better way to write this?) 5 | if [[ "$line" == ./.git* ]]; then 6 | continue 7 | fi 8 | if [[ "$line" == ./examples/renderings/showcase/models/* ]]; then 9 | continue 10 | fi 11 | found="false" 12 | for path in ./model3d/test_data/hierarchy_test.stl.gz ./model3d/test_data/non_intersecting_hook.stl ./examples/decoration/lockbagel/printed_lockbagel.jpg ./examples/renderings/yt_banner/assets/corgi.zip ./examples/renderings/tiffany/output_hd.png; do 13 | if [ "$line" == "$path" ]; then 14 | found="true" 15 | fi 16 | done 17 | if [ "$found" == "true" ]; then 18 | continue 19 | fi 20 | 21 | if [ -f "$line" ]; then 22 | size=$(du -k "$line" | cut -f 1 -d $'\t' | cut -f 1 -d ' ') 23 | if [ "$size" -ge 1000 ]; then 24 | echo "file is too large: $line ($size KB)" >&2 25 | exit 1 26 | fi 27 | fi 28 | done 29 | -------------------------------------------------------------------------------- /cli/inch_to_mm/main.go: -------------------------------------------------------------------------------- 1 | // Command inch_to_mm converts an STL file from using 2 | // inches to using millimeters. 3 | package main 4 | 5 | import ( 6 | "bufio" 7 | "os" 8 | 9 | "github.com/unixpickle/essentials" 10 | "github.com/unixpickle/model3d/model3d" 11 | ) 12 | 13 | func main() { 14 | if len(os.Args) < 2 { 15 | essentials.Die("Usage: inch_to_mm input1.stl [input2.stl ...]") 16 | } 17 | 18 | for _, inputFile := range os.Args[1:] { 19 | Convert(inputFile, inputFile) 20 | } 21 | } 22 | 23 | func Convert(inputFile, outputFile string) { 24 | r, err := os.Open(inputFile) 25 | essentials.Must(err) 26 | triangles, err := model3d.ReadSTL(r) 27 | r.Close() 28 | essentials.Must(err) 29 | 30 | for _, t := range triangles { 31 | for i := range t { 32 | t[i] = t[i].Scale(25.4) 33 | } 34 | } 35 | 36 | w, err := os.Create(outputFile) 37 | essentials.Must(err) 38 | defer w.Close() 39 | bufW := bufio.NewWriter(w) 40 | err = model3d.WriteSTL(bufW, triangles) 41 | essentials.Must(err) 42 | essentials.Must(bufW.Flush()) 43 | } 44 | -------------------------------------------------------------------------------- /cli/off_to_stl/main.go: -------------------------------------------------------------------------------- 1 | // Command off_to_stl converts OFF files to STL files. 2 | // This is useful to preprocess the dataset for ModelNet. 3 | package main 4 | 5 | import ( 6 | "io/ioutil" 7 | "os" 8 | 9 | "github.com/unixpickle/essentials" 10 | "github.com/unixpickle/model3d/model3d" 11 | ) 12 | 13 | func main() { 14 | if len(os.Args) != 3 { 15 | essentials.Die("Usage: off_to_stl ") 16 | } 17 | offFile := os.Args[1] 18 | stlFile := os.Args[2] 19 | 20 | f, err := os.Open(offFile) 21 | essentials.Must(err) 22 | defer f.Close() 23 | 24 | triangles, err := model3d.ReadOFF(f) 25 | essentials.Must(err) 26 | 27 | essentials.Must(ioutil.WriteFile(stlFile, model3d.EncodeSTL(triangles), 0755)) 28 | } 29 | -------------------------------------------------------------------------------- /cli/profile_mesh/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/unixpickle/model3d/model2d" 9 | "github.com/unixpickle/model3d/model3d" 10 | "github.com/unixpickle/model3d/toolbox3d" 11 | ) 12 | 13 | type Args struct { 14 | SmoothIters int `default:"20" usage:"2d mesh smoothing iterations"` 15 | Thickness float64 `default:"10.0" usage:"thickness of model (pixels)"` 16 | } 17 | 18 | func main() { 19 | var args Args 20 | toolbox3d.AddFlags(&args, nil) 21 | flag.Usage = func() { 22 | fmt.Fprintf(os.Stderr, "Usage: %s [flags] \n", os.Args[0]) 23 | fmt.Fprintln(os.Stderr) 24 | fmt.Fprintln(os.Stderr, "Flags:") 25 | fmt.Fprintln(os.Stderr) 26 | flag.PrintDefaults() 27 | fmt.Fprintln(os.Stderr) 28 | } 29 | flag.Parse() 30 | if len(flag.Args()) != 2 { 31 | flag.Usage() 32 | os.Exit(1) 33 | } 34 | 35 | inFile, outFile := flag.Args()[0], flag.Args()[1] 36 | mesh2d := model2d.MustReadBitmap(inFile, nil).FlipY().Mesh() 37 | if args.SmoothIters > 0 { 38 | mesh2d = mesh2d.SmoothSq(args.SmoothIters) 39 | } 40 | 41 | profile := model3d.ProfileMesh(mesh2d, 0, args.Thickness) 42 | profile.SaveGroupedSTL(outFile) 43 | } 44 | -------------------------------------------------------------------------------- /examples/_deprecated/apis/collider/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | ) 6 | 7 | func main() { 8 | m := model3d.NewMeshPolar(func(g model3d.GeoCoord) float64 { 9 | return 1.0 10 | }, 50) 11 | collider := model3d.MeshToCollider(m) 12 | solid := model3d.NewColliderSolid(collider) 13 | m1 := model3d.MarchingCubesSearch(solid, 0.025, 8) 14 | m1.SaveGroupedSTL("sphere.stl") 15 | } 16 | -------------------------------------------------------------------------------- /examples/_deprecated/apis/screw/README.md: -------------------------------------------------------------------------------- 1 | # screw 2 | 3 | This example shows how to make a working screw and a hole for it to screw into. The screw can be printed with a standard FDM printer, and it tends to work out of the box with no supports. 4 | -------------------------------------------------------------------------------- /examples/_deprecated/apis/screw/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | 6 | "github.com/unixpickle/model3d/model3d" 7 | "github.com/unixpickle/model3d/toolbox3d" 8 | ) 9 | 10 | func main() { 11 | screw := model3d.JoinedSolid{ 12 | &model3d.Cylinder{ 13 | P1: model3d.Coord3D{}, 14 | P2: model3d.Z(0.2), 15 | Radius: 0.2, 16 | }, 17 | &toolbox3d.ScrewSolid{ 18 | P1: model3d.Z(0.2), 19 | P2: model3d.Z(1.0), 20 | Radius: 0.14, 21 | GrooveSize: 0.05, 22 | }, 23 | } 24 | mesh := model3d.MarchingCubesSearch(screw, 0.004, 8) 25 | ioutil.WriteFile("screw.stl", mesh.EncodeSTL(), 0755) 26 | 27 | hole := &model3d.SubtractedSolid{ 28 | Positive: &model3d.Cylinder{ 29 | P1: model3d.Coord3D{}, 30 | P2: model3d.Z(1.0), 31 | Radius: 0.4, 32 | }, 33 | Negative: &toolbox3d.ScrewSolid{ 34 | P1: model3d.Z(0.0), 35 | P2: model3d.Z(1.0), 36 | Radius: 0.16, 37 | GrooveSize: 0.05, 38 | }, 39 | } 40 | mesh = model3d.MarchingCubesSearch(hole, 0.005, 8) 41 | ioutil.WriteFile("hole.stl", mesh.EncodeSTL(), 0755) 42 | } 43 | -------------------------------------------------------------------------------- /examples/_deprecated/apis/solid_collider/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/_deprecated/apis/solid_collider/rendering.png -------------------------------------------------------------------------------- /examples/_deprecated/apis/solids/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | ) 6 | 7 | func main() { 8 | solid := model3d.JoinedSolid{ 9 | &model3d.Sphere{Radius: 0.5}, 10 | &model3d.Cylinder{ 11 | P1: model3d.XYZ(0, 0.2, 0), 12 | P2: model3d.XYZ(-0.5, 0.5, 0), 13 | Radius: 0.2, 14 | }, 15 | &model3d.Torus{ 16 | Axis: model3d.XYZ(1, 1, 1), 17 | OuterRadius: 0.7, 18 | InnerRadius: 0.1, 19 | }, 20 | } 21 | mesh := model3d.MarchingCubesSearch(solid, 0.005, 8) 22 | mesh.SaveGroupedSTL("output.stl") 23 | } 24 | -------------------------------------------------------------------------------- /examples/_deprecated/box/README.md: -------------------------------------------------------------------------------- 1 | # box 2 | 3 | This is a four-part box. It includes a screw, a handle, a lid, and a body. It is 1 inch deep, 4 inches long, and 3 inches wide by default, but these dimensions can be adjusted in the constants at the top of the file. The handle screws onto the lid, and the lid fits snugly in the box. 4 | 5 | All parts are designed to be printed on a commodity FDM printer. 6 | 7 | The file heart.png controls the shape of the handle and the engraving on it. Shape is in red, and engraving is in black. Background is fully transparent. 8 | -------------------------------------------------------------------------------- /examples/_deprecated/box/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/_deprecated/box/heart.png -------------------------------------------------------------------------------- /examples/_deprecated/castle_tower/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/_deprecated/castle_tower/rendering.png -------------------------------------------------------------------------------- /examples/_deprecated/pine_tree/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/_deprecated/pine_tree/rendering.png -------------------------------------------------------------------------------- /examples/check_build_errors.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -eq 0 ]; then 4 | echo 'Testing all examples...' 5 | find . -name 'main.go' -exec ./check_build_errors.sh {} \; 6 | exit 7 | fi 8 | 9 | if echo "$1" | grep _deprecated >/dev/null; then 10 | exit 11 | fi 12 | echo $1 | grep _deprecated 13 | 14 | cd $(dirname $1) 15 | if ! [ -f README.md ]; then 16 | echo "Missing README for $(dirname $1)" >&2 17 | fi 18 | if ! go test 2>/dev/null >/dev/null; then 19 | echo "Test failure for $(dirname $1)" >&2 20 | fi 21 | cd - >/dev/null 22 | -------------------------------------------------------------------------------- /examples/decoration/apple/README.md: -------------------------------------------------------------------------------- 1 | # apple 2 | 3 | This is a decoration meant to be printed in color (e.g. with Binder Jetting). It is a small apple with Alan Turing's signature written in the bite. 4 | 5 | # Renderings 6 | 7 | ![Renderings](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/apple/half_apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/apple/half_apple.png -------------------------------------------------------------------------------- /examples/decoration/apple/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/apple/rendering.png -------------------------------------------------------------------------------- /examples/decoration/apple/turing_signature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/apple/turing_signature.png -------------------------------------------------------------------------------- /examples/decoration/banana/README.md: -------------------------------------------------------------------------------- 1 | # banana 2 | 3 | This example creates a banana shape on a small base. It demonstrates using bezier curves and 2D cross-sections to create a 3D shape. The model is intended to be printed (with supports) and stuck to a wall as decoration. 4 | 5 | # Defining the banana 6 | 7 | The 2D cross-section of the banana is created by intersecting four circles. This looks like this: 8 | 9 | ![Cross section](cross_section.svg) 10 | 11 | Next, the cross section is extended along a curve defining the length-wise shape of the banana. This defines the general arch that brings the middle of the banana down. 12 | 13 | Finally, a separate function determines the radius along the length of the banana, which is smooth except for the stem which is constant radius. This makes the tips of the banana thinner than the middle. 14 | 15 | # Renderings 16 | 17 | ![Rendering of the model](rendering.png) 18 | -------------------------------------------------------------------------------- /examples/decoration/banana/cross_section.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/decoration/banana/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/banana/rendering.png -------------------------------------------------------------------------------- /examples/decoration/cactus/README.md: -------------------------------------------------------------------------------- 1 | # cactus 2 | 3 | This example creates a fake, decorative cactus plant in a pot. 4 | 5 | # Renderings 6 | 7 | ![Renderings of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/cactus/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/cactus/rendering.png -------------------------------------------------------------------------------- /examples/decoration/corgi/README.md: -------------------------------------------------------------------------------- 1 | # corgi 2 | 3 | This example shows how to combine a bunch of rough geometric parts into a smooth result. In particular, [smooth_join.go](smooth_join.go) uses signed distance functions combined with the dynamic smoothing API to smooth a mesh more closer to intersections of different parts of the model. 4 | 5 | This example also colors its resulting mesh by defining a set of volumes in which various colors are used. 6 | 7 | # Renderings 8 | 9 | ![Renderings](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/decoration/corgi/colors.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | ) 6 | 7 | type Colorer struct { 8 | Solids []model3d.Solid 9 | Colors [][3]float64 10 | } 11 | 12 | func (c *Colorer) Add(s model3d.Solid, color [3]float64) { 13 | c.Solids = append(c.Solids, s) 14 | c.Colors = append(c.Colors, color) 15 | } 16 | 17 | func (c *Colorer) VertexColor(coord model3d.Coord3D) [3]float64 { 18 | for i, s := range c.Solids { 19 | if s.Contains(coord) { 20 | return c.Colors[i] 21 | } 22 | } 23 | return [3]float64{0, 0, 0} 24 | } 25 | 26 | func (c *Colorer) TriangleColor(t *model3d.Triangle) [3]float64 { 27 | var avg [3]float64 28 | for _, coord := range t { 29 | color := c.VertexColor(coord) 30 | for i, x := range color { 31 | avg[i] += x / 3 32 | } 33 | } 34 | return avg 35 | } 36 | -------------------------------------------------------------------------------- /examples/decoration/corgi/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/corgi/rendering.png -------------------------------------------------------------------------------- /examples/decoration/covid_jail/README.md: -------------------------------------------------------------------------------- 1 | # covid_jail 2 | 3 | This is a conceptual imitation of a COVID-19 particle inside of a cage. It is intended to be printed in color using Binder Jetting. 4 | 5 | # Renderings 6 | 7 | ![A rendering of a mock COVID molecule inside a cage.](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/covid_jail/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/covid_jail/rendering.png -------------------------------------------------------------------------------- /examples/decoration/cube_stack/README.md: -------------------------------------------------------------------------------- 1 | # cube_stack 2 | 3 | Create a stack of three colored cubes with rounded edges. This model is intended to be printed with Binder Jetting. As part of this design, only the bottom cube is filled in, while the others are hollow. A hole runs through the cubes out the bottom of the model to allow excess material to be removed from the top two cubes after printing. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the stack](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/cube_stack/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/cube_stack/rendering.png -------------------------------------------------------------------------------- /examples/decoration/curvy_thing/README.md: -------------------------------------------------------------------------------- 1 | # curvy-thing 2 | 3 | This example creates an abstract art piece by creating tubes around two algebraically-defined curves. First, the curves are approximated as 2D segments (an unclosed `model2d.Mesh`). Then, these line drawings are "thickened" using a `model2d.Collider`. 4 | 5 | # Renderings 6 | 7 | ![Renderings](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/curvy_thing/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/curvy_thing/rendering.png -------------------------------------------------------------------------------- /examples/decoration/cut_cube/README.md: -------------------------------------------------------------------------------- 1 | # cut-cube 2 | 3 | This demo creates a decorative container that is generated by cutting the corners off of a cube, and then cutting a hole in the top. 4 | 5 | # Rendering 6 | 7 | Here is a high-quality ray-traced rendering of the finished 3D model: 8 | 9 | ![Rendering](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/decoration/cut_cube/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/cut_cube/rendering.png -------------------------------------------------------------------------------- /examples/decoration/decision_tree/README.md: -------------------------------------------------------------------------------- 1 | # decision_tree 2 | 3 | This example creates a visual depiction of a binary decision tree. It isn't quite suitable for support-free printing, and I haven't tested how well it would balance. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the decision tree](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/decision_tree/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/decision_tree/rendering.png -------------------------------------------------------------------------------- /examples/decoration/diamond/README.md: -------------------------------------------------------------------------------- 1 | # diamond 2 | 3 | This example showcases the convex polytope API. In particular, a diamond shape is created as a system of linear inequalities, and then this system is turned into a mesh. 4 | 5 | As icing on the cake, we can turn the polytope into a Solid and cut it out of a circular stand. This stand must then be turned into a mesh with marching cubes, since it's not a convex polytope itself. 6 | 7 | # Renderings 8 | 9 | Here is the diamond: 10 | 11 | ![Renderings](rendering.png) 12 | 13 | Here is the stand: 14 | 15 | ![Renderings of the stand](rendering_stand.png) 16 | -------------------------------------------------------------------------------- /examples/decoration/diamond/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/diamond/rendering.png -------------------------------------------------------------------------------- /examples/decoration/diamond/rendering_stand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/diamond/rendering_stand.png -------------------------------------------------------------------------------- /examples/decoration/donut/README.md: -------------------------------------------------------------------------------- 1 | # donut 2 | 3 | This example creates a simplistic, multi-color 3D model that looks like a donut. The icing is created using an orthographic projection of a simple polar function, and the sprinkles are quasi-randomly laid out normal to the donut within the icing region. 4 | 5 | # Rendering 6 | 7 | Here is a rendering of the donut in color. It can also be printed in color, as it is exported in a multi-color format. 8 | 9 | ![Rendering of the color donut](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/decoration/donut/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/donut/rendering.png -------------------------------------------------------------------------------- /examples/decoration/dragon_egg/README.md: -------------------------------------------------------------------------------- 1 | # dragon_egg 2 | 3 | This example creates a prop dragon egg, with a stand so that it can be 3D printed and put up on display. 4 | 5 | # Renderings 6 | 7 | ![Renderings of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/dragon_egg/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/dragon_egg/rendering.png -------------------------------------------------------------------------------- /examples/decoration/globe/README.md: -------------------------------------------------------------------------------- 1 | # globe 2 | 3 | This example creates an FDM printable globe. It can be printed without supports because: 4 | 5 | * It is split into two halves 6 | * The continents jut out at 45 degrees or less, so no support is needed for them. 7 | 8 | # Renderings 9 | 10 | Here is the top: 11 | 12 | ![Top](rendering_top.png) 13 | 14 | Here is the bottom: 15 | 16 | ![Bottom](rendering_bottom.png) 17 | -------------------------------------------------------------------------------- /examples/decoration/globe/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/globe/map.png -------------------------------------------------------------------------------- /examples/decoration/globe/rendering_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/globe/rendering_bottom.png -------------------------------------------------------------------------------- /examples/decoration/globe/rendering_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/globe/rendering_top.png -------------------------------------------------------------------------------- /examples/decoration/gopher/README.md: -------------------------------------------------------------------------------- 1 | # gopher 2 | 3 | This is a 3D interpretation of the Golang mascot, the gopher. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the Gopher 3D model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/gopher/base.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/toolbox3d" 6 | ) 7 | 8 | func Base() (model3d.Solid, toolbox3d.CoordColorFunc) { 9 | return &model3d.Cylinder{ 10 | P1: model3d.Z(-0.5), 11 | P2: model3d.Z(-0.2), 12 | Radius: 1.5, 13 | }, toolbox3d.ConstantCoordColorFunc(BodyColor) 14 | } 15 | -------------------------------------------------------------------------------- /examples/decoration/gopher/body.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/render3d" 6 | "github.com/unixpickle/model3d/toolbox3d" 7 | ) 8 | 9 | var BodyColor = render3d.NewColorRGB(0x73/255.0, 0xce/255.0, 0xdd/255.0) 10 | 11 | func Body() (model3d.Solid, toolbox3d.CoordColorFunc) { 12 | c1 := &model3d.Capsule{ 13 | P1: model3d.XZ(-0.05, 0.5/0.8), 14 | P2: model3d.XZ(0.05, 0.5/0.8), 15 | Radius: 0.1 * 1.1, 16 | } 17 | c2 := &model3d.Sphere{ 18 | Center: model3d.Z(1.5 / 0.8), 19 | Radius: 0.1 * 1.1, 20 | } 21 | solid := model3d.MetaballSolid(nil, 0.82*1.1, c1, c2) 22 | squishedSolid := model3d.TransformSolid( 23 | &model3d.VecScale{Scale: model3d.XYZ(0.9, 0.7, 0.8)}, 24 | solid, 25 | ) 26 | return squishedSolid, toolbox3d.ConstantCoordColorFunc(BodyColor) 27 | } 28 | -------------------------------------------------------------------------------- /examples/decoration/gopher/eyes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | 6 | "github.com/unixpickle/model3d/model2d" 7 | "github.com/unixpickle/model3d/model3d" 8 | "github.com/unixpickle/model3d/render3d" 9 | "github.com/unixpickle/model3d/toolbox3d" 10 | ) 11 | 12 | func Eyes() (model3d.Solid, toolbox3d.CoordColorFunc) { 13 | ball := model3d.TranslateSolid( 14 | model3d.RotateSolid( 15 | model3d.VecScaleSolid( 16 | &model3d.Sphere{Radius: 0.3}, 17 | model3d.XYZ(1.0, 0.3, 1.0), 18 | ), 19 | model3d.X(1), 20 | 0.2, 21 | ), 22 | model3d.YZ(0.6, 1.7), 23 | ) 24 | combined := model3d.JoinedSolid{ 25 | model3d.TranslateSolid( 26 | model3d.RotateSolid(ball, model3d.Z(1), 0.3), 27 | model3d.X(-0.2), 28 | ), 29 | model3d.TranslateSolid( 30 | model3d.RotateSolid(ball, model3d.Z(1), -0.3), 31 | model3d.X(0.2), 32 | ), 33 | } 34 | return combined, func(c model3d.Coord3D) render3d.Color { 35 | c.X = math.Min(math.Abs(c.X-0.5), math.Abs(c.X+0.3)) 36 | dist := c.XZ().Dist(model2d.Y(1.7)) 37 | if dist < 0.1 { 38 | return render3d.NewColor(0) 39 | } else { 40 | return render3d.NewColor(1.0) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/decoration/gopher/feet.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/toolbox3d" 6 | ) 7 | 8 | var FeetColor = NoseColor 9 | 10 | func Feet() (model3d.Solid, toolbox3d.CoordColorFunc) { 11 | c1 := &model3d.Capsule{ 12 | P1: model3d.XYZ(0, 0.5, 0.1), 13 | P2: model3d.XYZ(0.05, 0.7, 0.0), 14 | Radius: 0.03, 15 | } 16 | c2 := &model3d.Capsule{ 17 | P1: model3d.XYZ(0.1, 0.5, 0.1), 18 | P2: model3d.XYZ(0.15, 0.7, 0.0), 19 | Radius: 0.03, 20 | } 21 | singleSolid := model3d.MetaballSolid(nil, 0.07, c1, c2) 22 | solid1 := model3d.TranslateSolid(singleSolid, model3d.XYZ(0.5, -0.2, -0.13)) 23 | solid2 := model3d.VecScaleSolid(solid1, model3d.XYZ(-1, 1, 1)) 24 | solid := model3d.JoinedSolid{solid1, solid2} 25 | return solid, toolbox3d.ConstantCoordColorFunc(FeetColor) 26 | } 27 | -------------------------------------------------------------------------------- /examples/decoration/gopher/hands.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/toolbox3d" 6 | ) 7 | 8 | var HandColor = NoseColor 9 | 10 | func Hands() (model3d.Solid, toolbox3d.CoordColorFunc) { 11 | c1 := &model3d.Capsule{ 12 | P1: model3d.XYZ(0, 0.1, 0.8), 13 | P2: model3d.XYZ(0.1, 0.12, 0.76), 14 | Radius: 0.03, 15 | } 16 | c2 := &model3d.Capsule{ 17 | P1: model3d.XYZ(0, 0.1, 0.7), 18 | P2: model3d.XYZ(0.1, 0.12, 0.66), 19 | Radius: 0.03, 20 | } 21 | singleSolid := model3d.MetaballSolid(nil, 0.07, c1, c2) 22 | solid1 := model3d.TranslateSolid(singleSolid, model3d.XZ(0.95, 0.05)) 23 | solid2 := model3d.VecScaleSolid(solid1, model3d.XYZ(-1, 1, 1)) 24 | solid := model3d.JoinedSolid{solid1, solid2} 25 | return solid, toolbox3d.ConstantCoordColorFunc(HandColor) 26 | } 27 | -------------------------------------------------------------------------------- /examples/decoration/gopher/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/render3d" 6 | "github.com/unixpickle/model3d/toolbox3d" 7 | ) 8 | 9 | func main() { 10 | base, baseColor := Base() 11 | body, bodyColor := Body() 12 | eyes, eyesColor := Eyes() 13 | ears, earsColor := Ears() 14 | nose, noseColor := Nose() 15 | teeth, teethColor := Teeth() 16 | hands, handsColor := Hands() 17 | feet, feetColor := Feet() 18 | solid := model3d.JoinedSolid{base, body, eyes, ears, nose, teeth, hands, feet} 19 | mesh, points := model3d.MarchingCubesInterior(solid, 0.01, 8) 20 | cf := toolbox3d.JoinedSolidCoordColorFunc( 21 | points, 22 | base, baseColor, 23 | body, bodyColor, 24 | eyes, eyesColor, 25 | ears, earsColor, 26 | nose, noseColor, 27 | teeth, teethColor, 28 | hands, handsColor, 29 | feet, feetColor, 30 | ) 31 | render3d.SaveRendering("rendering.png", mesh, model3d.XYZ(1, 5, 3), 512, 512, cf.RenderColor) 32 | mesh.SaveMaterialOBJ("gopher.zip", cf.TriangleColor) 33 | } 34 | -------------------------------------------------------------------------------- /examples/decoration/gopher/nose.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/render3d" 6 | "github.com/unixpickle/model3d/toolbox3d" 7 | ) 8 | 9 | var NoseColor = render3d.NewColorRGB(0xd9/255.0, 0xce/255.0, 0x98/255.0) 10 | 11 | func Nose() (model3d.Solid, toolbox3d.CoordColorFunc) { 12 | mound := &model3d.Torus{ 13 | Center: model3d.YZ(0.39, 1.0), 14 | Axis: model3d.YZ(-0.5, 0.55).Normalize(), 15 | InnerRadius: 0.18, 16 | OuterRadius: 0.28, 17 | } 18 | dot := model3d.TranslateSolid( 19 | model3d.VecScaleSolid( 20 | &model3d.Sphere{Radius: 0.1}, 21 | model3d.XYZ(1.0, 1.0, 0.8), 22 | ), 23 | model3d.YZ(0.68, 1.35), 24 | ) 25 | return model3d.JoinedSolid{mound, dot}, func(c model3d.Coord3D) render3d.Color { 26 | if dot.Contains(c) { 27 | return render3d.NewColor(0) 28 | } else { 29 | return NoseColor 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/decoration/gopher/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/gopher/rendering.png -------------------------------------------------------------------------------- /examples/decoration/gopher/teeth.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/render3d" 6 | "github.com/unixpickle/model3d/toolbox3d" 7 | ) 8 | 9 | func Teeth() (model3d.Solid, toolbox3d.CoordColorFunc) { 10 | tooth := &model3d.Capsule{ 11 | P1: model3d.YZ(0.69, 1.15), 12 | P2: model3d.YZ(0.69, 0.98), 13 | Radius: 0.055, 14 | } 15 | teeth := model3d.JoinedSolid{ 16 | model3d.TranslateSolid(tooth, model3d.X(-0.055)), 17 | model3d.TranslateSolid(tooth, model3d.X(0.055)), 18 | } 19 | return teeth, toolbox3d.ConstantCoordColorFunc(render3d.NewColor(1.0)) 20 | } 21 | -------------------------------------------------------------------------------- /examples/decoration/impossible_mug/README.md: -------------------------------------------------------------------------------- 1 | # impossible_mug 2 | 3 | Inspired by [this tweet](https://twitter.com/irinablok/status/1538573230184665093), I am creating an "impossible coffee mug" to have 3D printed. This mug has fake "coffee" inside of it, and is filled with holes. 4 | 5 | # Rendering 6 | 7 | ![Renderings of the impossible coffee mug](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/impossible_mug/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/impossible_mug/rendering.png -------------------------------------------------------------------------------- /examples/decoration/lamp/README.md: -------------------------------------------------------------------------------- 1 | # lamp 2 | 3 | This is a pair of optical illusions. First, a lamp shade appears to be floating above a lamp stand, but is actually attached to a neighboring plant. Second, the scene appears to be lit by the lamp using ray casting, so it can be printed in color and give the illusion that the lamp is actually casting light. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the lamp scene](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/lamp/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/lamp/rendering.png -------------------------------------------------------------------------------- /examples/decoration/lockbagel/README.md: -------------------------------------------------------------------------------- 1 | # lockbagel 2 | 3 | This is the first 3D model I designed with the Solid API. It shows how to create a non-trivial shape (a lock). It also demonstrates that you can 3D print interlocking shapes (a lock and a bagel). 4 | 5 | # Pictures 6 | 7 | Here's a picture of a real-life 3D print of the model created by this example: 8 | 9 | ![3D printed lock and bagel](printed_lockbagel.jpg) 10 | 11 | Here's a computer rendering: 12 | 13 | ![Rendering](rendering.png) 14 | -------------------------------------------------------------------------------- /examples/decoration/lockbagel/printed_lockbagel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/lockbagel/printed_lockbagel.jpg -------------------------------------------------------------------------------- /examples/decoration/lockbagel/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/lockbagel/rendering.png -------------------------------------------------------------------------------- /examples/decoration/makeup_brush/README.md: -------------------------------------------------------------------------------- 1 | # makeup brush 2 | 3 | This example creates an object that looks like a makeup brush. Intended to be printed in metal for use as a Monopoly piece. 4 | 5 | ![Rendering of model](rendering.png) 6 | -------------------------------------------------------------------------------- /examples/decoration/makeup_brush/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/makeup_brush/rendering.png -------------------------------------------------------------------------------- /examples/decoration/neural_network/README.md: -------------------------------------------------------------------------------- 1 | # neural_network 2 | 3 | This is a 3D representation of a small multilayer perceptron neural network. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the neural network model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/neural_network/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/neural_network/rendering.png -------------------------------------------------------------------------------- /examples/decoration/orange_slices/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/unixpickle/model3d/model3d" 7 | "github.com/unixpickle/model3d/render3d" 8 | ) 9 | 10 | const ( 11 | Epsilon = 0.003 12 | ) 13 | 14 | func main() { 15 | solid := model3d.JoinedSolid{ 16 | NewPeel(), 17 | NewWedge(-0.9999, -0.05), 18 | NewWedge(0.05, 0.9999), 19 | } 20 | 21 | log.Println("Creating mesh...") 22 | mesh := model3d.MarchingCubesSearch(solid, Epsilon, 8) 23 | 24 | log.Println("Rendering...") 25 | origin := model3d.XYZ(0.0, -2.0, 2.0) 26 | render3d.SaveRendering("rendering.png", mesh, origin, 1000, 1000, ColorFunc()) 27 | 28 | log.Println("Saving...") 29 | mesh.SaveGroupedSTL("peel.stl") 30 | } 31 | 32 | func ColorFunc() render3d.ColorFunc { 33 | peelMesh := PeelMesh(PeelStops / 2) 34 | peelSDF := model3d.MeshToSDF(peelMesh) 35 | return func(c model3d.Coord3D, rc model3d.RayCollision) render3d.Color { 36 | if peelSDF.SDF(c) > -(1e-3 + PeelRounding) { 37 | // Make the peel slightly brighter. 38 | return render3d.NewColorRGB(1.0, 0.63*1.1, 0.0) 39 | } 40 | return render3d.NewColorRGB(0.95, 0.60, 0.0) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/decoration/orange_slices/real.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/orange_slices/real.jpg -------------------------------------------------------------------------------- /examples/decoration/orange_slices/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/orange_slices/rendering.png -------------------------------------------------------------------------------- /examples/decoration/pickle/README.md: -------------------------------------------------------------------------------- 1 | # pickle 2 | 3 | This is a demo of creating a solid of revolution based on an outline. It leverages a `model2d.Collider` to slice the outline at each y value. 4 | 5 | The demo also overlays the orthographic projection of an inscription over the solid of revolution. This inscription can either be put into a different color, or can be etched out of the solid altogether. 6 | 7 | I had a small version of the etched model printed in metal. It makes a great piece for the Monopoly board game! 8 | 9 | # Renderings 10 | 11 | Here's the color version: 12 | 13 | ![A rendering of the color model](rendering_color.png) 14 | 15 | Here's the etched version: 16 | 17 | ![A rendering of the etched model](rendering_etched.png) 18 | -------------------------------------------------------------------------------- /examples/decoration/pickle/inscription.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/pickle/inscription.png -------------------------------------------------------------------------------- /examples/decoration/pickle/pickle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/pickle/pickle.png -------------------------------------------------------------------------------- /examples/decoration/pickle/rendering_color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/pickle/rendering_color.png -------------------------------------------------------------------------------- /examples/decoration/pickle/rendering_etched.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/pickle/rendering_etched.png -------------------------------------------------------------------------------- /examples/decoration/pumpkin/README.md: -------------------------------------------------------------------------------- 1 | # pumpkin 2 | 3 | This example shows how to create a [Jack-o'-lantern](https://en.wikipedia.org/wiki/Jack-o%27-lantern) with model3d solid primitives. 4 | 5 | The resulting model is two pieces (a lid and a body), and looks like this: 6 | 7 | ![Rendering of final model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/pumpkin/etching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/pumpkin/etching.png -------------------------------------------------------------------------------- /examples/decoration/pumpkin/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/pumpkin/rendering.png -------------------------------------------------------------------------------- /examples/decoration/pumpkin_v2/README.md: -------------------------------------------------------------------------------- 1 | # pumpkin_v2 2 | 3 | This example creates a simple pumpkin 3D model for 3D printing and then painting/decorating as you please. 4 | 5 | The base of the pumpkin is flattened out to make it easier to achieve good bed adhesion and reduce the amount of required support. 6 | 7 | # Renderings 8 | 9 | ![Renderings of the pumpkin](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/decoration/pumpkin_v2/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/pumpkin_v2/rendering.png -------------------------------------------------------------------------------- /examples/decoration/rock/README.md: -------------------------------------------------------------------------------- 1 | # rock 2 | 3 | This example creates rock-like objects using the `model3d.ConvexPolytope` API. A convex polytope is a system of linear inequalities, i.e. the space contained within a set of planes. It is easy to triangulate such systems (at least, when they are small). It is also easy to generate cool-looking randomized convex polytopes, as this example shows. 4 | 5 | # Rendering 6 | 7 | ![Rocks rendering](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/rock/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/rock/rendering.png -------------------------------------------------------------------------------- /examples/decoration/rose/README.md: -------------------------------------------------------------------------------- 1 | # rose 2 | 3 | This example creates a 3D flower model by creating flat petals and then thickening them using a `model3d.Collider`. 4 | 5 | # Renderings 6 | 7 | ![Renderings of the rose](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/rose/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/rose/rendering.png -------------------------------------------------------------------------------- /examples/decoration/rubiks_cube/README.md: -------------------------------------------------------------------------------- 1 | # rubiks cube 2 | 3 | This is a simple model of a rubik's cube (with no color). It is intended to be printed in metal for use as a Monopoly piece. 4 | 5 | ![Rendering of model](rendering.png) 6 | -------------------------------------------------------------------------------- /examples/decoration/rubiks_cube/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/rubiks_cube/rendering.png -------------------------------------------------------------------------------- /examples/decoration/sand_castle/README.md: -------------------------------------------------------------------------------- 1 | # sand_castle 2 | 3 | You are never too old to build a sand castle on the beach. Or on your computer. This is perfect for printing in sandstone. 4 | 5 | # Renderings 6 | 7 | ![Rendering of the sand castle](rendering.png) -------------------------------------------------------------------------------- /examples/decoration/sand_castle/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/sand_castle/rendering.png -------------------------------------------------------------------------------- /examples/decoration/sand_castle/text_imprint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/sand_castle/text_imprint.png -------------------------------------------------------------------------------- /examples/decoration/snake_table/README.md: -------------------------------------------------------------------------------- 1 | # snake_table 2 | 3 | This is a table design I originally stumbled across on twitter. It is a single piece that balances and supports weight in a "mysterious" way. 4 | 5 | # Renderings 6 | 7 | ![Renderings of the table](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/snake_table/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/snake_table/rendering.png -------------------------------------------------------------------------------- /examples/decoration/starfish/README.md: -------------------------------------------------------------------------------- 1 | # starfish 2 | 3 | This example creates a starfish with five arms. 4 | 5 | Each arm is represented as a Bezier curve eminating from the origin. At the origin, the thickness of each arm is at its maximum, and it linearly decreases throughout the length of the arm until a minimum value at the end of the Bezier curve. We then turn this 2D structure into a 3D structure. 6 | 7 | Given a 3D point `c`, we project it onto the xy plane (`p`) and then further project this point onto the Bezier curve (`p1`). The thickness for `p1` is then calculated. For `c` to be in the solid, `abs(||p-p1||) + abs(c.z)` must be less than the thickness. This produces a triangular shape, while still maintaining smoothness along Z cross-sections. Projections and thickness calculations are performed on a discretized version of the Bezier curves, for ease of computation. 8 | 9 | # Rendering 10 | 11 | ![Rendering of the starfish](rendering.png) 12 | -------------------------------------------------------------------------------- /examples/decoration/starfish/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/starfish/rendering.png -------------------------------------------------------------------------------- /examples/decoration/three_axis_chain/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/three_axis_chain/rendering.png -------------------------------------------------------------------------------- /examples/decoration/tiffany_tree/README.md: -------------------------------------------------------------------------------- 1 | # tiffany-tree 2 | 3 | This is a clone of a [Tiffany tree ornament](https://www.tiffany.com/accessories/holiday-ornaments/tree-ornament-69147747/). 4 | 5 | # Renderings 6 | 7 | ![Renderings of the ornament](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/tiffany_tree/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/tiffany_tree/rendering.png -------------------------------------------------------------------------------- /examples/decoration/tree/README.md: -------------------------------------------------------------------------------- 1 | # tree 2 | 3 | This example shows how to create a 3D model of a leafless tree. 4 | 5 | ![Rendering of the resulting tree](rendering.png) 6 | -------------------------------------------------------------------------------- /examples/decoration/tree/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/tree/rendering.png -------------------------------------------------------------------------------- /examples/decoration/tree_ornament/README.md: -------------------------------------------------------------------------------- 1 | # tree_ornament 2 | 3 | This is a 3D-printable topper or ornament for a [Christmas tree](https://en.wikipedia.org/wiki/Christmas_tree). It is a six-pointed star (i.e. a [Star of David](https://en.wikipedia.org/wiki/Star_of_David)), in order to mix the two traditions. 4 | 5 | The star includes a small cone on the bottom of it to help it stay on a tree. However, if it does not rest soundfully on the tree, this demo also includes a 3D-printable hook to mount to a wall or a nearby surface and use to hang the star. 6 | 7 | # Renderings 8 | 9 | Here is a rendering of the star decoration itself: 10 | 11 | ![Star ornament/topper](rendering_star.png) 12 | 13 | Here is the wall-mountable hanger that you may choose to use if the star does not balance on the tree: 14 | 15 | ![Mountable hook](rendering_hanger.png) 16 | -------------------------------------------------------------------------------- /examples/decoration/tree_ornament/rendering_hanger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/tree_ornament/rendering_hanger.png -------------------------------------------------------------------------------- /examples/decoration/tree_ornament/rendering_star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/tree_ornament/rendering_star.png -------------------------------------------------------------------------------- /examples/decoration/vase/README.md: -------------------------------------------------------------------------------- 1 | # vase 2 | 3 | This cylindrical-coordinate vase is conceptually simple, but very nice looking. The radius is defined by a high-frequency function radially, combined with a low-frequency curve going up the z-axis. 4 | 5 | The vase can be printed support-free with FDM, and it really does hold water! 6 | 7 | # Renderings 8 | 9 | ![Renderings](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/decoration/vase/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/vase/rendering.png -------------------------------------------------------------------------------- /examples/decoration/wall_flower/README.md: -------------------------------------------------------------------------------- 1 | # wall-flower 2 | 3 | This is a flower decoration that you can print out in batches and attach to your walls. 4 | 5 | # How it works 6 | 7 | The model is generated by first constructing the six-pedal flower in 2D polar coordinates. This looks like this: 8 | 9 | vector flower shape 10 | 11 | To turn this 2D shape into a 3D object, it is projected onto the bottom of a sphere, causing it to be rounded with the pedals sticking up. Finally, this flat shape is made thick by extending it 0.1 inches in every direction. 12 | 13 | In other words, to tell if a point `C` is within the flower, it is first projected onto the sphere, and then further projected onto the flower shape that was projected onto the sphere. This gives a point `P`. If `||C - P|| < 0.1`, then C is within the flower. 14 | 15 | # Renderings 16 | 17 | ![Renderings](rendering.png) 18 | -------------------------------------------------------------------------------- /examples/decoration/wall_flower/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/wall_flower/rendering.png -------------------------------------------------------------------------------- /examples/decoration/wall_sun/README.md: -------------------------------------------------------------------------------- 1 | # wall_sun 2 | 3 | This is a decoration meant to be printed in yellow or gold filament and mounted to the wall. It looks like a cartoon sun, with ripples to add texture, and points on the edges to signify light. 4 | 5 | # Renderings 6 | 7 | ![Rendering of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/decoration/wall_sun/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/wall_sun/rendering.png -------------------------------------------------------------------------------- /examples/decoration/xmas_tree/README.md: -------------------------------------------------------------------------------- 1 | # xmas_tree 2 | 3 | A printable Xmas tree design based on [this Tweet](https://twitter.com/3DPrintBunny/status/1472426896474337282). 4 | 5 | # Rendering 6 | 7 | Here is a rendering of the main tree: 8 | 9 | ![Rendering of main tree](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/decoration/xmas_tree/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/xmas_tree/rendering.png -------------------------------------------------------------------------------- /examples/decoration/zigzag_egg/README.md: -------------------------------------------------------------------------------- 1 | # zigzag_egg 2 | 3 | This example composes a number of 2D and 3D shapes to produce an egg-like solid with a zig-zag pattern on its surface. 4 | 5 | # How it works 6 | 7 | First, an egg shape is created from a bezier curve. A smaller egg is also created, and a zig zag is generated between the smaller and larger egg: 8 | 9 | ![Vertical zig zag rendering](zig_zag.png) 10 | 11 | To create the zig-zag going side to side up the egg, a zig-zaggy plane is created and rotated around the Z axis many times. The union of these two patterns, intersected with an egg shape (and a cylindrical base) look like this: 12 | 13 | ![Rendering](rendering.png) 14 | -------------------------------------------------------------------------------- /examples/decoration/zigzag_egg/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/zigzag_egg/rendering.png -------------------------------------------------------------------------------- /examples/decoration/zigzag_egg/zig_zag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/decoration/zigzag_egg/zig_zag.png -------------------------------------------------------------------------------- /examples/experiments/convex_globe/README.md: -------------------------------------------------------------------------------- 1 | # convex-globe 2 | 3 | This was an experiment to see how well a globe (with continents jutting out) could be approximated as a convex polytope. Turns out, not well! 4 | 5 | # Rendering 6 | 7 | ![Rendering of the result](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/experiments/convex_globe/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/convex_globe/map.png -------------------------------------------------------------------------------- /examples/experiments/convex_globe/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/convex_globe/rendering.png -------------------------------------------------------------------------------- /examples/experiments/decimation/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "math/rand" 6 | "time" 7 | 8 | "github.com/unixpickle/model3d/model3d" 9 | ) 10 | 11 | func main() { 12 | rand.Seed(time.Now().UnixNano()) 13 | 14 | model := &model3d.Sphere{Radius: 1.0} 15 | mesh := model3d.MarchingCubesSearch(model, 0.01, 8) 16 | numTris := len(mesh.TriangleSlice()) 17 | log.Printf("original: triangles=%d error=%e", numTris, MeanError(model, mesh)) 18 | 19 | for eps := 0.0005; eps < 0.1; eps *= 1.5 { 20 | dec := &model3d.Decimator{ 21 | PlaneDistance: eps, 22 | BoundaryDistance: eps, 23 | } 24 | mesh1 := dec.Decimate(mesh) 25 | numTris1 := len(mesh1.TriangleSlice()) 26 | log.Printf("eps %f: triangles=%d error=%e", eps, numTris1, MeanError(model, mesh1)) 27 | } 28 | } 29 | 30 | func MeanError(model model3d.SDF, mesh *model3d.Mesh) float64 { 31 | meshSDF := model3d.MeshToSDF(mesh) 32 | totalMSE := 0.0 33 | count := 0.0 34 | for i := 0; i < 10000; i++ { 35 | p := model3d.NewCoord3DRandBounds(model.Min(), model.Max()) 36 | real := model.SDF(p) 37 | approx := meshSDF.SDF(p) 38 | totalMSE += (real - approx) * (real - approx) 39 | count += 1 40 | } 41 | return totalMSE / count 42 | } 43 | -------------------------------------------------------------------------------- /examples/experiments/disc_with_cutout/README.md: -------------------------------------------------------------------------------- 1 | # disc_with_cutout 2 | 3 | This is a reproduction of an optical illusion that I recently saw. A disk with a seemingly straight pole coming out of it can be rotated, and pass through a curved slit that visually looks like it should collide with the pole. 4 | 5 | This program produces two meshes: one for the disc, and one for the board (with the "barrier/obstacle" attached to it). The disc can slide into place on the board (thanks to the slit), and hash a groove which matches a groove in the board. 6 | 7 | # Rendering 8 | 9 | Here are two different rotations of this illusion: 10 | 11 | ![Rendering of the illusion, number 1](rendering1.png) 12 | 13 | ![Rendering of the illusion, number 2](rendering2.png) 14 | -------------------------------------------------------------------------------- /examples/experiments/disc_with_cutout/rendering1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/disc_with_cutout/rendering1.png -------------------------------------------------------------------------------- /examples/experiments/disc_with_cutout/rendering2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/disc_with_cutout/rendering2.png -------------------------------------------------------------------------------- /examples/experiments/fix_mask/README.md: -------------------------------------------------------------------------------- 1 | # fix-mask 2 | 3 | This little program modifies an open-source face mask STL file to be easier to print with Cura on an FDM printer. In particular, it orients the model flatly, removes the need for support in the strap holes, and prints a tighter cover for the filter. 4 | 5 | See the top of [main.go](main.go) for details. 6 | -------------------------------------------------------------------------------- /examples/experiments/geneva_drive/README.md: -------------------------------------------------------------------------------- 1 | # geneva-drive 2 | 3 | This experiment creates a working, printable [Geneva drive](https://en.wikipedia.org/wiki/Geneva_drive). The Geneva drive is constructed by printing two gears (a drive and a driven gear), a board, and two screws. The screws attach the gears to the board, while allowing the gears to spin around freely. 4 | 5 | I actually printed this design, and it works very well! 6 | 7 | # Rendering 8 | 9 | The resulting model (minus the screws) looks like this: 10 | 11 | ![Rendering of the models put together](rendering.png) 12 | 13 | During the debugging stage, I also created a rendering of the gear profiles: 14 | 15 | ![Rendering of the profiles](rendering_profiles.svg) 16 | 17 | The program also produces an animated GIF of the Geneva drive in operation. However, it is not included here to save space. 18 | -------------------------------------------------------------------------------- /examples/experiments/geneva_drive/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/geneva_drive/rendering.png -------------------------------------------------------------------------------- /examples/experiments/hemisphere_param/README.md: -------------------------------------------------------------------------------- 1 | # hemisphere_param 2 | 3 | This example maps a hemisphere (approximated by an icosphere) onto a unit square. 4 | 5 | The resulting triangulation rendered to a file: 6 | 7 | ![Rendering of the mesh grid](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/experiments/hemisphere_param/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model2d" 5 | "github.com/unixpickle/model3d/model3d" 6 | ) 7 | 8 | func main() { 9 | sphere := model3d.NewMeshIcosphere(model3d.Origin, 5.0, 8) 10 | sphere.Iterate(func(t *model3d.Triangle) { 11 | if t.Min().Z < 0 { 12 | sphere.Remove(t) 13 | } 14 | }) 15 | 16 | param := model3d.Floater97( 17 | sphere, 18 | model3d.SquareBoundary(sphere), 19 | model3d.Floater97ShapePreservingWeights(sphere), 20 | nil, 21 | ) 22 | 23 | mesh2d := model2d.NewMesh() 24 | sphere.Iterate(func(t *model3d.Triangle) { 25 | for _, s := range t.Segments() { 26 | s2 := &model2d.Segment{ 27 | param.Value(s[0]), 28 | param.Value(s[1]), 29 | } 30 | if len(mesh2d.Find(s2[0], s2[1])) == 0 { 31 | mesh2d.Add(s2) 32 | } 33 | } 34 | }) 35 | 36 | model2d.Rasterize("rendering.png", mesh2d, 100.0) 37 | } 38 | -------------------------------------------------------------------------------- /examples/experiments/hemisphere_param/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/hemisphere_param/rendering.png -------------------------------------------------------------------------------- /examples/experiments/interlocking/README.md: -------------------------------------------------------------------------------- 1 | # interlocking 2 | 3 | This was my first FDM print that generates interlocking parts (and without using any support structures!). It is two interlocking triangles. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the interlocking parts](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/experiments/interlocking/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/interlocking/rendering.png -------------------------------------------------------------------------------- /examples/experiments/pillow/README.md: -------------------------------------------------------------------------------- 1 | # pillow 2 | 3 | These experiments try to address the question "how do we turn a 2D shape into a rounded, smooth, 3D model". The constraints are: 4 | 5 | 1. Circles turn into spheres 6 | 2. Smooth 2D shapes turn into smooth 3D shapes 7 | 8 | I find [pillow_medial](pillow_medial) to be the most compelling, as it creates the best 3D heart shape. 9 | -------------------------------------------------------------------------------- /examples/experiments/pillow/pillow_ellipses/README.md: -------------------------------------------------------------------------------- 1 | # pillow-ellipses 2 | 3 | This is an experiment to generate rounded 3D shapes from 2D shapes. For this method, we first select a center point in the 2D shape and convert the shape to polar coordinates (theta, r(theta)). To extend this shape on the xy plane into the z axis, we create ellipses eminating from the center, with central axis given by `z` and `(cos(theta), sin(theta))`. We use a constant radius along the z axis and `r(theta)` along the other axis. In the case of the original 2D shape being a circle, this method can produce a sphere (possibly squished or stretched along the `z` axis depending on our choice of radius there). 4 | 5 | The goal of this experiment is similar to [pillow_medial](../pillow_medial) and [pillow_sphere](../pillow_sphere). However, this particular method is less general since it requires the 2D shape to be a function in polar coordinates. I was hoping that the freedom to choose a center point would make this method a bit more tailorable to the specific 3D heart example I was interested in. 6 | 7 | # Renderings 8 | 9 | Here is what happens when you apply the algorithm to a heart shape: 10 | 11 | ![Renderings of the 3D heart](rendering.png) 12 | -------------------------------------------------------------------------------- /examples/experiments/pillow/pillow_ellipses/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/pillow/pillow_ellipses/rendering.png -------------------------------------------------------------------------------- /examples/experiments/pillow/pillow_medial/README.md: -------------------------------------------------------------------------------- 1 | # pillow-2d-shape 2 | 3 | This is an experiment to generate rounded 3D shapes from 2D shapes. 4 | 5 | This rounding algorithm is inspired by the fact that 2D shapes have natural extensions into 3D. For example, a circle naturally becomes a sphere, a square becomes a pillow-like shape, a heart becomes a rounded and smooth heart-like object, etc. 6 | 7 | To extend the above observation to arbitrary shapes, we fill the 2D solid with circles, and then turn those circles into spheres. 8 | 9 | # Renderings 10 | 11 | Here is what happens when you apply the algorithm to a heart shape: 12 | 13 | ![Renderings of the 3D heart](rendering.png) 14 | -------------------------------------------------------------------------------- /examples/experiments/pillow/pillow_medial/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/pillow/pillow_medial/rendering.png -------------------------------------------------------------------------------- /examples/experiments/pillow/pillow_sdf/README.md: -------------------------------------------------------------------------------- 1 | # pillow-sphere 2 | 3 | This is an experiment to generate rounded 3D shapes from 2D shapes by insetting their SDF according to the radius of a sphere. The goal is similar to [pillow_medial](../pillow_medial), but the results do not look nearly as compelling. Also see [pillow_sphere](../pillow_sphere). The main difference from `pillow_sphere` is that we instead use the maximum of the SDF instead of 1, potentially preventing odd behavior for asymmetrical shapes. 4 | 5 | # Renderings 6 | 7 | Here is what happens when you apply the algorithm to a heart shape: 8 | 9 | ![Renderings of the 3D heart](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/experiments/pillow/pillow_sdf/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/pillow/pillow_sdf/rendering.png -------------------------------------------------------------------------------- /examples/experiments/pillow/pillow_sphere/README.md: -------------------------------------------------------------------------------- 1 | # pillow-sphere 2 | 3 | This is an experiment to generate rounded 3D shapes from 2D shapes by shrinking them according to the radius of a sphere. The goal is similar to [pillow_medial](../pillow_medial), but the results do not look nearly as compelling. 4 | 5 | # Renderings 6 | 7 | Here is what happens when you apply the algorithm to a heart shape: 8 | 9 | ![Renderings of the 3D heart](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/experiments/pillow/pillow_sphere/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/pillow/pillow_sphere/rendering.png -------------------------------------------------------------------------------- /examples/experiments/plot_2d_sdf/README.md: -------------------------------------------------------------------------------- 1 | # plot-2d-sdf 2 | 3 | This example plots a two-dimensional signed distance field for any simple 2D shape (encoded as an image). The signed distance field is plotted using a color code, so that blue is positive and red is negative; intensity is used to indicate magnitude. 4 | 5 | This is intended to help visualize how the signed distance field behaves inside of a shape: where it changes derivatives, sign, magnitude, etc. It also helps visualize local minima and saddle points in the SDF landscape. 6 | 7 | # Output 8 | 9 | Here is an example output, which takes in the heart image on the left, and produces the distance field on the right: 10 | 11 | ![Example rendering](example.png) 12 | -------------------------------------------------------------------------------- /examples/experiments/plot_2d_sdf/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/plot_2d_sdf/example.png -------------------------------------------------------------------------------- /examples/experiments/plot_polar_shape/README.md: -------------------------------------------------------------------------------- 1 | # plot_polar_shape 2 | 3 | Some images (e.g. cartoon hearts) are naturally defined in polar coordinates, yet it may be hard to visualize what the radius function looks like when they are plotted. This tool helps "unwind" a polar function and plots it into an xy-graph, where the x axis is theta and the y axis is radius. 4 | -------------------------------------------------------------------------------- /examples/experiments/shadow_text/README.md: -------------------------------------------------------------------------------- 1 | # shadow_text 2 | 3 | Create a 3D shape whose shadow is a pre-specified 2D path. 4 | 5 | You can create a new path using [draw_path.html](draw_path.html). Extract the JSON and gzip it, then specify `-path path/to/file.json.gz`. 6 | 7 | # Renderings 8 | 9 | Here's the model from the light's point of view 10 | 11 | ![Rendering of the model from the light position](rendering_direct.png) 12 | 13 | Here's the model from random points of view: 14 | 15 | ![Rendering of the model from other directions](rendering.png) 16 | -------------------------------------------------------------------------------- /examples/experiments/shadow_text/paths/hello.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/shadow_text/paths/hello.json.gz -------------------------------------------------------------------------------- /examples/experiments/shadow_text/paths/nug.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/shadow_text/paths/nug.json.gz -------------------------------------------------------------------------------- /examples/experiments/shadow_text/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/shadow_text/rendering.png -------------------------------------------------------------------------------- /examples/experiments/shadow_text/rendering_direct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/shadow_text/rendering_direct.png -------------------------------------------------------------------------------- /examples/experiments/smooth_join_2d/images/easy_case_input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_join_2d/images/easy_case_input.png -------------------------------------------------------------------------------- /examples/experiments/smooth_join_2d/images/easy_case_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_join_2d/images/easy_case_v1.png -------------------------------------------------------------------------------- /examples/experiments/smooth_join_2d/images/easy_case_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_join_2d/images/easy_case_v2.png -------------------------------------------------------------------------------- /examples/experiments/smooth_join_2d/images/middle_case_input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_join_2d/images/middle_case_input.png -------------------------------------------------------------------------------- /examples/experiments/smooth_join_2d/images/middle_case_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_join_2d/images/middle_case_v1.png -------------------------------------------------------------------------------- /examples/experiments/smooth_join_2d/images/middle_case_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_join_2d/images/middle_case_v2.png -------------------------------------------------------------------------------- /examples/experiments/smooth_join_2d/images/parallel_case_input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_join_2d/images/parallel_case_input.png -------------------------------------------------------------------------------- /examples/experiments/smooth_join_2d/images/parallel_case_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_join_2d/images/parallel_case_v1.png -------------------------------------------------------------------------------- /examples/experiments/smooth_join_2d/images/parallel_case_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_join_2d/images/parallel_case_v2.png -------------------------------------------------------------------------------- /examples/experiments/smooth_shape/README.md: -------------------------------------------------------------------------------- 1 | # smooth_shape 2 | 3 | This program uses the `model2d` package to read a raster image of a shape, vectorize it, smooth it out, and save a higher-resolution version of the same image. 4 | 5 | # Results 6 | 7 | I've included a test image for reference. Run this command to reproduce this result: 8 | 9 | ``` 10 | $ go run . input.png output.png 11 | ``` to reproduce these results. 12 | 13 | In this example, we take a blurry raster image like so: 14 | 15 | ![input pickle](input.png) 16 | 17 | and produce a much crisper image in 2x the original resolution: 18 | 19 | ![output pickle](output.png) 20 | -------------------------------------------------------------------------------- /examples/experiments/smooth_shape/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_shape/input.png -------------------------------------------------------------------------------- /examples/experiments/smooth_shape/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/smooth_shape/output.png -------------------------------------------------------------------------------- /examples/experiments/telescoping/README.md: -------------------------------------------------------------------------------- 1 | # telescoping 2 | 3 | This is an attempt to make a series of interlocking telescoping tubes in a single print. In particular, this demo creates a model consisting of three interlocking tubes, which can be extended outward, but cannot be separated. See [Whip antenna](https://en.wikipedia.org/wiki/Whip_antenna). 4 | 5 | To allow printing on an FDM printer, the notches in the tubes are triangular, extending at a 45 degree angle, to avoid the need for supports. 6 | 7 | # Rendering 8 | 9 | Here is a rendering of the first attempt: 10 | 11 | ![Rendering of the model](rendering.png) 12 | -------------------------------------------------------------------------------- /examples/experiments/telescoping/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/telescoping/rendering.png -------------------------------------------------------------------------------- /examples/experiments/topology_puzzle/renderings/board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/topology_puzzle/renderings/board.png -------------------------------------------------------------------------------- /examples/experiments/topology_puzzle/renderings/board_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/topology_puzzle/renderings/board_bottom.png -------------------------------------------------------------------------------- /examples/experiments/topology_puzzle/renderings/bottom_holder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/topology_puzzle/renderings/bottom_holder.png -------------------------------------------------------------------------------- /examples/experiments/topology_puzzle/renderings/other_holder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/experiments/topology_puzzle/renderings/other_holder.png -------------------------------------------------------------------------------- /examples/parody/cable_car/README.md: -------------------------------------------------------------------------------- 1 | # cable_car 2 | 3 | This is a parody of the famous San Francisco cable car. It exports as two pieces: a body, and a separate "roof" (really a lid that can slide into the body). There is text on the side, which can be customized by changing the image `text.png`. 4 | 5 | This is loosely modeled after this [toy cable car](https://www.amazon.com/City-Souvenirs-Musical-Francisco-Wooden-Replica/dp/B07X4JM6C4). 6 | -------------------------------------------------------------------------------- /examples/parody/cable_car/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/cable_car/rendering.png -------------------------------------------------------------------------------- /examples/parody/cable_car/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/cable_car/text.png -------------------------------------------------------------------------------- /examples/parody/dumbell/README.md: -------------------------------------------------------------------------------- 1 | # dumbell 2 | 3 | Ever wanted to fool someone into thinking you work out? Now you can! Just print this fake dumbell in dark filament, and people will never know you are lifting a hollow piece of plastic. 4 | 5 | # Renderings 6 | 7 | The primary model is two side-pieces that look like this: 8 | 9 | ![Rendering of side](rendering_side.png) 10 | 11 | Then you can print out a pole to stick into both sides and hold: 12 | 13 | ![Rendering of bar](rendering_bar.png) 14 | -------------------------------------------------------------------------------- /examples/parody/dumbell/rendering_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/dumbell/rendering_bar.png -------------------------------------------------------------------------------- /examples/parody/dumbell/rendering_side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/dumbell/rendering_side.png -------------------------------------------------------------------------------- /examples/parody/flag_statue/README.md: -------------------------------------------------------------------------------- 1 | # flag-statue 2 | 3 | This is a parody of the statue [Raising the Flag on Iwo Jima](https://en.wikipedia.org/wiki/Raising_the_Flag_on_Iwo_Jima). My parents were holding on to a replica of this statue for a while, and my mom wanted it out. Once they finally got rid of it, I printed a small parody of the statue as a joke. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the statue](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/parody/flag_statue/flag.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | 6 | "github.com/unixpickle/model3d/model3d" 7 | ) 8 | 9 | const ( 10 | FlagHeight = 5.0 11 | FlagWidth = 1.5 12 | FlagThickness = 0.1 13 | FlagPoleRadius = 0.1 14 | 15 | FlagRippleRate = math.Pi * 2 16 | FlagRippleDepth = 0.1 17 | ) 18 | 19 | func GenerateFlag() model3d.Solid { 20 | return model3d.JoinedSolid{ 21 | &model3d.Cylinder{ 22 | P2: model3d.Z(FlagHeight), 23 | Radius: FlagPoleRadius, 24 | }, 25 | FlagFabric(), 26 | } 27 | } 28 | 29 | func FlagFabric() model3d.Solid { 30 | return model3d.CheckedFuncSolid( 31 | model3d.XYZ(0, -FlagThickness/2-FlagRippleDepth*2, FlagHeight-FlagWidth), 32 | model3d.XYZ(FlagWidth, FlagThickness/2+FlagRippleDepth*2, FlagHeight), 33 | func(c model3d.Coord3D) bool { 34 | if math.Abs(c.Y-FlagRippleDepth*math.Sin(c.X*FlagRippleRate)) > FlagThickness { 35 | return false 36 | } 37 | return c.X < c.Z-(FlagHeight-FlagWidth) 38 | }, 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /examples/parody/flag_statue/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/unixpickle/model3d/model3d" 7 | "github.com/unixpickle/model3d/render3d" 8 | ) 9 | 10 | func main() { 11 | solid := model3d.JoinedSolid{ 12 | GenerateBase(), 13 | GenerateFlag(), 14 | GeneratePeople(), 15 | } 16 | 17 | log.Println("Creating mesh...") 18 | m := model3d.MarchingCubesSearch(solid, 0.02, 8).Blur(-1, -1, -1, -1, -1) 19 | 20 | log.Println("Saving mesh...") 21 | m.SaveGroupedSTL("statue.stl") 22 | 23 | log.Println("Saving rendering...") 24 | render3d.SaveRendering("rendering.png", m, model3d.Coord3D{Y: -10, Z: 5.5}, 900, 900, nil) 25 | } 26 | -------------------------------------------------------------------------------- /examples/parody/flag_statue/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/flag_statue/rendering.png -------------------------------------------------------------------------------- /examples/parody/gl_inet/README.md: -------------------------------------------------------------------------------- 1 | # gl_inet 2 | 3 | This is a box with a lid that looks like a [GL.iNet Mango wireless router](https://www.amazon.com/GL-iNET-GL-MT300N-V2-Repeater-300Mbps-Performance/dp/B073TSK26W/ref=asc_df_B073TSK26W/). The real router looks like this: 4 | 5 | ![Small Amazon thumbnail of the GL.iNet router product](glinet.jpg) 6 | 7 | # Rendering 8 | 9 | Here is a rendering of the body of the model, not including the lid (which itself has three holes for "lights", but is otherwise quite plain): 10 | 11 | ![Rendering of the GL.iNet parody box](rendering.png) -------------------------------------------------------------------------------- /examples/parody/gl_inet/glinet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/gl_inet/glinet.jpg -------------------------------------------------------------------------------- /examples/parody/gl_inet/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/gl_inet/rendering.png -------------------------------------------------------------------------------- /examples/parody/golden_gate/README.md: -------------------------------------------------------------------------------- 1 | # golden_gate 2 | 3 | This example creates a colorful 3D model that imitates the [Golden Gate Bridge](https://en.wikipedia.org/wiki/Golden_Gate_Bridge). The model is not realistic or to scale. Instead, it is intended to be printable with Binder Jetting or some other color 3D printing process. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the parody Golden Gate Bridge](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/parody/golden_gate/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/golden_gate/rendering.png -------------------------------------------------------------------------------- /examples/parody/place_setting/README.md: -------------------------------------------------------------------------------- 1 | # place-setting 2 | 3 | This is a work in progress parody of a dinner place setting. 4 | 5 | It includes a wine glass generated with revolved Bezier curves. It also includes a fork 3D model with a shape derived from two Bezier curves. 6 | 7 | # Renderings 8 | 9 | Here is the wine glass: 10 | 11 | ![Rendering of the wine glass](rendering_wine_glass.png) 12 | 13 | Here is the fork: 14 | 15 | ![Rendering of the fork](rendering_fork.png) 16 | -------------------------------------------------------------------------------- /examples/parody/place_setting/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/unixpickle/model3d/render3d" 7 | 8 | "github.com/unixpickle/model3d/model3d" 9 | ) 10 | 11 | func main() { 12 | log.Println("Creating fork...") 13 | fork := model3d.MarchingCubesSearch(NewForkSolid(), 0.01, 8) 14 | fork.SaveGroupedSTL("fork.stl") 15 | render3d.SaveRandomGrid("rendering_fork.png", fork, 3, 3, 300, nil) 16 | 17 | log.Println("Creating wine glass...") 18 | wineGlass := model3d.MarchingCubesSearch(CreateWineGlass(), 0.02, 8) 19 | wineGlass.SaveGroupedSTL("wine_glass.stl") 20 | render3d.SaveRandomGrid("rendering_wine_glass.png", wineGlass, 3, 3, 300, nil) 21 | } 22 | -------------------------------------------------------------------------------- /examples/parody/place_setting/rendering_fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/place_setting/rendering_fork.png -------------------------------------------------------------------------------- /examples/parody/place_setting/rendering_wine_glass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/place_setting/rendering_wine_glass.png -------------------------------------------------------------------------------- /examples/parody/swiss_cheese/README.md: -------------------------------------------------------------------------------- 1 | # swiss-cheese 2 | 3 | I'll be honest, I only made this because I bought yellow filament for my printer and didn't know what to print. 4 | 5 | # Renderings 6 | 7 | ![Rendering of the cheese](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/parody/swiss_cheese/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/parody/swiss_cheese/rendering.png -------------------------------------------------------------------------------- /examples/renderings/ball_physics/README.md: -------------------------------------------------------------------------------- 1 | # ball-physics 2 | 3 | This demo simulates ball-model collisions using the `model3d.PointSDF` API. It renders the resulting animation using bidirectional path tracing. 4 | -------------------------------------------------------------------------------- /examples/renderings/ball_physics/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "math" 7 | "os" 8 | "path/filepath" 9 | 10 | "github.com/unixpickle/model3d/model3d" 11 | "github.com/unixpickle/model3d/render3d" 12 | ) 13 | 14 | func main() { 15 | log.Println("Creating scene...") 16 | scene := NewScene() 17 | 18 | log.Println("Rendering...") 19 | 20 | renderer := &render3d.BidirPathTracer{ 21 | Camera: render3d.NewCameraAt(model3d.Coord3D{Y: -RoomDepth + 0.1, Z: RoomHeight / 3}, 22 | model3d.Coord3D{Y: 0, Z: RoomHeight / 3}, math.Pi/3.6), 23 | 24 | MaxDepth: 15, 25 | MinDepth: 3, 26 | NumSamples: 40, 27 | RouletteDelta: 0.2, 28 | Antialias: 1.0, 29 | Cutoff: 1e-4, 30 | } 31 | 32 | os.Mkdir("frames", 0755) 33 | 34 | for i := 0; i < 50; i++ { 35 | log.Println("Rendering frame", i, "...") 36 | sceneObj, light := scene.NextFrame() 37 | renderer.Light = light 38 | img := render3d.NewImage(300, 300) 39 | renderer.Render(img, sceneObj) 40 | img.Save(filepath.Join("frames", fmt.Sprintf("scene_%03d.png", i))) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/renderings/bezier_fit/README.md: -------------------------------------------------------------------------------- 1 | # bezier_fit 2 | 3 | This demo showcases a Bezier least-squares fitting algorithm. 4 | 5 | # Rendering 6 | 7 | ![Rendering of a curve being fit to points on the quarter of a circle.](rendering.gif) 8 | -------------------------------------------------------------------------------- /examples/renderings/bezier_fit/rendering.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/bezier_fit/rendering.gif -------------------------------------------------------------------------------- /examples/renderings/cornell_box/README.md: -------------------------------------------------------------------------------- 1 | # cornell-box 2 | 3 | This ray tracing example shows area lighting, reflection, refraction, and how to load existing 3D models (the diamond). 4 | 5 | By default, it outputs a grainy low-resolution rendering (which takes about a minute): 6 | 7 | ![Low-res rendering](output.png) 8 | 9 | Raising the quality and resolution is as simple as modifying these lines: 10 | 11 | ```go 12 | MaxDepth: 5, 13 | NumSamples: 400, 14 | ``` 15 | 16 | and this line: 17 | 18 | ```go 19 | img := render3d.NewImage(200, 200) 20 | ``` 21 | 22 | Simply increase MaxDepth to maybe 15, increase NumSamples to 20000, and increase the resolution from 200x200 to whatever you want. Here's an example HD rendering at 500x500: 23 | 24 | ![High-resolution rendering](output_hd.png) 25 | -------------------------------------------------------------------------------- /examples/renderings/cornell_box/diamond.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/cornell_box/diamond.stl -------------------------------------------------------------------------------- /examples/renderings/cornell_box/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/cornell_box/output.png -------------------------------------------------------------------------------- /examples/renderings/cornell_box/output_hd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/cornell_box/output_hd.png -------------------------------------------------------------------------------- /examples/renderings/deformation/README.md: -------------------------------------------------------------------------------- 1 | # deformation 2 | 3 | This example uses the As-Rigid-As-Possible algorithm to animate a box being squeezed and twisted in various ways. 4 | 5 | By default, this produces a small, low frame-rate rendering to save space in the repository. Constants at the top of the file allow for higher-resolution renderings: 6 | 7 | ```go 8 | FrameSkip = 4 9 | ImageSize = 200 10 | ``` 11 | 12 | Simply set `FrameSkip = 1` and `ImageSize = 500` for a smoother, nicer animation. 13 | 14 | # Renderings 15 | 16 | Here is the low-resolution animation as a GIF: 17 | 18 | ![Animation of the deformation](output.gif) 19 | -------------------------------------------------------------------------------- /examples/renderings/deformation/output.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/deformation/output.gif -------------------------------------------------------------------------------- /examples/renderings/egg_2d/README.md: -------------------------------------------------------------------------------- 1 | # egg_2d 2 | 3 | This example shows how to rasterize multiple 2D shapes on top of each other, in this case to make a cartoon sunny-side up egg. 4 | 5 | # Renderings 6 | 7 | Here is the output 8 | 9 | ![Egg](egg.png) 10 | -------------------------------------------------------------------------------- /examples/renderings/egg_2d/egg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/egg_2d/egg.png -------------------------------------------------------------------------------- /examples/renderings/egg_2d/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "math" 6 | 7 | "github.com/unixpickle/model3d/model2d" 8 | ) 9 | 10 | func main() { 11 | // Create a wiggly egg. 12 | egg := model2d.NewMeshPolar(func(theta float64) float64 { 13 | return 0.9 + 0.1*math.Sin(theta*5) 14 | }, 300) 15 | circle := &model2d.Circle{Radius: 0.3} 16 | objs := []any{ 17 | model2d.NewColliderSolid(model2d.MeshToCollider(egg)), 18 | circle, 19 | } 20 | model2d.RasterizeColor("egg.png", objs, []color.Color{ 21 | color.Gray{Y: 0xff}, 22 | color.RGBA{R: 0xff, G: 0xff, A: 0xff}, 23 | }, 200.0) 24 | } 25 | -------------------------------------------------------------------------------- /examples/renderings/fog/README.md: -------------------------------------------------------------------------------- 1 | # fog 2 | 3 | This ray tracing example shows how to use a participating medium to simulate fog. The fog itself is created with this code: 4 | 5 | ```go 6 | &render3d.ParticipatingMedium{ 7 | Collider: bounds, 8 | Material: &render3d.HGMaterial{ 9 | G: 0.5, 10 | ScatterColor: render3d.NewColor(0.9), 11 | }, 12 | Lambda: 0.01, 13 | } 14 | ``` 15 | 16 | The fog fills a `model3d.Collider`, in this case a `model3d.Rect` encompassing the room. The material should always be an `HGMaterial`, since any other material won't know how to handle the randomized normals from a collision with the medium. 17 | 18 | # Result 19 | 20 | The resulting rendering is produced in a few minutes and looks like this: 21 | 22 | ![Rendering output](output.png) 23 | 24 | It is a foggy room with a single light source and a bunch of colored spheres at random positions. 25 | 26 | The quality could be increased by increasing the number of rays. In the example above, 1000 rays were used per pixel. 27 | -------------------------------------------------------------------------------- /examples/renderings/fog/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/fog/output.png -------------------------------------------------------------------------------- /examples/renderings/golf_balls/README.md: -------------------------------------------------------------------------------- 1 | # golf_balls 2 | 3 | Create a beautiful rendering of colorful golf balls arranged in a sphere. 4 | 5 | # Rendering 6 | 7 | ![Golf balls in a sphere](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/renderings/golf_balls/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/golf_balls/rendering.png -------------------------------------------------------------------------------- /examples/renderings/rope_indent/README.md: -------------------------------------------------------------------------------- 1 | # rope_indent 2 | 3 | This example uses some displacement voodoo magic to simulate elastic ropes squeezing an object. It demonstrates this by animating a rotating cube that is squeezed by two ropes, while the ropes themselves are locked at a particular angle. 4 | 5 | # Rendering 6 | 7 | This is the first frame of the animation: 8 | 9 | ![Rendering of a cube being squeezed by two elastic ropes.](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/renderings/rope_indent/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/rope_indent/rendering.png -------------------------------------------------------------------------------- /examples/renderings/showcase/README.md: -------------------------------------------------------------------------------- 1 | # showcase 2 | 3 | This example renders a bunch of different 3D models created by various `model3d` examples. It is meant to produce a sort of "banner ad" for `model3d` as a whole. 4 | 5 | Included are: 6 | 7 | * Wine glass - `examples/parody/place_setting` 8 | * Pumpkin - `examples/decoration/pumpkin` 9 | * Curvy thing - `examples/decoration/curvy_thing` 10 | * Vase - `examples/decoration/vase` 11 | * Rose - `examples/decoration/rose` 12 | * Rocks - `examples/decoration/rock` 13 | 14 | The default output looks like this: 15 | 16 | ![Output](output.png) 17 | 18 | To export a higher-resolution version, set the `HighRes` flag at the top of `main.go` to `true`. Then you will get: 19 | 20 | ![Output HD](output_hd.png) 21 | -------------------------------------------------------------------------------- /examples/renderings/showcase/constants.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/unixpickle/model3d/model3d" 4 | 5 | var ( 6 | LightDirection = model3d.XYZ(2, -3, 3).Normalize() 7 | LightCenter = LightDirection.Normalize().Scale(50) 8 | ) 9 | 10 | const ( 11 | CameraY = -5 12 | CameraZ = 4 13 | 14 | WineGlassX = -5.0 15 | WineGlassY = 10.5 16 | 17 | PumpkinX = -2 18 | PumpkinY = 10 19 | 20 | RocksY = 15.0 21 | 22 | VaseX = 5 23 | VaseY = 11 24 | RoseX = VaseX 25 | RoseY = VaseY 26 | RoseZ = 7 27 | RoseStemRadius = 0.15 28 | 29 | CurvyThingX = 1.8 30 | CurvyThingY = 9.0 31 | 32 | RoomRadius = 100.0 33 | 34 | LightRadius = 5.0 35 | LightBrightness = 300.0 36 | ) 37 | -------------------------------------------------------------------------------- /examples/renderings/showcase/models/curvy_thing.stl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/models/curvy_thing.stl.gz -------------------------------------------------------------------------------- /examples/renderings/showcase/models/pumpkin_inside.stl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/models/pumpkin_inside.stl.gz -------------------------------------------------------------------------------- /examples/renderings/showcase/models/pumpkin_outside.stl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/models/pumpkin_outside.stl.gz -------------------------------------------------------------------------------- /examples/renderings/showcase/models/pumpkin_stem.stl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/models/pumpkin_stem.stl.gz -------------------------------------------------------------------------------- /examples/renderings/showcase/models/rocks.stl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/models/rocks.stl.gz -------------------------------------------------------------------------------- /examples/renderings/showcase/models/rose.stl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/models/rose.stl.gz -------------------------------------------------------------------------------- /examples/renderings/showcase/models/vase.stl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/models/vase.stl.gz -------------------------------------------------------------------------------- /examples/renderings/showcase/models/wine_glass.stl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/models/wine_glass.stl.gz -------------------------------------------------------------------------------- /examples/renderings/showcase/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/output.png -------------------------------------------------------------------------------- /examples/renderings/showcase/output_hd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/showcase/output_hd.png -------------------------------------------------------------------------------- /examples/renderings/smooth_shading/README.md: -------------------------------------------------------------------------------- 1 | # smooth_shading 2 | 3 | In this example, we create a low-polygon icosphere and render it with both smooth and flat shading. We also turn text labels "Flat Shading" and "Phong Shading" into 3D meshes, and render these below each sphere with the same shading method as the accompanying sphere. 4 | 5 | Here is the final rendering: 6 | 7 | ![Rendering of a sphere with both flat (left) and smooth (right) shading](rendering.png) 8 | 9 | As can be seen in this rendering, Phong shading hides the polygonal surface of the sphere except around the edges, where an outline of the original low-polygon icosphere is still clearly visible. This is because shading can only affect pixels that actually intersect the surface. 10 | -------------------------------------------------------------------------------- /examples/renderings/smooth_shading/labels/flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/smooth_shading/labels/flat.png -------------------------------------------------------------------------------- /examples/renderings/smooth_shading/labels/smooth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/smooth_shading/labels/smooth.png -------------------------------------------------------------------------------- /examples/renderings/smooth_shading/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/smooth_shading/rendering.png -------------------------------------------------------------------------------- /examples/renderings/tiffany/README.md: -------------------------------------------------------------------------------- 1 | # tiffany 2 | 3 | This rendering example creates textured objects with Tiffany Blue coloration. It uses [bidirectional path tracing](https://en.wikipedia.org/wiki/Path_tracing#Bidirectional_path_tracing) to greatly reduce variance (versus standard path tracing). It shows how one might render: 4 | 5 | * Inset ceiling lights 6 | * Area lights 7 | * Textures - both hard-coded and image-based 8 | 9 | By default, this demo outputs a grainy, low-resolution rendering (which takes a minute or two): 10 | 11 | ![Low-res rendering](output.png) 12 | 13 | Raising the quality and resolution is as simple as modifying these lines: 14 | 15 | ```go 16 | NumSamples: 200, 17 | MinSamples: 200, 18 | ``` 19 | 20 | and this line: 21 | 22 | ```go 23 | img := render3d.NewImage(200, 200) 24 | ``` 25 | 26 | Simply increase `NumSamples` to maybe `100000`, increase MinSamples to `1000`, and increase the resolution from 200x200 to whatever you want. Here's an example HD rendering at 800x800: 27 | 28 | ![High-resolution rendering](output_hd.png) 29 | -------------------------------------------------------------------------------- /examples/renderings/tiffany/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/tiffany/output.png -------------------------------------------------------------------------------- /examples/renderings/tiffany/output_hd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/tiffany/output_hd.png -------------------------------------------------------------------------------- /examples/renderings/yt_banner/README.md: -------------------------------------------------------------------------------- 1 | # yt_banner 2 | 3 | This is a banner for a YouTube channel. The text is stored in [assets/letters.png](assets/letters.png) and can be easily changed. The floor texture is also in the `assets/` directory, and was from [rawpixel.com](https://www.rawpixel.com/image/2035862/pink-marble-slate). The corgi model was generated by the example in `examples/decoration/corgi`; it was split into different meshes per each color, and then stored in a single zip file. 4 | 5 | The current output looks like so: 6 | 7 | ![Render output](output.png) 8 | -------------------------------------------------------------------------------- /examples/renderings/yt_banner/assets/corgi.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/yt_banner/assets/corgi.zip -------------------------------------------------------------------------------- /examples/renderings/yt_banner/assets/letters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/yt_banner/assets/letters.png -------------------------------------------------------------------------------- /examples/renderings/yt_banner/assets/marble.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/yt_banner/assets/marble.jpg -------------------------------------------------------------------------------- /examples/renderings/yt_banner/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/renderings/yt_banner/output.png -------------------------------------------------------------------------------- /examples/romantic/coin/README.md: -------------------------------------------------------------------------------- 1 | # coin 2 | 3 | This tool creates one-sided coin models. The pattern on the coin is defined by an image, which is black on the face of the coin, and white on the recessed parts. 4 | 5 | Here is a sample rendering: 6 | 7 | ![Example of a generated coin model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/romantic/coin/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/coin/example.png -------------------------------------------------------------------------------- /examples/romantic/coin/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/coin/rendering.png -------------------------------------------------------------------------------- /examples/romantic/floral_arrangement/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/floral_arrangement/rendering.png -------------------------------------------------------------------------------- /examples/romantic/heart_arrow/README.md: -------------------------------------------------------------------------------- 1 | # heart_arrow 2 | 3 | This is an attempt to re-create a Tifanny necklace which looked like this: 4 | 5 | ![Original Tiffany heart necklace](original.png) 6 | 7 | # Rendering 8 | 9 | Here's how the current attempt looks: 10 | 11 | ![Renderings of the model](rendering.png) 12 | -------------------------------------------------------------------------------- /examples/romantic/heart_arrow/original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_arrow/original.png -------------------------------------------------------------------------------- /examples/romantic/heart_arrow/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_arrow/rendering.png -------------------------------------------------------------------------------- /examples/romantic/heart_box/README.md: -------------------------------------------------------------------------------- 1 | # heart-box 2 | 3 | This is a 3D-printable heart-shaped box with section cutouts. 4 | 5 | # Renderings 6 | 7 | Here is the sectioned box: 8 | 9 | ![Rendering of box](rendering_box.png) 10 | 11 | Here is the deep lid: 12 | 13 | ![Rendering of lid](rendering_lid.png) 14 | -------------------------------------------------------------------------------- /examples/romantic/heart_box/outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_box/outline.png -------------------------------------------------------------------------------- /examples/romantic/heart_box/rendering_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_box/rendering_box.png -------------------------------------------------------------------------------- /examples/romantic/heart_box/rendering_lid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_box/rendering_lid.png -------------------------------------------------------------------------------- /examples/romantic/heart_box/sections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_box/sections.png -------------------------------------------------------------------------------- /examples/romantic/heart_pizza/README.md: -------------------------------------------------------------------------------- 1 | # heart_pizza 2 | 3 | Did someone order a pizza? How about a *pizza my heart*? This example creates a pizza-like object with pepperonis--in a heart shape. 4 | 5 | # Renderings 6 | 7 | These renderings don't look the best, since they use Phong shading and make the pizza look shiny. Trust me, it's not as greasy as it looks! 8 | 9 | ![Renderings of the pizza](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/romantic/heart_pizza/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_pizza/heart.png -------------------------------------------------------------------------------- /examples/romantic/heart_pizza/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_pizza/rendering.png -------------------------------------------------------------------------------- /examples/romantic/heart_ring/README.md: -------------------------------------------------------------------------------- 1 | # heart-ring 2 | 3 | This is a real-sized ring with an inscribed heart ornament. The heart shape is defined by heart.png, and the inscription by letters.png. 4 | 5 | I actually printed this in polished silver through [Shapeways](http://shapeways.com/), and it looks amazing and fits well. 6 | 7 | # Renderings 8 | 9 | ![Rendering of the model](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/romantic/heart_ring/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_ring/heart.png -------------------------------------------------------------------------------- /examples/romantic/heart_ring/letters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_ring/letters.png -------------------------------------------------------------------------------- /examples/romantic/heart_ring/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_ring/rendering.png -------------------------------------------------------------------------------- /examples/romantic/heart_statue/README.md: -------------------------------------------------------------------------------- 1 | # heart-statue 2 | 3 | This example generates a 3D heart by building spheres around the medial axis of a heart shape. It then places this heart upright on a rectangular stand, and embeds 3D letters into the stand on either side of the heart. It colorizes each letter, the stand, and the heart differently, producing a neat multi-color print. 4 | 5 | The end result is meant to be 3D printed using a process that supports multiple colors. 6 | 7 | # Rendering 8 | 9 | Here are ideal renderings of the model: 10 | 11 | ![Renderings](rendering.png) 12 | -------------------------------------------------------------------------------- /examples/romantic/heart_statue/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_statue/heart.png -------------------------------------------------------------------------------- /examples/romantic/heart_statue/letter_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_statue/letter_1.png -------------------------------------------------------------------------------- /examples/romantic/heart_statue/letter_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_statue/letter_2.png -------------------------------------------------------------------------------- /examples/romantic/heart_statue/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/heart_statue/rendering.png -------------------------------------------------------------------------------- /examples/romantic/key/README.md: -------------------------------------------------------------------------------- 1 | # key 2 | 3 | This creates a romantic "love key", intended to be printed in a nice material (e.g. silver) and put on a keychain or necklace. 4 | 5 | # Renderings 6 | 7 | The key itself is created by first generating a 2D profile like so: 8 | 9 | ![Profile rendering](rendering_2d.png) 10 | 11 | Then this profile is converted into a 3D solid with rounded edges. A thin hook is added to the top of the key. As a final touch, tiny hearts are cut out of the side to look like ridges on the key. The final result looks like so: 12 | 13 | ![Rendering](rendering_3d.png) 14 | -------------------------------------------------------------------------------- /examples/romantic/key/engraving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/key/engraving.png -------------------------------------------------------------------------------- /examples/romantic/key/outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/key/outline.png -------------------------------------------------------------------------------- /examples/romantic/key/rendering_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/key/rendering_2d.png -------------------------------------------------------------------------------- /examples/romantic/key/rendering_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/key/rendering_3d.png -------------------------------------------------------------------------------- /examples/romantic/kisses/README.md: -------------------------------------------------------------------------------- 1 | # kisses 2 | 3 | This is a sweet little placard with text sticking out and some modeled Hershey kisses. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/romantic/kisses/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/kisses/rendering.png -------------------------------------------------------------------------------- /examples/romantic/kisses/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/kisses/text.png -------------------------------------------------------------------------------- /examples/romantic/love_graph/README.md: -------------------------------------------------------------------------------- 1 | # love-graph 2 | 3 | How do you compare your love for icecream and sunsets to your love for another person? Easy, plot it in a graph. This romantic gift tries to help visualize "how much more" you love your partner than you love other things. 4 | 5 | This program produces a 3D bar graph with axis labels from the files [label1.png](label1.png) through [label3.png](label3.png). It uses a [heart shape](heart.png) as the profile for each "bar" in the bar graph. 6 | 7 | # Renderings 8 | 9 | ![Renderings](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/romantic/love_graph/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/love_graph/heart.png -------------------------------------------------------------------------------- /examples/romantic/love_graph/label1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/love_graph/label1.png -------------------------------------------------------------------------------- /examples/romantic/love_graph/label2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/love_graph/label2.png -------------------------------------------------------------------------------- /examples/romantic/love_graph/label3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/love_graph/label3.png -------------------------------------------------------------------------------- /examples/romantic/love_graph/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/love_graph/rendering.png -------------------------------------------------------------------------------- /examples/romantic/my_home/README.md: -------------------------------------------------------------------------------- 1 | # my_home 2 | 3 | This example creates a cute printable decoration that says "you are my home" with a 3D house on top. The design can be printed support-free on an FDM printer. 4 | 5 | # Renderings 6 | 7 | Here are renderings of the model: 8 | 9 | ![Renderings of the model](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/romantic/my_home/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/my_home/rendering.png -------------------------------------------------------------------------------- /examples/romantic/my_home/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/my_home/text.png -------------------------------------------------------------------------------- /examples/romantic/my_world/README.md: -------------------------------------------------------------------------------- 1 | # my-world 2 | 3 | This is a placard with half a globe on it and text around it saying "You are / my world". 4 | 5 | # Rendering 6 | 7 | ![Rendering of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/romantic/my_world/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/my_world/base.png -------------------------------------------------------------------------------- /examples/romantic/my_world/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/my_world/map.png -------------------------------------------------------------------------------- /examples/romantic/my_world/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/my_world/rendering.png -------------------------------------------------------------------------------- /examples/romantic/necklace/README.md: -------------------------------------------------------------------------------- 1 | # necklace 2 | 3 | This is an FDM-printable necklace. It prints with no supports, and results in interlocking parts. 4 | 5 | # Rendering 6 | 7 | ![Rendering of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/romantic/necklace/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/necklace/rendering.png -------------------------------------------------------------------------------- /examples/romantic/necklace_2/README.md: -------------------------------------------------------------------------------- 1 | # necklace_2 2 | 3 | This is a necklace that is intended to be printed with a support-free printing process, ideally out of metal. It is customizable using command-line arguments. 4 | 5 | # Usage 6 | 7 | By default, the command will produce a necklace model with a heart attached to it. The units are in inches. Simply run `go run .`: 8 | 9 | ![Rendering of the heart necklace](renderings/heart.png) 10 | 11 | To print with a custom attachment, you can use the `-attachment` argument. By default, this will turn a 2D shape into a 3D pendant. To engrave the pendant, use `file.png:engraving.png`. For example: 12 | 13 | ``` 14 | $ go run . -attachment example_attachments/chanel.png:example_attachments/chanel_engraving.png 15 | ``` 16 | 17 | Here's a rendering when using `example_attachments/chanel.png` as the attachment: 18 | 19 | ![Rendering of the chanel necklace](renderings/chanel.png) 20 | 21 | To produce the necklace in higher resolution, pass `-resolution 0.0025` (default 0.005), which will make the command take roughly eight times as long to execute. You can also make the links smaller (to simulate finer jewelry) by passing something like `-link-length 0.1` (default 0.2). 22 | -------------------------------------------------------------------------------- /examples/romantic/necklace_2/example_attachments/chanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/necklace_2/example_attachments/chanel.png -------------------------------------------------------------------------------- /examples/romantic/necklace_2/example_attachments/chanel_engraving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/necklace_2/example_attachments/chanel_engraving.png -------------------------------------------------------------------------------- /examples/romantic/necklace_2/renderings/chanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/necklace_2/renderings/chanel.png -------------------------------------------------------------------------------- /examples/romantic/necklace_2/renderings/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/necklace_2/renderings/heart.png -------------------------------------------------------------------------------- /examples/romantic/otter_love/README.md: -------------------------------------------------------------------------------- 1 | # otter-love 2 | 3 | This is a simple plaque that says "I am otterly in love with you" with an Otter in the middle of it. 4 | 5 | # Renderings 6 | 7 | ![Rendering of the model](rendering.png) -------------------------------------------------------------------------------- /examples/romantic/otter_love/line_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/otter_love/line_1.png -------------------------------------------------------------------------------- /examples/romantic/otter_love/line_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/otter_love/line_2.png -------------------------------------------------------------------------------- /examples/romantic/otter_love/otter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/otter_love/otter.png -------------------------------------------------------------------------------- /examples/romantic/otter_love/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/otter_love/rendering.png -------------------------------------------------------------------------------- /examples/romantic/pendant/README.md: -------------------------------------------------------------------------------- 1 | # pendant 2 | 3 | Create custom pendants to 3D print in metal and put on a necklace. 4 | 5 | # Renderings 6 | 7 | Here's an example of running this command: 8 | 9 | ``` 10 | $ go run . -image examples/love_key.png -engraving examples/love_key_engraving.png 11 | ``` 12 | 13 | ![Rendering of the key](rendering.png) 14 | -------------------------------------------------------------------------------- /examples/romantic/pendant/examples/earth_engraving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/pendant/examples/earth_engraving.png -------------------------------------------------------------------------------- /examples/romantic/pendant/examples/earth_outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/pendant/examples/earth_outline.png -------------------------------------------------------------------------------- /examples/romantic/pendant/examples/love_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/pendant/examples/love_key.png -------------------------------------------------------------------------------- /examples/romantic/pendant/examples/love_key_engraving.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/pendant/examples/love_key_engraving.png -------------------------------------------------------------------------------- /examples/romantic/pendant/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/pendant/rendering.png -------------------------------------------------------------------------------- /examples/romantic/pill/README.md: -------------------------------------------------------------------------------- 1 | # pill 2 | 3 | This is a way to actually print the phrase: "your love is my drug". Meant to be printed in color (e.g. with Binder Jetting), these little love pills are a very romantic gift. 4 | 5 | The color, size, and heart pattern can be changed via command-line arguments. 6 | 7 | # Renderings 8 | 9 | ![Renderings](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/romantic/pill/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/pill/heart.png -------------------------------------------------------------------------------- /examples/romantic/pill/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/pill/rendering.png -------------------------------------------------------------------------------- /examples/romantic/ring_display/README.md: -------------------------------------------------------------------------------- 1 | # ring_display 2 | 3 | This is a ring box containing two rings, one lying on the other one. 4 | 5 | # Renderings 6 | 7 | ![Renderings of the ring box with rings](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/romantic/ring_display/metal_ring.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | 6 | "github.com/unixpickle/model3d/model3d" 7 | "github.com/unixpickle/model3d/render3d" 8 | "github.com/unixpickle/model3d/toolbox3d" 9 | ) 10 | 11 | func MetalRing() (model3d.Solid, toolbox3d.CoordColorFunc) { 12 | r := 0.45 13 | thickness := 0.1 14 | minThickness := 0.07 15 | depth := 0.22 16 | bevelRing := model3d.CheckedFuncSolid( 17 | model3d.XYZ(-r-thickness, -r-thickness, 0), 18 | model3d.XYZ(r+thickness, r+thickness, depth), 19 | func(c model3d.Coord3D) bool { 20 | edgeDist := math.Min(depth-c.Z, c.Z) 21 | th := math.Min(thickness, edgeDist+minThickness) 22 | return math.Abs(c.XY().Norm()-(r+thickness/2)) < th/2 23 | }, 24 | ) 25 | colorFn := toolbox3d.ConstantCoordColorFunc(render3d.NewColor(0.8)) 26 | return bevelRing, colorFn 27 | } 28 | -------------------------------------------------------------------------------- /examples/romantic/ring_display/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/ring_display/rendering.png -------------------------------------------------------------------------------- /examples/romantic/tiffany_box/README.md: -------------------------------------------------------------------------------- 1 | # tiffany_box 2 | 3 | This is a decorative imitation of a small Tiffany box. It is colored in Tiffany blue, and includes a white "bow" tied around it. The box can be printed in two separate halves and used as a real container. 4 | 5 | # Rendering 6 | 7 | ![Rendering of a tiffany-blue box with a ribbon and bow on it](rendering_both.png) 8 | -------------------------------------------------------------------------------- /examples/romantic/tiffany_box/rendering_both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/tiffany_box/rendering_both.png -------------------------------------------------------------------------------- /examples/romantic/wedding_cake/letters/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/wedding_cake/letters/1.png -------------------------------------------------------------------------------- /examples/romantic/wedding_cake/letters/H.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/wedding_cake/letters/H.png -------------------------------------------------------------------------------- /examples/romantic/wedding_cake/letters/a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/wedding_cake/letters/a.png -------------------------------------------------------------------------------- /examples/romantic/wedding_cake/letters/p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/wedding_cake/letters/p.png -------------------------------------------------------------------------------- /examples/romantic/wedding_cake/letters/s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/wedding_cake/letters/s.png -------------------------------------------------------------------------------- /examples/romantic/wedding_cake/letters/t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/wedding_cake/letters/t.png -------------------------------------------------------------------------------- /examples/romantic/wedding_cake/letters/y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/romantic/wedding_cake/letters/y.png -------------------------------------------------------------------------------- /examples/toys/ball_spiral/README.md: -------------------------------------------------------------------------------- 1 | # ball-spiral 2 | 3 | This is a spiral ramp that you can roll a ball down. It is designed to be printable, and also includes a printable ball that will fit the ramp. 4 | 5 | # Rendering 6 | 7 | ![Renderings of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/toys/ball_spiral/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/ball_spiral/rendering.png -------------------------------------------------------------------------------- /examples/toys/dreidel/README.md: -------------------------------------------------------------------------------- 1 | # dreidel 2 | 3 | This is a ![top](https://en.wikipedia.org/wiki/Top) that you can print and actually spin on the table. Its tip is shaped like a quadratic bowl. It is two parts. The body of the dreidel prints upside-down with a screw hole for the handle part to screw into. 4 | 5 | # Rendering 6 | 7 | Here is a rendering of the body model: 8 | 9 | ![Rendering of the main model](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/toys/dreidel/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/dreidel/rendering.png -------------------------------------------------------------------------------- /examples/toys/fidget_spinner/README.md: -------------------------------------------------------------------------------- 1 | # fidget-spinner 2 | 3 | This is a fidget spinner as a single interlocking part. It is intended to be printed using SLS or some other support-free method. 4 | 5 | The `PartSpacing` constant can be modified to give the axle more clearance. The default setting (0.01 inches) may be too agressive for most printers. 6 | 7 | # Rendering 8 | 9 | ![Rendering of the model](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/toys/fidget_spinner/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/fidget_spinner/rendering.png -------------------------------------------------------------------------------- /examples/toys/fidget_spinner/side_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/fidget_spinner/side_1.png -------------------------------------------------------------------------------- /examples/toys/fidget_spinner/side_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/fidget_spinner/side_2.png -------------------------------------------------------------------------------- /examples/toys/fidget_spinner/side_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/fidget_spinner/side_3.png -------------------------------------------------------------------------------- /examples/toys/jigsaw/README.md: -------------------------------------------------------------------------------- 1 | # jigsaw 2 | 3 | This is a jigsaw puzzle with a board to hold the pieces in place. It includes a tool to slice up an image so that you can print it out, cut it out, and tape the pieces of paper to the jigsaw pieces. 4 | 5 | # Renderings 6 | 7 | Here are the pieces, as they would print out and fit into the board: 8 | 9 | ![Rendering of the pieces](rendering_pieces.png) 10 | 11 | And here is the holder: 12 | 13 | ![Rendering of the holder](rendering_holder.png) 14 | -------------------------------------------------------------------------------- /examples/toys/jigsaw/generate_image.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image" 5 | _ "image/jpeg" 6 | "image/png" 7 | _ "image/png" 8 | "os" 9 | 10 | "github.com/unixpickle/essentials" 11 | "github.com/unixpickle/model3d/model2d" 12 | ) 13 | 14 | func GenerateImage(inPath, outPath string) { 15 | r, err := os.Open(inPath) 16 | essentials.Must(err) 17 | img, _, err := image.Decode(r) 18 | r.Close() 19 | essentials.Must(err) 20 | 21 | bounds := img.Bounds() 22 | 23 | cut := CutSolid() 24 | scale := BoardSize / float64(bounds.Dx()) 25 | 26 | outImage := image.NewRGBA(bounds) 27 | for y := bounds.Min.Y; y < bounds.Max.Y; y++ { 28 | for x := bounds.Min.X; x < bounds.Max.X; x++ { 29 | localPoint := model2d.Coord{ 30 | X: float64(x-bounds.Min.X) * scale, 31 | Y: float64(bounds.Max.Y-(y+1)) * scale, 32 | } 33 | if !cut.Contains(localPoint) { 34 | outImage.Set(x, y, img.At(x, y)) 35 | } 36 | } 37 | } 38 | 39 | w, err := os.Create(outPath) 40 | essentials.Must(err) 41 | defer w.Close() 42 | essentials.Must(png.Encode(w, outImage)) 43 | } 44 | -------------------------------------------------------------------------------- /examples/toys/jigsaw/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | if len(os.Args) < 2 { 10 | DieUsage() 11 | } 12 | switch os.Args[1] { 13 | case "mesh": 14 | GenerateMesh() 15 | case "image": 16 | if len(os.Args) != 4 { 17 | fmt.Fprintln(os.Stderr, "the 'image' sub-command expects two arguments") 18 | fmt.Fprintln(os.Stderr) 19 | DieUsage() 20 | } 21 | GenerateImage(os.Args[2], os.Args[3]) 22 | default: 23 | fmt.Fprintln(os.Stderr, "unknown sub-command:", os.Args[1]) 24 | fmt.Fprintln(os.Stderr) 25 | DieUsage() 26 | } 27 | } 28 | 29 | func DieUsage() { 30 | fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], " [args]") 31 | fmt.Fprintln(os.Stderr) 32 | fmt.Fprintln(os.Stderr, "sub-commands are:") 33 | fmt.Fprintln(os.Stderr, " mesh generate a 3D mesh") 34 | fmt.Fprintln(os.Stderr, " image [in] [out.png] cut slices out of an image") 35 | fmt.Fprintln(os.Stderr) 36 | os.Exit(1) 37 | } 38 | -------------------------------------------------------------------------------- /examples/toys/jigsaw/rendering_holder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/jigsaw/rendering_holder.png -------------------------------------------------------------------------------- /examples/toys/jigsaw/rendering_pieces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/jigsaw/rendering_pieces.png -------------------------------------------------------------------------------- /examples/toys/maze/README.md: -------------------------------------------------------------------------------- 1 | # maze 2 | 3 | This example creates a maze toy like the one from [Westworld](https://en.wikipedia.org/wiki/Westworld_(TV_series)). 4 | 5 | # Renderings 6 | 7 | ![Maze rendering](maze.png) 8 | -------------------------------------------------------------------------------- /examples/toys/maze/maze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/maze/maze.png -------------------------------------------------------------------------------- /examples/toys/maze/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/maze/rendering.png -------------------------------------------------------------------------------- /examples/toys/number_puzzle/README.md: -------------------------------------------------------------------------------- 1 | # number-puzzle 2 | 3 | This is a puzzle that consists of digital clock style numbers that fit neatly into a grid. Search is used to solve for a board that can be solved. 4 | 5 | # Renderings 6 | 7 | Here is a rendering where the digit pieces are a different color from the (yellow) board: 8 | 9 | ![Color rendering](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/toys/number_puzzle/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/number_puzzle/rendering.png -------------------------------------------------------------------------------- /examples/toys/puzzle/README.md: -------------------------------------------------------------------------------- 1 | # puzzle 2 | 3 | This is a 3D-printable [15-puzzle](https://en.wikipedia.org/wiki/15_puzzle). It includes a board, a piece, and a small piece model. The board should be printed once. The piece can be printed 14 times, and then the small piece once. The pieces pop into the board and are held in by each other. The small piece is meant to be put in last; it is only slightly smaller, but a regular piece is difficult to fit in after 14 other pieces are inserted. 4 | 5 | The pieces themselves are blank. This way, you can cut out and tape pictures to each piece, or you can simply draw numbers or letters on them with a marker. 6 | 7 | # Renderings 8 | 9 | Rendering of the board itself: 10 | 11 | ![Board rendering](rendering_board.png) 12 | 13 | Rendering of a piece: 14 | 15 | ![Piece rendering](rendering_piece.png) 16 | -------------------------------------------------------------------------------- /examples/toys/puzzle/rendering_board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/puzzle/rendering_board.png -------------------------------------------------------------------------------- /examples/toys/puzzle/rendering_piece.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/toys/puzzle/rendering_piece.png -------------------------------------------------------------------------------- /examples/usable/bracket/README.md: -------------------------------------------------------------------------------- 1 | # bracket 2 | 3 | This is an example of making a usable part. I used this bracket to assemble a table that was otherwise wooden. It was fairly strong. 4 | 5 | ![Rendering](rendering.png) 6 | -------------------------------------------------------------------------------- /examples/usable/bracket/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/bracket/rendering.png -------------------------------------------------------------------------------- /examples/usable/chip_clip/README.md: -------------------------------------------------------------------------------- 1 | # chip-clip 2 | 3 | This is a bag clip with a hinge that can be printed in-place without supports. 4 | It's very similar to [this](https://www.thingiverse.com/thing:330151) model on 5 | Thingiverse. 6 | 7 | I've been using it for opened bags of food (frozen vegetables, chips, etc), as 8 | well as to seal a trash bag that's been delegated for used cat litter. Some 9 | pictures: 10 | 11 | ![Pictures of our chip clip: open, closed, and applied on various 12 | bags](./pictures.jpg) 13 | 14 | # Renderings 15 | 16 | ![Chip clip renderings](./rendering.png) 17 | -------------------------------------------------------------------------------- /examples/usable/chip_clip/pictures.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/chip_clip/pictures.jpg -------------------------------------------------------------------------------- /examples/usable/chip_clip/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/chip_clip/rendering.png -------------------------------------------------------------------------------- /examples/usable/cubby_drawer/README.md: -------------------------------------------------------------------------------- 1 | # cubby-drawer 2 | 3 | This is a printable drawer for small cubby-like shelves. I am printing these because we bought a small shelf of 8 cubbies from a store, but didn't get bins/drawers to fit into them. 4 | 5 | # Renderings 6 | 7 | ![Rendering of the bin](rendering_bin.png) 8 | 9 | ![Rendering of the knob](rendering_knob.png) 10 | 11 | ![Rendering of the nut](rendering_nut.png) 12 | -------------------------------------------------------------------------------- /examples/usable/cubby_drawer/rendering_bin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/cubby_drawer/rendering_bin.png -------------------------------------------------------------------------------- /examples/usable/cubby_drawer/rendering_knob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/cubby_drawer/rendering_knob.png -------------------------------------------------------------------------------- /examples/usable/cubby_drawer/rendering_nut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/cubby_drawer/rendering_nut.png -------------------------------------------------------------------------------- /examples/usable/dog_tag/README.md: -------------------------------------------------------------------------------- 1 | # dog-tag 2 | 3 | This is a usable dog tag for your dog's collar. The shape of the tag is defined in [body.png](body.png), and the text is defined in [text.png](text.png). 4 | 5 | # Renderings 6 | 7 | ![Rendering of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/usable/dog_tag/body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/dog_tag/body.png -------------------------------------------------------------------------------- /examples/usable/dog_tag/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/dog_tag/rendering.png -------------------------------------------------------------------------------- /examples/usable/dog_tag/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/dog_tag/text.png -------------------------------------------------------------------------------- /examples/usable/drawer/README.md: -------------------------------------------------------------------------------- 1 | # drawer 2 | 3 | This is a usable, printable shelf with three drawers. The shelf is 6x6x6 inches by default, which is big enough for some medium-sized tools. All models can be printed support free. 4 | 5 | The shelf is made of four different 3D models: 6 | 7 | * A frame 8 | * A drawer to slide into the frame 9 | * A knob for the drawer 10 | * A nut to screw the knob into. 11 | 12 | Typically, you would print three drawers, knobs, and nuts per frame. 13 | 14 | # Renderings 15 | 16 | Here is the frame. It has fancy cutouts which require less material than a solid frame: 17 | 18 | ![Rendering of the frame](renderings/frame.png) 19 | 20 | Here is the drawer, designed to fit into the frame with a bit of slack: 21 | 22 | ![Rendering of the drawer](renderings/drawer.png) 23 | 24 | The knob and nut are rather trivial: 25 | 26 | ![Rendering of the knob](renderings/knob.png) 27 | 28 | ![Rendering of the nut](renderings/nut.png) 29 | -------------------------------------------------------------------------------- /examples/usable/drawer/knob.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/toolbox3d" 6 | ) 7 | 8 | func CreateKnob() model3d.Solid { 9 | return model3d.StackedSolid{ 10 | &model3d.Cylinder{ 11 | P2: model3d.Z(KnobBaseLength), 12 | Radius: KnobBaseRadius, 13 | }, 14 | &model3d.Cylinder{ 15 | P2: model3d.Z(KnobPoleLength), 16 | Radius: KnobPoleRadius, 17 | }, 18 | &toolbox3d.ScrewSolid{ 19 | P2: model3d.Coord3D{Z: DrawerThickness + KnobNutThickness}, 20 | GrooveSize: KnobScrewGroove, 21 | Radius: KnobScrewRadius, 22 | }, 23 | } 24 | } 25 | 26 | func CreateKnobNut() model3d.Solid { 27 | return &model3d.SubtractedSolid{ 28 | Positive: &model3d.Cylinder{ 29 | P2: model3d.Z(KnobNutThickness), 30 | Radius: KnobNutRadius, 31 | }, 32 | Negative: &toolbox3d.ScrewSolid{ 33 | P1: model3d.Coord3D{Z: -1e-5}, 34 | P2: model3d.Coord3D{Z: KnobNutThickness + 1e-5}, 35 | GrooveSize: KnobScrewGroove, 36 | Radius: KnobScrewRadius + KnobScrewSlack, 37 | }, 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/usable/drawer/renderings/drawer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/drawer/renderings/drawer.png -------------------------------------------------------------------------------- /examples/usable/drawer/renderings/frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/drawer/renderings/frame.png -------------------------------------------------------------------------------- /examples/usable/drawer/renderings/knob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/drawer/renderings/knob.png -------------------------------------------------------------------------------- /examples/usable/drawer/renderings/nut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/drawer/renderings/nut.png -------------------------------------------------------------------------------- /examples/usable/fan/README.md: -------------------------------------------------------------------------------- 1 | # fan 2 | 3 | This is an assembly-required hand-crank fan. It is made out of a handful of parts which screw together. Each part can be printed support-free. 4 | 5 | # Pictures 6 | 7 | Here are the parts separately: 8 | 9 | ![Parts photo](pictures/parts.jpg) 10 | 11 | Here is the assembled product: 12 | 13 | ![Assembled photo](pictures/assembled.jpg) 14 | -------------------------------------------------------------------------------- /examples/usable/fan/crank_bolt.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/toolbox3d" 6 | ) 7 | 8 | func CrankBoltMesh() *model3d.Mesh { 9 | solid := CrankBoltSolid() 10 | mesh := model3d.MarchingCubesSearch(solid, 0.005, 8) 11 | return mesh 12 | } 13 | 14 | func CrankBoltSolid() model3d.Solid { 15 | return model3d.StackedSolid{ 16 | &model3d.Cylinder{ 17 | P2: model3d.Z(CrankBoltThickness), 18 | Radius: CrankBoltRadius, 19 | }, 20 | &model3d.Cylinder{ 21 | P2: model3d.Coord3D{Z: SpineThickness + PoleExtraLength}, 22 | Radius: PoleRadius, 23 | }, 24 | &toolbox3d.ScrewSolid{ 25 | P2: model3d.Z(GearThickness), 26 | Radius: ScrewRadius - ScrewSlack, 27 | GrooveSize: ScrewGrooveSize, 28 | }, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/usable/fan/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/unixpickle/essentials" 9 | "github.com/unixpickle/model3d/model3d" 10 | ) 11 | 12 | const OutputDir = "models" 13 | 14 | func main() { 15 | CreateMeshFile("propeller.stl", PropellerMesh) 16 | CreateMeshFile("spine.stl", SpineMesh) 17 | CreateMeshFile("small_gear.stl", SmallGearMesh) 18 | CreateMeshFile("crank_gear.stl", CrankGearMesh) 19 | CreateMeshFile("crank_bolt.stl", CrankBoltMesh) 20 | } 21 | 22 | func CreateMeshFile(name string, f func() *model3d.Mesh) { 23 | if _, err := os.Stat(OutputDir); os.IsNotExist(err) { 24 | essentials.Must(os.Mkdir(OutputDir, 0755)) 25 | } 26 | outPath := filepath.Join(OutputDir, name) 27 | if _, err := os.Stat(outPath); os.IsNotExist(err) { 28 | log.Println("Creating mesh for", name, "...") 29 | mesh := f() 30 | log.Println("Saving mesh for", name, "...") 31 | mesh.SaveGroupedSTL(outPath) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/usable/fan/pictures/assembled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/fan/pictures/assembled.jpg -------------------------------------------------------------------------------- /examples/usable/fan/pictures/parts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/fan/pictures/parts.jpg -------------------------------------------------------------------------------- /examples/usable/fan/small_gear.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/toolbox3d" 6 | ) 7 | 8 | func SmallGearMesh() *model3d.Mesh { 9 | solid := SmallGearSolid() 10 | mesh := model3d.MarchingCubesSearch(solid, 0.005, 8) 11 | return mesh 12 | } 13 | 14 | func SmallGearSolid() model3d.Solid { 15 | return model3d.StackedSolid{ 16 | &toolbox3d.HelicalGear{ 17 | P2: model3d.Z(GearThickness), 18 | Profile: toolbox3d.InvoluteGearProfileSizes(GearPressureAngle, GearModule, 19 | GearAddendum, GearDedendum, SmallGearTeeth), 20 | Angle: -GearHelicalAngle, 21 | }, 22 | &model3d.Cylinder{ 23 | P2: model3d.Coord3D{Z: SpineThickness + SpineWasherSize + PoleExtraLength}, 24 | Radius: PoleRadius, 25 | }, 26 | &toolbox3d.ScrewSolid{ 27 | P2: model3d.Z(BladeDepth), 28 | Radius: ScrewRadius - ScrewSlack, 29 | GrooveSize: ScrewGrooveSize, 30 | }, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/usable/fan/spine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | ) 6 | 7 | func SpineMesh() *model3d.Mesh { 8 | solid := SpineSolid() 9 | mesh := model3d.MarchingCubesSearch(solid, 0.015, 8) 10 | return mesh 11 | } 12 | 13 | func SpineSolid() model3d.Solid { 14 | center1 := model3d.Coord3D{X: SpineWidth / 2, Y: SpineWidth / 2} 15 | center2 := center1.Add(model3d.Y(GearDistance)) 16 | thickVec := model3d.Coord3D{Z: SpineThickness + SpineWasherSize} 17 | return &model3d.SubtractedSolid{ 18 | Positive: model3d.JoinedSolid{ 19 | &model3d.Rect{ 20 | MaxVal: model3d.XYZ(SpineWidth, SpineLength, SpineThickness), 21 | }, 22 | &model3d.Cylinder{ 23 | P1: center1, 24 | P2: center1.Add(thickVec), 25 | Radius: SpineWasherRadius, 26 | }, 27 | }, 28 | Negative: model3d.JoinedSolid{ 29 | &model3d.Cylinder{ 30 | P1: center1, 31 | P2: center1.Add(thickVec), 32 | Radius: HoleRadius, 33 | }, 34 | &model3d.Cylinder{ 35 | P1: center2, 36 | P2: center2.Add(thickVec), 37 | Radius: HoleRadius, 38 | }, 39 | }, 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/usable/hanging_hook/README.md: -------------------------------------------------------------------------------- 1 | # hanging-hook 2 | 3 | This is a printable hook that you can hang from another hook, for example to hang a collection of coats on top of each other. It has no overhangs greater than 45 degrees, so can be easily printed. 4 | 5 | # Renderings 6 | 7 | Here is the default hook, which has a dip (lowest point) in the middle of the hook: 8 | 9 | ![Rendering of the hook with a dip in the middle](rendering_dip.png) 10 | 11 | Here is with the `-no-dip` flag, which removes the dip and allows more hooks to hang flush on this hook: 12 | 13 | ![Rendering of the hook with the lowest point flush against the hanging part](rendering_no_dip.png) 14 | -------------------------------------------------------------------------------- /examples/usable/hanging_hook/rendering_dip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/hanging_hook/rendering_dip.png -------------------------------------------------------------------------------- /examples/usable/hanging_hook/rendering_no_dip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/hanging_hook/rendering_no_dip.png -------------------------------------------------------------------------------- /examples/usable/hole_measure/README.md: -------------------------------------------------------------------------------- 1 | # hole_measure 2 | 3 | This example creates a set of cylindrical pegs of different sizes. Each peg is marked using a number of notches to indicate its size. These pegs, if printed, can be helpful for measuring holes (e.g. for pegs to hold up a cabinet shelf). 4 | 5 | # Rendering 6 | 7 | Here is a rendering of the largest (default) peg, complete with its nine notches: 8 | 9 | ![Rendering](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/usable/hole_measure/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/hole_measure/rendering.png -------------------------------------------------------------------------------- /examples/usable/kindle_holder/README.md: -------------------------------------------------------------------------------- 1 | # kindle-holder 2 | 3 | This incredibly useful and underrated print can be used as a phone stand, kindle holder, makeshift phone tripod, etc. It is an easy-to-print part that you can leave sitting on your desk or table for when you need it. 4 | 5 | # Renderings 6 | 7 | ![Renderings of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/usable/kindle_holder/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/kindle_holder/rendering.png -------------------------------------------------------------------------------- /examples/usable/menorah/README.md: -------------------------------------------------------------------------------- 1 | # menorah 2 | 3 | This is a 3D model of a [Hanukkah](https://en.wikipedia.org/wiki/Hanukkah) [menorah](https://en.wikipedia.org/wiki/Menorah_(Hanukkah)). It is based on a binary tree pattern, where the root node and the leaf nodes contain candle holders. 4 | 5 | The model is intended to be fully usable (with standard-sized candles). It is designed to be printable on a commodity FDM printer, although it is probably only safe to use if printed in a material that can withstand high temperatures. 6 | 7 | ![Rendering of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/usable/menorah/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/menorah/rendering.png -------------------------------------------------------------------------------- /examples/usable/milkshake_ringholder/README.md: -------------------------------------------------------------------------------- 1 | # Milkshake Ring Holder 2 | 3 | This is a model intended to be printed in full color and used as a ring holder. It resembles a tiny milkshake with two straws poking out and a cherry on top. The straws and cherries can be used for placing rings. An engraving in the side of the milkshake can be customized based on the image in [text.png](text.png), and currently says EST 2022. 4 | 5 | # Rendering 6 | 7 | Here are renderings of the model: 8 | 9 | ![Renderings of the milkshake ring holder](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/usable/milkshake_ringholder/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/render3d" 6 | "github.com/unixpickle/model3d/toolbox3d" 7 | ) 8 | 9 | const Production = true 10 | 11 | func main() { 12 | cup, cupColor := CupSolid() 13 | cream, creamColor := CreamSolid() 14 | straw, strawColor := StrawSolid() 15 | cherry, cherryColor := CherrySolid() 16 | joined := model3d.JoinedSolid{cup, cream, straw, cherry} 17 | 18 | delta := 0.02 19 | if Production { 20 | delta = 0.01 21 | } 22 | mesh, interior := model3d.DualContourInterior(joined, delta, true, false) 23 | mesh = model3d.MeshToHierarchy(mesh)[0].Mesh 24 | colorFunc := toolbox3d.JoinedSolidCoordColorFunc( 25 | interior, 26 | cup, cupColor, 27 | cream, creamColor, 28 | straw, strawColor, 29 | cherry, cherryColor, 30 | ) 31 | 32 | render3d.SaveRandomGrid("rendering.png", mesh, 3, 3, 300, colorFunc.RenderColor) 33 | mesh.SaveMaterialOBJ("milkshake.zip", colorFunc.TriangleColor) 34 | } 35 | -------------------------------------------------------------------------------- /examples/usable/milkshake_ringholder/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/milkshake_ringholder/rendering.png -------------------------------------------------------------------------------- /examples/usable/milkshake_ringholder/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/milkshake_ringholder/text.png -------------------------------------------------------------------------------- /examples/usable/napkin_holder/README.md: -------------------------------------------------------------------------------- 1 | # napkin-holder 2 | 3 | This is a 3D-printable napkin holder with an image popping out of the side. The image is stored in [image.png](image.png) and can be modified as one sees fit. 4 | 5 | The image protrudes at a 45-degree angle so that it can be printed on an FDM printer without supports. 6 | 7 | # Renderings 8 | 9 | ![Renderings of the model](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/usable/napkin_holder/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/napkin_holder/image.png -------------------------------------------------------------------------------- /examples/usable/napkin_holder/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/napkin_holder/rendering.png -------------------------------------------------------------------------------- /examples/usable/pencil_holder/README.md: -------------------------------------------------------------------------------- 1 | # Pencil Holder 2 | 3 | This example shows how to make a heart-shaped pencil holder with an inscription in the middle. It dynamically calculates the perfect size so that the pencil holes meet up perfectly where they started. Printable with FDM, this design is affordable and useful. 4 | 5 | # Renderings 6 | 7 | ![Rendering of pencil holder](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/usable/pencil_holder/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/pencil_holder/rendering.png -------------------------------------------------------------------------------- /examples/usable/pencil_holder/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/pencil_holder/schematic.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/README.md: -------------------------------------------------------------------------------- 1 | # penguin_calendar 2 | 3 | This is a cartoonish 3D model of a penguin, with a whole cut out for blocks that can be arranged to tell the current month and day. The blocks are stored as a separate model, which can also be printed in color. 4 | 5 | # Renderings 6 | 7 | Here is the penguin itself: 8 | 9 | ![Rendering of the penguin](rendering_penguin.png) 10 | 11 | Here are the blocks for indicating the date: 12 | 13 | ![Rendering of the blocks for showing month and day](rendering_blocks.png) 14 | -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/1.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/10.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/11.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/12.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/2.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/3.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/4.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/5.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/6.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/7.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/8.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/dates/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/dates/9.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/0.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/1.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/2.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/3.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/4.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/5.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/6.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/7.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/8.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/labels/numbers/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/labels/numbers/9.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/rendering_blocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/rendering_blocks.png -------------------------------------------------------------------------------- /examples/usable/penguin_calendar/rendering_penguin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/penguin_calendar/rendering_penguin.png -------------------------------------------------------------------------------- /examples/usable/phone_booth/README.md: -------------------------------------------------------------------------------- 1 | # phone_booth 2 | 3 | This is a London red phonebooth parody with inserts for four photos to be put inside, facing outward from each side. The top lifts off so that these can be inserted. 4 | 5 | # Rendering 6 | 7 | Top: 8 | 9 | ![Rendering of the top of the phonebooth](rendering_top.png) 10 | 11 | Bottom; 12 | 13 | ![Rendering of the bottom of the phonebooth](rendering_bottom.png) 14 | -------------------------------------------------------------------------------- /examples/usable/phone_booth/images/telephone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/phone_booth/images/telephone.png -------------------------------------------------------------------------------- /examples/usable/phone_booth/rendering_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/phone_booth/rendering_bottom.png -------------------------------------------------------------------------------- /examples/usable/phone_booth/rendering_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/phone_booth/rendering_top.png -------------------------------------------------------------------------------- /examples/usable/pitcher/README.md: -------------------------------------------------------------------------------- 1 | # pitcher 2 | 3 | This example creates a water pitcher with a handle and a lip. It is fully 3D-printable without supports, and is intended for watering plants! 4 | 5 | # Rendering 6 | 7 | Here is what the model looks like: 8 | 9 | ![Rendering of the pitcher](rendering.png) 10 | -------------------------------------------------------------------------------- /examples/usable/pitcher/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/pitcher/rendering.png -------------------------------------------------------------------------------- /examples/usable/quarter_case/README.md: -------------------------------------------------------------------------------- 1 | # quarter-case 2 | 3 | This is a 3D printable container that can store quarters. It is intended to be filled with quarters and then kept in a car in order to pay parking meters. 4 | 5 | The container is two pieces: a body and a lid. The body includes slits in the sides to see how many quarters you have left. 6 | 7 | # Renderings 8 | 9 | Here is the body: 10 | 11 | ![Rendering of the holder body](rendering_body.png) 12 | 13 | Here is the lid: 14 | 15 | ![Rendering of the holder lid](rendering_lid.png) 16 | -------------------------------------------------------------------------------- /examples/usable/quarter_case/rendering_body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/quarter_case/rendering_body.png -------------------------------------------------------------------------------- /examples/usable/quarter_case/rendering_lid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/quarter_case/rendering_lid.png -------------------------------------------------------------------------------- /examples/usable/razor_holder/README.md: -------------------------------------------------------------------------------- 1 | # Razor holder 2 | 3 | This is a 3D-printable object which can be stuck to the wall in a shower to hold a manual razor. 4 | 5 | ![Rendering of razor holder](rendering.png) 6 | -------------------------------------------------------------------------------- /examples/usable/razor_holder/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | 6 | "github.com/unixpickle/model3d/model3d" 7 | "github.com/unixpickle/model3d/render3d" 8 | "github.com/unixpickle/model3d/toolbox3d" 9 | ) 10 | 11 | const ( 12 | Width = 2.5 13 | StickyHeight = 1.2 14 | HolderHeight = 0.3 15 | HolderLength = 1.0 16 | Thickness = 0.2 17 | 18 | GapWidth = 0.75 19 | ) 20 | 21 | func main() { 22 | rs := toolbox3d.NewRectSet() 23 | rs.Add(&model3d.Rect{ 24 | MaxVal: model3d.XYZ(Width, HolderLength, Thickness), 25 | }) 26 | rs.Add(&model3d.Rect{ 27 | MaxVal: model3d.XYZ(Width, Thickness, StickyHeight), 28 | }) 29 | rs.Add(&model3d.Rect{ 30 | MinVal: model3d.XYZ(0, HolderLength, 0), 31 | MaxVal: model3d.XYZ(Width, HolderLength+Thickness, Thickness+HolderHeight), 32 | }) 33 | rs.Remove(&model3d.Rect{ 34 | MinVal: model3d.XY((Width-GapWidth)/2, Thickness*2), 35 | MaxVal: model3d.XYZ((Width+GapWidth)/2, Thickness+HolderLength, 36 | StickyHeight), 37 | }) 38 | mesh := rs.Mesh() 39 | ioutil.WriteFile("razor_holder.stl", mesh.EncodeSTL(), 0755) 40 | render3d.SaveRandomGrid("rendering.png", mesh, 3, 3, 200, nil) 41 | } 42 | -------------------------------------------------------------------------------- /examples/usable/razor_holder/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/razor_holder/rendering.png -------------------------------------------------------------------------------- /examples/usable/recycle_bin/README.md: -------------------------------------------------------------------------------- 1 | # recycle-bin 2 | 3 | This example creates a 3D printable recycling bin with the international recycling symbol on the side. It features rounded edges and a rounded rim, which are implemented as part of the `Solid` rather than with mesh operations. 4 | 5 | The generated model can be printed with no support structures, since the symbols on the sides are sloped rather than jutting directly out. 6 | 7 | # Rendering 8 | 9 | Here is a rendering of the produced model. 10 | 11 | ![Rendering of the recycling bin](rendering.png) 12 | -------------------------------------------------------------------------------- /examples/usable/recycle_bin/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/recycle_bin/rendering.png -------------------------------------------------------------------------------- /examples/usable/recycle_bin/wikipedia_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/recycle_bin/wikipedia_image.png -------------------------------------------------------------------------------- /examples/usable/ruler/README.md: -------------------------------------------------------------------------------- 1 | # ruler 2 | 3 | This example creates a simple mesh for a 5-inch ruler. The size of the ruler, as well as the spacing, can be easily adjusted. 4 | 5 | # Renderings 6 | 7 | ![Rendering of the model](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/usable/ruler/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/ruler/rendering.png -------------------------------------------------------------------------------- /examples/usable/shoe_rack/README.md: -------------------------------------------------------------------------------- 1 | # shoe rack 2 | 3 | This is a small, FDM-printable part that you can mount to your wall with adhesive strips. If you make a few of them, they can serve as shelves for shoes and other light objects. 4 | 5 | # Renderings 6 | 7 | ![Rendering of the object](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/usable/shoe_rack/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/shoe_rack/rendering.png -------------------------------------------------------------------------------- /examples/usable/table/README.md: -------------------------------------------------------------------------------- 1 | # table 2 | 3 | This is a 3D-printable bedside table. It is modular, so more legs can be added to increase height, and different stands (bases) can be substituted in. 4 | 5 | The table consists of three different types of parts: a stand, legs, and a top. There are currently two stand designs (one with three legs, and one which is just a cone). The legs can screw onto the stand, into each other, and into the top. Currently, the only top is a flat circle. 6 | 7 | All parts are designed to have inclines of 45 degrees or less, making support-free printing possible. 8 | 9 | # Renderings 10 | 11 | The cone stand: 12 | 13 | ![Rendering of the cone stand](cone_stand.png) 14 | 15 | The original three-legged stand: 16 | 17 | ![Rendering of the stand](stand.png) 18 | 19 | The leg part: 20 | 21 | ![Rendering of the leg](leg.png) 22 | 23 | The top: 24 | 25 | ![Rendering of the top](top.png) 26 | -------------------------------------------------------------------------------- /examples/usable/table/cone_stand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/table/cone_stand.png -------------------------------------------------------------------------------- /examples/usable/table/leg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/table/leg.png -------------------------------------------------------------------------------- /examples/usable/table/stand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/table/stand.png -------------------------------------------------------------------------------- /examples/usable/table/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/table/top.png -------------------------------------------------------------------------------- /examples/usable/trash_can/README.md: -------------------------------------------------------------------------------- 1 | # trash can 2 | 3 | These are a few cool trash can designs. They are implemented as functions in 3D cylindrical coordinates. 4 | 5 | "Swirl" design: 6 | 7 | ![Swirl design](rendering_swirl.png) 8 | 9 | "Bulge" design: 10 | 11 | ![Bulge design](rendering_bulge.png) -------------------------------------------------------------------------------- /examples/usable/trash_can/rendering_bulge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/trash_can/rendering_bulge.png -------------------------------------------------------------------------------- /examples/usable/trash_can/rendering_swirl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/trash_can/rendering_swirl.png -------------------------------------------------------------------------------- /examples/usable/treat_box/README.md: -------------------------------------------------------------------------------- 1 | # treat-box 2 | 3 | This is a 3D-printable box which is shaped like a dog bone. It is intended for storing small dog treats. The shape is derived from bone.png, and can be changed by changing bone.png to any other outline. 4 | 5 | The box consists of three parts: the box itself, a lid, and a handle that screws into the lid. 6 | 7 | # Renderings 8 | 9 | Here is the box itsellf: 10 | 11 | ![Rendering of the box](rendering_box.png) 12 | 13 | Here is the lid, note the screw hole: 14 | 15 | ![Rendering of the lid](rendering_lid.png) 16 | 17 | Here is the handle which screws into the lid: 18 | 19 | ![Rendering of the handle](rendering_handle.png) 20 | -------------------------------------------------------------------------------- /examples/usable/treat_box/bone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/treat_box/bone.png -------------------------------------------------------------------------------- /examples/usable/treat_box/rendering_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/treat_box/rendering_box.png -------------------------------------------------------------------------------- /examples/usable/treat_box/rendering_handle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/treat_box/rendering_handle.png -------------------------------------------------------------------------------- /examples/usable/treat_box/rendering_lid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/treat_box/rendering_lid.png -------------------------------------------------------------------------------- /examples/usable/tripod/README.md: -------------------------------------------------------------------------------- 1 | # tripod 2 | 3 | This is a miniature smartphone tripod that is meant to be custom-printed to your phone's dimensions. It includes two (main) parts: a cradle and the tripod itself. The cradle can be swapped out, and is customized, while the tripod legs themselves are a fixed size. 4 | 5 | The legs also include screw holes, which may be used to attach variable length extensions to change the height or incline of the tripod. The foot model that comes with this code is a small, screwable foot that can be adjusted by up to about an inch, allowing for changing the incline (but not really the height) of the tripod. 6 | 7 | This program accepts CLI arguments to customize the dimensions of the phone cradle. 8 | 9 | # Renderings 10 | 11 | Here's a custom-fit cradle: 12 | 13 | ![Rendering of the cradle](rendering_cradle.png) 14 | 15 | Here's the generic tripod legs: 16 | 17 | ![Rendering of the tripod](rendering_tripod.png) 18 | 19 | Here's the foot: 20 | 21 | ![Rendering of the foot](rendering_foot.png) 22 | -------------------------------------------------------------------------------- /examples/usable/tripod/foot.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/unixpickle/model3d/model3d" 5 | "github.com/unixpickle/model3d/toolbox3d" 6 | ) 7 | 8 | func CreateFoot() model3d.Solid { 9 | return model3d.StackSolids( 10 | &model3d.Cylinder{ 11 | P2: model3d.Z(0.2), 12 | Radius: TripodFootRadius, 13 | }, 14 | &toolbox3d.ScrewSolid{ 15 | P2: model3d.Z(1.0), 16 | Radius: ScrewRadius, 17 | GrooveSize: ScrewGroove, 18 | }, 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /examples/usable/tripod/rendering_cradle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/tripod/rendering_cradle.png -------------------------------------------------------------------------------- /examples/usable/tripod/rendering_foot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/tripod/rendering_foot.png -------------------------------------------------------------------------------- /examples/usable/tripod/rendering_tripod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/tripod/rendering_tripod.png -------------------------------------------------------------------------------- /examples/usable/umbrella_brace/README.md: -------------------------------------------------------------------------------- 1 | # umbrella_brace 2 | 3 | This is a printable umbrella hole ring for tightening an outdoor umbrella into a base or table. In particular, I needed this print to get an [AMMSUN Patio Umbrella](https://www.amazon.com/dp/B082SHSM5X?psc=1&ref=ppx_yo2_dt_b_product_details) to lock tightly into a [DC America Umbrella Base](https://www.amazon.com/dp/B0025VP5J8?psc=1&ref=ppx_yo2_dt_b_product_details). 4 | 5 | # Renderings 6 | 7 | ![A rendering of the part](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/usable/umbrella_brace/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/umbrella_brace/rendering.png -------------------------------------------------------------------------------- /examples/usable/wall_basket/README.md: -------------------------------------------------------------------------------- 1 | # wall_basket 2 | 3 | For this example, I wanted a trash can to mount on the wall next to my drying machine so that I could conveniently throw out dryer sheets and lint. However, I couldn't stick this trash can directly to the wall, since I needed to periodically empty it into a larger trash can (and fishing out trash doesn't sound fun). 4 | 5 | To achieve this, I created a mount that can be stuck to the wall that the trash can slides in and out of. This way, the trash can is usually hanging securely on the wall, but it can be lifted out of its mount and emptied. 6 | 7 | # Renderings 8 | 9 | Here is a rendering of the trash can: 10 | 11 | ![Rendering of the trash can](rendering_bin.png) 12 | 13 | Here is a rendering of the wall mount: 14 | 15 | ![Rendering of the wall mount](rendering_mount.png) 16 | -------------------------------------------------------------------------------- /examples/usable/wall_basket/rendering_bin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/wall_basket/rendering_bin.png -------------------------------------------------------------------------------- /examples/usable/wall_basket/rendering_mount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/wall_basket/rendering_mount.png -------------------------------------------------------------------------------- /examples/usable/watch_holder/README.md: -------------------------------------------------------------------------------- 1 | # watch_holder 2 | 3 | This example makes use of the `toolbox3d.RectSet` API to quickly create a 3D model that is comprised of 3D rectangular volumes. Many useful objects can be defined in such a way, and the API makes it easy to create meshes from these definitions. In this case, we create a "cradle" that you can 3D print and mount on a wall or a piece of furniture to hold a smartwatch while it charges. It includes a small slit for a charger to reach in and go under the watch. 4 | 5 | # Renderings 6 | 7 | ![Renderings](rendering.png) 8 | -------------------------------------------------------------------------------- /examples/usable/watch_holder/rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/examples/usable/watch_holder/rendering.png -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/unixpickle/model3d 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/pkg/errors v0.9.1 7 | github.com/unixpickle/essentials v1.3.0 8 | github.com/unixpickle/splaytree v1.1.0 9 | golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 2 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 3 | github.com/unixpickle/essentials v1.3.0 h1:H258Z5Uo1pVzFjxD2rwFWzHPN3s0J0jLs5kuxTRSfCs= 4 | github.com/unixpickle/essentials v1.3.0/go.mod h1:dQ1idvqrgrDgub3mfckQm7osVPzT3u9rB6NK/LEhmtQ= 5 | github.com/unixpickle/splaytree v1.1.0 h1:LXYm3OHPHLacGrUnEsrES4i8DFTqwyw1eoxXuZIE6kM= 6 | github.com/unixpickle/splaytree v1.1.0/go.mod h1:Wmzeu7zl1qJVgZXlOdWib73pZlFOsFVgYo3k/72bYDw= 7 | golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= 8 | golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= 9 | -------------------------------------------------------------------------------- /model2d/doc.go: -------------------------------------------------------------------------------- 1 | // Package model2d provides various tools for loading, 2 | // manipulating, saving, and using 2D shapes. 3 | // It is also intended to aid in creating 3D models which 4 | // incorporate 2D shapes in some way. 5 | package model2d 6 | -------------------------------------------------------------------------------- /model2d/import.go: -------------------------------------------------------------------------------- 1 | package model2d 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | 7 | "github.com/unixpickle/model3d/fileformats" 8 | ) 9 | 10 | // DecodeCSV decodes the CSV format from EncodeCSV(). 11 | func DecodeCSV(data []byte) ([]*Segment, error) { 12 | r := fileformats.NewSegmentCSVReader(bytes.NewReader(data)) 13 | res := []*Segment{} 14 | for { 15 | row, err := r.Read() 16 | if err == io.EOF { 17 | break 18 | } else if err != nil { 19 | return nil, err 20 | } 21 | res = append(res, &Segment{XY(row[0], row[1]), XY(row[2], row[3])}) 22 | } 23 | return res, nil 24 | } 25 | -------------------------------------------------------------------------------- /model2d/measurements.go: -------------------------------------------------------------------------------- 1 | package model2d 2 | 3 | import "math" 4 | 5 | // Area computes the area inside of a manifold mesh. 6 | func (m *Mesh) Area() float64 { 7 | var result float64 8 | m.Iterate(func(s *Segment) { 9 | mat := Matrix2{ 10 | s[0].X, s[0].Y, 11 | s[1].X, s[1].Y, 12 | } 13 | result += mat.Det() / 2.0 14 | }) 15 | return math.Abs(result) 16 | } 17 | -------------------------------------------------------------------------------- /model2d/measurements_test.go: -------------------------------------------------------------------------------- 1 | package model2d 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | func TestMeshArea(t *testing.T) { 9 | t.Run("Circle", func(t *testing.T) { 10 | circle := NewMeshPolar(func(t float64) float64 { 11 | return 1.0 12 | }, 2000) 13 | expected := math.Pi 14 | actual := circle.Area() 15 | if math.Abs(actual-expected) > 1e-4 { 16 | t.Errorf("expected area %f but got %f", expected, actual) 17 | } 18 | }) 19 | t.Run("Concentric", func(t *testing.T) { 20 | mesh := NewMeshPolar(func(t float64) float64 { 21 | return 1.0 22 | }, 2000) 23 | mesh.AddMesh(mesh.MapCoords(func(c Coord) Coord { 24 | return XY(c.X*0.5, -c.Y*0.5) 25 | })) 26 | expected := 0.75 * math.Pi 27 | actual := mesh.Area() 28 | if math.Abs(actual-expected) > 1e-4 { 29 | t.Errorf("expected area %f but got %f", expected, actual) 30 | } 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /model2d/mesh_test.go: -------------------------------------------------------------------------------- 1 | package model2d 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | func TestVertexSlice(t *testing.T) { 9 | s1 := &Segment{ 10 | XY(0, 1), 11 | XY(1, 0), 12 | } 13 | mesh := NewMesh() 14 | mesh.Add(s1) 15 | if len(mesh.VertexSlice()) != 2 { 16 | t.Error("unexpected number of vertices") 17 | } 18 | mesh.Remove(s1) 19 | if len(mesh.VertexSlice()) != 0 { 20 | t.Error("unexpected number of vertices") 21 | } 22 | } 23 | 24 | func TestNewMeshPolar(t *testing.T) { 25 | mesh := NewMeshPolar(func(theta float64) float64 { 26 | return math.Cos(theta) + 2 27 | }, 100) 28 | MustValidateMesh(t, mesh, true) 29 | } 30 | 31 | func TestNewMeshRect(t *testing.T) { 32 | mesh := NewMeshRect(XY(0.2, 0.3), XY(0.25, 0.5)) 33 | MustValidateMesh(t, mesh, true) 34 | } 35 | -------------------------------------------------------------------------------- /model2d/test_data/test_bitmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/model2d/test_data/test_bitmap.png -------------------------------------------------------------------------------- /model2d/test_data/test_bitmap_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/model2d/test_data/test_bitmap_small.png -------------------------------------------------------------------------------- /model2d/util_test.go: -------------------------------------------------------------------------------- 1 | // Generated from templates/util_test.template 2 | 3 | package model2d 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/pkg/errors" 9 | ) 10 | 11 | type Failer interface { 12 | Fatal(args ...any) 13 | } 14 | 15 | // ValidateMesh checks if m is manifold and has correct normals. 16 | // 17 | // If checkExtra is true, then normals are checked universally. 18 | // Otherwise, it is ensured that orientation is correct, but 19 | // normals could be flipped. 20 | func ValidateMesh(m *Mesh, checkExtra bool) error { 21 | if !m.Manifold() { 22 | return errors.New("mesh is non-manifold") 23 | } 24 | if checkExtra { 25 | if _, n := m.RepairNormals(1e-8); n != 0 { 26 | return fmt.Errorf("mesh has %d flipped normals", n) 27 | } 28 | } else { 29 | if n := len(m.InconsistentVertices()); n != 0 { 30 | return fmt.Errorf("mesh has %d inconsistent vertices", n) 31 | } 32 | } 33 | 34 | return nil 35 | } 36 | 37 | func MustValidateMesh(f Failer, m *Mesh, checkExtra bool) { 38 | if err := ValidateMesh(m, checkExtra); err != nil { 39 | f.Fatal(err) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /model3d/coords_test.go: -------------------------------------------------------------------------------- 1 | package model3d 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | func TestCoord3DOrthoBasis(t *testing.T) { 9 | testBasis := func(c Coord3D) { 10 | b1, b2 := c.OrthoBasis() 11 | if math.Abs(b1.Norm()-1) > 1e-8 || math.Abs(b2.Norm()-1) > 1e-8 { 12 | t.Error("not unit vectors") 13 | } else if math.Abs(c.Dot(b1)) > 1e-8 || math.Abs(c.Dot(b2)) > 1e-8 { 14 | t.Error("not orthogonal to original") 15 | } else if math.Abs(b1.Dot(b2)) > 1e-8 { 16 | t.Error("not orthogonal to each other") 17 | } 18 | } 19 | for i := 0; i < 100; i++ { 20 | testBasis(NewCoord3DRandNorm()) 21 | } 22 | testBasis(X(1e90)) 23 | testBasis(Y(1e90)) 24 | testBasis(Z(1e90)) 25 | } 26 | 27 | func BenchmarkCoord3DOrthoBasis(b *testing.B) { 28 | c := NewCoord3DRandNorm() 29 | for i := 0; i < b.N; i++ { 30 | c.OrthoBasis() 31 | } 32 | } 33 | 34 | func BenchmarkCoord3DFastHash(b *testing.B) { 35 | c := NewCoord3DRandNorm() 36 | for i := 0; i < b.N; i++ { 37 | c.fastHash() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /model3d/measurements.go: -------------------------------------------------------------------------------- 1 | package model3d 2 | 3 | import "math" 4 | 5 | // Area computes the total surface area of the mesh. 6 | func (m *Mesh) Area() float64 { 7 | var result float64 8 | m.Iterate(func(t *Triangle) { 9 | result += t.Area() 10 | }) 11 | return result 12 | } 13 | 14 | // Volume measures the volume of the mesh. 15 | // 16 | // This assumes that the mesh is manifold and the normals 17 | // are consistent. 18 | func (m *Mesh) Volume() float64 { 19 | var result float64 20 | m.Iterate(func(t *Triangle) { 21 | mat := Matrix3{ 22 | t[0].X, t[0].Y, t[0].Z, 23 | t[1].X, t[1].Y, t[1].Z, 24 | t[2].X, t[2].Y, t[2].Z, 25 | } 26 | result += mat.Det() / 6.0 27 | }) 28 | return math.Abs(result) 29 | } 30 | -------------------------------------------------------------------------------- /model3d/measurements_test.go: -------------------------------------------------------------------------------- 1 | package model3d 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | func TestMeshVolume(t *testing.T) { 10 | for i := 0; i < 5; i++ { 11 | solid := &Sphere{ 12 | Center: NewCoord3DRandNorm(), 13 | Radius: rand.Float64()*2 + 0.1, 14 | } 15 | mesh := MarchingCubesSearch(solid, 0.02, 8) 16 | expected := 4.0 / 3.0 * math.Pi * math.Pow(solid.Radius, 3) 17 | actual := mesh.Volume() 18 | if math.Abs(expected-actual) > 1e-2 { 19 | t.Errorf("expected volume %f but got %f", expected, actual) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /model3d/subdivision_test.go: -------------------------------------------------------------------------------- 1 | package model3d 2 | 3 | import ( 4 | "math/rand" 5 | "testing" 6 | ) 7 | 8 | func TestLoopSubdivision(t *testing.T) { 9 | base := NewMeshRect(X(-1), XYZ(1, 1, 1)) 10 | mesh := LoopSubdivision(base, 4) 11 | 12 | MustValidateMesh(t, mesh, false) 13 | } 14 | 15 | func TestSubdivideEdges(t *testing.T) { 16 | base := NewMeshTorus(XYZ(0.2, 0.3, 0.4), XY(0.5, 1.0).Normalize(), 0.2, 1.0, 5, 5) 17 | for i := 1; i < 6; i++ { 18 | mesh := SubdivideEdges(base, i) 19 | expectedN := len(base.TriangleSlice()) * i * i 20 | actualN := len(mesh.TriangleSlice()) 21 | if actualN != expectedN { 22 | t.Errorf("expected %d triangles but got %d", expectedN, actualN) 23 | } 24 | MustValidateMesh(t, mesh, true) 25 | } 26 | } 27 | 28 | func TestSubdivider(t *testing.T) { 29 | subdiv := NewSubdivider() 30 | mesh := NewMeshRect(X(-1), XYZ(1, 1, 1)) 31 | subdiv.AddFiltered(mesh, func(p1, p2 Coord3D) bool { 32 | return rand.Intn(2) == 0 33 | }) 34 | subdiv.Subdivide(mesh, func(p1, p2 Coord3D) Coord3D { 35 | x, y := p2.Sub(p1).OrthoBasis() 36 | return p1.Mid(p2).Add(x.Scale(1e-5 * rand.Float64())).Add(y.Scale(1e-5 * rand.Float64())) 37 | }) 38 | 39 | MustValidateMesh(t, mesh, false) 40 | } 41 | -------------------------------------------------------------------------------- /model3d/test_data/cube.off: -------------------------------------------------------------------------------- 1 | OFF 2 | 8 6 0 3 | -0.500000 -0.500000 0.500000 4 | 0.500000 -0.500000 0.500000 5 | -0.500000 0.500000 0.500000 6 | 0.500000 0.500000 0.500000 7 | -0.500000 0.500000 -0.500000 8 | 0.500000 0.500000 -0.500000 9 | -0.500000 -0.500000 -0.500000 10 | 0.500000 -0.500000 -0.500000 11 | 4 0 1 3 2 12 | 4 2 3 5 4 13 | 4 4 5 7 6 14 | 4 6 7 1 0 15 | 4 1 7 5 3 16 | 4 6 0 2 4 17 | -------------------------------------------------------------------------------- /model3d/test_data/hierarchy_test.stl.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/model3d/test_data/hierarchy_test.stl.gz -------------------------------------------------------------------------------- /model3d/test_data/non_intersecting_hook.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/model3d/test_data/non_intersecting_hook.stl -------------------------------------------------------------------------------- /model3d/util_test.go: -------------------------------------------------------------------------------- 1 | // Generated from templates/util_test.template 2 | 3 | package model3d 4 | 5 | import ( 6 | "fmt" 7 | "math" 8 | 9 | "github.com/pkg/errors" 10 | ) 11 | 12 | type Failer interface { 13 | Fatal(args ...any) 14 | } 15 | 16 | // ValidateMesh checks if m is manifold and has correct normals. 17 | // 18 | // If checkExtra is true, then self-intersections are tested. 19 | func ValidateMesh(m *Mesh, checkExtra bool) error { 20 | if m.NeedsRepair() { 21 | return errors.New("mesh needs repair") 22 | } 23 | if n := len(m.SingularVertices()); n > 0 { 24 | return fmt.Errorf("mesh has %d singular vertices", n) 25 | } 26 | if _, n := m.RepairNormals(1e-8); n != 0 { 27 | return fmt.Errorf("mesh has %d flipped normals", n) 28 | } 29 | if checkExtra { 30 | if n := m.SelfIntersections(); n != 0 { 31 | return fmt.Errorf("mesh has %d self-intersections", n) 32 | } 33 | } 34 | volume := m.Volume() 35 | if math.IsNaN(volume) || math.IsInf(volume, 0) { 36 | return fmt.Errorf("volume is %f", volume) 37 | } 38 | return nil 39 | } 40 | 41 | func MustValidateMesh(f Failer, m *Mesh, checkExtra bool) { 42 | if err := ValidateMesh(m, checkExtra); err != nil { 43 | f.Fatal(err) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /numerical/cg_test.go: -------------------------------------------------------------------------------- 1 | package numerical 2 | 3 | import "testing" 4 | 5 | func TestBiCGSTAB(t *testing.T) { 6 | matrix := NewSparseMatrix(5) 7 | matrix.Set(0, 0, 2.0) 8 | matrix.Set(0, 1, -2.0) 9 | matrix.Set(1, 4, 3.0) 10 | matrix.Set(1, 1, -0.1) 11 | matrix.Set(2, 0, 3.0) 12 | matrix.Set(2, 2, 1.0) 13 | matrix.Set(2, 4, -1.5) 14 | matrix.Set(3, 3, -1.0) 15 | matrix.Set(4, 3, 1.25) 16 | matrix.Set(4, 0, -0.25) 17 | 18 | groundTruth := Vec{3.14, -0.78, 2.9, 3.1, -2} 19 | b := matrix.Apply(groundTruth) 20 | 21 | // Since this is a small system, we find the exact 22 | // solution in N+1 iterations, where N is the size 23 | // of the matrix. 24 | solver := NewBiCGSTAB(matrix.Apply, b, nil) 25 | for i := 0; i < 5; i++ { 26 | solver.Iter() 27 | } 28 | solution := solver.Iter() 29 | if solution.Dist(groundTruth) > 1e-5 { 30 | t.Errorf("expected %v but got %v", groundTruth, solution) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /numerical/dense_search_test.go: -------------------------------------------------------------------------------- 1 | package numerical 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | ) 7 | 8 | func TestRecursiveLineSearch(t *testing.T) { 9 | rs := &RecursiveLineSearch[Vec3]{LineSearch: LineSearch{Stops: 10, Recursions: 4}} 10 | solution, value := rs.Minimize(Vec3{-3, -3, -3}, Vec3{3, 3, 3}, func(v Vec3) float64 { 11 | return math.Pow(v[0]-1, 2) + math.Pow(v[1]+1, 2) + math.Pow(v[2]-2, 4) + 1 12 | }) 13 | expected := Vec3{1, -1, 2} 14 | if math.Abs(value-1) > 1e-3 { 15 | t.Errorf("expected value %f but got %f", 1.0, value) 16 | } 17 | if solution.Dist(expected) > 1e-3 { 18 | t.Errorf("expected %v but got %v", expected, solution) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /numerical/gss.go: -------------------------------------------------------------------------------- 1 | package numerical 2 | 3 | import "math" 4 | 5 | const DefaultGSSIters = 64 6 | 7 | // GSS performs golden section search to find the minimum 8 | // of a unimodal function, given correct bounds on the 9 | // minimum. 10 | // 11 | // If iters is 0, DefaultGSSIters is used. 12 | func GSS(min, max float64, iters int, f func(float64) float64) float64 { 13 | if iters == 0 { 14 | iters = DefaultGSSIters 15 | } 16 | phi := (math.Sqrt(5) + 1) / 2 17 | mid1 := max - (max-min)/phi 18 | mid2 := min + (max-min)/phi 19 | val1 := f(mid1) 20 | val2 := f(mid2) 21 | for i := 0; i < iters; i++ { 22 | if mid1 <= min || mid2 <= mid1 || max <= mid2 { 23 | // Numerical precision has been exhausted. 24 | break 25 | } 26 | if val2 > val1 { 27 | max = mid2 28 | mid2 = mid1 29 | val2 = val1 30 | mid1 = max - (max-min)/phi 31 | val1 = f(mid1) 32 | } else { 33 | min = mid1 34 | mid1 = mid2 35 | val1 = val2 36 | mid2 = min + (max-min)/phi 37 | val2 = f(mid2) 38 | } 39 | } 40 | 41 | if val1 < val2 { 42 | return mid1 43 | } else { 44 | return mid2 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /numerical/sparse_matrix_test.go: -------------------------------------------------------------------------------- 1 | package numerical 2 | 3 | import ( 4 | "math/rand" 5 | "testing" 6 | ) 7 | 8 | func TestSparseMatrixPermute(t *testing.T) { 9 | matrix := NewSparseMatrix(1000) 10 | entries := map[[2]int]float64{} 11 | 12 | for i := 0; i < 100; i++ { 13 | x := rand.Intn(1000) 14 | y := rand.Intn(1000) 15 | if _, ok := entries[[2]int{x, y}]; ok { 16 | i-- 17 | continue 18 | } 19 | val := rand.NormFloat64() 20 | entries[[2]int{x, y}] = val 21 | entries[[2]int{y, x}] = val 22 | matrix.Set(x, y, val) 23 | matrix.Set(y, x, val) 24 | } 25 | 26 | perm := rand.Perm(1000) 27 | 28 | permuted := matrix.Permute(perm) 29 | permEntries := map[[2]int]bool{} 30 | for row := 0; row < 1000; row++ { 31 | permuted.Iterate(row, func(col int, x float64) { 32 | origRow := perm[row] 33 | origCol := perm[col] 34 | expected := entries[[2]int{origRow, origCol}] 35 | if x != expected { 36 | t.Errorf("unexpected entry: %f (expected %f)", x, expected) 37 | } 38 | permEntries[[2]int{row, col}] = true 39 | }) 40 | } 41 | 42 | if len(permEntries) != len(entries) { 43 | t.Errorf("expected %d entries but got %d", len(entries), len(permEntries)) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /numerical/test_data/sparse_mat.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixpickle/model3d/94de8b1e80b56af09771464364c9af2509647c1f/numerical/test_data/sparse_mat.json.gz -------------------------------------------------------------------------------- /render3d/concurrency.go: -------------------------------------------------------------------------------- 1 | package render3d 2 | 3 | import ( 4 | "math/rand" 5 | "runtime" 6 | "sync" 7 | ) 8 | 9 | type goInfo struct { 10 | Gen *rand.Rand 11 | Extra any 12 | } 13 | 14 | // mapCoordinates calls f with every coordinate in an 15 | // image, along with a per-goroutine random number 16 | // generator and the pixel index. 17 | func mapCoordinates(width, height int, f func(g *goInfo, x, y, idx int)) { 18 | coords := make(chan [3]int, width*height) 19 | var idx int 20 | for y := 0; y < height; y++ { 21 | for x := 0; x < width; x++ { 22 | coords <- [3]int{x, y, idx} 23 | idx++ 24 | } 25 | } 26 | close(coords) 27 | 28 | var wg sync.WaitGroup 29 | for i := 0; i < runtime.NumCPU(); i++ { 30 | wg.Add(1) 31 | go func() { 32 | defer wg.Done() 33 | g := &goInfo{ 34 | Gen: rand.New(rand.NewSource(rand.Int63())), 35 | } 36 | for c := range coords { 37 | f(g, c[0], c[1], c[2]) 38 | } 39 | }() 40 | } 41 | 42 | wg.Wait() 43 | } 44 | -------------------------------------------------------------------------------- /render3d/doc.go: -------------------------------------------------------------------------------- 1 | // Package render3d provides various APIs for creating and 2 | // rendering visual scenes. 3 | // 4 | // The RayCaster API can be used to render scenes quickly. 5 | // The RecursiveRayTracer API can be used to render very 6 | // realistic scenes with accurate lighting. 7 | package render3d 8 | -------------------------------------------------------------------------------- /render3d/focus_point_test.go: -------------------------------------------------------------------------------- 1 | package render3d 2 | 3 | import ( 4 | "math/rand" 5 | "testing" 6 | 7 | "github.com/unixpickle/model3d/model3d" 8 | ) 9 | 10 | func TestSampleAroundUniform(t *testing.T) { 11 | direction := model3d.NewCoord3DRandUnit() 12 | minCos := 0.83 13 | f := func(c model3d.Coord3D) model3d.Coord3D { 14 | if c.Dot(direction) < minCos { 15 | return model3d.Coord3D{} 16 | } 17 | return model3d.Coord3D{ 18 | X: c.X*c.Y - c.Z, 19 | Y: c.Z*c.Z - 0.7*c.Y*c.Y + 0.3*c.X*c.X, 20 | Z: 0.6*c.X + 0.5*c.Y + 0.3*c.Z, 21 | } 22 | } 23 | 24 | const iters = 5000000 25 | 26 | var expected model3d.Coord3D 27 | for i := 0; i < iters; i++ { 28 | expected = expected.Add(f(model3d.NewCoord3DRandUnit())) 29 | } 30 | 31 | gen := rand.New(rand.NewSource(1337)) 32 | 33 | var actual model3d.Coord3D 34 | for i := 0; i < iters; i++ { 35 | realDir := sampleAroundUniform(gen, minCos, direction) 36 | weight := 1 / densityAroundUniform(minCos, direction, realDir) 37 | actual = actual.Add(f(realDir).Scale(weight)) 38 | } 39 | 40 | diff := actual.Sub(expected).Scale(1.0 / iters) 41 | if diff.Norm() > 1e-3 { 42 | t.Errorf("expected %v but got %v", expected, actual) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /toolbox3d/angles.go: -------------------------------------------------------------------------------- 1 | package toolbox3d 2 | 3 | import "math" 4 | 5 | // AngleDist computes the (shortest) absolute distance in 6 | // radians between two angles. In the most basic case, 7 | // this is equivalent to ||theta2 - theta1||. However, it 8 | // handles the fact that angles can be offset by multiples 9 | // of 2*pi. 10 | func AngleDist(theta1, theta2 float64) float64 { 11 | theta1 = CanonicalAngle(theta1) 12 | theta2 = CanonicalAngle(theta2) 13 | diff := math.Abs(theta1 - theta2) 14 | return math.Min(diff, 2*math.Pi-diff) 15 | } 16 | 17 | // CanonicalAngle converts an angle to the range [0, 2*pi]. 18 | func CanonicalAngle(theta float64) float64 { 19 | if theta < 0 { 20 | return CanonicalAngle(2*math.Pi - theta) 21 | } 22 | return math.Mod(theta, 2*math.Pi) 23 | } 24 | -------------------------------------------------------------------------------- /toolbox3d/doc.go: -------------------------------------------------------------------------------- 1 | // Package toolbox3d provides a collection of parts for 2 | // building practical 3D models for 3D prints. 3 | package toolbox3d 4 | --------------------------------------------------------------------------------