algorithm - Deforming plane mesh to sphere -


good day,

currently i'm trying bend plane sphere. i've ready tried mercator projection lla ecef. result defers isn't sphere (half sphere). successful variant looked (more tent, not half sphere):

enter image description here

code tent (pastebin). i'm using three.js rendering.

so i'm asking advice. i'm doing wrong?

use spherical coordinate system. angles long,lat 2d linear u,v coordinates in plane , output 3d x,y,z.

  1. convert vertexes (points) of planar mesh sphere surface

    i suspect got points in form (x,y,z) need first compute u,v. let u,v perpendicular unit basis vectors lying on plane. can obtained substracting 2 point on plane mesh , normalizing size , exploiting cross product ensure perpendicularity. so:

    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 

    now convert sphere angles:

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

    and compute new (x,y,z) on sphere surface:

    x = r*cos(lat)*cos(long) y = r*cos(lat)*sin(long) z = r*sin(lat) 
  2. mesh

    the planar mesh must have dense enough points structure (enough triangles/faces) otherwise sphere not should. problem planar mesh have edges , sphere surface not. ti s possibly create seems/gaps on surface of sphere edges of plane connect. if want avoid can either add faces between edges on opposite sides of plane mesh fill gaps or throw away mesh , re-sample plane uniform grid of points.

    if want re-sample mesh best can first create regular sphere mesh example with:

    sphere triangulation mesh subdivision

    and compute corresponding point on plane inverse process #1 can interpolate other parameters of points (like color, texture coordinate etc)

[notes]

if want animate use linear interpolation between original plane point p0(x,y,z) , corresponding sphere surface point p1(x,y,z) animation parameter t=<0.0,1.0> this:

p = p0 + (p1-p0)*t 

if t=0 output planar mesh else if t=1 sphere. anywhere in between wrapping process increment t 1 small enough step (like 0.01) , render in timer ...

[edit1] u,v basis vectors

the idea simple obtain 2 non parallel vectors , change 1 of them perpendicular first still on same plane.

  1. take mesh face

    for example triangle abc

  2. compute 2 nonzero non parallel vectors on plane

    that easy substract 2 pairs of vertexes example:

    u.x=b.x-a.x u.y=b.y-a.y v.x=c.x-a.x v.y=c.y-a.y 

    and make them unit in size divide them size

    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. make them perpendicular

    so left 1 vector (for example u) , compute other perpendicular. can use cross product. cross product of 2 unit vectors new unit vector perpendicular both. 1 2 possibilities depends on order of operands ((u x v) = - (v x u)) example:

    // w perpendicular 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 perpendicular 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) 

    the w temporary vector (in image called v') btw normal vector surface.

    basis vectors

  4. size , alignment

    now not have more info mesh not know shape, size etc... ideal case if mesh rectangular , u,v vectors aligned edges. in such case normalize coordinates rectangle size in each direction (as in above image on left).

    if mesh not , computing u,v face approach result may not aligned edges @ (they can rotated angle)...

    non aligned

    if such case can not avoided (by selecting corners face) corner points of shape have various coordinate limits along each edges , need interpolate or map them correct spherical interval in meaning full way (can't more specific have no idea doing).

    for rectangular shapes ok use edges u,v if not perpendicular each other.

[edit2] c++ example

well if got aligned square shape mesh noise in z axis (like height map) how mesh conversion:

//--------------------------------------------------------------------------- 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];     (f=&fac[0],i=0;i<fac.num;i++,f++)         {         vector_sub(a,pnt[f->i1].xyz,pnt[f->i0].xyz);    // = pnt1 - pnt0         vector_sub(b,pnt[f->i2].xyz,pnt[f->i0].xyz);    // b = pnt2 - pnt0         vector_mul(a,a,b);                              // = x b         vector_one(f->nor,a);                           // nor = / |a|         }     } //--------------------------------------------------------------------------- void mesh_init()    // generate plane mesh (your square 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 avoid realocation     (p.xyz[0]=-1.0,u=0;u<n;u++,p.xyz[0]+=d) // x=<-1.0,+1.0>      (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);     (u=1;u<n;u++)      (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 sphere     {     int i;     _pnt *p;     double u,v,lon,lat,r,r=1.0;     // know generated mesh aligned so:     double u[3]={ 1.0,0.0,0.0 };     double v[3]={ 0.0,1.0,0.0 };     (p=&pnt[0],i=0;i<pnt.num;i++,p++)   // process points         {         // u,v coordinates         u=vector_mul(p->xyz,u);         v=vector_mul(p->xyz,v);         // know limits <-1,+1> conversion 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 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);     (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();     } //--------------------------------------------------------------------------- 

i used mine dynamic list template so:

  • list<double> xxx; same double xxx[];
  • xxx.add(5); adds 5 end of list
  • xxx[7] access array element (safe)
  • xxx.dat[7] access array element (unsafe fast direct access)
  • xxx.num actual used size of array
  • xxx.reset() clears array , set xxx.num=0
  • xxx.allocate(100) preallocate space 100 items

the usage of this:

mesh_init(); mesh_sphere(); 

here results:

overview

on left generated planar mesh noise , on right result after conversion.

the code reflects stuff above + add z - noise sphere radius preserve features. normals recomputed geometry in standard way. whole tbn matrix need connection info topology , recompute (or exploit sphere geometry , use tbn it.

btw if want mapping onto sphere instead of mesh conversion should take @ related qas:


Comments

Popular posts from this blog

java - Jasper subreport showing only one entry from the JSON data source when embedded in the Title band -

serialization - Convert Any type in scala to Array[Byte] and back -

SonarQube Plugin for Jenkins does not find SonarQube Scanner executable -