You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js:如何为不规则几何体映射纹理(UV-Coordinates)

解决Three.js自定义几何体的纹理投影问题

Absolutely! Custom UV coordinates are exactly what you need to fix that stretched side texture and achieve the projected look you showed in your Photoshop mockup. Let’s break down how to approach this step by step.

Why the default UVs are causing stretching

Three.js’s default BoxGeometry generates UVs by stretching the texture to fit each face’s original rectangular shape. When you modify the bottom vertices to create a tapered side, the default UVs still try to map the texture to the new trapezoidal face—resulting in that stretched effect you’re seeing. To fix this, we need to manually calculate UVs that "project" the texture onto the sides, ignoring the tapering.

How to create projected UVs for your custom geometry

The core idea is to map each vertex’s 3D position to a 2D UV coordinate based on the direction you want the texture to project (e.g., straight down the Y-axis, like a projector pointing at the sides). Here’s a practical example you can adapt to your modified geometry:

// Assume you have your modified BoxGeometry ready
const customBox = yourModifiedBoxGeometry;

// Extract position data and initialize a new UV array
const positions = customBox.attributes.position.array;
const uvData = [];

// Get your original box dimensions (adjust if you modified these)
const { width, height, depth } = customBox.parameters;

// Loop through each vertex (3 values per vertex: x, y, z)
for (let i = 0; i < positions.length; i += 3) {
  const x = positions[i];
  const y = positions[i + 1];
  const z = positions[i + 2];

  // Calculate base UVs (for top/bottom faces)
  const baseU = (x + width / 2) / width; // Map X from [-width/2, width/2] to [0, 1]
  const baseV = (y + height / 2) / height; // Map Y from [-height/2, height/2] to [0, 1]

  // Check if this vertex belongs to a side face
  const isXSide = Math.abs(x - width/2) < 0.001 || Math.abs(x + width/2) < 0.001;
  const isZSide = Math.abs(z - depth/2) < 0.001 || Math.abs(z + depth/2) < 0.001;

  if (isXSide) {
    // For X-aligned sides, use Z and Y for UVs (projects texture along X-axis)
    const u = (z + depth / 2) / depth;
    uvData.push(u, baseV);
  } else if (isZSide) {
    // For Z-aligned sides, use X and Y for UVs (projects texture along Z-axis)
    const u = (x + width / 2) / width;
    uvData.push(u, baseV);
  } else {
    // Top/bottom faces: use base UVs or adjust as needed
    uvData.push(baseU, baseV);
  }
}

// Create a new UV attribute and assign it to the geometry
customBox.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvData), 2));

// Important: Update geometry metadata after modifying attributes
customBox.computeBoundingBox();
customBox.computeVertexNormals();

Key adjustments to fit your specific geometry

  • Vertex detection: If your modified geometry’s side vertices don’t have exact width/2 or depth/2 values (e.g., you moved them inward), adjust the isXSide/isZSide checks to match your actual vertex positions.
  • Texture scaling: If you want the texture to repeat or fit differently, multiply the UV values by a scaling factor (e.g., u = ((z + depth/2)/depth) * 2 to repeat the texture twice horizontally).
  • Texture orientation: If your texture appears upside down, reverse the v value with 1 - baseV.

Final notes

This approach gives you full control over how the texture is mapped to your custom geometry, exactly replicating the projected look you created in Photoshop. The key is to think of UV mapping as a way to "project" your 2D texture onto the 3D surface, rather than stretching it to fit each face’s shape.

内容的提问来源于stack exchange,提问作者Fabian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:25:33