Seite 1 von 1

Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 15:02
von PatrickEgli
Hi

Ich bin daran einen Assimp Loader zu schreiben. Ich will ihn mit einem Vertex- und IndexBuffer programmieren.

Mein Code sieht so aus:

Code: Alles auswählen

// AssimpLoader.h
//
#ifndef ASSIMPLOADER_HPP
#define ASSIMPLOADER_HPP

#include "D3D.h"
#include <assimp.h>
#include <assimp.hpp>
#include <aiScene.h>
#include <aiPostProcess.h>
#include <aiMaterial.h>
#include <aiVector2D.h>
#include <aiVector3D.h>
#include <string>

using namespace std;

#pragma comment(lib, "assimp.lib")

// VertexStruktur erzeugen
struct SMeshVertex
{
	D3DXVECTOR3			vPosition;
	D3DXVECTOR3			vTangent;
	D3DXVECTOR3			vNormal;
	D3DXVECTOR2			vTexture;
};

#define MeshFVF (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)

// Klasse erzeugen
class CLoader
{
private:

	const aiScene *				m_Scene;
	LPD3DXMESH					m_pMesh;
	LPDIRECT3DVERTEXBUFFER9		m_pVB;
	LPDIRECT3DVERTEXBUFFER9		m_pIB;

public:

	bool				LoadFile(PDIRECT3DDEVICE9 Device, string &Filename);
	void				Render();
	void				Release();
	D3DXVECTOR3			MakeToD3DXVector3(const aiVector3D & Vector);
	D3DXVECTOR2			MakeToD3DXVector2(const aiVector3D & Vector);

};

#endif

Code: Alles auswählen

// AssimpLoader.cpp
//
#include "AssimpLoader.h"


bool CLoader::LoadFile(LPDIRECT3DDEVICE9 Device, string &file)
{
	HRESULT hResult;
	Assimp::Importer importer;

	SMeshVertex* vertices;
	UINT numVertices;
	UINT numTriangles;
	DWORD* indices;
	UINT* attributeBuffer;

	m_Scene = importer.ReadFile( file, 
        aiProcess_CalcTangentSpace  |
        aiProcess_Triangulate |
        aiProcess_MakeLeftHanded |
        aiProcess_JoinIdenticalVertices |
        aiProcess_SortByPType |
        aiProcess_CalcTangentSpace |
        aiProcess_JoinIdenticalVertices |
        aiProcess_GenSmoothNormals |
        aiProcess_LimitBoneWeights |
        aiProcess_RemoveRedundantMaterials |
        aiProcess_OptimizeMeshes);

	if(!m_Scene)
	{	
		MessageBox(NULL, "There is a mesh missing. Please try again or reeinstall the game.", "Mesh missing", MB_OK);
		PostQuitMessage(1);
	}

	aiMesh** meshes =m_Scene->mMeshes;
	aiMaterial** materials = m_Scene->mMaterials;

	UINT* meshID;
	UINT materialID;

	aiNode* sceneRoot = m_Scene->mRootNode;
	aiNode** children = sceneRoot->mChildren;
	aiNode* child;

	UINT i = 0;
	bool rootNode = true;

	while(i < sceneRoot->mNumChildren)
	{
		if(rootNode)
		{
			child = sceneRoot;
			rootNode = false;
		} else
		{
			child = children[i];
			i++;
		}

		if(!(child->mNumMeshes > 0))
			continue;
		
		meshID = child->mMeshes;

		numVertices = meshes[meshID[0]]->mNumVertices;
		numTriangles = meshes[meshID[0]]->mNumFaces;

		if(FAILED(hResult = g_pD3DDevice->CreateVertexBuffer((numVertices * sizeof(SMeshVertex)),
															 D3DUSAGE_WRITEONLY,
															 MeshFVF,
															 D3DPOOL_MANAGED,
															 &m_pVB,
															 NULL)))
		{
			MessageBox(NULL, "Fehler beim Erzeugen des VertexBuffers vom Mesh", "Fehler aufgetreten",
					   MB_OK | MB_ICONEXCLAMATION);

			return false;
		}

		vertices = new SMeshVertex[numVertices];

		m_pVB->Lock(0, 0, (VOID**)&vertices, 0);

		for(UINT  j = 0; j < meshes[meshID[0]]->mNumVertices; ++j)
        {
			vertices[j].vPosition = MakeToD3DXVector3(meshes[meshID[0]]->mVertices[j]);
			vertices[j].vTangent = MakeToD3DXVector3(meshes[meshID[0]]->mTangents[j]);
			vertices[j].vNormal = MakeToD3DXVector3(meshes[meshID[0]]->mNormals[j]);
			vertices[j].vTexture = MakeToD3DXVector2(meshes[meshID[0]]->mTextureCoords[0][j]);
		}

		m_pVB->Unlock();

		indices = new DWORD[numTriangles*3];
		attributeBuffer = new UINT[numTriangles];

		m_pIB->Lock(0, 0, (VOID**)&indices, 0);

		for(UINT j = 0; j < meshes[meshID[0]]->mNumFaces; j++)
		{
			indices[j*3+0] = meshes[meshID[0]]->mFaces[j].mIndices[0];
			indices[j*3+1] = meshes[meshID[0]]->mFaces[j].mIndices[1];
			indices[j*3+2] = meshes[meshID[0]]->mFaces[j].mIndices[2];
		}

		m_pIB->Unlock();
	}

	delete[] vertices;
	delete[] indices;
	delete[] attributeBuffer;

	return true;
}

