sdforge 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. sdforge-0.2.0/PKG-INFO +287 -0
  2. sdforge-0.2.0/README.md +248 -0
  3. sdforge-0.2.0/examples/__init__.py +0 -0
  4. sdforge-0.2.0/examples/camera.py +66 -0
  5. sdforge-0.2.0/examples/debug.py +56 -0
  6. sdforge-0.2.0/examples/export.py +32 -0
  7. sdforge-0.2.0/examples/forge.py +63 -0
  8. sdforge-0.2.0/examples/group.py +58 -0
  9. sdforge-0.2.0/examples/light.py +62 -0
  10. sdforge-0.2.0/examples/material.py +23 -0
  11. sdforge-0.2.0/examples/noise.py +57 -0
  12. sdforge-0.2.0/examples/operations.py +71 -0
  13. sdforge-0.2.0/examples/params.py +35 -0
  14. sdforge-0.2.0/examples/primitives.py +68 -0
  15. sdforge-0.2.0/examples/render.py +30 -0
  16. sdforge-0.2.0/examples/saving.py +79 -0
  17. sdforge-0.2.0/examples/shaping.py +70 -0
  18. sdforge-0.2.0/examples/transforms.py +125 -0
  19. sdforge-0.2.0/sdforge/__init__.py +30 -0
  20. sdforge-0.2.0/sdforge/core.py +340 -0
  21. sdforge-0.2.0/sdforge/debug.py +13 -0
  22. sdforge-0.2.0/sdforge/export.py +119 -0
  23. {sdforge-0.1.2/sdforge/glsl/scene → sdforge-0.2.0/sdforge/glsl}/camera.glsl +2 -2
  24. sdforge-0.2.0/sdforge/glsl/debug.glsl +15 -0
  25. sdforge-0.2.0/sdforge/glsl/noise.glsl +50 -0
  26. {sdforge-0.1.2/sdforge/glsl/sdf → sdforge-0.2.0/sdforge/glsl}/operations.glsl +7 -31
  27. {sdforge-0.1.2/sdforge/glsl/sdf → sdforge-0.2.0/sdforge/glsl}/primitives.glsl +12 -9
  28. {sdforge-0.1.2/sdforge/glsl/scene → sdforge-0.2.0/sdforge/glsl}/raymarching.glsl +2 -4
  29. sdforge-0.2.0/sdforge/glsl/shaping.glsl +23 -0
  30. {sdforge-0.1.2/sdforge/glsl/sdf → sdforge-0.2.0/sdforge/glsl}/transforms.glsl +32 -35
  31. sdforge-0.2.0/sdforge/loader.py +32 -0
  32. sdforge-0.2.0/sdforge/mesh.py +150 -0
  33. sdforge-0.2.0/sdforge/render.py +309 -0
  34. sdforge-0.2.0/sdforge/utils.py +8 -0
  35. sdforge-0.2.0/sdforge.egg-info/PKG-INFO +287 -0
  36. sdforge-0.2.0/sdforge.egg-info/SOURCES.txt +59 -0
  37. sdforge-0.2.0/sdforge.egg-info/requires.txt +15 -0
  38. sdforge-0.2.0/sdforge.egg-info/top_level.txt +3 -0
  39. {sdforge-0.1.2 → sdforge-0.2.0}/setup.py +10 -5
  40. sdforge-0.2.0/tests/__init__.py +0 -0
  41. sdforge-0.2.0/tests/camera.py +27 -0
  42. sdforge-0.2.0/tests/conftest.py +147 -0
  43. sdforge-0.2.0/tests/debug.py +64 -0
  44. sdforge-0.2.0/tests/export.py +47 -0
  45. sdforge-0.2.0/tests/forge.py +85 -0
  46. sdforge-0.2.0/tests/group.py +67 -0
  47. sdforge-0.2.0/tests/light.py +10 -0
  48. sdforge-0.2.0/tests/material.py +48 -0
  49. sdforge-0.2.0/tests/noise.py +50 -0
  50. sdforge-0.2.0/tests/operations.py +131 -0
  51. sdforge-0.2.0/tests/params.py +27 -0
  52. sdforge-0.2.0/tests/primitives.py +144 -0
  53. sdforge-0.2.0/tests/render.py +95 -0
  54. sdforge-0.2.0/tests/saving.py +78 -0
  55. sdforge-0.2.0/tests/shaping.py +58 -0
  56. sdforge-0.2.0/tests/transforms.py +124 -0
  57. sdforge-0.1.2/PKG-INFO +0 -255
  58. sdforge-0.1.2/README.md +0 -219
  59. sdforge-0.1.2/sdforge/__init__.py +0 -45
  60. sdforge-0.1.2/sdforge/api.py +0 -1078
  61. sdforge-0.1.2/sdforge/mesh.py +0 -95
  62. sdforge-0.1.2/sdforge/render.py +0 -427
  63. sdforge-0.1.2/sdforge.egg-info/PKG-INFO +0 -255
  64. sdforge-0.1.2/sdforge.egg-info/SOURCES.txt +0 -19
  65. sdforge-0.1.2/sdforge.egg-info/requires.txt +0 -11
  66. sdforge-0.1.2/sdforge.egg-info/top_level.txt +0 -1
  67. {sdforge-0.1.2 → sdforge-0.2.0}/LICENSE +0 -0
  68. {sdforge-0.1.2 → sdforge-0.2.0}/MANIFEST.in +0 -0
  69. {sdforge-0.1.2/sdforge/glsl/scene → sdforge-0.2.0/sdforge/glsl}/light.glsl +0 -0
  70. {sdforge-0.1.2 → sdforge-0.2.0}/sdforge.egg-info/dependency_links.txt +0 -0
  71. {sdforge-0.1.2 → sdforge-0.2.0}/setup.cfg +0 -0
