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

如何避免带缩放的父对象中子对象旋转后被拉伸?

解决父对象缩放导致子对象旋转拉伸的问题

当父对象存在非均匀缩放时,直接给子对象设置反向缩放后旋转仍会出现拉伸,这是因为Three.js的变换顺序为父缩放→父旋转→父平移→子缩放→子旋转→子平移,子对象的旋转会在父缩放扭曲后的空间中执行,最终导致拉伸变形。要让子对象表现得如同父对象缩放为(1,1,1),可以通过手动控制子对象的矩阵变换来实现:

具体实现步骤

  • 禁用子对象的自动矩阵更新,避免Three.js自动覆盖我们手动设置的矩阵。
  • 计算父对象缩放的逆向量,用于抵消父对象的缩放影响。
  • 手动构建子对象的变换矩阵:先应用旋转操作,再应用逆父缩放操作(确保旋转在未被缩放的空间中执行)。
  • 将构建好的矩阵赋值给子对象的matrix属性。

修改后的代码

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// Renderer
const renderer = new THREE.WebGLRenderer({
  alpha: false,
  antialias: true,
  stencil: false,
  depth: false
});
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera();
camera.position.z = 10;
new OrbitControls(camera, renderer.domElement)

// Parent
const parentGeometry = new THREE.BoxGeometry(1, 1, 1);
const parentMaterial = new THREE.MeshBasicMaterial({ color: "tomato" });
const parent = new THREE.Mesh(parentGeometry, parentMaterial);
parent.scale.set(3, 0.5, 3)
scene.add(parent);

// Child
const childGeometry = new THREE.BoxGeometry(1, 1, 1);
const childMaterial = new THREE.MeshBasicMaterial({ color: "lightblue" });
const child = new THREE.Mesh(childGeometry, childMaterial);
parent.add(child);

// 关键修改部分
child.matrixAutoUpdate = false; // 禁用自动矩阵更新
const invParentScale = new THREE.Vector3(1/parent.scale.x, 1/parent.scale.y, 1/parent.scale.z);
const childMatrix = new THREE.Matrix4();
childMatrix.makeRotationX(Math.PI / 4); // 先应用旋转
childMatrix.scale(invParentScale); // 再应用逆父缩放,抵消父的缩放影响
child.matrix.copy(childMatrix); // 赋值给子对象矩阵

function resize() {
  const width = document.documentElement.clientWidth;
  const height = window.innerHeight;
  camera.aspect = width / height;
  camera.fov = 55
  camera.updateProjectionMatrix();
  renderer.setPixelRatio(Math.min(2, devicePixelRatio));
  renderer.setSize(width, height);
}
window.addEventListener("resize", resize);
resize();

function tick(t) {
  requestAnimationFrame(tick);
  renderer.render(scene,camera);
}
requestAnimationFrame(tick);

原理说明

通过手动调整变换顺序,让旋转操作先于逆父缩放执行,这样旋转是在未被父对象缩放扭曲的原始空间中完成的,之后再用逆父缩放抵消父对象的缩放影响,最终子对象的视觉效果就如同父对象缩放为(1,1,1)时的状态,且仍保持与父对象的层级关系。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 18:40:32