// void Spawn(float deltaTime, ref DirectedGraph <SplineGraphPayload, SplineGraphPayloadSerializable> splineGraph) { if (count >= requestedCount) { return; } for (; count < requestedCount; ++count) { float t = UnityEngine.Random.value; Int16 edgeIndex = (Int16)Mathf.FloorToInt((splineGraph.edgePoolChildren.data.Length - 1) * UnityEngine.Random.value + 0.5f); int isComplete = 0; int isReverse = isTwoWayPathEnabled ? ((UnityEngine.Random.value >= 0.5f) ? 1 : 0) : 0; followStates[count] = new SplineMath.SplineGraphFollowState(t, edgeIndex, isComplete, isReverse); float velocityRandom = UnityEngine.Random.value; randoms[count] = new Unity.Mathematics.Random((uint)count + 1); velocities[count] = Mathf.Lerp(velocityMin, velocityMax, velocityRandom); scales[count] = Mathf.Lerp(1.0f, 1.0f, UnityEngine.Random.value); float leashPolarRadiusNormalized = math.lerp(leashNormalizedMin, leashNormalizedMax, math.pow(1.0f - velocityRandom, 2.0f)); float leashPolarThetaMin = isTwoWayPathEnabled ? (-0.5f * math.PI) : 0.0f; float leashPolarThetaMax = isTwoWayPathEnabled ? (0.5f * math.PI) : math.PI * 2.0f; float leashPolarTheta = math.lerp(leashPolarThetaMin, leashPolarThetaMax, UnityEngine.Random.value); float2 leashCartesianNormalized = new float2( math.cos(leashPolarTheta), math.sin(leashPolarTheta) ) * leashPolarRadiusNormalized; leashes[count] = leashCartesianNormalized; // Seed position and rotation with their initial values, so that dampening does not lerp between the previous garbage position of a newly spawned vehicle. // If this probes to make Spawn() significantly more expensive, we can store a flag that says whether or not we should apply dampening instead. { SplineMath.Spline spline = (isReverse == 0) ? splineGraph.payload.edgeParentToChildSplines.data[edgeIndex] : splineGraph.payload.edgeChildToParentSplines.data[edgeIndex]; Int16 vertexIndexChild = splineGraph.edgePoolChildren.data[edgeIndex].vertexIndex; Int16 vertexIndexParent = splineGraph.edgePoolParents.data[edgeIndex].vertexIndex; if (isReverse == 1) { Int16 vertexIndexTemp = vertexIndexChild; vertexIndexChild = vertexIndexParent; vertexIndexParent = vertexIndexTemp; } quaternion rotationParent = splineGraph.payload.rotations.data[vertexIndexParent]; quaternion rotationChild = splineGraph.payload.rotations.data[vertexIndexChild]; float3 positionOnSpline = SplineMath.EvaluatePositionFromT(spline, t); positions[count] = positionOnSpline; rotations[count] = SplineMath.EvaluateRotationWithRollFromT(spline, rotationParent, rotationChild, t); } followPool.EnableInstanceNext(); } }
private void Swap(int a, int b) { int capacity = positions.Length; Debug.Assert(a >= 0 && a < capacity); Debug.Assert(b >= 0 && b < capacity); float3 positionTemp = positions[b]; positions[b] = positions[a]; positions[a] = positionTemp; quaternion rotationTemp = rotations[b]; rotations[b] = rotations[a]; rotations[a] = rotationTemp; float scaleTemp = scales[b]; scales[b] = scales[a]; scales[a] = scaleTemp; float2 leashTemp = leashes[b]; leashes[b] = leashes[a]; leashes[a] = leashTemp; SplineMath.SplineGraphFollowState followStateTemp = followStates[b]; followStates[b] = followStates[a]; followStates[a] = followStateTemp; Unity.Mathematics.Random randomTemp = randoms[b]; randoms[b] = randoms[a]; randoms[a] = randomTemp; float velocityTemp = velocities[b]; velocities[b] = velocities[a]; velocities[a] = velocityTemp; float ageTemp = ages[b]; ages[b] = ages[a]; ages[a] = ageTemp; float lifetimeTemp = lifetimes[b]; lifetimes[b] = lifetimes[a]; lifetimes[a] = lifetimeTemp; bool facingReverseIsEnabledTemp = facingReverseIsEnabled[b]; facingReverseIsEnabled[b] = facingReverseIsEnabled[a]; facingReverseIsEnabled[a] = facingReverseIsEnabledTemp; }
// TODO: Debug only: private void OnSceneGUI() { // If we are currently tumbling the camera, do not attempt to do anything else. if (Event.current.alt) { return; } serializedObject.Update(); var sgm = target as SplineGraphManager; sgm.Verify(); if (!sgm.isEditingEnabled) { return; } // return; // TODO: Remove? if (Tools.current == Tool.Move) { sgm.debugPosition = Handles.PositionHandle(sgm.debugPosition, quaternion.identity); for (int i = 0, iCount = sgm.debugFollowStates.Count; i < iCount; ++i) { SplineMath.SplineGraphFollowState state = sgm.debugFollowStates[i]; int isReverse = state.DecodeIsReverse(); Int16 edgeIndex = state.DecodeEdgeIndex(); float t = state.t; SplineMath.Spline spline = (state.DecodeIsReverse() == 0) ? sgm.splineGraph.payload.edgeParentToChildSplines.data[edgeIndex] : sgm.splineGraph.payload.edgeChildToParentSplines.data[edgeIndex]; float3 position = SplineMath.EvaluatePositionFromT(spline, t); quaternion rotation = SplineMath.EvaluateRotationFromT(spline, t); Handles.PositionHandle(position, rotation); } } if (sgm.isAutoUpdateEnabled) { sgm.BuildGraphFromInstances(); } }
public void Execute(int i) { float positionDelta = math.length(velocities[i]) * deltaTime; SplineMath.SplineGraphFollowState followState = followStates[i]; Unity.Mathematics.Random random = randoms[i]; SplineMath.AdvanceTFromDelta( ref followState, ref random, positionDelta, splineGraph.vertices.data, splineGraph.vertices.count, splineGraph.edgePoolChildren.data, splineGraph.edgePoolParents.data, splineGraph.payload.edgeParentToChildSplines.data, splineGraph.payload.edgeChildToParentSplines.data ); followStates[i] = followState; randoms[i] = random; Int16 edgeIndex = followState.DecodeEdgeIndex(); SplineMath.Spline spline = (followState.DecodeIsReverse() == 0) ? splineGraph.payload.edgeParentToChildSplines.data[edgeIndex] : splineGraph.payload.edgeChildToParentSplines.data[edgeIndex]; Int16 vertexIndexChild = splineGraph.edgePoolChildren.data[edgeIndex].vertexIndex; Int16 vertexIndexParent = splineGraph.edgePoolParents.data[edgeIndex].vertexIndex; if (followState.DecodeIsReverse() == 1) { Int16 vertexIndexTemp = vertexIndexChild; vertexIndexChild = vertexIndexParent; vertexIndexParent = vertexIndexTemp; } quaternion rotationParent = splineGraph.payload.rotations.data[vertexIndexParent]; quaternion rotationChild = splineGraph.payload.rotations.data[vertexIndexChild]; float3 positionPrevious = positions[i]; quaternion rotationPrevious = rotations[i]; float3 positionOnSpline = SplineMath.EvaluatePositionFromT(spline, followState.t); positions[i] = positionOnSpline; // rotations[i] = SplineMath.EvaluateRotationFromT(spline, followState.t); // rotations[i] = math.slerp(rotationParent, rotationChild, followState.t); rotations[i] = SplineMath.EvaluateRotationWithRollFromT(spline, rotationParent, rotationChild, followState.t); // For now, simply evaluate the current leash value by lerping between the parent and child leash values, rather than using spline interpolation. // This seems good enough for now (there is a bug in the spline interpolation code commented out below.) float2 leashParent = splineGraph.payload.leashes.data[vertexIndexParent]; float2 leashChild = splineGraph.payload.leashes.data[vertexIndexChild]; float2 leashMaxOS = math.lerp(leashParent, leashChild, followState.t); // SplineMath.Spline splineLeash = (followState.DecodeIsReverse() == 0) // ? splineGraph.payload.edgeParentToChildSplinesLeashes.data[edgeIndex] // : splineGraph.payload.edgeChildToParentSplinesLeashes.data[edgeIndex]; // float2 leashMaxOS = SplineMath.EvaluatePositionFromT(splineLeash, followState.t).xy; float2 leashOS = leashMaxOS * leashes[i]; float3 leashWS = math.mul(rotations[i], new float3(leashOS, 0.0f)); positions[i] += leashWS; if (avoidanceSoftBodySphereRadius > 1e-5f) { float3 avoidanceDirection = positions[i] - avoidanceSoftBodySphereOrigin; float avoidanceLength = math.length(avoidanceDirection); avoidanceDirection *= (avoidanceLength > 1e-5f) ? (1.0f / avoidanceLength) : 0.0f; float avoidanceOffset = math.saturate((avoidanceLength / avoidanceSoftBodySphereRadius) * -0.5f + 1.0f) * avoidanceSoftBodySphereRadius; if (avoidanceOffset > 0.0f) { float3 leashPlaneNormal = math.mul(rotations[i], new float3(0.0f, 0.0f, 1.0f)); float3 avoidanceDirectionLeashPlaneT = avoidanceDirection - leashPlaneNormal * math.dot(leashPlaneNormal, avoidanceDirection); avoidanceDirectionLeashPlaneT = (math.lengthsq(avoidanceDirectionLeashPlaneT) > 1e-3f) ? avoidanceDirectionLeashPlaneT : leashWS; avoidanceDirectionLeashPlaneT = (math.lengthsq(avoidanceDirectionLeashPlaneT) > 1e-3f) ? avoidanceDirectionLeashPlaneT : new float3(0.0f, 1.0f, 0.0f); avoidanceDirectionLeashPlaneT = math.normalize(avoidanceDirectionLeashPlaneT); positions[i] += avoidanceDirectionLeashPlaneT * avoidanceOffset; } } positions[i] = math.lerp(positions[i], positionPrevious, dampeningPosition); rotations[i] = math.slerp(rotations[i], rotationPrevious, dampeningRotation); // { // float3 acceleration = SplineMath.EvaluateAccelerationFromT(spline, followState.t); // float3 directionRightWS = math.mul(rotations[i], new float3(1.0f, 0.0f, 0.0f)); // float accelerationRight = math.dot(directionRightWS, acceleration); // float rollAngle = math.lerp(-0.25f * math.PI, 0.25f * math.PI, math.saturate((accelerationRight * rollFromAccelerationScale) * -0.5f + 0.5f)); // rotations[i] = math.mul(rotations[i], quaternion.AxisAngle(new float3(0.0f, 0.0f, 1.0f), rollAngle)); // } }
// Debug only: void Update() { Verify(); if (!isEditingEnabled) { return; } // Debug.Log("debugSpawnDeltaTime = " + debugSpawnDeltaTime); debugSpawnDeltaTime += Time.deltaTime; if (debugIsSpawnEnabled && (debugSpawnDeltaTime > 1.0f)) { debugSpawnDeltaTime = 0; int isReverse = debugIsReverse ? 1 : 0; SplineMath.FindTFromClosestPointOnSplineGraph( out float t, out float d, out Int16 edgeIndex, isReverse, debugPosition, splineGraph.vertices.data, splineGraph.vertices.count, splineGraph.edgePoolChildren.data, splineGraph.edgePoolParents.data, splineGraph.payload.edgeParentToChildSplines.data, splineGraph.payload.edgeChildToParentSplines.data ); SplineMath.SplineGraphFollowState state = new SplineMath.SplineGraphFollowState(t, edgeIndex, 0, isReverse); // Debug.Log("Spawning at:" + state.DebugString()); debugFollowStates.Add(state); UInt32 seed = randomSeedGenerator.NextUInt(); while (seed == 0) { seed = randomSeedGenerator.NextUInt(); } debugFollowRandoms.Add(new Unity.Mathematics.Random(seed)); } for (int i = 0; i < debugFollowStates.Count;) { SplineMath.SplineGraphFollowState state = debugFollowStates[i]; Unity.Mathematics.Random random = debugFollowRandoms[i]; float delta = Time.deltaTime * debugVelocity; SplineMath.AdvanceTFromDelta( ref state, ref random, delta, splineGraph.vertices.data, splineGraph.vertices.count, splineGraph.edgePoolChildren.data, splineGraph.edgePoolParents.data, splineGraph.payload.edgeParentToChildSplines.data, splineGraph.payload.edgeChildToParentSplines.data ); // Debug.Log("Updating at: " + state.DebugString()); if (state.DecodeIsComplete() == 1) { debugFollowStates.RemoveAt(i); debugFollowRandoms.RemoveAt(i); } else { debugFollowStates[i] = state; debugFollowRandoms[i] = random; ++i; } } }