首页 > 解决方案 > Three.js 上 ShapeBufferGeometry 的 uv 坐标差异

问题描述

我正在ShapeBufferGeometry以我在 three.js 源代码中看到的方式在 2d 中生成 uv 坐标,但必须缺少一些东西。我找不到原因,但是对于某些形状,相对于由三个计算的 uv,我计算的点是“某种”的倒序。其他时候,我的积分是商品,等于按三计算的积分。

我做了一个简单的演示,我根据 svg 路径创建了 4 个形状(官方 svg 加载器的简单形式)。对于每个形状,我都创建了自己的 uv 点,并用三个计算的 vs 点来面对它们。由于某种原因,第二组uvs是错误的。

我的算法缺少什么?即使在 three.js 源代码中,2d 形状上的 uv 点也不是这样计算的吗?

const {Shape, ShapeBufferGeometry} = THREE; 

const points2array = points =>
  points.reduce((tot, point, i) => {
    const idx = i * 2;
    tot[idx] = point.x;
    tot[idx + 1] = point.y;
    return tot;
  }, new Float32Array((points.length - 1) * 2));

const arrayAreEquals = (a1, a2) => {
  return a1.join("-") === a2.join("-");
};
const parseSvgPath = definition => {
  const p = new Shape();
  let lastX = 0;
  let lastY = 0;

  definition.forEach(bs => {
    switch (bs[0]) {
      case "M":
        p.moveTo(bs[1], bs[2]);
        lastX = bs[1];
        lastY = bs[2];
        break;
      case "H":
        p.lineTo(bs[1], lastY);
        lastX = bs[1];
        break;
      case "V":
        p.lineTo(lastX, bs[1]);
        lastY = bs[1];
        break;
      case "L":
        p.lineTo(bs[1], bs[2]);
        lastX = bs[1];
        lastY = bs[2];
        break;
      case "C":
        p.bezierCurveTo(bs[1], bs[2], bs[3], bs[4], bs[5], bs[6]);
        lastX = bs[5];
        lastY = bs[6];
        break;
      default:
        break;
    }
  });

  return p;
};

const path1 = [
  ["M", 86.1843823832321, 872.5106859767442],
  [
    "C",
    86.1843823832321,
    837.5758574244353,
    86.1843823832321,
    802.6410288721266,
    86.1843823832321,
    767.7062003198178
  ],
  [
    "C",
    77.62876350586899,
    767.6487330044671,
    70.52307758179892,
    761.3164804522894,
    69.16676572516424,
    752.9424605076606
  ],
  [
    "C",
    69.16676572516424,
    797.7197823857083,
    69.16676572516424,
    842.4971039108538,
    69.16676572516424,
    887.2744257889015
  ],
  [
    "C",
    70.52307758179892,
    878.9004061971749,
    77.62876350586899,
    872.5682394002545,
    86.1843823832321,
    872.5106859767442
  ],
  ["Z"]
];

const path2 = [
  ["M", 172.65222400571358, 137.48388635774268],
  ["H", 189.6698420753906],
  ["V", 224.78143268159283],
  ["H", 172.65222400571358],
  ["V", 137.48388635774268],
  ["Z"]
];

const path3 = [
  ["M", 207.14740017508217, 140.2259332997697],
  [
    "C",
    207.14740017508217,
    162.57569399538315,
    207.14740017508217,
    184.9254546909966,
    207.14740017508217,
    207.27521503370772
  ],
  [
    "C",
    212.81992129835598,
    207.27521503370772,
    218.49246359576745,
    207.27521503370772,
    224.16500624608122,
    207.27521503370772
  ],
  [
    "C",
    224.16500624608122,
    189.8467227044548,
    224.16500624608122,
    172.41821943523075,
    224.16500624608122,
    154.98971616600673
  ],
  [
    "C",
    215.6093870158158,
    154.93218426953638,
    208.50369615111362,
    148.5999962984784,
    207.14740017508217,
    140.2259332997697
  ],
  ["Z"]
];

const path4 = [
  ["M", 241.64254387743972, 259.9104933629545],
  [
    "C",
    241.64254387743972,
    266.86288841179913,
    245.7391956877056,
    273.23298585307725,
    252.1793827006818,
    275.9596857801452
  ],
  [
    "C",
    258.63565958794584,
    278.69319248665875,
    266.044712322569,
    277.1609193114356,
    270.93427418233006,
    272.1613119293537
  ],
  [
    "C",
    275.807530897404,
    267.1784194115222,
    277.2311807465509,
    259.739448326223,
    274.6196949488009,
    253.29540585568543
  ],
  [
    "C",
    272.0027169326503,
    246.83783664022096,
    265.7852479689919,
    242.52102990999816,
    258.7751272803175,
    242.52102990999816
  ],
  [
    "C",
    258.7368084434364,
    242.52102990999816,
    258.6984684324176,
    242.52102990999816,
    258.6601495955365,
    242.52102990999816
  ],
  [
    "C",
    258.6601495955365,
    230.85035448266098,
    258.6601495955365,
    219.17970093526603,
    258.6601495955365,
    207.50904703496877
  ],
  [
    "C",
    249.12653188515915,
    207.57398846800282,
    241.64254352453744,
    215.45796440533448,
    241.64254352453744,
    224.89814382244174
  ],
  [
    "C",
    241.64254387743972,
    236.56892723788087,
    241.64254387743972,
    248.23968877337776,
    241.64254387743972,
    259.9104933629545
  ],
  ["Z"]
];

const shape1 = parseSvgPath(path1);
const geometry1 = new ShapeBufferGeometry(shape1);
const shape2 = parseSvgPath(path2);
const geometry2 = new ShapeBufferGeometry(shape2);
const shape3 = parseSvgPath(path3);
const geometry3 = new ShapeBufferGeometry(shape3);
const shape4 = parseSvgPath(path4);
const geometry4 = new ShapeBufferGeometry(shape4);

console.log(
  arrayAreEquals(
    points2array(shape1.getPoints()),
    geometry1.attributes.uv.array
  )
);
console.log(
  arrayAreEquals(
    points2array(shape2.getPoints()),
    geometry2.attributes.uv.array
  )
);
console.log(
  arrayAreEquals(
    points2array(shape3.getPoints()),
    geometry3.attributes.uv.array
  )
);
console.log(
  arrayAreEquals(
    points2array(shape4.getPoints()),
    geometry4.attributes.uv.array
  )
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.js"></script>

标签: three.jsuv-mapping

解决方案


推荐阅读