当前位置: 首页 > ai >正文

Unity 绳子插件 ObjRope 使用简记

Unity 绳子插件,是一个基于物理的、高度逼真且可交互的绳索模拟解决方案。

其性能良好,能够运行在小游戏平台。

一、插件基本

插件资源商店地址:

Obi Rope | Physics | Unity Asset Store

官方文档(手册):

Obi Physics for Unity - Rope Setup

官方文档(API):

Obi - Unified Particle Physics for Unity 3D

1、导入插件

2、按照URP和插件文档说明,修复材质为URP材质

https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.1/manual/upgrading-your-shaders.html

3、安装Burst 、Collections 、Mathematics 包(unity2021.3.42f1c1)

二、ObiSolver 及相关设置

可以添加到任何GameObject上;

在同一个场景中可以有多个解算器同时工作;

每个Actor都必须在一个 ObiSolver 层级之下才能工作

每个ObiSolver独立,由不同 ObiSolver更新的 Actor 不会产生相互影响/碰撞。

Solver 设置

Backends

使用哪个模拟后端。Brust性能更好,如果任何给定的后端不可用,Obi 将尝试回退到 Oni 后端。

Mode

2D 模式通常与 2D 碰撞器一起使用。

Interpolation

用于渲染粒子的插值模式。None计算速度更快,而插值将提供更美观的结果.插值会引入 1 帧延迟。

模拟设置

Gravity Space

如果设置为“Self”,重力方向将与解算器一起旋转。

Gravity

应用于此ObiSolver中粒子的重力方向和大小,以ObiSolver的局部空间表示。

Sleep threshold都将冻结

任何动能低于此值的粒子在原地。(忽略微小抖动)

注意,休眠粒子并不会从模拟中移除,也不会节省性能。

Damping

应用于粒子速度的速度阻尼。增加速度阻尼可降低粒子的动能

World linear inertia scale

应用于粒子的世界空间线性(移动)惯性,范围0~1

控制 运动时突然停止/减速;停止时突然运动或加速的表现

World angular inertia scale

应用于粒子的世界空间角惯性(旋转),范围0~1

Max Anisotropy

最大各向异性

Obi 中的流体粒子可以是椭圆形,而不是完美的球形。这用于更好地使其形状适应它们所代表的物体的表面,从而实现更准确的碰撞检测和更平滑的渲染。最大各向异性可让您确定椭圆半径之间的最大比率:值为 1 将强制所有粒子为球形(停用各向异性),大于 1 的值将允许粒子变得更椭圆,最大各向异性越高。

Simulate when invisible

隐藏时模拟?

当所有相机都看不到该ObiSolver时,该ObiSolver是否应保持模拟继续进行?

如果您的模拟需要始终更新,请保持启用此功能;

当场景中存在多个ObiSolver但它们并非始终可见时,请禁用此功能以提高性能。

平流设置平流粒子(泡沫)的全局设置)(暂跳过)

碰撞设置

Collider CCD(Continuous collision detection)

连续碰撞检测

在碰撞检测期间用于扩展碰撞体边界框的刚体速度百分比。值为 1 将使用 100% 的速度,从而产生完全的连续碰撞检测。值为 0 将导致纯静态碰撞检测。

Particle CCD (Continuous collision detection)

粒子连续碰撞检测

在碰撞检测期间用于扩展其边界框的粒子速度百分比。值为 1 将使用 100% 的速度,从而产生完全的连续碰撞检测。值为 0 将导致纯静态碰撞检测。

Collision margin  Collision margin

碰撞边距

添加到粒子边界框的边距(CCD 扩展后),在生成触点时使用。粒子边界框内的任何碰撞体/粒子都将被考虑用于接触生成。此值应保持相对较低。较大的值将生成更多的接触,这可以提高非常复杂场景中的稳定性,但会对性能产生负面影响。

Max depenetration  

最大穿透力

使粒子脱离碰撞盒的最大速度(以米/秒为单位)。

Shock propagation  冲击传播