D3DXVECTOR3 CLoader::MakeToD3DXVector3(const aiVector3D & Vector)
{
	D3DXVECTOR3 NewVector;

	NewVector.x = Vector.x;
	NewVector.y = Vector.y;
	NewVector.z = Vector.z;

	return NewVector;
}

D3DXVECTOR2 CLoader::MakeToD3DXVector2(const aiVector3D & Vector)
{
	D3DXVECTOR2 NewVector;

	NewVector.x = Vector.x;
	NewVector.y = Vector.y;

	return NewVector;
}
Beim kompilieren kommen noch drei Fehler:

Code: Alles auswählen

1>------ Erstellen gestartet: Projekt: AssimpLoader, Konfiguration: Debug Win32 ------
1>AssimpLoader.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: __thiscall Assimp::Importer::~Importer(void)" (??1Importer@Assimp@@QAE@XZ)" in Funktion ""public: bool __thiscall CLoader::LoadFile(struct IDirect3DDevice9 *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)" (?LoadFile@CLoader@@QAE_NPAUIDirect3DDevice9@@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)".
1>AssimpLoader.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: __thiscall Assimp::Importer::Importer(void)" (??0Importer@Assimp@@QAE@XZ)" in Funktion ""public: bool __thiscall CLoader::LoadFile(struct IDirect3DDevice9 *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)" (?LoadFile@CLoader@@QAE_NPAUIDirect3DDevice9@@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)".
1>AssimpLoader.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: struct aiScene const * __thiscall Assimp::Importer::ReadFile(char const *,unsigned int)" (?ReadFile@Importer@Assimp@@QAEPBUaiScene@@PBDI@Z)" in Funktion ""public: struct aiScene const * __thiscall Assimp::Importer::ReadFile(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>> const &,unsigned int)" (?ReadFile@Importer@Assimp@@QAEPBUaiScene@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@I@Z)".
1>c:\users\patrick egli\documents\visual studio 2010\Projects\AssimpLoader\Debug\AssimpLoader.exe : fatal error LNK1120: 3 nicht aufgelöste externe Verweise.
========== Erstellen: 0 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========
Ich habe den Include-Ordner von Assimp, wie auch den Lib-Ordner in den VC++-Verzeichnissen hinzugefügt. Assimp.lib habe ich im ebenfalls dem Linker übergeben.

Was habe ich vergessen?

Meine zweite Frage, habe ich die Init-Funktion richtig geschrieben, oder wird der das Modell falsch geladen, wenn ich es so programmiere?

LG Patrick

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 15:34
von Schrompf
Du hast anscheinend vergessen, die Assimp.lib als Linker-Abhängigkeit mit anzugeben. Das Setzen von Pfaden zu Include- und Lib-Verzeichnissen ermöglicht der IDE nur, die Dateien zu finden, falls jemand danach fragt. Jetzt musst Du aber noch in Deinem Projekt die Assimp.lib als Abhängigkeit angeben, damit der Linker auch in dieser Lib sucht, wenn er eine Funktion vermisst.

Dein Ladecode sieht ansonsten ok aus, soweit ich das bewerten kann. Du solltest aber evtl. noch Triangulate zu den PostProcessingSteps hinzufügen, sonst können Faces auch mehr als 3 Ecken haben. Probier's aus und schau, wie es aussieht.

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 15:52
von PatrickEgli
Das habe ich bereits gemacht, also unter Eigenschaften => Linker => Eingabe => Zusätzliche Abhängigkeiten, dort habe ich assimp.lib eingegeben. Oder habe ich hier etwas falsch verstanden?

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 15:53
von Aramis
Guck bitte mal ob es in einem Release-Build klappt, mir schwant da uebles.

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 16:09
von PatrickEgli
Ja, mit Release funktioniert es.

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 16:14
von Aramis
Du nutzt das aktuellste Download-Zip, nicht war? Bedauerlichweise ist mit ausgelieferte die Debug-Lib die falsche, genauer: es ist die Release-Lib … daher compiled der ganze Spass nicht. Der einzige Ausweg besteht aktuell darin, Assimp selber auf Debug neuzubauen.

Bei Gelegenheit gibt's mal aktualisierte Pakete. Sorry!

Gruss, Alex

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 16:25
von PatrickEgli
Ja, ich bentuze das aktuelle Assimp 2.0. Kein Ding, ich kann auch mit Release arbeiten.

Wenn ich nun mein Modell rendern will, kommt gar nichts, also lediglich ein schwarzer Hintergrund mit dem Wartekreiscursor von Windows7.

Hier ist meine Render Funktion:

Code: Alles auswählen

void CLoader::Render()
{
	g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE);

	g_pD3DDevice->SetFVF(MeshFVF);
	g_pD3DDevice->SetStreamSource(0, m_pVB, 0, sizeof(SMeshVertex));
	g_pD3DDevice->SetIndices(m_pIB);
	g_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, m_NumVertices, 0, m_NumFaces);

	g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
	g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
}
Hier der Aufruf von der LoadFunktion in der InitFunktion von Direct3D:

