schnelle mehrfache Animationen
-
zu finale matrizen-multiplikation der vertices auf der graka. ich meine das genau so, wie das gesagt hast mac_bu. nur die matrix-vektor-multiplikation auf der graka. aber wie mache ich diese finale multiplikation auf der graka? das dürfte doch nur mit nem vertex-shader funzen, oder? und wie bekomme ich dann die finale matrix auf die graka? (Quelltext)
die nehes kenne ich größten teils, aber der nutzt ja auch hauptsächlich die Funktion glVertex3fv. ansonsten verwendet er vertex-buffer. bei welchem tut siehst du, wo er nen vertex-array am stück rüber zieht??
heimschmiede
-
Entschuldige, ich meinte die VertexBuffer. Zu VertexList gibt es zwar auch etwas (Begin(List), dann die draw aufrufe, dann end) und anschließend diese Liste zeichnen. Das ist aber eigentlich nur für statische Objekte sinnvoll. Ich komme von DX, daher habe ich hier keine besonders tiefgehenden Kenntnisse.
Unter DX gibt es den Aufruf SetVertexShaderConstant(...) mit dem sich eine begrenzte Anzahl an Konstanten (üblicherweise Vektoren) setzen läßt (?196 Vektoren?). Hiermit würdest du der Karte die Matrizen übermitteln. Anschließend kannst du auf diese Konstanten von deinem Shader aus zugreifen. Mit OGL dürfte es wohl ähnlich ablaufen. Anstelle von Matrizen könntest du in diese Konstanten auch Quaternione legen (+TranslationsVektoren). Dadurch könntest du auf mehr Bones zugreifen (Dürfte aber mehr Rechenaufwand sein). Solltest du Pro Modell mehr Bones haben, als sich in den ?196? Vektoren übermitteln lässt musst du dein Modell 'zerschneiden' d.h. in 2 Objekte unterteilen, die möglichst wenige gemeinsame Bones haben.
Sieh dir mal die Teile auf der NVidia homepage an, da bekommst du denke ich ein ganz gutes Gefühl, wie das ganze funktioniert.Da fällt mir noch was ein:
Schau dir mal die Funktionen
glInterleavedArrays, glDrawArrays, glDrawElements, glArrayElement an.VertexBuffer wären aber wahrscheinlich trotzdem schneller (zumindest bei DX - ich weiß nicht in wie weit die ähnlich sind).
Viel Spaß damit!
-
Also Nehe hat eigentlich alles was du für diese einfache Aufgabe brauchst.
Ansonsten würde ich dir gerne das OpenGL ReadBook zu Herzen legen. Ist zwar schon etwas älter aber ein sehr gutes Buch um zu sehen was man alles wie machen machen.Hab grad mal etwas oberflächlich dort gesucht:
glVertexPointer und glDrawElements oder ähnliche Sachen sollten dir bei Aufgabe 1. helfen.Die Matrizen auf der Grafikkarte rechnen lassen das tust du Teilweise schon.
Wie bewegst und rotierst du deine Objekte denn. Ich glaube doch kaum in Software !!
Du Benutzt die Methoden glRotate/Translate
Also entweder benutzt du anschliessend diese um deine Körperteile zu bewegen, oder du übergibst gleich die Matrix mit den Befehlen glLoadIdentity oder glLoadMatrix/MultMatrixDamit schickst du die Matrizen zur Transformation an die GK, danach zeichnest du dein Objekt und die GK Multipliziert deine Vertices mit der Matrix (und noch einigen anderen Matrizen (Projektion, World, etc...)
Wie gesagt, lass erstmal noch die Finger von Shadern. Sie sind sehr interessant, aber vorher brauchst du noch ein paar Grundkenntnisse was die generelle Kommunikation mit der GK angeht.
-
Ist schon richtig. Wenn du auf shader zurückgreifen würdest müßtest du in denen auch die beleuchtung deiner Objekte selbst berechnen. Lohnen könnte es sich trotzdem!
Das mit den Matrizen war wohl ein Missverständis meinerseits.
-
das was ich bisher von den shadern gesehen habe, sieht sehr übel aus, deshalb wollt ich erst einmal auf andere methoden zurückgreifen.
momentan berechne ich alle meine punkte in software. dh: an hand der keyframes und den absoluten und relativen matrizen werden die finalen matrizen erstellt, die dann die ganze tranformation enthalten. diese werden dann bei mir im code in software transformiert und dann erst in die graka verschifft. in der graka kommt dann noch das anderes gedönse, der vorher mit glRotate und glTranslate erstellt wird. das ist ja im prinzip auch nur ne matrix.
ich denke, dass ich mal mit glDrawArrays rumexperimentiere um zu sehen, wie viel es mir wirklich bringt.
dann danke ich mal allen für die guten antworten! ich werd wahrscheinlich mal wieder kommen, wenn ich irgendwo wieder probleme haben werde.
aber wer noch weitere ideen ´hat, kann ja ruhig weiter posten
heimschmiede
-
Wie gesagt, DrawArrays wird sich auf jeden Fall lohnen. Aber noch viel mehr (oder genauso, egal, beides wird SEHR SEHR VIEL bringen) lohnt sich die Matrix Multiplikation auf der GK.
Die Grafikkarte muss sowieso jedes Vertex mit der Matrix multiplizieren. Es ist also kein Mehraufwand.Teste einfach mal all deine Modelle OHNE Animation !
Diese Geschwindigkeit sollte ungefähr die gleiche sein wie wenn du die Matrizen mit glLoadMatrix erst auf der GK mutltiplizierst.Viel Spass beim ausprobieren !
-
moinmoin,
ich werde dieses thema wieder auffrischen müssen. es hat so lang gedauert, weil noch ein paar klausuren dazwischen lagen ....ich hab mir ja auch viel von den vertex-arrays versprochen, deshalb hab ich alles uaf vertex-arrays umgebaut und nachher wieder viele zeiten gemessen. leider sind die vertex-arrays kein bischen schneller als die massenweisen alten glVertex3f(v)-funktionen. auf die 100 models ist keine veränderung zu spüren. zusätzlich muss auch noch gesagt werden, dass man wegen der transformationen noch zusätzlichen speicherplatz reservieren muss. leider hat es sich nicht gelohnt. jetzt bin ich aber am überlegen, wie ich da noch was rausholen kann.
ansatz: alle matrizen-multiplikationen auf der GK durchführen lassen. da im milkshape-model-format jeder vertex einem bone zugeordnet ist, ist es sinnvoll das gesamte format nach den bones zu sortieren, sonst könnte es passieren, dass bei jedem vertex ne neue matrix rübergeschoben werden muss, was eher kontraproduktiv wäre. also wären ale bones zusammen mit bone-eigener matrix, wo sich auch dann seperate vertex-buffer lohnen könnten. nachteil: es ist nicht vorher bekannt, ob alle dreiecke eines bones die selbe textur besitzen. es könnte also vorkommen, dass innerhalb des rendern eines bones mehrfach die textur geändert werden muss. -> ist aber ein eher kleinerer nachteil, weil man beim modellieren dieses problem beseitigen könnte.
das milkshape-model ist nach meshes aufgebaut und sortiert. ein mesh besitzt maximal ein material und somit auch maximal eine textur.ist dieser ansatz vielversprechend? könnt ihr mir weitere nachteile oder auch weitere vorteile nennen?? denn dies ist mit ner menge arbeit verbunden, deshalb wollt ich lieber einmal nochmal nachfragen.
heimschmiede
-
klingt als würdest du sehr viel optimieren ohne dass du überhaupt weißt woran dein problem liegt. normalerweise ist das einzelne verschieben von vertices das hauptproblem und die umsteleung auf drawarray ein großer boost. wenn das bei dir nichts gebracht hat, gibt es ein anderes problem als die transformation bzw der vertextransfer.
nur der neigierde wegen, stell das iechnen mal auf wireframe

rapso->greets();
-
Normalerweise sollte es schon einiges gebracht haben ...
Also 2 Möglichkeiten:
1. Du machst was falsch
PS: is die häufigste
2. Deine spezielle Situation hat ihren Bottleneck woanders ...
-> nach Bottleneck suchen ...Aber so wie du es beschrieben hast sollte es eigentlich viel schneller werden.
Mach einfach mal das was Rapso gesagt hat, stell das ganze auf Wireframe, dann siehst du ob die Fillrate dein Problem ist ... wenn ja solltest du über CullingAlgos nachdenken ..Ansonsten poste ansatzweise was du mit den VA's machst.
(vielleicht füllst du sie ja jedes Frame oder so ...)
-
ChaosAngel schrieb:
(vielleicht füllst du sie ja jedes Frame oder so ...)
er transformiert per software, das impliziert das füllen jedes frames. aber da er auch ohne transformationen miese performance hat.... macht er was falsch und das bottlenevk ist woanders :)... ich tippe ja mal auf software rendering

