Codels
1,1 тыс. треуг.1,53 × 8,00 × 1,58 m

Использовать в коде

Ремикс в редакторе
Самодостаточный ES-модуль — зависит только от three. Вызовите фабрику и добавьте группу в сцену.
/**
 * Cypress Tree — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,100 · Size (W × H × D): 1.53 × 8.00 × 1.58 m
 *
 * Usage:
 *   import { createCypressTree } from './cypress-tree.js';
 *   
 *   const model = createCypressTree();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// Deterministic vertex displacement (organic low-poly look).
function jitter(geometry, amount, seed) {
  const pos = geometry.attributes.position;
  const h = (a, b, c, s) => {
    let x = Math.imul(a, 73856093) ^ Math.imul(b, 19349663) ^ Math.imul(c, 83492791) ^ Math.imul(s, 2654435761);
    x = Math.imul(x ^ (x >>> 16), 2246822507);
    x = Math.imul(x ^ (x >>> 13), 3266489909);
    return ((x ^ (x >>> 16)) >>> 0) / 4294967295 - 0.5;
  };
  for (let i = 0; i < pos.count; i++) {
    const x = pos.getX(i), y = pos.getY(i), z = pos.getZ(i);
    const qx = Math.round(x * 1000), qy = Math.round(y * 1000), qz = Math.round(z * 1000);
    pos.setXYZ(i, x + h(qx, qy, qz, seed) * 2 * amount, y + h(qx, qy, qz, seed + 1) * 2 * amount, z + h(qx, qy, qz, seed + 2) * 2 * amount);
  }
  pos.needsUpdate = true;
  geometry.computeVertexNormals();
  return geometry;
}

// Revolve a 2D profile [[radius, y], ...] around the Y axis.
function lathe(points, segments, phiStart = 0, phiLength = Math.PI * 2) {
  return new THREE.LatheGeometry(points.map(([x, y]) => new THREE.Vector2(x, y)), segments, phiStart, phiLength);
}

export function createCypressTree() {
  const root = new THREE.Group();
  root.name = 'CypressTree';

  // Materials
  const barkMat = new THREE.MeshStandardMaterial({ name: 'bark', color: 0x5d4636, roughness: 0.95, flatShading: true });
  const leafMat = new THREE.MeshStandardMaterial({ name: 'leaf', color: 0x36643a, roughness: 0.9, flatShading: true });
  const leafLightMat = new THREE.MeshStandardMaterial({ name: 'leafLight', color: 0x507c57, roughness: 0.85, flatShading: true });
  const leafDarkMat = new THREE.MeshStandardMaterial({ name: 'leafDark', color: 0x2a4e31, roughness: 0.95, flatShading: true });

  // Parts
  const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.144, 0.24, 0.96, 6), barkMat);
  trunk.name = 'trunk';
  trunk.position.set(0, 0.48, 0);
  root.add(trunk);
  const column = new THREE.Mesh(jitter(lathe([[0, 0.56], [0.2632, 0.56], [0.4795, 1.0808], [0.5848, 2.3456], [0.5673, 3.6848], [0.4912, 5.024], [0.3509, 6.2888], [0.1754, 7.3304], [0, 8]], 8), 0.034, 3), leafDarkMat);
  column.name = 'column';
  root.add(column);
  const tuft1 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3172, 0), 0.0381, 123), leafMat);
  tuft1.name = 'tuft1';
  tuft1.position.set(0.3303, 0.9741, 0.025);
  tuft1.rotation.set(deg(12.0539), deg(10.4936), 0);
  tuft1.scale.set(0.9, 1.7, 0.9);
  root.add(tuft1);
  const tuft2 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3599, 0), 0.0432, 124), leafLightMat);
  tuft2.name = 'tuft2';
  tuft2.position.set(-0.3242, 1.3192, 0.2);
  tuft2.rotation.set(deg(1.8678), deg(334.7794), 0);
  tuft2.scale.set(0.9, 1.7, 0.9);
  root.add(tuft2);
  const tuft3 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3235, 0), 0.0388, 125), leafMat);
  tuft3.name = 'tuft3';
  tuft3.position.set(0.0099, 1.5095, -0.4025);
  tuft3.rotation.set(deg(0.045), deg(116.4623), 0);
  tuft3.scale.set(0.9, 1.7, 0.9);
  root.add(tuft3);
  const tuft4 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3767, 0), 0.0452, 126), leafDarkMat);
  tuft4.name = 'tuft4';
  tuft4.position.set(0.2956, 1.6239, 0.2703);
  tuft4.rotation.set(deg(21.674), deg(343.09), 0);
  tuft4.scale.set(0.9, 1.7, 0.9);
  root.add(tuft4);
  const tuft5 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3654, 0), 0.0438, 127), leafMat);
  tuft5.name = 'tuft5';
  tuft5.position.set(-0.4238, 1.9163, 0.0309);
  tuft5.rotation.set(deg(6.289), deg(189.1715), 0);
  tuft5.scale.set(0.9, 1.7, 0.9);
  root.add(tuft5);
  const tuft6 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3492, 0), 0.0419, 128), leafLightMat);
  tuft6.name = 'tuft6';
  tuft6.position.set(0.3654, 2.2744, -0.2714);
  tuft6.rotation.set(deg(25.5916), deg(73.5592), 0);
  tuft6.scale.set(0.9, 1.7, 0.9);
  root.add(tuft6);
  const tuft7 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3732, 0), 0.0448, 129), leafMat);
  tuft7.name = 'tuft7';
  tuft7.position.set(-0.0885, 2.3676, 0.4468);
  tuft7.rotation.set(deg(15.1454), deg(216.6746), 0);
  tuft7.scale.set(0.9, 1.7, 0.9);
  root.add(tuft7);
  const tuft8 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.4129, 0), 0.0495, 130), leafDarkMat);
  tuft8.name = 'tuft8';
  tuft8.position.set(-0.2358, 2.5559, -0.3778);
  tuft8.rotation.set(deg(8.7897), deg(148.568), 0);
  tuft8.scale.set(0.9, 1.7, 0.9);
  root.add(tuft8);
  const tuft9 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3702, 0), 0.0444, 131), leafMat);
  tuft9.name = 'tuft9';
  tuft9.position.set(0.3947, 3.0736, 0.2113);
  tuft9.rotation.set(deg(14.313), deg(349.3623), 0);
  tuft9.scale.set(0.9, 1.7, 0.9);
  root.add(tuft9);
  const tuft10 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3803, 0), 0.0456, 132), leafLightMat);
  tuft10.name = 'tuft10';
  tuft10.position.set(-0.3949, 3.3112, 0.2005);
  tuft10.rotation.set(deg(2.3425), deg(266.2875), 0);
  tuft10.scale.set(0.9, 1.7, 0.9);
  root.add(tuft10);
  const tuft11 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.4062, 0), 0.0487, 133), leafMat);
  tuft11.name = 'tuft11';
  tuft11.position.set(0.2419, 3.5554, -0.3613);
  tuft11.rotation.set(deg(26.9599), deg(134.6857), 0);
  tuft11.scale.set(0.9, 1.7, 0.9);
  root.add(tuft11);
  const tuft12 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3979, 0), 0.0478, 134), leafDarkMat);
  tuft12.name = 'tuft12';
  tuft12.position.set(0.2156, 3.7356, 0.3747);
  tuft12.rotation.set(deg(22.407), deg(210.0276), 0);
  tuft12.scale.set(0.9, 1.7, 0.9);
  root.add(tuft12);
  const tuft13 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3665, 0), 0.044, 135), leafMat);
  tuft13.name = 'tuft13';
  tuft13.position.set(-0.4186, 3.8054, -0.1183);
  tuft13.rotation.set(deg(21.2292), deg(86.3043), 0);
  tuft13.scale.set(0.9, 1.7, 0.9);
  root.add(tuft13);
  const tuft14 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.4003, 0), 0.048, 136), leafLightMat);
  tuft14.name = 'tuft14';
  tuft14.position.set(0.4112, 4.0383, -0.0647);
  tuft14.rotation.set(deg(10.0491), deg(329.0812), 0);
  tuft14.scale.set(0.9, 1.7, 0.9);
  root.add(tuft14);
  const tuft15 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3569, 0), 0.0428, 137), leafMat);
  tuft15.name = 'tuft15';
  tuft15.position.set(-0.2534, 4.5013, 0.3109);
  tuft15.rotation.set(deg(25.76), deg(329.1092), 0);
  tuft15.scale.set(0.9, 1.7, 0.9);
  root.add(tuft15);
  const tuft16 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3855, 0), 0.0463, 138), leafDarkMat);
  tuft16.name = 'tuft16';
  tuft16.position.set(-0.113, 4.7742, -0.3642);
  tuft16.rotation.set(deg(9.1265), deg(4.9754), 0);
  tuft16.scale.set(0.9, 1.7, 0.9);
  root.add(tuft16);
  const tuft17 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3607, 0), 0.0433, 139), leafMat);
  tuft17.name = 'tuft17';
  tuft17.position.set(0.2707, 4.8793, 0.2679);
  tuft17.rotation.set(deg(24.7343), deg(243.5511), 0);
  tuft17.scale.set(0.9, 1.7, 0.9);
  root.add(tuft17);
  const tuft18 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3466, 0), 0.0416, 140), leafLightMat);
  tuft18.name = 'tuft18';
  tuft18.position.set(-0.3451, 5.2984, 0.0493);
  tuft18.rotation.set(deg(9.0693), deg(9.9762), 0);
  tuft18.scale.set(0.9, 1.7, 0.9);
  root.add(tuft18);
  const tuft19 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3072, 0), 0.0369, 141), leafMat);
  tuft19.name = 'tuft19';
  tuft19.position.set(0.1913, 5.375, -0.2916);
  tuft19.rotation.set(deg(1.4462), deg(333.5274), 0);
  tuft19.scale.set(0.9, 1.7, 0.9);
  root.add(tuft19);
  const tuft20 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3428, 0), 0.0411, 142), leafDarkMat);
  tuft20.name = 'tuft20';
  tuft20.position.set(0.0362, 5.7051, 0.3063);
  tuft20.rotation.set(deg(15.9015), deg(243.0827), 0);
  tuft20.scale.set(0.9, 1.7, 0.9);
  root.add(tuft20);
  const tuft21 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3225, 0), 0.0387, 143), leafMat);
  tuft21.name = 'tuft21';
  tuft21.position.set(-0.2472, 5.7538, -0.1831);
  tuft21.rotation.set(deg(20.9057), deg(192.6207), 0);
  tuft21.scale.set(0.9, 1.7, 0.9);
  root.add(tuft21);
  const tuft22 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3033, 0), 0.0364, 144), leafLightMat);
  tuft22.name = 'tuft22';
  tuft22.position.set(0.2822, 6.0409, -0.0133);
  tuft22.rotation.set(deg(9.4011), deg(261.764), 0);
  tuft22.scale.set(0.9, 1.7, 0.9);
  root.add(tuft22);
  const tuft23 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.2641, 0), 0.0317, 145), leafMat);
  tuft23.name = 'tuft23';
  tuft23.position.set(-0.1926, 6.498, 0.132);
  tuft23.rotation.set(deg(17.2796), deg(158.2811), 0);
  tuft23.scale.set(0.9, 1.7, 0.9);
  root.add(tuft23);
  const tuft24 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.2821, 0), 0.0339, 146), leafDarkMat);
  tuft24.name = 'tuft24';
  tuft24.position.set(0.0119, 6.7192, -0.1957);
  tuft24.rotation.set(deg(8.0412), deg(182.1798), 0);
  tuft24.scale.set(0.9, 1.7, 0.9);
  root.add(tuft24);
  const tuft25 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.257, 0), 0.0308, 147), leafMat);
  tuft25.name = 'tuft25';
  tuft25.position.set(0.063, 6.7544, 0.1853);
  tuft25.rotation.set(deg(17.8313), deg(21.082), 0);
  tuft25.scale.set(0.9, 1.7, 0.9);
  root.add(tuft25);
  const tuft26 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.246, 0), 0.0295, 148), leafLightMat);
  tuft26.name = 'tuft26';
  tuft26.position.set(-0.1575, 6.9857, -0.0402);
  tuft26.rotation.set(deg(11.7424), deg(36.3086), 0);
  tuft26.scale.set(0.9, 1.7, 0.9);
  root.add(tuft26);
  const tip = new THREE.Mesh(new THREE.ConeGeometry(0.136, 0.744, 6), leafLightMat);
  tip.name = 'tip';
  tip.position.set(0, 7.628, 0);
  root.add(tip);

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

export default createCypressTree;

Оценки и комментарии

—
Оценок пока нет — будьте первым.
5
0
4
0
3
0
2
0
1
0

Войдите, чтобы ставить оценки и оставлять комментарии.

0 комментариев

Комментариев пока нет. Расскажите, как вы использовали эту модель или что можно улучшить.

Похожие модели

Та же категория или похожие теги