是靜態還是動態地圖?
對於使用不同的渲染靜態地圖
爲什麼不tesselated多邊形存儲一些文件,而不是再次tesselate它...
對於動態地圖
將可能會更快不需要像這樣凸出多邊形的方法:
- 島嶼色彩清晰的屏幕
渲染島嶼勾勒
像GL_LINE_LOOP
未填寫原語並不需要在所有tesselate。
填充在瓦爾特
簡單地從點開始以外的多邊形和洪水填充瓦爾特地圖。如果洪水填充編碼正確(沒有遞歸和填充線而不是像素),那麼它應該只需要幾個[毫秒]。這種方法的問題是你需要訪問渲染的東西,所以你至少需要2遍渲染。在GPU上實現洪水填充並不容易。
也有像CPU存儲邊緣點側和預計算上CPU側的瓦爾特填充的替代品。在這種情況下,您需要爲每個y
圖像掃描線列出x
座標,這些掃描線將保存每個地塊的起點和終點。然後只需填寫單渲染通道的空白......
這應該RT呈現容易
[編輯]成長填充測試演示
做了一些測試用迭代增長填充你的數據。數據集中存在一些問題,例如您的多邊形重疊,這可能只是漏洞,但由於我沒有填充顏色信息,而只是反對ID,所以很難說。無論如何,這也可以修復。這裏小贏32 VCL/OpenGL的/ SW演示使用方法,我上面提到的(動態地圖):
它是Win32的獨立的沒有安裝使用OpenGL + VCL
- 鼠標滾輪放大
- 移+鼠標滾輪選擇不同多邊形
- 鼠標+左按鈕平底鍋
有很少的問題可以修復,但作爲概念證明它運作良好。我把你的ASCII地圖編譯成二進制形式(所以加載速度更快,但形式相同,只是計算多邊形,然後計算每個多邊形的點數,然後將點x,y計數爲64位雙精度值,計數爲32位整數)。我使用我自己的OpenGL引擎(我無法共享),因此您需要編碼這些東西(如OpenGL,FBO和Texture init/set/usage)。反正這裏這個VCL應用的C++代碼:
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "win_main.h"
#include "gl/OpenGL3D_double.cpp"
#include "performance.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
// VCL
TMain *Main;
// OpenGL
OpenGLtime tim;
OpenGLscreen scr;
OpenGL_FBO fbo;
GLuint txr_map=-1;
// miscel
int pn=0; // vertex count
double px0,px1,py0,py1; // bbox
double mx,my; // mouse
double view[16],iview[16]; // direct and inverse Modelview matrix
double zoom=1.0,dzoom=1.1,viewx=0.0,viewy=0.0; // view
int index=0; // selected polygon
bool _redraw=true;
DWORD cl_water=0xFFEE9040;
DWORD cl_land =0xFF70A0B0;
DWORD cl_edge =0xFF000000;
DWORD cl_sel =0xFF00FFFF;
AnsiString tcpu,tgpu;
// map
List< List<double> > polygon; // loaded polygons
List<double> water; // points with water from last frame
//---------------------------------------------------------------------------
void view_compute()
{
double x,y;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
x=divide(1.0,px1-px0)*scr.aspect;
y=divide(1.0,py1-py0)*scr._aspect;
if (x>y) x=y;
x*=zoom;
glTranslated(viewx,viewy,0.0);
glScaled(x,x,1.0);
glTranslated(-0.5*(px0+px1),-0.5*(py0+py1),0.0);
glGetDoublev(GL_MODELVIEW_MATRIX,view);
glPopMatrix();
matrix_inv(iview,view);
}
//---------------------------------------------------------------------------
void map_load_csv(AnsiString filename)
{
BYTE *dat;
AnsiString lin,s,s0;
int ix,i,l,hnd,siz,adr;
double x,y;
List<AnsiString> id;
id.allocate(128); id.num=0;
polygon.allocate(128); polygon.num=0;
hnd=FileOpen(filename,fmOpenRead); if (hnd<0) return;
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
dat=new BYTE[siz]; if (dat==NULL) { FileClose(hnd); return; }
siz=FileRead(hnd,dat,siz);
FileClose(hnd);
adr=0; txt_load_lin(dat,siz,adr,true);
for (ix=-1,s0="";adr<siz;)
{
lin=txt_load_lin(dat,siz,adr,true);
if (lin=="") continue;
i=1; l=lin.Length();
s=str_load_str(lin,i,true); s=s.SubString(2,s.Length()-2);
if (s0!=s)
{
for (ix=0;ix<id.num;ix++) if (id[ix]==s) break;
if (ix>=id.num)
{
ix=id.num;
id.add(s);
polygon.add();
polygon[ix].allocate(256);
polygon[ix].num=0;
}
s0=s;
}
s=str_load_str(lin,i,true); s=s.SubString(2,s.Length()-2); x=str2flt(s);
s=str_load_str(lin,i,true); s=s.SubString(2,s.Length()-2); y=str2flt(s);
polygon[ix].add(x);
polygon[ix].add(y);
}
}
//---------------------------------------------------------------------------
void map_save_bin(AnsiString filename)
{
int hnd,i;
hnd=FileCreate(filename); if (hnd<0) return;
FileWrite(hnd,&polygon.num,4);
for (i=0;i<polygon.num;i++)
{
FileWrite(hnd,&polygon[i].num,4);
FileWrite(hnd,polygon[i].dat,polygon[i].num*8);
}
FileClose(hnd);
}
//---------------------------------------------------------------------------
void map_load_bin(AnsiString filename)
{
int hnd,i,n,m;
hnd=FileOpen(filename,fmOpenRead); if (hnd<0) return;
FileRead(hnd,&n,4);
polygon.allocate(n); polygon.num=n;
for (i=0;i<n;i++)
{
FileRead(hnd,&m,4);
polygon[i].allocate(m); polygon[i].num=m;
FileRead(hnd,polygon[i].dat,m*8);
}
FileClose(hnd);
}
//---------------------------------------------------------------------------
void map_bbox()
{
int ix,i,n;
double *p,a;
pn=0;
px0=px1=polygon[0][0];
py0=py1=polygon[0][1];
for (ix=0;ix<polygon.num;ix++)
{
p=polygon[ix].dat;
n=polygon[ix].num; pn+=n>>1;
for (i=0;i<n;i+=2)
{
a=*p; p++; if (px0>a) px0=a; if (px1<a) px1=a;
a=*p; p++; if (py0>a) py0=a; if (py1<a) py1=a;
}
}
}
//---------------------------------------------------------------------------
void map_draw()
{
int ix,i,n;
double *p,a;
// glLineWidth(2.0);
for (ix=0;ix<polygon.num;ix++)
{
p=polygon[ix].dat;
n=polygon[ix].num;
if (ix==index) glColor4ubv((BYTE*)&cl_sel);
else glColor4ubv((BYTE*)&cl_edge);
glBegin(GL_LINE_LOOP);
for (i=0;i<n;i+=2,p+=2) glVertex2dv(p);
glEnd();
}
// glLineWidth(1.0);
}
//---------------------------------------------------------------------------
void TMain::draw()
{
tbeg();
tim.tbeg();
// [ render outline to texture ]
fbo.bind(scr);
glClearColor(divide((cl_land)&255,255),divide((cl_land>>8)&255,255),divide((cl_land>>16)&255,255),1.0);
scr.cls();
glMatrixMode(GL_MODELVIEW);
glLoadMatrixd(view);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (water.num) // water start points for grow fill
{
// add water around txr border
glBegin(GL_POINTS);
glColor4ubv((BYTE*)&cl_water);
for (int i=0;i<water.num;i+=2)
glVertex2dv(water.dat+i);
glEnd();
}
map_draw();
scr.exe();
fbo.unbind(scr);
// [ copy GL texture to CPU image ]
scr.txrs.txr_ld(txr_map);
// [ create ScanLines for direct pixel access pyx[y][x] ]
int e,x,y,xs,ys; DWORD **pyx,*p,c0,c1; double a[3];
xs=scr.txrs.txr.xs; // texture resolution (rounded up to power of 2)
ys=scr.txrs.txr.ys;
pyx=new DWORD*[ys];
p=(DWORD*)scr.txrs.txr.txr; // CPU image pixel data
for (y=0;y<ys;y++,p+=xs) pyx[y]=p; // scan line pointers
// [ Grow Fill water ]
c0=rgb2bgr(cl_land);
c1=rgb2bgr(cl_water);
if (water.num==0) // first frame view must be set so water is on all borders
{
// add water around txr border
for (x= 1,y=0;y<ys;y++) pyx[y][x]=c1;
for (x=xs-2,y=0;y<ys;y++) pyx[y][x]=c1;
for (y= 1,x=0;x<xs;x++) pyx[y][x]=c1;
for (y=ys-2,x=0;x<xs;x++) pyx[y][x]=c1;
}
for (e=1;e;) // grow it
for (e=0,y=1;y<ys-1;y++)
for ( x=1;x<xs-1;x++)
if (pyx[y][x]==c0)
if ((pyx[y-1][x]==c1)
||(pyx[y+1][x]==c1)
||(pyx[y][x-1]==c1)
||(pyx[y][x+1]==c1)) { e=1; pyx[y][x]=c1; }
// create water start points for next frame
water.num=0;
e=4; // step
for (y=1;y<ys-2;y+=e)
for (x=1;x<xs-2;x+=e)
if ((pyx[y-1][x-1]==c1) // enough water around (x,y)?
&&(pyx[y-1][x ]==c1)
&&(pyx[y-1][x+1]==c1)
&&(pyx[y ][x-1]==c1)
&&(pyx[y ][x ]==c1)
&&(pyx[y ][x+1]==c1)
&&(pyx[y+1][x-1]==c1)
&&(pyx[y+1][x ]==c1)
&&(pyx[y+1][x+1]==c1))
{
// convert pixel(x,y) -> World(x,y)
a[0]=divide(2.0*x,xs)-1.0;
a[1]=divide(2.0*y,ys)-1.0;
a[2]=0.0;
matrix_mul_vector(a,iview,a);
water.add(a[0]);
water.add(a[1]);
}
// [ copy CPU image back to GL texture ]
delete[] pyx; // release ScanLines no need for them anymore
scr.txrs.txr.rgb2bgr(); // I got RGB/BGR mismatch somewhere
scr.txrs.txr_st(txr_map); // scr.txrs.txr.txr holds pointer to 32bit pixel data
scr.exe();
// [ render texture to screen ]
scr.cls();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
scr.txrs.bind(txr_map);
glColor3f(1.0,1.0,1.0);
glBegin(GL_QUADS);
glTexCoord2f(0.0,0.0); glVertex2f(-1.0,-1.0);
glTexCoord2f(1.0,0.0); glVertex2f(+1.0,-1.0);
glTexCoord2f(1.0,1.0); glVertex2f(+1.0,+1.0);
glTexCoord2f(0.0,1.0); glVertex2f(-1.0,+1.0);
glEnd();
scr.txrs.unbind();
// [info]
glColor3f(1.0,1.0,1.0);
scr.text_init_pix(1.0);
scr.text(tcpu);
scr.text(tgpu);
scr.text_exit();
scr.exe();
scr.rfs();
tend(); tcpu=" CPU time: "+tstr(1);
tim.tend();
}
//---------------------------------------------------------------------------
void TMain::mouse(double x,double y,TShiftState sh)
{
x=divide(2.0*x,scr.xs)-1.0;
y=1.0-divide(2.0*y,scr.ys);
if (sh.Contains(ssLeft))
{
viewx+=x-mx;
viewy+=y-my;
view_compute();
_redraw=true;
}
mx=x;
my=y;
}
//---------------------------------------------------------------------------
__fastcall TMain::TMain(TComponent* Owner) : TForm(Owner)
{
scr.init(this);
txr_map=fbo.add(scr);
// map_load_csv("map.csv");
// map_save_bin("map.bin");
map_load_bin("map.bin");
map_bbox();
view_compute();
draw();
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormDestroy(TObject *Sender)
{
scr.exit();
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormPaint(TObject *Sender)
{
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormResize(TObject *Sender)
{
scr.resize();
fbo.resize(scr);
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
{
if (Shift.Contains(ssShift))
{
if (WheelDelta>0) index++; else index--;
if (index>=polygon.num) index=polygon.num-1;
if (index<0) index=0;
_redraw=true;
}
else{
double p[3]={ mx,my,0.0 };
view_compute();
matrix_mul_vector(p,iview,p);
if (WheelDelta>0) zoom*=dzoom; else zoom/=dzoom;
view_compute();
matrix_mul_vector(p,view,p);
viewx-=p[0]-mx;
viewy-=p[1]-my;
view_compute();
_redraw=true;
}
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormMouseMove(TObject *Sender, TShiftState Shift, int X,int Y) { mouse(X,Y,Shift); }
void __fastcall TMain::FormMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { mouse(X,Y,Shift); }
void __fastcall TMain::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { mouse(X,Y,Shift); }
//---------------------------------------------------------------------------
void __fastcall TMain::Timer1Timer(TObject *Sender)
{
tgpu=AnsiString().sprintf(" GPU time: [%8.3lf ms]",tim.time());
if (_redraw) { draw(); _redraw=false; }
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormDblClick(TObject *Sender)
{
Width+=10; // ignore this had some bug in resize FBO texture and this was for debugging it
}
//---------------------------------------------------------------------------
我也用我的動態列表模板,以便:
List<double> xxx;
相同double xxx[];
xxx.add(5);
增加5
結束的列表
xxx[7]
訪問數組元素(保險箱)
xxx.dat[7]
訪問ar光元件(不安全的,但快速直達)
xxx.num
是數組
xxx.reset()
的實際使用的大小將清除陣列,並設置xxx.num=0
xxx.allocate(100)
爲100
項目
如果您需要的矩陣和向量幫忙預分配的空間數學例程看到這一點:
在底部,你可以找到連C++實現我使用鏈接的答案...
可以忽略VCL東西的應用程序只需要在它的單定時器間隔40 ms
如果需要重畫,並獲取如果準備好測量GL時間...
對你來說重要的東西只是draw()
例程。
它的工作原理是這樣的:
- 綁定FBO,使渲染
texture
- 明確其與
land color
呈現多邊形與edge color
勾勒如果你有孔使其與watter color
和填充後渲染他們再與edge color
在第一幀,你應該有鑑於未放大,因此所有的土地被包圍瓦爾特渲染瓦爾特起點與watter color
。所以第一個watter點是紋理的邊界矩形。
解除綁定FBO和紋理PixelData取出複製到CPU端內存
增長填滿所有瓦爾特到land color
像素(停止edge color
或任何其他)
您可以使用任何填補像洪水填充,分段線填充等,但謹慎堆棧溢出遞歸方法。我決定用:
因爲它是重複的。它並不是那麼快(因此CPU時間很大,但CPU時間的大部分是由GPU/CPU之間的紋理傳輸同步引起的),但通過將圖像細分爲「方形」區域並在需要時傳播填充可顯着加速。
從該映像創建瓦爾特起點
所以掃描整個圖像(有一些步驟不需要掃描所有點),如果發現瓦爾特其添加爲瓦爾特起點watter
爲下一幀(在世界座標)。這很好的工作,直到你的看法不會改變太多幀,所以限制縮放變化和平移步驟...
當新的幀包含watter沒有任何起點和其他watter不可訪問時,這裏出現gfx問題。這需要一些思考/測試,但我認爲它應該可以通過從第一幀獲得的一些靜態預定義的watter起始點(每個多邊形很少)解決。
直接呈現CPU側圖像或傳回給GL質地和渲染。
這裏預覽:
又一想我是多久你打的鑲嵌。你能在其他一半的框架上運行tesselation嗎? –
我只爲每個圖表稱呼它一次 –