sdforge 0.1.3__tar.gz → 0.2.1__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 (101) hide show
  1. sdforge-0.2.1/PKG-INFO +290 -0
  2. sdforge-0.2.1/README.md +248 -0
  3. sdforge-0.2.1/examples/__init__.py +0 -0
  4. sdforge-0.2.1/examples/camera.py +66 -0
  5. sdforge-0.2.1/examples/constraints.py +213 -0
  6. sdforge-0.2.1/examples/debug.py +72 -0
  7. sdforge-0.2.1/examples/export.py +32 -0
  8. sdforge-0.2.1/examples/forge.py +63 -0
  9. sdforge-0.2.1/examples/group.py +58 -0
  10. sdforge-0.2.1/examples/light.py +62 -0
  11. sdforge-0.2.1/examples/material.py +65 -0
  12. sdforge-0.2.1/examples/noise.py +57 -0
  13. sdforge-0.2.1/examples/operations.py +149 -0
  14. sdforge-0.2.1/examples/params.py +35 -0
  15. sdforge-0.2.1/examples/primitives.py +130 -0
  16. sdforge-0.2.1/examples/render.py +30 -0
  17. sdforge-0.2.1/examples/saving.py +166 -0
  18. sdforge-0.2.1/examples/shaping.py +102 -0
  19. sdforge-0.2.1/examples/sketch.py +99 -0
  20. sdforge-0.2.1/examples/transforms.py +141 -0
  21. sdforge-0.2.1/sdforge/__init__.py +14 -0
  22. sdforge-0.2.1/sdforge/api/__init__.py +0 -0
  23. sdforge-0.2.1/sdforge/api/camera.py +29 -0
  24. sdforge-0.2.1/sdforge/api/constraints.py +277 -0
  25. sdforge-0.2.1/sdforge/api/core.py +618 -0
  26. sdforge-0.2.1/sdforge/api/cpu.py +748 -0
  27. sdforge-0.2.1/sdforge/api/debug.py +28 -0
  28. sdforge-0.2.1/sdforge/api/export.py +119 -0
  29. sdforge-0.2.1/sdforge/api/forge.py +45 -0
  30. sdforge-0.2.1/sdforge/api/gpu.py +163 -0
  31. sdforge-0.2.1/sdforge/api/group.py +51 -0
  32. sdforge-0.2.1/sdforge/api/light.py +32 -0
  33. sdforge-0.2.1/sdforge/api/loader.py +69 -0
  34. sdforge-0.2.1/sdforge/api/material.py +62 -0
  35. sdforge-0.2.1/sdforge/api/mesh.py +403 -0
  36. sdforge-0.2.1/sdforge/api/noise.py +35 -0
  37. sdforge-0.2.1/sdforge/api/operations.py +167 -0
  38. sdforge-0.2.1/sdforge/api/params.py +76 -0
  39. sdforge-0.2.1/sdforge/api/primitives.py +544 -0
  40. sdforge-0.2.1/sdforge/api/render.py +441 -0
  41. sdforge-0.2.1/sdforge/api/shaping.py +95 -0
  42. sdforge-0.2.1/sdforge/api/sketch.py +121 -0
  43. sdforge-0.2.1/sdforge/api/transforms.py +209 -0
  44. sdforge-0.2.1/sdforge/api/utils.py +55 -0
  45. {sdforge-0.1.3/sdforge/glsl/scene → sdforge-0.2.1/sdforge/glsl}/camera.glsl +2 -2
  46. sdforge-0.2.1/sdforge/glsl/debug.glsl +34 -0
  47. sdforge-0.2.1/sdforge/glsl/noise.glsl +58 -0
  48. sdforge-0.2.1/sdforge/glsl/operations.glsl +73 -0
  49. {sdforge-0.1.3/sdforge/glsl/sdf → sdforge-0.2.1/sdforge/glsl}/primitives.glsl +72 -42
  50. sdforge-0.2.1/sdforge/glsl/raymarching.glsl +39 -0
  51. sdforge-0.2.1/sdforge/glsl/shaping.glsl +23 -0
  52. sdforge-0.2.1/sdforge/glsl/transforms.glsl +101 -0
  53. sdforge-0.2.1/sdforge.egg-info/PKG-INFO +290 -0
  54. sdforge-0.2.1/sdforge.egg-info/SOURCES.txt +79 -0
  55. sdforge-0.2.1/sdforge.egg-info/requires.txt +19 -0
  56. sdforge-0.2.1/sdforge.egg-info/top_level.txt +3 -0
  57. {sdforge-0.1.3 → sdforge-0.2.1}/setup.py +14 -5
  58. sdforge-0.2.1/tests/__init__.py +0 -0
  59. sdforge-0.2.1/tests/camera.py +27 -0
  60. sdforge-0.2.1/tests/conftest.py +81 -0
  61. sdforge-0.2.1/tests/constraints.py +267 -0
  62. sdforge-0.2.1/tests/debug.py +110 -0
  63. sdforge-0.2.1/tests/export.py +47 -0
  64. sdforge-0.2.1/tests/forge.py +77 -0
  65. sdforge-0.2.1/tests/group.py +67 -0
  66. sdforge-0.2.1/tests/light.py +10 -0
  67. sdforge-0.2.1/tests/material.py +77 -0
  68. sdforge-0.2.1/tests/noise.py +64 -0
  69. sdforge-0.2.1/tests/operations.py +210 -0
  70. sdforge-0.2.1/tests/params.py +27 -0
  71. sdforge-0.2.1/tests/primitives.py +241 -0
  72. sdforge-0.2.1/tests/render.py +172 -0
  73. sdforge-0.2.1/tests/saving.py +187 -0
  74. sdforge-0.2.1/tests/shaping.py +85 -0
  75. sdforge-0.2.1/tests/sketch.py +112 -0
  76. sdforge-0.2.1/tests/transforms.py +378 -0
  77. sdforge-0.1.3/PKG-INFO +0 -255
  78. sdforge-0.1.3/README.md +0 -219
  79. sdforge-0.1.3/sdforge/__init__.py +0 -37
  80. sdforge-0.1.3/sdforge/api.py +0 -1369
  81. sdforge-0.1.3/sdforge/glsl/scene/raymarching.glsl +0 -25
  82. sdforge-0.1.3/sdforge/glsl/sdf/operations.glsl +0 -65
  83. sdforge-0.1.3/sdforge/glsl/sdf/transforms.glsl +0 -109
  84. sdforge-0.1.3/sdforge/mesh.py +0 -96
  85. sdforge-0.1.3/sdforge/render.py +0 -434
  86. sdforge-0.1.3/sdforge.egg-info/PKG-INFO +0 -255
  87. sdforge-0.1.3/sdforge.egg-info/SOURCES.txt +0 -26
  88. sdforge-0.1.3/sdforge.egg-info/requires.txt +0 -11
  89. sdforge-0.1.3/sdforge.egg-info/top_level.txt +0 -1
  90. sdforge-0.1.3/tests/test_api_operations.py +0 -185
  91. sdforge-0.1.3/tests/test_api_primitives.py +0 -266
  92. sdforge-0.1.3/tests/test_api_transforms.py +0 -201
  93. sdforge-0.1.3/tests/test_examples.py +0 -37
  94. sdforge-0.1.3/tests/test_glsl.py +0 -361
  95. sdforge-0.1.3/tests/test_rendering.py +0 -108
  96. sdforge-0.1.3/tests/test_saving.py +0 -72
  97. {sdforge-0.1.3 → sdforge-0.2.1}/LICENSE +0 -0
  98. {sdforge-0.1.3 → sdforge-0.2.1}/MANIFEST.in +0 -0
  99. {sdforge-0.1.3/sdforge/glsl/scene → sdforge-0.2.1/sdforge/glsl}/light.glsl +0 -0
  100. {sdforge-0.1.3 → sdforge-0.2.1}/sdforge.egg-info/dependency_links.txt +0 -0
  101. {sdforge-0.1.3 → sdforge-0.2.1}/setup.cfg +0 -0
