0
\$\begingroup\$

There is some unit vector, which is a coordinate in a spherical space. It is necessary to obtain from it 4 vectors diverted in different directions (right, left, forward, backward) by a certain number of degrees. For these actions I use the following code:

Vector3 center = point;
Vector3 left = Quaternion.Euler(-30, 0, 0) * center;
Vector3 right = Quaternion.Euler(30, 0, 0) * center;
Vector3 back = Quaternion.Euler(0, 0, -30) * center;
Vector3 front = Quaternion.Euler(0, 0, 30) * center;

The problem is that this works when point is equal or close to Vector3.up. When deviating from the vertical position, the lateral vectors begin to "stick together".

Here is a visualization of what I need:

Visualization of the question

Test code is attached:

using System.Collections;
using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject centerGO;
    public GameObject leftGO;
    public GameObject rightGO;
    public GameObject backGO;
    public GameObject frontGO;

    ArrayList list = new ArrayList();

    void Start()
    {
        SetCenterPoint(Vector3.up);
    }

    void Update()
    {
        DrawDebugRays();

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit))
        {
            SetCenterPoint(hit.point);
        }
    }

    void SetCenterPoint(Vector3 point)
    {
        Vector3 center = point;
        Vector3 left = Quaternion.Euler(-30, 0, 0) * center;
        Vector3 right = Quaternion.Euler(30, 0, 0) * center;
        Vector3 back = Quaternion.Euler(0, 0, -30) * center;
        Vector3 front = Quaternion.Euler(0, 0, 30) * center;

        centerGO.transform.position = center;
        leftGO.transform.position = left;
        rightGO.transform.position = right;
        backGO.transform.position = back;
        frontGO.transform.position = front;

        list.Clear();
        list.Add(center);
        list.Add(left);
        list.Add(right);
        list.Add(front);
        list.Add(back);
    }

    void DrawDebugRays()
    {
        for (int i = 0; i < list.Count; i++)
        {
            Color color = Color.red;
            switch (i)
            {
                case 0:
                    color = Color.green;
                    break;
                case 1:
                case 2:
                    color = Color.blue;
                    break;
            }
            Debug.DrawRay(Vector3.zero, (Vector3)list[i], color);
        }
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ Hello and welcome to gamedev.se! You'll notice that I removed the link to your Google drive. This is because links like these are transient and are subject to link rot: you'll change your project in the future, making the link irrelevant. \$\endgroup\$
    – Vaillancourt
    Commented Mar 12, 2018 at 0:42
  • \$\begingroup\$ Because of the hairy ball theorem, there's no way to assign these points in a way that will be globally consistent and smooth between adjacent input vectors all around the sphere (we'll inevitably have a singularity somewhere, where two nearby inputs get significantly different outputs). Is that acceptable for your use case? If not, we can sacrifice global consistency and use some memory of previous history to pick a locally-smooth option, where the output for a given input depends on the route we took to get to that input. \$\endgroup\$
    – DMGregory
    Commented Mar 12, 2018 at 3:54
  • \$\begingroup\$ @DMGregory, For my case, the following conditions are important: the plane BackFront ┴ LeftRight, <BCL = <BCR = <FCR = <FCL = 90*, and the distance from any point to the center should be the same \$\endgroup\$
    – Ziens
    Commented Mar 12, 2018 at 10:52
  • \$\begingroup\$ That's doable, it's just a matter of if it's OK for, say, the whole quintet to rotate 180° between adjacent inputs. \$\endgroup\$
    – DMGregory
    Commented Mar 12, 2018 at 10:55
  • \$\begingroup\$ @DMGregory, yes, it's quite \$\endgroup\$
    – Ziens
    Commented Mar 12, 2018 at 10:56

1 Answer 1

2
\$\begingroup\$

Pick a local coordinate system that puts your center direction along the local z+ axis, then rotate the other 4 relative to those coordinates:

Quaternion localSpace = Quaternion.LookRotation(centerDirection);

Vector3 backDirection = localSpace * Quaternion.Euler(-30, 0, 0) * Vector3.forward;
Vector3 frontDirection = localSpace * Quaternion.Euler(30, 0, 0) * Vector3.forward;
Vector3 rightDirection = localSpace * Quaternion.Euler(0, -30, 0) * Vector3.forward;
Vector3 leftDirection = localSpace * Quaternion.Euler(0, 30, 0) * Vector3.forward;
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .