2016-09-11 10 views
0

Добрый день,Деформирующая плоская сетка в сферу

В настоящее время я пытаюсь сгибать самолет к сфере. Я все уже пробовал Mercator projection вместе с lla to ecef. Таким образом, результат отступает, но он не похож на сферу (полусферу). Наиболее удачный вариант выглядел так (больше похож на палатку, а не как полусфера):

enter image description here

Code for this tent (pastebin). Я использую three.js для рендеринга.

Так что я прошу совета. Что я делаю неправильно?

+0

Вы когда-нибудь пробовали обернуть мяч прямоугольник бумажке? Это ** не может работать **, и вам нужно выбрать свой компромисс. – Amit

+0

Я думаю [это] (http://stackoverflow.com/questions/38712632/morphing-sphere-into-plane/38777667#38777667) и [это] (http://stackoverflow.com/questions/33065204/how- to-create-sphere-using-multiple-objects/33086141 # 33086141) содержит некоторую полезную информацию. – mlkn

ответ

2

Использование сферическая координата system. Углы long,lat: 2D Линейные u,v Координаты в вашей плоскости и продукции 3Dx,y,z.

  1. Преобразовать Вершины (точки) вашей плоской сетки к поверхности сферы

    Я подозреваю, что вы получили очки в форме (x,y,z) так что вам нужно первым вычислить u,v. Пусть U,V являются перпендикулярными единичными базисными векторами, лежащими на плоскости. Их можно получить, вычитая 2 точки на плоской сетке, нормализуя размер и используя перекрестное изделие, чтобы обеспечить перпендикулярность. Итак:

    u = `dot_product((x,y,z),U)` = x*U.x + y*U.y + z*U.z 
    v = `dot_product((x,y,z),V)` = x*V.x + y*V.y + z*V.z 
    

    Теперь конвертировать в сферу углов:

    long=6.2831853*u/u_size_of_mesh 
    lat =3.1415926*v/v_size_of_mesh 
    

    И, наконец, вычислить новый (x,y,z) на поверхности сферы:

    x = R*cos(lat)*cos(long) 
    y = R*cos(lat)*sin(long) 
    z = R*sin(lat) 
    
  2. сетки

    планарной сетки должно быть достаточно плотным (достаточно треугольников/граней), иначе сфера не будет выглядеть так, как должна. Другая проблема заключается в том, что в плоской сетке нет ребер и поверхности сферы. Ti s, возможно, создаст вид/зазоры на поверхности сферы, где соединяются края плоскости. Если вы хотите избежать этого, вы можете либо добавить грани между краями на противоположных сторонах плоской сетки, чтобы заполнить пробелы, либо полностью выбросить вашу сетку, и повторно пробовать плоскость с единой сеткой точек.

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

    Sphere triangulation by mesh subdivision

    А затем вычислить соответствующую точку на плоскости с помощью обратного процесса в # 1 так что вы можете интерполировать другие параметры точек (например, цвет, координаты текстуры и т.д.)

[Примечания]

Если вы хотите, чтобы оживить это, то просто использовать линейную интерполяцию между исходной точкой плоскости P0(x,y,z) и соответствующей точкой поверхности сферы P1(x,y,z) с параметром анимации t=<0.0,1.0> как это:

P = P0 + (P1-P0)*t 

если t=0 то выход плоской сеткой еще если t=1, то это сфера. где-нибудь между собой процесс оборачивания так увеличивает t до 1 с достаточно малым шагом (например, 0.01) и сделать в каком-то таймере ...

[Edit1] U, V базисных векторы

Идея является просто получить 2 непараллельных вектора и изменить один из них, чтобы перпендикулярно первому, но все же на одной плоскости.

  1. принимать какие-либо сетки лицо

    , например, треугольник ABC

  2. Compute 2 ненулевых не являющиеся параллельными векторами на плоскости

    Это легко просто вычитать любой 2 пары вершин, например:

    U.x=B.x-A.x 
    U.y=B.y-A.y 
    V.x=C.x-A.x 
    V.y=C.y-A.y 
    

    и сделать их единицы в размерах, чтобы разделить их по размеру

    ul=sqrt((U.x*U.x)+(U.y*U.y)) 
    vl=sqrt((V.x*V.x)+(V.y*V.y)) 
    U.x/=ul 
    U.y/=ul 
    V.x/=vl 
    V.y/=vl 
    
  3. сделать их перпендикулярно

    Так оставил один вектор, как это (например U) и вычислить другой поэтому он перпендикулярен. Для этого вы можете использовать кросс-продукт. Перекрестное произведение двух единичных векторов - это новый единичный вектор, перпендикулярный обоим. Какой из них от 2 возможностей зависит только от порядка операндов ((U x V) = - (V x U)) так, например:

    // W is perpendicular to U,V 
    W.x=(U.y*V.z)-(U.z*V.y) 
    W.y=(U.z*V.x)-(U.x*V.z) 
    W.z=(U.x*V.y)-(U.y*V.x) 
    // V is perpendicular to U,W 
    V.x=(U.y*W.z)-(U.z*W.y) 
    V.y=(U.z*W.x)-(U.x*W.z) 
    V.z=(U.x*W.y)-(U.y*W.x) 
    

    W является лишь временным вектором (в изображении его называют V') кстати это вектор нормали к поверхность.

    basis vectors

  4. размер и выравнивание

    Теперь, когда у меня нет больше информации о вашей сетке я не знаю, его форму, размер и т.д. ... Идеальный случай, если сетки прямоугольная и U,V векторы выровнены по краям. В таком случае вы просто нормализуете координаты по размеру прямоугольника в каждом направлении (как в предыдущем изображении слева).

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

    non aligned

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

    Для почти прямоугольных форм иногда достаточно использовать края как U,V, даже если они не идеально перпендикулярны друг другу.

[Edit2] C++ пример

Ну, если вы получили идеально выровнены квадратную форму сетки с некоторым шумом в оси Z (например, карты высот), то это, как я хотел бы сделать преобразование сетки:

//--------------------------------------------------------------------------- 
struct _pnt // points 
    { 
    double xyz[3]; 
    _pnt(){}; _pnt(_pnt& a){ *this=a; }; ~_pnt(){}; _pnt* operator = (const _pnt *a) { *this=*a; return this; }; /*_pnt* operator = (const _pnt &a) { ...copy... return this; };*/ 
    }; 
struct _fac // faces (triangles) 
    { 
    int i0,i1,i2; 
    double nor[3]; 
    _fac(){}; _fac(_fac& a){ *this=a; }; ~_fac(){}; _fac* operator = (const _fac *a) { *this=*a; return this; }; /*_fac* operator = (const _fac &a) { ...copy... return this; };*/ 
    }; 
// dynamic mesh 
List<_pnt> pnt; 
List<_fac> fac; 
//--------------------------------------------------------------------------- 
void mesh_normals() // compute normals 
    { 
    int i; 
    _fac *f; 
    double a[3],b[3]; 
    for (f=&fac[0],i=0;i<fac.num;i++,f++) 
     { 
     vector_sub(a,pnt[f->i1].xyz,pnt[f->i0].xyz); // a = pnt1 - pnt0 
     vector_sub(b,pnt[f->i2].xyz,pnt[f->i0].xyz); // b = pnt2 - pnt0 
     vector_mul(a,a,b);        // a = a x b 
     vector_one(f->nor,a);       // nor = a/|a| 
     } 
    } 
//--------------------------------------------------------------------------- 
void mesh_init() // generate plane mesh (your square with some z noise) 
    { 
    int u,v,n=40; // 40x40 points 
    double d=2.0/double(n-1); 
    _pnt p; 
    _fac f; 
    Randomize(); 
    RandSeed=13; 
    // create point list 
    pnt.allocate(n*n); pnt.num=0;    // preallocate list size to avoid realocation 
    for (p.xyz[0]=-1.0,u=0;u<n;u++,p.xyz[0]+=d) // x=<-1.0,+1.0> 
    for (p.xyz[1]=-1.0,v=0;v<n;v++,p.xyz[1]+=d)// y=<-1.0,+1.0> 
     { 
     p.xyz[2]=0.0+(0.05*Random());   // z = <0.0,0.05> noise 
     pnt.add(p); 
     } 
    // create face list 
    vector_ld(f.nor,0.0,0.0,1.0); 
    for (u=1;u<n;u++) 
    for (v=1;v<n;v++) 
     { 
     f.i0=(v-1)+((u-1)*n); 
     f.i1=(v-1)+((u )*n); 
     f.i2=(v )+((u-1)*n); 
     fac.add(f); 
     f.i0=(v )+((u-1)*n); 
     f.i1=(v-1)+((u )*n); 
     f.i2=(v )+((u )*n); 
     fac.add(f); 
     } 
    mesh_normals(); 
    } 
//--------------------------------------------------------------------------- 
void mesh_sphere() // convert to sphere 
    { 
    int i; 
    _pnt *p; 
    double u,v,lon,lat,r,R=1.0; 
    // I know my generated mesh is aligned so: 
    double U[3]={ 1.0,0.0,0.0 }; 
    double V[3]={ 0.0,1.0,0.0 }; 
    for (p=&pnt[0],i=0;i<pnt.num;i++,p++) // process all points 
     { 
     // get the u,v coordinates 
     u=vector_mul(p->xyz,U); 
     v=vector_mul(p->xyz,V); 
     // I also know the limits are <-1,+1> so conversion to spherical angles: 
     lon=M_PI*(u+1.0);    // <-1.0,+1.0> -> <0.0,6.28> 
     lat=M_PI*v*0.5;     // <-1.0,+1.0> -> <-1.57,+1.57> 
     // compute spherical position (superponate z to r preserve noise) 
     r=R+p->xyz[2]; 
     p->xyz[0]=r*cos(lat)*cos(lon); 
     p->xyz[1]=r*cos(lat)*sin(lon); 
     p->xyz[2]=r*sin(lat); 
     } 
    mesh_normals(); 
    } 
//--------------------------------------------------------------------------- 
void mesh_draw() // render 
    { 
    int i; 
    _fac *f; 
    glColor3f(0.2,0.2,0.2); 
    glBegin(GL_TRIANGLES); 
    for (f=&fac[0],i=0;i<fac.num;i++,f++) 
     { 
     glNormal3dv(f->nor); 
     glVertex3dv(pnt[f->i0].xyz); 
     glVertex3dv(pnt[f->i1].xyz); 
     glVertex3dv(pnt[f->i2].xyz); 
     } 
    glEnd(); 
    } 
//--------------------------------------------------------------------------- 

Я использовал мой динамический шаблон списка так:

  • List<double> xxx; таких же, как double xxx[];
  • xxx.add(5); добавляет 5 в конце списка
  • xxx[7] доступа к массиву (безопасный)
  • xxx.dat[7] доступа элемент массива (небезопасный, но быстро прямой доступ)
  • xxx.num фактический используемого размер массива
  • xxx.reset() очищает массив и установить xxx.num = 0
  • xxx.allocate(100) пространство для предварительно выделить 100 жет мс

Использование это так:

mesh_init(); 
mesh_sphere(); 

Здесь результаты:

overview

Слева генерируемый плоской сетки с шумом и справа от результат после преобразования.

Код отражает все перечисленное выше + добавляет Z-шум к радиусу сферы для сохранения функций. Нормали пересчитываются из геометрии стандартным образом. Для всей матрицы TBN вам нужна информация о соединении из топологии и пересчитайте ее (или используйте геометрию сферы и используйте TBN из нее.

Кстати, если вы хотите отображать сферу вместо преобразования сетки, вы должны взглянуть на QA s:

+0

Если возможно, мне нужно пояснить эту часть: _ Их можно получить, вычитая 2 точки на плоской сетке, нормализуя размер и используя кросс-продукт, чтобы обеспечить перпендикулярность. И вот эти два параметра: _u_size_of_mesh_ и _v_size_of_mesh_ – QuentinCaffeino

+0

Я создал почти все, кроме тех, что указаны в параметрах [link] (http://pastebin.com/vbxiBSQu). Теперь я получаю очень большие цифры e на длинных (-6.975736996024239e-28) – QuentinCaffeino

+0

@ Sergey95 добавил ** [edit1] ** с запрошенной информацией. '-6.975736996024239e-28' почти не имеет большого числа. Проверьте свои функции 'sin, cos', если они нуждаются в радианах или градусах. Также проверьте, не округляете ли вы числа с плавающей запятой целыми числами, эти два являются наиболее частыми причинами ошибки – Spektre