Войти
ПрограммированиеФорумГрафика

Граница дня и ночи на плоской карте Земли

Страницы: 1 2 3 Следующая »
#0
10:37, 22 мар. 2020

Всем доброго времени суток! Есть плоская масштабируемая карта Земли, которая собирается из квадратных кусочков (тайлов), подгружаемых при изменении масштаба. Необходимо затенить на полученном изображении область где сейчас ночь. Например так:
Изображение

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

В каждом цикле отрисовки  посчитал направление Солнечных лучей (Ra, Dec это широта и долгота подсолнечной точки):

            // Положение Солнца (направление)
            float SunPos[] = { cos(Dec)*sin(Ra), sin(Dec), cos(Dec)*cos(Ra), 0.0f };
            // Фоновое освещение
            float fAmbientShadow[] = { 0.5f, 0.5f, 0.5f, 1.0f };

            // Начальная позиция источника света и интенсивность тёмной части.
            glLightfv(GL_LIGHT0, GL_POSITION, SunPos);
            glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fAmbientShadow);

            // Включаем источник света.
            glEnable(GL_LIGHTING);
            glEnable(GL_LIGHT0);

затем отдал ранее посчитанные массивы вершин , номалей и текстурных координат. (s - это число кусочков на которые разбит фрагмент текстуры, каждому кусочку сооответствует 4 нормали):

    glEnable(GL_TEXTURE_2D);
    glColor4d(1.0, 1.0, 1.0, 0.0);

    glBindTexture(GL_TEXTURE_2D, 0);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    for (int i = 0; i < textureMap.size(); ++i)
    {
        glBindTexture(GL_TEXTURE_2D, textureMap[i]);
        glVertexPointer(3, GL_DOUBLE, 0, coord.data()+12*s*i);
        glNormalPointer(GL_DOUBLE, 0, normal.data()+12*s*i);
        glTexCoordPointer(2, GL_DOUBLE, 0, texture.data()+8*s*i);
        glDrawArrays(GL_QUADS, 0, 4*s);
    }
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glDisable(GL_TEXTURE_2D);

// Затем выключил освещение
        glDisable(GL_LIGHTING);
        glDisable(GL_LIGHT0);

в итоге вся текстура освещена равномерно также как и без освещения, т.е. массивы нормалей переданные в opengl не оказали никакого влияния на итоговое изображение. Что я делаю не так?


#1
11:28, 22 мар. 2020

Я представляю себе это так: форма затемненной области будет меняться в течении года. поэтому саму текстуру затемненной области нужно будет пересчитывать

#2
11:53, 22 мар. 2020

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

Кривую (по науке линию терминатора) посчитать можно но что это даст без шейдеров?

С освещением не понятно почему не получается... Вроде все по инструкции делаю. Направление источника есть, нормали есть. Или он вершины тоже как-то учитывает (они на плоскости лежат)? может в инициализацию нужно что то добавить?

