コード例 #1
0
        public static void HyperbolaAsymptotes(
            NativeSlice <float3x2> segments,
            float a, float b, float xrange,
            float3 pos, quaternion rot
            )
        {
            float Asymptote(float x) => (b / a) * x;

            float2 vertex = new float2 {
                y = a
            };
            float xmin = vertex.x - xrange;
            float xmax = vertex.x + xrange;

            segments[0] = new float3x2 {
                c0 = pos + math.mul(rot, new float3 {
                    x = xmin, y = Asymptote(xmin)
                }),
                c1 = pos + math.mul(rot, new float3 {
                    x = xmax, y = Asymptote(xmax)
                })
            };
            segments[1] = new float3x2 {
                c0 = pos + math.mul(rot, new float3 {
                    x = xmin, y = -Asymptote(xmin)
                }),
                c1 = pos + math.mul(rot, new float3 {
                    x = xmax, y = -Asymptote(xmax)
                })
            };
        }
コード例 #2
0
    public static float3x2 sincos(this Vector3 f3)
    {
        var f = new float3x2();

        math.sincos(f3, out f.c0, out f.c1);
        return(f);
    }
コード例 #3
0
        /// <inheritdoc/> <remarks> Will throw exception if length < 12. </remarks>
        public static void Parabola(
            NativeSlice <float3x2> segments,
            float a, float b,
            float xmin, float xmax,
            float3 pos, quaternion rot,
            int numSegments
            )
        {
            const float c = 0;

            // float2 vertex = new float2{ x = -b / (2 * a) , y = ((4 * a * c) - (b * b)) / (4 * a) };
            // float3 focus = new float3{ x = -b / (2 * a) , y = ((4 * a * c) - (b * b) + 1) / (4 * a) };
            for (int index = 0; index < numSegments; index++)
            {
                float  x0 = math.lerp(xmin, xmax, (float)index / (float)numSegments);
                float  x1 = math.lerp(xmin, xmax, (float)(index + 1) / (float)numSegments);
                float3 v0 = math.mul(rot, new float3 {
                    x = x0, y = a * x0 * x0 + b * x0 + c
                });
                float3 v1 = math.mul(rot, new float3 {
                    x = x1, y = a * x1 * x1 + b * x1 + c
                });
                segments[index] = new float3x2 {
                    c0 = pos + v0, c1 = pos + v1
                };
            }
        }
コード例 #4
0
    public static bool CapsuleIntersectsCapsule(float3 posa, float3 posb, float3 rota, float3 rotb, float lena, float lenb, float rada, float radb, out float distance)
    {
        float3x2 tipsA    = GetCapsuleEndPoints(posa, rota, lena);
        float3x2 tipsB    = GetCapsuleEndPoints(posb, rotb, lenb);
        float3x2 spheresA = GetCapsuleEndSpheres(tipsA.c0, tipsA.c1, rada);
        float3x2 spheresB = GetCapsuleEndSpheres(tipsB.c0, tipsB.c1, radb);

        float3 v0 = spheresB.c1 - spheresA.c1;
        float3 v1 = spheresB.c0 - spheresA.c1;
        float3 v2 = spheresB.c1 - spheresA.c0;
        float3 v3 = spheresA.c0 - spheresA.c0;

        float d0 = math.dot(v0, v0);
        float d1 = math.dot(v1, v1);
        float d2 = math.dot(v2, v2);
        float d3 = math.dot(v3, v3);

        float3 closestPointA = math.select(spheresA.c1, spheresA.c0, d2 < d0 || d2 < d1 || d3 < d0 || d3 < d1);
        float3 closestPointB = ClosestPointLineSegementPoint(spheresB.c1, spheresB.c0, closestPointA);

        closestPointA = ClosestPointLineSegementPoint(spheresA.c1, spheresA.c0, closestPointB);

        distance = math.distance(closestPointA, closestPointB);

        return(distance < rada + radb);
    }
