ASSIMP - Vertices und Indices extrahieren

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Jonsc1
Beiträge: 19
Registriert: 14.08.2006, 18:51

ASSIMP - Vertices und Indices extrahieren

Beitrag von Jonsc1 »

Vorweg:
Ja, ich habe noch einen anderen Thread am laufen :)
Aber dieses Thema hier hat absolut nichts mit meiner anderen Frage zu tun, also vergebt mir wenn ich einen extra Thread dafür eröffne.

Ich benutze ASSIMP um unter DirectX10 (C++) ein .x -File zu lesen und die darin enthaltene Geometrie zu rendern.
Da es mir zu Beginn sehr schwer fand mich einzulesen habe ich mich entschlossen ein File zu laden dass eine Kugel enthält, die nur aus einem Mesh besteht.
So umgehe ich erstmal die ganzen dynamischen Anpassungen und mach alles "von Hand", um ein wenig damit experimentieren zu können, und implementiere das später anständig.

Es ist mir gelungen Vertex und Indexdaten zu extrahieren, Vertexdaten auch offensichtlich richtig, wenn ich sie POINTLIST rendere erhalte ich eine Kugel (bestehend aus Punkten natürlich).
Wenn ich nun aber meine extrahierten Indices dazu nehme, und DrawIndexed verwende, kommt Murks raus. Es funktioniert, aber das Ergebniss ist keine Kugel, gerade so als würden Vertices und Indices nicht zusammenpassen.

Hier mein (etwas unschöner) Code:
erst die Vertices:

Code: Alles auswählen

scene = importer.ReadFile("kugel.x", 
		aiProcess_CalcTangentSpace       | 
        aiProcess_Triangulate            |
        aiProcess_JoinIdenticalVertices  |
        aiProcess_SortByPType);

	if (!scene)
		ISENEXCEPTION("importer.ReadFile");

	const aiMesh* mesh = scene->mMeshes[0];  // Der Einfachheit halber erstmal nur Mesh[0] auslesen
	m_numVertices = mesh->mNumVertices;
	m_numFaces = mesh->mNumFaces;

	// Vertexbuffer erstellen
    D3D10_BUFFER_DESC vbd;
    vbd.Usage = D3D10_USAGE_DYNAMIC;
    vbd.ByteWidth = sizeof(VERTEX) * m_numVertices;      // grösse des buffer abhängig von anzahl d. vertices und grösse d. vertexstruktur
    vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    vbd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    vbd.MiscFlags = 0;

    if(FAILED(m_pDevice->CreateBuffer(&vbd, NULL, &m_vertexBuffer)))
		ISENEXCEPTION("m_pDevice->CreateBuffer");
	
	// Vertices erstellen
	void* pVoid;
	VERTEX *Vertices = new VERTEX[m_numVertices];  

	for(int a = 0; a < m_numVertices; ++a)
	{
	Vertices[a].Position.x = mesh->mVertices[a].x;
	Vertices[a].Position.y = mesh->mVertices[a].y;
	Vertices[a].Position.z = mesh->mVertices[a].z;
	Vertices[a].Color = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);
	}
	
	// Kopiere Vertices in Vertexbuffer
	if(FAILED(m_vertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid)))   // map the index buffer
		ISENEXCEPTION("m_vertexBuffer->Map");
	memcpy(pVoid, Vertices, sizeof(VERTEX)*m_numVertices );    // copy the indices to the buffer
    m_vertexBuffer->Unmap();

	delete Vertices;
	Vertices = NULL;


bis hierhin scheint alles gut zu laufen, die Daten passen zumindest mal....
nun die Indices (selbe Funktion)

Code: Alles auswählen

// Indexbuffer erstellen
    D3D10_BUFFER_DESC ibd;
    ibd.Usage = D3D10_USAGE_DYNAMIC;
    ibd.ByteWidth = sizeof(DWORD) * m_numFaces*3;   // welche grösse -> wie viele indices  *2 wegen doppelt so vielen dreiecken
    ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    ibd.MiscFlags = 0;

     m_pDevice->CreateBuffer(&ibd, NULL, &m_indexBuffer);


	// Extrahiere Indices
	DWORD* Indices = new DWORD[m_numFaces*3];

	int tmp = 0;
	for(int a = 0; a < m_numFaces; ++a)
	{
	Indices[tmp] = mesh->mFaces[a].mIndices[0];
	Indices[tmp+1] = mesh->mFaces[a].mIndices[1];
	Indices[tmp+2] = mesh->mFaces[a].mIndices[2];
	tmp+=3;
	}

	// Kopiere Indices in Indexbuffer
    m_indexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid);   // map the index buffer
    memcpy(pVoid, Indices, sizeof(Indices));			  // copy the indices to the buffer
    m_indexBuffer->Unmap();

	delete Indices;
	Indices = NULL;
