16 float ftime = (float)time;
22 if (next.time <= ftime)
48 , m_positionsBuffer(0)
53 , m_boneWeightBuffer(0)
55 , m_instancesInBuffer(0)
56 , m_needToUpdateIdBuffer(true)
60 auto scene = imp.ReadFile((
"content\\scenes\\" + name).c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals);
64 cerr <<
"ERROR: Failed to load scene '" << name <<
"'" << endl;
68 string baseDir =
"scenes\\" + name;
69 baseDir = baseDir.substr(0, baseDir.find_last_of(
"\\") + 1);
83 auto& assimpMtl = scene->mMaterials[i];
87 if (AI_SUCCESS == aiGetMaterialColor(assimpMtl, AI_MATKEY_COLOR_AMBIENT, &color))
88 ambient = vec4(color.r, color.g, color.b, color.a);
90 ambient = vec4(0, 0, 0, 0);
92 if (AI_SUCCESS == aiGetMaterialColor(assimpMtl, AI_MATKEY_COLOR_DIFFUSE, &color))
93 diffuse = vec4(color.r, color.g, color.b, color.a);
95 diffuse = vec4(0, 0, 0, 0);
97 if (AI_SUCCESS == aiGetMaterialColor(assimpMtl, AI_MATKEY_COLOR_SPECULAR, &color))
98 specular = vec4(color.r, color.g, color.b, color.a);
100 specular = vec4(0, 0, 0, 0);
104 aiGetMaterialFloatArray(assimpMtl, AI_MATKEY_SHININESS, &(shininess), &max);
108 if (AI_SUCCESS == assimpMtl->GetTexture(aiTextureType_DIFFUSE, 0, &texPath))
109 texture = app->
getTextures().
get(
"..\\" + baseDir + texPath.C_Str());
113 mtl.reset(
new Material(ambient, diffuse, specular, shininess, texture));
117 map<string, uint> bones;
121 vector<vec3> positions;
123 vector<vec3> normals;
124 vector<ivec4> boneIds;
125 vector<vec4> boneWeights;
126 vector<uint> indices;
128 vector<uint> boneCount;
131 for (uint i = 0; i <
m_meshes.size(); i++)
133 auto& assimpMesh = scene->mMeshes[i];
136 if (!assimpMesh->HasPositions())
138 cerr <<
"ERROR: Failed to load scene '" << name <<
"' (Mesh '" << assimpMesh->mName.C_Str() <<
"' has no positions)" << endl;
141 if (!assimpMesh->HasNormals())
143 cerr <<
"ERROR: Failed to load scene '" << name <<
"' (Mesh '" << assimpMesh->mName.C_Str() <<
"' has no normals)" << endl;
146 if (!assimpMesh->HasTextureCoords(0))
148 cerr <<
"ERROR: Failed to load scene '" << name <<
"' (Mesh '" << assimpMesh->mName.C_Str() <<
"' has no texture-coordinates)" << endl;
151 if (!assimpMesh->HasFaces())
153 cerr <<
"ERROR: Failed to load scene '" << name <<
"' (Mesh '" << assimpMesh->mName.C_Str() <<
"' has no faces)" << endl;
156 if (!assimpMesh->HasBones())
158 cerr <<
"ERROR: Failed to load scene '" << name <<
"' (Mesh '" << assimpMesh->mName.C_Str() <<
"' has no bones)" << endl;
162 auto meshBaseVertex = positions.size();
163 auto meshBaseIdx = indices.size();
166 auto meshVertexCount = assimpMesh->mNumVertices;
167 auto meshIndexCount = assimpMesh->mNumFaces * 3;
168 auto meshBoneCount = assimpMesh->mNumBones;
170 auto newVertexCount = meshBaseVertex + meshVertexCount;
171 auto newIndexCount = meshBaseIdx + meshIndexCount;
172 auto newBoneCount = meshBaseBone + meshBoneCount;
174 indices.reserve(newIndexCount);
175 for (uint fid = 0; fid < meshIndexCount/3; fid++)
177 auto& face = assimpMesh->mFaces[fid];
179 if (face.mNumIndices != 3)
181 cerr <<
"ERROR: Failed to load scene '" << name <<
"' (Mesh '" << assimpMesh->mName.C_Str() <<
"' has faces with " << face.mNumIndices <<
" vertices)" << endl;
185 for (
size_t iid = 0; iid < 3; iid++)
186 indices.push_back(meshBaseVertex + face.mIndices[iid]);
189 uvs.reserve(newVertexCount);
190 positions.reserve(newVertexCount);
191 normals.reserve(newVertexCount);
192 for (uint vid = 0; vid < meshVertexCount; vid++)
194 auto& uv = assimpMesh->mTextureCoords[0][vid];
195 auto& pos = assimpMesh->mVertices[vid];
196 auto& normal = assimpMesh->mNormals[vid];
198 uvs.push_back(vec2(uv.x, uv.y));
199 positions.push_back(vec3(pos.x, pos.y, pos.z));
200 normals.push_back(vec3(normal.x, normal.y, normal.z));
203 boneIds.resize(newVertexCount);
204 boneWeights.resize(newVertexCount);
205 boneCount.resize(newVertexCount);
206 for (uint vid = 0; vid < meshVertexCount; vid++)
208 boneIds[meshBaseVertex + vid] = ivec4(0);
209 boneWeights[meshBaseVertex + vid] = vec4(0);
210 boneCount[meshBaseVertex + vid] = 0;
214 for (uint bid = 0; bid < assimpMesh->mNumBones; bid++)
216 auto& bone = assimpMesh->mBones[bid];
218 auto gbid = bones.size();
220 auto found = bones.find(bone->mName.C_Str());
221 if (found != bones.end())
223 gbid = found->second;
227 bones[bone->mName.C_Str()] = gbid;
228 auto boneMat = bone->mOffsetMatrix;
234 for (uint wid = 0; wid < bone->mNumWeights; wid++)
236 auto& weight = bone->mWeights[wid];
237 auto& vid = weight.mVertexId;
239 auto& count = boneCount[meshBaseVertex + vid];
241 if (count >= 4)
continue;
243 auto& v_bid = boneIds[meshBaseVertex + vid];
244 auto& v_bweight = boneWeights[meshBaseVertex + vid];
247 v_bweight[count] = weight.mWeight;
253 mesh.reset(
new Mesh(
this,
254 assimpMesh->mName.C_Str(),
260 auto vertexCount = positions.size();
261 auto indexCount = indices.size();
266 glBufferData(GL_ARRAY_BUFFER, vertexCount *
sizeof(vec3), &positions[0], GL_STATIC_DRAW);
268 glBindBuffer(GL_ARRAY_BUFFER, 0);
273 glBufferData(GL_ARRAY_BUFFER, vertexCount *
sizeof(vec3), &normals[0], GL_STATIC_DRAW);
275 glBindBuffer(GL_ARRAY_BUFFER, 0);
280 glBufferData(GL_ARRAY_BUFFER, vertexCount *
sizeof(vec2), &uvs[0], GL_STATIC_DRAW);
282 glBindBuffer(GL_ARRAY_BUFFER, 0);
287 glBufferData(GL_ARRAY_BUFFER, vertexCount *
sizeof(ivec4), &boneIds[0], GL_STATIC_DRAW);
289 glBindBuffer(GL_ARRAY_BUFFER, 0);
294 glBufferData(GL_ARRAY_BUFFER, vertexCount *
sizeof(vec4), &boneWeights[0], GL_STATIC_DRAW);
296 glBindBuffer(GL_ARRAY_BUFFER, 0);
301 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount *
sizeof(uint), &indices[0], GL_STATIC_DRAW);
303 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
306 glGenVertexArrays(1, &
m_vao);
307 glBindVertexArray(
m_vao);
311 glEnableVertexAttribArray(positionIndex);
312 glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, 0, 0);
316 glEnableVertexAttribArray(normalIndex);
317 glVertexAttribPointer(normalIndex, 3, GL_FLOAT, GL_FALSE, 0, 0);
321 glEnableVertexAttribArray(uvIndex);
322 glVertexAttribPointer(uvIndex, 2, GL_FLOAT, GL_FALSE, 0, 0);
326 glEnableVertexAttribArray(boneIdIndex);
327 glVertexAttribIPointer(boneIdIndex, 4, GL_INT, 0, 0);
331 glEnableVertexAttribArray(boneWeightIndex);
332 glVertexAttribPointer(boneWeightIndex, 4, GL_FLOAT, GL_FALSE, 0, 0);
336 glBindVertexArray(0);
337 glBindBuffer(GL_ARRAY_BUFFER, 0);
338 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
341 map<string, Node*> nodesByName;
342 list<pair<int,Node*>> nodes;
349 function<void(Node*)> storeResult;
351 create_node(aiNode* _assimpNode,
function<
void(
Node*)> _storeResult)
352 : assimpNode(_assimpNode)
353 , storeResult(_storeResult)
357 queue<create_node> todos;
359 todos.push(create_node(scene->mRootNode, [
this]
362 m_root.reset(result);
366 auto temp = scene->mRootNode->mTransformation;
371 while (!todos.empty())
373 auto& todo = todos.front();
374 auto& assimpNode = todo.assimpNode;
377 aiMatrix4x4 assimpLocal = assimpNode->mTransformation;
378 assimpLocal.Transpose();
379 mat4* local =
reinterpret_cast<mat4*
>(&assimpLocal);
382 todo.storeResult(node);
383 nodesByName[assimpNode->mName.C_Str()] = node;
385 auto foundBone = bones.find(assimpNode->mName.C_Str());
386 if (foundBone != bones.end())
389 nodes.push_back(pair<int,Node*>(foundBone->second,node));
391 else if (assimpNode->mNumMeshes != 0)
393 nodes.push_back(pair<int,Node*>(-1,node));
396 node->
m_meshes.resize(assimpNode->mNumMeshes);
397 for (
size_t i = 0; i < assimpNode->mNumMeshes; i++)
402 node->
m_children.reserve(assimpNode->mNumChildren);
403 for (
size_t i = 0; i < assimpNode->mNumChildren; i++)
405 todos.push(create_node(assimpNode->mChildren[i], [node]
408 node->m_children.push_back(unique_ptr<Node>(result));
420 for (
auto& node : nodes)
421 if (node.first == -1)
426 (pair<int,Node*>
const & left, pair<int,Node*>
const & right)
428 return left.first < right.first;
432 for (
auto& node : nodes)
434 node.second->m_idx = i;
436 for (
auto& mesh : node.second->m_meshes)
437 mesh->m_nodeIndices.push_back(i);
449 for (
size_t aid = 0; aid < scene->mNumAnimations; aid++)
451 auto& anim = scene->mAnimations[aid];
453 auto ticks = 1.0 / (anim->mTicksPerSecond == 0 ? 25.0 : anim->mTicksPerSecond);
458 for (
size_t cid = 0; cid < anim->mNumChannels; cid++)
460 auto& chan = anim->mChannels[cid];
461 auto& node = nodesByName[chan->mNodeName.C_Str()]->m_animations[aid];
463 node.m_positions.resize(chan->mNumPositionKeys);
464 for (
size_t kid = 0; kid < chan->mNumPositionKeys; kid++)
466 auto& assimpKey = chan->mPositionKeys[kid];
467 auto& key = node.m_positions[kid];
469 key.time = (float)(assimpKey.mTime * ticks);
470 key.value = vec3(assimpKey.mValue.x, assimpKey.mValue.y, assimpKey.mValue.z);
472 sort(node.m_positions.begin(), node.m_positions.end(), []
475 return left.
time < right.time;
478 node.m_rotations.resize(chan->mNumRotationKeys);
479 for (
size_t kid = 0; kid < chan->mNumRotationKeys; kid++)
481 auto& assimpKey = chan->mRotationKeys[kid];
482 auto& key = node.m_rotations[kid];
484 key.time = (float)(assimpKey.mTime * ticks);
485 key.value = quat(assimpKey.mValue.w, assimpKey.mValue.x, assimpKey.mValue.y, assimpKey.mValue.z);
487 sort(node.m_rotations.begin(), node.m_rotations.end(), []
490 return left.
time < right.time;
493 node.m_scalings.resize(chan->mNumScalingKeys);
494 for (
size_t kid = 0; kid < chan->mNumScalingKeys; kid++)
496 auto& assimpKey = chan->mScalingKeys[kid];
497 auto& key = node.m_scalings[kid];
499 key.time = (float)(assimpKey.mTime * ticks);
500 key.value = vec3(assimpKey.mValue.x, assimpKey.mValue.y, assimpKey.mValue.z);
502 sort(node.m_scalings.begin(), node.m_scalings.end(), []
505 return left.
time < right.time;
519 glBindBuffer(GL_TEXTURE_BUFFER, 0);
526 glBindTexture(GL_TEXTURE_BUFFER, 0);
534 glBindBuffer(GL_TEXTURE_BUFFER, 0);
537 glBindTexture(GL_TEXTURE_BUFFER,
m_idTBO);
541 glBindTexture(GL_TEXTURE_BUFFER, 0);
552 glDeleteVertexArrays(1, &
m_vao);
562 size_t const minInstancesForParallel = 20;
579 float instanceTime = time;
597 if (needBufferResize)
598 glBufferData(GL_TEXTURE_BUFFER, m_boneCount*
m_instancesInBuffer*
sizeof(mat4), NULL, GL_STREAM_DRAW);
600 mat4 * states = (mat4 *)glMapBuffer(GL_TEXTURE_BUFFER, GL_WRITE_ONLY);
602 size_t instanceIdx = 0;
606 states[instanceIdx*m_boneCount + i] = instance->m_state[i];
611 glUnmapBuffer(GL_TEXTURE_BUFFER);
619 if (needBufferResize)
622 id_t * ids = (
id_t *)glMapBuffer(GL_TEXTURE_BUFFER, GL_WRITE_ONLY);
624 size_t instanceIdx = 0;
627 ids[instanceIdx] = instance->getPickId();
631 glUnmapBuffer(GL_TEXTURE_BUFFER);
633 glBindBuffer(GL_TEXTURE_BUFFER, 0);
641 glActiveTexture(GL_TEXTURE1);
643 glActiveTexture(GL_TEXTURE2);
644 glBindTexture(GL_TEXTURE_BUFFER,
m_idTBO);
646 glBindVertexArray(
m_vao);
651 glBindVertexArray(0);
653 glActiveTexture(GL_TEXTURE1);
654 glBindTexture(GL_TEXTURE_BUFFER, 0);
655 glActiveTexture(GL_TEXTURE2);
656 glBindTexture(GL_TEXTURE_BUFFER, 0);
657 glActiveTexture(GL_TEXTURE0);
700 glBindBuffer(GL_UNIFORM_BUFFER,
m_ubuffer);
702 glBufferData(GL_UNIFORM_BUFFER,
sizeof(
data), &buffer_data, GL_STATIC_DRAW);
704 glBindBuffer(GL_UNIFORM_BUFFER, 0);
708 glDeleteBuffers(1, &m_ubuffer);
715 cerr <<
"no texture found" << endl;
717 glBindBufferRange(GL_UNIFORM_BUFFER, shader->
uniformBlock(uniform), m_ubuffer, 0,
sizeof(
data));
730 , m_material(material)
731 , m_indexCount(idxCount)
732 , m_baseIndex(baseIdx)
736 m_material->bindTo(shader,
"material");
738 glDrawElementsInstanced(GL_TRIANGLES,
741 reinterpret_cast<GLuint const*>(0) + m_baseIndex,
755 glm::translate(mat4(1), interpolate(m_positions, time))
756 * glm::mat4_cast(interpolate(m_rotations, time))
757 * glm::scale(mat4(1), interpolate(m_scalings, time));
782 instance.
m_state[m_idx] = model * m_scene->m_boneOffsets[m_idx];
784 else if (m_idx != -1)
789 for (
auto& child : m_children)
790 child->updateInstance(instance, time, model);
794 auto& found = m_animations.find(animation);
796 if (found == m_animations.end())
800 if (!found->second.transformationByTime(time, OUT result))
816 , m_shader(app->getShaders().get(
"scene.mesh"))
825 cout <<
"Skinning-Mode: multi-threaded" << endl;
827 cout <<
"Skinning-Mode: single-threaded" << endl;
837 return instance.get();
840 return found->second.get();
850 mesh.second->updateNdraw(args,
m_shader);
SceneInstance * createInstance(bool pickable=true)
uint16 id_t
The data-type used for the id-buffer.
unique_ptr< Node > m_root
Configuration & getConfig()
vector< unique_ptr< Material > > m_materials
#define GL_ID_FORMAT
The OpenGL-format used for the id-buffer (has to match id_t)
void unregisterInstance(SceneInstance *obj)
vector< unique_ptr< Node > > m_children
size_t m_instancesInBuffer
static const uint boneWeight
void bindTo(Shader *shader, string const uniform)
void drawAll(DrawArgs &args)
t_obj & add(t_obj *object)
Transformation m_transformation
void updateAllInstances(float const time)
Scene(Application *app, string const &name)
static const uint position
vector< float > m_animationsDuration
void updateInstance(SceneInstance *instance, float const time)
Scene * get(string const &name)
Material(vec4 const &ambient, vec4 const &diffuse, vec4 const &specular, float const shininess, Texture *texture)
bool transformationByTime(float const time, OUT mat4 &result)
Transformation & getTransform()
SceneInstance(Application *app, Scene *parent, bool pickable=true)
bool m_needToUpdateIdBuffer
bool skinnningMultiThreaded() const
Node(Scene *scene, mat4 const &local)
vector< unique_ptr< Mesh > > m_meshes
SceneGraph & getSceneGraph()
void updateNdraw(DrawArgs &args, Shader *shader)
mat4 transformationByTime(uint const animation, float const time)
void queueAnimation(float time, uint animation)
friend class SceneInstance
mat4 const * projectionMatrix
mat4 m_inverseRootTransform
vector< mat4 > m_boneOffsets
virtual bool update(double time, double timeDelta)
void updateInstance(SceneInstance &instance, float time, mat4 const &parentTransformation)
Mesh(Scene *scene, string const &name, GLuint const baseIdx, GLuint const idxCount, Material *material)
vector< Mesh * > m_meshes
set< SceneInstance * > m_instances
GLint uniformBlock(string const &name)
queue< AnimationStart > m_animationQueue
Texture * get(string const &name)
void drawInstances(Shader *shader, set< SceneInstance * > const &instances)
void wait(uint nTimes=1)
Wait (block) until the event is set to signaled-mode.
GLuint m_boneWeightBuffer
auto_reset_event m_parallelEvent
map< string, int > m_animationsByName
AnimationStart m_animation
GLint uniform(string const &name)
void drawAllInstances(DrawArgs &args, Shader *shader)