[PYTHON] Construisez un ciel étoilé sur Unity à partir d'une base de données stellaire (publié)

Dessin d'achèvement

image.png

À partir de la gauche

Celui joué comme écran de jeu est le suivant. </ s> Publié en tant qu'application WebGL.

https://hibit-at.github.io/StarSphere/

Base de données stellaire

Il semble qu'il existe une base de données stellaire dans le monde, donc si vous organisez cela comme une sphère telle qu'elle est, vous pouvez créer un planétarium réaliste? J'y ai pensé et l'ai essayé. Le code du script ci-dessous.

using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class Reader : MonoBehaviour
{
    TextAsset csvFile;
    List<string[]> csvDatas = new List<string[]>();
    public Material[] _material;//Ce matériel nécessite une préparation préalable

    //Liste pour colorier des constellations spécifiques
    List<string> Spring = new List<string> { "Arcturus" , "Spica" , "Denebola" };
    List<string> Summer = new List<string> { "Deneb", "Altair", "Vega" };
    List<string> Autumn = new List<string> { "Markab", "Sheat", "Algenib" , "Alpheratz" };
    List<string> Winter = new List<string> { "Capella", "Aldebaran", "Rigel", "Pollux" ,"Procyon" , "Sirius" };

    int Color(string target) //Une fonction qui renvoie un nombre pour colorer la constellation
    {
        foreach (string c in Spring) if (target == c) return 1;
        foreach (string c in Summer) if (target == c) return 2;
        foreach (string c in Autumn) if (target == c) return 3;
        foreach (string c in Winter) if (target == c) return 4;
        return 0;
    }

    void Start()
    {
        csvFile = Resources.Load("mdata") as TextAsset; //Renvoyez vos propres données ici
        StringReader reader = new StringReader(csvFile.text);
        while (reader.Peek() != -1)
        {
            string line = reader.ReadLine();
            csvDatas.Add(line.Split(','));
        }

        foreach (string[] c in csvDatas)
        {
            int lon1 = int.Parse(c[3]);
            int lon2 = int.Parse(c[4]);
            float theta = lon1 * 15 + lon2 / 4;
            theta *= 2.0f * Mathf.PI / 360;
            int lat1 = int.Parse(c[7]);
            int lat2 = int.Parse(c[8]);
            float phi = lat1 + lat2 / 60;
            if (c[6] == "0") phi = -phi;
            phi *= 2.0f * Mathf.PI / 360;
            GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            sphere.transform.position = new Vector3(10 * Mathf.Cos(theta) * Mathf.Cos(phi),
                                                    10 * Mathf.Sin(phi),
                                                    10 * Mathf.Sin(theta) * Mathf.Cos(phi));
            float tokyu = float.Parse(c[10]);
            tokyu = 0.6f - tokyu / 10;
            if (tokyu < 0) tokyu = 0;
            sphere.transform.localScale = new Vector3(tokyu, tokyu, tokyu);
            sphere.GetComponent<Renderer>().material = _material[Color(c[2])];
        }
    }
}

Si vous attachez ceci à un objet de jeu approprié, environ 3000 étoiles (sphères) seront dessinées dans la scène au début du jeu. Si vous essayez réellement de le faire, un prétraitement est nécessaire, comme décrit plus loin.

Traitement préalable des données

