vb füllen -> fps extrem runter?



  • Hallo!

    Nachdem ich das Problem mit der Belichtung gelöst habe 🙂 kommt ein nächstes.

    Ich möchte jetzt ein terrain rendern, welches nicht in den speicher passt, erstmal Brute-Force mäßig ohne LOD und so. Dazu hab ich mir das so überlegt:

    eine Klasse Heightmap bekommt eine Datei vorgesetzt die die Höhendaten enthält, und diese Klasse ist dafür zuständig, die Daten zu laden und wenn sie nicht mehr gebraucht werden wieder zu löschen um neue Daten zu laden. dann gibts die Klasse BFTerrain, welche auf die Heightmap zugreift und in jedem Frame die Heightmap fagt, wie hoch es an den einzelnen Stellen ist und dann mit diesen Inormationen einen VB füllt.

    aber das Problem ist, dass das füllen des VB viel zu lange dauert. Wenn ich nur 8k dreiecke rendere (mit quadtree gecullt), gehn die fps schon auf 40 runter. Mein Profiler sagt, das füllen dauert 100mal so lange wie das rendern.

    In jedem Frame packe ich einfach alle Vertizes die gerendert werden müssen als trianglelist in den VB und render die dann auf einmal. Der VB ist schon dynamisch und mit discard gelockt, also da kann man glaub ich nichts mehr rausholen. Warum dauert das füllen dann so lange?



  • Maxi schrieb:

    aber das Problem ist, dass das füllen des VB viel zu lange dauert. Wenn ich nur 8k dreiecke rendere (mit quadtree gecullt), gehn die fps schon auf 40 runter.

    Na das ist ja klar.

    Bye, TGGC (Das Eine, welches ist.)



  • Hi,

    klar kann man da mehr rausholen 🙂

    Bei den dynamischen Buffern nicht immer ein DISCARD machen, dann hat der dynamische Buffer auch wenig Sinn. Das NOOVERWRITE Flag ist dazu da, dass man gleichzeitig Daten in den Buffer schreiben kann während noch andere Daten aus dem Buffer gerendert werden.

    Mann kann auch darüber nachdenken, schon wesentlich mehr Vertex-Daten in den Vertex-Buffer zu schreiben und nur die Indices zu verändern bzw. ein anderes Offset bei den Indices zu verwenden, so dass man mit denselben Indices in verschiedenen Draw-Calls verschiedene Teile des Vertex-Buffers rendert.

    Ciao,
    Stefan

    PS: Bei 8000 Triangles macht so ein Sysem wenig Sinn. Man kann durchaus 100k Tris eines Terrains aus einem statischen Buffer rendern. So lange der auf der Grafikkarte sitzt geht das wesetlich schneller als wenn man in jedem Frame 8k Triangles über den Bus schiebt und dann rendert.


  • Mod

    Maxi schrieb:

    In jedem Frame packe ich einfach alle Vertizes die gerendert werden müssen als trianglelist in den VB und render die dann auf einmal. Der VB ist schon dynamisch und mit discard gelockt, also da kann man glaub ich nichts mehr rausholen. Warum dauert das füllen dann so lange?

    beim erstellen der buffer, mußt du D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY angeben.
    wenn du den ganzen Buffer beim lock überschreibst, dann am besten D3DLOCK_DISCARD.

    Locken dauert extrem lange, weil dadurch zum einen die asynchrone arbeite von graphikkarte und cpu ausgehebelt werden kann und zum anderen schafft man es einfach nicht soviele daten über den agp-bus zu schieben, wie die graka verarbeiten kann. normalerweise kommt man auf ca 2MPolys/s als ziemliches limit, meiner erfahrung nach.

    Stefan Zerbst schrieb:

    Bei den dynamischen Buffern nicht immer ein DISCARD machen, dann hat der dynamische Buffer auch wenig Sinn. Das NOOVERWRITE Flag ist dazu da, dass man gleichzeitig Daten in den Buffer schreiben kann während noch andere Daten aus dem Buffer gerendert werden.

    wenn man den buffer komplett neu füllt ist DISCARD besser, nooverwrite ist nur dazu da, wenn man den buffer mehrmals im selben frame lockt bevor man ihn benutzt, um neue daten dranzuhängen, so wie ich ihn verstanden habe macht er das nicht.

    PS: Bei 8000 Triangles macht so ein Sysem wenig Sinn. Man kann durchaus 100k Tris eines Terrains aus einem statischen Buffer rendern. So lange der auf der Grafikkarte sitzt geht das wesetlich schneller als wenn man in jedem Frame 8k Triangles über den Bus schiebt und dann rendert.

    👍 das ist auch meine meinung.
    dazu gab es auch einen schönen bashthread



  • Was? Stefan, rapso und ich sind der gleichen Meinung? Das ist doch irgendwie! (Näh?)

    Bye, TGGC (Das Eine, welches ist.)



  • ich zeig euch ma den Code, wie ich den VB mache:

    // JEtzt vb erstellen
    if(FAILED(me_g_D3D->GetDevice()->CreateVertexBuffer(sizeof(sVerts) * 6*256*256,
    	D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, FVF, D3DPOOL_DEFAULT, &m_Verts, NULL)))
    {
    	ME_ERRORLOG("Fehler beim Erstellen eines VertexBuffers!");
    	return ME_ERROR;
    }
    else
    	ME_INFOLOG("Vb erstellt");
    
    // render:
    m_Verts->Lock(0, 0, (void**)&m_VertPtr, D3DLOCK_DISCARD);
    m_NumTris = 0;
    RenderNode(m_Root);
    m_Verts->Unlock();
    
    dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, m_NumTris);
    
    meResult meBFTerrain::RenderNode(sQuad* node)
    {
    	// Testen obs zu sehen ist:
    	//float h = node->MinY + (node->MaxY - node->MinY) * m_Scaling.y;
    	float h = m_Scaling.y / 2;
    	meVector3 Pos(node->XOrig, h, node->ZOrig);
    	meVector3 Size(node->Size, m_Scaling.y / 2, node->Size);
    	if(!m_UseFrustrum->CheckBox(Pos, Size))
    		return ME_OK;
    
    	if(node->IsLeaf)
    	{
    		sVerts* v = &m_VertPtr[m_NumTris * 3];
    		int maxY = node->YOrigHM+node->HMSize.y;
    		int maxX = node->XOrigHM+node->HMSize.x;
    		if(maxY >= m_HMSize.y)
    			maxY = m_HMSize.y - 1;
    		if(maxX >= m_HMSize.x)
    			maxX = m_HMSize.x - 1;
    		for(int y = node->YOrigHM-node->HMSize.y; y < maxY; y++)
    		{
    			for(int x = node->XOrigHM-node->HMSize.x; x < maxX; x++)
    			{
    				sVerts vert;
    				vert.u1 = x / m_HMSize.x;
    				vert.v1 = y / m_HMSize.y;
    
    				meHeightMap::sHeight h;
    				m_Heightmap->GetHeightAt(x, y, h); 
    				vert.pos = meVector3(-m_Size.x / 2 + x / m_HMSize.x * m_Size.x,
    						h.Height / 255.0f,
    						-m_Size.y / 2 + y / m_HMSize.y * m_Size.y);										
    				vert.normal = h.Normal;
    				v[TOPLEFT] = vert;
    
    				m_Heightmap->GetHeightAt(x+1, y, h); 
    				vert.pos = meVector3(-m_Size.x / 2 + (x+1) / m_HMSize.x * m_Size.x,
    							h.Height / 255.0f,
    							-m_Size.y / 2 + y / m_HMSize.y * m_Size.y);
    				vert.normal = h.Normal;
    				v[TOPRIGHT_T1] = vert;
    				v[TOPRIGHT_T2] = vert;
    
    				m_Heightmap->GetHeightAt(x, y+1, h); 
    				vert.pos = meVector3(-m_Size.x / 2 + x / m_HMSize.x * m_Size.x,
    						h.Height / 255.0f,
    						-m_Size.y / 2 + (y+1) / m_HMSize.y * m_Size.y);
    
    				vert.normal = h.Normal;
    				v[BOTTOMLEFT_T1] = vert;
    				v[BOTTOMLEFT_T2] = vert;
    
    				m_Heightmap->GetHeightAt(x+1, y+1, h); 
    				vert.pos = meVector3(-m_Size.x / 2 + (x+1) / m_HMSize.x * m_Size.x,
    						h.Height / 255.0f,
    						-m_Size.y / 2 + (y+1) / m_HMSize.y * m_Size.y);
    
    				vert.normal = h.Normal;
    				v[BOTTOMRIGHT] = vert;
    
    				v+=6;
    				m_NumTris += 2;
    			}
    		}
    
    	}
    	else
    	{
    		for(int i = 0; i < 4; i++)
    			RenderNode(node->Children[i]);
    	}
    
    	return ME_OK;
    }
    

    @stefan: Ich ruf pro frame ja nur einmal drawprimitive auf, da bringts doch nichts den buffer zwischendurch zu unlocken und dann mit nooverwrite wieder zu locken.
    Wie meinst du das, dass man schon vorher viele vertizes in den Vb haut und dann nur noch mit dem IB die vertizes anspricht? in etwa so, dass ich um die Kamera ein viel größeres stück als man sehen kann in den VB haue und nur, wenn sich die Position dramatisch ändert einen neuen vb baue? aber is das nicht dann das selbe, als wenn ich in jedem Frame wenig dreiecke rüberschiebe als einmal ganz viele?
    Das mit den 8k dreiecken war ja auch nur ein Beispiel, ich schicke wenn ich alles sehe so um die 80k Dreiecke pro frame rüber, da gehts dann runter auf 20fps

    den anderen Thread werd ich mir mal durchlesen...



  • Maxi schrieb:

    in etwa so, dass ich um die Kamera ein viel größeres stück als man sehen kann in den VB haue und nur, wenn sich die Position dramatisch ändert einen neuen vb baue?

    Eher so, das du ein ganz viel größerers Stück in VBs hast und nie einen neuen baust.

    Bye, TGGC (Das Eine, welches ist.)



  • wenn jetzt aber das terrain zu groß ist, so um die 1GB oder sonstwas, dann kann ich den ganzen buffer doch nicht immer so lassen, das wär doch viel zu speicherfressend.



  • jeden frame musste ja eigentlich sowieso nicht den buffer neu erstellen.. Wenn der Benutzer sich z.b. nicht bewegt, so muss natürlich auch der buffer nicht geschrieben werden. Entsprechend kann mans ja auch so machen, dass der buffer nur dann neu beschrieben wird, wenn sich der User beispielsweise 100m vom vorigen Punkt entfernt hat..

    Aber bevor du auch mich hörst, wart mal lieber auf rapsos antwort.. Er hat wahrscheinlich wieder ne tolle Idee, wie man die x GB terriandaten in die Grafikkarte stopfen kann. Wahrscheinlich würd er erst irgend nen Komprimierungsalgorithmus über die Daten laufen lassen und dann in buffer schieben oder ähnliches... Mal abwarten 😉



  • Also bei 1 GB ist ja das Problem eher, das man von Platte streamen muss, und die ist noch etwas langsamer als der Bus zur GraKa.

    Bye, TGGC (Das Eine, welches ist.)



  • ja wie gesagt, ds streamen dauert glaub ich nich so lange, ich lad ja immer stücke mit einer größe von 256*256 in den speicher, und die bleiben dann auch da liegen, bis man sie länger nicht mehr gesehen hat. nur, wenn man ein neues stück sieht wird das geladen und bleibt dann im speicher


Anmelden zum Antworten