Code: Alles auswählen

string FileName ("Sphere.x");

m_pLoader->LoadFile(FileName);
Der Aufruf von der RenderFunktion in der RenderFunktion von Direct3D

Code: Alles auswählen

void CD3D::RenderD3D()
{
	// ------------------------------------------------------
	// Direct3D initialisieren
	// ------------------------------------------------------

	g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

	g_pD3DDevice->BeginScene();

	m_pLoader->Render();

	g_pD3DDevice->EndScene();

	g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}
Warum funktioniert das rendern nicht?

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 16:53
von Schrompf
Patrick, nix für ungut, aber Assimp ist ein denkbar schlechter Kandidat, um daran die Grundlagen der 3D-Programmierung zu lernen. Du setzt keinen Shader oder sowas, keine Model-, View- oder Projectionmatrix, keinerlei Licht- oder Materialeinstellumgen (falls Du keinen Shader benutzen willst) und noch einige sonstige Parameter. Versuche Dich erstmal am rotierenden Dreieck aus dem D3D-Tutorial, um ein Grundverständnis für Transformationen und Koordinatensysteme zu bekommen.

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 17:37
von PatrickEgli
Aber das ist auch kein Problem für mich, ich habe auch schon eigene Spiele programmiert.

Ich kenne mich einfach noch nicht so aus, was ich hier genau machen muss, was es alles benötigt, damit man die Grafik richtig anzeigen kann. Eine View und Projektionsmatrix habe ich bereits im Programm drin, ich habe nicht den ganzen Code meines Programmes vorhin gepostet. Die Modellmatrix habe ich zur Zeit noch nicht drin.

Muss ich denn diese Matrizen, das Licht und die Shader mit Hilfe von Assimp in mein Programm parsen oder soll ich diese selber reinprogrammieren?

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 26.12.2010, 18:15
von Schrompf
Die Model Matrix wird über die Transformationen in den aiNodes gegeben. Die Viewmatrix gibt die Position und Orientierung des Betrachters an, die musst Du also selbst festlegen. Die Projektionsmatrix gibt die Kenndaten der virtuellen Kamera an, also z.B. Nahgrenze, Sichtweite, Öffnungswinkel, Seitenverhältnis des Zielbildes. Das musst Du demzufolge auch selbst definieren.

Der Shader (bzw. die FixedFunction-Einstellungen, wenn Du keine Shader benutzen willst), musst Du ebenso selbst schreiben. Das Aussehen eines Modells ist in gewissem Maße von Assimp vorgegeben. In aiMaterial steht, wie ein Modell auszusehen hat. Ich persönlich mag diese Einstellungen aber nicht, weil sie mir zu divers und umfangreich sind. Du kannst also auch einfach händisch eine Textur und ein paar Farbeinstellungen zuweisen, je nachdem, wie Du damit klarkommst. Das Licht ist entweder eine Einstellung der FixedFunction-Pipeline oder ein Rudel Parameter für Deinen Shader - je nachdem, wie der aussieht.

Ich persönlich würde erstmal empfehlen, komplett ohne Material und Beleuchtung zu rendern. Du müsstest dafür aber zumindest die Texturkoordinaten mit in den VertexBuffer packen, eine Textur zuweisen und die erste TextureStage konfigurieren, so dass die Textur verwendet wird. Und Du solltest vielleicht, solange Du noch mit den Matrizen rumprobierst, die Leer-Farbe Deines Fensters ändern. Viele Einstellungsfehler am Anfang führen zu komplett schwarzem Output, den Du dann zumindest als Silhouette erkennen kannst.

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 28.12.2010, 11:40
von PatrickEgli
Ich habe nun den Loader etwas umgeschrieben, doch das Mesh wird noch nicht richtig geladen.

Code: Alles auswählen