#3
12:01, 22 мар. 2020
            //! Массивы привязки текстурных координат к координатам карты
            for(GLdouble a_m = 0.0; a_m < l_s; a_m += l_m)
            {
                for(GLdouble a_n = 0.0; a_n < l_s; a_n += l_m)
                {
                    GLdouble lat, lon;

                    // Верхняя левая точка
                    Map2DToGeo(a_x + a_m, a_y - a_n, &lat, &lon);
                    coordVertexMap.push_back( a_x + a_m );
                    coordVertexMap.push_back( a_y - a_n );
                    coordVertexMap.push_back( 0.0 );
                    normalVertexMap.push_back( cos(lat)*sin(lon) );
                    normalVertexMap.push_back( sin(lat) );
                    normalVertexMap.push_back( cos(lat)*cos(lon) );
                    textureVertexMap.push_back( a_m / l_s );
                    textureVertexMap.push_back( 1.0 - a_n / l_s );

                    // Нижняя левая точка
                    Map2DToGeo(a_x + a_m, a_y - a_n - l_m, &lat, &lon);
                    coordVertexMap.push_back( a_x + a_m );
                    coordVertexMap.push_back( a_y - a_n - l_m );
                    coordVertexMap.push_back( 0.0 );
                    normalVertexMap.push_back( cos(lat)*sin(lon) );
                    normalVertexMap.push_back( sin(lat) );
                    normalVertexMap.push_back( cos(lat)*cos(lon) );
                    textureVertexMap.push_back( a_m / l_s );
                    textureVertexMap.push_back( 1.0 - (a_n + l_m) / l_s );

                    // Нижняя правая точка
                    Map2DToGeo(a_x + a_m + l_m, a_y - a_n - l_m, &lat, &lon);
                    coordVertexMap.push_back( a_x + a_m + l_m );
                    coordVertexMap.push_back( a_y - a_n - l_m );
                    coordVertexMap.push_back( 0.0 );
                    normalVertexMap.push_back( cos(lat)*sin(lon) );
                    normalVertexMap.push_back( sin(lat) );
                    normalVertexMap.push_back( cos(lat)*cos(lon) );
                    textureVertexMap.push_back( (a_m + l_m) / l_s );
                    textureVertexMap.push_back( 1.0 - (a_n + l_m) / l_s );

                    // Верхняя правая точка
                    Map2DToGeo(a_x + a_m + l_m, a_y - a_n, &lat, &lon);
                    coordVertexMap.push_back( a_x + a_m + l_m );
                    coordVertexMap.push_back( a_y - a_n );
                    coordVertexMap.push_back( 0.0 );
                    normalVertexMap.push_back( cos(lat)*sin(lon) );
                    normalVertexMap.push_back( sin(lat) );
                    normalVertexMap.push_back( cos(lat)*cos(lon) );
                    textureVertexMap.push_back( (a_m + l_m) / l_s );
                    textureVertexMap.push_back( 1.0 - a_n / l_s );
                }
            }
#ifdef  __cplusplus
extern "C"
{
#endif
// Определение точки на текстуре по геодезическим координатам
void GeoToMap2D(double lat, double lon, double *x, double *y)
{
    *x = lon / M_PI;
    *y = log(tan(M_PI / 4.0 + lat / 2.0)) / M_PI;
}
// Определение геодезических координат по точке текстуры
void Map2DToGeo(double x, double y, double *lat, double *lon)
{
    *lon = x * M_PI;
    *lat = 2.0 * atan(exp(y * M_PI)) - M_PI / 2.0;
}
#ifdef  __cplusplus
}
#endif
#4
12:14, 22 мар. 2020

urii
> кроме того код должен выполняться на очень старом железе, поэтому думаю
> обойтись без шейдеров.
Сейчас железо бес шейдеров ты разве что в музее найдёшь.

> старое железо в лучшем случае поддерживает OpenGL 2.0
Это уже хорошо.
На OpenGL 2.0 можно сделать игру на уровне Half-Life 2 или даже RAGE. Рисование карты с затенением всяко можно сделать.

#5
12:20, 22 мар. 2020

А на картинке вообще нет тени:
https://ibb.co/Ntvq9QM

#6
12:38, 22 мар. 2020

Включен ли все режимы shademodel там и т.д.

метод initializeGL()

 

    qglClearColor(Qt::black);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_FLAT);
    glEnable(GL_CULL_FACE);

а ты проверял что у тебя в normalVertexMap вообще, есть хоть что нибудь

