一、传送带动效实现
1. 传送带视觉问题的识别
- 问题本质:当前模拟中,箱子在传送带上滑动,但传送带本身没有任何运动迹象,看起来不真实。
- 问题性质:这不是物理问题,而是视觉问题------需要让传送带看起来在运动。
- 解决思路:添加与物理交互无关的视觉技巧,让传送带材质产生移动效果。
2. 通过材质平铺与偏移实现运动效果
- 素材准备:使用课程附带的箭头图片,将其拖入项目的资源(Assets)文件夹中。
- 材质调整:打开传送带使用的材质,找到转换材质着色器(Shader),展开相关属性。
- 平铺(Tiling)设置:
- 在X轴增加平铺值会导致箭头被拉伸,不采用。
- 在Y轴上进行平铺,可以得到多个箭头排列的效果。
- 偏移(Offset)设置:改变Y轴偏移值,可以产生材质移动的视觉效果,让传送带看起来在运动。
- 核心原理:这只是材质制造的视觉错觉,并非真实的物理运动。
3. 创建ConveyorMaterialMotion脚本
- 脚本命名:新建C#脚本,命名为 ConveyorMaterialMotion。
- 脚本用途:通过代码控制材质的偏移量,实现传送带动画效果。
4. 编写速度变量与过渡计算逻辑
- 速度变量:声明 public float speed = 1.0f;,用于控制材质移动速度。
- 过渡变量计算:float transition = Time.time * speed;
- 将游戏运行时间(Time.time)乘以速度,得到随时间增长的偏移量。
- 与之前物理脚本中速度乘以时间的逻辑类似,但这里没有使用固定更新(FixedUpdate)。
5. 获取Renderer组件并修改主纹理偏移
- 获取组件方式:与获取Rigidbody组件的方式相同,使用 GetComponent<Renderer>() 获取渲染器组件。
- 修改偏移量:GetComponent<Renderer>().material.mainTextureOffset = new Vector2(0, transition);
- 修改材质的主纹理偏移(mainTextureOffset)属性。
- 使用 Vector2 类型(而非Vector3),因为纹理偏移只有X和Y两个分量。
6. 调整偏移量参数与速度匹配
- X轴与Y轴的分工:
- 箭头在Y轴方向排列,因此Y轴偏移产生运动效果。
- X轴固定为0,保持不变。
- 不同移动方向的修改方法:
- 若要在X轴移动:将过渡变量传给X分量,Y分量设为0。
- 若要在X轴和Y轴同时移动:需要创建两个变量分别控制。
- 代码修正:new Vector2(0, transition) 将X设为0,Y设为过渡变量。
7. 视觉调试与数值优化
- 速度调整:将速度设为1时运动过快,可调整为0.1或-0.1等数值。
- 调试方法:通过视觉观察传送带运动效果,反复调整速度值,找到最合适的参数。
- 最终效果:调整后传送带看起来在真实移动,视觉欺骗效果达成。
8. 技巧应用展望:数字孪生与旋转轴更改
- 当前用途:这类普通技巧目前看似无用,但在后续添加机器设备时会发挥重要作用。
- 应用场景:对设备进行数字孪生(Digital Twin)模拟时,需要让传送带等设备呈现真实的运动状态。
- 其他应用:更改物体的旋转轴(Pivot Point)也是类似的实用技巧之一。
二、更改物体的旋转轴
1. 默认旋转轴:物体自身中心
- 默认旋转行为:在Unity中新建一个球体,其旋转轴默认位于物体自身的中心位置。
- 旋转轴方向:旋转轴与物体的局部坐标轴(X、Y、Z轴)对齐,分别对应场景中看到的红、绿、蓝三条轴线。
- 旋转效果:当在Y轴上旋转球体时,它会绕穿过球体中心的Y轴旋转;同理,X轴和Z轴旋转也以球体中心为旋转中心。
2. 创建圆柱体作为自定义旋转轴
- 需求场景:当需要球体围绕自身中心以外的某个点旋转时,默认的旋转轴无法满足需求。
- 实现方法:创建一个圆柱体,将其放置在期望的旋转中心位置,并沿Y轴拉长,作为虚拟的旋转轴。
- 操作步骤:
- 在场景中新建一个圆柱体(Cylinder)。
- 调整圆柱体的位置,使其位于期望的旋转中心。
- 沿Y轴拉伸圆柱体,使其成为一个细长的轴状物体。
3. 将球体设为圆柱体的子对象实现绕轴旋转
- 核心操作:将球体设为圆柱体的子对象(Child Object)。
- 旋转效果:旋转圆柱体时,球体会围绕圆柱体所在的轴旋转,从而实现绕自定义旋转点旋转的效果。
- 操作步骤:
- 先将球体和圆柱体的旋转值全部归零。
- 在层级面板中,将球体拖拽到圆柱体下方,使其成为圆柱体的子对象。
- 旋转圆柱体,观察球体绕自定义轴旋转的效果。
4. 移除圆柱体的网格渲染器以隐藏旋转轴
- 隐藏辅助物体:圆柱体仅作为旋转轴使用,不需要在场景中显示。
- 操作方法:选中圆柱体,在Inspector面板中禁用或移除其Mesh Renderer(网格渲染器)组件。
- 使用方式:每次需要旋转球体时,只需选中圆柱体并旋转即可。
- 注意事项:在播放模式下,绿色辅助线不会显示,但旋转功能不受影响。
5. 应用场景:导入模型的枢轴点不准确问题
- 问题描述:从外部软件(如CAD)导入Unity的模型(如传送带),其枢轴点(Pivot Point)往往不在预期的位置。
- 具体表现:导入后,模型的轴移动和旋转不会围绕自身正确的轴进行,而是在空间中随意旋转。
- 原因分析:这类模型的枢轴点在导入Unity后不会自动校准,导致旋转行为不符合预期。
6. 解决方案:在机器周围创建想象中的枢轴
- 解决思路:在机器模型周围创建一些虚拟的枢轴物体(如空物体或圆柱体),作为想象中的旋转中心。
- 操作步骤:
- 在机器周围创建多个空物体(Empty Object),放置在期望的旋转中心位置。
- 将机器模型设为这些空物体的子对象。
- 隐藏这些空物体(不显示网格),仅作为旋转控制点使用。
- 最终效果:通过旋转这些隐藏的枢轴物体,即可控制机器模型绕指定轴旋转。
- 重要性:该旋转轴概念在处理导入模型时非常关键,是Unity中控制复杂模型运动的基础技巧。
三、线性运动简介
1. 线性运动的两个核心要素
- 线性运动的重要性:在数字孪生中,物体需要能够在空间中沿任意方向移动,因此线性运动是基础能力。
- 两个核心要素:
- 速率(速度):物体在任意轴上移动的快慢程度。
- 方向:物体移动的朝向。
2. 方向与 Vector3
- 方向表示:在三维空间中,方向由 x、y、z 三个轴共同决定。
- Vector3 类型:C# 中使用 Vector3 表示三维向量,因为它包含 x、y、z 三个分量。
- 六个基本方向:
- 前向(Forward):正 x 轴方向。
- 后向(Back):负 x 轴方向。
- 右向(Right):正 z 轴方向。
- 左向(Left):负 z 轴方向。
- 上向(Up):正 y 轴方向。
- 下向(Down):负 y 轴方向。
3. 简单示例:创建立方体
- 操作步骤:
- 创建一个 3D 对象(立方体)。
- 适当增大其尺寸以便观察。
- 通过 Transform 组件可手动调整物体在 x、y、z 轴上的位置。
- 编写 C# 脚本并附加到立方体上,即可在代码中访问并修改其属性。
4. 平移(Translate)的实现
- 速度定义:定义一个 float 类型的变量 speed,用于控制移动快慢。
- 平移公式:
- 变化率 = speed * Time.deltaTime(将速度乘以时间增量,确保帧率无关)。
- 平移量 = 变化率 × 方向向量(如 Vector3.right)。
- 执行移动:调用 transform.Translate(translation) 实现位置更新。
- 方向修改:将 Vector3.right 替换为 Vector3.up,物体将向上移动;替换为其他方向向量即可改变移动方向。
- 速度调整:
- 增大 speed 值,物体移动更快。
- 设为负数,物体朝相反方向移动(向量乘以负号仅改变方向)。
5. 平移的应用
- 应用场景:平移机制在数字孪生中有广泛应用,是实现物体空间运动的基础方法。
四、传感器简介
1. 触发器应用示例
- 触发器的作用:当遇到特定情况时,触发一个事件。例如,在单轴滑轨上安装线位传感器,当滑座到达传感器位置时,触发停止电机,防止电机在终点处继续旋转。
- 实现触发器所需的三要素:
- 激活触发器:触发器需要设置在传感器处,而不是设置在希望被传感器触发的对象上。
- 设置标签:为传感器物体分配一个标签(如"Sensor"),用于识别碰撞对象。
- 添加刚体:被触发的物体(如滑座)需要添加刚体组件,并设置为运动学(Kinematic),因为其运动由脚本控制,而非物理交互。
1)触发器设置步骤
- 创建传感器:复制一个方块作为线位传感器,将其位置调高,作为滑座移动的边界。
- 创建新标签:在标签管理器中添加新标签,命名为"Sensor"。
- 设置传感器:将传感器的标签设为"Sensor",并在其碰撞器(Collider)组件中勾选 Is Trigger 选项。
- 设置滑座:为滑座添加刚体(Rigidbody)组件,勾选 Is Kinematic,并取消 Use Gravity,因为其运动由脚本控制。
2)编写触发器脚本
- OnTriggerEnter 函数:内置的私有 void 函数,当物体进入触发器区域时被调用。参数为 Collider other,即与触发器发生碰撞的物体。
- 标签比较:通过 other.CompareTag("Sensor") 判断碰撞物体是否为传感器,从而执行特定操作。
- OnTriggerExit 函数:内置的私有 void 函数,当物体离开触发器区域时被调用。同样通过标签比较确认离开的是传感器。
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Sensor"))
{
Debug.Log("Touch!");
}
}
private void OnTriggerExit(Collider other)
{
if (other.CompareTag("Sensor"))
{
Debug.Log("Not Touch!");
}
}
3)实现方向反转
- 定义反转变量:声明一个 public bool reverse 变量,初始值为 false。
- 触发时设置反转:在 OnTriggerEnter 中,当检测到与传感器碰撞时,将 reverse 设为 true。
- 离开时取消反转:在 OnTriggerExit 中,当离开传感器时,将 reverse 设为 false。
- 更新函数中应用反转:在 Update 函数中,根据 reverse 的值决定移动方向。若 reverse 为 true,则将速度乘以 -1,实现方向反转。
public bool reverse = false;
void Update()
{
float translation = speed * Time.deltaTime;
if (reverse)
{
translation *= -1;
}
transform.Translate(Vector3.up * translation);
}
- 注意事项:Update 函数持续运行,而触发器函数仅在碰撞发生时触发。因此,方向反转的判断需在 Update 中根据 reverse 变量的状态执行。
五、知识小结
|--------|----------------------------------------------------------------------------------------|--------------------------------------------------------------|------|
| 知识点 | 核心内容 | 考试重点/易混淆点 | 难度系数 |
| 材质动画技术 | 通过修改材质偏移量实现传送带动画效果,使用Material.mainTextureOffset属性 | 区分平铺(Tiling)与偏移(Offset)的区别;x轴与y轴偏移方向的选择 | ⭐⭐⭐ |
| 脚本控制材质 | 创建ConveyorMaterialMotion脚本,使用Time.time * speed计算偏移量,通过GetComponent<Renderer>()获取渲染器 | Vector2与Vector3的使用场景区别;Time.time与Time.deltaTime的区别 | ⭐⭐⭐ |
| 旋转轴控制 | 通过创建空父对象(如圆柱体)作为虚拟旋转轴,将目标物体设为子对象实现绕指定轴旋转 | 导入模型的枢轴点(Pivot Point)偏移问题;父对象与子对象的层级关系 | ⭐⭐⭐⭐ |
| 线性运动基础 | 使用Transform.Translate()方法实现物体移动,包含速度(Speed)和方向(Direction)两个核心要素 | Vector3的六个方向关键词:forward/back/left/right/up/down;速度与方向向量的乘法运算 | ⭐⭐ |
| 触发器机制 | 使用OnTriggerEnter和OnTriggerExit函数检测碰撞,需设置IsTrigger和刚体(Rigidbody)组件 | 运动学刚体(Kinematic Rigidbody)与动态刚体的区别;标签(Tag)比较方法CompareTag() | ⭐⭐⭐⭐ |
| 触发器应用 | 实现滑座碰到限位传感器时改变运动方向,通过布尔变量reverse控制方向反转 | 触发器函数与Update()函数的执行流程差异;碰撞检测的实时性 | ⭐⭐⭐⭐ |
| 物体追踪移动 | 物体向另一个物体移动的概念,为液压缸等执行机构提供运动基础 | 目标追踪与固定路径运动的区别;距离计算与停止条件设置 | ⭐⭐⭐⭐ |
|-------|------------------------------------------------------------------------------|----------------------|
| 功能模块 | 核心代码 | 易错点 |
| 材质偏移 | renderer.material.mainTextureOffset = new Vector2(0, transition); | 需使用Vector2而非Vector3 |
| 平移运动 | transform.Translate(Vector3.right * speed * Time.deltaTime); | 速度与方向向量的乘法顺序 |
| 触发器进入 | void OnTriggerEnter(Collider other) { if(other.CompareTag("sensor")) {...} } | 需检查标签(Tag)是否匹配 |
| 方向反转 | speed *= -1; | 需在触发器函数中修改,而非Update中 |