sdforge-0.2.1/PKG-INFO ADDED
@@ -0,0 +1,290 @@
1
+ Metadata-Version: 2.4
2
+ Name: sdforge
3
+ Version: 0.2.1
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: saving
27
+ Requires-Dist: trimesh; extra == "saving"
28
+ Provides-Extra: full
29
+ Requires-Dist: imgui[glfw]>=2.0.0; extra == "full"
30
+ Requires-Dist: pygltflib; extra == "full"
31
+ Requires-Dist: trimesh; extra == "full"
32
+ Dynamic: author
33
+ Dynamic: classifier
34
+ Dynamic: description
35
+ Dynamic: description-content-type
36
+ Dynamic: home-page
37
+ Dynamic: license-file
38
+ Dynamic: provides-extra
39
+ Dynamic: requires-dist
40
+ Dynamic: requires-python
41
+ Dynamic: summary
42
+
43
+ <p align="center">
44
+ <picture>
45
+ <source srcset="./assets/logo_dark.png" media="(prefers-color-scheme: dark)">
46
+ <source srcset="./assets/logo_light.png" media="(prefers-color-scheme: light)">
47
+ <img src="./assets/logo_light.png" alt="SDForge Logo" height="200">
48
+ </picture>
49
+ </p>
50
+
51
+ ## About
52
+
53
+ 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.
54
+
55
+ ## Features
56
+
57
+ - **Simple, Pythonic API:** Define complex shapes by combining primitives using standard operators (`|`, `-`, `&`) and chaining transformations.
58
+ - **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.
59
+ - **Mesh Exporting:** Save your creations as `.stl`, `.obj`, or `.glb` files for 3D printing or use in other software.
60
+ - **Interactive Parameters:** Define parameters that can be controlled by UI sliders in real-time (with a compatible UI renderer).
61
+ - **Standalone GLSL Export:** Export your entire scene to a single, self-contained GLSL fragment shader for use in game engines or graphics applications.
62
+ - **Custom GLSL Primitives:** Write custom SDF logic directly in GLSL using the `Forge` object for maximum flexibility and performance.
63
+
64
+ ## Getting Started
65
+
66
+ ### Hello Forge
67
+
68
+ Define a simple shape and open a real-time preview window with just a few lines of code.
69
+
70
+ ```python
71
+ from sdforge import sphere, box
72
+
73
+ # A sphere intersected with a box
74
+ shape = sphere(1) & box(1.5)
75
+
76
+ # Render a preview in a native window.
77
+ # An interactive orbit camera is used by default.
78
+ shape.render()
79
+ ```
80
+
81
+ ### Live Preview & Hot-Reloading
82
+ 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.
83
+
84
+ ```python
85
+ from sdforge import box, sphere
86
+
87
+ def main():
88
+ """
89
+ While this script is running, try changing the values below and
90
+ saving the file. The render window will update automatically.
91
+ """
92
+ box_size = 1.5
93
+ sphere_radius = 1.2
94
+
95
+ scene = box(box_size, radius=0.1) | sphere(sphere_radius)
96
+ return scene
97
+
98
+ if __name__ == "__main__":
99
+ # The render() function automatically enables hot-reloading by default
100
+ # and looks for a `main` function in this file to call upon reload.
101
+ scene = main()
102
+ scene.render()
103
+ ```
104
+
105
+ ### Saving to a Mesh File
106
+ 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.
107
+
108
+ ```python
109
+ from sdforge import sphere, box
110
+
111
+ # A box with a sphere carved out of it
112
+ shape = box(1.5) - sphere(1.2)
113
+
114
+ # Save the model. Higher samples = more detail.
115
+ shape.save('model.obj', samples=2**22)
116
+ ```
117
+
118
+ ## Core Concepts
119
+
120
+ ### Primitives & Operations
121
+ Create complex objects by starting with primitives and combining them with Python's bitwise operators: `|` for union, `&` for intersection, and `-` for difference.
122
+
123
+ ```python
124
+ from sdforge import sphere, box
125
+
126
+ # A box with a sphere carved out of it.
127
+ b = box(size=1.5)
128
+ s = sphere(r=1.0)
129
+ scene = b - s
130
+
131
+ scene.render()
132
+ ```
133
+
134
+ ### Transformations & Shaping
135
+ Chain methods to transform, shape, and repeat objects.
136
+
137
+ ```python
138
+ import numpy as np
139
+ from sdforge import box, Y
140
+
141
+ # A tall box
142
+ b = box(size=(0.5, 2.5, 0.5))
143
+
144
+ # Twist it around the Y-axis
145
+ # The 'k' parameter controls the amount of twist.
146
+ scene = b.twist(k=3.0).rotate(Y, np.pi / 4)
147
+
148
+ scene.render()
149
+ ```
150
+
151
+ ### Materials
152
+ You can assign a unique color to any object or group of objects using the `.color()` method.
153
+
154
+ ```python
155
+ from sdforge import sphere, box
156
+
157
+ # A blue sphere is subtracted from a red box.
158
+ red_box = box(1.5, radius=0.1).color(1.0, 0.2, 0.2)
159
+ blue_sphere = sphere(1.2).color(0.3, 0.5, 1.0)
160
+
161
+ scene = red_box - blue_sphere
162
+
163
+ scene.render()
164
+ ```
165
+
166
+ ### Camera & Lighting
167
+ 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.
168
+
169
+ ```python
170
+ from sdforge import box, sphere, Camera, Light
171
+
172
+ def main():
173
+ scene = box(1.5, radius=0.1) | sphere(1.2)
174
+
175
+ # A camera positioned at (4, 3, 4), looking at the origin.
176
+ cam = Camera(position=(4, 3, 4), target=(0, 0, 0), zoom=1.5)
177
+
178
+ # A light source with soft shadows
179
+ light = Light(position=(4, 5, 3), shadow_softness=16.0)
180
+
181
+ return scene, cam, light
182
+
183
+ if __name__ == '__main__':
184
+ scene, cam, light = main()
185
+ scene.render(camera=cam, light=light)
186
+ ```
187
+
188
+ ## Advanced Usage
189
+
190
+ ### Interactive Parameters
191
+ 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.
192
+
193
+ ```python
194
+ from sdforge import box, Param
195
+
196
+ # Create Param objects to control different aspects of the scene.
197
+ # Param(name, default_value, min_value, max_value)
198
+ p_size = Param("Box Size", 0.8, 0.2, 2.0)
199
+ p_radius = Param("Corner Radius", 0.1, 0.0, 0.5)
200
+
201
+ # Use the Param objects just like regular numbers.
202
+ scene = box(size=p_size, radius=p_radius)
203
+
204
+ scene.render()
205
+ ```
206
+
207
+ ### Custom GLSL with `Forge`
208
+ For complex or highly-performant shapes, you can write GLSL code directly. This object integrates perfectly with the rest of the API.
209
+
210
+ ```python
211
+ from sdforge import sphere, Forge
212
+
213
+ # A standard library primitive
214
+ s = sphere(1.2)
215
+
216
+ # A custom shape defined with GLSL
217
+ # 'p' is the vec3 point in space
218
+ custom_box = Forge("""
219
+ vec3 q = abs(p) - vec3(0.8);
220
+ return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
221
+ """)
222
+
223
+ # The Forge object can be combined like any other shape
224
+ scene = s - custom_box
225
+
226
+ scene.render()
227
+ ```
228
+
229
+ ### Standalone GLSL Export
230
+ 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.
231
+
232
+ ```python
233
+ from sdforge import box, sphere
234
+
235
+ scene = box(1.5, radius=0.1) - sphere(1.2)
236
+
237
+ # This single call generates the entire shader file.
238
+ scene.export_shader("exported_shader.glsl")
239
+ ```
240
+
241
+ ## Installation
242
+
243
+ ### 1. System Dependencies
244
+
245
+ 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.
246
+
247
+ **On Debian/Ubuntu:**
248
+ ```bash
249
+ sudo apt-get install libglfw3-dev
250
+ ```
251
+
252
+ **On macOS (with Homebrew):**
253
+ ```bash
254
+ brew install glfw
255
+ ```
256
+ **On Windows:**
257
+ `glfw` is generally bundled with the Python wheels, so no separate installation is typically needed.
258
+
259
+ ### 2. Python Package
260
+
261
+ The library and its core dependencies can be installed using pip.
262
+
263
+ **Standard Installation:**
264
+ 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.
265
+
266
+ ```bash
267
+ pip install sdforge
268
+ ```
269
+
270
+ **Optional Features:**
271
+ For additional functionality, you can install "extras":
272
+
273
+ * **`.glb` Export:** To enable saving models to the GLB format, a modern and efficient format for web and game engines.
274
+ ```bash
275
+ pip install "sdforge[export]"
276
+ ```
277
+
278
+ * **Interactive UI:** To enable UI widgets like sliders for `Param` objects.
279
+ ```bash
280
+ pip install "sdforge[ui]"
281
+ ```
282
+
283
+ * **Full Installation:** To install all optional features at once.
284
+ ```bash
285
+ pip install "sdforge[full]"
286
+ ```
287
+
288
+ ## Acknowledgements
289
+
290
+ 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).round(0.1) | sphere(radius=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).round(0.1) | sphere(radius=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()