qDebug()<<"--------------------";
for( int i=0; i<normalVertexMap.size(); i+=3)
{
    qDebug()<<normalVertexMap[i]<<normalVertexMap[i+1]<<normalVertexMap[i+2];
}
-------------------- 
-0.187873 0.982193 1.15039e-17 
-0.206853 0.978372 1.26661e-17 
-0.205857 0.978372 0.0202752 
-0.186968 0.982193 0.0184147 
-0.206853 0.978372 1.26661e-17 
-0.227657 0.973741 1.394e-17 
-0.226561 0.973741 0.0223143 
-0.205857 0.978372 0.0202752 
-0.227657 0.973741 1.394e-17 
-0.250428 0.968135 1.53343e-17 
-0.249222 0.968135 0.0245462 
-0.226561 0.973741 0.0223143 
-0.250428 0.968135 1.53343e-17 
-0.275309 0.961356 1.68578e-17 
-0.273984 0.961356 0.026985 
-0.249222 0.968135 0.0245462 
-0.275309 0.961356 1.68578e-17 
-0.302441 0.953168 1.85192e-17 
-0.300985 0.953168 0.0296444 
-0.273984 0.961356 0.026985 
-0.302441 0.953168 1.85192e-17 
-0.331953 0.943296 2.03263e-17 
-0.330355 0.943296 0.0325371 
-0.300985 0.953168 0.0296444 
-0.331953 0.943296 2.03263e-17 
-0.363958 0.931416 2.2286e-17 
-0.362205 0.931416 0.0356741 
-0.330355 0.943296 0.0325371 
-0.363958 0.931416 2.2286e-17 
-0.398537 0.917152 2.44033e-17 
-0.396618 0.917152 0.0390634 
-0.362205 0.931416 0.0356741 
-0.186968 0.982193 0.0184147 
-0.205857 0.978372 0.0202752 
-0.202879 0.978372 0.0403551 
-0.184263 0.982193 0.0366522 
-0.205857 0.978372 0.0202752 
-0.226561 0.973741 0.0223143 
-0.223283 0.973741 0.0444137 
-0.202879 0.978372 0.0403551 
-0.226561 0.973741 0.0223143 
-0.249222 0.968135 0.0245462 
-0.245616 0.968135 0.0488561 
-0.223283 0.973741 0.0444137 
-0.249222 0.968135 0.0245462 
-0.273984 0.961356 0.026985 
-0.270019 0.961356 0.0537102 
-0.245616 0.968135 0.0488561 
-0.273984 0.961356 0.026985 
-0.300985 0.953168 0.0296444 
-0.29663 0.953168 0.0590034 
-0.270019 0.961356 0.0537102 
-0.300985 0.953168 0.0296444 
-0.330355 0.943296 0.0325371 
-0.325575 0.943296 0.0647609 
-0.29663 0.953168 0.0590034 
-0.330355 0.943296 0.0325371 
-0.362205 0.931416 0.0356741 
-0.356964 0.931416 0.0710046 
-0.325575 0.943296 0.0647609 
-0.362205 0.931416 0.0356741 
-0.396618 0.917152 0.0390634 
-0.390879 0.917152 0.0777507 
-0.356964 0.931416 0.0710046 
-0.184263 0.982193 0.0366522 
-0.202879 0.978372 0.0403551 
-0.197946 0.978372 0.0600463 
-0.179783 0.982193 0.0545366 
-0.202879 0.978372 0.0403551 
-0.223283 0.973741 0.0444137 
-0.217854 0.973741 0.0660854 
-0.197946 0.978372 0.0600463 
-0.223283 0.973741 0.0444137 
-0.245616 0.968135 0.0488561 
-0.239645 0.968135 0.0726954 
-0.217854 0.973741 0.0660854 
-0.245616 0.968135 0.0488561 
-0.270019 0.961356 0.0537102 
-0.263455 0.961356 0.0799181 
-0.239645 0.968135 0.0726954 
-0.270019 0.961356 0.0537102 
-0.29663 0.953168 0.0590034 
-0.289418 0.953168 0.0877941 
-0.263455 0.961356 0.0799181 
-0.29663 0.953168 0.0590034 
-0.325575 0.943296 0.0647609 
-0.31766 0.943296 0.096361 
-0.289418 0.953168 0.0877941 
-0.325575 0.943296 0.0647609 
-0.356964 0.931416 0.0710046 
и т.д.
#7
12:52, 22 мар. 2020

Уже попробовал - не помогло

#8
13:15, 22 мар. 2020

Попробуй поверни источник света на 90 градусов

            SunPos[0]=0.0;
            SunPos[1]=1.0;
            SunPos[2]=0.0;

            SunPos[0]=0.0;
            SunPos[1]=0.0;
            SunPos[2]=-1.0;

            SunPos[0]=1.0;
            SunPos[1]=0.0;
            SunPos[2]=0.0;

