Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: spirits25 от Октябрь 01, 2010, 20:09



Название: 3D планеты, помогите новичку
Отправлено: spirits25 от Октябрь 01, 2010, 20:09
Проблема в том, что графикой ранее не занимался, но "неожиданно" (как это обычно и бывает=)) понадобилось в гуи проекте вставить окошко с графикой. всё прошло нормально, кроме самой графики. необходимо отобразить планету (собственно Земля), спутник, Луну и Солнце, причём всё это желательно должно вращаться вокруг Земли. параметры орбиты спутника задаются кеплеровской шестёркой координат. Луна и Солнце вращаются по кругу относительно Земли. На планеты наложены простые текстуры. За любую помощь буду благодарен. Ранее уже получал советы из разряда "юзай glut", но проблема в том, что моё основное внимание уделено мат.расчётам (а именно влиянию различных параметров на изменение орбиты).
Посему, если кто обладает исходниками, знаниями, советами - заранее спасибо=)


Название: Re: 3D планеты, помогите новичку
Отправлено: Igors от Октябрь 01, 2010, 22:00
Мне кажется что гораздо проще (и намного полезнее) сделать это руками вместо чтобы забивать голову изучением OpenGL. Нужно немного:

- понятие про камеру/перспективу (ну или еще проще в изометрии)
- уметь находить пересечение луча со сферой (в рамках школьной программы)
- формулы сферического наложения текстуры (я подскажу когда дело до этого дойдет)
- ну и помножить на диффузный косинус (расчет света)

Ото и все 


Название: Re: 3D планеты, помогите новичку
Отправлено: vipet от Октябрь 01, 2010, 23:03
Поддерживаю предыдущего оратора. Не надо заморачиваться с лишними либами.

Юзай QGraphicsView/QGraphicsScene + State Machine Framework (чтобы крутилось все красиво)


Название: Re: 3D планеты, помогите новичку
Отправлено: navrocky от Октябрь 02, 2010, 01:37
Цитировать
что графикой ранее не занимался....  необходимо отобразить планету (собственно Земля), спутник, Луну и Солнце... На планеты наложены простые текстуры

Не надо заморачиваться с лишними либами.
...
Юзай QGraphicsView/QGraphicsScene

хохо ну и советы... и сделает он это за полтора дня.. и тормозить это ниразу не будет...

Мне кажется OpenGL тут однозначно. Ну или тогда уж спрайтики рисовать QPainter'ом...


Название: Re: 3D планеты, помогите новичку
Отправлено: Igors от Октябрь 02, 2010, 11:24
хохо ну и советы... и сделает он это за полтора дня.. и тормозить это ниразу не будет...

Мне кажется OpenGL тут однозначно. Ну или тогда уж спрайтики рисовать QPainter'ом...
OpenGL часто неизбежен, но у человека случай специфический - по существу ему полигоны не нужны. Гораздо быстрее найти пересечение луча со сферой чем молотить тонны полигонов. Так что не исключено что ручная реализация обгонит крутой GPU  :)  Другое дело тут надо думать, а не либы прикручивать. Ну это уж кому как.


Название: Re: 3D планеты, помогите новичку
Отправлено: navrocky от Октябрь 03, 2010, 00:32
Цитировать
OpenGL часто неизбежен, но у человека случай специфический - по существу ему полигоны не нужны. Гораздо быстрее найти пересечение луча со сферой чем молотить тонны полигонов.
Предлагаешь ему трассировку лучей забацать?

Цитировать
Так что не исключено что ручная реализация обгонит крутой GPU  :)
Вот уж не думаю... судя по демкам с трассировкой 320x200 почти не тормозит :D


Название: Re: 3D планеты, помогите новичку
Отправлено: Igors от Октябрь 03, 2010, 11:51
Предлагаешь ему трассировку лучей забацать?
А что здесь бацать? Это не BSP строить, тут "только сферы". Берем пиксель, x, y есть. z = фокальному расстоянию. Луч готов. Центры сфер и радиусы известны. Для каждой решаем квадратное уравнение (изучалось в 6-м классе). Выбираем ближайшее пересечение по лучу. Шейдим пиксель, берем следующий. Так же легко получаются др. эффекты, напр. сферы могут бросать тень друг на друга. Или планета может иметь атмосферу (показать ободок). Или сияние (glow).

Ну конечно все это пригодно только для сфер. Если напр. потребуется космический корабль - придется запрягать OpenGL, то да


Название: Re: 3D планеты, помогите новичку
Отправлено: spirits25 от Октябрь 03, 2010, 13:56
Спутник точно будет не сфера, хоть и очень близкое к ней. Так что в итоге посоветуете? нужно простое отображение без "особой крутости и красоты"=) главное в программе чтобы траектория менялась в зависимости от изменения параметров орбиты.


