private void SetupParticles() { if (rootBoneTransform == null) { return; } particleCount = 0; HeadInfo = new HeadInfo { ObjectPrevPosition = rootBoneTransform.position, ObjectScale = math.abs(rootBoneTransform.lossyScale.x), Gravity = gravity, Weight = weight, Force = force, ParticleCount = 0, }; particleCount = 0; boneTotalLength = 0; AppendParticles(rootBoneTransform, -1, 0, in HeadInfo); UpdateParameters(); HeadInfo.ParticleCount = particleCount; }
/// <summary> /// 当目标骨骼需要移除的时候使用,目前还不完善,先不要使用 /// </summary> /// <param name="target">要移除的目标骨骼</param> public void RemoveBone(DynamicBone target) { int index = boneList.IndexOf(target); if (index == -1) { return; } //TODO:移除骨骼的逻辑 boneList.RemoveAt(index); int curHeadIndex = target.HeadInfo.Index; //移除Bone的相关Collider的关系 boneColliderMatchMap.Remove(curHeadIndex); //是否是队列中末尾对象 bool isEndTarget = curHeadIndex == headInfoList.Length - 1; if (isEndTarget) { headInfoList.RemoveAtSwapBack(curHeadIndex); headTransformAccessArray.RemoveAtSwapBack(curHeadIndex); for (int i = MaxParticleLimit - 1; i >= 0; i--) { int dataOffset = curHeadIndex * MaxParticleLimit + i; particleInfoList.RemoveAtSwapBack(dataOffset); particleTransformAccessArray.RemoveAtSwapBack(dataOffset); } } else { //将最末列的HeadInfo 索引设置为当前将要移除的HeadInfo 索引 DynamicBone lastTarget = boneList[boneList.Count - 1]; HeadInfo lastHeadInfo = lastTarget.ResetHeadIndexAndDataOffset(curHeadIndex); headInfoList.RemoveAtSwapBack(curHeadIndex); headInfoList[curHeadIndex] = lastHeadInfo; headTransformAccessArray.RemoveAtSwapBack(curHeadIndex); for (int i = MaxParticleLimit - 1; i >= 0; i--) { int dataOffset = curHeadIndex * MaxParticleLimit + i; particleInfoList.RemoveAtSwapBack(dataOffset); particleTransformAccessArray.RemoveAtSwapBack(dataOffset); } } target.ClearJobData(); }
public void Execute(int index, TransformAccess transform) { HeadInfo curHeadInfo = HeadArray[index]; curHeadInfo.RootParentBoneWorldPosition = transform.position; curHeadInfo.RootParentBoneWorldRotation = transform.rotation; curHeadInfo.ObjectMove = transform.position - (Vector3)curHeadInfo.ObjectPrevPosition; curHeadInfo.ObjectPrevPosition = transform.position; float3 force = curHeadInfo.Gravity; float3 forceDir = math.normalizesafe(force); float3 pf = forceDir * math.max(math.dot(force, forceDir), 0); // project current gravity to rest gravity force -= pf; // remove projected gravity force = (force + curHeadInfo.Force) * curHeadInfo.ObjectScale; curHeadInfo.FinalForce = force; HeadArray[index] = curHeadInfo; }
public void Execute(int index) { int headIndex = index / MaxParticleLimit; HeadInfo curHeadInfo = HeadArray[headIndex]; int offset = index % MaxParticleLimit; //每个Head及其Particle只需要计算一次就够了! if (offset == 0) { float3 parentPosition = curHeadInfo.RootParentBoneWorldPosition; quaternion parentRotation = curHeadInfo.RootParentBoneWorldRotation; for (int j = 0; j < curHeadInfo.ParticleCount; j++) { int pIdx = curHeadInfo.DataOffsetInGlobalArray + j; ParticleInfo p = ParticleArray[pIdx]; float3 localPosition = p.LocalPosition * p.ParentScale; quaternion localRotation = p.LocalRotation; float3 worldPosition = Util.LocalToWorldPosition(parentPosition, parentRotation, localPosition); quaternion worldRotation = Util.LocalToWorldRotation(parentRotation, localRotation); parentPosition = p.WorldPosition = worldPosition; parentRotation = p.WorldRotation = worldRotation; ParticleArray[pIdx] = p; } } //如果遍历到空的部分就直接跳过就好了 if (offset >= curHeadInfo.ParticleCount) { return; } int particleId = curHeadInfo.DataOffsetInGlobalArray + offset; ParticleInfo particle = ParticleArray[particleId]; if (particle.ParentIndex >= 0) { float3 v = particle.TempWorldPosition - particle.TempPrevWorldPosition; float3 rMove = curHeadInfo.ObjectMove * particle.Inert; particle.TempPrevWorldPosition = particle.TempWorldPosition + rMove; float damping = particle.Damping; if (particle.IsCollide) { damping += particle.Friction; if (damping > 1) { damping = 1; } particle.IsCollide = false; } particle.TempWorldPosition += v * (1 - damping) + curHeadInfo.FinalForce + rMove; } else { particle.TempPrevWorldPosition = particle.TempWorldPosition; particle.TempWorldPosition = particle.WorldPosition; } ParticleArray[particleId] = particle; }
public void Execute(int index) { //避免IndexOutOfRangeException:Index {0} is out of restricted IJobParallelFor range [{1}...{2] in ReadWriteBuffer. if (index % MaxParticleLimit == 0) { return; } int headIndex = index / MaxParticleLimit; HeadInfo curHeadInfo = HeadArray[headIndex]; //遍历到那些空的Particle就不用再计算了 int offset = index % MaxParticleLimit; if (offset >= curHeadInfo.ParticleCount) { return; } int particleId = curHeadInfo.DataOffsetInGlobalArray + offset; ParticleInfo particleInfo = ParticleArray[particleId]; int parentParticleIndex = curHeadInfo.DataOffsetInGlobalArray + particleInfo.ParentIndex; ParticleInfo parentParticleInfo = ParticleArray[parentParticleIndex]; float3 pos = particleInfo.WorldPosition; float3 parentPos = parentParticleInfo.WorldPosition; //TODO:尾节点的长度计算方法需要用math修改 Matrix4x4 m = float4x4.TRS(parentParticleInfo.TempWorldPosition, parentParticleInfo.WorldRotation, particleInfo.ParentScale); float restLen = !particleInfo.IsEndBone ? math.distance(parentPos, pos) : m.MultiplyVector(particleInfo.EndOffset).magnitude; float stiffness = math.lerp(1.0f, particleInfo.Stiffness, curHeadInfo.Weight); if (stiffness > 0 || particleInfo.Elasticity > 0) { float4x4 em0 = float4x4.TRS(parentParticleInfo.TempWorldPosition, parentParticleInfo.WorldRotation, particleInfo.ParentScale); float3 restPos = math.mul(em0, new float4(particleInfo.LocalPosition.xyz, 1)).xyz; float3 d = restPos - particleInfo.TempWorldPosition; particleInfo.TempWorldPosition += d * particleInfo.Elasticity; if (stiffness > 0) { d = restPos - particleInfo.TempWorldPosition; float len = math.length(d); float maxLen = restLen * (1 - stiffness) * 2; if (len > maxLen) { particleInfo.TempWorldPosition += d * ((len - maxLen) / len); } } } // //与指定的非全局碰撞器进行计算,会过滤掉挂载的全局碰撞器防止重复计算 // NativeMultiHashMap<int, int>.Enumerator enumerator = BoneColliderMatchMap.GetValuesForKey(headIndex); // while (enumerator.MoveNext()) // { // if (ColliderArray[enumerator.Current].IsGlobal) continue; // particleInfo.IsCollide = // DynamicBoneCollider.HandleCollision(ColliderArray[enumerator.Current], // ref particleInfo.TempWorldPosition, // in particleInfo.Radius); // } // // //与所有的全局碰撞器进行计算 // for (int i = 0; i < ColliderArray.Length; i++) // { // if (!ColliderArray[i].IsGlobal) continue; // particleInfo.IsCollide = // DynamicBoneCollider.HandleCollision(ColliderArray[i], // ref particleInfo.TempWorldPosition, // in particleInfo.Radius); // } // particleInfo.WorldPosition = particleInfo.TempWorldPosition; float3 dd = parentParticleInfo.TempWorldPosition - particleInfo.TempWorldPosition; float leng = math.length(dd); if (leng > 0) { particleInfo.TempWorldPosition += dd * ((leng - restLen) / leng); } ParticleArray[particleId] = particleInfo; }