Codels
712 tris0.99 × 0.14 × 1.28 m

Use it in code

Remix in the editor
Self-contained ES module — only depends on three. Call the factory and add the group to your scene.
/**
 * Lily Pads — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 712 · Size (W × H × D): 0.99 × 0.14 × 1.28 m
 *
 * Usage:
 *   import { createLilyPad } from './lily-pad.js';
 *   
 *   const model = createLilyPad();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// Extrude a 2D outline along Z (centered). bevel = [thickness, size, segments].
function extrude(outline, depth, holes = [], bevel = null) {
  const shape = new THREE.Shape(outline.map(([x, y]) => new THREE.Vector2(x, y)));
  for (const hole of holes) shape.holes.push(new THREE.Path(hole.map(([x, y]) => new THREE.Vector2(x, y))));
  const options = bevel
    ? { depth, bevelEnabled: true, bevelThickness: bevel[0], bevelSize: bevel[1], bevelSegments: bevel[2] }
    : { depth, bevelEnabled: false };
  return new THREE.ExtrudeGeometry(shape, options).translate(0, 0, -depth / 2);
}

export function createLilyPad() {
  const root = new THREE.Group();
  root.name = 'LilyPad';

  // Materials
  const padMat = new THREE.MeshStandardMaterial({ name: 'pad', color: 0x4f9a3c, roughness: 0.55, flatShading: true });
  const padLightMat = new THREE.MeshStandardMaterial({ name: 'padLight', color: 0x54a64e, roughness: 0.55, flatShading: true });
  const veinMat = new THREE.MeshStandardMaterial({ name: 'vein', color: 0x75b673, roughness: 0.6, flatShading: true });
  const petalMat = new THREE.MeshStandardMaterial({ name: 'petal', color: 0xf5a8c6, roughness: 0.6, flatShading: true });
  const petalInnerMat = new THREE.MeshStandardMaterial({ name: 'petalInner', color: 0xfbd8e5, roughness: 0.6, flatShading: true });
  const heartMat = new THREE.MeshStandardMaterial({ name: 'heart', color: 0xf4c23c, roughness: 0.6, flatShading: true });
  const budMat = new THREE.MeshStandardMaterial({ name: 'bud', color: 0xdd97b2, roughness: 0.6, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.246, 0.003, 0.008);
  const boxGeo2 = new THREE.BoxGeometry(0.1403, 0.003, 0.008);
  const boxGeo3 = new THREE.BoxGeometry(0.1478, 0.003, 0.008);
  const boxGeo4 = new THREE.BoxGeometry(0.1628, 0.003, 0.008);
  const octahedronGeo = new THREE.OctahedronGeometry(1, 0);

  // Parts
  const lily1 = new THREE.Group();
  lily1.name = 'lily1';
  lily1.position.set(-0.2572, 0, 0.0653);
  lily1.rotation.set(0, deg(128.8474), 0);
  root.add(lily1);
  const pad = new THREE.Group();
  pad.name = 'pad';
  lily1.add(pad);
  const pad2 = new THREE.Mesh(extrude([[0, 0], [0.2869, -0.0877], [0.2152, -0.209], [0.096, -0.2842], [-0.0443, -0.2967], [-0.1749, -0.2437], [-0.2669, -0.137], [-0.3, 0], [-0.2669, 0.137], [-0.1749, 0.2437], [-0.0443, 0.2967], [0.096, 0.2842], [0.2152, 0.209], [0.2869, 0.0877]], 0.015), padMat);
  pad2.name = 'pad';
  pad2.position.set(0, 0.0075, 0);
  pad2.rotation.set(deg(-90), 0, 0);
  pad.add(pad2);
  const vein1 = new THREE.Mesh(boxGeo, veinMat);
  vein1.name = 'vein1';
  vein1.position.set(0.1079, 0.0165, -0.059);
  vein1.rotation.set(0, deg(28.6479), 0);
  lily1.add(vein1);
  const vein2 = new THREE.Mesh(boxGeo, veinMat);
  vein2.name = 'vein2';
  vein2.position.set(0.0233, 0.0165, -0.1208);
  vein2.rotation.set(0, deg(79.0986), 0);
  lily1.add(vein2);
  const vein3 = new THREE.Mesh(boxGeo, veinMat);
  vein3.name = 'vein3';
  vein3.position.set(-0.0783, 0.0165, -0.0948);
  vein3.rotation.set(0, deg(129.5493), 0);
  lily1.add(vein3);
  const vein4 = new THREE.Mesh(boxGeo, veinMat);
  vein4.name = 'vein4';
  vein4.position.set(-0.123, 0.0165, 0);
  vein4.rotation.set(0, deg(180), 0);
  lily1.add(vein4);
  const vein5 = new THREE.Mesh(boxGeo, veinMat);
  vein5.name = 'vein5';
  vein5.position.set(-0.0783, 0.0165, 0.0948);
  vein5.rotation.set(0, deg(230.4507), 0);
  lily1.add(vein5);
  const vein6 = new THREE.Mesh(boxGeo, veinMat);
  vein6.name = 'vein6';
  vein6.position.set(0.0233, 0.0165, 0.1208);
  vein6.rotation.set(0, deg(280.9014), 0);
  lily1.add(vein6);
  const vein7 = new THREE.Mesh(boxGeo, veinMat);
  vein7.name = 'vein7';
  vein7.position.set(0.1079, 0.0165, 0.059);
  vein7.rotation.set(0, deg(331.3521), 0);
  lily1.add(vein7);
  const lily2 = new THREE.Group();
  lily2.name = 'lily2';
  lily2.position.set(0.2682, 0, -0.0965);
  lily2.rotation.set(0, deg(272.4929), 0);
  root.add(lily2);
  const pad3 = new THREE.Group();
  pad3.name = 'pad';
  lily2.add(pad3);
  const pad4 = new THREE.Mesh(extrude([[0, 0], [0.1636, -0.05], [0.1227, -0.1192], [0.0547, -0.1621], [-0.0253, -0.1692], [-0.0997, -0.139], [-0.1522, -0.0781], [-0.1711, 0], [-0.1522, 0.0781], [-0.0997, 0.139], [-0.0253, 0.1692], [0.0547, 0.1621], [0.1227, 0.1192], [0.1636, 0.05]], 0.012), padLightMat);
  pad4.name = 'pad';
  pad4.position.set(0, 0.006, 0);
  pad4.rotation.set(deg(-90), 0, 0);
  pad3.add(pad4);
  const vein12 = new THREE.Mesh(boxGeo2, veinMat);
  vein12.name = 'vein1';
  vein12.position.set(0.0615, 0.0135, -0.0336);
  vein12.rotation.set(0, deg(28.6479), 0);
  lily2.add(vein12);
  const vein22 = new THREE.Mesh(boxGeo2, veinMat);
  vein22.name = 'vein2';
  vein22.position.set(0.0133, 0.0135, -0.0689);
  vein22.rotation.set(0, deg(79.0986), 0);
  lily2.add(vein22);
  const vein32 = new THREE.Mesh(boxGeo2, veinMat);
  vein32.name = 'vein3';
  vein32.position.set(-0.0447, 0.0135, -0.0541);
  vein32.rotation.set(0, deg(129.5493), 0);
  lily2.add(vein32);
  const vein42 = new THREE.Mesh(boxGeo2, veinMat);
  vein42.name = 'vein4';
  vein42.position.set(-0.0701, 0.0135, 0);
  vein42.rotation.set(0, deg(180), 0);
  lily2.add(vein42);
  const vein52 = new THREE.Mesh(boxGeo2, veinMat);
  vein52.name = 'vein5';
  vein52.position.set(-0.0447, 0.0135, 0.0541);
  vein52.rotation.set(0, deg(230.4507), 0);
  lily2.add(vein52);
  const vein62 = new THREE.Mesh(boxGeo2, veinMat);
  vein62.name = 'vein6';
  vein62.position.set(0.0133, 0.0135, 0.0689);
  vein62.rotation.set(0, deg(280.9014), 0);
  lily2.add(vein62);
  const vein72 = new THREE.Mesh(boxGeo2, veinMat);
  vein72.name = 'vein7';
  vein72.position.set(0.0615, 0.0135, 0.0336);
  vein72.rotation.set(0, deg(331.3521), 0);
  lily2.add(vein72);
  const lily3 = new THREE.Group();
  lily3.name = 'lily3';
  lily3.position.set(-0.0991, 0, -0.4347);
  lily3.rotation.set(0, deg(302.2002), 0);
  root.add(lily3);
  const pad5 = new THREE.Group();
  pad5.name = 'pad';
  lily3.add(pad5);
  const pad6 = new THREE.Mesh(extrude([[0, 0], [0.1724, -0.0527], [0.1293, -0.1256], [0.0577, -0.1708], [-0.0266, -0.1783], [-0.1051, -0.1464], [-0.1603, -0.0823], [-0.1802, 0], [-0.1603, 0.0823], [-0.1051, 0.1464], [-0.0266, 0.1783], [0.0577, 0.1708], [0.1293, 0.1256], [0.1724, 0.0527]], 0.012), padMat);
  pad6.name = 'pad';
  pad6.position.set(0, 0.006, 0);
  pad6.rotation.set(deg(-90), 0, 0);
  pad5.add(pad6);
  const vein13 = new THREE.Mesh(boxGeo3, veinMat);
  vein13.name = 'vein1';
  vein13.position.set(0.0648, 0.0135, -0.0354);
  vein13.rotation.set(0, deg(28.6479), 0);
  lily3.add(vein13);
  const vein23 = new THREE.Mesh(boxGeo3, veinMat);
  vein23.name = 'vein2';
  vein23.position.set(0.014, 0.0135, -0.0726);
  vein23.rotation.set(0, deg(79.0986), 0);
  lily3.add(vein23);
  const vein33 = new THREE.Mesh(boxGeo3, veinMat);
  vein33.name = 'vein3';
  vein33.position.set(-0.0471, 0.0135, -0.057);
  vein33.rotation.set(0, deg(129.5493), 0);
  lily3.add(vein33);
  const vein43 = new THREE.Mesh(boxGeo3, veinMat);
  vein43.name = 'vein4';
  vein43.position.set(-0.0739, 0.0135, 0);
  vein43.rotation.set(0, deg(180), 0);
  lily3.add(vein43);
  const vein53 = new THREE.Mesh(boxGeo3, veinMat);
  vein53.name = 'vein5';
  vein53.position.set(-0.0471, 0.0135, 0.057);
  vein53.rotation.set(0, deg(230.4507), 0);
  lily3.add(vein53);
  const vein63 = new THREE.Mesh(boxGeo3, veinMat);
  vein63.name = 'vein6';
  vein63.position.set(0.014, 0.0135, 0.0726);
  vein63.rotation.set(0, deg(280.9014), 0);
  lily3.add(vein63);
  const vein73 = new THREE.Mesh(boxGeo3, veinMat);
  vein73.name = 'vein7';
  vein73.position.set(0.0648, 0.0135, 0.0354);
  vein73.rotation.set(0, deg(331.3521), 0);
  lily3.add(vein73);
  const lily4 = new THREE.Group();
  lily4.name = 'lily4';
  lily4.position.set(0.0882, 0, 0.4659);
  lily4.rotation.set(0, deg(217.3457), 0);
  root.add(lily4);
  const pad7 = new THREE.Group();
  pad7.name = 'pad';
  lily4.add(pad7);
  const pad8 = new THREE.Mesh(extrude([[0, 0], [0.1899, -0.058], [0.1424, -0.1383], [0.0635, -0.1881], [-0.0293, -0.1963], [-0.1158, -0.1613], [-0.1766, -0.0906], [-0.1985, 0], [-0.1766, 0.0906], [-0.1158, 0.1613], [-0.0293, 0.1963], [0.0635, 0.1881], [0.1424, 0.1383], [0.1899, 0.058]], 0.012), padLightMat);
  pad8.name = 'pad';
  pad8.position.set(0, 0.006, 0);
  pad8.rotation.set(deg(-90), 0, 0);
  pad7.add(pad8);
  const vein14 = new THREE.Mesh(boxGeo4, veinMat);
  vein14.name = 'vein1';
  vein14.position.set(0.0714, 0.0135, -0.039);
  vein14.rotation.set(0, deg(28.6479), 0);
  lily4.add(vein14);
  const vein24 = new THREE.Mesh(boxGeo4, veinMat);
  vein24.name = 'vein2';
  vein24.position.set(0.0154, 0.0135, -0.0799);
  vein24.rotation.set(0, deg(79.0986), 0);
  lily4.add(vein24);
  const vein34 = new THREE.Mesh(boxGeo4, veinMat);
  vein34.name = 'vein3';
  vein34.position.set(-0.0518, 0.0135, -0.0628);
  vein34.rotation.set(0, deg(129.5493), 0);
  lily4.add(vein34);
  const vein44 = new THREE.Mesh(boxGeo4, veinMat);
  vein44.name = 'vein4';
  vein44.position.set(-0.0814, 0.0135, 0);
  vein44.rotation.set(0, deg(180), 0);
  lily4.add(vein44);
  const vein54 = new THREE.Mesh(boxGeo4, veinMat);
  vein54.name = 'vein5';
  vein54.position.set(-0.0518, 0.0135, 0.0628);
  vein54.rotation.set(0, deg(230.4507), 0);
  lily4.add(vein54);
  const vein64 = new THREE.Mesh(boxGeo4, veinMat);
  vein64.name = 'vein6';
  vein64.position.set(0.0154, 0.0135, 0.0799);
  vein64.rotation.set(0, deg(280.9014), 0);
  lily4.add(vein64);
  const vein74 = new THREE.Mesh(boxGeo4, veinMat);
  vein74.name = 'vein7';
  vein74.position.set(0.0714, 0.0135, 0.039);
  vein74.rotation.set(0, deg(331.3521), 0);
  lily4.add(vein74);
  const waterLily = new THREE.Group();
  waterLily.name = 'waterLily';
  waterLily.position.set(-0.3172, 0.015, 0.0953);
  waterLily.rotation.set(0, deg(8.7699), 0);
  root.add(waterLily);
  const octahedron42 = new THREE.Mesh(octahedronGeo, petalMat);
  octahedron42.position.set(0.0785, 0.0435, 0);
  octahedron42.rotation.set(0, 0, deg(-72));
  octahedron42.scale.set(0.0363, 0.0825, 0.0132);
  waterLily.add(octahedron42);
  const octahedron43 = new THREE.Mesh(octahedronGeo, petalMat);
  octahedron43.position.set(0.0555, 0.0435, 0.0555);
  octahedron43.rotation.set(deg(45.7767), deg(-20.2118), deg(-45.7767));
  octahedron43.scale.set(0.0363, 0.0825, 0.0132);
  waterLily.add(octahedron43);
  const octahedron44 = new THREE.Mesh(octahedronGeo, petalMat);
  octahedron44.position.set(0, 0.0435, 0.0785);
  octahedron44.rotation.set(deg(72), 0, 0);
  octahedron44.scale.set(0.0363, 0.0825, 0.0132);
  waterLily.add(octahedron44);
  const octahedron45 = new THREE.Mesh(octahedronGeo, petalMat);
  octahedron45.position.set(-0.0555, 0.0435, 0.0555);
  octahedron45.rotation.set(deg(45.7767), deg(20.2118), deg(45.7767));
  octahedron45.scale.set(0.0363, 0.0825, 0.0132);
  waterLily.add(octahedron45);
  const octahedron46 = new THREE.Mesh(octahedronGeo, petalMat);
  octahedron46.position.set(-0.0785, 0.0435, 0);
  octahedron46.rotation.set(0, 0, deg(72));
  octahedron46.scale.set(0.0363, 0.0825, 0.0132);
  waterLily.add(octahedron46);
  const octahedron47 = new THREE.Mesh(octahedronGeo, petalMat);
  octahedron47.position.set(-0.0555, 0.0435, -0.0555);
  octahedron47.rotation.set(deg(-45.7767), deg(-20.2118), deg(45.7767));
  octahedron47.scale.set(0.0363, 0.0825, 0.0132);
  waterLily.add(octahedron47);
  const octahedron48 = new THREE.Mesh(octahedronGeo, petalMat);
  octahedron48.position.set(0, 0.0435, -0.0785);
  octahedron48.rotation.set(deg(-72), 0, 0);
  octahedron48.scale.set(0.0363, 0.0825, 0.0132);
  waterLily.add(octahedron48);
  const octahedron49 = new THREE.Mesh(octahedronGeo, petalMat);
  octahedron49.position.set(0.0555, 0.0435, -0.0555);
  octahedron49.rotation.set(deg(-45.7767), deg(20.2118), deg(-45.7767));
  octahedron49.scale.set(0.0363, 0.0825, 0.0132);
  waterLily.add(octahedron49);
  const octahedron50 = new THREE.Mesh(octahedronGeo, petalInnerMat);
  octahedron50.position.set(0.0369, 0.0774, 0.0213);
  octahedron50.rotation.set(deg(19.6731), deg(-6.3857), deg(-35.669));
  octahedron50.scale.set(0.0281, 0.0638, 0.0102);
  waterLily.add(octahedron50);
  const octahedron51 = new THREE.Mesh(octahedronGeo, petalInnerMat);
  octahedron51.position.set(0, 0.0774, 0.0427);
  octahedron51.rotation.set(deg(42), 0, 0);
  octahedron51.scale.set(0.0281, 0.0638, 0.0102);
  waterLily.add(octahedron51);
  const octahedron52 = new THREE.Mesh(octahedronGeo, petalInnerMat);
  octahedron52.position.set(-0.0369, 0.0774, 0.0213);
  octahedron52.rotation.set(deg(19.6731), deg(6.3857), deg(35.669));
  octahedron52.scale.set(0.0281, 0.0638, 0.0102);
  waterLily.add(octahedron52);
  const octahedron53 = new THREE.Mesh(octahedronGeo, petalInnerMat);
  octahedron53.position.set(-0.0369, 0.0774, -0.0213);
  octahedron53.rotation.set(deg(-19.6731), deg(-6.3857), deg(35.669));
  octahedron53.scale.set(0.0281, 0.0638, 0.0102);
  waterLily.add(octahedron53);
  const octahedron54 = new THREE.Mesh(octahedronGeo, petalInnerMat);
  octahedron54.position.set(0, 0.0774, -0.0427);
  octahedron54.rotation.set(deg(-42), 0, 0);
  octahedron54.scale.set(0.0281, 0.0638, 0.0102);
  waterLily.add(octahedron54);
  const octahedron55 = new THREE.Mesh(octahedronGeo, petalInnerMat);
  octahedron55.position.set(0.0369, 0.0774, -0.0213);
  octahedron55.rotation.set(deg(-19.6731), deg(6.3857), deg(-35.669));
  octahedron55.scale.set(0.0281, 0.0638, 0.0102);
  waterLily.add(octahedron55);
  const cylinder56 = new THREE.Mesh(new THREE.CylinderGeometry(0.033, 0.039, 0.045, 6), heartMat);
  cylinder56.position.set(0, 0.0405, 0);
  waterLily.add(cylinder56);
  const bud = new THREE.Group();
  bud.name = 'bud';
  bud.position.set(0.1179, 0.012, 0.4659);
  root.add(bud);
  const octahedron58 = new THREE.Mesh(octahedronGeo, budMat);
  octahedron58.position.set(0, 0.05, 0);
  octahedron58.scale.set(0.035, 0.06, 0.035);
  bud.add(octahedron58);
  const cylinder59 = new THREE.Mesh(new THREE.CylinderGeometry(0.022, 0.026, 0.02, 6), padMat);
  cylinder59.position.set(0, 0.01, 0);
  bud.add(cylinder59);

  root.traverse((o) => {
    if (o.isMesh) {
      o.castShadow = true;
      o.receiveShadow = true;
    }
  });
  return root;
}

export default createLilyPad;

Ratings & comments

—
No ratings yet — be the first.
5
0
4
0
3
0
2
0
1
0

Sign in to rate and comment.

0 comments

No comments yet. Share how you used this model or what could be better.

Related models

Same category or similar tags