Obi Rope(7.0.3)插件使用心得

简介: 1、绳子必须是Obi Solver子级才能实时更新运动和仿真 2.绳索异常抖动 尝试将Solver改成同步模式(Synchronization:Synchronous Fixed/Synchronous); 固定点物

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 points = new 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().enabled = true;

PinRod(rod, a.GetComponent(), b.GetComponent());

}

void CreateRodList(ObiRod obiRod, List points)

{

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(), points[points.Count - 1].GetComponent());

}

void CreateRopeList(ObiRope obiRope, List points)

{

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(), points[points.Count - 1].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);