コード例 #5
0
    private void CollisionCapsuleBox()
    {
        FixedList128 <float3> verticesOBB = ColPhysics.GetAABBVerticesOBB(posB, extentsB);

        verticesOBB = ColPhysics.GetRotatedVerticesOBB(verticesOBB, posB, rotB);
        FixedList128 <float3> normalAxesOBB = ColPhysics.GetAxisNormalsOBB(verticesOBB[0], verticesOBB[1], verticesOBB[3], verticesOBB[4]);
        FixedList128 <float>  exte          = new FixedList128 <float>();

        exte.Add(extentsB.x);
        exte.Add(extentsB.y);
        exte.Add(extentsB.z);

        float3x2 capsuleTips    = ColPhysics.GetCapsuleEndPoints(posA, rotA, extentsA.y * 2);
        float3x2 capsuleSpheres = ColPhysics.GetCapsuleEndSpheres(capsuleTips.c0, capsuleTips.c1, extentsA.x);

        if (ColPhysics.CapsuleIntersectsBox(capsuleSpheres, posB, extentsA.x, normalAxesOBB, exte, out float distance))
        {
            isColliding = true;

            if (resolveCollisions)
            {
                ColPhysics.ResolveSphereBoxCollision(ref posA, extentsA.x, ref posB, distance);
            }
        }
    }
コード例 #6
0
            // TREE //
            private void createTree(int index, Entity prefab, BlobAssetReference <Collider> collider, float2x2 bounds)
            {
                float3x2 minMaxPositions = new float3x2
                {
                    c0 = new float3
                    {
                        x = bounds.c0.x,
                        y = 4,
                        z = bounds.c0.y
                    },
                    c1 = new float3
                    {
                        x = bounds.c1.x,
                        y = 0,
                        z = bounds.c1.y
                    }
                };
                Entity newEntity = CommandBuffer.Instantiate(index, prefab);
                float3 position  = getRandomPosition(minMaxPositions);

                CommandBuffer.SetComponent(index, newEntity, new Translation
                {
                    Value = position
                });
                CommandBuffer.SetComponent(index, newEntity, new PhysicsCollider
                {
                    Value = collider
                });

                float3 fruitSpawnPositionMin = position;
                float3 fruitSpawnPositionMax = position;

                fruitSpawnPositionMin.y  = 8;
                fruitSpawnPositionMin.x -= 5;
                fruitSpawnPositionMax.x += 5;
                fruitSpawnPositionMin.z -= 5;
                fruitSpawnPositionMax.z += 5;
                fruitSpawnPositionMax.y  = 10;
                CommandBuffer.AddComponent(index, newEntity, new ThingSpawner
                {
                    PrefabCollider       = prefabs.prefabColliderFruit,
                    PrefabEntity         = prefabs.prefabEntityFruit,
                    SpawnPerCycle        = 1,
                    ThingToSpawn         = ThingType.Fruit,
                    ToSpawn              = 0,
                    MinMaxSpawnPositions = new float3x2
                    {
                        c0 = fruitSpawnPositionMin,
                        c1 = fruitSpawnPositionMax
                    },
                    SpawnedFrom = newEntity
                });
                float spawnFruitEvery = 300;

                CommandBuffer.AddComponent(index, newEntity, new Tree
                {
                    ProducesEvery       = spawnFruitEvery,
                    SinceLastProduction = random.NextFloat(spawnFruitEvery)
                });
            }
コード例 #7
0
        public void Execute(int index)
        {
            var points = new float3x4
            {
                c0 = BezierData[index].B1.c0,
                c1 = BezierData[index].B1.c1,
                c2 = BezierData[index].B2.c0,
                c3 = BezierData[index].B2.c2
            };

            var extents = new float3x2
            {
                c0 =
                {
                    x = Min(points.c0.x, points.c1.x, points.c2.x, points.c3.x),
                    y = Min(points.c0.y, points.c1.y, points.c2.y, points.c3.y),
                    z = Min(points.c0.z, points.c1.z, points.c2.z, points.c3.z)
                },

                c1 =
                {
                    x = Max(points.c0.x, points.c1.x, points.c2.x, points.c3.x),
                    y = Max(points.c0.y, points.c1.y, points.c2.y, points.c3.y),
                    z = Max(points.c0.z, points.c1.z, points.c2.z, points.c3.z)
                }
            };

            BoundsArray[index] = new float3x2
            {
                c0 = math.lerp(extents.c1, extents.c0, 0.5f),
                c1 = extents.c1 - extents.c0
            };
        }
