Быстрая сфера объединяет звездные данные

Я хочу создать приложение для наблюдения за звездами. И теперь я уже построил сферу и накрыл ее звездной картой (на основе небесных координат). ( https://svs.gsfc.nasa.gov/cgi-bin/details.cgi?aid=3895)

Теперь у меня есть файл JSON, в котором есть каталог звезд от YBS. (также на основе небесных координат). ( http://tdc-www.harvard.edu/catalogs/bsc5.html)

я хочу объединить данные со звездной картой, желая, чтобы карта отображала название созвездия всякий раз, когда мой узел камеры поворачивается к этому месту. но я не знаю, как объединить данные и сферу. так как сфера будет вращаться из-за широты и времени пользователя. Координаты звездных данных также должны измениться.

У кого-нибудь есть предложения?

1 ответ

Не уверен в вашей среде, но в вашем случае я бы:

  1. визуализировать текстурированную сферу (с глубокой картой)

    Сфера должна быть в центре вашей камеры и иметь большой радиус, охватывающий всю область обзора. Чтобы избежать появления в полярных регионах, вы можете использовать это:

  2. затем визуализировать BSC

    Начните с точек (очков). Однако, если вы хотите (не) увеличить и / или лучше визуализировать величину звезд, вам понадобятся возможности смешивания и рендеринга звезд в виде полупрозрачного диска, обращенного к камере (рекламным щитам) с радиусом и интенсивностью, зависящими от масштаба и величины.

    Я обычно использую эту текстуру для локальной звезды (ширина D=1/3, остальное - корона):

    местная звезда

    И это для звезд BSC (D= почти 100% ширины):

    далекая звезда

    alpha рассчитывается как интенсивность цвета alpha=r+g+b/3,

    Таким образом, визуальные и физические двоичные файлы будут смешиваться вместе, добавляя их визуальную величину, как в реальности. Это также позволит избежать мерцания при любом изменении вида из-за наложения между очень близкими звездами.

    Вот GIF-анимация увеличения (цвета размыты, отсюда зеленоватый шум), чтобы вы почувствовали, как это выглядит:

    дальняя звезда зум

[Edit1] простой полный пример VCL C++ OpenGL

Я использую глубокие карты по вашей ссылке. Они отображаются со сферическим искажением, поэтому сферическая триангуляция не имеет смысла (ничего не улучшится, поскольку исходные данные уже неверны). Это подразумевает использование стандартной сферической сетки с особенностями на полюсах. Файлы JPG непригодны из-за того, что артефакты сжатия с потерями испортили все (особенно вблизи полюсов). Я использую TIF и масштабирую все текстуры, чтобы 4096x2048 разрешающая способность. Меньшее разрешение мне не подходит.

После этого нужно просто смешать скайбокс с каждой текстурой. Результат таков:

обзор

Который показывает область Северного полюса, так что вы можете видеть, что искажения не так уж и плохи (если вы не увеличите изображение).

После этого вы можете добавить звезды, которых нет на глубокой карте. Но так как карта глубины уже включает BSC, я не вижу смысла добавлять ее снова (если только вы не хотите откалибровать ваш рендерер так, чтобы он был таким же, каким была создана карта глубины).

В соответствии с запросом здесь Полный пример на C++/GL. Он был написан на BDS2006, поэтому он основан на приложении VCL Form с одним таймером 20 мс. Вы можете игнорировать все содержимое VCL (единственное, что используется, это загрузчик растровых изображений, и я уверен, что вы уже получили его) и использовать только тот код события, который вам нужен.

//---------------------------------------------------------------------------
#include <vcl.h>
#include <Math.h>
#include <gl/gl.h>
#include <gl/glu.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
// key codes (Arrows + Space), pressed state
WORD key_left =37; bool _left =false;
WORD key_right=39; bool _right=false;
WORD key_up   =38; bool _up   =false;
WORD key_down =40; bool _down =false;
WORD key_reset=32; bool _reset=false;
//---------------------------------------------------------------------------
GLfloat rep[16],inv[16]; // camera matrix and its pseudo inverse
void pseudo_inverse(GLfloat *a,GLfloat *b)  // a = inverse(b)
    {
    // this works only for orthonormal matrices with origin (0,0,0) and no projections
    a[ 0]=b[ 0]; a[ 4]=b[ 1]; a[ 8]=b[ 2]; a[12]=b[ 3];
    a[ 1]=b[ 4]; a[ 5]=b[ 5]; a[ 9]=b[ 6]; a[13]=b[ 7];
    a[ 2]=b[ 8]; a[ 6]=b[ 9]; a[10]=b[10]; a[14]=b[11];
    a[ 3]=b[12]; a[ 7]=b[13]; a[11]=b[14]; a[15]=b[15];
    }
//---------------------------------------------------------------------------
const int nb=64;        // slices
const int na=nb<<1;     // points per equator
const int _skybox_textures=4;
class skybox
    {
public:
    bool _init;             // has been initiated ?
    GLfloat pos[na][nb][3]; // vertex
    GLfloat txr[na][nb][2]; // texcoord
    GLuint  txrid[_skybox_textures]; // texture ids
    skybox() { _init=false; }
    ~skybox() { if (_init) glDeleteTextures(_skybox_textures,txrid); }
    void init();        // call after OpenGL is already working !!!
    void draw();
    };
void skybox::init()
    {
    if (!_init) { _init=true; glGenTextures(_skybox_textures,txrid); }
    GLfloat x,y,z,a,b,da,db,r=99.9;
    GLfloat tx0,tdx,ty0,tdy;// just correction if CLAMP_TO_EDGE is not available
    int ia,ib;

    // a,b to texture coordinate system
    tx0=0.0;
    ty0=0.5;
    tdx=0.5/M_PI;
    tdy=1.0/M_PI;

    // load textures to GPU memory
    Graphics::TBitmap *bmp=new Graphics::TBitmap;   // new bmp
    #ifndef GL_CLAMP_TO_EDGE
    #define GL_CLAMP_TO_EDGE 0x812F
    #endif
    for (int i=0;i<_skybox_textures;i++)
        {
        Byte q;
        unsigned int *pp;
        int xs,ys,x,y,adr,*txr;
        union { unsigned int c32; Byte db[4]; } c;
        // load bmp from file
             if (i==0) bmp->LoadFromFile("skybox_grid.bmp");
        else if (i==1) bmp->LoadFromFile("skybox_sectors.bmp");
        else if (i==2) bmp->LoadFromFile("skybox_figures.bmp");
        else if (i==3) bmp->LoadFromFile("skybox_stars.bmp");
        else break;
        bmp->HandleType=bmDIB;      // allow direct access to pixels
        bmp->PixelFormat=pf32bit;   // set pixel to 32bit so int is the same size as pixel
        xs=bmp->Width;              // resolution should be power of 2
        ys=bmp->Height;
        txr=new int[xs*ys];         // create 1D txr[] array and store texture in it in GL manner
        for(adr=0,y=0;y<ys;y++)
            {
            pp=(unsigned int*)bmp->ScanLine[y];
            for(x=0;x<xs;x++,adr++)
                {
                // rgb2bgr and copy bmp -> txr[]
                c.c32=pp[x];
                q      =c.db[2];
                c.db[2]=c.db[0];
                c.db[0]=q;
                txr[adr]=c.c32;
                }
            }
        glEnable(GL_TEXTURE_2D);    // copy txr[] to GL
        glBindTexture(GL_TEXTURE_2D,txrid[i]);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0, GL_RGBA, GL_UNSIGNED_BYTE, txr);
        glDisable(GL_TEXTURE_2D);
        delete[] txr;               // release memory
        }
    delete bmp;
    // generate sphere mesh
    da=(2.0*M_PI)/GLfloat(na-1);
    db=     M_PI /GLfloat(nb-1);
    for (ib=0,b=-0.5*M_PI;ib<nb;ib++,b+=db)
    for (ia=0,a= 0.0     ;ia<na;ia++,a+=da)
        {
        x=cos(b)*cos(a);
        y=cos(b)*sin(a);
        z=sin(b);
        pos[ia][ib][0]=r*x;
        pos[ia][ib][1]=r*y;
        pos[ia][ib][2]=r*z;
        txr[ia][ib][0]=tx0+(a*tdx);
        txr[ia][ib][1]=ty0+(b*tdy);
        }
    }
void skybox::draw()
    {
    if (!_init) return;
    int i,ia,ib0,ib1;
    // color table
    GLfloat col[_skybox_textures][3]=
        {
        // R   G   B
        { 0.3,0.2,0.4 },    // Ra,Dec grid
        { 0.0,0.2,0.3 },    // sectors
        { 0.0,0.3,0.4 },    // figures
        { 1.0,1.0,1.0 },    // stars
        };
    // modlevie = inverse of camera matrix to allow local coordinate system rotations
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadMatrixf(inv);
    // set rendering pipeline
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
    // render mesh once per each texture layer (stars are last)
    for (i=0;i<_skybox_textures;i++)
        {
        glBindTexture(GL_TEXTURE_2D,txrid[i]);
        glColor3fv(col[i]);
        for (ib0=0,ib1=1;ib1<nb;ib0=ib1,ib1++)
            {
            glBegin(GL_QUAD_STRIP);
            for (ia=0;ia<na;ia++)
                {
                glTexCoord2fv(txr[ia][ib0]);
                glVertex3fv  (pos[ia][ib0]);
                glTexCoord2fv(txr[ia][ib1]);
                glVertex3fv  (pos[ia][ib1]);
                }
            glEnd();
            }
        }
    // restore states ...
    glEnable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
    }
//---------------------------------------------------------------------------
skybox sky;
//---------------------------------------------------------------------------
int TForm1::ogl_init()
    {
    if (ogl_inicialized) return 1;
    hdc = GetDC(Form1->Handle);             // get device context
    PIXELFORMATDESCRIPTOR pfd;
    ZeroMemory( &pfd, sizeof( pfd ) );      // set the pixel format for the DC
    pfd.nSize = sizeof( pfd );
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 24;
    pfd.iLayerType = PFD_MAIN_PLANE;
    SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
    hrc = wglCreateContext(hdc);            // create current rendering context
    if(hrc == NULL)
            {
            ShowMessage("Could not initialize OpenGL Rendering context !!!");
            ogl_inicialized=0;
            return 0;
            }
    if(wglMakeCurrent(hdc, hrc) == false)
            {
            ShowMessage("Could not make current OpenGL Rendering context !!!");
            wglDeleteContext(hrc);          // destroy rendering context
            ogl_inicialized=0;
            return 0;
            }
    ogl_resize();
    glEnable(GL_DEPTH_TEST);                // Zbuf
    glDisable(GL_CULL_FACE);                // vynechavaj odvratene steny
    glDisable(GL_TEXTURE_2D);               // pouzivaj textury, farbu pouzivaj z textury
    glDisable(GL_BLEND);                    // priehladnost
    glShadeModel(GL_SMOOTH);                // gourard shading
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);   // background color
    ogl_inicialized=1;

    return 1;
    }
