ricky
ricky

Reputation: 2108

How to draw latitude/longitude lines on the surface of a Sphere in Unity 3D?

I'm a beginner of Unity 3D. And I'm trying to create a globe with Unity 3D as shown below. I created a Sphere game object on a scene and set the radius as 640. Then, I want to draw latitude/longitude lines (every 10 degree) on the surface of this Sphere in C# script.

enter image description here

I tried to draw each lat/long line by using LineRender, but did not get it work. My code:

public class EarthController : MonoBehaviour {
private float _radius = 0;
// Use this for initialization
void Start () {
    _radius = gameObject.transform.localScale.x;
    DrawLatLongLines();
}

// Update is called once per frame
void Update()
{
}

private void DrawLatLongLines()
{
    float thetaStep = 0.0001F;
    int size = (int)((2.0 * Mathf.PI) / thetaStep); 

    // draw lat lines
    for (int latDeg = 0; latDeg < 90; latDeg += 10)
    {
        // throw error here. 
        // seems I cannot add more than one component per type
        LineRenderer latLineNorth = gameObject.AddComponent<LineRenderer>(); 
        latLineNorth.startColor = new Color(255, 0, 0);
        latLineNorth.endColor = latLineNorth.startColor;
        latLineNorth.startWidth = 0.2F;
        latLineNorth.endWidth = 0.2F;
        latLineNorth.positionCount = size;

        LineRenderer latLineSouth = Object.Instantiate<LineRenderer>(latLineNorth);

        float theta = 0;
        var r = _radius * Mathf.Cos(Mathf.Deg2Rad * latDeg);
        var z = _radius * Mathf.Sin(Mathf.Deg2Rad * latDeg);
        for (int i = 0; i < size; i++)
        {
            var x = r * Mathf.Sin(theta);
            var y = r * Mathf.Cos(theta);

            Vector3 pos = new Vector3(x, y, z);
            latLineNorth.SetPosition(i, pos);

            pos.z = -z;
            latLineSouth.SetPosition(i, pos);

            theta += thetaStep;
        }
    }
}
}

What's the correct way to do this?

I don't want to write custom shader (if possible) since I know nothing about it.

Upvotes: 3

Views: 4448

Answers (1)

Basile Perrenoud
Basile Perrenoud

Reputation: 4112

The usual way to customize the way 3d objects look is to use shaders.

In your case, you would need a wireframe shader, and if you want control on the number of lines, then you might have to write it yourself.

Another solution is to use a texture. In unity, you will have many default materials that will apply a texture on your object. You can apply an image texture that contains your lines.

If you don't want a texture and really just the lines, you could use the line renderer. LineRenderer doesn't need a 3D object to work. You just give it a number of points and it is going to link them with a line. Here is how I would do it:

  • Create an object with a line renderer and enter points that create a circle (You can do it dynamically in c# or manually in the editor on the line renderer).
  • Store this as a prefab (optional) and duplicate it in your scene (copy paste. Each copy draws a new line
  • Just be modifying the rotation, scale and position of your lines you can recreate a sphere

If your question is "What is the equation of a circle so I can find the proper x and y coord?" here is a short idea to compute x and y coord

for(int i =0; i< nbPointsOnTheCircle; ++i)
{
    var x = Mathf.Cos(nbPointsOnTheCircle / 360);
    var y = Mathf.Sin(nbPointsOnTheCircle / 360);
}

If your question is "How to assign points on the line renderer dynamicaly with Unity?" here is a short example:

public class Circle : MonoBehavior
{
    private void Start()
    {
        Vector3[] circlePoints = computePoints(); // a function that compute points of a circle
        var lineRenderer = GetComponent<LineRenderer>();
        linerenderer.Positions = circlePoints;
    }
}

EDIT

You can only have one per object. This is why the example above only draws one circle. You already have a earth controller, but this controller can't add many LineRenderes to itself. Instead, the idea would be that the earth object has a script that does the something like following:

private void Start()
{
    for(int i=0; i<nbLines;++i) 
    {
        GameObject go = new GameObject();
        go.AddComponent<LineRenderer>();
        go.AddCOmponent<Circle>();
        go.transform.SetParent = transform;
        go.name = "Circle" + i;
    }
}

Then you will see several objects created in you scene, each having exactly one LineRenderer and one Circle component

From there you should be able to do what you want (for instance, pass parameters to the Circle so each Circle is a bit different)

Upvotes: 2

Related Questions