1use crate::material_graph::{GraphMode, MaterialGraph};
12use crate::material_presets::Preset;
13
14const BASE: usize = 0;
15const ROUGH: usize = 1;
16const METAL: usize = 2;
17const EMIT: usize = 3;
18const AO: usize = 5;
19const NORMAL: usize = 6;
20
21const WORLD: u8 = 2; const UV: u8 = 0;
24const FACTOR: u8 = 0;
25const COLOUR: u8 = 1; const EDGE: u8 = 2; const CELL: u8 = 3; const MASK: u8 = 1; const BRICK_VALUE: u8 = 2;
30const SLOPE: u8 = 5; const NORMAL_UP: u8 = 1; const ADD: f32 = 0.0;
35const SUB: f32 = 1.0;
36const MUL: f32 = 2.0;
37const POW: f32 = 4.0;
38const ABS: f32 = 7.0;
39const SIN: f32 = 17.0;
40const MULADD: f32 = 25.0;
41
42const MIX: f32 = 0.0;
44const MULTIPLY: f32 = 1.0;
45const OVERLAY: f32 = 3.0;
46
47struct G {
49 g: MaterialGraph,
50 out: u32,
51 col: [f32; 8],
52}
53
54impl G {
55 fn new() -> Self {
56 let mut g = MaterialGraph { nodes: Vec::new(), textures: Default::default(), next_id: 1, mode: GraphMode::Material };
57 let out = g.add_node("Output", [1900.0, 140.0]);
58 G { g, out, col: [0.0; 8] }
59 }
60
61 fn node(&mut self, kind: &str, column: usize, params: &[f32]) -> u32 {
62 let c = column.min(7);
63 let y = self.col[c];
64 let id = self.g.add_node(kind, [40.0 + c as f32 * 260.0, 30.0 + y]);
65 let n = self.g.nodes.iter_mut().find(|n| n.id == id).unwrap();
66 for (i, v) in params.iter().enumerate() {
67 n.params[i] = *v;
68 }
69 let h = 60.0 + (n.inputs.len() + n.params.len() + crate::material_nodes_v4::outputs(kind).len()) as f32 * 24.0;
70 self.col[c] += h.max(120.0);
71 id
72 }
73
74 fn value(&mut self, id: u32, input: usize, v: [f32; 3]) {
75 let n = self.g.nodes.iter_mut().find(|n| n.id == id).unwrap();
76 n.inputs[input].value = v;
77 n.inputs[input].override_default = true;
78 }
79
80 fn num(&mut self, id: u32, input: usize, v: f32) {
81 self.value(id, input, [v; 3]);
82 }
83
84 fn link(&mut self, from: u32, out: u8, to: u32, input: usize, convert: u8) {
86 assert!(self.g.connect_output(from, out, to, input, convert), "link {from}.{out} -> {to}.{input}");
87 }
88
89 fn out(&mut self, from: u32, out: u8, socket: usize) {
90 let o = self.out;
91 self.link(from, out, o, socket, 0);
92 }
93
94 fn out_value(&mut self, socket: usize, v: f32) {
95 let o = self.out;
96 self.num(o, socket, v);
97 }
98
99 fn world(&mut self, scale: f32) -> u32 {
101 let tc = self.node("Texture coordinate", 0, &[]);
102 let m = self.node("Mapping", 0, &[0.0, 0.0, 0.0, 0.0, scale, scale, scale]);
103 self.link(tc, WORLD, m, 0, 0);
104 m
105 }
106
107 fn uv(&mut self, scale: f32) -> u32 {
108 let tc = self.node("Texture coordinate", 0, &[]);
109 let m = self.node("Mapping", 0, &[0.0, 0.0, 0.0, 0.0, scale, scale, 1.0]);
110 self.link(tc, UV, m, 0, 0);
111 m
112 }
113
114 fn noise(&mut self, coords: u32, scale: f32, detail: f32, roughness: f32, distortion: f32, column: usize) -> u32 {
115 let n = self.node("Noise texture", column, &[0.0, 2.0]);
116 self.link(coords, 0, n, 0, 0);
117 self.num(n, 1, scale);
118 self.num(n, 2, detail);
119 self.num(n, 3, roughness);
120 self.num(n, 4, distortion);
121 n
122 }
123
124 fn voronoi(&mut self, coords: u32, scale: f32, randomness: f32, column: usize) -> u32 {
125 let v = self.node("Voronoi texture", column, &[0.0]);
126 self.link(coords, 0, v, 0, 0);
127 self.num(v, 1, scale);
128 self.num(v, 2, randomness);
129 v
130 }
131
132 fn math(&mut self, op: f32, column: usize, clamp: bool) -> u32 {
133 self.node("Math", column, &[op, if clamp { 1.0 } else { 0.0 }])
134 }
135
136 fn ramp(&mut self, source: u32, out: u8, stops: [[f32; 3]; 4], pos: [f32; 4], ease: bool, column: usize) -> u32 {
137 let r = self.node("Color ramp", column, &[pos[0], pos[1], pos[2], pos[3], if ease { 2.0 } else { 0.0 }]);
138 for (i, s) in stops.iter().enumerate() {
139 self.value(r, i + 1, *s);
140 }
141 self.link(source, out, r, 0, 0);
142 r
143 }
144
145 fn mix(&mut self, mode: f32, column: usize) -> u32 {
147 self.node("Mix colour", column, &[mode, 0.0])
148 }
149
150 fn map(&mut self, source: u32, out: u8, lo: f32, hi: f32, column: usize) -> u32 {
151 let m = self.node("Map range", column, &[0.0, 1.0, lo, hi]);
152 self.link(source, out, m, 0, 0);
153 m
154 }
155
156 fn bump(&mut self, height: u32, out: u8, strength: f32, distance: f32, column: usize) -> u32 {
157 let b = self.node("Bump", column, &[0.0]);
158 self.link(height, out, b, 0, 4);
159 self.num(b, 1, strength);
160 self.num(b, 2, distance);
161 self.out(b, 0, NORMAL);
162 b
163 }
164}
165
166pub fn marble(base: [f32; 3], vein: [f32; 3], warp: f32, frequency: f32) -> MaterialGraph {
169 let mut b = G::new();
170 let p = b.world(3.0);
171 let dir = b.node("Vector math", 1, &[7.0]);
173 b.link(p, 0, dir, 0, 0);
174 b.value(dir, 1, [0.82, 0.31, 0.48]);
175 let turb = b.noise(p, 0.9, 7.0, 0.58, 0.35, 1);
177 let along = b.math(MUL, 2, false);
178 b.link(dir, 0, along, 0, 1);
179 b.num(along, 1, frequency);
180 let phase = b.math(MULADD, 2, false);
181 b.link(turb, FACTOR, phase, 0, 0);
182 b.num(phase, 1, warp);
183 b.link(along, 0, phase, 2, 0);
184 let wave = b.math(SIN, 3, false);
185 b.link(phase, 0, wave, 0, 0);
186 let veins = b.math(ABS, 3, false);
187 b.link(wave, 0, veins, 0, 0);
188 let fine_phase = b.math(MULADD, 2, false);
190 b.link(turb, FACTOR, fine_phase, 0, 0);
191 b.num(fine_phase, 1, warp * 2.3);
192 b.link(along, 0, fine_phase, 2, 0);
193 let fine_sin = b.math(SIN, 3, false);
194 b.link(fine_phase, 0, fine_sin, 0, 0);
195 let fine_abs = b.math(ABS, 3, false);
196 b.link(fine_sin, 0, fine_abs, 0, 0);
197 let fine_soft = b.math(POW, 4, true);
198 b.link(fine_abs, 0, fine_soft, 0, 0);
199 b.num(fine_soft, 1, 0.35);
200 let mid = [(base[0] + vein[0]) * 0.5, (base[1] + vein[1]) * 0.5, (base[2] + vein[2]) * 0.5];
201 let colour = b.ramp(veins, 0, [vein, mid, base, [base[0] * 1.03, base[1] * 1.03, base[2] * 1.02]], [0.0, 0.035, 0.16, 1.0], true, 4);
202 let faint = b.mix(MULTIPLY, 5);
203 b.num(faint, 0, 0.25);
204 b.link(colour, 0, faint, 1, 0);
205 b.link(fine_soft, 0, faint, 2, 0);
206 let clouds = b.noise(p, 2.4, 4.0, 0.5, 0.0, 4);
208 let cloudy = b.mix(OVERLAY, 6);
209 b.num(cloudy, 0, 0.3);
210 b.link(faint, 0, cloudy, 1, 0);
211 b.link(clouds, COLOUR, cloudy, 2, 0);
212 b.out(cloudy, 0, BASE);
213 let rough = b.map(veins, 0, 0.32, 0.08, 5);
215 b.out(rough, 0, ROUGH);
216 b.out_value(METAL, 0.0);
217 b.bump(veins, 0, 0.08, 0.01, 6);
218 b.g
219}
220
221fn brick_wall(c1: [f32; 3], c2: [f32; 3], mortar: [f32; 3], scale: f32, moss: f32) -> MaterialGraph {
223 let mut b = G::new();
224 let p = b.uv(scale);
225 let bricks = b.node("Brick texture", 1, &[2.1, 0.5, 0.045, 0.03, 0.8]);
226 b.link(p, 0, bricks, 0, 0);
227 b.value(bricks, 1, c1);
228 b.value(bricks, 2, c2);
229 b.value(bricks, 3, mortar);
230 b.num(bricks, 4, 4.0);
231 let w = b.world(1.0);
232 let grime = b.noise(w, 3.0, 6.0, 0.6, 0.2, 1);
233 let dirty = b.mix(MULTIPLY, 2);
234 b.num(dirty, 0, 0.55);
235 b.link(bricks, 0, dirty, 1, 0);
236 b.link(grime, COLOUR, dirty, 2, 0);
237 let up = b.node("Normal", 2, &[]);
239 let moss_noise = b.noise(w, 5.0, 5.0, 0.6, 0.0, 2);
240 let moss_mask = b.math(MUL, 3, true);
241 b.link(up, NORMAL_UP, moss_mask, 0, 0);
242 b.link(moss_noise, FACTOR, moss_mask, 1, 0);
243 let moss_k = b.math(MUL, 3, true);
244 b.link(moss_mask, 0, moss_k, 0, 0);
245 b.num(moss_k, 1, moss * 2.0);
246 let mossy = b.mix(MIX, 4);
247 b.link(moss_k, 0, mossy, 0, 0);
248 b.link(dirty, 0, mossy, 1, 0);
249 b.value(mossy, 2, [0.07, 0.16, 0.04]);
250 b.out(mossy, 0, BASE);
251 let rough = b.map(grime, FACTOR, 0.75, 0.98, 4);
252 b.out(rough, 0, ROUGH);
253 let ao = b.map(bricks, MASK, 0.45, 1.0, 4);
254 b.out(ao, 0, AO);
255 b.out_value(METAL, 0.0);
256 let pits = b.noise(w, 18.0, 3.0, 0.5, 0.0, 4);
258 let height = b.math(MULADD, 5, false);
259 b.link(pits, FACTOR, height, 0, 0);
260 b.num(height, 1, 0.15);
261 b.link(bricks, MASK, height, 2, 0);
262 b.bump(height, 0, 0.9, 0.06, 6);
263 b.g
264}
265
266fn cobbles(stone_a: [f32; 3], stone_b: [f32; 3], gap: [f32; 3], scale: f32) -> MaterialGraph {
268 let mut b = G::new();
269 let p = b.world(1.0);
270 let jitter = b.node("Jitter coords", 1, &[3.0]);
271 b.link(p, 0, jitter, 0, 0);
272 b.num(jitter, 1, 0.12);
273 let cells = b.voronoi(jitter, scale, 0.9, 1);
274 let stone = b.mix(MIX, 2);
275 b.link(cells, CELL, stone, 0, 0);
276 b.value(stone, 1, stone_a);
277 b.value(stone, 2, stone_b);
278 let edge = b.node("Smoothstep", 2, &[0.0, 0.12]);
279 b.link(cells, EDGE, edge, 0, 0);
280 let grain = b.noise(p, 14.0, 4.0, 0.6, 0.0, 2);
281 let grainy = b.mix(OVERLAY, 3);
282 b.num(grainy, 0, 0.4);
283 b.link(stone, 0, grainy, 1, 0);
284 b.link(grain, COLOUR, grainy, 2, 0);
285 let with_gaps = b.mix(MIX, 4);
286 b.link(edge, 0, with_gaps, 0, 0);
287 b.value(with_gaps, 1, gap);
288 b.link(grainy, 0, with_gaps, 2, 0);
289 b.out(with_gaps, 0, BASE);
290 let rough = b.map(edge, 0, 1.0, 0.7, 4);
291 b.out(rough, 0, ROUGH);
292 b.out(edge, 0, AO);
293 b.out_value(METAL, 0.0);
294 let dome = b.math(POW, 5, false);
295 b.link(edge, 0, dome, 0, 0);
296 b.num(dome, 1, 0.5);
297 b.bump(dome, 0, 1.2, 0.08, 6);
298 b.g
299}
300
301fn planks(light: [f32; 3], dark: [f32; 3], scale: f32, worn: f32) -> MaterialGraph {
303 let mut b = G::new();
304 let p = b.uv(scale);
305 let boards = b.node("Brick texture", 1, &[6.0, 0.37, 0.012, 0.006, 0.7]);
306 b.link(p, 0, boards, 0, 0);
307 b.num(boards, 4, 3.0);
308 let stretch = b.node("Mapping", 1, &[0.0, 0.0, 0.0, 0.0, 1.0, 18.0, 1.0]);
310 b.link(p, 0, stretch, 0, 0);
311 let grain = b.noise(stretch, 2.5, 6.0, 0.62, 1.2, 2);
312 let rings = b.node("Wave texture", 2, &[0.0, 0.0]);
313 b.link(stretch, 0, rings, 0, 0);
314 b.num(rings, 1, 1.4);
315 b.num(rings, 2, 6.0);
316 let both = b.math(MUL, 3, true);
317 b.link(grain, FACTOR, both, 0, 0);
318 b.link(rings, 0, both, 1, 0);
319 let wood = b.ramp(both, 0, [[dark[0] * 0.7, dark[1] * 0.7, dark[2] * 0.7], dark, light, [light[0] * 1.08, light[1] * 1.06, light[2] * 1.04]], [0.0, 0.25, 0.6, 1.0], true, 4);
320 let tone = b.node("Hue saturation value", 5, &[]);
322 b.link(wood, 0, tone, 0, 0);
323 b.link(boards, BRICK_VALUE, tone, 3, 11);
324 let gaps = b.mix(MIX, 6);
325 b.link(boards, MASK, gaps, 0, 0);
326 b.value(gaps, 1, [0.03, 0.02, 0.012]);
327 b.link(tone, 0, gaps, 2, 0);
328 b.out(gaps, 0, BASE);
329 let rough = b.map(grain, FACTOR, 0.45 + worn * 0.3, 0.8, 5);
330 b.out(rough, 0, ROUGH);
331 b.out(boards, MASK, AO);
332 b.out_value(METAL, 0.0);
333 let height = b.math(MULADD, 6, false);
334 b.link(grain, FACTOR, height, 0, 0);
335 b.num(height, 1, 0.2);
336 b.link(boards, MASK, height, 2, 0);
337 b.bump(height, 0, 0.7, 0.03, 7);
338 b.g
339}
340
341fn chipped_paint(paint: [f32; 3], under: [f32; 3], rusty: bool) -> MaterialGraph {
343 let mut b = G::new();
344 let p = b.world(1.0);
345 let chips = b.noise(p, 3.5, 8.0, 0.65, 0.3, 1);
346 let chip_mask = b.node("Smoothstep", 2, &[0.56, 0.6]);
347 b.link(chips, FACTOR, chip_mask, 0, 0);
348 let stains = b.noise(p, 8.0, 5.0, 0.6, 0.0, 1);
349 let metal_col = b.mix(OVERLAY, 2);
350 b.num(metal_col, 0, 0.6);
351 b.value(metal_col, 1, under);
352 b.link(stains, COLOUR, metal_col, 2, 0);
353 let col = b.mix(MIX, 3);
354 b.link(chip_mask, 0, col, 0, 0);
355 b.value(col, 1, paint);
356 b.link(metal_col, 0, col, 2, 0);
357 let geo = b.node("Geometry info", 3, &[]);
359 let dust = b.mix(MULTIPLY, 4);
360 b.link(geo, SLOPE, dust, 0, 0);
361 b.num(dust, 0, 0.15);
362 b.link(col, 0, dust, 1, 0);
363 b.value(dust, 2, [0.6, 0.55, 0.5]);
364 b.out(dust, 0, BASE);
365 let rough = b.map(chip_mask, 0, 0.35, if rusty { 0.95 } else { 0.4 }, 4);
366 b.out(rough, 0, ROUGH);
367 let metal = b.map(chip_mask, 0, 0.0, if rusty { 0.3 } else { 1.0 }, 4);
368 b.out(metal, 0, METAL);
369 b.bump(chip_mask, 0, -0.5, 0.01, 5);
370 b.g
371}
372
373fn ground(low: [f32; 3], high: [f32; 3], rocks: [f32; 3], scale: f32, rough: f32) -> MaterialGraph {
375 let mut b = G::new();
376 let p = b.world(1.0);
377 let big = b.noise(p, scale * 0.35, 6.0, 0.55, 0.4, 1);
378 let mix = b.mix(MIX, 2);
379 b.link(big, FACTOR, mix, 0, 0);
380 b.value(mix, 1, low);
381 b.value(mix, 2, high);
382 let pebbles = b.voronoi(p, scale * 2.2, 1.0, 1);
383 let peb_mask = b.node("Smoothstep", 2, &[0.32, 0.22]);
384 b.link(pebbles, 1, peb_mask, 0, 0);
385 let peb_noise = b.noise(p, scale * 3.0, 3.0, 0.5, 0.0, 2);
386 let peb_sparse = b.math(MUL, 3, true);
387 b.link(peb_mask, 0, peb_sparse, 0, 0);
388 b.link(peb_noise, FACTOR, peb_sparse, 1, 0);
389 let peb_cut = b.node("Smoothstep", 3, &[0.25, 0.4]);
390 b.link(peb_sparse, 0, peb_cut, 0, 0);
391 let with_rocks = b.mix(MIX, 4);
392 b.link(peb_cut, 0, with_rocks, 0, 0);
393 b.link(mix, 0, with_rocks, 1, 0);
394 b.value(with_rocks, 2, rocks);
395 let fine = b.noise(p, scale * 6.0, 3.0, 0.6, 0.0, 4);
396 let detail = b.mix(OVERLAY, 5);
397 b.num(detail, 0, 0.35);
398 b.link(with_rocks, 0, detail, 1, 0);
399 b.link(fine, COLOUR, detail, 2, 0);
400 b.out(detail, 0, BASE);
401 let r = b.map(big, FACTOR, rough, (rough + 0.15).min(1.0), 5);
402 b.out(r, 0, ROUGH);
403 b.out_value(METAL, 0.0);
404 let height = b.math(MULADD, 5, false);
405 b.link(fine, FACTOR, height, 0, 0);
406 b.num(height, 1, 0.3);
407 b.link(peb_cut, 0, height, 2, 0);
408 b.bump(height, 0, 0.8, 0.04, 6);
409 b.g
410}
411
412fn glowing_cracks(crust: [f32; 3], glow: [f32; 3], scale: f32, intensity: f32) -> MaterialGraph {
414 let mut b = G::new();
415 let p = b.world(1.0);
416 let jitter = b.node("Jitter coords", 1, &[2.0]);
417 b.link(p, 0, jitter, 0, 0);
418 b.num(jitter, 1, 0.25);
419 let cells = b.voronoi(jitter, scale, 1.0, 1);
420 let crack = b.node("Smoothstep", 2, &[0.08, 0.0]);
421 b.link(cells, EDGE, crack, 0, 0);
422 let pulse = b.node("Time", 2, &[]);
423 let flicker = b.noise(p, 1.5, 3.0, 0.5, 0.0, 2);
424 let live = b.math(MULADD, 3, false);
425 b.link(pulse, 1, live, 0, 0);
426 b.num(live, 1, 0.35);
427 b.link(flicker, FACTOR, live, 2, 0);
428 let heat = b.math(MUL, 4, false);
429 b.link(crack, 0, heat, 0, 0);
430 b.link(live, 0, heat, 1, 0);
431 let fire = b.ramp(heat, 0, [[0.0; 3], [glow[0] * 0.4, glow[1] * 0.1, 0.0], glow, [1.0, 0.95, 0.7]], [0.0, 0.3, 0.7, 1.0], true, 5);
432 let bright = b.math(MUL, 6, false);
433 b.link(fire, 0, bright, 0, 0);
434 b.num(bright, 1, intensity);
435 b.out(bright, 0, EMIT);
436 let rock = b.noise(p, scale * 2.0, 6.0, 0.6, 0.0, 3);
437 let base = b.mix(MULTIPLY, 4);
438 b.num(base, 0, 0.7);
439 b.value(base, 1, crust);
440 b.link(rock, COLOUR, base, 2, 0);
441 b.out(base, 0, BASE);
442 let r = b.map(crack, 0, 0.9, 0.5, 5);
443 b.out(r, 0, ROUGH);
444 b.out_value(METAL, 0.0);
445 b.bump(crack, 0, -1.2, 0.05, 6);
446 b.g
447}
448
449fn car_paint(colour: [f32; 3], flake: f32) -> MaterialGraph {
451 let mut b = G::new();
452 let p = b.world(1.0);
453 let flakes = b.voronoi(p, 260.0, 1.0, 1);
454 let sparkle = b.math(POW, 2, false);
455 b.link(flakes, CELL, sparkle, 0, 0);
456 b.num(sparkle, 1, 8.0);
457 let lw = b.node("Layer weight", 1, &[]);
458 b.num(lw, 0, 0.35);
459 let body = b.mix(MIX, 3);
460 b.link(lw, 1, body, 0, 8);
461 b.value(body, 1, [colour[0] * 0.35, colour[1] * 0.35, colour[2] * 0.35]);
462 b.value(body, 2, colour);
463 let flaky = b.mix(ADD, 4);
464 b.node_param(flaky, 0, 4.0);
465 b.link(sparkle, 0, flaky, 0, 0);
466 b.num(flaky, 0, flake);
467 b.link(body, 0, flaky, 1, 0);
468 b.value(flaky, 2, [0.25; 3]);
469 b.out(flaky, 0, BASE);
470 let r = b.map(sparkle, 0, 0.18, 0.05, 4);
471 b.out(r, 0, ROUGH);
472 b.out_value(METAL, 0.6);
473 b.g
474}
475
476impl G {
477 fn node_param(&mut self, id: u32, k: usize, v: f32) {
478 self.g.nodes.iter_mut().find(|n| n.id == id).unwrap().params[k] = v;
479 }
480}
481
482fn fabric(a: [f32; 3], b_col: [f32; 3], scale: f32) -> MaterialGraph {
484 let mut b = G::new();
485 let p = b.uv(scale);
486 let sep = b.node("Separate XYZ", 1, &[]);
487 b.link(p, 0, sep, 0, 0);
488 let warp_threads = b.math(SIN, 2, false);
489 b.link(sep, 1, warp_threads, 0, 0);
490 let weft_threads = b.math(SIN, 2, false);
491 b.link(sep, 2, weft_threads, 0, 0);
492 let scale_x = b.math(MUL, 1, false);
493 b.link(sep, 1, scale_x, 0, 0);
494 b.num(scale_x, 1, 28.0);
495 let scale_y = b.math(MUL, 1, false);
496 b.link(sep, 2, scale_y, 0, 0);
497 b.num(scale_y, 1, 28.0);
498 b.link(scale_x, 0, warp_threads, 0, 0);
499 b.link(scale_y, 0, weft_threads, 0, 0);
500 let cross = b.math(MUL, 3, false);
501 b.link(warp_threads, 0, cross, 0, 0);
502 b.link(weft_threads, 0, cross, 1, 0);
503 let weave = b.math(ABS, 3, false);
504 b.link(cross, 0, weave, 0, 0);
505 let cloth = b.mix(MIX, 4);
506 b.link(weave, 0, cloth, 0, 0);
507 b.value(cloth, 1, a);
508 b.value(cloth, 2, b_col);
509 let w = b.world(1.0);
510 let fuzz = b.noise(w, 40.0, 3.0, 0.6, 0.0, 4);
511 let fuzzy = b.mix(OVERLAY, 5);
512 b.num(fuzzy, 0, 0.3);
513 b.link(cloth, 0, fuzzy, 1, 0);
514 b.link(fuzz, COLOUR, fuzzy, 2, 0);
515 b.out(fuzzy, 0, BASE);
516 b.out_value(ROUGH, 0.92);
517 b.out_value(METAL, 0.0);
518 b.bump(weave, 0, 0.4, 0.01, 5);
519 b.g
520}
521
522fn tiles_marble(base: [f32; 3], vein: [f32; 3], grout: [f32; 3], scale: f32) -> MaterialGraph {
524 let g = marble(base, vein, 3.0, 2.2);
525 let out = g.nodes.iter().find(|n| n.kind == "Output").unwrap().id;
527 let base_link = g.nodes.iter().find(|n| n.id == out).unwrap().inputs[BASE].link.unwrap();
528 let mut b = G { g, out, col: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 900.0] };
529 let p = b.uv(scale);
530 let grid = b.node("Brick texture", 7, &[1.0, 0.0, 0.02, 0.006, 0.0]);
531 b.link(p, 0, grid, 0, 0);
532 b.num(grid, 4, 4.0);
533 let tiled = b.mix(MIX, 7);
534 b.link(grid, MASK, tiled, 0, 0);
535 b.value(tiled, 1, grout);
536 b.link(base_link, 0, tiled, 2, 0);
537 b.out(tiled, 0, BASE);
538 let rough = b.map(grid, MASK, 0.8, 0.06, 7);
539 b.out(rough, 0, ROUGH);
540 b.bump(grid, MASK, 0.5, 0.02, 7);
541 b.g
542}
543
544fn painted_rock(dark: [f32; 3], light: [f32; 3]) -> MaterialGraph {
546 let mut b = G::new();
547 let p = b.world(1.0);
548 let n = b.noise(p, 1.8, 3.0, 0.5, 0.6, 1);
549 let ramp = b.node("Color ramp", 2, &[0.0, 0.4, 0.62, 1.0, 1.0]);
550 b.link(n, FACTOR, ramp, 0, 0);
551 b.value(ramp, 1, dark);
552 b.value(ramp, 2, [(dark[0] + light[0]) * 0.45, (dark[1] + light[1]) * 0.45, (dark[2] + light[2]) * 0.5]);
553 b.value(ramp, 3, light);
554 b.value(ramp, 4, [light[0] * 1.15, light[1] * 1.12, light[2] * 1.0]);
555 let up = b.node("Normal", 2, &[]);
556 let top = b.mix(MIX, 3);
557 b.link(up, NORMAL_UP, top, 0, 0);
558 b.link(ramp, 0, top, 1, 0);
559 b.value(top, 2, [light[0] * 1.2, light[1] * 1.25, light[2] * 1.1]);
560 b.out(top, 0, BASE);
561 b.out_value(ROUGH, 0.85);
562 b.out_value(METAL, 0.0);
563 b.bump(n, FACTOR, 0.6, 0.1, 4);
564 b.g
565}
566
567fn ice(clear: [f32; 3], deep: [f32; 3]) -> MaterialGraph {
569 let mut b = G::new();
570 let p = b.world(1.0);
571 let cracks = b.voronoi(p, 3.0, 1.0, 1);
572 let crack = b.node("Smoothstep", 2, &[0.04, 0.0]);
573 b.link(cracks, EDGE, crack, 0, 0);
574 let frost = b.noise(p, 6.0, 6.0, 0.6, 0.2, 1);
575 let lw = b.node("Layer weight", 1, &[]);
576 b.num(lw, 0, 0.4);
577 let body = b.mix(MIX, 3);
578 b.link(lw, 0, body, 0, 0);
579 b.value(body, 1, deep);
580 b.value(body, 2, clear);
581 let cracked = b.mix(MIX, 4);
582 b.link(crack, 0, cracked, 0, 0);
583 b.link(body, 0, cracked, 1, 0);
584 b.value(cracked, 2, [0.9, 0.97, 1.0]);
585 b.out(cracked, 0, BASE);
586 let r = b.map(frost, FACTOR, 0.02, 0.45, 4);
587 b.out(r, 0, ROUGH);
588 b.out_value(METAL, 0.0);
589 let glow = b.math(MUL, 4, false);
590 b.link(lw, 0, glow, 0, 0);
591 b.value(glow, 1, [deep[0] * 0.3, deep[1] * 0.4, deep[2] * 0.6]);
592 b.out(glow, 0, EMIT);
593 b.bump(crack, 0, 0.6, 0.02, 5);
594 b.g
595}
596
597fn scifi(plate: [f32; 3], seam: [f32; 3], glow: f32) -> MaterialGraph {
599 let mut b = G::new();
600 let p = b.uv(3.0);
601 let panels = b.node("Brick texture", 1, &[1.6, 0.0, 0.02, 0.004, 0.4]);
602 b.link(p, 0, panels, 0, 0);
603 b.num(panels, 4, 3.0);
604 let small = b.node("Brick texture", 1, &[1.0, 0.0, 0.035, 0.004, 0.0]);
605 b.link(p, 0, small, 0, 0);
606 b.num(small, 4, 12.0);
607 let tone = b.mix(MIX, 2);
608 b.link(panels, BRICK_VALUE, tone, 0, 11);
609 b.value(tone, 1, plate);
610 b.value(tone, 2, [plate[0] * 0.75, plate[1] * 0.75, plate[2] * 0.8]);
611 let col = b.mix(MULTIPLY, 3);
612 b.link(small, MASK, col, 0, 8);
613 b.num(col, 0, 0.25);
614 b.link(tone, 0, col, 1, 0);
615 b.value(col, 2, [0.4; 3]);
616 let seams = b.math(SUB, 3, true);
617 b.num(seams, 0, 1.0);
618 b.link(panels, MASK, seams, 1, 0);
619 b.out(col, 0, BASE);
620 let time = b.node("Time", 2, &[]);
621 let pulse = b.math(MULADD, 4, false);
622 b.link(time, 1, pulse, 0, 0);
623 b.num(pulse, 1, 0.5);
624 b.num(pulse, 2, 0.6);
625 let light = b.math(MUL, 5, false);
626 b.link(seams, 0, light, 0, 0);
627 b.link(pulse, 0, light, 1, 0);
628 let emit = b.mix(MULTIPLY, 6);
629 b.num(emit, 0, 1.0);
630 b.link(light, 0, emit, 1, 0);
631 b.value(emit, 2, [seam[0] * glow, seam[1] * glow, seam[2] * glow]);
632 b.out(emit, 0, EMIT);
633 let r = b.map(panels, BRICK_VALUE, 0.25, 0.5, 4);
634 b.out(r, 0, ROUGH);
635 b.out_value(METAL, 0.85);
636 let height = b.math(ADD, 5, false);
637 b.link(panels, MASK, height, 0, 0);
638 b.link(small, MASK, height, 1, 8);
639 b.bump(height, 0, 0.6, 0.02, 6);
640 b.g
641}
642
643pub fn library() -> Vec<Preset> {
645 let p = |name: &'static str, graph: MaterialGraph| Preset { category: "Game Ready", name, graph };
646 vec![
647 p("Marble Carrara", marble([0.9, 0.9, 0.88], [0.28, 0.3, 0.34], 3.0, 1.6)),
648 p("Marble Nero", marble([0.025, 0.025, 0.03], [0.75, 0.72, 0.6], 3.5, 1.4)),
649 p("Marble Verde", marble([0.04, 0.2, 0.13], [0.75, 0.85, 0.78], 4.0, 1.8)),
650 p("Marble Rosso", marble([0.42, 0.12, 0.1], [0.9, 0.8, 0.75], 3.0, 2.0)),
651 p("Marble Floor Tiles", tiles_marble([0.86, 0.85, 0.82], [0.32, 0.33, 0.36], [0.12, 0.12, 0.12], 2.0)),
652 p("Red Brick Wall", brick_wall([0.42, 0.13, 0.07], [0.3, 0.09, 0.05], [0.55, 0.52, 0.47], 3.0, 0.15)),
653 p("Mossy Stone Wall", brick_wall([0.32, 0.31, 0.29], [0.22, 0.22, 0.21], [0.35, 0.34, 0.3], 2.0, 0.9)),
654 p("Sandstone Blocks", brick_wall([0.66, 0.5, 0.31], [0.55, 0.4, 0.24], [0.6, 0.52, 0.4], 1.5, 0.05)),
655 p("Castle Wall", brick_wall([0.38, 0.37, 0.35], [0.27, 0.27, 0.27], [0.18, 0.17, 0.16], 1.2, 0.4)),
656 p("Cobblestone Path", cobbles([0.3, 0.29, 0.27], [0.45, 0.42, 0.38], [0.05, 0.05, 0.04], 3.5)),
657 p("River Pebbles", cobbles([0.42, 0.4, 0.37], [0.2, 0.18, 0.16], [0.08, 0.07, 0.05], 9.0)),
658 p("Mossy Cobbles", cobbles([0.25, 0.27, 0.22], [0.36, 0.38, 0.3], [0.06, 0.12, 0.03], 4.0)),
659 p("Oak Floor", planks([0.5, 0.33, 0.17], [0.25, 0.14, 0.06], 1.0, 0.2)),
660 p("Weathered Planks", planks([0.42, 0.38, 0.32], [0.2, 0.18, 0.15], 1.0, 0.9)),
661 p("Dark Walnut Floor", planks([0.22, 0.12, 0.06], [0.08, 0.04, 0.02], 1.2, 0.1)),
662 p("Ship Deck", planks([0.6, 0.45, 0.28], [0.32, 0.22, 0.12], 0.8, 0.6)),
663 p("Chipped Red Paint", chipped_paint([0.5, 0.06, 0.04], [0.32, 0.14, 0.06], true)),
664 p("Chipped Blue Paint", chipped_paint([0.06, 0.18, 0.42], [0.55, 0.56, 0.58], false)),
665 p("Military Green", chipped_paint([0.16, 0.2, 0.1], [0.4, 0.4, 0.42], false)),
666 p("Industrial Yellow", chipped_paint([0.75, 0.52, 0.04], [0.35, 0.16, 0.07], true)),
667 p("Forest Floor", ground([0.08, 0.05, 0.03], [0.14, 0.12, 0.05], [0.3, 0.28, 0.25], 2.0, 0.85)),
668 p("Beach Sand", ground([0.62, 0.52, 0.36], [0.78, 0.68, 0.5], [0.5, 0.46, 0.4], 3.0, 0.9)),
669 p("Gravel Road", ground([0.25, 0.24, 0.22], [0.35, 0.33, 0.3], [0.5, 0.48, 0.45], 4.0, 0.9)),
670 p("Muddy Ground", ground([0.07, 0.05, 0.03], [0.16, 0.12, 0.07], [0.25, 0.22, 0.18], 2.5, 0.35)),
671 p("Snowy Ground", ground([0.75, 0.8, 0.88], [0.95, 0.97, 1.0], [0.3, 0.3, 0.32], 2.0, 0.6)),
672 p("Lava Rock", glowing_cracks([0.05, 0.04, 0.04], [1.0, 0.35, 0.05], 2.5, 6.0)),
673 p("Magic Crystal Cracks", glowing_cracks([0.05, 0.04, 0.08], [0.45, 0.2, 1.0], 3.0, 5.0)),
674 p("Toxic Cracks", glowing_cracks([0.04, 0.05, 0.03], [0.35, 1.0, 0.1], 3.0, 4.0)),
675 p("Car Paint Red", car_paint([0.5, 0.02, 0.02], 0.35)),
676 p("Car Paint Midnight", car_paint([0.02, 0.04, 0.12], 0.5)),
677 p("Car Paint Pearl", car_paint([0.8, 0.8, 0.78], 0.25)),
678 p("Denim", fabric([0.05, 0.09, 0.2], [0.18, 0.25, 0.4], 6.0)),
679 p("Tweed", fabric([0.25, 0.18, 0.1], [0.4, 0.33, 0.22], 5.0)),
680 p("Painted Rock", painted_rock([0.18, 0.2, 0.28], [0.62, 0.55, 0.45])),
681 p("Painted Rock Warm", painted_rock([0.25, 0.15, 0.12], [0.85, 0.65, 0.42])),
682 p("Glacier Ice", ice([0.75, 0.9, 1.0], [0.05, 0.3, 0.6])),
683 p("Sci-Fi Panels", scifi([0.35, 0.37, 0.4], [0.2, 0.7, 1.0], 4.0)),
684 p("Sci-Fi Panels Orange", scifi([0.22, 0.22, 0.24], [1.0, 0.45, 0.1], 4.0)),
685 ]
686}