//---------------------------------------------------------------------------
void TForm1::ogl_exit()
    {
    if (!ogl_inicialized) return;
    wglMakeCurrent(NULL, NULL);     // release current rendering context
    wglDeleteContext(hrc);          // destroy rendering context
    ogl_inicialized=0;
    }
//---------------------------------------------------------------------------
void TForm1::ogl_draw()
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    sky.draw();

    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------
void TForm1::ogl_resize()
    {
    xs=ClientWidth;
    ys=ClientHeight;
    if (xs<=0) xs = 1;                  // Prevent a divide by zero
    if (ys<=0) ys = 1;
    if (!ogl_inicialized) return;
    glViewport(0,0,xs,ys);              // Set Viewport to window dimensions
    glMatrixMode(GL_PROJECTION);        // operacie s projekcnou maticou
    glLoadIdentity();                   // jednotkova matica projekcie
    gluPerspective(60,float(xs)/float(ys),0.1,100.0); // matica=perspektiva,120 stupnov premieta z viewsize do 0.1
    glMatrixMode(GL_TEXTURE);           // operacie s texturovou maticou
    glLoadIdentity();                   // jednotkova matica textury
    glMatrixMode(GL_MODELVIEW);         // operacie s modelovou maticou
    glLoadIdentity();                   // jednotkova matica modelu (objektu)
    ogl_draw();
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    ogl_inicialized=0;
    hdc=NULL;
    hrc=NULL;
    ogl_init();
    sky.init();
    int i;  // unit matrices at start
    for (i=0;i<16;i++) rep[i]=0.0;
    for (i=0;i<16;i+=5) rep[i]=1.0;
    for (i=0;i<16;i++) inv[i]=rep[i];
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)   { ogl_exit(); }
void __fastcall TForm1::FormResize(TObject *Sender)    { ogl_resize(); }
void __fastcall TForm1::Splitter1Moved(TObject *Sender){ ogl_resize(); }
void __fastcall TForm1::FormPaint(TObject *Sender)     { ogl_draw(); }
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
    GLfloat da=5.0; // angular turn speed in [deg/timer_iteration]
    pseudo_inverse(inv,rep);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadMatrixf(rep);
    bool _redraw=false;
    if (_left ) { _redraw=true; glRotatef(+da,0.0,1.0,0.0); }
    if (_right) { _redraw=true; glRotatef(-da,0.0,1.0,0.0); }
    if (_up   ) { _redraw=true; glRotatef(+da,1.0,0.0,0.0); }
    if (_down ) { _redraw=true; glRotatef(-da,1.0,0.0,0.0); }
    if (_reset) { _redraw=true; glLoadIdentity(); }
    if (_redraw)
        {
        glGetFloatv(GL_MODELVIEW_MATRIX,rep);
        pseudo_inverse(inv,rep);
        }
    glPopMatrix();
    if (_redraw) ogl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
    {
    if (Key==key_left ) _left =false;
    if (Key==key_right) _right=false;
    if (Key==key_up   ) _up   =false;
    if (Key==key_down ) _down =false;
    if (Key==key_reset) _reset=false;
    Key=0;  // key is handled
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
    {
    // on key down event
    if (Key==key_left ) _left =true;
    if (Key==key_right) _right=true;
    if (Key==key_up   ) _up   =true;
    if (Key==key_down ) _down =true;
    if (Key==key_reset) _reset=true;
    Key=0;  // key is handled
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormActivate(TObject *Sender)
    {
    _left =false; // clear key flags after focus change
    _right=false; // just to avoid constantly "pressed" keys
    _up   =false; // after window focus swaping during key press
    _down =false; // many games are ignoring this and you need to
    _reset=false; // press&release the stuck key again to stop movement ...
    }
//---------------------------------------------------------------------------

Здесь скомпилирован демо и полный исходный код с включенными текстурами

Управление осуществляется с помощью стрелок на клавиатуре и пробела. Теперь нужно просто поиграть с цветами, смешать функции и т. Д. Пример использует только OpenGL 1.0 без расширения (кроме CLAMP_TO_EDGE).

Вы можете заменить многократный рендеринг на один проход с помощью MultiTexturing с соответствующими функциями комбинирования, но я не использую эту функцию в течение длительного времени (так как вместо этого переключаюсь на GLSL), поэтому я не уверен добавить код для этого.

Повеселись.

Другие вопросы по тегам