コード例 #8
0
        /// <inheritdoc/> <remarks> Will throw exception if length < numSegments. </remarks>
        public static void HyperbolaAtFoci(
            NativeSlice <float3x2> segments,
            float a, float b, float xrange,
            float3 pos, quaternion rot,
            int numSegments
            )
        {
            float  c      = math.sqrt(a * a + b * b);
            float2 vertex = new float2 {
                y = a
            };
            float3 focus = new float3 {
                x = 0, y = c
            };
            float xmin  = vertex.x - xrange;
            float xmax  = vertex.x + xrange;
            int   index = 0;

            for ( ; index < numSegments;)
            {
                float  x0 = math.lerp(xmin, xmax, (float)index / (float)numSegments);
                float  x1 = math.lerp(xmin, xmax, (float)(index + 1) / (float)numSegments);
                float3 v0 = math.mul(rot, (new float3 {
                    x = x0, y = (b * math.sqrt(a * a + x0 * x0)) / a
                } -focus));
                float3 v1 = math.mul(rot, (new float3 {
                    x = x1, y = (b * math.sqrt(a * a + x1 * x1)) / a
                } -focus));
                segments[index++] = new float3x2 {
                    c0 = pos + v0, c1 = pos + v1
                };
            }
        }
コード例 #9
0
        /// <inheritdoc/> <remarks> Will throw exception if length < numSegments. </remarks>
        public static void Ellipse(
            NativeSlice <float3x2> segments,
            float rx, float ry,
            float3 pos, quaternion rot,
            int numSegments
            )
        {
            float theta = (2f * math.PI) / (float)numSegments;
            int   index = 0;

            for ( ; index < numSegments;)
            {
                float  f0 = theta * (float)index;
                float  f1 = theta * (float)(index + 1);
                float3 v0 = math.mul(rot, (new float3 {
                    x = math.cos(f0) * rx, y = math.sin(f0) * ry
                }));
                float3 v1 = math.mul(rot, (new float3 {
                    x = math.cos(f1) * rx, y = math.sin(f1) * ry
                }));

                segments[index++] = new float3x2 {
                    c0 = pos + v0, c1 = pos + v1
                };
            }

            // float a = math.max(rx,ry);
            // float b = math.min(rx,ry);
            // float ecc = math.sqrt( 1f - (b*b)/(a*a) );
            // float c = a * ecc;
            // float3 focus = rx>ry ? new float3{x=c} : new float3{y=c};

            // foci( pos + math.mul(rot,focus) );
            // foci( pos + math.mul(rot,-focus) );
        }
コード例 #10
0
            // BUBBLE //
            private void createBubble(int index, Entity prefab, float2x2 bounds)
            {
                float3x2 minMaxPositions = new float3x2
                {
                    c0 = new float3(bounds.c0.x + 20, -10, bounds.c0.y + 20),
                    c1 = new float3(bounds.c1.x - 20, -4, bounds.c1.y - 20)
                };
                Entity newEntity = CommandBuffer.Instantiate(index, prefab);
                float3 position  = getRandomPosition(minMaxPositions);

                CommandBuffer.SetComponent(index, newEntity, new Translation
                {
                    Value = position
                });
                CommandBuffer.AddComponent(index, newEntity, new ScaleChange
                {
                    Axis      = ScaleChangeAxis.Y,
                    MinMax    = new float2(22, 28),
                    Shrinking = 0,
                    Speed     = random.NextFloat(1, 4),
                    SpeedRatioWhenShrinking = random.NextFloat(.1f, .9f)
                });
                CommandBuffer.SetComponent(index, newEntity, new NonUniformScale
                {
                    Value = new float3(random.NextFloat(10, 50), random.NextFloat(22, 28), random.NextFloat(10, 50))
                });
            }
コード例 #11
0
        public void TestMatrix()
        {
            var a = new float3x2(1, 2, 1, 2, 2, 1);
            var b = new float2x3(2, 2, 1, 3, 1, 2);
            var c = math.mul(a, b);

            Debug.Log($"{c}");
        }
コード例 #12
0
    public static bool CapsuleIntersectsBox(float3x2 capsuleSpheres, float3 obbPos, float capsuleRadius, FixedList128 <float3> boxNormals, FixedList128 <float> boxExtents, out float distance)
    {
        float3 closestPoint = ClosestPointLineSegementPoint(capsuleSpheres.c1, capsuleSpheres.c0, obbPos);
        bool   intersects   = SphereIntersectsBox(closestPoint, capsuleRadius, obbPos, boxNormals, boxExtents, out float dist);

        distance = dist;
        return(intersects);
    }
