Obi Rope(7.0.3)插件使用心得
1、绳子必须是Obi Solver子级才能实时更新运动和仿真
2.绳索异常抖动 尝试将Solver改成同步模式(Synchronization:Synchronous Fixed/Synchronous);
固定点物体的碰撞体没有开启Is Trigger
3.增加Substeps或者减少Fixed Timestep(Project Settings->Time)或者降低Blueprint的Resolution可减少拉伸(即加大弹性),此外,还有降低ObiRope的Stretch Scale和StretchCompliance(拉伸柔韧性)、增加距离约束的Iterations
4.设置两个连接点(ObiParticleAttachment)可让绳子以特定角度连接物体
5.让绳索“冻结”,只需调高ObiSolver的Sleep Threshold(任何动能低于此值的粒子都将冻结在原地)即可; 如果想让绳索完全停止活动,将Max Steps Per Frame设为0,但是将失去交互(不进行计算); 此外,将绳索逆质量置0也会完全停止行动,甚至连接的对象也会停止活动 for (int i = 0; i < rope.activeParticleCount; ++i) solver.invMasses[rope.solverIndices[i]] = 0;
6.绳子在碰撞检测时容易穿模,很可能就是弹性太大,例如粒子密度Resolution的值太低、stretchingScale的值太低等; 也可增加Collision约束的Iterations值、增加ObiCollider的Thickness; 此外,速度太快也会导致碰撞失效,所以,遇到在绷紧绳子容易穿模的情况下,可以循序渐进地减小stretchingScale值; 还有,使用Distance Field(可能会产生抖动)
7.使用绳索去拖动物体,两者的质量应相差10倍以内,否则就会过度拉伸 使用路径编辑器(Obi Path Editor)设置每个控制点的绳索质量(Mass),控制点的质量值将插入到粒子中。
using Obi;
using System.Collections.Generic;
using UnityEngine;
using Material = UnityEngine.Material;
using RigidBody = UnityEngine.Rigidbody;
///
/// 动态创建绳和杆
///
public class testt : MonoBehaviour
{
public Transform cube;
public Transform capsule;
public Transform sphere;
public Material material;
public ObiRopeSection section;
public RopeType ropeType = RopeType.Rope;
private ObiRod rod;
private ObiRope rope;
private ObiSolver solver;
private ObiRodBlueprint blueprint;
private ObiRopeBlueprint ropeBlueprint;
private ObiRopeExtrudedRenderer ropeRenderer;
private ObiRopeCursor cursor;
private RigidBody rb;
public enum RopeType
{
Rope,
Rod
}
private void Awake()
{
GameObject solverObj = new GameObject();
solverObj.name = "Solver";
solver = solverObj.AddComponent
//solver.parameters.sleepThreshold = 0.1f;
solver.particleCollisionConstraintParameters.enabled = false;
solver.particleFrictionConstraintParameters.enabled = false;
solver.collisionConstraintParameters.iterations = 1;
solver.frictionConstraintParameters.enabled = false;
solver.skinConstraintParameters.enabled = false;
solver.volumeConstraintParameters.enabled = false;
solver.shapeMatchingConstraintParameters.enabled = false;
solver.tetherConstraintParameters.enabled = false;
solver.stitchConstraintParameters.enabled = false;
solver.densityConstraintParameters.enabled = false;
solver.pinConstraintParameters.iterations = 3;
if (ropeType == RopeType.Rod)
{
solver.bendingConstraintParameters.enabled = false;
//杆硬度
solver.stretchShearConstraintParameters.iterations = 10;
solver.bendTwistConstraintParameters.iterations = 10;
solver.chainConstraintParameters.enabled = true;
solver.chainConstraintParameters.iterations = 3;
}
solver.PushSolverParameters();//不调用此方法修改无效
GameObject ropeObj = new GameObject();
ropeObj.transform.parent = solver.transform;
ropeObj.name = "Rope";
if (ropeType == RopeType.Rod)
{
blueprint = ScriptableObject.CreateInstance
//blueprint.thickness = 0.2f;//厚度
blueprint.resolution = 0.3f;//粒子密度
//blueprint.pooledParticles = 5;
rod = ropeObj.AddComponent
rod.rodBlueprint = blueprint;
rod.aerodynamicsEnabled = false;
rod.tightness = 0;
}
else
{
ropeBlueprint = ScriptableObject.CreateInstance
//ropeBlueprint.thickness = 0.2f;//厚度
ropeBlueprint.resolution = 1f;//粒子密度
//ropeBlueprint.pooledParticles = 5;
rope = ropeObj.AddComponent
rope.ropeBlueprint = ropeBlueprint;
}
ropeRenderer = ropeObj.AddComponent
ropeRenderer.section = section;
ropeRenderer.uvScale = new Vector2(1, 4);
ropeRenderer.normalizeV = false;
ropeRenderer.uvAnchor = 1;
ropeRenderer.material = material;
// Add a cursor to be able to change rope length:
//cursor = rope.gameObject.AddComponent
//cursor.cursorMu = 0;
//cursor.direction = true;
//rope.stretchingScale = 0.1f;//绷紧
//rope.stretchCompliance = 0;//不允许拉伸(还是会被拉伸,只不过弹力更强)
}
// Start is called before the first frame update
void Start()
{
rb = transform.GetComponent
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
List
{
cube.transform,
//capsule.transform,
sphere.transform
};
if (ropeType == RopeType.Rod)
{
CreateRodList(rod, points);
}
else
{
CreateRopeList(rope, points);
}
}
}
void CreateRod(Transform a, Transform b)
{
// Clear pin constraints
var pinConstraints = rod.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints
pinConstraints.Clear();
Vector3 pointA = a.position;
Vector3 pointB = b.position;
// 将两个点转换为绳索的局部空间
pointA = rod.transform.InverseTransformPoint(pointA);
pointB = rod.transform.InverseTransformPoint(pointB);
// 按程序生成绳索路径(一条简单的直线)
//Vector3 direction = (pointB - pointA) * 0.3f;
Vector3 direction = (pointB - pointA).normalized;
// 按程序生成绳索路径(只是一小段,因为我们会随着时间的推移而扩展它)
int filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 0);//碰撞所有
blueprint.path.Clear();
//起点,方向起点,方向终点...
blueprint.path.AddControlPoint(a.position, -direction, direction, Vector3.up, 0.1f, 0.1f, 1, filter, Color.white, "Hook start");
blueprint.path.AddControlPoint(b.position, -direction, direction, Vector3.up, 0.1f, 0.1f, 1, filter, Color.white, "Hook end");
blueprint.path.FlushEvents();
// Set the blueprint (this adds particles/constraints to the solver and starts simulating them).
rod.rodBlueprint = blueprint;
rod.GetComponent
PinRod(rod, a.GetComponent
}
void CreateRodList(ObiRod obiRod, List
{
var pinConstraints = obiRod.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints
pinConstraints.Clear();
Vector3 pointA = points[0].position;
Vector3 pointB = points[points.Count - 1].position;
Vector3 direction = (pointB - pointA).normalized;
// 按程序生成绳索路径
int filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 0);//碰撞所有
obiRod.rodBlueprint.path.Clear();
//添加点位
for (int i = 0; i < points.Count; i++)
{
//起点,方向起点,方向终点...
obiRod.rodBlueprint.path.AddControlPoint(points[i].position, -direction, direction, Vector3.up, 0.1f, 0.1f, 1, filter, Color.white, "Rope" + i);
}
obiRod.rodBlueprint.path.FlushEvents();
PinRod(obiRod, points[0].GetComponent
}
void CreateRopeList(ObiRope obiRope, List
{
var pinConstraints = obiRope.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints
pinConstraints.Clear();
Vector3 pointA = points[0].position;
Vector3 pointB = points[points.Count - 1].position;
Vector3 direction = (pointB - pointA).normalized;
// 按程序生成绳索路径
int filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 0);//碰撞所有
obiRope.ropeBlueprint.path.Clear();
//添加点位
for (int i = 0; i < points.Count; i++)
{
//起点,方向起点,方向终点...
obiRope.ropeBlueprint.path.AddControlPoint(points[i].position, -direction, direction, Vector3.up, 50f, 0.1f, 1, filter, Color.white, "Rope" + i);
}
obiRope.ropeBlueprint.path.FlushEvents();
PinRope(obiRope, points[0].GetComponent
}
private void PinRope(ObiRope rope, ObiCollider bodyA, ObiCollider bodyB)
{
var A = rope.gameObject.AddComponent
var B = rope.gameObject.AddComponent
A.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
B.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
A.target = bodyA.transform;
B.target = bodyB.transform;
A.particleGroup = rope.ropeBlueprint.groups[0];
B.particleGroup = rope.ropeBlueprint.groups[1];
}
private void PinRod(ObiRod rope, ObiCollider bodyA, ObiCollider bodyB)
{
var A = rope.gameObject.AddComponent
var B = rope.gameObject.AddComponent
A.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
B.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
A.target = bodyA.transform;
B.target = bodyB.transform;
A.particleGroup = rope.rodBlueprint.groups[0];
B.particleGroup = rope.rodBlueprint.groups[rope.rodBlueprint.groups.Count - 1];
}
}
8.绳索数据存在Blueprint中,所以保存绳索状态要保存Blueprint而不是预制体 rope.SaveStateToBlueprint(blueprint);