# Py5 loves 3D (P3D, hints, shaders)

**URL:** <https://discourse.processing.org/t/py5-loves-3d-p3d-hints-shaders/43821>\
**Category:** py5\
**Created:** [February 3, 2024, 2:05am UTC](https://discourse.processing.org/t/py5-loves-3d-p3d-hints-shaders/43821 "2024-02-03T02:05:26Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [February 3, 2024, 4:31am UTC](https://discourse.processing.org/t/py5-loves-3d-p3d-hints-shaders/43821/2 "2024-02-03T04:31:40Z")

</div>

> [@villares](#):
>
> `from sdf import sphere, box, cylinder, X, Y, Z`

Package’s name is “sdf-fork”: pip install sdf-fork

> [@villares](#):
>
> `import trimesh`

pip install trimesh

> [@villares](#):
>
> ```auto
> #f.save('out.stl')
> m = trimesh.load_mesh('out.stl')
> 
> ```

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”:

```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”:

```auto
#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”:

```auto
// 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];
}

```

* * *

---

_[View the full topic](https://discourse.processing.org/t/py5-loves-3d-p3d-hints-shaders/43821)._