コード例 #13
0
    public static bool SphereIntersectsCapsule(float3 spherePos, float sphereRadius, float3 capsulePos, float3 capsuleRot, float capsuleLength, float capsuleRadius)
    {
        float3x2 capsuleTips    = GetCapsuleEndPoints(capsulePos, capsuleRot, capsuleLength);
        float3x2 capsuleSpheres = GetCapsuleEndSpheres(capsuleTips.c0, capsuleTips.c1, capsuleRadius);
        float3   closestPoint   = ClosestPointLineSegementPoint(capsuleSpheres.c1, capsuleSpheres.c0, spherePos);

        return(math.distancesq(spherePos, closestPoint) < sphereRadius + capsuleRadius);
    }
コード例 #14
0
 private static void CustomVisit(ref float3x2 f)
 {
     LogVisit(f);
     GUILayout.Label(name);
     EditorGUI.indentLevel++;
     f[0] = EditorGUILayout.Vector3Field("", (Vector3)f[0]);
     f[1] = EditorGUILayout.Vector3Field("", (Vector3)f[1]);
     EditorGUI.indentLevel--;
 }
コード例 #15
0
ファイル: AnimalUpdateJob.cs プロジェクト: tuvus/iowa-systems
    float GetClosestDistanceFromTwoPositions(float3x2 from, float3 to)
    {
        float distance         = GetDistance(from.c0, to);
        float otherEyeDistance = GetDistance(from.c1, to);

        if (otherEyeDistance < distance)
        {
            return(otherEyeDistance);
        }
        return(distance);
    }
コード例 #16
0
ファイル: AnimalUpdateJob.cs プロジェクト: tuvus/iowa-systems
 float GetEyeDistance(float3x2 eyePositions, float3 to)
 {
     if (speciesEyeType == EyesScript.EyeTypes.Foward)
     {
         return(GetDistance(eyePositions.c0, to));
     }
     else
     {
         return(GetClosestDistanceFromTwoPositions(eyePositions, to));
     }
 }
コード例 #17
0
        private static float3x2 GetControlPoints([ReadOnly] ref float3[] knots, int index, float tension = 0.66f)
        {
            var   result         = new float3x2(new float3(), new float3());
            var   thisVector     = knots[index];
            float looseness      = (1f - tension) / 2;
            var   previousVector = knots[index - 1 < 0 ? knots.Length - 1 : index - 1];
            var   nextVector     = knots[index + 1 >= knots.Length ? 0 : index + 1];
            var   heading        = math.normalize(nextVector - previousVector);

            result.c0 = thisVector - heading * math.length(thisVector - previousVector) * looseness;
            result.c1 = thisVector + heading * math.length(nextVector - thisVector) * looseness;
            return(result);
        }
コード例 #18
0
        void Update()
        {
            _batch.Dependency.Complete();

            var buffer = _batch.buffer;

            buffer.Length = 3;
            Vector3 position = transform.position;

            buffer[0] = new float3x2(position, position + transform.right);
            buffer[1] = new float3x2(position, position + transform.up);
            buffer[2] = new float3x2(position, position + transform.forward);
        }
コード例 #19
0
        /// <inheritdoc/> <remarks> Will throw exception if length < 12. </remarks>
        public static void ParabolaAtFoci(
            NativeSlice <float3x2> segments,
            float a, float b, float xrange,
            float3 pos, quaternion rot,
            int numSegments
            )
        {
            const float c      = 0;
            float2      vertex = new float2 {
                x = -b / (2 * a), y = ((4 * a * c) - (b * b)) / (4 * a)
            };
            float3 focus = new float3 {
                x = -b / (2 * a), y = ((4 * a * c) - (b * b) + 1) / (4 * a)
            };
            float directrix_y = c - ((b * b) + 1) * 4 * a;

            float xmin  = vertex.x - xrange;
            float xmax  = vertex.x + xrange;
            int   index = 0;

            for ( ; index < numSegments - 1;)
            {
                float  x0 = math.lerp(xmin, xmax, (float)index / (float)numSegments);
                float  x1 = math.lerp(xmin, xmax, (float)(index + 1) / (float)numSegments);
                float3 v0 = math.mul(rot, (new float3 {
                    x = x0, y = a * x0 * x0 + b * x0 + c
                } -focus));
                float3 v1 = math.mul(rot, (new float3 {
                    x = x1, y = a * x1 * x1 + b * x1 + c
                } -focus));

                segments[index++] = new float3x2 {
                    c0 = pos + v0, c1 = pos + v1
                };
            }

            segments[index++] = new float3x2 {
                c0 = math.mul(rot, new float3 {
                    x = xmin, y = directrix_y
                } -focus) + new float3 {
                    x = pos.z
                },
                c1 = math.mul(rot, new float3 {
                    x = xmax, y = directrix_y
                } -focus) + new float3 {
                    x = pos.z
                }
            };
        }
