Zobrazit předchozí téma :: Zobrazit následující téma |
Autor |
Zpráva |
jaromir
Založen: 02. 01. 2016 Příspěvky: 3
|
Zaslal: 2. leden 2016, 11:22:36 Předmět: Animace modelů - CPU klasika vs. VBO - výkonnost |
|
|
Dobrý den,
již několik dnů řeším malý problém s animací modelů formátu MS3D. Vím, že existuje spousta jiných formátů a lepších, ale mne tento vyhovuje a v současné chvíli je dostačující.
Už zpočátku jsem přemýšlel především o využití VertexArrays nebo VBO a shaderů. Proto nevyužívám, jak je ve všech examplech k reprezentaci transformací kloubů matice, ale quaternion a vektor kvůli menšímu posílání dat do shaderu.
Samotnou animaci počítám na CPU, kde vypočtu quaternion pro rotaci a vektor posunutí a toto pole pošlu do shaderu. Dále jsem se inspiroval jednou starší diskuzí zde a do VBO posílám čtyř-složkový vektor, kde w=index kloubu.
Co se týče VBO, tak nemám bohužel jeden, ale každý mesh má svůj vlastní VBO. Důvodem je, že každý mesh může mít a má jinou texturu.
Samotný shader pak vypadá takto:
kód: |
varying vec2 Texcoord;
uniform vec4 rotation[25];
uniform vec3 translation[25];
vec3 rotateVectorToQuaternion(vec4 rot, vec3 trans)
{
vec3 temp = vec3(rot.x, rot.y, rot.z);
vec3 t = cross(temp, trans) * 2.0;
return trans + t * rot.w + cross(temp, t);
}
void main( void )
{
vec3 transformedVertex = rotateVectorToQuaternion(rotation[gl_Vertex.w], vec3(gl_Vertex.x, gl_Vertex.y, gl_Vertex.z)) + translation[gl_Vertex.w];
gl_Position = gl_ModelViewProjectionMatrix * vec4(transformedVertex, 1.0);
Texcoord = gl_MultiTexCoord0.xy;
}
|
A můj dotaz se týká rychlosti. Byl jsem totiž překvapen když VBO bylo asi o 100 FPS pomalejší než klasické CPU vykreslování trojúhelník po trojúhelníku. Konkrétně:
glVertex3f: 430 FPS
VBO: 320 FPS
Uvědomuji si, že když se pracuje se shadery, buffery,... stačí jedna nějaká hloupost a rychlost jde do kytek, tak jestli tam nemůže být nějaká zrada. Či jestli celý můj návrh je špatný .
Děkuji za každý názor, radu,... Pokud by bylo třeba poslat nějaké další části kódu, stačí říct |
|
Návrat nahoru |
|
|
Peto
Založen: 01. 08. 2007 Příspěvky: 206 Bydliště: Košice
|
Zaslal: 2. leden 2016, 17:48:23 Předmět: Re: Animace modelů - CPU klasika vs. VBO - výkonnost |
|
|
jaromir napsal: |
Dále jsem se inspiroval jednou starší diskuzí zde a do VBO posílám čtyř-složkový vektor, kde w=index kloubu. |
Mozno som trochu mimo.. predsa som skor DirectXkár ... ale neupdatujes nahodou ten VBO kazdy frame? _________________ Code or die!
|
|
Návrat nahoru |
|
|
nou
Založen: 28. 07. 2007 Příspěvky: 1047
|
Zaslal: 2. leden 2016, 20:24:34 Předmět: |
|
|
Mozes to nasypat do jedneho VBO. Usetris pri tom nieco na vykone. Jednotlive meshe potom vykreslis pomocou glDrawElements() a ako posledny parameter poslel offset v bytoch. Tak sa da vykreslit len jedna cast
To je dobry postrech. V renderovacej slucke by mal byt len update tych quaterionov, bind textur a samotne glDrawElements(). _________________ Najjednoduchšie chyby sa najtažšie hľadajú. |
|
Návrat nahoru |
|
|
jaromir
Založen: 02. 01. 2016 Příspěvky: 3
|
Zaslal: 3. leden 2016, 09:57:49 Předmět: |
|
|
Děkuji moc za rekce.
citace: |
Mozno som trochu mimo.. predsa som skor DirectXkár Smile... ale neupdatujes nahodou ten VBO kazdy frame?
|
Nikoliv, vytvořím VBO jednou a veškerý update se provádí v shaderu, který jsem poslal. Co se updatuje, je finální vektor posunutí a quaternion rotace pro každý joint a ten se pak posílá do shaderu.
citace: |
Mozes to nasypat do jedneho VBO. Usetris pri tom nieco na vykone. Jednotlive meshe potom vykreslis pomocou glDrawElements() a ako posledny parameter poslel offset v bytoch. Tak sa da vykreslit len jedna cast
To je dobry postrech. V renderovacej slucke by mal byt len update tych quaterionov, bind textur a samotne glDrawElements().
|
Díky, to s tím offsetem je super nápad.
Render u mě vypadá takto:
kód: |
this->Animate(dt);
ShaderManager::Get(MODEL_SHADER)->Activate();
for (int i = 0; i < _numMeshes; i++)
{
int materialIndex = _meshes[i].material;
if (materialIndex >= 0)
{
TextureManager::Get(_materials[materialIndex].textureName)->Bind();
}
_meshes[i].vertexBufferObject->Render();
}
ShaderManager::Get(MODEL_SHADER)->Deactivate();
|
a render pro VBO pak takto:
kód: |
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer->GetId());
glVertexPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER, _textureBuffer->GetId());
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer->GetId());
glDrawElements(GL_TRIANGLES, _indexBuffer->GetSize(), GL_UNSIGNED_SHORT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
No nevím no. Už ale z principu, přestože mám více VBO, tak bych očekával lepších výkonnostních výsledků než-li vykreslování trojúhelník po trojúhelníku.... |
|
Návrat nahoru |
|
|
Ladis
Založen: 18. 09. 2007 Příspěvky: 1536 Bydliště: u Prahy
|
Zaslal: 3. leden 2016, 14:03:18 Předmět: |
|
|
Může být problém i v tom, že tvoje scéna je moc jednoduchá (však máš stovky FPS). Třeba se jedno řešení s větší složitostí bude zpomalovat rychleji. Takže bych to řešil až pak (pokud teda nemáš ten kód copy&paste na spoustě míst). |
|
Návrat nahoru |
|
|
jaromir
Založen: 02. 01. 2016 Příspěvky: 3
|
Zaslal: 3. leden 2016, 14:43:01 Předmět: |
|
|
Značný problém byl v předávání parametrů do shaderu absolutně by mne nenapadlo, že tato původní metoda, která byla zatím provizorní, může způsobovat tak razantní zpomalení. Volala se n-krát v každém render cyklu pro model, kde n je počet kloubů:
kód: |
string temp = rotAttrName + "[" + to_string(index) + "]";
GLint location = glGetUniformLocation(_shaderId, temp.c_str());
glProgramUniform4f(_shaderId, location, q.x, q.y, q.z, q.w);
temp = transAttrName + "[" + to_string(index) + "]";
location = glGetUniformLocation(_shaderId, temp.c_str());
glProgramUniform3f(_shaderId, location, v.x, v.y, v.z);
|
Nahradil jsem ji těmito metodami:
kód: |
GLint myLoc = glGetUniformLocation(_shaderId, name.c_str());
glProgramUniform3fv(_shaderId, myLoc, size, values);
|
a
kód: |
GLint myLoc = glGetUniformLocation(_shaderId, name.c_str());
glProgramUniform4fv(_shaderId, myLoc, size, values);
|
kde si předtím naplním pole potřebnými daty a každá metoda je volána jen jednou.
Nyní se dostanu k 1600-1800 FPS, což už je podstatně veselejší. |
|
Návrat nahoru |
|
|
pcmaster
Založen: 28. 07. 2007 Příspěvky: 1824
|
Zaslal: 4. leden 2016, 08:56:47 Předmět: |
|
|
Konstanty (uniform) su totiz tiez buffer (constant buffer) a od vertex buffera sa to lisi len velmi nepatrne (na strane driveru zrejme nelisi vobec), takze CPU->GPU update po jednom je totalny killer Uz to mas dobre, good job. _________________ Off-topic flame-war addict since the very beginning. Registered since Oct. 2003!
Interproductum fimi omne est. |
|
Návrat nahoru |
|
|
|