TDME2  1.9.200
SkinningShader.cpp
Go to the documentation of this file.
2 
3 #include <string>
4 
5 #include <tdme/tdme.h>
18 #include <tdme/engine/Engine.h>
20 #include <tdme/utilities/Console.h>
23 
24 using std::begin;
25 using std::copy;
26 using std::end;
27 using std::string;
28 using std::to_string;
29 
31 
49 
50 SkinningShader::SkinningShader(Renderer* renderer): mutex("skinningshader-mutex")
51 {
52  this->renderer = renderer;
53  isRunning = false;
54  initialized = false;
55  auto threadCount = renderer->isSupportingMultithreadedRendering() == true?Engine::getThreadCount():1;
56  contexts.resize(threadCount);
57 }
58 
60 {
61  return initialized;
62 }
63 
65 {
66  if (renderer->isGLCLAvailable() == true) {
70  } else {
71  auto shaderVersion = renderer->getShaderVersion();
72 
73  // shader
76  "shader/" + shaderVersion + "/skinning",
77  "skinning.glsl"
78  );
79  if (shaderId == 0) return;
80 
81  // create, attach and link program
84 
85  // link program
86  if (renderer->linkProgram(programId) == false) return;
87 
88  //
90  if (uniformVertexCount == -1) return;
92  if (uniformMatrixCount == -1) return;
94  if (uniformInstanceCount == -1) return;
95  }
96 
97  //
98  initialized = true;
99 }
100 
102 {
103  isRunning = true;
104 }
105 
106 void SkinningShader::computeSkinning(int contextIdx, ObjectBase* objectBase, ObjectNodeMesh* objectNodeMesh)
107 {
108  //
109  auto& skinningContext = contexts[contextIdx];
110  if (skinningContext.running == false) {
111  skinningContext.running = true;
112  renderer->useProgram(contextIdx, programId);
114  }
115 
116  // vbo base ids
117  auto vboBaseIds = objectNodeMesh->objectNodeRenderer->vboBaseIds;
118 
119  //
120  ModelSkinningCache* modelSkinningCacheCached = nullptr;
121  auto node = objectNodeMesh->node;
122  const auto& vertices = node->getVertices();
123  auto id = node->getModel()->getId() + "." + node->getId();
124  mutex.lock();
125  auto cacheIt = cache.find(id);
126  if (cacheIt == cache.end()) {
127  ModelSkinningCache modelSkinningCache;
128 
129  auto created = false;
130  auto skinning = node->getSkinning();
131  const auto& verticesJointsWeights = skinning->getVerticesJointsWeights();
132  const auto& weights = skinning->getWeights();
133 
134  // vbos
135  {
136  auto vboManaged = Engine::getVBOManager()->addVBO("skinning_compute_shader." + id + ".vbos", 5, true, true, created);
137  modelSkinningCache.vboIds = vboManaged->getVBOIds();
138  }
139  {
141  for (auto i = 0; i < Engine::getThreadCount(); i++) {
142  auto vboManaged = Engine::getVBOManager()->addVBO("skinning_compute_shader." + id + ".vbos.matrices." + to_string(i), 1, false, false, created);
143  modelSkinningCache.matricesVboIds.push_back(vboManaged->getVBOIds());
144  }
145  } else {
146  auto vboManaged = Engine::getVBOManager()->addVBO("skinning_compute_shader." + id + ".vbos.matrices", 1, false, false, created);
147  modelSkinningCache.matricesVboIds.push_back(vboManaged->getVBOIds());
148  }
149  }
150 
151  // vertices
152  {
153  objectNodeMesh->setupVerticesBuffer(renderer, contextIdx, (*modelSkinningCache.vboIds)[0]);
154  }
155 
156  // normals
157  {
158  objectNodeMesh->setupNormalsBuffer(renderer, contextIdx, (*modelSkinningCache.vboIds)[1]);
159  }
160 
161  {
162  // vertices joints
163  auto ibVerticesJoints = ObjectBuffer::getByteBuffer(contextIdx, vertices.size() * 1 * sizeof(int))->asIntBuffer();
164  for (auto nodeVertexIndex = 0; nodeVertexIndex < vertices.size(); nodeVertexIndex++) {
165  auto vertexJoints = verticesJointsWeights[nodeVertexIndex].size();
166  // put number of joints
167  ibVerticesJoints.put((int)vertexJoints);
168  }
169  renderer->uploadSkinningBufferObject(contextIdx, (*modelSkinningCache.vboIds)[2], ibVerticesJoints.getPosition() * sizeof(int), &ibVerticesJoints);
170  }
171 
172  {
173  // vertices joints indices
174  auto ibVerticesVertexJointsIdxs = ObjectBuffer::getByteBuffer(contextIdx, vertices.size() * 4 * sizeof(float))->asIntBuffer();
175  for (auto nodeVertexIndex = 0; nodeVertexIndex < vertices.size(); nodeVertexIndex++) {
176  const auto& vertexJointsWeight = verticesJointsWeights[nodeVertexIndex];
177  // vertex joint idx 1..4
178  for (auto i = 0; i < 4; i++) {
179  auto jointIndex = i < vertexJointsWeight.size()?vertexJointsWeight[i].getJointIndex():-1;
180  ibVerticesVertexJointsIdxs.put((int)jointIndex);
181  }
182  }
183  renderer->uploadSkinningBufferObject(contextIdx, (*modelSkinningCache.vboIds)[3], ibVerticesVertexJointsIdxs.getPosition() * sizeof(int), &ibVerticesVertexJointsIdxs);
184  }
185 
186  {
187  // vertices joints weights
188  auto fbVerticesVertexJointsWeights = ObjectBuffer::getByteBuffer(contextIdx, vertices.size() * 4 * sizeof(float))->asFloatBuffer();
189  for (auto nodeVertexIndex = 0; nodeVertexIndex < vertices.size(); nodeVertexIndex++) {
190  const auto& vertexJointsWeight = verticesJointsWeights[nodeVertexIndex];
191  // vertex joint weight 1..4
192  for (auto i = 0; i < 4; i++) {
193  fbVerticesVertexJointsWeights.put(static_cast<float>(i < vertexJointsWeight.size()?weights[vertexJointsWeight[i].getWeightIndex()]:0.0f));
194  }
195  }
196  renderer->uploadSkinningBufferObject(contextIdx, (*modelSkinningCache.vboIds)[4], fbVerticesVertexJointsWeights.getPosition() * sizeof(float), &fbVerticesVertexJointsWeights);
197  }
198 
199  // add to cache
200  cache[id] = modelSkinningCache;
201  modelSkinningCacheCached = &cache[id];
202  } else {
203  modelSkinningCacheCached = &cacheIt->second;
204  }
205  mutex.unlock();
206 
207  // bind
208  renderer->bindSkinningVerticesBufferObject(contextIdx, (*modelSkinningCacheCached->vboIds)[0]);
209  renderer->bindSkinningNormalsBufferObject(contextIdx, (*modelSkinningCacheCached->vboIds)[1]);
210  renderer->bindSkinningVertexJointsBufferObject(contextIdx, (*modelSkinningCacheCached->vboIds)[2]);
211  renderer->bindSkinningVertexJointIdxsBufferObject(contextIdx, (*modelSkinningCacheCached->vboIds)[3]);
212  renderer->bindSkinningVertexJointWeightsBufferObject(contextIdx, (*modelSkinningCacheCached->vboIds)[4]);
213 
214  // bind output / result buffers
215  renderer->bindSkinningVerticesResultBufferObject(contextIdx, (*vboBaseIds)[1]);
216  renderer->bindSkinningNormalsResultBufferObject(contextIdx, (*vboBaseIds)[2]);
217 
218  // upload matrices and set corresponding uniforms
219  {
220  Matrix4x4 skinningMatrix;
221  auto currentInstance = objectBase->getCurrentInstance();
222  auto skinning = node->getSkinning();
223  const auto& skinningJoints = skinning->getJoints();
224  auto fbMatrices = ObjectBuffer::getByteBuffer(contextIdx, objectBase->instances * skinningJoints.size() * 16 * sizeof(float))->asFloatBuffer();
225  for (auto i = 0; i < objectBase->instances; i++) {
226  if (objectBase->instanceEnabled[i] == false) continue;
227  objectBase->setCurrentInstance(i);
228  for (auto jointSkinningMatrix: objectNodeMesh->jointsSkinningMatrices[i]) {
229  if (jointSkinningMatrix != nullptr) {
230  fbMatrices.put((skinningMatrix.set(*jointSkinningMatrix).multiply(objectBase->getTransformMatrix()).getArray()));
231  } else {
232  fbMatrices.put(objectBase->getTransformMatrix().getArray());
233  }
234  }
235  }
236  objectBase->setCurrentInstance(currentInstance);
237  renderer->uploadSkinningBufferObject(contextIdx, (*modelSkinningCacheCached->matricesVboIds[contextIdx])[0], fbMatrices.getPosition() * sizeof(float), &fbMatrices);
238  renderer->setProgramUniformInteger(contextIdx, uniformMatrixCount, skinningJoints.size());
240  }
241 
242  //
243  renderer->bindSkinningMatricesBufferObject(contextIdx, (*modelSkinningCacheCached->matricesVboIds[contextIdx])[0]);
244 
245  // skinning count
246  renderer->setProgramUniformInteger(contextIdx, uniformVertexCount, vertices.size());
247 
248  // do it so
250  contextIdx,
251  (int)Math::ceil(vertices.size() / 16.0f),
252  (int)Math::ceil(objectBase->instances / 16.0f),
253  1
254  );
255 }
256 
258 {
259  if (isRunning == false) return;
260  isRunning = false;
261  for (auto& skinningContext: contexts) skinningContext.running = false;
262  // we are done, do memory barrier
264 }
265 
267  for (const auto& [cacheId, cacheEntry]: cache) {
268  Engine::getVBOManager()->removeVBO("skinning_compute_shader." + cacheEntry.id + ".vbos");
269  }
270  // TODO: Remove vaos
271  cache.clear();
272 }
Engine main class.
Definition: Engine.h:131
static VBOManager * getVBOManager()
Definition: Engine.h:635
static int getThreadCount()
Definition: Engine.h:670
Joint / Bone.
Definition: Joint.h:19
Representation of a 3D model.
Definition: Model.h:35
Model node.
Definition: Node.h:32
const vector< Vector3 > & getVertices() const
Definition: Node.h:155
Skinning definition for nodes.
Definition: Skinning.h:25
VBOManager_VBOManaged * addVBO(const string &vboId, int32_t ids, bool useGPUMemory, bool shared, bool &created)
Adds a VBO to manager or retrieve VBO if existing.
Definition: VBOManager.cpp:31
void removeVBO(const string &vboId)
Removes a VBO from manager.
Definition: VBOManager.cpp:73
virtual int32_t loadShader(int32_t type, const string &pathName, const string &fileName, const string &definitions=string(), const string &functions=string())=0
Loads a shader.
virtual void memoryBarrier()=0
Memory barrier.
virtual void bindSkinningVertexJointIdxsBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind skinning vertex joint indices buffer object.
virtual int32_t createProgram(int type)=0
Creates a shader program.
virtual void bindSkinningMatricesBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind skinning matrices result buffer object.
virtual void bindSkinningVerticesResultBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind skinning vertices result buffer object.
virtual void setProgramUniformInteger(int contextIdx, int32_t uniformId, int32_t value)=0
Set up a integer uniform value.
virtual bool linkProgram(int32_t programId)=0
Links attached shaders to a program.
virtual void bindSkinningNormalsBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind skinning normal buffer object.
void setLighting(int contextIdx, int32_t lighting)
Set current lighting model.
Definition: Renderer.h:504
virtual void attachShaderToProgram(int32_t programId, int32_t shaderId)=0
Attaches a shader to a program.
virtual void bindSkinningNormalsResultBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind skinning normals result buffer object.
virtual int32_t getProgramUniformLocation(int32_t programId, const string &name)=0
Returns location of given uniform variable.
virtual void bindSkinningVertexJointsBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind skinning vertex joints buffer object.
virtual void bindSkinningVerticesBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind skinning vertices buffer object.
virtual void uploadSkinningBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, FloatBuffer *data)=0
Upload skinning buffer object.
virtual void dispatchCompute(int contextIdx, int32_t numGroupsX, int32_t numGroupsY, int32_t numGroupsZ)=0
Dispatch compute.
virtual void bindSkinningVertexJointWeightsBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind skinning vertex joint weights buffer object.
virtual void useProgram(int contextIdx, int32_t programId)=0
Use shader program.
void setCurrentInstance(int currentInstance)
Set current instance.
Definition: ObjectBase.h:165
const Matrix4x4 & getTransformMatrix() const
Definition: ObjectBase.h:293
Buffers used to transfer data between main memory to graphics board memory.
Definition: ObjectBuffer.h:24
Object node mesh specifically for rendering.
void setupNormalsBuffer(Renderer *renderer, int contextIdx, int32_t vboId)
Set up normals buffer.
void setupVerticesBuffer(Renderer *renderer, int contextIdx, int32_t vboId)
Set up vertices buffer.
vector< vector< Matrix4x4 * > > jointsSkinningMatrices
Interface to compute shader skinning shader program.
void computeSkinning(int contextIdx, ObjectBase *objectBase, ObjectNodeMesh *objectNodeMesh)
Compute skinning.
map< string, ModelSkinningCache > cache
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Definition: Matrix4x4.h:23
Vector3 multiply(const Vector3 &vector3) const
Multiplies this matrix with vector3.
Definition: Matrix4x4.h:225
Matrix4x4 & set(float r0c0, float r0c1, float r0c2, float r0c3, float r1c0, float r1c1, float r1c2, float r1c3, float r2c0, float r2c1, float r2c2, float r2c3, float r3c0, float r3c1, float r3c2, float r3c3)
Sets this matrix by its components.
Definition: Matrix4x4.h:108
const array< float, 16 > & getArray() const
Definition: Matrix4x4.h:611
const array< float, 3 > & getArray() const
Definition: Vector3.h:366
void unlock()
Unlocks this mutex.
Definition: Mutex.h:54
void lock()
Locks the mutex, additionally mutex locks will block until other locks have been unlocked.
Definition: Mutex.h:47
Byte buffer class.
Definition: ByteBuffer.h:27
Console class.
Definition: Console.h:29
Float buffer class.
Definition: FloatBuffer.h:18
Integer buffer class.
Definition: IntBuffer.h:14