コード例 #20
0
        /// <inheritdoc/> <remarks> Will does nothing if array is too short. </remarks>
        public static void Line(
            NativeArray <float3x2> segments, ref int index,
            float3 start, float3 end
            )
        {
            int bufferSizeRequired = index + 1;

            if (segments.Length < bufferSizeRequired)
            {
                return;
            }

            segments[index++] = new float3x2 {
                c0 = start, c1 = end
            };
        }
コード例 #21
0
        /// <inheritdoc/> <remarks> Will throw exception if length < numDashes. </remarks>
        public static void DashedLine(
            NativeSlice <float3x2> segments,
            float3 start, float3 end, int numSegments
            )
        {
            int index = 0;
            int max   = math.max(numSegments * 2 - 1, 0);

            for (int i = 0; i < max; i += 2)
            {
                segments[index++] = new float3x2 {
                    c0 = math.lerp(start, end, (float)(i) / (float)max),
                    c1 = math.lerp(start, end, (float)(i + 1) / (float)max)
                };
            }
        }
コード例 #22
0
ファイル: AnimalScript.cs プロジェクト: tuvus/iowa-systems
 public AnimalData(AnimalScript animal)
 {
     age                     = animal.age;
     speciesIndex            = animal.species.speciesIndex;
     specificSpeciesIndex    = animal.species.specificSpeciesIndex;
     animalIndex             = animal.specificOrganismIndex;
     position                = animal.position;
     zone                    = animal.zone;
     animalEyePosition       = GetAnimalEyePositions(animal, animal.GetEyes());
     animalMouthPosition     = GetMouthPosition(animal, animal.GetMouth());
     animalFood              = animal.food;
     animalSex               = animal.GetReproductive().GetSex();
     animalHasMate           = AnimalHasMate(animal);
     animalReproductionReady = ReadyToReproduce(animal);
     stage                   = animal.stage;
 }
コード例 #23
0
            void IJobParallelFor.Execute(int index)
            {
                int    i0 = Edges[index].x;
                int    i1 = Edges[index].y;
                float4 p0 = math.mul(Transform, new float4(Vertices[i0], 1));
                float4 p1 = math.mul(Transform, new float4(Vertices[i1], 1));

                Segments[index] = new float3x2 {
                    c0 = new float3 {
                        x = p0.x, y = p0.y, z = p0.z
                    },
                    c1 = new float3 {
                        x = p1.x, y = p1.y, z = p1.z
                    }
                };
            }
コード例 #24
0
ファイル: AnimalScript.cs プロジェクト: tuvus/iowa-systems
 public static float3x2 GetAnimalEyePositions(AnimalScript animal, EyesScript eyes)
 {
     if (eyes != null)
     {
         float3x2 eyePostions;
         if (eyes.GetEyeType() == EyesScript.EyeTypes.Foward)
         {
             eyePostions = new float3x2(eyes.eyes[0].position, eyes.eyes[0].position);
         }
         else
         {
             eyePostions = new float3x2(eyes.eyes[0].position, eyes.eyes[1].position);
         }
         return(eyePostions);
     }
     return(new float3x2(animal.position, animal.position));
 }
コード例 #25
0
    public static bool CapsuleIntersectsCapsule(float3x2 spheresA, float3x2 spheresB, float rada, float radb)
    {
        float3 v0 = spheresB.c1 - spheresA.c1;
        float3 v1 = spheresB.c0 - spheresA.c1;
        float3 v2 = spheresB.c1 - spheresA.c0;
        float3 v3 = spheresA.c0 - spheresA.c0;

        float d0 = math.dot(v0, v0);
        float d1 = math.dot(v1, v1);
        float d2 = math.dot(v2, v2);
        float d3 = math.dot(v3, v3);

        float3 closestPointA = math.select(spheresA.c1, spheresA.c0, d2 < d0 || d2 < d1 || d3 < d0 || d3 < d1);
        float3 closestPointB = ClosestPointLineSegementPoint(spheresB.c1, spheresB.c0, closestPointA);

        closestPointA = ClosestPointLineSegementPoint(spheresA.c1, spheresA.c0, closestPointB);

        return(math.distancesq(closestPointA, closestPointB) < rada + radb);
    }