Ich denke der Fehler muss in meiner Routine liegen die die Indices auswertet... irgendwie scheine ich da was verwechselt zu haben.
Aber egal wie oft ich das kontrolliere, für mich macht es absolut Sinn. Vielleicht habe ich auch einfach etwas falsch verstanden?
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von kimmi »

Das sieht auch für mich richtig aus. Wie renderst du den ganzen Kram? Ist da vielleicht der Fehler? Und hast du einen Screenshot? Vielleicht erkennt man da mehr, wo das Problem herkommen könnte.

Gruß Kimmi
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von Schrompf »

Nein, das ist grober Unsinn. Allerdings nicht auf Assimp-Seite - Du hast das Prinzip völlig korrekt verstanden. Nur Dein memcpy() für die Indizes ist Murks. Bei den Vertizes hast Du die Größe des zu kopierenden Speicherblocks korrekt angegeben: sizeof(VERTEX)*m_numVertices. Bei den Indizes dagegen hast Du nur sizeof( Indices) als Größe angegeben. Und was ist "Indices"? Ein Zeiger. Also ist sizeof( Zeiger) 4 Byte bzw. 8 Byte bei ner 64Bit-Exe. Du kopierst also quasi nichts. Korrekterweise müsste da genauso sizeof( unsigned int) * mNumIndices stehen.

Meine Empfehlung wäre übrigens, das new[] komplett seinzulassen. Nimm stattdessen einen std::vector. Damit kannst Du gleichzeitig den IndexBuffer-Inhalt zusammenstellen und durchzählen, wieviele Indices es gibt.

Code: Alles auswählen

std::vector<unsigned int> indices;
indices.reserve( mNumFaces*3); // reicht als grobe Abschätzung

for( size_t a = 0; a < mesh->mNumFaces; ++a)
{
  const aiFace* face = mesh->mFaces + a;
  // alles außer Dreiecke wird ignoriert.
  if( face->mNumIndices != 3)
    continue;

  indices.push_back( face->mIndices[0]);
  indices.push_back( face->mIndices[1]);
  indices.push_back( face->mIndices[2]);
}

// und das kannst Du dann gleich als Speicherblock bei der Erzeugung des IndexBuffers benutzen.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von kimmi »

Ops, Den memcpy-Fehler hab ich gar nicht gesehen :). Um den std::vector-Copy noch vollständig darzustellen: der memcpy mit std::vector wäre memcpy(pVoid, Indices, sizeof(unsigned int) * indices.size() );

Gruß Kimmi
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von Schrompf »

Das stimmt. Ich würde allerdings empfehlen, den Inhalt von Vertex- und IndexBuffer vorher zusammenzustellen, um dann den Speicherblock gleich bei der Erzeugung des jeweiligen Buffers anzugeben. Direct3D10 hat dafür einen speziellen Pfad vorgesehen, der ein bisschen effizienter als USAGE_DYNAMIC und das Mappen sein dürfte.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Jonsc1
Beiträge: 19
Registriert: 14.08.2006, 18:51

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von Jonsc1 »

Hi
Danke für die Antworten, ihr hattet natürlich recht.
Ich war erst ein wenig frustriert weil es immernoch Müll gerendert hat, nur um dann festzustellen dass ich in meiner render-Funktion gar keinen Indexbuffer setze (sondern der vom Terrain benutzt wird) ;)
Werde mir das mit std::vector mal anschauen, habe halt wenig Erfahrung mit der STL, nutze bisher eigentlich fast nur std::string... :roll:
Das stimmt. Ich würde allerdings empfehlen, den Inhalt von Vertex- und IndexBuffer vorher zusammenzustellen, um dann den Speicherblock gleich bei der Erzeugung des jeweiligen Buffers anzugeben. Direct3D10 hat dafür einen speziellen Pfad vorgesehen, der ein bisschen effizienter als USAGE_DYNAMIC und das Mappen sein dürfte.
Was hat es damit genau auf sich?
Ich kenn es nur so wie ich es gemacht habe, hab das noch nirgendwo anders gesehen.
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von Schrompf »

Oh doch, ich bin mir sicher, dass das an vielen anderen Ecken so gemacht wird. Du gibst einfach den Inhalt als zweiten Parameter von CreateBuffer() an - da, wo Du bisher nur NULL übergibst. Dann kannst Du die Resource auch mit D3D10_USAGE_IMMUTABLE erzeugen und braucht keine CPU-Zugriffsmöglichkeiten mehr. Das erlaubt dem Treiber evtl. weitere Optimierungen.

Im Detail kenne ich mich damit aber nicht aus, ich habe noch kein D3D10 benutzt. Schau Dir mal die Doku zu CreateBuffer() an, dann müsste es klarer werden.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von Krishty »

