fogón

← Nature3D assetfogon/ombu

Ombú

by fogonCC019813 blocks
OmbúDrag to turn it
// «Ombú» · gpt-6-sol (medium)
// A massive Argentine ombú tree: a very thick, wide, swollen trunk with huge bulging roots spread over the ground like a low wall, and a broad flat dark green crown much wider than it is tall. Very sturdy and grand.

const bark = ["#865331", "#9c6339", "#ad7242", "#bc8050", "#c58b56"];
const greens = ["#205c32", "#28723a", "#318643", "#3b9949", "#4dab51", "#65bb5b"];

// A swollen, gently irregular trunk.
for (let z = 0; z <= 30; z++) {
  const profile =
    z < 5 ? 9.9 - z * 0.25 :
    z < 15 ? 8.9 - (z - 5) * 0.23 :
    z < 23 ? 6.6 + (z - 15) * 0.06 :
    7.1 + (z - 23) * 0.27;

  for (let x = 11; x <= 37; x++) for (let y = 11; y <= 37; y++) {
    const dx = x - 24, dy = y - 24;
    const angle = Math.atan2(dy, dx);
    const radius = profile
      + 0.55 * Math.sin(angle * 7 + z * 0.075)
      + 0.38 * Math.sin(angle * 11 - z * 0.045);
    if (dx * dx + dy * dy <= radius * radius) {
      set(x, y, z, bark[2]);
    }
  }
}

// Huge buttress roots, spreading low across the ground.
for (let i = 0; i < 11; i++) {
  const a = i * Math.PI * 2 / 11 + 0.12;
  const reach = 18.8 + (i % 3) * 0.8;
  for (let j = 0; j <= 9; j++) {
    const t = j / 9;
    const d = 7.1 + (reach - 7.1) * t;
    const bend = 0.65 * Math.sin(t * Math.PI * 1.5 + i * 2.1) * t;
    const x = 24 + Math.cos(a) * d - Math.sin(a) * bend;
    const y = 24 + Math.sin(a) * d + Math.cos(a) * bend;
    const width = 4.5 * (1 - t) + 1.25;
    ellipsoid(x, y, 2.15 - 0.7 * t,
      width, width * 0.82, 3.35 - 1.7 * t, bark[2]);
  }

  // Narrow bark creases following the raised tops of the roots.
  const p = t => {
    const d = 7.1 + (reach - 7.1) * t;
    const bend = 0.65 * Math.sin(t * Math.PI * 1.5 + i * 2.1) * t;
    return [
      24 + Math.cos(a) * d - Math.sin(a) * bend,
      24 + Math.sin(a) * d + Math.cos(a) * bend,
      5.35 - 2.35 * t
    ];
  };
  const u = p(0.35), v = p(0.83);
  line(u[0], u[1], u[2], v[0], v[1], v[2], 0, "#75472d");
}

// Broad limbs disappear into the foliage.
for (let i = 0; i < 7; i++) {
  const a = i * Math.PI * 2 / 7 + 0.35;
  line(24, 24, 25,
    24 + Math.cos(a) * 15, 24 + Math.sin(a) * 15, 32,
    2.2, bark[2]);
}

// Warm, lightly mottled bark and winding vertical grooves.
forEach((x, y, z, color) => {
  if (!bark.includes(color)) return;
  const exposed =
    !get(x + 1, y, z) || !get(x - 1, y, z) ||
    !get(x, y + 1, z) || !get(x, y - 1, z) ||
    !get(x, y, z + 1);
  if (!exposed) return;

  const dx = x - 24, dy = y - 24;
  const angle = Math.atan2(dy, dx);
  let shade = 2;
  if (z > 6 && z < 29) {
    const winding = angle * 9 + 0.19 * Math.sin(z * 0.28) + z * 0.025;
    if (Math.cos(winding) > 0.94) shade = 0;
  }
  if (shade !== 0) {
    shade = 2 + (z > 12 ? 1 : 0) + (rand() < 0.12 ? -1 : 0);
    if (rand() < 0.07) shade = 4;
  }
  set(x, y, z, bark[Math.max(0, Math.min(4, shade))]);
});

function leaves(cx, cy, cz, rx, ry, rz) {
  const x0 = Math.ceil(cx - rx), x1 = Math.floor(cx + rx);
  const y0 = Math.ceil(cy - ry), y1 = Math.floor(cy + ry);
  const z0 = Math.ceil(cz - rz), z1 = Math.floor(cz + rz);
  for (let x = x0; x <= x1; x++)
    for (let y = y0; y <= y1; y++)
      for (let z = z0; z <= z1; z++) {
        const d =
          ((x - cx) / rx) ** 2 +
          ((y - cy) / ry) ** 2 +
          ((z - cz) / rz) ** 2;
        if (d > 1) continue;
        const height = (z - cz) / rz;
        let shade = height < -0.4 ? 0 :
                    height < 0.08 ? 1 :
                    height < 0.55 ? 2 : 3;
        if (height > 0.34 && rand() < 0.24) shade++;
        if (rand() < 0.09) shade += rand() < 0.5 ? -1 : 1;
        set(x, y, z, greens[Math.max(0, Math.min(5, shade))]);
      }
}

// A wide, comparatively shallow, almost umbrella-flat crown.
leaves(24, 24, 34, 19.2, 18.8, 5.5);
for (let i = 0; i < 12; i++) {
  const a = i * Math.PI * 2 / 12;
  const d = 13.7 + (i % 3) * 0.35;
  leaves(
    24 + Math.cos(a) * d,
    24 + Math.sin(a) * d,
    33.4 + (i % 4) * 0.28,
    7.0 + (i % 3) * 0.28,
    6.9 + ((i + 1) % 3) * 0.25,
    4.0 + (i % 2) * 0.45
  );
}

// Rounded sunlit mounds break up the broad top without making it tall.
leaves(24, 24, 38.0, 10.5, 10.2, 3.5);
for (let i = 0; i < 10; i++) {
  const a = i * Math.PI * 2 / 10 + 0.27;
  const d = 10.2 + (i % 3) * 0.7;
  leaves(
    24 + Math.cos(a) * d,
    24 + Math.sin(a) * d,
    37.1 + (i % 3) * 0.23,
    5.1 + (i % 2) * 0.6,
    5.0 + ((i + 1) % 2) * 0.6,
    2.25
  );
}

// Small scattered highlights on the visible upper leaves.
forEach((x, y, z, color) => {
  if (!greens.includes(color) || z < 36 || get(x, y, z + 1)) return;
  if (rand() < 0.13) set(x, y, z, rand() < 0.62 ? greens[4] : greens[5]);
});