bool CMesh::Init(aiMesh* pMesh, CMeshModel* pModel)
{
	HRESULT hResult;

    if(!pMesh->HasFaces())
	{
		MessageBox(NULL, "Fehler: Mesh hat keine Indizes", "Fehler aufgetreten",
										MB_OK | MB_ICONEXCLAMATION);

		return false;
	}

	m_NumVertices = pMesh->mNumVertices;

	if(FAILED(hResult = g_pD3DDevice->CreateVertexBuffer(pMesh->mNumVertices * sizeof(SMeshVertex),
														 D3DUSAGE_WRITEONLY,
														 SMeshVertex::dwFVF,
														 D3DPOOL_MANAGED,
														 &m_pVB,
														 NULL)))
	{
		MessageBox(NULL, "Fehler beim Erzeugen des VertexBuffers vom Mesh", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);

		return false;
	}

	SMeshVertex * Vertex;

	m_pVB->Lock(0, 0, (VOID**)&Vertex, 0);

    for(int i = 0; i < pMesh->mNumVertices; i++)
    {
            Vertex[i].vPosition = D3DXVECTOR3(pMesh->mVertices[i].x, pMesh->mVertices[i].y, pMesh->mVertices[i].z);
            if(pMesh->HasNormals())
            {
                    Vertex[i].vNormal = D3DXVECTOR3(pMesh->mNormals[i].x, pMesh->mNormals[i].y, pMesh->mNormals[i].z);;
            }
            else
            {
                    MessageBox(NULL, "Vertex ohne Normalen", "Hinweis",
										MB_OK | MB_ICONEXCLAMATION);
            }

            if(pMesh->HasTextureCoords(0))
            {
                    Vertex[i].vTexture = D3DXVECTOR2(pMesh->mTextureCoords[0][i].x, pMesh->mTextureCoords[0][i].y);
            }
            else
            {
				// nichts
            }

            if(pMesh->HasVertexColors(0))
            {
                    Vertex[i].dwColor = MakeToD3DColor(pMesh->mColors[0][i].r, pMesh->mColors[0][i].g, pMesh->mColors[0][i].b, pMesh->mColors[0][i].a);
            }
            else
            {
                    Vertex[i].dwColor = D3DCOLOR_XRGB(0, 0, 1);
            }
    }

	m_pVB->Unlock();

	m_NumTriangles = pMesh->mNumFaces * 3 * 4;

	if(FAILED(hResult = g_pD3DDevice->CreateIndexBuffer(pMesh->mNumFaces * 3 * 4,
														 D3DUSAGE_WRITEONLY,
														 D3DFMT_INDEX32,
														 D3DPOOL_MANAGED,
														 &m_pIB,
														 NULL)))
	{
		MessageBox(NULL, "Fehler beim Erzeugen des IndexBuffers vom Mesh", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);

		return false;
	}

	WORD * Indices;

	m_pIB->Lock(0, 0, (VOID**)&Indices, 0);
	
    for(int i = 0; i < pMesh->mNumFaces; i++)
    {
        aiFace& Face = pMesh->mFaces[i];
        if(Face.mNumIndices != 3)
		{
			MessageBox(NULL, "Fläche hat keine drei Indizen", "Warnung",
				        MB_OK | MB_ICONEXCLAMATION);
		}

		Indices[i*3+0] = pMesh->mFaces[i].mIndices[0];
		Indices[i*3+1] = pMesh->mFaces[i].mIndices[1];
		Indices[i*3+2] = pMesh->mFaces[i].mIndices[2];
	}

	m_pIB->Unlock();

    m_iMaterialIndex = pMesh->mMaterialIndex;
    m_pModel = pModel;

    return true;
}
Der Aufruf der InitFunktion:

Code: Alles auswählen

for(int i = 0; i < m_iMeshCount; i++)
    {
            CMesh* pMesh = new CMesh();
            if(pMesh->Init(pModel->mMeshes[i], this))
            {
				MessageBox(NULL, "Fehler beim Laden eines Meshes", "Fehler aufgetreten",
				           MB_OK | MB_ICONEXCLAMATION);
				
				return false;
            }
            m_apMeshes[i] = pMesh;
    }
Was habe ich denn falsch gemacht?

LG Patrick

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 28.12.2010, 12:19
von Krishty
WORD * Indices;

D3DFMT_INDEX32,

Mal eine andere Frage: Sowas passiert hier alle zwei Wochen. Ich habe typsichere automatisierte Wrapper für Vertex-, Index- und Constant Buffers unter D3D9 und D3D11 rumliegen; im Zweifelsfall könnten wir dem Betreffenden einfach eine Quelldatei an den Kopf schmeißen und sagen, er solle wiederkommen, falls der Fehler mit den Wrappern immernoch passiert. Würde jedem Beteiligten Stunden sparen. Ich müsste die Dinger nur aus meinem Framework rauspfriemeln, überarbeiten und irgendjemand müsste sie testen (weil ich keine D3D9-Projekte mehr rumliegen habe). Bedarf oder vertane Mühe?

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 28.12.2010, 12:24
von Schrompf
Na, hier liegt's dann doch an anderen Grundproblemen.
PatrickEgli hat geschrieben:Was habe ich denn falsch gemacht?
So ziemlich alles, was man als Programmierer in Foren falsch machen kann. Du weißt anscheinend nicht mal selbst, was Du überhaupt an Ausgaben erwartest. Du schreibst keinerlei Fehlerbeschreibung, postest kein Bild von "falschen" Output und benutzt anscheinend keinen Debugger. Langsam werde ich ungeduldig. Wie soll denn irgendein Leser erkennen, was genau da schiefgeht, wenn Du SOWAS als Fehlerbeschreibung postest?

Der Code, den Du gepostet hast, ist eigentlich ok. Deine Berechnung von m_nNumTriangles ist abenteuerlich - aiMesh::mNumFaces *ist* bereits die Dreiecksanzahl, falls Du die dazu notwendigen PostProcessingSteps beim Importieren angegeben hast, damit alles andere außer Dreiecken rausgefiltert wird. Das scheint aber unkritisch, weil Du die Variable ja nirgends sonst verwendest. Leider ist das nur ein Bruchteil des Codes, den man zum Rendern eines beliebigen 3D-Modells braucht. Ich kann Dir als Hilfestellung also nur geben: an Deiner Verarbeitung der Assimp-Daten liegt es wohl nicht.

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 28.12.2010, 13:57
von PatrickEgli
Sorry, habe total vergessen anzugeben, was denn falsch läuft.

