Хорошо выглядит, как текстура полусферы в сферических координатах:
x
ось - это угол долготы a <0,180> [deg]
y
ось - это угол широты b <-45,+45> [deg]
- интенсивность - это радиус
r <0,1> [-]
Таким образом, для каждого пикселя просто:
, линейное преобразование x,y
в a,b
в градусах:
a = x*180 / (width -1)
b = -45 + ( y* 90 / (height-1) )
или в радианах:
a = x*M_PI / (width -1)
b = -0.25*M_PI + ( 0.5*y*M_PI / (height-1) )
применяется сферическое преобразование в декартовое
x=r*cos(a)*cos(b);
y=r*sin(a)*cos(b);
z=r* sin(b);
Похоже, вы неверно закодировали это преобразование , поскольку угол широты должен быть во всех x,y,z
, а не только y
!!! Также вам следует не нормализовать результирующую позицию, которая бы испортила форму !!!
сохранить точку в облаке точек.
Когда я собираю все вместе в VCL / C ++ (извините, не кодируйте в javascript):
List<double> pnt; // 3D point list x0,y0,z0,x1,y1,z1,...
void compute()
{
int x,y,xs,ys; // texture positiona and size
double a,b,r,da,db; // spherical positiona and angle steps
double xx,yy,zz; // 3D point
DWORD *p; // texture pixel access
// load and prepare BMP texture
Graphics::TBitmap *bmp=new Graphics::TBitmap;
bmp->LoadFromFile("map.bmp");
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
xs=bmp->Width;
ys=bmp->Height;
/*
// 360x180 deg
da=2.0*M_PI/double(xs-1);
db=1.0*M_PI/double(ys-1);
b=-0.5*M_PI;
*/
// 180x90 deg
da=1.0*M_PI/double(xs-1);
db=0.5*M_PI/double(ys-1);
b=-0.25*M_PI;
// proces all its pixels
pnt.num=0;
for ( y=0; y<ys; y++,b+=db)
for (p=(DWORD*)bmp->ScanLine[y],a=0.0,x=0; x<xs; x++,a+=da)
{
// pixel access
r=DWORD(p[x]&255); // obtain intensity from texture <0..255>
r/=255.0; // normalize to <0..1>
// convert to 3D
xx=r*cos(a)*cos(b);
yy=r*sin(a)*cos(b);
zz=r* sin(b);
// store to pointcloud
pnt.add(xx);
pnt.add(yy);
pnt.add(zz);
}
// clean up
delete bmp;
}
Вот предварительный просмотр для 180x90 градусов:
и предварительный просмотр для 360x180 град .:
Не уверен, какой из них правильный (как я не имеют никакого контекста к вашей карте), но первый вариант выглядит более корректным для меня ...
В случае, если второй вариант просто использует разные числа (удвоенные) для интерполяции в маркере # 1
Также, если вы хотите удалить фон, просто игнорируйте r==1
пикселей:
, просто проверяя интенсивность до максимальное значение (до нормализации) в моем случае, добавив эту строку:
if (r==255) continue;
после этой
r=DWORD(p[x]&255);
В вашем случае (у вас уже есть <0..1>
) вы должны проверить r>=0.9999
о Вместо этого что-то подобное.