Название: Re: 3D планеты, помогите новичку
Отправлено: ufna от Октябрь 03, 2010, 14:03
а вид нужен именно 3д, чтобы можно было сцену вращать?


Название: Re: 3D планеты, помогите новичку
Отправлено: spirits25 от Октябрь 03, 2010, 15:21
да, с простым объектом у меня получилось. Вот например 3D пирамиду (которую можно вращать относительно всех 3-х осей) я в гуи окно нормально поместил.


Название: Re: 3D планеты, помогите новичку
Отправлено: Igors от Октябрь 03, 2010, 16:36
Спутник точно будет не сфера, хоть и очень близкое к ней.
А что? Если напр сфероид (сплюснутая сфера) то нет проблем,

((x - cx) * (x - cx)) / (a * a) + ((y - cy) * (y - cy)) / (b * b) + ((z - cz) * (z - cz)) / (c * c) = 1;
 //  поверхность сфероида, a, b, c - размеры по осям, cx, cy, cz - координаты центра

Задан луч 3 числа (rx, ry, rz), значит точку пересечения (x, y, z) можно записать как

x = rx * d;
y = ry * d;
z = rz * d;

Где d = расстояние вдоль луча. Подставляем эти (x, y, z) в уравнение сфероида, находим d как 2 корня получившегося квадратного уравнения. Это расстояния по лучу с передней и задней стенками сфероида

Так что в итоге посоветуете?
Как уже говорилось, с более сложными объектами придется привлекать OpenGL. А так - смотрите сами что Вам больше нравится


Название: Re: 3D планеты, помогите новичку
Отправлено: spirits25 от Октябрь 03, 2010, 17:58
хорошо, буду разбираться=) начну с рисования сферы Земли.
Может сразу подскажите как это с помощью openGL делается?=)


Название: Re: 3D планеты, помогите новичку
Отправлено: spirits25 от Октябрь 03, 2010, 19:17
вот код нашёл

//=== Команды OpenGL для изображения одного треугольника
void Graphics::setTria (double *v1, double *v2, double *v3)
{
//====== Нормаль и вершина задаются одним вектором
glNormal3dv(v1);
glVertex3dv(v1);
glNormal3dv (v2);
glVertex3dv(v2);
glNormal3dv(v3);
glVertex3dv(v3);
glEnd() ;
}

//====== Генерация внутренних треугольников

void Graphics::Split(double *v1, double *v2, double *v3)
{
//====== Промежуточные вершины
double v12[3], v23[3], v31[3];

for ( int i=0; i< 3; i++) {
//====== Можно не делить пополам,
//====== так как будем нормировать
v12 = v1+v2;
v23 = v2+v3;
v31 = v3+v1 ;
}

//====== Нормируем три новые вершины
scale(v12);
scale(v23);
scale(v31);
//====== и рисуем четыре треугольника
setTria(v1, v12, v31);
setTria (v2, v23, v12);
setTria(v3, v31, v23);
setTria(v12,v23, v31);
}

void Graphics::DrawScene()
{
static double angle = 3.0 * atan(1.0)/2.5, V = cos (angle), W = sin (angle),
v[12] [3] =
{{-V,0.,W}, {V,0.,W}, {-V,0.,-W},
 {V,0.,-W}, {0.,W,V}, {0.,W,-V},
 {0.,-W,V}, {0.,-W,-V}, {W,V,0.},
{-W,V,0.}, {W,-V,0.}, {-W,-V,0.}
};

static GLuint id[20][3] =
{
{0,1, 4}, {0,4, 9}, {9,4, 5}, {4,8, 5}, {4,1,8},
{8,1,10}, {8,10,3}, {5,8, 3}, {5,3, 2}, {2,3,7},
{7,3,10}, {7,10,6}, {7,6,11}, {11,6,0}, {0,6,1},
{6,10,1}, {9,11,0}, {9,2,11}, {9,5, 2}, {7,11,2}
};
glNewList(1,GL_COMPILE);
glColor3d (1., 0.4, 1.) ;
glBegin(GL_TRIANGLES);
for (int i = 0; i < 20; i++)
Split (v[id
  • ], v[id[1]], v[id [2] ]);
glEnd();
glEndList () ;
}

но тут scale с одним параметром и не работает поэтому.


Название: Re: 3D планеты, помогите новичку
Отправлено: Igors от Октябрь 03, 2010, 19:43
вот код нашёл
Хмм... ну вообще-то с OpenGL в первый раз надо хотя бы недельку "маны покурить" (как говорит молодежь). Там надо довольно много знать, это нормально. Кстати там есть ф-ция для создания сферы.