较高的值将人为地增加支持其他粒子的粒子的质量。

使用它来获得更好的堆叠稳定性。

Surface collision iterations
表面碰撞迭代

为优化表面碰撞而执行的最大迭代次数。

Surface collision tolerance
曲面碰撞容差

容差阈值,低于该阈值时,曲面碰撞优化将停止。

稍微增加它有助于获得与平面更稳定的表面碰撞。

约束设置

您可以为解算器管理的所有角色全局启用/禁用每种约束类型。以这种方式禁用约束(与禁用单个角色的约束组件相反)将允许解算器完全跳过与该特定约束类型相关的任何计算。

例如,如果禁用碰撞约束和粒子碰撞约束,则会跳过整个碰撞检测管道。这使您可以自定义在后台执行的作,并消除不必要的开销。

默认情况下,所有约束类型都处于启用状态,尽管这很少是生产就绪模拟所需的。您应该禁用任何对模拟的最终外观不重要的约束。

Iterations  

迭代
每个子步骤应该评估这些约束多少次?高迭代计数将使模拟更接近真实解决方案。如果这些约束对于您的特定目的不是很重要,并且您希望获得更好的性能,请保持较低的值。默认值为 3。

Evaluation mode  

评估模式

在 Sequential (顺序) 模式下,所有约束都按照它们的创建顺序 (由每个特定的 ObiActor 确定) 进行评估,并且每个约束 “看到” 所有先前的约束所做的调整。这确保了快速收敛,因此您的约束只需要很少的迭代即可看起来不错。但是,当多个约束争夺控制权时,它不是很稳定 - 它会引入抖动 - 因此在某些用例中,这种模式不是一个好的选择。它与顺序相关,因此在低预算情况下(少量粒子、少量迭代和/或大时间步长),这可能会导致粒子排列中出现可见的图案。对于那些稍微懂技术的人来说,这是一个 Gauss-Seidel 类型的求解器。

在 Parallel 模式下,将评估所有约束,但不会立即将其调整应用于粒子。相反,它们被存储、平均,然后使用最终结果来调整粒子位置。即使同时应用了大量约束,这也能产生非常稳定的模拟,但是“硬”约束需要更多的迭代,因为它的收敛速度更慢。它也是与阶次无关的,因此可以确保颗粒的平滑排列。如果您想用性能(高迭代次数)或质量(低迭代次数)来换取稳定性和平滑度,请使用此模式。同样,对于技术用户来说:这是类似 Jacobi 的求解。

Relaxation Factor  

松弛因子

连续过度弛豫 (SOR) 因子。当尝试满足约束时,提高收敛性的一种方法是 “过度放宽” 约束。也就是说,如果将粒子向左移动 2 个单位现在就满足约束,为什么不将其移动 3 个单位呢?这正是这个因子的用途。1 是默认值,它根本不执行过度松弛。2 是最大值,它允许您对约束执行两倍 (200%) 的松弛。高值可用于帮助加快两种模式(顺序或并行)中的任何一种的收敛速度,但请记住,仿真稳定性可能会降低。小于 1 的值将仅部分强制执行约束。例如,当松弛因子为 0.25 时,约束将仅具有其正常效果的 25%。

一块布、一根绳子、一个流体发射器或一个软体,它们都是Actor。

所有 Actor 都以蓝图作为输入。

Actor 将实例化蓝图中包含的信息(粒子和约束),以便解算器可以对其进行模拟。

您可以在多个 Actor 之间重复使用同一个蓝图

如果希望将 Actor 包含在模拟中,则Actor 必须是Resolver的子项

三、原理

本质:

模拟原理,重要!!!

若自己有手写碰撞需求,亦可参考其实现原理

Obi 的工作原理

物理更新循环

Obi 将万物建模为一组粒子和约束。

约束,即为:预测后的校正

注意点:

        顺序模式和并行模式

        更高次数的迭代

        时间步长

        较重的物体不会下落得更快

        物体的绝对质量并不重要,它们的相对质量才是关键,通常称为质量比。

        警惕较大的质量比,需要增加解算器的预算(迭代/子步)以确保满足约束。

