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 einfach int ?


  • 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 mit register , also würd ich den nativen Integertyp verwenden und der ist int .



  • 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;//^^
    }
    

Anmelden zum Antworten