//=== Команды OpenGL для изображения одного треугольника
void Graphics::setTria (double *v1, double *v2, double *v3)
Для 3D есть одна "народная примета" как отличить хороший пример на С++ от плохого: просто смотрите как реализован класс "3D точка". Если его вообще нет, то смело бросайте этот пример в trash, ничего хорошего Вы в нем не найдете.


Название: Re: 3D планеты, помогите новичку
Отправлено: spirits25 от Октябрь 03, 2010, 20:04
Цитировать
Кстати там есть ф-ция для создания сферы.
не подскажете? вся проблема в том, что этого времени нет. Да и openGL меня интересует в самой меньшей степени, так как дальше им заниматься не собираюсь (другие планы). Просто пришлось по теме диплома его использовать. Если сможете помочь, буду признателен. только не надо заставлять учить, было бы время и желание - так бы и сделал=)


Название: Re: 3D планеты, помогите новичку
Отправлено: ufna от Октябрь 03, 2010, 20:27
дак есть же в QtDemo примерчики красивые, там даже что-то крутится вокруг чего-то


Название: Re: 3D планеты, помогите новичку
Отправлено: Igors от Октябрь 03, 2010, 20:31
Цитировать
Кстати там есть ф-ция для создания сферы.
не подскажете? вся проблема в том, что этого времени нет. Да и openGL меня интересует в самой меньшей степени, так как дальше им заниматься не собираюсь (другие планы). Просто пришлось по теме диплома его использовать. Если сможете помочь, буду признателен. только не надо заставлять учить, было бы время и желание - так бы и сделал=)
Подсказать ф-цию gluSphere не проблема, но ведь на этом Ваши проблемы не кончатся  :). В задаче ничего особенного нет, но в любом случае повозиться придется. Считая все доделки - с неделю (считая что всей "кухней" владеем, иначе больше). Я сам не смогу, напишите в личку, порекомендую нормальных пацанов с этого форума. Разумеется это работа за деньги.


Название: Re: 3D планеты, помогите новичку
Отправлено: spirits25 от Октябрь 10, 2010, 19:42
 
Код:
   glPushMatrix();
    qMultMatrix(mat);
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, faceColor);

    //stars();
    GLUquadric* quad = gluNewQuadric();
    gluSphere (quad, 10.0d, 40, 40);
    gluDeleteQuadric(quad);

    glTranslated(15.0d,15.0d,15.0d);
    glColor3d(1,0,0);

    GLUquadric* quad2 = gluNewQuadric();
    gluSphere (quad2, 2.0d, 10, 10);
    gluDeleteQuadric(quad2);

    GLUquadric* quad3 = gluNewQuadric();
    glTranslated(-35.0d,30.0d,10.0d);
    gluSphere (quad3, 5.5d, 10, 10);
    gluDeleteQuadric(quad3);

    glPopMatrix();

допустим есть такой вывод сфер. пространство у меня 100 единиц. Как лучше сделать функцию void stars(), чтобы на заднем плане звёзды были видны, а на переднем, соответственно, нет?
и ещё, GLUquadric* quad = gluNewQuadric(); для каждого объекта ведь не нужно новый создавать?


Название: Re: 3D планеты, помогите новичку
Отправлено: spirits25 от Октябрь 25, 2010, 18:37
может хотя бы это подскажите. есть сфера, нужно текстуру натянуть.
сфера строится с помощью функции:

