diff --git a/create_glb.py b/create_glb.py new file mode 100644 index 0000000..701a9dc --- /dev/null +++ b/create_glb.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# create_glb.py — Blender headless STL -> GLB +# +# Example: +# blender-bin-5.0.0 --background --python create_glb.py -- input.stl [output.glb] + +import bpy +import sys +import os +from mathutils import Vector + +def die(msg, rc=2): + print(f"ERROR: {msg}") + raise SystemExit(rc) + +# args after "--" +argv = sys.argv +argv = argv[argv.index("--") + 1:] if "--" in argv else [] + +if len(argv) == 1: + inp = argv[0] + base, _ = os.path.splitext(inp) + outp = base + ".glb" +elif len(argv) >= 2: + inp, outp = argv[0], argv[1] +else: + die("USAGE: blender --background --python create_glb.py -- input.stl [output.glb]") + +if not os.path.exists(inp): + die(f"Input not found: {inp}") + +# Empty scene +bpy.ops.wm.read_factory_settings(use_empty=True) + +# Import STL (Blender 4/5 operator) +res = bpy.ops.wm.stl_import(filepath=inp) +if 'FINISHED' not in res: + die(f"STL import failed for: {inp}") + +# Gather imported mesh objects +objs = [o for o in bpy.context.scene.objects if o.type == 'MESH'] +if not objs: + die("No mesh objects after import (unexpected)") + +# Compute combined bounding box center in world space +min_v = Vector(( 1e30, 1e30, 1e30)) +max_v = Vector((-1e30, -1e30, -1e30)) + +for o in objs: + # object bound_box is in local coords; transform to world + for corner in o.bound_box: + v = o.matrix_world @ Vector(corner) + min_v.x = min(min_v.x, v.x); min_v.y = min(min_v.y, v.y); min_v.z = min(min_v.z, v.z) + max_v.x = max(max_v.x, v.x); max_v.y = max(max_v.y, v.y); max_v.z = max(max_v.z, v.z) + +center = (min_v + max_v) * 0.5 + +# Translate all meshes so center is at origin +for o in objs: + o.location -= center + +# Export GLB +res = bpy.ops.export_scene.gltf( + filepath=outp, + export_format='GLB', + export_apply=True, +) +if 'FINISHED' not in res: + die(f"GLB export failed: {outp}") + +print(f"Wrote: {outp}") \ No newline at end of file diff --git a/creating_glbs.md b/creating_glbs.md new file mode 100644 index 0000000..df1a1d3 --- /dev/null +++ b/creating_glbs.md @@ -0,0 +1,14 @@ + + + +Here is a command to create a single glb: + + blender-bin-5.0.0 --background --python create_glb.py -- \ + /usr/local/src/Voron-Stealthburner/STLs/Stealthburner/'[o]_stealthburner_LED_carrier.stl' \ + /tmp/out.glb + +The git repository for Voron-Stealthburner was staged under /usr/local/src. The above command +selects a specific STL and then places the STL under /tmp. + +In a production mode, we want to be able to point to a directory tree of STLs and then +generate glb equivalents in the similar tree structure. \ No newline at end of file diff --git a/exercises/create_png_from_glb/README.md b/exercises/create_png_from_glb/README.md new file mode 100644 index 0000000..e69de29 diff --git a/exercises/create_png_profile/20260304_101254_Wed.png b/exercises/create_png_profile/20260304_101254_Wed.png new file mode 100644 index 0000000..23a84a7 Binary files /dev/null and b/exercises/create_png_profile/20260304_101254_Wed.png differ diff --git a/exercises/create_png_profile/20260304_101754_Wed.png b/exercises/create_png_profile/20260304_101754_Wed.png new file mode 100644 index 0000000..e9eb68e Binary files /dev/null and b/exercises/create_png_profile/20260304_101754_Wed.png differ diff --git a/exercises/create_png_profile/20260304_102737_Wed.png b/exercises/create_png_profile/20260304_102737_Wed.png new file mode 100644 index 0000000..37602b5 Binary files /dev/null and b/exercises/create_png_profile/20260304_102737_Wed.png differ diff --git a/exercises/create_png_profile/20260304_102919_Wed.png b/exercises/create_png_profile/20260304_102919_Wed.png new file mode 100644 index 0000000..9790d34 Binary files /dev/null and b/exercises/create_png_profile/20260304_102919_Wed.png differ diff --git a/exercises/create_png_profile/README.md b/exercises/create_png_profile/README.md new file mode 100644 index 0000000..a731784 --- /dev/null +++ b/exercises/create_png_profile/README.md @@ -0,0 +1,260 @@ +# Goal +Create a "profile", i.e. a JSON file, to be used by the script that mass converts *.glb to *.png + +## Introduction +This exercise only requires that you launch a small HTTP server in a console. Otherwise, everything involved is handled through the HTML page lab.html. You will interact with lab.html's 3D rendering of a glb file that is included with this project. + +## Steps +Open a browser or a new window of the browser (Ctrl-n in Firefox) and resize the browser to a small rectangle. You are reducing the size so as to mimic what the PNG cell in the manifest table will look like. For example, this reduced window +is 521 × 432 pixels. + + +In a console: + + cd ~/work/Voron/voronstl/web + python3 -m http.server 8001 + +You should have a console that looks like this: + + + +It is necessary to start the web server within the "web" directory as that directory +will be servers "root". + + +Visit: + + http://localhost:8001/lab.html + + +You will see a zoomed-in image: + + +Zoom out until the entire part fits within the window. + +Click the Controls bar to collapse the sub menus. + +Move the object to center it in the window: Shift + left mouse button. You want to have the entire part fit within the view and be cenetered. + +Click Controls bar to open the sub menus. Adjust the lighintensity to a high value, if not the maximum values. This will cause the image to go lighter allowing for contrast with shadows that help discern the part. + +Optional: Save the PNG for your own reference. + +Click "Export Profile" and save your current settings. + + + +You now have a specification on sizing and angles which may work well for all of the other parts. Note: I took mine and applied the specifications saved above for a mass PNG creation and all the others looked very good. + +### Additional Information: +Here's what a JSON file looks like: + +
| Image | +Description | +
|---|---|
+
+ |
+
+jlpoole@jp ~/work/Voron/voronstl/web $ jq . out/three_profile_20260304_102657.json
+{
+ "provenance": "lab.html exportProfile Wed Mar 04 2026 10:26:57 GMT-0800 (Pacific Standard Time)",
+ "output": {
+ "width": 500,
+ "height": 315,
+ "pixelRatio": 1
+ },
+ "scene": {
+ "background": 16777215
+ },
+ "camera": {
+ "type": "PerspectiveCamera",
+ "fov": 50,
+ "near": 0.1,
+ "far": 1000,
+ "position": [
+ 11.93432933230491,
+ 11.71721921868296,
+ 13.265804443912849
+ ],
+ "up": [
+ 0,
+ 1,
+ 0
+ ]
+ },
+ "controls": {
+ "target": [
+ 2.075876663103527,
+ -2.147814989328729,
+ 0.7122034073683343
+ ]
+ },
+ "renderParams": {
+ "wireframe": false,
+ "edgeAngle": 30,
+ "lightIntensity": 1.5
+ },
+ "lights": {
+ "directional": {
+ "position": [
+ 5,
+ 5,
+ 5
+ ],
+ "intensity": 1.5
+ },
+ "ambient": {
+ "intensity": 0.6
+ }
+ }
+}
+jlpoole@jp ~/work/Voron/voronstl/web $
+
+ |
+