Il utilise les données de la base de données mentionnée ci-dessus dans hip_lite_major.csv (environ 3000 lignes), mais il ne contient pas les noms des étoiles. Pour toutes les étoiles [Hipparcos Star Chart](https://ja.wikipedia.org/wiki/%E3%83%92%E3%83%83%E3%83%91%E3%83%AB%E3% Il semble que les nombres (numéros HIP) soient attribués par le tableau 82% B3% E3% 82% B9% E6% 98% 9F% E8% A1% A8) (Wow!), Mais bien sûr, le nom y est donné. Il n'y a que quelques étoiles importantes qui peuvent être attachées. Les données sont organisées séparément dans hip_proper_name.csv, mais elles doivent être ce que l'on appelle une combinaison relationnelle. Heureusement, le numéro HIP est la clé primaire, le processus est donc rapide.

Le pré-traitement ici se fait rapidement avec python et pandas.

import pandas as pd
data = pd.read_csv('hip_proper_name.csv',header=None)
detail = pd.read_csv('hip_lite_major.csv',header=None)
mdata = pd.merge(detail,data,on=0,how="left")
mdata.to_csv('mdata.csv',header=None)

Cela créera un mdata.csv qui est une fusion des deux, alors mettez-le dans votre projet Unity.

En outre, les paramètres de matériau sont définis manuellement du côté Unity. Si vous faites de votre mieux, vous pouvez l'écrire dans un script, mais vous pouvez vraiment faire des compromis ici.

image.png

Créez un matériau de couleur de constellation et placez-le dans l'emplacement Matériau GameObject pour attacher le script.

Explication du code source

    //Liste pour colorier des constellations spécifiques
    List<string> Spring = new List<string> { "Arcturus" , "Spica" , "Denebola" };
    List<string> Summer = new List<string> { "Deneb", "Altair", "Vega" };
    List<string> Autumn = new List<string> { "Markab", "Sheat", "Algenib" , "Alpheratz" };
    List<string> Winter = new List<string> { "Capella", "Aldebaran", "Rigel", "Pollux" ,"Procyon" , "Sirius" };

Le nom de la constellation (ce n'est pas une constellation mais quelque chose qui chevauche plusieurs étoiles, mais je ne trouve pas d'autre bon nom, alors je l'appellerai une constellation) ne figure pas sur le csv que j'ai mentionné plus tôt, donc je dois le préparer moi-même. Il y a. Faites une liste de chaque constellation.

Pour savoir comment lire le fichier csv, je me suis référé entièrement à https://note.com/macgyverthink/n/n83943f3bad60. Merci beaucoup.

A partir de chaque ligne de csv, nous calculerons l'angle et l'échelle.

L'angle est calculé à partir de la longitude rouge (heures, minutes, secondes) et de la latitude rouge (degrés, minutes, secondes) dans la base de données. C'est un peu déroutant car il s'agit de degrés, minutes et secondes, mais l'angle de latitude rouge $ \ phi $ est

\ phi = degré + \ frac {minutes} {60} + \ frac {secondes} {3600}

Vous pouvez découvrir que c'est le cas. En ce qui concerne le sutra rouge $ \ theta $, c'est ** heures **, minutes, secondes, qui ne sortent pas même si je l'ai vérifié, mais le fait est que 360 degrés est divisé en 24, donc ** Ce sera 15 degrés ** par heure. Vous pouvez donc voir que vous pouvez ajouter 15 $ à la formule ci-dessus.

\ theta = heure * 15 + \ frac {minutes} {4} + \ frac {secondes} {240}

Vous pouvez calculer avec ce qui précède. Notez que «Rotate» d'Unity est en unités radianes et que le système de coordonnées est gaucher.

            theta *= 2.0f * Mathf.PI / 360;
(Omis)
            phi *= 2.0f * Mathf.PI / 360;
(Omis)
            sphere.transform.position = new Vector3(10 * Mathf.Cos(theta) * Mathf.Cos(phi),
                                                    10 * Mathf.Sin(phi),
                                                    10 * Mathf.Sin(theta) * Mathf.Cos(phi));

Vous pouvez placer chaque étoile aux bonnes coordonnées avec. De plus, la différence de luminosité pour chaque grade est indiquée par la taille de la sphère.

            float tokyu = float.Parse(c[10]);
            tokyu = 0.6f - tokyu / 10;
            if (tokyu < 0) tokyu = 0;
            sphere.transform.localScale = new Vector3(tokyu, tokyu, tokyu);

Cela vous donnera une impression de ciel étoilé.

Chose que tu veux faire

Puisqu'il peut être traité comme des données sur Unity, un planétarium interactif peut être réalisé si un mécanisme est créé qui permet aux étoiles affichées d'être manipulées et aux lignes de constellation d'émerger. Si vous le construisez avec Quest, il semble que vous puissiez faire quelque chose comme un planétarium autonome et facile (et déçu par le shobo du ciel étoilé à chaque fois que vous retirez le casque) même à l'extérieur. J'aimerais l'essayer si j'ai le temps et l'énergie.

Ajouté (publié)

Après cela, j'ai demandé à un ami qui est familier avec l'observation astronomique de le voir, j'ai ajusté la taille et la couleur et l'ai publié en tant qu'application WebGL. La dernière version du code.

using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class Reader : MonoBehaviour
{
    TextAsset csvFile;
    List<string[]> csvDatas = new List<string[]>();
    public Material[] _material;

    List<string> Spring = new List<string> { "Arcturus" , "Spica" , "Denebola" };
    List<string> Summer = new List<string> { "Deneb", "Altair", "Vega" };
    List<string> Autumn = new List<string> { "Markab", "Sheat", "Algenib" , "Alpheratz" };
    List<string> Winter = new List<string> { "Capella", "Aldebaran", "Rigel", "Pollux" ,"Procyon" , "Sirius" };

    int Colorization(string target)
    {
        foreach (string c in Spring) if (target == c) return 1;
        foreach (string c in Summer) if (target == c) return 2;
        foreach (string c in Autumn) if (target == c) return 3;
        foreach (string c in Winter) if (target == c) return 4;
        return 0;
    }

    Color Spectrum(string s)
    {
        if(s == "")
        {
            return new Color(.5f, .5f, .5f, 1);
        }
        char c = s[0];
        if(c == 'O')
        {
            return new Color(.3f, .3f, .8f,1);
        }
        else if (c == 'B')
        {
            return new Color(.3f, .3f, .8f, 1);
        }
        else if (c == 'A')
        {
            return new Color(.5f, .5f, 1, 1);
        }
        else if (c == 'F')
        {
            return new Color(1, 1, 1, 1);
        }
        else if (c == 'G')
        {
            return new Color(.8f, .8f, .4f, 1);
        }
        else if (c == 'K')
        {
            return new Color(.8f, .4f, 0, 1);
        }
        else if(c == 'M')
        {
            return new Color(.4f, 0, 0, 0);
        }
        else
        {
            return new Color(.5f, .5f, .5f, 1);
        }
    }
    
    void Start()
    {
        csvFile = Resources.Load("mdata") as TextAsset;
        StringReader reader = new StringReader(csvFile.text);
        while (reader.Peek() != -1)
        {
            string line = reader.ReadLine();
            csvDatas.Add(line.Split(','));
        }

        foreach (string[] c in csvDatas)
        {
            int lon1 = int.Parse(c[3]);
            int lon2 = int.Parse(c[4]);
            float theta = lon1 * 15 + lon2 / 4;
            theta *= 2.0f * Mathf.PI / 360;
            int lat1 = int.Parse(c[7]);
            int lat2 = int.Parse(c[8]);
            float phi = lat1 + lat2 / 60;
            if (c[6] == "0") phi = -phi;
            phi *= 2.0f * Mathf.PI / 360;
            GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            sphere.transform.position = new Vector3(10 * Mathf.Cos(theta) * Mathf.Cos(phi),
                                                    10 * Mathf.Sin(phi),
                                                    10 * Mathf.Sin(theta) * Mathf.Cos(phi));
            float tokyu = float.Parse(c[10]);
            tokyu = 0.3f - tokyu / 20;
            if (tokyu < 0) tokyu = 0;
            sphere.transform.localScale = new Vector3(tokyu, tokyu, tokyu);
            MeshRenderer r = sphere.GetComponent<MeshRenderer>();
            r.material = _material[0];
            r.material.EnableKeyword("_EMISSION");
            Color StarColor = Spectrum(c[11]) * tokyu / 0.3f;
            if (float.Parse(c[10]) <= 1.5f)
            {
                r.material.SetColor("_EmissionColor", StarColor * .3f);
            }
            
            //sphere.GetComponent<Renderer>().material = _material[Colorization(c[2])];
        }
    }
}

La couleur de l'étoile est [Classification du spectre](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%9A%E3%82%AF%E3%83%88%E3%83% Cela correspond à AB% E5% 88% 86% E9% A1% 9E). Comme il est classé par des lettres telles que O et K, il est traité avec l'instruction if. La couleur est ajustée en la réglant sur la couleur d'émission du matériau avec r.material.SetColor (" _EmissionColor ", StarColor * .3f);.

Le référentiel GitHub sera ici.

Ce que je veux faire 2

  • Application VR --Affichage de la ligne de constellation

Recommended Posts

Construisez un ciel étoilé sur Unity à partir d'une base de données stellaire (publié)
Créer un environnement python3 sur CentOS7
Créez un environnement d'apprentissage pour le «Deep learning from scratch» avec Cloud9 (jupyter miniconda python3)
J'ai fait une webAPI! Construire un environnement à partir de Django Rest Framework 1 avec EC2
Construire un serveur de cache Pypi sur QNAP
Construire un environnement python sur MacOS (Catallina)
Construisez un serveur WebDAV simple sur Linux
Faire de Unity Accelerator un service sous Linux
Construire un serveur Samba sur Arch Linux
Configurons un serveur WEB avec Chromebook
Créer un environnement Python + OpenCV sur Cloud9