Korrekt – in D3D9 war der Weg immer: Erzeugen (GPU) -> sperren, füllen, entsperren (CPU) -> rendern (GPU). Dadurch mussten auch Ressourcen, die man exklusiv auf der GPU benutzt hat, einmal zur CPU und wieder zurück zur GPU übertragen werden (obwohl die Treiber da sicher optimiert haben).
In D3D10 gibst du per D3D10_SUBRESOURCE_DATA direkt beim Erzeugen an, welche Daten in der Ressource sein sollen. Die wandern dann auf die GPU und nie wieder zurück. Für Vertex- oder Indexdaten gibst du dort die Basisadresse deines Arrays an (die beiden anderen Felder sind nur für Texturen von Bedeutung) und fertig.

Sicher, dass du D3D10 benutzen willst, und nicht D3D11? D3D11 bietet mehr Features, hat größeren Hardware-Support und in 99,9 % der Fälle kannst du allen D3D10-Code übernehmen, indem du das D3D10_* / ID3D10* am Anfang der Bezeichner durch D3D11* / ID3D11* ersetzt …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jonsc1
Beiträge: 19
Registriert: 14.08.2006, 18:51

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von Jonsc1 »

DX11 habe ich nicht initialisiert bekommen... obwohl ich den Code teilweise 1zu1 aus der Doku kopiert habe... denke es ist am Shader-Modell 5.0 gescheitert, dass meine Karte nicht unterstützt (war etwas faul bei der Enumeration).

Ich habe nun angefangen das ganze laden dynamisch zu machen (hab mit sowas kaum Erfahrung, aber die gute Doku hat mir sehr geholfen)
Seltsam finde ich nur, dass anscheinend meinen Sub-Meshes (die ASSIMP ja automatisch generiert wenn ein Mesh verschiedene Materialien (Texturen) verwendet) die FALSCHEN Texturen zugewiesen bekommen.
Ein Submesh wird so letzendlich mit der Textur eines anderen Submeshes gerendert.
Mein Code sollte allerdings soweit korrekt sein, aber wie gesagt, hab sowas noch nie gemacht.

EDIT2: hier zwei Screens die das Problem verdeutlichen (anhand des Modells spider.obj aus dem Assimp-Ordner)

So sollte es sein:
Bild


So ist es: (nicht durch das Koordinatenkreuz irritieren lassen)
Bild


Entschuldigung im Vorraus für die etwas lange Funktion, ich sollte sie event. noch in ein paar Funktionen zerlegen.

Code: Alles auswählen

void ISEN_Mesh::loadFromFile(std::string file)
{
	
	pTextureVariable = m_pEffect->GetVariableByName("Texture")->AsShaderResource();
	
	scene = importer.ReadFile(file.c_str(),		// Lade Modelldatei
		aiProcess_CalcTangentSpace       | 
        aiProcess_Triangulate            |
        aiProcess_JoinIdenticalVertices  |
		aiProcess_MakeLeftHanded		 |		// wegen DX
        aiProcess_SortByPType);

	if (!scene)									// Öffnen fehlgeschlagen
		ISENEXCEPTION("importer.ReadFile");		// -> throw exception

	drawIndexed = true;    // rendere später mit Indexbuffer

	numSubmeshes = scene->mNumMeshes;		// hole Anzahl der Sub-Meshes...
	submeshes = new SUBMESH[numSubmeshes];	// ... und reserviere Speicher für sie

	for(int i=0; i<numSubmeshes; i++)		// gehe Sub-Meshes Stück für Stück durch
	{
		const aiMesh* mesh = scene->mMeshes[i];  // i-tes Mesh holen

		// Texturpfad für das Submesh extrahieren (Diffuse-Textur) und speichern
		aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];  // das zum Sub-Mesh passende Material holen
		aiString texpath;
		mat->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE,0) ,texpath);	// Texturpfad der Diffusen Textur extrahieren...
		submeshes[i].texturepath = texpath.data;						// ... und speichern
		
		D3DX10CreateShaderResourceViewFromFile(m_pDevice,				// Textur laden und speichern (Optimierung: Texturmanager?)				
                                       s2ws(submeshes[i].texturepath.c_str() ).c_str() ,    
                                       NULL,						
                                       NULL,						
				       &submeshes[i].pTexture,		
                                       NULL); 

[.... Vertexdaten extrahieren und in Vertexbuffer des Submeshes kopieren ... ]
[... Indexdaten extrahieren und in Indexbuffer des Submeshes kopieren ... ]


EDIT:
Der Rendercode:

Code: Alles auswählen

