Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_Math3D.c
Go to the documentation of this file.
1 class SCR_Math3D
3 {
4  //------------------------------------------------------------------------------------------------
6  static vector GetFixedAxisVector(vector toFlip)
7  {
8  return { toFlip[1], toFlip[0], toFlip[2] };
9  }
10 
11  //------------------------------------------------------------------------------------------------
13  static void RotateTowards(out float result[4], float from[4], float to[4], float maxDegreesDelta)
14  {
15  float num = Math3D.QuatAngle(from, to);
16  if (float.AlmostEqual(num, 0.0))
17  {
18  Math3D.QuatCopy(to, result);
19  return;
20  }
21 
22  float t = Math.Min(1, maxDegreesDelta / num);
23  Math3D.QuatLerp(result, from, to, t);
24  }
25 
26  //------------------------------------------------------------------------------------------------
28  static vector MoveTowards(vector start, vector target, float maxDistanceDelta)
29  {
30  vector diff = target - start;
31  float magnitude = diff.Length();
32  if (magnitude <= maxDistanceDelta || magnitude == 0)
33  return target;
34 
35  return start + diff / magnitude * maxDistanceDelta;
36  }
37 
38  //------------------------------------------------------------------------------------------------
44  static vector FixEulerVector180(vector angles)
45  {
46  for (int i = 0; i < 3; i++)
47  {
48  if (angles[i] < -180 || angles[i] > 180)
49  angles[i] = Math.Repeat(180 + angles[i], 360) - 180;
50  }
51 
52  return angles;
53  }
54 
55  //------------------------------------------------------------------------------------------------
56  // IEntity entity is the entity you want to be affected by extrapolation.
57  // Physics physics is the physics that the extrapolation should calculate with.
58  // vector netPosition is the last received position.
59  // vector netVelocity is the last received velocity.
60  // float netTeleportDistance is the max distance between position and netPosition, anything over this causes the entity to teleport.
61  // float netRotation[4] is the last received rotation.
62  // vector netVelocityAngular is the last received angular velocity.
63  // float netTeleportAng is the max angle between current rotation and replicated rotation, anything over this causes the entity to teleport.
64  // float timeSinceLastTick is the time since last synchronization of extrapolation relevant data was received, it should already be incremented by timeSlice by you!
65  // float timeSlice is the time since last frame / simulation step.
66  static void Extrapolate(IEntity entity, Physics physics, vector netPosition, vector netVelocityLinear, float netTeleportDistance, float netRotation[4], vector netVelocityAngular, float netTeleportAng, float timeSinceLastTick, float timeSlice, float netTickInterval)
67  {
68  float scale = entity.GetScale();
69  vector currentMatrix[4];
70  entity.GetWorldTransform(currentMatrix);
71 
72  // Lerp to positions/rotations received
73  vector position = currentMatrix[3];
74  float rotation[4];
75  Math3D.MatrixToQuat(currentMatrix, rotation);
76 
77  // Static object, ensure exact rotation/position
78  if (!physics || !physics.IsDynamic())
79  {
80  if (rotation != netRotation)
81  Math3D.QuatToMatrix(netRotation, currentMatrix);
82 
83  currentMatrix[3] = netPosition;
84 
85  entity.SetWorldTransform(currentMatrix);
86  entity.SetScale(scale);
87  return;
88  }
89 
90  // Dynamic object, so calculate projected position/rotation based on last tick
91  vector projectedPos = netPosition + netVelocityLinear * timeSinceLastTick;
92 
93  vector netVelocityAngularFlipped = SCR_Math3D.GetFixedAxisVector(netVelocityAngular * timeSinceLastTick);
94  float projectedRotation[4];
95  float netVelocityAngularQuat[4];
96  netVelocityAngularFlipped.QuatFromAngles(netVelocityAngularQuat);
97  Math3D.QuatMultiply(projectedRotation, netRotation, netVelocityAngularQuat);
98 
99  // Calculate the position and rotation error
100  float posError = vector.Distance(projectedPos, position);
101  float rotError = Math3D.QuatAngle(projectedRotation, rotation);
102 
103  // If too far off position, teleport
104  if (posError > netTeleportDistance)
105  {
106  entity.SetOrigin(netPosition);
107  posError = 0;
108  }
109 
110  // If too far off rotation, teleport
111  if (rotError > netTeleportAng)
112  {
113  Math3D.QuatToMatrix(netRotation, currentMatrix);
114  currentMatrix[3] = entity.GetOrigin();
115  entity.SetWorldTransform(currentMatrix);
116  rotError = 0;
117  }
118 
119  float timeStep = timeSlice / netTickInterval;
120  float timeStepTick = Math.Clamp(timeSlice / netTickInterval, 0, 1);
121 
122  // Adjust to account for errors in position/rotation
123  if (posError > 0.01)
124  {
125  entity.SetOrigin(SCR_Math3D.MoveTowards(position, projectedPos, posError * timeStep));
126  physics.SetVelocity(physics.GetVelocity() + (projectedPos - position) * timeStepTick);
127  }
128 
129  if (rotError > 0.01)
130  {
131  float outRot[4];
132  Math3D.QuatRotateTowards(outRot, rotation, projectedRotation, (rotError * timeStep) * Math.RAD2DEG);
133  Math3D.QuatToMatrix(outRot, currentMatrix);
134  currentMatrix[3] = entity.GetOrigin();
135  entity.SetWorldTransform(currentMatrix);
136 
137  float rotDiff[4];
138  float rotInv[4];
139  Math3D.QuatInverse(rotInv, rotation);
140  Math3D.QuatMultiply(rotDiff, projectedRotation, rotInv);
141  vector angularVelocity = Math3D.QuatToAngles(rotDiff);
142  angularVelocity = SCR_Math3D.FixEulerVector180(angularVelocity) * Math.DEG2RAD * timeStepTick;
143  angularVelocity += physics.GetAngularVelocity();
144  physics.SetAngularVelocity(angularVelocity);
145  }
146 
147  entity.SetScale(scale);
148  }
149 
150  //------------------------------------------------------------------------------------------------
159  static vector IntersectPlane(vector rayPos, vector rayVector, vector planePos, vector planeNormal)
160  {
161  return rayPos - rayVector * (vector.Dot(rayPos - planePos, planeNormal) / vector.Dot(rayVector, planeNormal));
162  }
163 
164  //------------------------------------------------------------------------------------------------
171  static bool MatrixEqual(vector matrixA[4], vector matrixB[4])
172  {
173  return matrixA[3] == matrixB[3]
174  && matrixA[2] == matrixB[2]
175  && matrixA[1] == matrixB[1]
176  && matrixA[0] == matrixB[0];
177  }
178 
179  //------------------------------------------------------------------------------------------------
185  static bool IsMatrixEmpty(vector matrix[4])
186  {
187  return matrix[3] == vector.Zero
188  && matrix[2] == vector.Zero
189  && matrix[1] == vector.Zero
190  && matrix[0] == vector.Zero;
191  }
192 
193  //------------------------------------------------------------------------------------------------
199  static bool IsMatrixIdentity(vector matrix[4])
200  {
201  return matrix[3] == vector.Zero
202  && matrix[2] == vector.Forward
203  && matrix[1] == vector.Up
204  && matrix[0] == vector.Right;
205  }
206 
207  //------------------------------------------------------------------------------------------------
217  static vector Min(vector vA, vector vB)
218  {
219  return Vector(
220  Math.Min(vA[0], vB[0]),
221  Math.Min(vA[1], vB[1]),
222  Math.Min(vA[2], vB[2])
223  );
224  }
225 
226  //------------------------------------------------------------------------------------------------
236  static vector Max(vector vA, vector vB)
237  {
238  return Vector(
239  Math.Max(vA[0], vB[0]),
240  Math.Max(vA[1], vB[1]),
241  Math.Max(vA[2], vB[2])
242  );
243  }
244 
245  //------------------------------------------------------------------------------------------------
250  static float GetDistanceFromSpline(notnull array<vector> points, vector point)
251  {
252  int count = points.Count();
253  if (count < 1)
254  return -1;
255 
256  if (count == 1)
257  return vector.Distance(point, points[0]);
258 
259  float tempDistanceSq;
260  vector segmentStart = points[0];
261  float minDistanceSq = vector.DistanceSq(point, segmentStart);
262 
263  foreach (int i, vector segmentEnd : points)
264  {
265  if (i == 0)
266  continue;
267 
268  tempDistanceSq = Math3D.PointLineSegmentDistanceSqr(point, segmentStart, segmentEnd);
269  if (tempDistanceSq < minDistanceSq)
270  minDistanceSq = tempDistanceSq;
271 
272  segmentStart = segmentEnd;
273  }
274 
275  return Math.Sqrt(minDistanceSq);
276  }
277 
278  //------------------------------------------------------------------------------------------------
283  static float GetDistanceFromSplineXZ(notnull array<vector> points, vector point)
284  {
285  int count = points.Count();
286  if (count < 1)
287  return -1;
288 
289  if (count == 1)
290  return vector.DistanceXZ(point, points[0]);
291 
292  float tempDistanceSq;
293  vector segmentStart = points[0];
294  float minDistanceSq = vector.DistanceSqXZ(point, segmentStart);
295  segmentStart[1] = 0; // 2D conversion
296  point[1] = 0; // 2D conversion
297 
298  foreach (int i, vector segmentEnd : points)
299  {
300  if (i == 0)
301  continue;
302 
303  segmentEnd[1] = 0;
304 
305  tempDistanceSq = Math3D.PointLineSegmentDistanceSqr(point, segmentStart, segmentEnd);
306  if (tempDistanceSq < minDistanceSq)
307  minDistanceSq = tempDistanceSq;
308 
309  segmentStart = segmentEnd;
310  }
311 
312  return Math.Sqrt(minDistanceSq);
313  }
314 
315  //------------------------------------------------------------------------------------------------
321  static bool IsPointWithinSplineDistance(notnull array<vector> points, vector point, float distance)
322  {
323  int count = points.Count();
324  if (count < 1)
325  return -1;
326 
327  if (count == 1)
328  return vector.Distance(point, points[0]) <= distance;
329 
330  distance *= distance; // variable reuse
331  vector segmentStart = points[0];
332 
333  foreach (int i, vector segmentEnd : points)
334  {
335  if (i == 0)
336  continue;
337 
338  if (Math3D.PointLineSegmentDistanceSqr(point, segmentStart, segmentEnd) < distance)
339  return true;
340 
341  segmentStart = segmentEnd;
342  }
343 
344  return false;
345  }
346 
347  //------------------------------------------------------------------------------------------------
353  static bool IsPointWithinSplineDistanceXZ(notnull array<vector> points, vector point, float distance)
354  {
355  int count = points.Count();
356  if (count < 1)
357  return -1;
358 
359  if (count == 1)
360  return vector.DistanceXZ(point, points[0]) <= distance;
361 
362  distance *= distance; // variable reuse
363  vector segmentStart = points[0];
364  segmentStart[1] = 0; // 2D conversion
365  point[1] = 0; // 2D conversion
366 
367  foreach (int i, vector segmentEnd : points)
368  {
369  if (i == 0)
370  continue;
371 
372  segmentEnd[1] = 0; // 2D conversion
373 
374  if (Math3D.PointLineSegmentDistanceSqr(point, segmentStart, segmentEnd) < distance)
375  return true;
376 
377  segmentStart = segmentEnd;
378  }
379 
380  return false;
381  }
382 
383  //------------------------------------------------------------------------------------------------
397  static void QuatAngleAxis(float angle, vector axis, out float quat[4])
398  {
399  angle = angle * 0.5;
400  float sin = Math.Sin(angle);
401 
402  axis.Normalize();
403  quat[0] = axis[0] * sin;
404  quat[1] = axis[1] * sin;
405  quat[2] = axis[2] * sin;
406  quat[3] = Math.Cos(angle);
407  }
408 
409  //------------------------------------------------------------------------------------------------
416  static vector QuatMultiply(float quat[4], vector vec)
417  {
418  vector xyz = Vector(quat[0], quat[1], quat[2]);
419  vector t = 2.0 * (xyz * vec);
420  return vec + quat[3] * t + (xyz * t);
421  }
422 
423  //------------------------------------------------------------------------------------------------
432  static void RotateAround(vector transform[4], vector pivot, vector axis, float angle, out vector result[4])
433  {
434  float q[4];
435  QuatAngleAxis(angle, axis, q);
436  result[3] = QuatMultiply(q, (transform[3] - pivot)) + pivot;
437 
438  float qt[4];
439  Math3D.MatrixToQuat(transform, qt);
440  Math3D.QuatMultiply(qt, q, qt);
441  Math3D.QuatToMatrix(qt, result);
442  }
443 
444  //------------------------------------------------------------------------------------------------
452  static void LookAt(vector source, vector destination, vector up, out vector rotMat[4])
453  {
454  vector lookDir = destination - source;
455  Math3D.DirectionAndUpMatrix(lookDir.Normalized(), up.Normalized(), rotMat);
456  }
457 
458  //------------------------------------------------------------------------------------------------
465  static vector ClampMagnitude(vector v, float magnitude)
466  {
467  if (v.LengthSq() > magnitude * magnitude)
468  return v.Normalized() * magnitude;
469 
470  return v;
471  }
472 }
SCR_Math3D
Contains various scripted 3D math functions.
Definition: SCR_Math3D.c:2
distance
float distance
Definition: SCR_DestructibleTreeV2.c:29
rotation
RespawnSystemComponentClass GameComponentClass vector vector rotation
Definition: RespawnSystemComponent.c:23
position
vector position
Definition: SCR_DestructibleTreeV2.c:30
Max
@ Max
Definition: EEquipItemType.c:21