sdforge-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,287 @@
1
+ Metadata-Version: 2.4
2
+ Name: sdforge
3
+ Version: 0.2.0
4
+ Summary: A Python library for SDF modeling with real-time GLSL rendering and mesh export.
5
+ Home-page: https://github.com/nassimberrada/sdforge
6
+ Author: nassimberrada
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
13
+ Classifier: Topic :: Scientific/Engineering :: Visualization
14
+ Requires-Python: >=3.6
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: numpy
18
+ Requires-Dist: scikit-image>=0.17
19
+ Requires-Dist: watchdog
20
+ Requires-Dist: moderngl
21
+ Requires-Dist: glfw
22
+ Provides-Extra: ui
23
+ Requires-Dist: imgui[glfw]>=2.0.0; extra == "ui"
24
+ Provides-Extra: export
25
+ Requires-Dist: pygltflib; extra == "export"
26
+ Provides-Extra: full
27
+ Requires-Dist: imgui[glfw]>=2.0.0; extra == "full"
28
+ Requires-Dist: pygltflib; extra == "full"
29
+ Dynamic: author
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: home-page
34
+ Dynamic: license-file
35
+ Dynamic: provides-extra
36
+ Dynamic: requires-dist
37
+ Dynamic: requires-python
38
+ Dynamic: summary
39
+
40
+ <p align="center">
41
+ <picture>
42
+ <source srcset="./assets/logo_dark.png" media="(prefers-color-scheme: dark)">
43
+ <source srcset="./assets/logo_light.png" media="(prefers-color-scheme: light)">
44
+ <img src="./assets/logo_light.png" alt="SDForge Logo" height="200">
45
+ </picture>
46
+ </p>
47
+
48
+ ## About
49
+
50
+ SDF Forge is a Python library for creating 3D models using Signed Distance Functions (SDFs). It provides a real-time, interactive rendering experience in a native desktop window, powered by GLSL raymarching.
51
+
52
+ ## Features
53
+
54
+ - **Simple, Pythonic API:** Define complex shapes by combining primitives using standard operators (`|`, `-`, `&`) and chaining transformations.
55
+ - **Real-time Rendering with Hot-Reloading:** Get instant visual feedback in a lightweight native window powered by `moderngl` and `glfw`. Changes to your script are reloaded automatically.
56
+ - **Mesh Exporting:** Save your creations as `.stl`, `.obj`, or `.glb` files for 3D printing or use in other software.
57
+ - **Interactive Parameters:** Define parameters that can be controlled by UI sliders in real-time (with a compatible UI renderer).
58
+ - **Standalone GLSL Export:** Export your entire scene to a single, self-contained GLSL fragment shader for use in game engines or graphics applications.
59
+ - **Custom GLSL Primitives:** Write custom SDF logic directly in GLSL using the `Forge` object for maximum flexibility and performance.
60
+
61
+ ## Getting Started
62
+
63
+ ### Hello Forge
64
+
65
+ Define a simple shape and open a real-time preview window with just a few lines of code.
66
+
67
+ ```python
68
+ from sdforge import sphere, box
69
+
70
+ # A sphere intersected with a box
71
+ shape = sphere(1) & box(1.5)
72
+
73
+ # Render a preview in a native window.
74
+ # An interactive orbit camera is used by default.
75
+ shape.render()
76
+ ```
77
+
78
+ ### Live Preview & Hot-Reloading
79
+ For an interactive workflow, wrap your scene definition in a `main()` function. When you save any changes to the file, the preview window will automatically update.
80
+
81
+ ```python
82
+ from sdforge import box, sphere
83
+
84
+ def main():
85
+ """
86
+ While this script is running, try changing the values below and
87
+ saving the file. The render window will update automatically.
88
+ """
89
+ box_size = 1.5
90
+ sphere_radius = 1.2
91
+
92
+ scene = box(box_size, radius=0.1) | sphere(sphere_radius)
93
+ return scene
94
+
95
+ if __name__ == "__main__":
96
+ # The render() function automatically enables hot-reloading by default
97
+ # and looks for a `main` function in this file to call upon reload.
98
+ scene = main()
99
+ scene.render()
100
+ ```
101
+
102
+ ### Saving to a Mesh File
103
+ You can save any static model to an `.stl`, `.obj`, or `.glb` file. The `.save()` method uses the Marching Cubes algorithm to generate a mesh from the SDF.
104
+
105
+ ```python
106
+ from sdforge import sphere, box
107
+
108
+ # A box with a sphere carved out of it
109
+ shape = box(1.5) - sphere(1.2)
110
+
111
+ # Save the model. Higher samples = more detail.
112
+ shape.save('model.obj', samples=2**22)
113
+ ```
114
+
115
+ ## Core Concepts
116
+
117
+ ### Primitives & Operations
118
+ Create complex objects by starting with primitives and combining them with Python's bitwise operators: `|` for union, `&` for intersection, and `-` for difference.
119
+
120
+ ```python
121
+ from sdforge import sphere, box
122
+
123
+ # A box with a sphere carved out of it.
124
+ b = box(size=1.5)
125
+ s = sphere(r=1.0)
126
+ scene = b - s
127
+
128
+ scene.render()
129
+ ```
130
+
131
+ ### Transformations & Shaping
132
+ Chain methods to transform, shape, and repeat objects.
133
+
134
+ ```python
135
+ import numpy as np
136
+ from sdforge import box, Y
137
+
138
+ # A tall box
139
+ b = box(size=(0.5, 2.5, 0.5))
140
+
141
+ # Twist it around the Y-axis
142
+ # The 'k' parameter controls the amount of twist.
143
+ scene = b.twist(k=3.0).rotate(Y, np.pi / 4)
144
+
145
+ scene.render()
146
+ ```
147
+
148
+ ### Materials
149
+ You can assign a unique color to any object or group of objects using the `.color()` method.
150
+
151
+ ```python
152
+ from sdforge import sphere, box
153
+
154
+ # A blue sphere is subtracted from a red box.
155
+ red_box = box(1.5, radius=0.1).color(1.0, 0.2, 0.2)
156
+ blue_sphere = sphere(1.2).color(0.3, 0.5, 1.0)
157
+
158
+ scene = red_box - blue_sphere
159
+
160
+ scene.render()
161
+ ```
162
+
163
+ ### Camera & Lighting
164
+ You can override the default interactive camera and lighting to set a static viewpoint or create specific lighting conditions by passing `Camera` and `Light` objects to the renderer.
165
+
166
+ ```python
167
+ from sdforge import box, sphere, Camera, Light
168
+
169
+ def main():
170
+ scene = box(1.5, radius=0.1) | sphere(1.2)
171
+
172
+ # A camera positioned at (4, 3, 4), looking at the origin.
173
+ cam = Camera(position=(4, 3, 4), target=(0, 0, 0), zoom=1.5)
174
+
175
+ # A light source with soft shadows
176
+ light = Light(position=(4, 5, 3), shadow_softness=16.0)
177
+
178
+ return scene, cam, light
179
+
180
+ if __name__ == '__main__':
181
+ scene, cam, light = main()
182
+ scene.render(camera=cam, light=light)
183
+ ```
184
+
185
+ ## Advanced Usage
186
+
187
+ ### Interactive Parameters
188
+ Use `Param` objects to define interactive, real-time parameters for your model. A compatible UI-enabled renderer would show these as sliders. The default renderer will use their default values.
189
+
190
+ ```python
191
+ from sdforge import box, Param
192
+
193
+ # Create Param objects to control different aspects of the scene.
194
+ # Param(name, default_value, min_value, max_value)
195
+ p_size = Param("Box Size", 0.8, 0.2, 2.0)
196
+ p_radius = Param("Corner Radius", 0.1, 0.0, 0.5)
197
+
198
+ # Use the Param objects just like regular numbers.
199
+ scene = box(size=p_size, radius=p_radius)
200
+
201
+ scene.render()
202
+ ```
203
+
204
+ ### Custom GLSL with `Forge`
205
+ For complex or highly-performant shapes, you can write GLSL code directly. This object integrates perfectly with the rest of the API.
206
+
207
+ ```python
208
+ from sdforge import sphere, Forge
209
+
210
+ # A standard library primitive
211
+ s = sphere(1.2)
212
+
213
+ # A custom shape defined with GLSL
214
+ # 'p' is the vec3 point in space
215
+ custom_box = Forge("""
216
+ vec3 q = abs(p) - vec3(0.8);
217
+ return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
218
+ """)
219
+
220
+ # The Forge object can be combined like any other shape
221
+ scene = s - custom_box
222
+
223
+ scene.render()
224
+ ```
225
+
226
+ ### Standalone GLSL Export
227
+ Generate a complete, self-contained GLSL fragment shader for your scene. This file can be used directly in applications like Godot, TouchDesigner, or Three.js.
228
+
229
+ ```python
230
+ from sdforge import box, sphere
231
+
232
+ scene = box(1.5, radius=0.1) - sphere(1.2)
233
+
234
+ # This single call generates the entire shader file.
235
+ scene.export_shader("exported_shader.glsl")
236
+ ```
237
+
238
+ ## Installation
239
+
240
+ ### 1. System Dependencies
241
+
242
+ The live viewer relies on `glfw`, which may require you to install its system-level libraries first. This is a common first step before installing the Python package.
243
+
244
+ **On Debian/Ubuntu:**
245
+ ```bash
246
+ sudo apt-get install libglfw3-dev
247
+ ```
248
+
249
+ **On macOS (with Homebrew):**
250
+ ```bash
251
+ brew install glfw
252
+ ```
253
+ **On Windows:**
254
+ `glfw` is generally bundled with the Python wheels, so no separate installation is typically needed.
255
+
256
+ ### 2. Python Package
257
+
258
+ The library and its core dependencies can be installed using pip.
259
+
260
+ **Standard Installation:**
261
+ This will install the core library, including `numpy`, `moderngl`, and `glfw`, enabling all fundamental features like modeling, live preview with hot-reloading, and exporting to `.stl` and `.obj` formats.
262
+
263
+ ```bash
264
+ pip install sdforge
265
+ ```
266
+
267
+ **Optional Features:**
268
+ For additional functionality, you can install "extras":
269
+
270
+ * **`.glb` Export:** To enable saving models to the GLB format, a modern and efficient format for web and game engines.
271
+ ```bash
272
+ pip install "sdforge[export]"
273
+ ```
274
+
275
+ * **Interactive UI:** To enable UI widgets like sliders for `Param` objects.
276
+ ```bash
277
+ pip install "sdforge[ui]"
278
+ ```
279
+
280
+ * **Full Installation:** To install all optional features at once.
281
+ ```bash
282
+ pip install "sdforge[full]"
283
+ ```
284
+
285
+ ## Acknowledgements
286
+
287
+ This project is inspired by the simplicity and elegant API of Michael Fogleman's [fogleman/sdf](https://github.com/fogleman/sdf) library. SDF Forge aims to build on that foundation by adding a real-time, interactive GLSL-powered renderer.
@@ -0,0 +1,248 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source srcset="./assets/logo_dark.png" media="(prefers-color-scheme: dark)">
4
+ <source srcset="./assets/logo_light.png" media="(prefers-color-scheme: light)">
5
+ <img src="./assets/logo_light.png" alt="SDForge Logo" height="200">
6
+ </picture>
7
+ </p>
8
+
9
+ ## About
10
+
11
+ SDF Forge is a Python library for creating 3D models using Signed Distance Functions (SDFs). It provides a real-time, interactive rendering experience in a native desktop window, powered by GLSL raymarching.
12
+
13
+ ## Features
14
+
15
+ - **Simple, Pythonic API:** Define complex shapes by combining primitives using standard operators (`|`, `-`, `&`) and chaining transformations.
16
+ - **Real-time Rendering with Hot-Reloading:** Get instant visual feedback in a lightweight native window powered by `moderngl` and `glfw`. Changes to your script are reloaded automatically.
17
+ - **Mesh Exporting:** Save your creations as `.stl`, `.obj`, or `.glb` files for 3D printing or use in other software.
18
+ - **Interactive Parameters:** Define parameters that can be controlled by UI sliders in real-time (with a compatible UI renderer).
19
+ - **Standalone GLSL Export:** Export your entire scene to a single, self-contained GLSL fragment shader for use in game engines or graphics applications.
20
+ - **Custom GLSL Primitives:** Write custom SDF logic directly in GLSL using the `Forge` object for maximum flexibility and performance.
21
+
22
+ ## Getting Started
23
+
24
+ ### Hello Forge
25
+
26
+ Define a simple shape and open a real-time preview window with just a few lines of code.
27
+
28
+ ```python
29
+ from sdforge import sphere, box
30
+
31
+ # A sphere intersected with a box
32
+ shape = sphere(1) & box(1.5)
33
+
34
+ # Render a preview in a native window.
35
+ # An interactive orbit camera is used by default.
36
+ shape.render()
37
+ ```
38
+
39
+ ### Live Preview & Hot-Reloading
40
+ For an interactive workflow, wrap your scene definition in a `main()` function. When you save any changes to the file, the preview window will automatically update.
41
+
42
+ ```python
43
+ from sdforge import box, sphere
44
+
45
+ def main():
46
+ """
47
+ While this script is running, try changing the values below and
48
+ saving the file. The render window will update automatically.
49
+ """
50
+ box_size = 1.5
51
+ sphere_radius = 1.2
52
+
53
+ scene = box(box_size, radius=0.1) | sphere(sphere_radius)
54
+ return scene
55
+
56
+ if __name__ == "__main__":
57
+ # The render() function automatically enables hot-reloading by default
58
+ # and looks for a `main` function in this file to call upon reload.
59
+ scene = main()
60
+ scene.render()
61
+ ```
62
+
63
+ ### Saving to a Mesh File
64
+ You can save any static model to an `.stl`, `.obj`, or `.glb` file. The `.save()` method uses the Marching Cubes algorithm to generate a mesh from the SDF.
65
+
66
+ ```python
67
+ from sdforge import sphere, box
68
+
69
+ # A box with a sphere carved out of it
70
+ shape = box(1.5) - sphere(1.2)
71
+
72
+ # Save the model. Higher samples = more detail.
73
+ shape.save('model.obj', samples=2**22)
74
+ ```
75
+
76
+ ## Core Concepts
77
+
78
+ ### Primitives & Operations
79
+ Create complex objects by starting with primitives and combining them with Python's bitwise operators: `|` for union, `&` for intersection, and `-` for difference.
80
+
81
+ ```python
82
+ from sdforge import sphere, box
83
+
84
+ # A box with a sphere carved out of it.
85
+ b = box(size=1.5)
86
+ s = sphere(r=1.0)
87
+ scene = b - s
88
+
89
+ scene.render()
90
+ ```
91
+
92
+ ### Transformations & Shaping
93
+ Chain methods to transform, shape, and repeat objects.
94
+
95
+ ```python
96
+ import numpy as np
97
+ from sdforge import box, Y
98
+
99
+ # A tall box
100
+ b = box(size=(0.5, 2.5, 0.5))
101
+
102
+ # Twist it around the Y-axis
103
+ # The 'k' parameter controls the amount of twist.
104
+ scene = b.twist(k=3.0).rotate(Y, np.pi / 4)
105
+
106
+ scene.render()
107
+ ```
108
+
109
+ ### Materials
110
+ You can assign a unique color to any object or group of objects using the `.color()` method.
111
+
112
+ ```python
113
+ from sdforge import sphere, box
114
+
115
+ # A blue sphere is subtracted from a red box.
116
+ red_box = box(1.5, radius=0.1).color(1.0, 0.2, 0.2)
117
+ blue_sphere = sphere(1.2).color(0.3, 0.5, 1.0)
118
+
119
+ scene = red_box - blue_sphere
120
+
121
+ scene.render()
122
+ ```
123
+
124
+ ### Camera & Lighting
125
+ You can override the default interactive camera and lighting to set a static viewpoint or create specific lighting conditions by passing `Camera` and `Light` objects to the renderer.
126
+
127
+ ```python
128
+ from sdforge import box, sphere, Camera, Light
129
+
130
+ def main():
131
+ scene = box(1.5, radius=0.1) | sphere(1.2)
132
+
133
+ # A camera positioned at (4, 3, 4), looking at the origin.
134
+ cam = Camera(position=(4, 3, 4), target=(0, 0, 0), zoom=1.5)
135
+
136
+ # A light source with soft shadows
137
+ light = Light(position=(4, 5, 3), shadow_softness=16.0)
138
+
139
+ return scene, cam, light
140
+
141
+ if __name__ == '__main__':
142
+ scene, cam, light = main()
143
+ scene.render(camera=cam, light=light)
144
+ ```
145
+
146
+ ## Advanced Usage
147
+
148
+ ### Interactive Parameters
149
+ Use `Param` objects to define interactive, real-time parameters for your model. A compatible UI-enabled renderer would show these as sliders. The default renderer will use their default values.
150
+
151
+ ```python
152
+ from sdforge import box, Param
153
+
154
+ # Create Param objects to control different aspects of the scene.
155
+ # Param(name, default_value, min_value, max_value)
156
+ p_size = Param("Box Size", 0.8, 0.2, 2.0)
157
+ p_radius = Param("Corner Radius", 0.1, 0.0, 0.5)
158
+
159
+ # Use the Param objects just like regular numbers.
160
+ scene = box(size=p_size, radius=p_radius)
161
+
162
+ scene.render()
163
+ ```
164
+
165
+ ### Custom GLSL with `Forge`
166
+ For complex or highly-performant shapes, you can write GLSL code directly. This object integrates perfectly with the rest of the API.
167
+
168
+ ```python
169
+ from sdforge import sphere, Forge
170
+
171
+ # A standard library primitive
172
+ s = sphere(1.2)
173
+
174
+ # A custom shape defined with GLSL
175
+ # 'p' is the vec3 point in space
176
+ custom_box = Forge("""
177
+ vec3 q = abs(p) - vec3(0.8);
178
+ return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
179
+ """)
180
+
181
+ # The Forge object can be combined like any other shape
182
+ scene = s - custom_box
183
+
184
+ scene.render()
185
+ ```
186
+
187
+ ### Standalone GLSL Export
188
+ Generate a complete, self-contained GLSL fragment shader for your scene. This file can be used directly in applications like Godot, TouchDesigner, or Three.js.
189
+
190
+ ```python
191
+ from sdforge import box, sphere
192
+
193
+ scene = box(1.5, radius=0.1) - sphere(1.2)
194
+
195
+ # This single call generates the entire shader file.
196
+ scene.export_shader("exported_shader.glsl")
197
+ ```
198
+
199
+ ## Installation
200
+
201
+ ### 1. System Dependencies
202
+
203
+ The live viewer relies on `glfw`, which may require you to install its system-level libraries first. This is a common first step before installing the Python package.
204
+
205
+ **On Debian/Ubuntu:**
206
+ ```bash
207
+ sudo apt-get install libglfw3-dev
208
+ ```
209
+
210
+ **On macOS (with Homebrew):**
211
+ ```bash
212
+ brew install glfw
213
+ ```
214
+ **On Windows:**
215
+ `glfw` is generally bundled with the Python wheels, so no separate installation is typically needed.
216
+
217
+ ### 2. Python Package
218
+
219
+ The library and its core dependencies can be installed using pip.
220
+
221
+ **Standard Installation:**
222
+ This will install the core library, including `numpy`, `moderngl`, and `glfw`, enabling all fundamental features like modeling, live preview with hot-reloading, and exporting to `.stl` and `.obj` formats.
223
+
224
+ ```bash
225
+ pip install sdforge
226
+ ```
227
+
228
+ **Optional Features:**
229
+ For additional functionality, you can install "extras":
230
+
231
+ * **`.glb` Export:** To enable saving models to the GLB format, a modern and efficient format for web and game engines.
232
+ ```bash
233
+ pip install "sdforge[export]"
234
+ ```
235
+
236
+ * **Interactive UI:** To enable UI widgets like sliders for `Param` objects.
237
+ ```bash
238
+ pip install "sdforge[ui]"
239
+ ```
240
+
241
+ * **Full Installation:** To install all optional features at once.
242
+ ```bash
243
+ pip install "sdforge[full]"
244
+ ```
245
+
246
+ ## Acknowledgements
247
+
248
+ This project is inspired by the simplicity and elegant API of Michael Fogleman's [fogleman/sdf](https://github.com/fogleman/sdf) library. SDF Forge aims to build on that foundation by adding a real-time, interactive GLSL-powered renderer.
File without changes
@@ -0,0 +1,66 @@
1
+ import sys
2
+ from sdforge import box, sphere, Camera
3
+
4
+ def static_camera_example():
5
+ """
6
+ Returns a scene and a fixed Camera object.
7
+ The renderer will use this camera's position and target.
8
+ """
9
+ scene = box(1.5, radius=0.1) | sphere(1.2)
10
+
11
+ # Define a camera positioned at (4, 3, 4), looking at the origin.
12
+ cam = Camera(position=(4, 3, 4), target=(0, 0, 0), zoom=1.5)
13
+
14
+ return scene, cam
15
+
16
+ def interactive_camera_example():
17
+ """
18
+ Returns only a scene.
19
+ When no camera is provided to the render function, it defaults
20
+ to an interactive orbit camera controlled by the mouse.
21
+ """
22
+ scene = box(1.5, radius=0.1) | sphere(1.2)
23
+ return scene
24
+
25
+ def main():
26
+ """
27
+ Renders an example based on a command-line argument.
28
+ """
29
+ print("--- SDForge Camera Examples ---")
30
+
31
+ examples = {
32
+ "static": static_camera_example,
33
+ "interactive": interactive_camera_example,
34
+ }
35
+
36
+ if len(sys.argv) < 2:
37
+ print("\nPlease provide the name of an example to run.")
38
+ print("Available examples:")
39
+ for key in examples:
40
+ print(f" - {key}")
41
+ print(f"\nUsage: python {sys.argv[0]} <example_name>")
42
+ return
43
+
44
+ example_name = sys.argv[1]
45
+ scene_func = examples.get(example_name)
46
+
47
+ if not scene_func:
48
+ print(f"\nError: Example '{example_name}' not found.")
49
+ print("Available examples are:")
50
+ for key in examples:
51
+ print(f" - {key}")
52
+ return
53
+
54
+ print(f"Rendering: {example_name.replace('_', ' ').title()} Example")
55
+ result = scene_func()
56
+
57
+ # Handle both return types: (scene, camera) or just scene
58
+ if isinstance(result, tuple):
59
+ scene, cam = result
60
+ scene.render(camera=cam)
61
+ else:
62
+ scene = result
63
+ scene.render() # camera=None, defaults to interactive
64
+
65
+ if __name__ == "__main__":
66
+ main()
@@ -0,0 +1,56 @@
1
+ import sys
2
+ from sdforge import box, sphere, Debug
3
+
4
+ def normals_debug_example():
5
+ """Visualizes the surface normals as colors."""
6
+ scene = box(1.5, radius=0.1) - sphere(1.2)
7
+ debug = Debug('normals')
8
+ return scene, debug
9
+
10
+ def steps_debug_example():
11
+ """Visualizes the number of raymarching steps."""
12
+ scene = box(1.5, radius=0.1) - sphere(1.2)
13
+ debug = Debug('steps')
14
+ return scene, debug
15
+
16
+ def main():
17
+ """Renders a debug example based on a command-line argument."""
18
+ print("--- SDForge Debug Examples ---")
19
+
20
+ examples = {
21
+ "normals": normals_debug_example,
22
+ "steps": steps_debug_example,
23
+ }
24
+
25
+ if len(sys.argv) < 2:
26
+ print("\nPlease provide the name of an example to run.")
27
+ print("Available examples:")
28
+ for key in examples:
29
+ print(f" - {key}")
30
+ print(f"\nUsage: python {sys.argv[0]} <example_name>")
31
+ return
32
+
33
+ example_name = sys.argv[1]
34
+ scene_func = examples.get(example_name)
35
+
36
+ if not scene_func:
37
+ print(f"\nError: Example '{example_name}' not found.")
38
+ return
39
+
40
+ print(f"Rendering: {example_name.replace('_', ' ').title()} Example")
41
+ result = scene_func()
42
+
43
+ scene, debug = None, None
44
+ for item in result:
45
+ from sdforge.core import SDFNode
46
+ if isinstance(item, SDFNode): scene = item
47
+ if isinstance(item, Debug): debug = item
48
+
49
+ if scene:
50
+ scene.render(debug=debug)
51
+ else:
52
+ print("Error: Example function did not return a scene object.")
53
+
54
+
55
+ if __name__ == "__main__":
56
+ main()
@@ -0,0 +1,32 @@
1
+ import sys
2
+ import os
3
+ from sdforge import box, sphere, Param
4
+
5
+ def main():
6
+ """
7
+ Demonstrates exporting a complete, standalone GLSL shader file.
8
+ """
9
+ print("--- SDForge Shader Export Example ---")
10
+
11
+ # Create a scene with some complexity and a parameter.
12
+ p_radius = Param("Sphere Radius", 0.8, 0.5, 1.5)
13
+ scene = box(1.5, radius=0.1) - sphere(p_radius)
14
+
15
+ output_path = "exported_shader.glsl"
16
+ print(f"Exporting scene to '{output_path}'...")
17
+
18
+ # This single call generates the entire shader file.
19
+ scene.export_shader(output_path)
20
+
21
+ if os.path.exists(output_path):
22
+ print("\nSUCCESS! You can now use this shader file in other applications")
23
+ print("that support GLSL fragment shaders, like Godot, TouchDesigner, or Three.js.")
24
+ else:
25
+ print("\nERROR: Shader export failed.")
26
+
27
+ # We can also render the scene as usual.
28
+ return scene
29
+
30
+ if __name__ == "__main__":
31
+ scene = main()
32
+ scene.render()