if(drawIndexed)
	{
		for(int i = 0; i < numSubmeshes; i++)
		{
			m_pDevice->IASetVertexBuffers(0, 1, &submeshes[i].vertexBuffer , &stride, &offset);
			m_pDevice->IASetIndexBuffer(submeshes[i].indexBuffer, DXGI_FORMAT_R32_UINT, 0);
			// apply pass
			if( FAILED(m_pPass->Apply(0)))
				ISENEXCEPTION("mpPass->Apply");
			// setze textur
			pTextureVariable->SetResource(submeshes[i].pTexture);
			m_pDevice->DrawIndexed(submeshes[i].numIndices , 0, 0);  
		}
	}
Jonsc1
Beiträge: 19
Registriert: 14.08.2006, 18:51

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von Jonsc1 »

Ich habe mich sehr drauf festgebissen dass der Fehler irgendwo dort geschehen muss wo die Texturen erzeugt werden (und ich schliesse nicht aus dass ich dort ebenfalls Fehler drin habe -.-)
aber ich habe festgestellt dass es an der Stelle an der ich die Texturkoordinaten extrahiere ebenfalls hapert.

Code: Alles auswählen

for(int a = 0; a < submeshes[i].numVertices; ++a)
{
	Vertices[a].Position.x = mesh->mVertices[a].x;
	Vertices[a].Position.y = mesh->mVertices[a].y;
	Vertices[a].Position.z = mesh->mVertices[a].z;
	Vertices[a].Color = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);
	Vertices[a].v = mesh->mTextureCoords[0][a].x;
	Vertices[a].u = mesh->mTextureCoords[0][a].y;
}
Verices[a].v und Vertices[a].u enthalten danach aber lediglich 0, sämtliche Werte :/
Jonsc1
Beiträge: 19
Registriert: 14.08.2006, 18:51

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von Jonsc1 »

Selbe Datei, selber Code, KEINE ÄNDERUNG... einen Tag später: ich bekomm Texturkoordinaten... aber das Renderergebnis ist immernoch Mist und ich bekomm den Fehler nicht raus :/

EDIT:
Die Sache mit den Texturkoordinaten passt jetzt, solange ich eine Datei lade die nur in EIN Submesh zerlegt wird. Dann wird die Textur richtig gemappt:
Bild

Wenn ich allerdings Dateien mit mehreren verschiedenen Texturen laden werden die Texturen noch immer "verwechselt", die Submeshs bekommen die Textur eines anderen Submeshs... :cry:

EDIT2:
Um das nochmal zu verdeutlichen, die Texturen auf der Spinne sind nun nicht mehr um 90* gedreht, allerdings immernoch vertauscht:
Bild
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von kimmi »

Erst einmal: bei den Texturkoordinaten sollten du prüfen, ob diese überhaupt vorhanden sind. Code hierzu habe ich gerade nicht im Kopf, aber in den Beispielen von Assimp solltest du dazu mehr finden. Dieser Check fehlt in deinem Code. Du gehst du immer davon aus, dass nur Level-0-Texturkoordinaten da sind. Dieses muss so nicht sein.
Dann kann ich von dem Kopieren der Vertices, was du an Code gepostest hast, keinen wirklichen Fehler sehen. Ich tippe darauf, dass sich der Fehler woanders im Code versteckt.
Prüfen könntest du:
  • Stimmt deine Zuordnung von Vertices zu Submesh, wenn gerade hier der Fehler auftritt.
  • Wie schauen die Submeshes einzelnd gerendert auf, kannst du die Daten dort grob sichten?
Versuche das Ganze erst einmal in einem kleinen Beispiel wie einem Würfel mit mehreren Submeshes zu testen. Das ist zum Debugging leichter verständlich.

Gruß Kimmi
Jonsc1
Beiträge: 19
Registriert: 14.08.2006, 18:51

Re: ASSIMP - Vertices und Indices extrahieren

Beitrag von Jonsc1 »

Hey, danke für deine Antwort.
Habe den Fehler nun gefunden, er steckte in der Renderfunktion:

Code: Alles auswählen

if(drawIndexed)
{
for(int i = 0; i < numSubmeshes; i++)
{
m_pDevice->IASetVertexBuffers(0, 1, &submeshes[i].vertexBuffer , &stride, &offset);
m_pDevice->IASetIndexBuffer(submeshes[i].indexBuffer, DXGI_FORMAT_R32_UINT, 0);
// apply pass
if( FAILED(m_pPass->Apply(0)))
ISENEXCEPTION("mpPass->Apply");
// setze textur
pTextureVariable->SetResource(submeshes[i].pTexture);
m_pDevice->DrawIndexed(submeshes[i].numIndices , 0, 0); 
SetResource wurde erst NACH m_pPass->Apply angewendet, somit wurde die Textur erst im nächsten Schleifendurchlauf gesetzt.
Andersrum gibt es nun keine Probleme mehr und alles rendert wie es soll.
Fehlerabfragen baue ich jetzt natürlich auch noch ein :)
Antworten