Результат не меняется. Как будто вообще освещения нет

#9
13:39, 22 мар. 2020

попробую Но что интересно: тот же код освещения (и без всякого материала) отлично работает на шарике:
https://ibb.co/1KL0vHX

#10
13:43, 22 мар. 2020

нет точно также создаю массивы и гружу текстуру. правда там это все статично, один раз при инициализации происходит загрузка и все...

все отличие только в том что там текстура подвязана к точкам лежащим на шаре, а здесь на плоскости. но по идее нормали посчитаны для шара....

#11
14:01, 22 мар. 2020

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

Если поставлю 0.0 0.0 1.0  то это доска перпендикулярная направлению на камеру. под каким углом не свети - будет тот же эффект. максимум чуть темнее , но однородная картинка выйдет

#12
14:06, 22 мар. 2020

направленный. т.к. расстояние от Солнца до Земли во много раз превышает размеры самой Земли

#13
14:21, 22 мар. 2020
SunPos[0]*=-1.0;
SunPos[1]*=-1.0;
SunPos[2]*=-1.0;

неа. все тоже самое.

А как opengl считает освещение только по нормалям ? есть подозрение что нет....

#14
14:36, 22 мар. 2020
void CMap::initializeGL()
{


    initializeGLFunctions();

    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
    glShadeModel(GL_SMOOTH);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glDisable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);

    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);

//    qglClearColor(Qt::black);
//    glEnable(GL_DEPTH_TEST);
//    glShadeModel(GL_SMOOTH);
//    glEnable(GL_CULL_FACE);

 
    updateScene();
}

void CMap::drawSunLight()
{
                // Положение Солнца (направление)
                float SunPos[] = { 0.0, 0.0, 1.0, 0.0f };
    
                // Фоновое освещение
                float fAmbientShadow[] = { 0.5f, 0.5f, 0.5f, 1.0f };
    
                // Начальная позиция источника света и интенсивность тёмной части.
                glLightfv(GL_LIGHT0, GL_POSITION, SunPos);
                glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fAmbientShadow);
    
                // Включаем источник света.
                glEnable(GL_LIGHTING);
                glEnable(GL_LIGHT0);
}
void CMap::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    setModelViewMatrix();

        // Освещение
        drawSunLight();

        // Карта
        drawMap();

        glDisable(GL_LIGHTING);
        glDisable(GL_LIGHT0);

}

