fogón

← BásicoObjeto 3Dfogon/jarra

Jarra

de fogonCC013738 bloques
JarraArrastrá para girarlo
// «Jarra» · gpt-6-sol (medium)
// Pitcher («Jarra»).

const cx = 20, cy = 24;

const profile = [
  [0, 7.5], [2, 9], [5, 10.5], [9, 12],
  [15, 13.5], [20, 14], [24, 13],
  [28, 11], [31, 9.5], [35, 9.5],
  [37, 10.5], [39, 12], [40, 12]
];

function radius(z) {
  for (let i = 1; i < profile.length; i++) {
    if (z <= profile[i][0]) {
      const [z0, r0] = profile[i - 1];
      const [z1, r1] = profile[i];
      return r0 + (r1 - r0) * (z - z0) / (z1 - z0);
    }
  }
  return 12;
}

const teal = ["#17686b", "#207b7d", "#28898a", "#329494"];
const cream = ["#c5b99a", "#d9ceb0", "#e7dec3"];

for (let z = 0; z <= 40; z++) {
  const rx = radius(z);
  const ry = rx * 0.86;
  for (let x = 5; x <= 35; x++) {
    for (let y = 10; y <= 38; y++) {
      const dx = (x - cx) / rx, dy = (y - cy) / ry;
      const d = dx * dx + dy * dy;
      const flute = z >= 5 && z <= 33
        ? 0.025 * Math.cos(Math.atan2(y - cy, x - cx) * 18)
        : 0;
      if (d > 1 + flute) continue;

      // The mouth is genuinely open, with a deep, shaded interior.
      if (z >= 32) {
        const inner = z < 37 ? 0.67 : 0.63;
        if (d < inner) continue;
      }

      let color;
      if (z >= 39) {
        color = y < cy ? cream[2] : cream[1];
        if (rand() < 0.15) color = cream[0];
      } else if (z === 38 && d > 0.78) {
        color = y < cy ? cream[1] : cream[0];
      } else if (z >= 32 && d < 0.82) {
        color = y < cy ? "#a99e82" : "#bcb092";
      } else {
        const ridge = Math.cos(Math.atan2(y - cy, x - cx) * 18);
        color = ridge > 0.38 ? teal[2] : ridge < -0.45 ? teal[0] : teal[1];
        if (z > 25 && y < cy) color = ridge > 0 ? teal[2] : teal[1];
        if (z < 5) color = teal[0];
        if (rand() < 0.075) color = teal[Math.floor(rand() * teal.length)];
      }
      set(x, y, z, color);
    }
  }
}

// Sandy floor of the hollow mouth and its irregular, visible inner markings.
for (let x = 13; x <= 27; x++)
  for (let y = 18; y <= 30; y++)
    if (((x-cx)/7.3)**2 + ((y-cy)/5.9)**2 < 1)
      set(x, y, 31, rand() < 0.22 ? "#8e876e" : "#b8ad8d");

for (let x = 17; x <= 24; x++) {
  box(x, 22 + (x % 3), 32, x, 22 + (x % 3), 35,
      x % 2 ? "#857d67" : "#a99d7f");
}
box(18, 25, 34, 22, 26, 34, "#c8bd9d");

// Thick, uneven pale lip and the little projecting pouring spout on the left.
for (let x = 7; x <= 13; x++) {
  const y0 = 18 + Math.floor((13 - x) / 3);
  box(x, y0, 38, x, 25, 38, "#d7ceb3");
  if (x <= 10) box(x, y0, 39, x, 24, 39, "#eee6cd");
}
box(6, 20, 37, 9, 24, 37, "#287f80");
box(7, 20, 38, 10, 22, 38, "#f0e9d5");

// Front-facing surface details follow the curve of the vessel.
function front(x, z, color, raised = false) {
  let y = 24;
  while (y > 8 && !get(x, y, z)) y--;
  if (y > 8) set(x, raised ? y - 1 : y, z, color);
}

// Long, subtly broken ceramic flutes.
for (let x = 10; x <= 31; x += 3) {
  for (let z = 8; z <= 29; z++) {
    if (rand() < 0.14 || (z > 23 && x < 14)) continue;
    front(x, z, z % 5 === 0 ? "#358f8c" : "#155f64");
    if (x + 1 <= 31 && z % 4 !== 0)
      front(x + 1, z, "#349494");
  }
}
for (let x = 12; x <= 30; x++)
  if (rand() < 0.75) front(x, 4 + Math.floor(rand() * 2), "#adab8e");

// Small cream-colored painted motifs on the belly.
for (const [x, z, c] of [
  [15,19,"#c5b99a"],[16,20,"#e5d9b8"],[17,20,"#e9ddbf"],
  [18,19,"#d5c8a7"],[19,18,"#b6a988"],
  [23,24,"#ddd3b6"],[24,25,"#e9e0c6"],[25,25,"#e9e0c6"],
  [26,25,"#d9ceb0"],[27,24,"#e5dbc0"],
  [23,23,"#e6ddc3"],[27,23,"#e4d9bb"],
  [24,22,"#b4a478"],[25,22,"#c49d57"],[26,22,"#b7894d"],
  [23,21,"#d5c7a4"],[24,20,"#eadfc1"],[25,20,"#e9ddbc"],
  [26,20,"#d8c9a5"],[28,22,"#e8ddbf"],
  [29,20,"#ddd0ac"],[29,19,"#d9caa7"],[30,21,"#eadfc2"]
]) front(x, z, c, true);

// The handle sits behind the right shoulder: a chunky angular D-shaped loop.
const handlePath = [
  [29, 29, 36], [35, 29, 38], [39, 29, 38],
  [42, 29, 35], [43, 29, 32], [43, 29, 25],
  [41, 29, 20], [37, 29, 17], [32, 29, 17]
];
for (let i = 1; i < handlePath.length; i++) {
  const a = handlePath[i-1], b = handlePath[i];
  line(...a, ...b, 1.8, "#176b70");
}
line(31, 27, 37, 37, 27, 39, 0.8, "#3b9b9a");
line(39, 27, 38, 41, 27, 35, 0.8, "#329494");
line(42, 27, 34, 42, 27, 26, 0.8, "#2b888a");
line(41, 27, 23, 38, 27, 19, 0.8, "#268082");
box(30, 27, 34, 33, 30, 36, "#238184");
box(31, 27, 16, 35, 30, 19, "#1c7175");