约束类型一览

Obi Physics for Unity - Scripting Particles

注意:每个ObiSolver都有一个数组用于这些属性中的每一个,该数组存储由解算器管理的任何参与者正在使用的所有粒子的当前数据。所有空间属性(位置、方向、速度、涡度等)都在解算器的局部空间中表示。

即:绳子的位置基于Solver,会跟着Solver移动,不会受中间层父物体位置的影响

四、具体操作或功能

绳子编辑

Obi Physics for Unity - Rope Setup

将绳子固定在某个点

动态设置绳子位置(移动后同步粒子)

public void SyncParticlesToTransform()
{// 计算当前 GameObject 位置与绳子实际位置的偏移量Vector3 positionOffset = transform.position - m_ObiRope.transform.position;// 遍历所有粒子并应用偏移for (int i = 0; i < m_ObiRope.particleCount; i++){m_ObiRope.solver.positions.SetVector3(i, m_ObiRope.solver.positions.GetVector3(i) + positionOffset);}// 更新粒子位置并重置物理状态m_ObiRope.UpdateParticleProperties();m_ObiRope.ResetParticles();
}

绳子撕裂/剪断

Obi Physics for Unity - Cloth Tearing

Obi Physics for Unity - Scripting Ropes

//从鼠标点击处切断
public void Cut(Vector2 mousePosition)
{//不再允许点击到m_BoxCollider2D.enabled = false;float minDistance = float.MaxValue;int nearestSegmentIndex = -1;// 遍历所有线段寻找最近点for (int i = 0; i < m_ObiRope.elements.Count; i++){var element = m_ObiRope.elements[i];// 获取当前元素的两个粒子的索引int particleIndex1 = element.particle1;int particleIndex2 = element.particle2;// 获取两个粒子的世界坐标Vector3 worldPos1 = m_ObiRope.solver.positions.GetVector3(particleIndex1);Vector3 worldPos2 = m_ObiRope.solver.positions.GetVector3(particleIndex2);worldPos1 = m_ObiRope.transform.TransformPoint(worldPos1);worldPos2 = m_ObiRope.transform.TransformPoint(worldPos2);if (!Mathf.Approximately(worldPos1.z, worldPos2.z)) { continue; }   //忽略非XY平面的线段// 计算点击点与线段的最近点Vector2 clickScreenPos = mousePosition;Vector2 screenPos1 = Camera.main.WorldToScreenPoint(worldPos1);Vector2 screenPos2 = Camera.main.WorldToScreenPoint(worldPos2);Vector2 closestPoint = ClosestPointOnLineSegment(screenPos1, screenPos2, clickScreenPos);float distance = Vector2.Distance(clickScreenPos, closestPoint);// 更新最近记录if (distance < minDistance){minDistance = distance;nearestSegmentIndex = i;}//绳子线段位置调试//GameObject go1 = new GameObject($"Test{i}_1");//go1.transform.position = worldPos1;//GameObject go2 = new GameObject($"Test{i}_2");//go2.transform.position = worldPos1;}// 获取控制点 start 和 end 的索引//限制(即:不允许从两头断开)int startIndex = 2;int endIndex = m_ObiRope.elements.Count - 2;int cutIndex = Mathf.Clamp(nearestSegmentIndex, startIndex, endIndex);// 执行切割m_ObiRope.Tear(m_ObiRope.elements[cutIndex]);m_ObiRope.RebuildConstraintsFromElements();//光标设为切割处m_CursorMu = CalculateCursorMu(cutIndex);// 获取剪开处的2个粒子int particle1_1 = m_ObiRope.elements[cutIndex - 1].particle2;int particle2_1 = m_ObiRope.elements[cutIndex].particle1;// 施加一个指向绳子左侧/右侧的力(使摇摆)// 施加一个指向屏幕外的力(使看起来像向外崩开)// 施加一个沿着轴向两端的力(使看起来像扯开)//todo:考虑受 m_CursorMu 的影响float sideForce = 50f;float backForce = 50f;float axisForce = 100f;Axis axis = m_RopeData.GetAxis();float xForce = axis == Axis.Horizontal ? axisForce : -sideForce;float yForce = axis == Axis.Horizontal ? 0 : axisForce;m_ObiRope.solver.velocities[particle1_1] += new Vector4(xForce, yForce, -backForce, 0);m_ObiRope.solver.velocities[particle2_1] += new Vector4(-xForce, -yForce, -backForce, 0);
}private Vector2 ClosestPointOnLineSegment(Vector2 A, Vector2 B, Vector2 P)
{Vector2 AP = P - A;Vector2 AB = B - A;float magnitudeAB = AB.sqrMagnitude;float ABAPproduct = Vector2.Dot(AP, AB);float distance = ABAPproduct / magnitudeAB;if (distance < 0) return A;else if (distance > 1) return B;else return A + AB * distance;
}

