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.pswp.cn/diannao/95798.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/95798.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/95798.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

demo 通讯录 + 城市选择器 (字母索引左右联动 ListItemGroup+AlphabetIndexer)笔记

一、城市选择器实现笔记1. 双层 for 循环渲染数据结构interface BKCityContent {initial: string; // 字母索引cityNameList: string[]; // 城市列表 }核心实现// 外层循环&#xff1a;字母分组 - 遍历城市数据&#xff0c;按字母分组显示 ForEach(this.cityContentList, (item…

【总结型】c语言中的位运算

位运算包括 & | ^ ~ << >>按位与 将某些变量中的某些位清0同时保持其他位不变。也可以用来获取变量中的某一位。 例如&#xff1a;将int型变量n低8位全置为0&#xff0c;其余位保持不变。 n n & 0xffffff00 如何判断一个int型变量n的第七位。 n & 0x8…

如何在FastAPI中玩转APScheduler,实现动态定时任务的魔法?

url: /posts/4fb9e30bb20956319c783e21897a667a/ title: 如何在FastAPI中玩转APScheduler,实现动态定时任务的魔法? date: 2025-08-16T01:14:26+08:00 lastmod: 2025-08-16T01:14:26+08:00 author: cmdragon summary: APScheduler是Python中强大的任务调度库,支持任务持久化…

GitHub的简单使用方法----(5)

最后一篇简单讲讲git管理远程仓库 1.目的 备份&#xff0c;实现代码共享集中化管理 &#xff08;将本地仓库同步到git远程仓库中&#xff09; git clone 仓库地址 以下图为示例&#xff0c;我打开了一个别人的项目仓库&#xff0c;点击code能看到仓库地址 等待完成即可 如…

C++ STL-string类底层实现

摘要&#xff1a; 本文实现了一个简易的string类&#xff0c;主要包含以下功能&#xff1a; 1. 默认成员函数&#xff1a;构造函数&#xff08;默认/参数化&#xff09;、拷贝构造、赋值重载和析构函数&#xff0c;采用深拷贝避免内存问题&#xff1b; 2. 迭代器支持&#xff1…

【LeetCode每日一题】

每日一题3. 无重复字符的最长子串题目总体思路代码1.两数之和题目总体思路代码15. 三数之和题目总体思路代码2025.8.153. 无重复字符的最长子串 题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长 子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3…

sharding-jdbc读写分离配置

一主两从&#xff0c;爆红是正常的&#xff0c;不知为啥 spring:shardingsphere:datasource:names: ds_master,ds_s1,ds_s2ds_master:type: com.zaxxer.hikari.HikariDataSourcedriverClassName: com.mysql.jdbc.DriverjdbcUrl: jdbc:mysql://192.168.135.100:3306/gmall_produ…

【大模型核心技术】Dify 入门教程

文章目录一、Dify 是什么二、安装与部署2.1 云端 SaaS 版&#xff08;快速入门&#xff09;2.2 私有化部署&#xff08;企业级方案&#xff09;三、界面导航与核心模块3.1 控制台概览3.2 核心功能模块详解3.2.1 知识库&#xff08;RAG 引擎&#xff09;3.2.2 工作流编排3.2.3 模…

homebrew 1

文章目录brew(1) – macOS&#xff08;或 Linux&#xff09;上缺失的包管理器概要描述术语表基本命令install *formula*uninstall *formula*listsearch \[*text*|/*text*/]命令alias \[--edit] \[*alias*|*alias**command*]analytics \[*subcommand*]autoremove \[--dry-run]bu…

设计索引的原则有哪些?

MySQL 索引设计的核心原则是 在查询性能与存储成本之间取得平衡。以下是经过实践验证的 10 大设计原则及具体实现策略&#xff1a;一、基础原则原则说明示例/反例1. 高频查询优先为 WHERE、JOIN、ORDER BY、GROUP BY 频繁出现的列建索引✅ SELECT * FROM orders WHERE user_id1…

使用影刀RPA实现快递信息抓取

最近公司项目有个需求&#xff0c;要求抓取快递单号快递信息&#xff0c;比如签收地点、签收日期等。该项目对应的快递查询网站是一个国外的网站&#xff0c;他们有专门的快递平台可以用于查询。该平台提供了快递接口进行查询&#xff0c;但需要付费。同时也提供了免费的查询窗…

蚁剑--安装、使用

用途限制声明&#xff0c;本文仅用于网络安全技术研究、教育与知识分享。文中涉及的渗透测试方法与工具&#xff0c;严禁用于未经授权的网络攻击、数据窃取或任何违法活动。任何因不当使用本文内容导致的法律后果&#xff0c;作者及发布平台不承担任何责任。渗透测试涉及复杂技…

Varjo XR虚拟现实军用车辆驾驶与操作培训

Patria基于混合现实的模拟器提供了根据现代车辆乘员需求定制的培训&#xff0c;与传统显示设置相比&#xff0c;全新的模拟解决方案具有更好的沉浸感和更小的物理空间需求。Patria是芬兰领先的国防、安全和航空解决方案提供商。提供尖端技术和全面的培训系统&#xff0c;以支持…

Java 10 新特性及具体应用

目录 1. 局部变量类型推断&#xff08;JEP 286&#xff09; 2. 不可修改集合&#xff08;JEP 269&#xff09; 3. 并行全垃圾回收&#xff08;JEP 307&#xff09; 4. 应用类数据共享&#xff08;JEP 310&#xff09; 5. 线程局部管控&#xff08;JEP 312&#xff09; 总结…

【力扣 Hot100】刷题日记

D8 全排列(非回溯法) 全排列原题链接 在刷leetcode的时候&#xff0c;看到这道题目并没法使用像STL的next_permutation方法&#xff0c;感叹C便利的同时&#xff0c;又惋惜Java并没有类似的API&#xff0c;那我们只能从原理入手了&#xff0c;仿写此算法。 其实回溯法更应该…

JetPack系列教程(七):Palette——让你的APP色彩“飞”起来!

JetPack系列教程&#xff08;七&#xff09;&#xff1a;Palette——让你的APP色彩“飞”起来&#xff01; 各位开发小伙伴们&#xff0c;还在为APP的配色发愁吗&#xff1f;别担心&#xff0c;今天咱们就来聊聊JetPack家族里的“色彩魔法师”——Palette&#xff01;这个神奇的…

力扣hot100 | 矩阵 | 73. 矩阵置零、54. 螺旋矩阵、48. 旋转图像、240. 搜索二维矩阵 II

73. 矩阵置零 力扣题目链接 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]…

ARC与eARC是什么?主要用在哪?

在家庭影音设备不断升级的今天&#xff0c;人们对音视频体验的要求越来越高。无论是追剧、玩游戏还是观看电影大片&#xff0c;很多用户不再满足于电视自带的扬声器&#xff0c;而是希望借助回音壁、功放或家庭影院系统&#xff0c;获得更加震撼的沉浸式声音体验。一、ARC是什么…

解锁JavaScript性能优化:从理论到实战

文章目录 前言 一、常见性能瓶颈剖析 二、实战案例与优化方案 (一)DOM 操作优化案例​ (二)事件绑定优化案例​ (三)循环与递归优化案例​ (四)内存管理优化案例​ 三、性能优化工具介绍 总结 前言 性能优化的重要性 在当今数字化时代,Web 应用已成为人们生活和工作…

结构化记忆、知识图谱与动态遗忘机制在医疗AI中的应用探析(上)

往期相关内容推荐: 基于Python的多元医疗知识图谱构建与应用研究(上)