コード例 #26
0
        /// <remarks> Will throw exception if length < 1. </remarks>
        public static void ParabolaDirectrix(
            NativeSlice <float3x2> segments,
            float a, float b,
            float xmin, float xmax,
            float3 pos, quaternion rot
            )
        {
            const float c           = 0;
            float       directrix_y = c - ((b * b) + 1) * 4 * a;

            segments[0] = new float3x2 {
                c0 = pos + math.mul(rot, new float3 {
                    x = xmin, y = directrix_y
                }),
                c1 = pos + math.mul(rot, new float3 {
                    x = xmax, y = directrix_y
                })
            };
        }
コード例 #27
0
            void IJobParallelFor.Execute(int index)
            {
                float  t0  = (float)index / (float)NumSegments;
                float  t1  = (float)(index + 1) / (float)NumSegments;
                float2 amp = math.sin(Frequency * new float2 {
                    x = t0 * math.PI * 2f + Offset,
                    y = t1 * math.PI * 2f + Offset
                });
                float3 vec0 = math.transform(Transform, new float3 {
                    x = t0, y = amp.x
                });
                float3 vec1 = math.transform(Transform, new float3 {
                    x = t1, y = amp.y
                });

                Segments[index] = new float3x2 {
                    c0 = vec0, c1 = vec1
                };
            }
コード例 #28
0
            void IJob.Execute()
            {
                float3 position = new float3 {
                    x = LocalToWorld.c3.x, y = LocalToWorld.c3.y, z = LocalToWorld.c3.z
                };
                float3x3 rotation = new float3x3(LocalToWorld);
                float3   right    = math.mul(rotation, new float3 {
                    x = 1
                });
                float3 up = math.mul(rotation, new float3 {
                    y = 1
                });
                float3 forward = math.mul(rotation, new float3 {
                    z = 1
                });

                Buffer[0] = new float3x2(position, position + right);
                Buffer[1] = new float3x2(position, position + up);
                Buffer[2] = new float3x2(position, position + forward);
            }
コード例 #29
0
        /// <inheritdoc/> <remarks> Will throw exception if length < numSegments. </remarks>
        public static void Hyperbola(
            NativeSlice <float3x2> segments,
            float a, float b, float xrange,
            float3 pos, quaternion rot,
            int numSegments
            )
        {
            float  c      = math.sqrt(a * a + b * b);
            float2 vertex = new float2 {
                y = a
            };
            float3 focus = new float3 {
                y = c
            };

            float3 fmirror = new float3 {
                x = 1, y = -1f, z = 1
            };
            float xmin  = vertex.x - xrange;
            float xmax  = vertex.x + xrange;
            int   index = 0;

            for (int i = 0; i < numSegments; i++)
            {
                float x0 = math.lerp(xmin, xmax, (float)i / (float)numSegments);
                float x1 = math.lerp(xmin, xmax, (float)(i + 1) / (float)numSegments);

                float3 p0 = new float3 {
                    x = x0, y = (b * math.sqrt(a * a + x0 * x0)) / a
                };
                float3 p1 = new float3 {
                    x = x1, y = (b * math.sqrt(a * a + x1 * x1)) / a
                };
                float3 v0 = math.mul(rot, p0);
                float3 v1 = math.mul(rot, p1);
                segments[index++] = new float3x2 {
                    c0 = pos + v0, c1 = pos + v1
                };
            }
        }
コード例 #30
0
        /// <inheritdoc/> <remarks> Will throw exception if length < 4. </remarks>
        public static void Arrow(
            NativeSlice <float3x2> segments,
            float3 v1, float3 v2, float3 cameraPos
            )
        {
            float3 arrowLen = math.normalize(v1 - v2) * math.distance(v1, v2) * 0.06f;
            float3 camAxis  = math.normalize(v2 - cameraPos);
            float3 v3       = v2 + math.mul(quaternion.AxisAngle(camAxis, math.PI / 14f), arrowLen);
            float3 v4       = v2 + math.mul(quaternion.AxisAngle(camAxis, -math.PI / 14f), arrowLen);

            segments[0] = new float3x2 {
                c0 = v1, c1 = v2
            };
            segments[1] = new float3x2 {
                c0 = v2, c1 = v3
            };
            segments[2] = new float3x2 {
                c0 = v3, c1 = v4
            };
            segments[3] = new float3x2 {
                c0 = v4, c1 = v2
            };
        }