-
ich schick jetzt mal auszüge aus meinem Quelltext:
KlassebStruktur: class VERTEX { public: float location[3]; char boneID; }; class TRIANGLE { public: int VertexIndex[3]; float Normals[3][3]; float s[3]; float t[3]; }; class MESH { public: int nTri; int *TriangleIndex; int MaterialIndex; }; class KEYFRAME { public: int JointIndex; float time; //millisekunden float parameter[3]; }; class JOINT { public: float rotation[3]; float translation[3]; MATRIX absoluteMatrix; MATRIX relativeMatrix; int numRotationKeyframes; int numTranslationKeyframes; KEYFRAME *TranslationKeyframe; KEYFRAME *RotationKeyframe; int curRotationKeyframe; int curTranslationKeyframe; MATRIX finalMatrix; //final MATRIX int parent; }; class Milkmodel { public: Milkmodel(); ~Milkmodel(); int numVertex; int numTriangle; int numMaterial; int numMesh; int numJoints; VERTEX *vertex; TRIANGLE *triangle; MATERIAL *material; MESH *mesh; JOINT *joint; TIMER timer; double totaltime; bool loop; float min[3]; float max[3]; GLfloat *vertexarr; GLfloat *normalarr; GLfloat *texcoordarr; bool LoadMilkModel(char *filename, float scale, char* logfilename); void DrawMilkModel(float scale); //scale ist nicht eingebunden void DrawBoundingBox(); void SetupJoints(); void Animate(); void restart(); private: void AddMilkmodelLog(const char *message, ...); char* LogFilename; }; //und hier noch einen Auszug aus der DrawMilkModel-Funktion: [...] int arrindex=0; int mi, mj, mk; for(mi=0;mi<numMesh;mi++) //Mesh { for(mj=0;mj<mesh[mi].nTri;mj++) //Dreiecke { int triangleIndex=mesh[mi].TriangleIndex[mj]; for(mk=0;mk<3;mk++) //Vertices { int index=triangle[triangleIndex].VertexIndex[mk]; if(vertex[index].boneID==-1) { memcpy(&vertexarr[arrindex*3],vertex[index].location,sizeof(float)*3); memcpy(&normalarr[arrindex*3],triangle[triangleIndex].Normals[mk],sizeof(float)*3); } else { MATRIX &final=joint[vertex[index].boneID].finalMatrix; float tempv[3]; memcpy(tempv,triangle[triangleIndex].Normals[mk],sizeof(float)*3); final.TransformNormalVect(tempv); memcpy(&normalarr[arrindex*3],tempv,sizeof(float)*3); memcpy(tempv,vertex[index].location,sizeof(float)*3); final.TransformVect(tempv); memcpy(&vertexarr[arrindex*3],tempv,sizeof(float)*3); } if(materialIndex>=0) { if(material[materialIndex].boolTexture) { float tc[2]; //tex coords tc[0]=triangle[triangleIndex].s[mk]; tc[1]=triangle[triangleIndex].t[mk]; memcpy(&texcoordarr[arrindex*2],tc,sizeof(float)*2); } } arrindex++; } } } //glEnd(); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3,GL_FLOAT,0,vertexarr); glTexCoordPointer(2,GL_FLOAT,0,texcoordarr); glNormalPointer(GL_FLOAT,0,normalarr); glDrawArrays(GL_TRIANGLES,0,arrindex); arrindex=0; }sorry, wenn es ein wenig lang geworden ist, aber so sieht es aus. ich muss die Arrays jeden frame neu füllen, weil es in der natur einer animation liegt, dass sich dinge bewegen...

was meint ihr mit bottlenevk ?? am meisten zeit frisst diese draw-funktion. die animations-funktion berechnet nur die finalen Matrizen der Bones (in Milkshape: Joints)
sagt einfach laut los, was ich falsch mache, dafür bin ich ja hier hin gekommen!
-
hi
tja, den klausurenstress kenn ich auch. Deswegen misch ich mich auch erst jetz ein.

Ich hab bei meinem derzeitigen Projekt eine ähnliche Situation wie Heimschmiede und weiß auch noch nich genau, wie ich die Berechnungen auf die Graka krieg. Allerdings is die Problematik bei mir doch ne etwas andere, also erstma ne allgemeine Beschreibung:
Ich schreibe auch (VC6, OpenGl) an ner Modelrenderklasse, die MS3D-Files lädt, derzeit noch ohne animation, is aber für ziemlich bald in Planung.
Ich hab mich aber erstma auf Schattierung konzentriert: Mein Ansatz war die Beleuchtung der Pixelshader durch dynamische Texturierung zu simulieren. So werden also quadratische Texturen, die in der Mitte einen hellen Punkt haben und nach außen dunkler werden, so auf das Model gemappt, dass der helle Punkt immer entweder auf den Seiten direkt zum Licht (diffuse), zum helbvector (specular) oder zum vertex-eye-vector (glow-ähnlicher Effekt) steht (Vorlage war nehe's CellShading Tut).
Das bringt denkt ich bei natürlich einigen Nachteilen gegenüber Pixelshadern trotzdem ne ganze Menge:
- es werden keine Pixelshader für eine gute Beleuchtung gebraucht (läuft daher auch auf älteren Rechnern)
- helligkeitsberechnungen sind nur pro vertex, nich pro pixel nötig - mehr speed, also auch besser für alte PCs
- es lassen sich einige Effekte erzielen, die mit Pixelshadern eigentlich unmöglich sind, wenn die Texturen zB. nicht einfache Hellikeitsverläufe enthalten, sondern zB. ein Schachmuster oder sowas:| \ | / \ | / ---+#+--- / | \ / | \ |Das funzt alles auch bis auf ein paar kleine Fehler schon ziemlich gut.
Falls interesse:http://cthulhu.homelinux.org/bsp.jpg
http://cthulhu.homelinux.org/bsp.zipDie Addierung der unterschiedlichen Helligkeiten für zB. Diffuse und Specular hab ich zur zeit noch durch mehrere Passes gelöst, in Planung is aber Mutlitexture (mehr speed!!
). Außerdem läuft die Berechnung der uv-Koordinaten derzeit noch auf der CPU und die werden mit glTexCoord2f und glVertex3f übergeben. Das will ich natürlich ändern. Das halte ich aber bei für ziemlich stressig. Ich stell mir das ca. so vor:Für jedes Material jedes Bones müssten in einem ersten Pass alle Dreiecke (am besten durch VertexArrays?) mit den ShadingTexturen gezeichnet werden.
Dafür müssten mit multitexture die entsprechenden Helligkeits-Texturen gebindet werden. Die erste wäre dann zB. die für diffuse, die zweite für specular. Dann sollte das Model der Graka übergeben werden, welche dann per Vertexshader die eigentliche Berechnung der uv-Koordinaten durchführt. Dazu müssen Vertexshader allerdings Multitexture verstehen und jede uv-Koordinate jeder Textureschicht ändern können. Können die das?Letztendlich würde dann dachte ich in nem zweiten Pass das Model mit glBlendFunc(GL_DST_COLOR,GL_SRC_COLOR) mit den eigentlichen Texturen gerendert.
Haltet ihr das so für durchführbar/sinnvoll? Oder gibt es eine andere Möglichkeit diese Berechnungen von der Graka durchführen zu lassen, also ohne Vertexshader?
Thx schonmal jetz
[edit] ähm, ein Moderator möge das bitte ma besser in nen neuen thread schieben, thx[/edit]