void CMap::updateScene()
{
    //! Выбор масштаба текстуры
    zoom = qBound(MIN_ZOOM, (unsigned int)floor(log(qMax((2.0*width()/scnmove.w/TILE_SIZE),
                                                         (2.0*height()/scnmove.h/TILE_SIZE))) / log(2.0)), MAX_ZOOM);
    //! Размер фрагмента текстуры (тайла)
    GLdouble  l_s = 2.0 / (1 << zoom),
              l_m = l_s / qMax(1, LG_SLICE_CNT / (1 << zoom));


    //! Индексы крайних отображаемых фрагментов текстуры (от верхнего левого угла)
    int
         t_x = (1.0 + scnmove.x - scnmove.w) / l_s,
         t_y = (1.0 - scnmove.y - scnmove.h) / l_s,
         t_w = (1.0 + scnmove.x + scnmove.w) / l_s,
         t_h = (1.0 - scnmove.y + scnmove.h) / l_s;

    makeCurrent();

    //! Очистка массивов
    glDeleteTextures(textureMap.size(), textureMap.data());
    textureMap.clear();
    coordVertexMap.clear();
    normalVertexMap.clear();
    textureVertexMap.clear();

    //! Инициализация текстур, массивов вершин и нормалей

    // Циклы по фрагментам тектуры (тайлам)
    for(int s = t_x; s <= t_w; s++)
    {
        GLdouble a_x = s * l_s - 1.0;

        for(int t = t_y; t <= t_h; t++)
        {
            GLdouble a_y = 1.0 - t * l_s;

            //! Загрузка текстуры из базы
            textureMap.push_back(loadTexture(s, t, zoom));

            //! Массивы привязки текстурных координат к координатам карты
            for(GLdouble a_m = 0.0; a_m < l_s; a_m += l_m)
            {
                for(GLdouble a_n = 0.0; a_n < l_s; a_n += l_m)
                {
                    GLdouble lat, lon;

                    // Верхняя левая точка
                    Map2DToGeo(a_x + a_m, a_y - a_n, &lat, &lon);
                    coordVertexMap.push_back( a_x + a_m );
                    coordVertexMap.push_back( a_y - a_n );
                    coordVertexMap.push_back( 0.0 );
                    normalVertexMap.push_back( cos(lat)*sin(lon) );
                    normalVertexMap.push_back( sin(lat) );
                    normalVertexMap.push_back( cos(lat)*cos(lon) );
                    textureVertexMap.push_back( a_m / l_s );
                    textureVertexMap.push_back( 1.0 - a_n / l_s );

                    // Нижняя левая точка
                    Map2DToGeo(a_x + a_m, a_y - a_n - l_m, &lat, &lon);
                    coordVertexMap.push_back( a_x + a_m );
                    coordVertexMap.push_back( a_y - a_n - l_m );
                    coordVertexMap.push_back( 0.0 );
                    normalVertexMap.push_back( cos(lat)*sin(lon) );
                    normalVertexMap.push_back( sin(lat) );
                    normalVertexMap.push_back( cos(lat)*cos(lon) );
                    textureVertexMap.push_back( a_m / l_s );
                    textureVertexMap.push_back( 1.0 - (a_n + l_m) / l_s );

                    // Нижняя правая точка
                    Map2DToGeo(a_x + a_m + l_m, a_y - a_n - l_m, &lat, &lon);
                    coordVertexMap.push_back( a_x + a_m + l_m );
                    coordVertexMap.push_back( a_y - a_n - l_m );
                    coordVertexMap.push_back( 0.0 );
                    normalVertexMap.push_back( cos(lat)*sin(lon) );
                    normalVertexMap.push_back( sin(lat) );
                    normalVertexMap.push_back( cos(lat)*cos(lon) );
                    textureVertexMap.push_back( (a_m + l_m) / l_s );
                    textureVertexMap.push_back( 1.0 - (a_n + l_m) / l_s );

                    // Верхняя правая точка
                    Map2DToGeo(a_x + a_m + l_m, a_y - a_n, &lat, &lon);
                    coordVertexMap.push_back( a_x + a_m + l_m );
                    coordVertexMap.push_back( a_y - a_n );
                    coordVertexMap.push_back( 0.0 );
                    normalVertexMap.push_back( cos(lat)*sin(lon) );
                    normalVertexMap.push_back( sin(lat) );
                    normalVertexMap.push_back( cos(lat)*cos(lon) );
                    textureVertexMap.push_back( (a_m + l_m) / l_s );
                    textureVertexMap.push_back( 1.0 - a_n / l_s );
                }
            }
        }
    }
}

//! Отрисовка текстуры
void CMap::drawMap()
{

    // Число разбиений фрагмента текстуры (тайла)
    int s = qMax(1, LG_SLICE_CNT * LG_SLICE_CNT / (1 << (2 * zoom)));

    glEnable(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, 0);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    for (int i = 0; i < textureMap.size(); ++i)
    {
        glBindTexture(GL_TEXTURE_2D, textureMap[i]);
        glVertexPointer(3, GL_DOUBLE, 0, coordVertexMap.data()+12*s*i);
        glNormalPointer(GL_DOUBLE, 0, normalVertexMap.data()+12*s*i);
        glTexCoordPointer(2, GL_DOUBLE, 0, textureVertexMap.data()+8*s*i);
        glDrawArrays(GL_QUADS, 0, 4*s);
    }
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glDisable(GL_TEXTURE_2D);
}
Страницы: 1 2 3 Следующая »
ПрограммированиеФорумГрафика

Тема в архиве.