绳子收缩

//从光标处收缩(每帧更新)
private void UpdateToShrink()
{float minLength = 0.2f;//修改长度float newLength = m_ObiRope.restLength - ShowConfig.kRopeShrinkSpeed * Time.deltaTime * m_RopeData.GetLength();float safeNewLength = Mathf.Max(newLength, minLength);m_ObiRopeCursor.cursorMu = m_CursorMu;m_ObiRopeCursor.ChangeLength(safeNewLength);if (newLength < minLength) {m_OnShrinkCompleted();}
}

五、性能相关

1、绳子的解算器应开启 Burst。

2、绳子的解算器,可分为全局大量静止时(极低消耗设置),剪断收缩动态表现时(流畅表现设置)

3、绳子的解算器,要关闭不必要的项,数值设置够用即可。

4、可减少绳子 截面N边型绳子PathSmooting(纵向网格密),以减少模型面数

5、绳子在2D视角大量静止时,其 Render Face 可使用 Front(Cull Front) 而非 Both(Cull Off)仅当剪断收缩表现时,改为Both。

http://www.xdnf.cn/news/17848.html

相关文章:

  • C#文件复制异常深度剖析:解决“未能找到文件“之谜
  • 硬件开发_基于STM32单片机的热水壶系统
  • 领域防腐层(ACL)在遗留系统改造中的落地
  • 疯狂星期四文案网第40天运营日记
  • 分布式锁那些事
  • AI浪潮之巅:解码技术革命、重塑产业生态与构建责任未来
  • 超高车辆碰撞预警系统如何帮助提升城市立交隧道安全?
  • uniApp App 端日志本地存储方案:实现可靠的日志记录功能
  • 【python实用小脚本-187】Python一键批量改PDF文字:拖进来秒出新文件——再也不用Acrobat来回导
  • RH134 管理存储堆栈知识点
  • Day60--图论--94. 城市间货物运输 I(卡码网),95. 城市间货物运输 II(卡码网),96. 城市间货物运输 III(卡码网)
  • StarRocks集群部署
  • 顺丰面试题
  • 最长递增子序列-dp问题+二分优化
  • 金融业务安全增强方案:国密SM4/SM3加密+硬件加密机HSM+动态密钥管理+ShardingSphere加密
  • 【职场】-啥叫诚实
  • es7.x的客户端连接api以及Respository与template的区别
  • 基本电子元件:碳膜电阻器
  • pytorch 数据预处理,加载,训练,可视化流程
  • Ubuntu DNS 综合配置与排查指南
  • 研究学习3DGS的顺序
  • Golang信号处理实战
  • Linux操作系统从入门到实战(二十三)详细讲解进程虚拟地址空间
  • Canal 技术解析与实践指南
  • 【Spring框架】SpringAOP
  • Vue3从入门到精通: 4.4 复杂状态管理模式与架构设计
  • Python爬虫大师课:HTTP协议深度解析与工业级请求封装
  • dockerfile自定义镜像,乌班图版
  • MC0439符号统计
  • 智能家居【home assistant】(一)-在Windows电脑上运行home assistant