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

Unity拾取物体后透视拉伸 如何保持物体原有缩放比例

Unity 拾取功能物体透视拉伸问题修复

问题描述

拾取物体后转动视角时,持握的物体会随透视效果出现非预期拉伸变形,拾取前后效果如下:

  • 拾取前(物体原始尺寸):物体原始尺寸
  • 拾取后(物体变形效果):拾取后物体变形效果
    核心诉求:拾取过程中维持物体缩放参数稳定,消除拉伸变形。

现有实现代码

PickupObject 拾取方法

public void PickupObject()
{
    physicsObject = lookObject.GetComponentInChildren<PhysicsObjects>();
    currentlyPickedUpObject = lookObject;
    pickupRB = currentlyPickedUpObject.GetComponent<Rigidbody>();
    /* priorConstraints = pickupRB.constraints;    // <--- NEW
    pickupRB.constraints = RigidbodyConstraints.FreezeAll;    // <--- NEW*/
    pickupRB.constraints = RigidbodyConstraints.FreezeRotation;
    physicsObject.playerInteractions = this;
    pickupRB.isKinematic = true;
    pickupRB.transform.parent = PickupParent.transform;
    //   pickupRB.isKinematic = true;
    //  StartCoroutine(physicsObject.PickUp());
}

Update 中持物/投掷/断开连接逻辑

if (currentlyPickedUpObject != null)
{
    HoldingItemIcon.SetActive(true);
    InteractIcon.SetActive(false);
    CenterIcon.SetActive(false); 
    currentDist = Vector3.Distance(PickupParent.position, pickupRB.position);
    currentSpeed = Mathf.SmoothStep(minSpeed, maxSpeed, currentDist / maxDistance);
    currentSpeed *= Time.fixedDeltaTime;
    pickupRB.transform.position = PickupParent.position;
    // pickupRB.transform.SetParent(PickupParent.transform);
    Vector3 direction = PickupParent.position - pickupRB.position;
    pickupRB.velocity = direction.normalized * currentSpeed;
    Vector3 camerDirection = mainCamera.transform.forward;
    // 投掷物体
    if (Throw)
    {
        HoldingItemIcon.SetActive(false);
        InteractIcon.SetActive(false);
        pickupRB.constraints = RigidbodyConstraints.None;
        pickupRB.isKinematic = false;
        pickupRB.AddForce(camerDirection * 500);
        currentlyPickedUpObject = null;
        pickupRB.transform.parent = null;               
    }
    Throw = false;
}

public void BreakConnection()
{
    pickupRB.isKinematic = false; 
    pickupRB.transform.parent = null;
    pickupRB.constraints = priorConstraints;
    //   pickupRB.constraints = RigidbodyConstraints.None;
    currentlyPickedUpObject = null;
    lookObject = null;
    physicsObject.pickedUp = false;
    currentDist = 0;
    pickupRB.useGravity = true;
}

参考截图

  • 场景截图1:场景截图1
  • 场景截图2:场景截图2
  • 拾取状态下PickupParent的lossyScale参数:lossy scale参数截图

问题根因

拉伸问题来自父物体PickupParent的缩放不是等比(1,1,1),且其上级父物体链存在非等比缩放。Unity中子物体的世界空间缩放为自身localScale与所有父物体lossyScale的乘积,只要父链存在x/y/z轴缩放值不一致的情况,子物体随父物体旋转时,不同轴向的缩放传递就会不匹配,叠加透视相机投影后就会出现明显的拉伸变形,提供的lossyScale截图可以直接验证这个问题。

修复方案

二选一即可:

  • 方案1(推荐,改动最小无副作用):取消拾取物体与PickupParent的父子层级绑定,直接每帧同步物体的位置和旋转到PickupParent的坐标,完全规避父物体缩放传递问题:
    1. 删除PickupObject()方法中的pickupRB.transform.parent = PickupParent.transform;
    2. 删除投掷逻辑、BreakConnection()方法中所有pickupRB.transform.parent = null;代码
    3. 在Update持物逻辑块中,原有设置position的代码后,添加旋转同步代码:pickupRB.transform.rotation = PickupParent.rotation;
  • 方案2(保留父子层级):检查PickupParent以及它所有上级父物体(包括主相机、相机挂载的父节点)的Transform缩放值,将所有轴向缩放统一设为1,原本靠缩放实现的持物偏移效果,改为调整PickupParent的Position值实现。
    额外优化提示:当前代码同时用了直接修改transform.position和给刚体赋值velocity的逻辑,持物阶段刚体为isKinematic状态时,用Rigidbody.MovePosition()和Rigidbody.MoveRotation()同步坐标,物理效果会更平滑,不会出现位置抖动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:15:18