Es ist so, dass beim Aufruf von Init der Klasse CMesh die MessageBox, Fehler beim Laden eines Meshes, auftritt.

Code: Alles auswählen

for(int i = 0; i < m_iMeshCount; i++)
{
CMesh* pMesh = new CMesh();
if(pMesh->Init(pModel->mMeshes[i], this))
{
MessageBox(NULL, "Fehler beim Laden eines Meshes", "Fehler aufgetreten",
MB_OK | MB_ICONEXCLAMATION);

return false;
}
Ich erwarte beim Rendern des Meshes, dass ein Mesh gerendert wird. Da leider nichts gerendert wird, ist der Nutzen eines Bildes nicht sehr gross.

Hier ist der RenderCode:

Code: Alles auswählen

bool CMesh::Render()
{
	HRESULT hResult;

    // Vertexformat sowie Vertex- und Index-Buffer setzen
	g_pD3DDevice->SetFVF(SMeshVertex::dwFVF);
    g_pD3DDevice->SetStreamSource(0, m_pVB, 0, sizeof(SMeshVertex));
    g_pD3DDevice->SetIndices(m_pIB);

    string sTextureName = (*m_pModel->GetMaterial(m_iMaterialIndex)->asTextureNames.begin());
    sTextureName = "Data\\" + sTextureName;
       
    PDIRECT3DTEXTURE9 pTexture;

	// Eine Textur erzeugen für den Planeten
	if(FAILED(hResult = D3DXCreateTextureFromFileEx(g_pD3DDevice,
													sTextureName.c_str(), 
													D3DX_DEFAULT, 
													D3DX_DEFAULT,
													D3DX_DEFAULT, 
													0, 
													D3DFMT_UNKNOWN, 
													D3DPOOL_MANAGED,
													D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR|D3DX_FILTER_DITHER,
													D3DX_FILTER_BOX|D3DX_FILTER_MIRROR|D3DX_FILTER_DITHER,
													D3DCOLOR_XRGB(0,0,0), 
													0, 
													0,
													&pTexture)))
	{
		MessageBox(NULL, "Texture ungültig", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);

		return false;
	}

    g_pD3DDevice->SetTexture(0, pTexture);

    g_pD3DDevice->SetMaterial(&m_pModel->GetMaterial(m_iMaterialIndex)->Material);

    // Rendern - Ist Trianglestrip als Typ korrekt?
    if(FAILED(hResult = g_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
                                                           0,
                                                           0,
                                                           m_NumVertices,
                                                           0,
                                                           m_NumTriangles / 3 * sizeof(float))))
	{
		MessageBox(NULL, "Fehler beim Rendern", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);

		return false;
    }

    return true;
}
Am liebsten wäre es mir, wenn ich ein Modell ganz einfach ohne Materialien usw. laden und rendern könnte. Dann könnte ich mit diesem Code immer weiter aufbauen. Kann man das machen oder geht das nur mit allem drum und dran? Gibt es ein gutes Tutorial, über Assimp? Ich habe bei diesem Code sehr viel von diesem Thread abgeschaut: http://developia.zfx.info/viewtopic.php?f=5&t=902

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 28.12.2010, 14:28
von Schrompf
Dann nimm doch mal den Debugger zur Hand und geh Schritt für Schritt durch Deine MeshInit-Funktion, warum genau der Aufruf scheitert. Als Minimalbeispiel gibt es das SimpleGl Example im Assimp-Verzeichnis, aber ich weiß nicht, ob Du Dir das auf DX umschreiben kannst. Ansonsten gibt es da noch den AssimpView-Sourcecode, aber der ist wegen seiner Komplexität auch nicht wirklich zu empfehlen.

In Anbetracht der Probleme, die Du bisher hast, würde ich empfehlen:

a) Google mal nach einem Tutorial für die Benutzung des Debuggers Deiner IDE. Das ist so wichtig, dass Du besser nicht weitermachst, bevor Du mal mit dem Debugger Schritt für Schritt durch Dein Programm durchgelatscht bist und gesehen hast, wie sich dabei die Variablenwerte verändern.

b) Nimm Dir das minimale Direct3D-Tutorial zum Anzeigen eines Dreiecks und steppe da mit dem Debugger durch, um zu verstehen, welche Wege die Daten nehmen und was alles an Funktionsaufrufen nötig ist, um eine Renderpipeline aufzusetzen.

c) Du hast bereits im letzten Thread einen vollständigen Beispielcode bekommen, wie Du einen Assimp-Mesh in einen Vertex-/IndexBuffer lädst. Nutze es.

d) Benutze PIX, um durch die Direct3D-Zeichenaufrufe durchzugehen und zu erkennen, was da gezeichnet wird und warum es nicht auf dem Bildschirm sichtbar ist.

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 28.12.2010, 16:14
von PatrickEgli
Danke für deine Tipps.

Ich habe mich nun mit dem Debugger auseinander gesetzt und habe nun den alten Thread nochmals durchgeschaut. Ich habe mit Hilfe von deinem Code, den du mir damals geschickt hast einen kleien Assimp parser geschrieben. Die Init-Funktion funktioniert eigentlich ganz gut, jedoch habe ich durch den Debugger feststellen müssen, dass alle Membervariablen nicht ausgewertet werden können.