Код:
//-----------------------------------------------------------------------------
// Name: renderSphere()
// Desc: Create a sphere centered at cy, cx, cz with radius r, and
//       precision p. Based on a function Written by Paul Bourke.
//       http://astronomy.swin.edu.au/~pbourke/opengl/sphere/
//-----------------------------------------------------------------------------
void renderSphere( float cx, float cy, float cz, float r, int p )
{
    const float PI     = 3.14159265358979f;
    const float TWOPI  = 6.28318530717958f;
    const float PIDIV2 = 1.57079632679489f;

    float theta1 = 0.0;
    float theta2 = 0.0;
    float theta3 = 0.0;

    float ex = 0.0f;
    float ey = 0.0f;
    float ez = 0.0f;

    float px = 0.0f;
    float py = 0.0f;
    float pz = 0.0f;

    // Disallow a negative number for radius.
    if( r < 0 )
        r = -r;

    // Disallow a negative number for precision.
    if( p < 0 )
        p = -p;

    // If the sphere is too small, just render a OpenGL point instead.
    if( p < 4 || r <= 0 )
    {
        glBegin( GL_POINTS );
        glVertex3f( cx, cy, cz );
        glEnd();
        return;
    }

    for( int i = 0; i < p/2; ++i )
    {
        theta1 = i * TWOPI / p - PIDIV2;
        theta2 = (i + 1) * TWOPI / p - PIDIV2;

        glBegin( GL_TRIANGLE_STRIP );
        {
            for( int j = 0; j <= p; ++j )
            {
                theta3 = j * TWOPI / p;

                ex = cosf(theta2) * cosf(theta3);
                ey = sinf(theta2);
                ez = cosf(theta2) * sinf(theta3);
                px = cx + r * ex;
                py = cy + r * ey;
                pz = cz + r * ez;

                glNormal3f( ex, ey, ez );
                glTexCoord2f( -(j/(float)p) , 2*(i+1)/(float)p );
                glVertex3f( px, py, pz );

                ex = cosf(theta1) * cosf(theta3);
                ey = sinf(theta1);
                ez = cosf(theta1) * sinf(theta3);
                px = cx + r * ex;
                py = cy + r * ey;
                pz = cz + r * ez;

                glNormal3f( ex, ey, ez );
                glTexCoord2f( -(j/(float)p), 2*i/(float)p );
                glVertex3f( px, py, pz );
            }
        }
        glEnd();
    }
}

необходимо текстуру (собственно карту земли) натянуть на неё..
ведб по-любому есть у кого-то исходники этого. Заранее спасибо=)


Название: Re: 3D планеты, помогите новичку
Отправлено: spirits25 от Декабрь 14, 2010, 21:49
наговнокодил примерно следующее:
Код:
void Patch::draw() const
{
    GLbyte *pBytes;
    glPushMatrix();
    qMultMatrix(mat);
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, faceColor);

    GLint Width, Height, Components;
    GLenum Format;
    GLUquadric* quad = gluNewQuadric();
//----------
    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
    pBytes = gltLoadTGA("earth.tga", &Width, &Height, &Components, &Format);

    if (pBytes == NULL)
        exit (2);
    glTexImage2D(GL_TEXTURE_2D, 0, Components, Width, Height, 0, Format, GL_UNSIGNED_BYTE, pBytes);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glEnable(GL_TEXTURE_2D);
   
    glBindTexture(GL_TEXTURE_2D,15);
//----------
    gluQuadricTexture(quad, GL_TRUE);
    gluQuadricDrawStyle(quad, GLU_FILL);
    gluSphere (quad, 10.0d, 20, 20);
    gluDeleteQuadric(quad);
    free(pBytes);
    glTranslated(15.0d,15.0d,15.0d);
    glColor3d(1,0,0);
    glDisable(GL_TEXTURE_2D);

//----------------------------------------------------------------------------------
    GLUquadric* quad2 = gluNewQuadric();
     glEnable(GL_TEXTURE_2D);
     GLbyte *pBytes2;
    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
    pBytes2 = gltLoadTGA("luna.tga", &Width, &Height, &Components, &Format);

    if (pBytes2 == NULL)
        exit (2);
    glTexImage2D(GL_TEXTURE_2D, 0, Components, Width, Height, 0, Format, GL_UNSIGNED_BYTE, pBytes2);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    glBindTexture(GL_TEXTURE_2D,15);

    gluQuadricTexture(quad2, GL_TRUE);
    gluQuadricDrawStyle(quad2, GLU_FILL);
    gluSphere (quad2,  2.0d, 10, 10);


    gluDeleteQuadric(quad2);
    free(pBytes2);
    glTranslated(15.0d,15.0d,15.0d);
    glColor3d(1,0,0);
    glDisable(GL_TEXTURE_2D);

//------------------------------------------------------------------
    GLUquadric* quad3 = gluNewQuadric();
     glEnable(GL_TEXTURE_2D);
     GLbyte *pBytes3;
    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
    pBytes3 = gltLoadTGA("luna.tga", &Width, &Height, &Components, &Format);

    if (pBytes3 == NULL)
        exit (2);
    glTexImage2D(GL_TEXTURE_2D, 0, Components, Width, Height, 0, Format, GL_UNSIGNED_BYTE, pBytes3);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    glBindTexture(GL_TEXTURE_2D,15);

    gluQuadricTexture(quad3, GL_TRUE);
    gluQuadricDrawStyle(quad3, GLU_FILL);
    gluSphere (quad3, 5.5d, 20, 20);
    gluDeleteQuadric(quad3);
    free(pBytes3);
    glTranslated(-35.0d,30.0d,10.0d);
    glColor3d(1,0,0);
    glDisable(GL_TEXTURE_2D);

    glPopMatrix();

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