Visual LabINTERACTIVE LEARNING
OpenGL 与 3D第 4 / 5 章

UV 标准化

处理不同几何数据之间的 UV 范围和映射一致性。

Three.jsUV相机
专题预计 46 分钟查看源文 ↗

标准化UV

  • 原理简述;假设是一个规则的图形,那么去找到uv的四个顶点,然后以uv范围,把全部uv坐标初始化到0~1范围内,然后找到uv坐标最值对应的顶点,用顶点的坐标来计算图形的边长
function standardizeUVs(geometry: THREE.BufferGeometry) {
  if (!geometry.attributes.uv || !geometry.attributes.position) {
    console.error('Geometry does not have UV or position attributes');
    return null;
  }

  const uvs = geometry.attributes.uv;
  const positions = geometry.attributes.position;
  const uvArray = uvs.array;

  // Find min and max UV coordinates
  let minU = Infinity, minV = Infinity;
  let maxU = -Infinity, maxV = -Infinity;
  let minUIndex = -1, minVIndex = -1, maxUIndex = -1, maxVIndex = -1;

  for (let i = 0; i < uvArray.length; i += 2) {
    const u = uvArray[i];
    const v = uvArray[i + 1];

    if (u < minU) {
      minU = u;
      minUIndex = i / 2;
    }
    if (v < minV) {
      minV = v;
      minVIndex = i / 2;
    }
    if (u > maxU) {
      maxU = u;
      maxUIndex = i / 2;
    }
    if (v > maxV) {
      maxV = v;
      maxVIndex = i / 2;
    }
  }
  // Calculate range
  const rangeU = maxU - minU;
  const rangeV = maxV - minV;

  // Normalize UV coordinates
  for (let i = 0; i < uvArray.length; i += 2) {
    uvArray[i] = (uvArray[i] - minU) / rangeU;
    uvArray[i + 1] = (uvArray[i + 1] - minV) / rangeV;
  }

  uvs.needsUpdate = true;

  // Get vertex positions for the extreme points
  const minUPos = new THREE.Vector3().fromBufferAttribute(positions, minUIndex);
  const maxUPos = new THREE.Vector3().fromBufferAttribute(positions, maxUIndex);
  const minVPos = new THREE.Vector3().fromBufferAttribute(positions, minVIndex);
  const maxVPos = new THREE.Vector3().fromBufferAttribute(positions, maxVIndex);

  // Calculate max edge lengths in XY plane
  const xEdgeLength = Math.sqrt(
    Math.pow(maxUPos.x - minUPos.x, 2) +
    Math.pow(maxUPos.y - minUPos.y, 2)
  );
  const yEdgeLength = Math.sqrt(
    Math.pow(maxVPos.x - minVPos.x, 2) +
    Math.pow(maxVPos.y - minVPos.y, 2)
  );

  return {
    maxEdges: {
      x: xEdgeLength,
      y: yEdgeLength
    }
  };
}