Package’s name is “sdf-fork”: pip install sdf-fork
pip install trimesh
No mention we need to uncomment f.save('out.stl')
in order to have the STL file.
So I’ve added some code to execute f.save('out.stl')
if it doesn’t exist already:
“sketch_2024_01_30.py”:
"""
* Toon Shading
*
* Example showing the use of a custom lighting shader in order to apply
* a "toon" effect on the scene. Based on the glsl tutorial from lighthouse 3D:
* https://Lighthouse3d.com/tutorials/glsl-tutorial/toon-shader-version-ii/
*
* https://Discourse.Processing.org/t/py5-loves-3d-pd3-hints-shaders/43821/2
"""
import py5 # https://py5Coding.org/content/install.html
from trimesh import load_mesh # pip install -U trimesh[easy]
from sdf import sphere, box, cylinder, X, Y, Z # pip install sdfcad or sdf-fork
from os.path import isfile
STL_FILE, FRAG_FILE, VERT_FILE = 'out.stl', 'ToonFrag.glsl', 'ToonVert.glsl'
MOUSE_STEP, SHAPE_SCALE = .01, .4
shader_enabled = lights_enabled = False
def settings(): py5.size(700, 550, py5.P3D)
def setup():
py5.fill(0o320)
py5.no_stroke()
global shape, toon, shape_scale, cx, cy
shape = py5.convert_shape(mesh)
shape.disable_style()
toon = py5.load_shader(FRAG_FILE, VERT_FILE)
shape_scale = min(py5.width, py5.height) * SHAPE_SCALE
cx, cy = py5.width >> 1, py5.height >> 1
def draw():
py5.background(0)
lights_enabled and py5.lights()
py5.directional_light(204, 204, 204, 0, 0, -1)
py5.translate(cx, cy)
py5.rotate_x(py5.mouse_y * MOUSE_STEP)
py5.rotate_y(py5.mouse_x * MOUSE_STEP)
py5.scale(shape_scale)
py5.shape(shape, 0, 0)
def mouse_pressed():
global shader_enabled, lights_enabled
shader_enabled ^= py5.mouse_button == py5.LEFT
py5.shader(toon) if shader_enabled else py5.reset_shader()
lights_enabled ^= py5.mouse_button == py5.RIGHT
def create_stl_file(filename=STL_FILE):
c = cylinder(.5)
f = sphere(1) & box(1.5)
f -= c.orient(X) | c.orient(Y) | c.orient(Z)
f.save(filename)
def main(filename=STL_FILE):
isfile(filename) or create_stl_file(filename)
global mesh
mesh = load_mesh(filename)
py5.run_sketch(sketch_functions = SKETCH_CALLBACKS_DICT)
SKETCH_CALLBACKS = settings, setup, draw, mouse_pressed
SKETCH_CALLBACKS_DICT = { funct.__name__: funct for funct in SKETCH_CALLBACKS }
__name__ == '__main__' and main()
“ToonFrag.glsl”:
#version 330 core
precision mediump float;
precision mediump int;
in vec3 vertNormal, vertLightDir;
out vec4 fragColor;
const vec4 colors[] = {
vec4(.2, .15, .15, 1),
vec4(.4, .25, .25, 1),
vec4(.6, .35, .35, 1),
vec4(1, .5, .5, 1)
};
void main() {
fragColor = colors[ int(4 * clamp(dot(vertLightDir, vertNormal), 0, 1)) ];
}
“ToonVert.glsl”:
// Toon shader using per-pixel lighting. Based on the glsl
// tutorial from lighthouse 3D:
// https://Lighthouse3d.com/tutorials/glsl-tutorial/toon-shader-version-ii/
#version 330 core
#define PROCESSING_LIGHT_SHADER
precision mediump float;
uniform vec3 lightNormal[8];
uniform mat4 transform;
uniform mat3 normalMatrix;
in vec4 vertex;
in vec3 normal;
out vec3 vertNormal, vertLightDir;
void main() {
// Vertex in clip coordinates.
gl_Position = transform * vertex;
// Normal the vector if eye coordinates are passed
// to the fragment shader.
vertNormal = normalize(normalMatrix * normal);
// Assuming that there is only one directional light,
// its normal vector is passed to the fragment shader
// in order to perform per-pixel lighting calculation.
vertLightDir = -lightNormal[0];
}