0

I was trying to map the 360 video pixel coordinate to sphere surface coordinate but I couldn't get right result... It just mapped to the wrong position I already know the points of the XY data for 360 video pixels.

how map 2d grid points (x,y) onto sphere as 3d points (x,y,z)

I checked this link and I copied method from this but what I'm getting is not mapped to the desired position.

How can I get radius from the pixels?

I am not sure if I'm passing right radius for imageRadius but I thought it will be circumference/PI to get radius and the video ratio is 4096x2048. I also tried to pass the number 1 because UV is 0-1 but it was not right...

Is Method wrong?

Maybe the method is wrong. I passed random numbers into the imageRadius but couldn't get the right position... If I make X to negative number the seems like little bit closer to result....?

Current Result

https://youtu.be/t0I7Hlb-tbk It mapped to up right position with the method that I found online...

Project File

https://drive.google.com/a/swordfish-sf.com/file/d/0B45RYzVs0t0_VVdaaHdmNHRWTk0/view?usp=sharing If somebody can check the Unity project file that will be great...

Current Code

public class mapScript : MonoBehaviour {

public int input = 4098;
float imageRadius = 4098f / Mathf.PI; //2098? 3072? 4098?
float radius;
public GameObject testSphere;

void Start () {
    radius = this.transform.localScale.x;
}


void Update () {
    imageRadius = input / Mathf.PI;
    int currentFrame = (int)this.GetComponent<VideoPlayer>().frame;

    testSphere.transform.position = MercatorProjection(mapVals[currentFrame,0],mapVals[currentFrame,1]);
}

Vector3 MercatorProjection(float xVal, float yVal)
{
    float lon = (xVal / imageRadius);
    float lat = (2 * Mathf.Atan(Mathf.Exp(yVal / imageRadius)) - Mathf.PI / 2);


    float calcX = radius * Mathf.Cos(lat) * Mathf.Cos(lon);
    float calcY = radius * Mathf.Cos(lat) * Mathf.Sin(lon);
    float calcZ = radius * Mathf.Sin(lat);

    Vector3 result = new Vector3(calcX,calcY,calcZ);
    Debug.Log(result);
    return result;
}



float[,] mapVals = new float[,] {
{1969.21f, 928.625f},
{1969.6f, 928.533f},
{1968.92f, 928.825f},
{1968.68f, 929f},
{1968.47f, 929.067f},
{1968.41f, 929.025f},
{1968.48f, 928.992f},
....
};
}

Thank you.

Tats
  • 69
  • 1
  • 2
  • 10

1 Answers1

1

As a side note, the radius is arbitrary. The pixel coordinates only map to the directional coordinates (polar [θ] and azimuthal [ϕ] angles).


We can do this by mapping each pixel to equal θ and ϕ intervals. The diagram below illustrates a low-resolution setup:

enter image description here

Let us adopt the convention that, for an image of with W, ϕ = 0 corresponds to:

  • Even W: half way between X = floor((W - 1) / 2) and X = ceil((W - 1) / 2)
  • Odd W: in the middle of the pixel column at X = floor((W - 1) / 2)

The pixel row at Y maps to the equilatitudinal line at θ = (Y + 0.5) / H * π.

To map all pixels in their entirety, let X start at -0.5 instead of 0, and end at W - 0.5; likewise for Y. Since integer coordinates map to the centers of the pixel regions shown above, this allows the whole area of any particular pixel to be addressed. You may need this later on if you plan on doing multi-sampling filtering for e.g. anti-aliasing.

Code:

Vector3 Mercator(float x, float y, int w, int h)
{
   // outside of valid pixel region
   if (x < -0.5f || x >= w - 0.5f || y < -0.5f || y >= h - 0.5f)
      return new Vector3();

   float theta = (y + 0.5f) / h * Math.PI;
   float phi = ((x + 0.5f) / w - 0.5f) * 2.0 * Math.PI;

   float c_t = Math.Cos(theta);
   return new Vector3(c_t * Math.Cos(phi), c_t * Math.Sin(phi), Math.Sin(theta));
}

... and multiply the resulting direction vector by any "radius" you like, since it has (basically) nothing to do with the mapping anyway.

meowgoesthedog
  • 14,670
  • 4
  • 27
  • 40