fogón

← Nature3D assetfogon/termitero

Termitero

by fogonCC023207 blocks
TermiteroDrag to turn it
// «Termitero» · gpt-6-sol (medium)
// A tall termite mound: a lumpy reddish-earth tower with several pointed spires and holes.

const clay = ["#b9633f", "#c97045", "#d87e4d", "#e28d59"];
const darkClay = "#984b35";
const lightClay = "#eb9c62";

function earthColor(z) {
  const n = rand();
  if (n < 0.09) return darkClay;
  if (n < 0.29) return clay[0];
  if (n < 0.69) return clay[1];
  if (n < 0.91) return clay[2];
  return z > 18 ? lightClay : clay[3];
}

function radiusAt(z) {
  const levels = [
    [0, 17], [4, 18], [9, 17.3], [15, 15.5],
    [21, 13.2], [27, 10.3], [32, 7.2],
    [35, 4.8], [37, 1.5]
  ];
  for (let i = 1; i < levels.length; i++) {
    if (z <= levels[i][0]) {
      const a = levels[i - 1], b = levels[i];
      return a[1] + (b[1] - a[1]) * (z - a[0]) / (b[0] - a[0]);
    }
  }
  return 0;
}

// A solid, gently twisting mound, with scalloped rather than smooth sides.
for (let z = 0; z <= 37; z++) {
  const r = radiusAt(z);
  const cx = 24 + 0.8 * Math.sin(z * 0.15);
  const cy = 24 + 0.6 * Math.sin(z * 0.11 + 1);
  for (let x = 4; x <= 44; x++) {
    for (let y = 4; y <= 44; y++) {
      const angle = Math.atan2(y - cy, x - cx);
      const ripple = 0.65 * Math.sin(7 * angle + z * 0.16)
                   + 0.38 * Math.sin(11 * angle - z * 0.21);
      const distance = Math.hypot((x - cx) / 1.03, (y - cy) / 0.96);
      if (distance <= r + ripple + (rand() - 0.5) * 0.48) {
        set(x, y, z, earthColor(z));
      }
    }
  }
}

// Three pointed, uneven earthen peaks grow out of its shoulders.
const peaks = [
  { x: 22, y: 24, bottom: 26, top: 44, radius: 6.3 },
  { x: 14, y: 28, bottom: 24, top: 40, radius: 5.1 },
  { x: 33, y: 27, bottom: 25, top: 41, radius: 5.3 }
];
for (const p of peaks) {
  for (let z = p.bottom; z <= p.top; z++) {
    const t = (z - p.bottom) / (p.top - p.bottom);
    const r = p.radius * Math.pow(1 - t, 0.83) + 0.48;
    const cx = p.x + 1.3 * t * Math.sin(p.x);
    const cy = p.y - 1.0 * t;
    for (let x = Math.floor(cx - r - 1); x <= Math.ceil(cx + r + 1); x++) {
      for (let y = Math.floor(cy - r - 1); y <= Math.ceil(cy + r + 1); y++) {
        const angle = Math.atan2(y - cy, x - cx);
        const edge = r + 0.32 * Math.sin(angle * 5 + z * 0.4);
        if (Math.hypot(x - cx, y - cy) <= edge) set(x, y, z, earthColor(z));
      }
    }
  }
}

// Raised, winding clay flutes give the front its termite-built texture.
function frontY(x, z) {
  for (let y = 3; y < 45; y++) if (get(x, y, z)) return y;
  return -1;
}
for (const startX of [10, 16, 23, 31, 38]) {
  for (let z = 2; z <= 32; z++) {
    const x = Math.round(
      24 + (startX - 24) * (1 - z / 42) +
      0.8 * Math.sin(z * 0.35 + startX)
    );
    const y = frontY(x, z);
    if (y > 3) {
      set(x, y - 1, z, "#df8652");
      if (z % 5 !== 0 && get(x + 1, y, z)) {
        set(x + 1, y - 1, z, "#bb623e");
      }
    }
  }
}

// Recessed openings: irregular pale rims, warm shaded throats, dark interiors.
const openings = [
  [24, 10, 3.5, 4.0],
  [15, 20, 2.8, 3.4],
  [30, 24, 2.8, 3.4],
  [23, 32, 2.0, 2.6],
  [35, 11, 2.4, 2.9],
  [11, 9, 1.8, 2.3]
];
for (const [hx, hz, rx, rz] of openings) {
  for (let x = Math.floor(hx - rx - 2); x <= Math.ceil(hx + rx + 2); x++) {
    for (let z = Math.floor(hz - rz - 2); z <= Math.ceil(hz + rz + 2); z++) {
      if (z < 2) continue;
      const dx = (x - hx) / rx;
      const dz = (z - hz) / rz;
      const shape = dx * dx + dz * dz + 0.09 * Math.sin(x * 2.3 + z);
      const y = frontY(x, z);
      if (y < 4) continue;

      if (shape < 0.80) {
        set(x, y, z, null);
        set(x, y + 1, z, null);
        set(x, y + 2, z, null);
        set(x, y + 3, z, shape < 0.43 ? "#65382d" : "#81432f");
      } else if (shape < 1.30) {
        set(x, y - 1, z, dz > 0.25 ? "#a85437" : lightClay);
      }
    }
  }
}

// A few smaller holes face the right-hand side.
function rightX(y, z) {
  for (let x = 44; x >= 3; x--) if (get(x, y, z)) return x;
  return -1;
}
for (const [hy, hz, ry, rz] of [[23, 17, 2.4, 3], [29, 7, 1.8, 2.2]]) {
  for (let y = Math.floor(hy - ry - 2); y <= Math.ceil(hy + ry + 2); y++) {
    for (let z = Math.floor(hz - rz - 2); z <= Math.ceil(hz + rz + 2); z++) {
      const shape = ((y - hy) / ry) ** 2 + ((z - hz) / rz) ** 2;
      const x = rightX(y, z);
      if (x < 4) continue;
      if (shape < 0.78) {
        set(x, y, z, null);
        set(x - 1, y, z, null);
        set(x - 2, y, z, "#75402f");
      } else if (shape < 1.34) {
        set(x + 1, y, z, z > hz ? lightClay : "#a85437");
      }
    }
  }
}

// Sparse cheerful moss and tiny grass tufts around the foot.
for (let i = 0; i < 105; i++) {
  const a = rand() * Math.PI * 2;
  const r = 17.3 + rand() * 1.5;
  const x = Math.round(24 + Math.cos(a) * r);
  const y = Math.round(24 + Math.sin(a) * r);
  if (get(x, y, 0)) {
    const green = rand() < 0.5 ? "#78aa48" : "#93be55";
    set(x, y, 0, green);
    if (rand() < 0.26 && !get(x, y, 1)) set(x, y, 1, "#a8cb65");
  }
}