Hier ist mein Code:

Code: Alles auswählen

// AssimpLoader.h
//
#ifndef ASSIMPLOADER_HPP
#define ASSIMPLOADER_HPP

#include "D3D.h"
#include <assimp.h>
#include <assimp.hpp>
#include <aiScene.h>
#include <aiPostProcess.h>
#include <aiMaterial.h>
#include <aiVector2D.h>
#include <aiVector3D.h>
#include <string>

using namespace std;

struct Vertex
{
	float posx, posy, posz;
	float normalx, normaly, normalz;
	float tu, tv;
};

#define VertexFVF (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)

// Klasse erzeugen
class CLoader
{
private:

	const aiScene *			m_pModel;
	int						m_NumVertices;
	int						m_NumFaces;
	PDIRECT3DVERTEXBUFFER9  vertices;
	PDIRECT3DINDEXBUFFER9   indices;

public:

	bool CreateMeshFromAssimp(aiMesh * quellMesh);
	bool CreateScene(string & Filename);
	bool Render();

};

Code: Alles auswählen

// AssimpLoader.cpp
//
#include "AssimpLoader.h"

bool CLoader::CreateMeshFromAssimp(aiMesh * quellMesh)
{
	HRESULT hResult;

	m_NumVertices = quellMesh->mNumVertices;

	// VerexBuffer erzeugen
	if(FAILED(hResult = g_pD3DDevice->CreateVertexBuffer((quellMesh->mNumVertices * sizeof(Vertex)),
														 D3DUSAGE_WRITEONLY,
														 VertexFVF,
														 D3DPOOL_MANAGED,
														 &vertices,
														 NULL)))
	{
		MessageBox(NULL, "Fehler beim erzeugen des VertexBuffers vom Mesh", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);
	}

	Vertex * vertex;

	vertices->Lock(0, 0, (VOID**)&vertex, 0);

	for(size_t a= 0; a < quellMesh->mNumVertices; ++a)
	{
		vertex->posx = quellMesh->mVertices[a].x;
		vertex->posy = quellMesh->mVertices[a].y;
		vertex->posz = quellMesh->mVertices[a].z;

		if(quellMesh->HasNormals())
		{
			vertex->normalx = quellMesh->mNormals[a].x;
			vertex->normaly = quellMesh->mNormals[a].y;
			vertex->normalz = quellMesh->mNormals[a].z;
		}

		if(quellMesh->HasTextureCoords(0))
		{
			vertex->tu = quellMesh->mTextureCoords[0][a].x;
			vertex->tv = quellMesh->mTextureCoords[0][a].y;
		}

		vertex++;
	}

	MessageBox(NULL, "Alles in Ordnung", "Erfolgreich",
			   MB_OK | MB_ICONEXCLAMATION);

	vertices->Unlock();

	m_NumFaces = quellMesh->mNumFaces;

	// IndexBuffer erzeugen
	if(FAILED(hResult = g_pD3DDevice->CreateIndexBuffer((quellMesh->mNumFaces * 3 * sizeof(unsigned short)),
														D3DUSAGE_WRITEONLY,
														D3DFMT_INDEX32,
														D3DPOOL_MANAGED,
														&indices,
														NULL)))
	{
		MessageBox(NULL, "Fehler beim Erzeugen des IndexBuffers", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);
	}

	unsigned short * index;
	
	indices->Lock(0, 0, (VOID**)&index, 0);

	for(size_t a = 0; a < quellMesh->mNumFaces; ++a)
	{
		*index++ = quellMesh->mFaces[a].mIndices[0];
		*index++ = quellMesh->mFaces[a].mIndices[1];
		*index++ = quellMesh->mFaces[a].mIndices[2];
	}

	indices->Unlock();

	MessageBox(NULL, "Alles in Ordnung", "Erfolgreich",
			   MB_OK | MB_ICONEXCLAMATION);

	return true;
}

bool CLoader::CreateScene(string & Filename)
{
	Assimp::Importer importer;

	m_pModel = importer.ReadFile( Filename, 
        aiProcess_CalcTangentSpace  |
        aiProcess_Triangulate |
        aiProcess_MakeLeftHanded |
        aiProcess_JoinIdenticalVertices |
        aiProcess_SortByPType |
        aiProcess_CalcTangentSpace |
        aiProcess_JoinIdenticalVertices |
        aiProcess_GenSmoothNormals |
        aiProcess_LimitBoneWeights |
        aiProcess_RemoveRedundantMaterials |
        aiProcess_OptimizeMeshes);

	if(m_pModel->HasMeshes())
	{
		CreateMeshFromAssimp(m_pModel->mMeshes[0]);
	}

	return true;
}

bool CLoader::Render()
{
	HRESULT hResult;

	g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE);

	g_pD3DDevice->SetFVF(VertexFVF);
	g_pD3DDevice->SetStreamSource(0, vertices, 0, sizeof(Vertex));
	g_pD3DDevice->SetIndices(indices);

	// Rendern - Ist Trianglestrip als Typ korrekt?
    if(FAILED(hResult = g_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
                                                           0,
                                                           0,
                                                           m_NumVertices,
                                                           0,
                                                           m_NumFaces / 3 * sizeof(float))))
	{
		MessageBox(NULL, "Fehler beim Rendern", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);

		return false;
    }

	g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
	g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);

	return true;
}
Der Aufruf von der Init-Funktion:

Code: Alles auswählen

string FileName ("City.3ds");

	m_pLoader->CreateScene(FileName);
und der Aufruf von der Render-Funktion:

Code: Alles auswählen

m_pLoader->Render();
Warum können denn bei diesem Code alle Membervariablen der Klasse CLoader nicht ausgewertet werden?

Folgendes sagt der Debugger:

D3DPT_TRIANGLELIST 4 int
g_pD3DDevice 0x02624b80 IDirect3DDevice9 *
- IUnknown {...} IUnknown
- __vfptr 0x0262791c *
[0] 0x6ef46e99 *
[1] 0x6ef467f2 *
[2] 0x6ef467c9 *


this 0x000015e8 {m_pModel=??? m_NumVertices=??? m_NumFaces=??? ...} CLoader * const
m_pModel CXX0017: Fehler: Symbol "" nicht gefunden
m_NumVertices CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
m_NumFaces CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
vertices CXX0017: Fehler: Symbol "" nicht gefunden
indices CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden

Was ist eigentlich PIX, ich habe bereits auf Google nachgeschaut, doch ich fand wahrscheinlich falsche Ergebnisse. Wo kann ich das Herunterladen?

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 28.12.2010, 16:31
von Schrompf
Oh haua. Der Debugger meint, dass bereits der this-Pointer von dem CLoader ungültig sei... Du hast anscheinend recht fundamentale C++-Probleme in Deinem Code. Du musst allerdings auch daran denken, dass all die Werte sich natürlich erst im Laufe der Zeit verändern. Setze mal einen Breakpoint an den Anfang der Meshlade-Funktion (mit F9) und schau, wie sich die Dinge ab da entwickeln. Sprich: mit F10 bzw. F11 zum Hineingehen in Funktionen Schritt für Schritt verfolgen, wie Dein Programm ausgeführt wird. An 3D ist da jedenfalls noch gar nicht zu denken. Und bitte sieh es mir nach, dass ich meine Freizeit nicht darauf verwenden will, Dir die Grundlagen der C++-Resourcenverwaltung beizubringen.

Deine Lade-Funktion steckt jedenfalls voller Bugs. Mich wundert, dass das nicht sofort abstürzt. Du erzeugst den IndexBuffer mit NumIndices * sizeof( unsigned short), gibst aber an, dass Du unsigned int als Indextyp benutzen willst. Damit ist Dein Buffer nur halb so groß, wie er sein müsste, um soviele Indizes aufzunehmen. Außerdem stehen da wahlfrei reinkopierte Textschnipsel drin - bist Du sicher, dass das überhaupt kompiliert, was Du da schreibst? "unsigned short * index" ist ja wohl offensichtlicher Unsinn. Lies bitte Deinen Quelltext vorher nochmal durch, bevor Du meine Zeit damit verschwendest.

Beim Rendern musst Du noch beachten, dass Du bei DrawIndexedPrimitive() als PrimitiveCount auch wirklich die Anzahl Dreiecke angibst. Du gibst da aktuell stattdessen AnzahlDreiecke / 3 * sizeof( float) - was auch immer Du Dir dabei gedacht hast.

Re: Assimp Loader mit Vertex- und IndexBuffer

Verfasst: 28.12.2010, 17:05
von PatrickEgli
Ich habe nun an meien Code weitergeschrieben. Ich habe nun Materialien hinzugefügt und ich versuchte mit den aiNode umzugehen.

Hier ist der Code:

Code: Alles auswählen

// AssimpLoader.cpp
//
#include "AssimpLoader.h"

D3DCOLORVALUE CLoader::AiToD3DColor(const aiColor3D & color)
{
	D3DCOLORVALUE NewColor;

	NewColor.r = color.r;
	NewColor.g = color.g;
	NewColor.b = color.b;

	return NewColor;
}

