Grafos de shaders
Un grafo de shader es un shader hecho de nodos en lugar de WGSL: entradas como UV
y Time, matemáticas, ruido, formas y colores, conectados a un nodo Output. Lo creas en la
vista de shaders del diseñador y lo guardas como archivo .pzshad;
pyzed.shading lo compila al WGSL que pz.shader ejecuta en la GPU, así que es exactamente igual de rápido que un
shader escrito a mano.
import pyzed as pz
pz.shader("shaders/fuego.pzshad", uniforms={"speed": 2.0}, width=320, height=200)Dibujar un .pzshad
Sección titulada «Dibujar un .pzshad»pz.shader acepta la ruta de un .pzshad (un str o un Path) donde acepta código WGSL. uniforms cambia las
variables mutables del shader por nombre, y los ajustes del propio shader (su color fallback, si se anima) se
aplican salvo que los pases tú:
from pathlib import Path
import pyzed as pz
SHADERS = Path(__file__).parent / "shaders"
class Menu(pz.App): speed = 1.0
def view(self): return pz.stack([ pz.shader(SHADERS / "synthwave.pzshad", width="fill", height="fill"), pz.slider(0, 3, self.speed, on_change=lambda v: setattr(self, "speed", v)), ])Cambiar una variable mutable no cuesta nada: el código se compila una vez y solo cambia el valor, así que un deslizador o una animación pueden moverla a la máxima velocidad de fotogramas.
Cargar y cambiar variables
Sección titulada «Cargar y cambiar variables»shading.load devuelve un Shader: el grafo más sus propios valores de las variables. Se guarda en caché por
ruta y se recarga solo cuando el archivo cambia, así que guardar en el diseñador actualiza una app en marcha.
from pyzed import shading
# un shader con las variables speed y tint (mutables) y octaves (una constante)fuego = shading.load("shaders/fuego.pzshad")fuego["speed"] = 2.0 # una variable mutable: no recompilafuego.set(speed=2.0, tint="#ff8800") # varias a la vezfuego.set(octaves=6) # una constante: se vuelve a generar el códigofuego.variables # {"speed": 2.0, "tint": "#ff8800", "octaves": 6}
pz.shader(fuego, width=320, height=200) # o fuego.widget(width=320, height=200)print(fuego.wgsl) # el código generado| Variable | En el grafo | Cambiarla |
|---|---|---|
| Mutable | Un uniform que la GPU lee en cada frame. | Gratis: fuego["speed"] = 2. |
| Constante | Un literal escrito en el código. | Vuelve a generar el código (bien de vez en cuando, no en cada frame). |
Las variables pueden ser float, int, bool, vec2, vec3, vec4, color (un color hex o un token del
tema como "accent") o texture (la ruta de una imagen). Un shader admite hasta 32 variables mutables y 8
texturas.
Crear un grafo en código
Sección titulada «Crear un grafo en código»shading.Graph es el mismo grafo que edita el diseñador, con una API que se lee como los nodos: llama a un tipo de
nodo sobre el grafo para añadirlo, pasa las entradas como argumentos y elige una salida con nodo["nombre"]. Las
operaciones aritméticas entre salidas añaden nodos matemáticos por ti.
from pyzed import shading
g = shading.Graph("anillos")speed = g.uniform("speed", "float", 1.0, min=0, max=4) # una variable mutable y un nodo que la lee
d = g.ring(g.centered_uv()["centered"], radius=0.3, thickness=0.02)brillo = g.glow(d["distance"], radius=0.1)tono = g.time()["time"] * speed["value"] * 0.1 # nodos Multiplycolor = g.hsv_to_rgb(tono, 0.8, 1.0)["rgb"] * brillo["value"]g.output(g.rgba(color, 1.0)["color"])
g.arrange() # columnas, de izquierda a derecha, como Arrange del diseñadorg.save("shaders/anillos.pzshad") # ábrelo en Pyzed Design para seguir editándolog.add("noise", kind="simplex", scale=4)es la forma larga;g.noise(...),g.sin(x),g.multiply(a, b)y todas las entradas de la barra funcionan como métodos. Claves como"func:sin"o"math:max"funcionan enadd.- Los argumentos posicionales van a las entradas en orden; los de palabra clave van a entradas o ajustes por
nombre. Un valor puede ser un número, una lista (un vector), un color, la salida de otro nodo o un contexto como
"@uv". nodo["x"]es una salida; los vectores tienen swizzles (uv["uv"].x,color.xyz).g.uniform(nombre, tipo, valor)yg.constant(...)añaden una variable y un nodo que la lee;g.get(nombre)añade otro lector;g.set_variable(nombre, value=..., mutable=False)la cambia.g.connect(origen, salida, destino, entrada)yg.disconnect(destino, entrada)conectan por id de nodo; se comprueban los tipos y se rechazan los ciclos (GraphError).g.compile()devuelve el WGSL (.code), los uniforms y texturas parapz.shadery los problemas por nodo (.errors);.check()también ejecuta el compilador de la GPU y pone lo que encuentra en el nodo que escribió la línea.
Nodos que hacen grafos más pequeños
Sección titulada «Nodos que hacen grafos más pequeños»| Nodo | Qué hace |
|---|---|
| Set value / Get value | Nombra un valor una vez y lo lee en cualquier parte, sin una conexión larga. |
| Expression | Tu propio WGSL: una expresión con a, b, c y d (y uv, px, size, time), o el cuerpo de una función con return. Los tipos de a–d siguen lo que tengan conectado. |
| Shader function | Otro .pzshad usado como función: sus variables mutables son entradas, su entrada uv lo mueve o lo deforma, sus salidas son el color. |
| Reroute | Un punto para llevar una conexión alrededor de otros nodos. |
En formularios y desde la línea de comandos
Sección titulada «En formularios y desde la línea de comandos»El control Shader del diseñador (caja de herramientas → Display) dibuja un .pzshad en un formulario; su
propiedad variables ({"speed": 2}) cambia las variables, desde el panel de propiedades o desde un manejador.
pyzed run fuego.pzshad muestra un shader ocupando una ventana, con deslizadores para sus variables mutables
(pulsa V).
El formato de archivo
Sección titulada «El formato de archivo»Un .pzshad es JSON: el nombre y la descripción del shader, sus variables, sus nodos (tipo, posición, entradas y
ajustes) y sus conexiones. Se compara bien en git, y un agente de IA puede escribir uno: el
servidor MCP tiene list_shader_nodes, new_shader y check_shader.
{ "format": "pyzed.shader/1", "name": "brillo", "variables": [{"name": "speed", "type": "float", "value": 1.0, "mutable": true, "min": 0, "max": 4}], "nodes": [{"id": "1", "type": "time", "x": 0, "y": 0}, "..."], "links": [{"from": "1", "out": "time", "to": "3", "in": "a"}, "..."]}