Elements
-
Hallo,
ich erzeuge ein Netz mittels Highmap dafür nutze ich VBO's und rendere das
Netz über eine Indextabelle.Nun konnte ich lediglich 2 Vertice von 6 benötigten ecken via
GL_TRIANGLES einsparen, es liegen jedoch noch viel mehr Eckwete
an doppelten Positionen, wie kann der Indexbuffer nun optimiert
werden um drastische Ecküberlagerungen zu rationalisieren ?Hier der Triangle Generator mit einsparung mit nur zweier doppelecken:
//m_pIdx=indexarray m_pVert=verticearray m_pTVert=texcoordarray bool CTerrain::MakeTriangle(void) { int nIdx(0),nId(0); for(register WORD nY(0); nY < m_height-m_stp; nY += (int) m_stp ) for(register WORD nX(0); nX < m_width-m_stp; nX += (int) m_stp ) for(register WORD n(0),p1(0),p2(0); n < 6; n++ )//1 quad = 2 triangles = 6 edges and edge 3&5 exists twice { register WORD X(nX+(n==1||n==2||n==5?m_stp:0)); register WORD y(nY+(n==2||n==4||n==5?m_stp:0)); if(n == 3) m_pIdx[nId++] = nIdx-3;//this x,y is the same as nIdx else if(n == 5) m_pIdx[nId++] = nIdx-2;//this x,y is the same as nIdx else m_pIdx[nId++] = nIdx; //new x,y if(n!=3&&n!=5) //6edges - 2 block edge 3&5 to save memory { m_pVert[nIdx].x = X - (m_width>>1); m_pVert[nIdx].y = y - (m_height>>1); m_pVert[nIdx].z = GetHVal(X,y);//get z from highmap m_pTVert[nIdx].u = (float)X / m_width; m_pTVert[nIdx].v = (float)y / m_height; nIdx++;//next vertice } } return true; }
Danke für Hinweise
-
- Generier erstmal nur dein Grid aus Vertices und erzeug die Indices, die die Vertices zu Dreiecken verbinden, dann in einem extra Schritt.
- Spar dir den
register
Kram. - Warum
WORD
statt einfachint
?
-
Es wurde natürlich längst mit den VBO's im ganzen stück gerendert.
hier die Auflösung, mit dynamischer index erzeugung. funktioniert
reduziert die Datenmenge um ein drittel.Warum register.. warum Word.. warum nicht ?
bool CTerrain::MakeTriangle(void) { int nIdx(0),nId(0),cnt(0); for(register WORD nY(1); nY < m_height-m_stp; nY += (int) m_stp ) for(register WORD nX(0); nX < m_width-m_stp; nX += (int) m_stp ) for(register WORD n(0),p1(0),p2(0); n < 6; n++ )//1 quad = 2 triangles = 6 edges and edge 3&5 exists twice { register WORD x(nX+(n==1||n==2||n==5?m_stp:0)); register WORD y(nY+(n==2||n==4||n==5?m_stp:0)); if(n == 3) m_pIdx[nId] = nIdx-3;//this x,y is the same as nIdx else if(n == 5) m_pIdx[nId] = nIdx-2;//this x,y is the same as nIdx else m_pIdx[nId] = nIdx; //new x,y if((n == 1 || n == 4)) //can find latest same points in row below ? { DWORD id((((DWORD)m_width*(y-1))+x)*6); if(m_pIdx[id])m_pIdx[nId] = m_pIdx[id]; } if(m_pIdx[nId] == nIdx) //(n!=5 && n!=3)) //6edges - 2 block edge 3&5 to save memory { m_pVert[nIdx].x = x - (m_width>>1); m_pVert[nIdx].y = y - (m_height>>1); m_pVert[nIdx].z = GetHVal(x,y);//get z from highmap m_pTVert[nIdx].u = (float)x / m_width; m_pTVert[nIdx].v = (float)y / m_height; nIdx++;//next vertice } nId++; } DWORD vertice_ersparnis(m_idsz-nIdx); return true; }
-
Ich bin etwas verwirrt, wenn eh alles funktioniert, was ist dann eigentlich genau deine Frage!?
Karsten Schulz schrieb:
Warum register.. warum Word.. warum nicht ?
Imo machen die ganzen
register
den Code da unnötig unleserlich (der Compiler ignoriert sie wohl sowieso). Und es gibt dort keinen besonderen Grund,WORD
zu verwenden, erst recht nicht in Zusammenhang mitregister
, also würd ich den nativen Integertyp verwenden und der istint
.
-
lächelt
-
Naja, meine Lösung würde wohl so aussehen:
{ const int num_vertices = xres * yres; const float du = 1.0f / xres; const float dv = 1.0f / yres; float v = 0.0f; for (int j = 0; j < xres; ++j, v += dv) { float u = 0.0f; for (int i = 0; i < yres; ++i, u += du;) { vertices[j * xres + i].x = u * xscale + xoffset; vertices[j * xres + i].y = v * yscale + yoffset; } } const int num_quads = (xres - 1) * (yres - 1); const int num_indices = num_quads * 6; int index = 0; for (int j = 0; j < yres - 1; ++j) for (int i = 0; i < xres - 1; ++i) { indices[index++] = j * xres + i; indices[index++] = (j + 1) * xres + i; indices[index++] = j * xres + i + 1; indices[index++] = (j + 1) * xres + i; indices[index++] = (j + 1) * xres + i + 1; indices[index++] = j * xres + i + 1; } }
Find ich jetzt nicht nur um einiges lesbarer, sondern ist wohl auch flexibler.
-
Du ich date das Netz in Echtzeit auf einer solar rechenanlage ab,
keine Zeit die vertice menge zweimal durchlaufen zu müssen.
-
Um ok. Ka was für eine CPU du da hast und wie gut der Compiler ist, aber bist du dir sicher, dass diese ganzen Branches in der inner Loop tatsächlich besser sind als getrennte Schleifen!? Die Indexberechnung lässt sich außerdem problemlos mit den Vertices in die selbe Schleife packen, es braucht dazu nur ein einziges if:
{ const int num_vertices = xres * yres; const int num_quads = (xres - 1) * (yres - 1); const int num_indices = num_quads * 6; const float du = 1.0f / xres; const float dv = 1.0f / yres; int index = 0; float v = 0.0f; for (int j = 0; j < xres; ++j, v += dv) { float u = 0.0f; for (int i = 0; i < yres; ++i, u += du;) { vertices[j * xres + i].x = u * xscale + xoffset; vertices[j * xres + i].y = v * yscale + yoffset; if (j < (yres - 1) && i < (xres - 1)) { indices[index++] = j * xres + i; indices[index++] = (j + 1) * xres + i; indices[index++] = j * xres + i + 1; indices[index++] = (j + 1) * xres + i; indices[index++] = (j + 1) * xres + i + 1; indices[index++] = j * xres + i + 1; } } } }
Man könnte da oben außerdem praktisch alle Multiplikationen durch inkrementelle Additionen ersetzen.
-
naja im moment zieht diese loop , ich bin dabei diese zu optimieren,
wird noch dauern.. aber danke für deine Hinweise, das untere liefert
gerade zügige Ergebnise,und richtig die muls kommen weg
DWORD CTerrain::MakeTriangle(void) { register DWORD nIdx(0),nId(0); for(register WORD nY(m_stp),x,y; nY < m_height-m_stp; nY += m_stp ) for(register WORD nX(0); nX < m_width-m_stp; nX += m_stp ) for(register WORD n(0),p1(0),p2(0); n < 6; n++ )//1 quad = 2 triangles = 6 edges and edge 3&5 exists twice { switch(n) { case 0:x=nX,y=nY,m_pIdx[nId] = nIdx;break; case 1:{ y=nY,x=nX+m_stp,m_pIdx[nId] = nIdx; register DWORD id(((((DWORD)m_width*(y-1))+x)*6)/(m_stp*m_stp)); m_pIdx[nId]=m_pIdx[id]?m_pIdx[id]:nIdx; } break; case 2:x=nX+m_stp,y=nY+m_stp,m_pIdx[nId]=nIdx; break; case 3:x=nX,y=nY,m_pIdx[nId]=nIdx-3;break; case 4:{ x=nX,y=nY+m_stp,m_pIdx[nId] = nIdx; register DWORD id(((((DWORD)m_width*(y-1))+x)*6)/(m_stp*m_stp)); m_pIdx[nId]=m_pIdx[id]?m_pIdx[id]:nIdx; }break; case 5:x=nX+m_stp,y=nY+m_stp,m_pIdx[nId] = nIdx-2;//this x,y is the same as nIdx break; }; if(m_pIdx[nId] == nIdx) { m_pVert[nIdx].x = x - (m_width>>1); m_pVert[nIdx].y = y - (m_height>>1); m_pVert[nIdx].z = GetHVal(x,y);//get z from highmap m_pTVert[nIdx].u = (float)x / m_width; m_pTVert[nIdx].v = (float)y / m_height; nIdx++;//next vertice } nId++; } DWORD vertice_ersparnis(m_idsz-nIdx); return nIdx; }
-
Außerdem ist der Vertice count gewinn bei deiner loop NULL
-
Man könnte die verschachtelte Schleife überhaupt loswerden und die Indexberechnung mit % und / anstellen. Wenn die Auflösung des Gitters eine Zweierpotenz ist, sollte der Compiler % und / über triviale Bitoperationen implementieren.
Karsten Schulz schrieb:
Außerdem ist der Vertice count gewinn bei deiner loop NULL
Was genau meinst du damit? Weniger als xres * yres Vertices geht doch gar nicht mehr!?
-
aber natürlich, viele der eckwerte im netz sind indetisch , und
können durch die indextabelle mehrmals indiziert werden, somit
spare ich im VBO massig daten. Ich hatte vorher ein TRIANGLE_STRIP
netz, leider bereitet die geometire dann mehr probs als nutzen.Daher nun der Umbau auf vertice -Elements klar der index buffer
enthält für jeden vertice einen index, aber die anzahl der vertices
im VBO ist wesentlich geringer als bei width*height
-
Karsten Schulz schrieb:
aber natürlich, viele der eckwerte im netz sind indetisch, und können durch die indextabelle mehrmals indiziert werden, [...]
Exakt. Und dann braucht man genau xres * yres Vertices, statt (xres - 1) * (yres - 1) * 6 ...
-
Sehr gut, ich verwende deine loop.
thx
-
Okay.. also nun hab ich das optimal , danke für deine Mithilfe
DWORD CTerrain::MakeTriangle(void) { register GLuint *pIdx(m_pIdx),Off; for(register WORD y = 0; y < m_height; y+=m_stp) for(register WORD x = 0; x < m_width; x+=m_stp) { Off = y * m_width + x; m_pTVert[Off].u = (float)x/m_width; m_pTVert[Off].v = (float)y/m_height; m_pVert[Off].y = y; m_pVert[Off].x = x; m_pVert[Off].z = GetHVal(x,y); if(y<m_height-1 && x<m_width-1) { *pIdx++ = Off; *pIdx++ = (y + 1) * m_width + x; *pIdx++ = Off + 1; *pIdx++ = (y + 1) * m_width + x; *pIdx++ = (y + 1) * m_width + x + 1; *pIdx++ = Off + 1; } } return m_width*m_height;//^^ }