fogón

← Basics3D assetfogon/arco-de-piedra

Arco de piedra

by fogonCC09017 blocks
Arco de piedraDrag to turn it
// «Arco de piedra» · gpt-6-sol (medium)
// Stone arch («Arco de piedra»).

const dark = "#505a51";
const mortar = "#666d62";
const stone = ["#8e9387", "#999d90", "#a5a89a", "#858c80"];
const light = "#b9baaa";
const moss = ["#526c34", "#668042", "#77904a", "#405b32"];

function block(x0, y0, z0, x1, y1, z1, color) {
  box(x0, y0, z0, x1, y1, z1, color);
  if (z1 > z0) box(x0, y0, z1, x1, y1, z1, light);
  if (y0 <= y1 && z1 > z0) box(x0, y0, z0, x1, y0, z1 - 1, stone[0]);
}

// Low, slightly irregular foundation.
box(5, 13, 0, 43, 34, 0, dark);
box(6, 12, 0, 41, 34, 0, dark);
box(6, 14, 1, 42, 33, 1, mortar);
box(7, 15, 2, 41, 32, 2, "#777d70");
for (let x = 7; x <= 41; x += 5) {
  box(x, 14, 1, Math.min(x + 3, 42), 14, 1, stone[0]);
  box(x, 33, 1, Math.min(x + 3, 42), 33, 1, stone[0]);
}

// Worn paving, with broad, dark joints between individual flagstones.
for (let y = 15; y <= 31; y += 5) {
  const offset = ((y - 15) / 5) % 2 ? 2 : 0;
  for (let x = 8 - offset; x <= 40; x += 6) {
    const a = Math.max(7, x), b = Math.min(41, x + 4);
    if (a > b) continue;
    const c = stone[Math.floor(rand() * stone.length)];
    box(a, y, 3, b, Math.min(y + 3, 32), 3, c);
    if (rand() > 0.19)
      box(a + 1, y + 1, 4, Math.min(b, a + 3), Math.min(y + 2, 32), 4, c);
    if (rand() > 0.66) set(a, y, 4, light);
  }
}

// Raised, layered feet beneath the two uprights.
for (const x of [11, 35]) {
  box(x - 3, 19, 3, x + 7, 31, 3, dark);
  block(x - 2, 20, 4, x + 6, 30, 4, stone[1]);
  box(x - 1, 21, 5, x + 5, 29, 5, mortar);
}

// Thick masonry pillars. Each course has staggered vertical joints.
for (const left of [true, false]) {
  const x0 = left ? 10 : 34;
  const x1 = left ? 17 : 41;
  box(x0, 21, 5, x1, 29, 25, mortar);

  for (let z = 5, row = 0; z <= 25; z += 4, row++) {
    const top = Math.min(z + 2, 25);
    const split = row % 2 ? x0 + 3 : x0 + 4;
    block(x0, 21, z, split - 1, 29, top, stone[(row + 1) % 4]);
    block(split + 1, 21, z, x1, 29, top, stone[(row + 2) % 4]);
    // The recessed joint stays visible on the front and outer faces.
    box(split, 21, z, split, 21, top, dark);
    if (row % 2 === 0) box(x0, 20, z + 1, x1, 20, z + 1, "#777e72");
  }

  // Projecting caps and narrow carved bands.
  block(x0 - 1, 20, 22, x1 + 1, 30, 23, stone[2]);
  box(x0 - 1, 20, 21, x1 + 1, 30, 21, dark);
  box(x0, 20, 24, x1, 29, 24, "#777e71");
  block(x0 - 1, 20, 5, x1 + 1, 30, 6, stone[1]);
}

// The arch is solid stone from its stepped inner curve to its outer crest.
function outer(x) {
  return Math.floor(40 - 0.048 * (x - 25) * (x - 25));
}
function inner(x) {
  return Math.floor(33 - 0.061 * (x - 25) * (x - 25));
}
for (let x = 11; x <= 39; x++) {
  const lo = inner(x), hi = outer(x);
  for (let y = 21; y <= 29; y++) {
    for (let z = lo; z <= hi; z++) {
      let c = stone[Math.floor(x / 4 + (z - lo) / 4) % 4];
      if (y === 21) c = stone[Math.floor(x / 4 + (z - lo) / 4 + 1) % 4];
      if (z === hi || y === 29) c = light;
      if (z === lo) c = "#737c70";
      // Deep joints divide the curved span into chunky voussoirs.
      if ((x + 1) % 4 === 0 && z < hi) c = mortar;
      if (z === lo + 4 && y === 21) c = mortar;
      set(x, y, z, c);
    }
  }
}

// Raised stone ribs across the crown, and its conspicuous central keystone.
for (let x = 12; x <= 38; x += 4) {
  const h = outer(x);
  box(x, 20, h, Math.min(x + 2, 38), 30, h, stone[2]);
  box(x, 21, h + 1, Math.min(x + 1, 38), 29, h + 1, light);
}
block(23, 19, 34, 27, 30, 39, stone[2]);
box(23, 19, 34, 27, 19, 38, "#929789");
box(22, 20, 39, 29, 30, 39, stone[1]);
box(22, 21, 40, 27, 28, 40, light);

// A chipped, uneven silhouette along the old upper edge.
box(15, 23, 35, 16, 27, 35, stone[2]);
box(19, 23, 39, 20, 28, 39, stone[1]);
box(30, 24, 38, 31, 29, 38, stone[2]);
set(36, 21, 32, null);
set(37, 21, 31, null);

// Small ivy and moss patches favor the shaded left face and mortar seams.
function mossPatch(x, y, z, radius) {
  for (let dx = -radius; dx <= radius; dx++)
    for (let dz = -radius; dz <= radius; dz++) {
      if (Math.abs(dx) + Math.abs(dz) > radius + 1 || rand() < 0.28) continue;
      const xx = x + dx, zz = z + dz;
      if (get(xx, y + 1, zz) || get(xx, y, zz))
        set(xx, y - 1, zz, moss[Math.floor(rand() * moss.length)]);
    }
}
mossPatch(14, 20, 16, 3);
mossPatch(12, 20, 9, 2);
mossPatch(17, 20, 25, 3);
mossPatch(19, 20, 32, 2);
mossPatch(25, 20, 37, 1);
mossPatch(38, 20, 8, 1);
mossPatch(39, 20, 25, 1);

// Stray growth in cracks and at the foot of the arch.
for (let i = 0; i < 65; i++) {
  const x = 8 + Math.floor(rand() * 34);
  const y = 15 + Math.floor(rand() * 18);
  if (rand() < 0.5 && get(x, y, 3))
    set(x, y, 4, moss[Math.floor(rand() * moss.length)]);
}