bool CLoader::CreateMeshFromAssimp(aiMesh * quellMesh)
{
	HRESULT hResult;

	m_NumVertices = quellMesh->mNumVertices;

	// VerexBuffer erzeugen
	if(FAILED(hResult = g_pD3DDevice->CreateVertexBuffer((quellMesh->mNumVertices * sizeof(Vertex)),
														 D3DUSAGE_WRITEONLY,
														 VertexFVF,
														 D3DPOOL_MANAGED,
														 &vertices,
														 NULL)))
	{
		MessageBox(NULL, "Fehler beim erzeugen des VertexBuffers vom Mesh", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);
	}

	Vertex * vertex;

	vertices->Lock(0, 0, (VOID**)&vertex, 0);

	for(size_t a= 0; a < quellMesh->mNumVertices; ++a)
	{
		vertex->posx = quellMesh->mVertices[a].x;
		vertex->posy = quellMesh->mVertices[a].y;
		vertex->posz = quellMesh->mVertices[a].z;

		if(quellMesh->HasNormals())
		{
			vertex->normalx = quellMesh->mNormals[a].x;
			vertex->normaly = quellMesh->mNormals[a].y;
			vertex->normalz = quellMesh->mNormals[a].z;
		}

		if(quellMesh->HasTextureCoords(0))
		{
			vertex->tu = quellMesh->mTextureCoords[0][a].x;
			vertex->tv = quellMesh->mTextureCoords[0][a].y;
		}

		vertex++;
	}

	MessageBox(NULL, "Alles in Ordnung", "Erfolgreich",
			   MB_OK | MB_ICONEXCLAMATION);

	vertices->Unlock();

	m_NumFaces = quellMesh->mNumFaces;

	// IndexBuffer erzeugen
	if(FAILED(hResult = g_pD3DDevice->CreateIndexBuffer((quellMesh->mNumFaces * 3 * sizeof(unsigned int)),
														D3DUSAGE_WRITEONLY,
														D3DFMT_INDEX32,
														D3DPOOL_MANAGED,
														&indices,
														NULL)))
	{
		MessageBox(NULL, "Fehler beim Erzeugen des IndexBuffers", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);
	}

	unsigned int * index;
	
	indices->Lock(0, 0, (VOID**)&index, 0);

	for(size_t a = 0; a < quellMesh->mNumFaces; ++a)
	{
		*index++ = quellMesh->mFaces[a].mIndices[0];
		*index++ = quellMesh->mFaces[a].mIndices[1];
		*index++ = quellMesh->mFaces[a].mIndices[2];
	}

	indices->Unlock();

	MessageBox(NULL, "Alles in Ordnung", "Erfolgreich",
			   MB_OK | MB_ICONEXCLAMATION);

	m_MaterialIndex = quellMesh->mMaterialIndex;

	return true;
}

bool CLoader::CreateScene(string & Filename)
{
	Assimp::Importer importer;

	m_pModel = importer.ReadFile( Filename, 
        aiProcess_CalcTangentSpace  |
        aiProcess_Triangulate |
        aiProcess_MakeLeftHanded |
        aiProcess_JoinIdenticalVertices |
        aiProcess_SortByPType |
        aiProcess_CalcTangentSpace |
        aiProcess_JoinIdenticalVertices |
        aiProcess_GenSmoothNormals |
        aiProcess_LimitBoneWeights |
        aiProcess_RemoveRedundantMaterials |
        aiProcess_OptimizeMeshes);

	aiNode * nd = m_pModel->mRootNode;

	if(m_pModel->HasMeshes())
	{
		for(int i = 0; i < nd->mNumChildren; i++)
		{
			CreateMeshFromAssimp(m_pModel->mMeshes[i]);
		}
	}

	m_pMaterial = new SMaterial*[m_pModel->mNumMaterials];

	// Alle Materialien laden
	for(int i = 0; i < m_pModel->mNumMaterials; i++)
	{
		m_pMaterial[i] = new SMaterial();

		aiColor3D color(0.0f, 0.0f, 0.0f);
		m_pModel->mMaterials[i]->Get(AI_MATKEY_COLOR_DIFFUSE, color);
		m_pMaterial[i]->Material.Diffuse = AiToD3DColor(color);

		color.r = 0.0f; color.g = 0.0f; color.b = 0.0f;
		m_pModel->mMaterials[i]->Get(AI_MATKEY_COLOR_SPECULAR, color);
		m_pMaterial[i]->Material.Specular = AiToD3DColor(color);

		color.r = 0.0f; color.g = 0.0f; color.b = 0.0f;
		m_pModel->mMaterials[i]->Get(AI_MATKEY_COLOR_EMISSIVE, color);
		m_pMaterial[i]->Material.Emissive = AiToD3DColor(color);

		color.r = 0.0f; color.g = 0.0f; color.b = 0.0f;
		m_pModel->mMaterials[i]->Get(AI_MATKEY_COLOR_AMBIENT, color);
		m_pMaterial[i]->Material.Ambient = AiToD3DColor(color);

		float fPower = 0.0f;
		m_pModel->mMaterials[i]->Get(AI_MATKEY_SHININESS, fPower);
		m_pMaterial[i]->Material.Power = fPower;
	}

	return true;
}

bool CLoader::Render()
{
	HRESULT hResult;

	g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE);

	g_pD3DDevice->SetMaterial(&m_pMaterial[m_MaterialIndex]->Material);

	g_pD3DDevice->SetFVF(VertexFVF);
	g_pD3DDevice->SetStreamSource(0, vertices, 0, sizeof(Vertex));
	g_pD3DDevice->SetIndices(indices);

	// Rendern - Ist Trianglestrip als Typ korrekt?
    if(FAILED(hResult = g_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
                                                           0,
                                                           0,
                                                           m_NumVertices,
                                                           0,
                                                           m_NumFaces / 3)))
	{
		MessageBox(NULL, "Fehler beim Rendern", "Fehler aufgetreten",
				   MB_OK | MB_ICONEXCLAMATION);

		return false;
    }

	g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
	g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);

	return true;
}
Was muss ich noch hinzufügen, damit das ganze Mesh dargestellt wird? Habe den aiNode richtig verwendet, also bzw. sieht das richtig aus:

Code: Alles auswählen

if(m_pModel->HasMeshes())
	{
		for(int i = 0; i < nd->mNumChildren; i++)
		{
			CreateMeshFromAssimp(m_pModel->mMeshes[i]);
		}
	}
LG Patrick