TDME2  1.9.200
EntityRenderer.cpp
Go to the documentation of this file.
2 
3 #include <algorithm>
4 #include <map>
5 #include <memory>
6 #include <set>
7 #include <string>
8 #include <unordered_map>
9 #include <unordered_set>
10 #include <vector>
11 
12 #include <tdme/tdme.h>
13 #include <tdme/engine/Texture.h>
14 #include <tdme/engine/Color4.h>
15 #include <tdme/engine/model/Face.h>
19 #include <tdme/engine/model/Node.h>
49 #include <tdme/engine/Camera.h>
50 #include <tdme/engine/Engine.h>
51 #include <tdme/engine/Entity.h>
55 #include <tdme/engine/Lines.h>
56 #include <tdme/engine/Object.h>
58 #include <tdme/math/Math.h>
59 #include <tdme/math/Matrix4x4.h>
60 #include <tdme/math/Vector2.h>
61 #include <tdme/math/Vector3.h>
64 #include <tdme/utilities/Console.h>
66 #include <tdme/utilities/Pool.h>
67 
68 using std::find;
69 using std::make_unique;
70 using std::map;
71 using std::set;
72 using std::sort;
73 using std::string;
74 using std::to_string;
75 using std::unique_ptr;
76 using std::unordered_map;
77 using std::unordered_set;
78 using std::vector;
79 
122 using tdme::engine::Lines;
125 using tdme::math::Math;
127 using tdme::math::Vector2;
128 using tdme::math::Vector3;
134 
135 constexpr int32_t EntityRenderer::BATCHRENDERER_MAX;
136 constexpr int32_t EntityRenderer::INSTANCEDRENDERING_OBJECTS_MAX;
137 
138 EntityRenderer::EntityRenderer(Engine* engine, Renderer* renderer) {
139  this->engine = engine;
140  this->renderer = renderer;
141  transparentRenderFacesGroupPool = make_unique<EntityRenderer_TransparentRenderFacesGroupPool>();
142  transparentRenderFacesPool = make_unique<TransparentRenderFacesPool>();
143  renderTransparentRenderPointsPool = make_unique<RenderTransparentRenderPointsPool>(65535);
144  psePointBatchRenderer = make_unique<BatchRendererPoints>(renderer, 0);
146  contexts.resize(threadCount);
147  if (this->renderer->isInstancedRenderingAvailable() == true) {
148  for (auto& contextIdx: contexts) {
149  contextIdx.bbEffectColorMuls = unique_ptr<ByteBuffer>(ByteBuffer::allocate(4 * sizeof(float) * INSTANCEDRENDERING_OBJECTS_MAX));
150  contextIdx.bbEffectColorAdds = unique_ptr<ByteBuffer>(ByteBuffer::allocate(4 * sizeof(float) * INSTANCEDRENDERING_OBJECTS_MAX));
151  contextIdx.bbMvMatrices = unique_ptr<ByteBuffer>(ByteBuffer::allocate(16 * sizeof(float) * INSTANCEDRENDERING_OBJECTS_MAX));
152  }
153  }
154 }
155 
157 }
158 
160 {
161  psePointBatchRenderer->initialize();
162  for (auto i = 0; i < threadCount; i++) {
163  auto created = false;
164  auto vboManaged = Engine::getInstance()->getVBOManager()->addVBO("tdme.objectrenderer.instancedrendering." + to_string(i), 3, false, false, created);
165  contexts[i].vboInstancedRenderingIds = vboManaged->getVBOIds();
166  }
167 }
168 
170 {
171  // dispose VBOs
172  for (auto i = 0; i < threadCount; i++) {
173  Engine::getInstance()->getVBOManager()->removeVBO("tdme.objectrenderer.instancedrendering." + to_string(i));
174  }
175  // dispose batch vbo renderer
176  for (const auto& batchRenderer: trianglesBatchRenderers) {
177  batchRenderer->dispose();
178  batchRenderer->release();
179  }
180  psePointBatchRenderer->dispose();
181 }
182 
184 {
185  // check for free batch vbo renderer
186  auto i = 0;
187  for (const auto& batchRenderer: trianglesBatchRenderers) {
188  if (batchRenderer->acquire()) return batchRenderer.get();
189  i++;
190  }
191  // try to add one
192  if (i < BATCHRENDERER_MAX) {
193  trianglesBatchRenderers.push_back(make_unique<BatchRendererTriangles>(renderer, i));
194  const auto& batchRenderer = trianglesBatchRenderers[trianglesBatchRenderers.size() - 1];
195  batchRenderer->initialize();
196  if (batchRenderer->acquire()) return batchRenderer.get();
197 
198  }
199  Console::println(string("EntityRenderer::acquireTrianglesBatchRenderer()::failed"));
200  // nope
201  return nullptr;
202 }
203 
205 {
206 }
207 
208 void EntityRenderer::render(Entity::RenderPass renderPass, const vector<Object*>& objects, bool renderTransparentFaces, int32_t renderTypes)
209 {
211  renderFunction(0, renderPass, objects, objectsByModels, renderTransparentFaces, renderTypes, transparentRenderFacesPool.get());
212  } else {
213  auto elementsIssued = 0;
214  auto queueElement = Engine::engineThreadQueueElementPool.allocate();
216  queueElement->engine = engine;
217  queueElement->rendering.renderPass = renderPass;
218  queueElement->rendering.collectTransparentFaces = renderTransparentFaces;
219  queueElement->rendering.renderTypes = renderTypes;
220  for (auto i = 0; i < objects.size(); i++) {
221  queueElement->objects.push_back(objects[i]);
222  if (queueElement->objects.size() == Engine::ENGINETHREADSQUEUE_RENDER_DISPATCH_COUNT) {
223  auto queueElementToSubmit = queueElement;
226  queueElement->engine = engine;
227  queueElement->rendering.renderPass = renderPass;
228  queueElement->rendering.collectTransparentFaces = renderTransparentFaces;
229  queueElement->rendering.renderTypes = renderTypes;
230  elementsIssued++;
231  engine->engineThreadsQueue->addElement(queueElementToSubmit, false);
232  }
233  }
234  if (queueElement->objects.empty() == false) {
235  elementsIssued++;
236  engine->engineThreadsQueue->addElement(queueElement, false);
237  }
238 
239  // wait until all elements have been processed
240  while (true == true) {
241  auto elementsProcessed = 0;
242  for (const auto& engineThread: Engine::engineThreads) elementsProcessed+= engineThread->getProcessedElements();
243  if (elementsProcessed == elementsIssued) {
244  for (const auto& engineThread: Engine::engineThreads) engineThread->resetProcessedElements();
245  break;
246  }
247  }
248 
249  //
251 
252  //
253  for (const auto& engineThread: Engine::engineThreads) {
254  transparentRenderFacesPool->merge(engineThread->transparentRenderFacesPool.get());
255  engineThread->transparentRenderFacesPool->reset();
256  }
257  }
258 }
259 
261  // use default context
262  auto contextIdx = renderer->CONTEXTINDEX_DEFAULT;
263  // render transparent render faces if any exist
264  auto& transparentRenderFaces = transparentRenderFacesPool->getTransparentRenderFaces();
265  if (transparentRenderFaces.size() > 0) {
266  // sort transparent render faces from far to near
267  sort(
268  transparentRenderFaces.begin(),
269  transparentRenderFaces.end(),
270  [](const TransparentRenderFace* face1, const TransparentRenderFace* face2) {
271  return face1->distanceFromCamera > face2->distanceFromCamera;
272  }
273  );
274  // second render pass, draw color buffer for transparent objects
275  // set up blending, but no culling and no depth buffer
276  // TODO: enabling depth buffer let shadow disappear
277  //renderer->disableDepthBufferWriting(); // TODO: a.drewke, verify that this works ok in all cases?
278  renderer->disableCulling(contextIdx);
280  // disable foliage animation
281  // reset shader
282  // TODO: shader parameters
283  renderer->setShader(contextIdx, string());
284  renderer->onUpdateShader(contextIdx);
285  // have identity texture matrix
286  renderer->getTextureMatrix(contextIdx).identity();
287  renderer->onUpdateTextureMatrix(contextIdx);
288  // actually this should not make any difference as culling is disabled
289  // but having a fixed value is not a bad idea except that it is a renderer call
290  // TODO: confirm this
292  for (auto transparentRenderFace: transparentRenderFaces) {
293  // do we have any faces yet?
294  if (nodeTransparentRenderFaces.size() == 0) {
295  // nope, so add this one
296  nodeTransparentRenderFaces.push_back(transparentRenderFace);
297  } else
298  // do we have more than face already?
299  if (nodeTransparentRenderFaces.size() > 0) {
300  // check if we have more of first type
301  if (nodeTransparentRenderFaces[0]->objectNode == transparentRenderFace->objectNode) {
302  // yep, we can add this one
303  nodeTransparentRenderFaces.push_back(transparentRenderFace);
304  } else {
305  // no, render nodeed faces
307  // reset
309  // add current face
310  nodeTransparentRenderFaces.push_back(transparentRenderFace);
311  }
312  }
313  }
314  // check if there are any left overs
315  if (nodeTransparentRenderFaces.size() > 0) {
318  }
319  // render transparent faces nodes
320  renderTransparentFacesGroups(contextIdx);
321  // no blending, but culling and depth buffer
323  renderer->enableCulling(contextIdx);
324  //renderer->enableDepthBufferWriting(); // TODO: a.drewke, verify that this works ok in all cases?
325  // done!
326  }
327 
328  // clear transparent render faces data
331 }
332 
333 void EntityRenderer::prepareTransparentFaces(const vector<TransparentRenderFace*>& transparentRenderFaces)
334 {
335  // all those faces should share the object and object node, ...
336  auto objectNode = transparentRenderFaces[0]->objectNode;
337  auto object = static_cast<Object*>(objectNode->object);
338  // model view matrix to be used with given transparent render faces
339  Matrix4x4 modelViewMatrix;
340  if (objectNode->mesh->skinning == true) {
341  modelViewMatrix.identity();
342  } else {
343  modelViewMatrix.set(*objectNode->nodeTransformMatrix).multiply(object->getTransformMatrix());
344  }
345  //
346  auto model = objectNode->object->getModel();
347  const auto& facesEntities = objectNode->node->getFacesEntities();
348  const FacesEntity* facesEntity = nullptr;
349  // attributes we collect for a transparent render face node
350  const auto& effectColorAdd = object->getEffectColorAdd();
351  const auto& effectColorMul = object->getEffectColorMul();
352  const Material* material = nullptr;
353  auto textureCoordinates = false;
354  // render transparent faces
355  for (auto i = 0; i < transparentRenderFaces.size(); i++) {
356  auto transparentRenderFace = transparentRenderFaces[i];
357  auto facesEntityIdx = transparentRenderFace->facesEntityIdx;
358  // determine if faces entity and so material did switch between last face and current face
359  if (facesEntity != &facesEntities[facesEntityIdx]) {
360  facesEntity = &facesEntities[facesEntityIdx];
361  material = facesEntity->getMaterial();
362  }
363  textureCoordinates = facesEntity->isTextureCoordinatesAvailable();
364  // create node key
365  auto transparentRenderFacesNodeKey = TransparentRenderFacesGroup::createKey(model, objectNode, facesEntityIdx, effectColorAdd, effectColorMul, material, textureCoordinates, object->getUniqueShaderId());
366  // get node
367  TransparentRenderFacesGroup* trfNode = nullptr;
368  auto trfNodeIt = transparentRenderFacesGroups.find(transparentRenderFacesNodeKey);
369  if (trfNodeIt != transparentRenderFacesGroups.end()) {
370  trfNode = trfNodeIt->second;
371  }
372  if (trfNode == nullptr) {
373  // we do not have the node, create node
374  trfNode = transparentRenderFacesGroupPool->allocate();
375  trfNode->set(this, model, objectNode, facesEntityIdx, effectColorAdd, effectColorMul, material, textureCoordinates, object->getShader());
376  transparentRenderFacesGroups[transparentRenderFacesNodeKey] = trfNode;
377  }
378  const auto& textureCoordinates = transparentRenderFace->objectNode->mesh->node->getTextureCoordinates();
379  for (auto vertexIdx = 0; vertexIdx < 3; vertexIdx++) {
380  auto arrayIdx = transparentRenderFace->objectNode->mesh->indices[transparentRenderFace->faceIdx * 3 + vertexIdx];
381  trfNode->addVertex(
382  modelViewMatrix.multiply((*transparentRenderFace->objectNode->mesh->vertices)[arrayIdx]),
383  modelViewMatrix.multiplyNoTranslation((*transparentRenderFace->objectNode->mesh->normals)[arrayIdx]),
384  transparentRenderFace->objectNode->textureMatricesByEntities[facesEntityIdx].multiply(
385  textureCoordinates.size() > 0?
386  Vector2(textureCoordinates[arrayIdx].getArray()):
387  Vector2(0.0f, 0.0f)
388  )
389  );
390  }
391  }
392 }
393 
395  for (const auto& [id, transparentRenderFacesGroup]: transparentRenderFacesGroups) {
396  transparentRenderFacesGroup->render(engine, renderer, contextIdx);
397  }
398 }
399 
401 {
402  for (const auto& [id, transparentRenderFacesGroup]: transparentRenderFacesGroups) {
403  transparentRenderFacesGroupPool->release(transparentRenderFacesGroup);
404  }
406 }
407 
408 void EntityRenderer::renderObjectsOfSameTypeNonInstanced(const vector<Object*>& objects, bool collectTransparentFaces, int32_t renderTypes) {
409  Vector3 objectCamFromAxis;
410  auto camera = engine->getCamera();
411 
412  // use default context
413  auto& objectRenderContext = contexts[0];
414  auto contextIdx = renderer->CONTEXTINDEX_DEFAULT;
415 
416  //
417  auto shadowMapping = engine->getShadowMapping();
418  Matrix4x4 modelViewMatrix;
419  Matrix4x4 cameraMatrix;
420  cameraMatrix.set(renderer->getModelViewMatrix());
421  // render faces entities
422  auto currentFrontFace = -1;
423  string shaderParametersHash;
424  auto firstObject = objects[0];
425  // all objects share the same object node structure, so we just take the first one
426  vector<int32_t>* boundVBOBaseIds = nullptr;
427  vector<int32_t>* boundVBOTangentBitangentIds = nullptr;
428  vector<int32_t>* boundVBOOrigins = nullptr;
429  auto currentLODLevel = -1;
430  int32_t boundEnvironmentMappingCubeMapTextureId = -1;
431  Vector3 boundEnvironmentMappingCubeMapPosition;
432  for (auto objectNodeIdx = 0; objectNodeIdx < firstObject->objectNodes.size(); objectNodeIdx++) {
433  auto objectNode = firstObject->objectNodes[objectNodeIdx];
434  // render each faces entity
435  const auto& facesEntities = objectNode->node->getFacesEntities();
436  auto faceIdx = 0;
437  auto facesEntityIdxCount = facesEntities.size();
438  for (auto faceEntityIdx = 0; faceEntityIdx < facesEntityIdxCount; faceEntityIdx++) {
439  auto facesEntity = &facesEntities[faceEntityIdx];
440  auto isTextureCoordinatesAvailable = facesEntity->isTextureCoordinatesAvailable();
441  auto faces = facesEntity->getFaces().size() * firstObject->instances;
442  auto facesToRender = facesEntity->getFaces().size() * firstObject->enabledInstances;
443  // material
444  auto material = facesEntity->getMaterial();
445  auto specularMaterialProperties = material != nullptr?material->getSpecularMaterialProperties():nullptr;
446  // determine if transparent
447  auto transparentFacesEntity = false;
448  // via material
449  if (specularMaterialProperties != nullptr) {
450  if (specularMaterialProperties->hasColorTransparency() == true || specularMaterialProperties->hasTextureTransparency() == true) transparentFacesEntity = true;
451  if (material->isDoubleSided() == true ||
452  (specularMaterialProperties->hasDiffuseTextureTransparency() == true && specularMaterialProperties->hasDiffuseTextureMaskedTransparency() == true)) {
453  renderer->disableCulling(contextIdx);
454  }
455  }
456  // skip, if requested
457  if (transparentFacesEntity == true) {
458  // add to transparent render faces, if requested
459  auto objectCount = objects.size();
460  for (auto objectIdx = 0; objectIdx < objectCount; objectIdx++) {
461  auto object = objects[objectIdx];
462  auto _objectNode = object->objectNodes[objectNodeIdx];
463  // set up textures
464  ObjectNode::setupTextures(renderer, contextIdx, objectNode, faceEntityIdx);
465  // set up transparent render faces
466  if (collectTransparentFaces == true) {
467  transparentRenderFacesPool->createTransparentRenderFaces(
468  (_objectNode->mesh->skinning == true?
469  modelViewMatrix.identity():
470  modelViewMatrix.set(*_objectNode->nodeTransformMatrix).multiply(object->getTransformMatrix())
471  ).multiply(cameraMatrix),
472  object->objectNodes[objectNodeIdx],
473  faceEntityIdx,
474  faceIdx
475  );
476  }
477  }
478  // keep track of rendered faces
479  faceIdx += faces;
480  // skip to next entity
481  continue;
482  }
483  // draw this faces entity for each object
484  bool materialUpdateOnly = false;
485  auto objectCount = objects.size();
486  for (auto objectIdx = 0; objectIdx < objectCount; objectIdx++) {
487  auto object = objects[objectIdx];
488  auto _objectNode = object->objectNodes[objectNodeIdx];
489  // check transparency via effect
490  if (object->effectColorMul.getAlpha() < 1.0f - Math::EPSILON ||
491  object->effectColorAdd.getAlpha() < -Math::EPSILON) {
492  // add to transparent render faces, if requested
493  if (collectTransparentFaces == true) {
494  transparentRenderFacesPool->createTransparentRenderFaces(
495  (_objectNode->mesh->skinning == true ?
496  modelViewMatrix.identity() :
497  modelViewMatrix.set(*_objectNode->nodeTransformMatrix).multiply(object->getTransformMatrix())
498  ).multiply(cameraMatrix),
499  _objectNode,
500  faceEntityIdx,
501  faceIdx
502  );
503  }
504  // skip to next object
505  continue;
506  }
507 
508  // shader
509  // TODO: shader parameters
510  if (renderer->getShader(contextIdx) != object->getShader()) {
511  renderer->setShader(contextIdx, object->getShader());
512  renderer->onUpdateShader(contextIdx);
513  // update lights
514  for (auto j = 0; j < engine->lights.size(); j++) engine->lights[j]->update(contextIdx);
515  materialUpdateOnly = false;
516  }
517  // set up material on first object
518  string materialKey;
519  if (materialUpdateOnly == false || checkMaterialChangable(_objectNode, faceEntityIdx, renderTypes) == true) {
520  setupMaterial(contextIdx, _objectNode, faceEntityIdx, renderTypes, materialUpdateOnly, materialKey);
521  // only update materials for next calls
522  materialUpdateOnly = true;
523  }
524  // shader parameters
525  if (shaderParametersHash.empty() == true || shaderParametersHash != renderer->getShaderParameters(contextIdx).getShaderParametersHash()) {
526  renderer->setShaderParameters(contextIdx, object->shaderParameters);
527  renderer->onUpdateShaderParameters(contextIdx);
528  shaderParametersHash = renderer->getShaderParameters(contextIdx).getShaderParametersHash();
529  }
530  // bind buffer base objects if not bound yet
531  auto currentVBOBaseIds = _objectNode->renderer->vboBaseIds;
532  if (boundVBOBaseIds != currentVBOBaseIds) {
533  boundVBOBaseIds = currentVBOBaseIds;
534  // texture coordinates
535  if (isTextureCoordinatesAvailable == true &&
536  (((renderTypes & RENDERTYPE_TEXTUREARRAYS) == RENDERTYPE_TEXTUREARRAYS) ||
537  ((renderTypes & RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY && specularMaterialProperties != nullptr && specularMaterialProperties->hasDiffuseTextureMaskedTransparency() == true))) {
538  renderer->bindTextureCoordinatesBufferObject(contextIdx, (*currentVBOBaseIds)[3]);
539  }
540  // indices
541  renderer->bindIndicesBufferObject(contextIdx, (*currentVBOBaseIds)[0]);
542  // vertices
543  renderer->bindVerticesBufferObject(contextIdx, (*currentVBOBaseIds)[1]);
544  // normals
545  if ((renderTypes & RENDERTYPE_NORMALS) == RENDERTYPE_NORMALS) renderer->bindNormalsBufferObject(contextIdx, (*currentVBOBaseIds)[2]);
546  }
547  auto currentVBOLods = _objectNode->renderer->vboLods;
548  if (currentVBOLods != nullptr) {
549  auto distanceSquared = objectCamFromAxis.set(object->getWorldBoundingBox()->computeClosestPointInBoundingBox(camera->getLookFrom())).sub(camera->getLookFrom()).computeLengthSquared();
550  // index buffer
551  auto lodLevel = 0;
552  if (currentVBOLods->size() >= 3 && distanceSquared >= Math::square(_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD3Distance())) {
553  lodLevel = 3;
554  } else
555  if (currentVBOLods->size() >= 2 && distanceSquared >= Math::square(_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD2Distance())) {
556  lodLevel = 2;
557  } else
558  if (currentVBOLods->size() >= 1 && distanceSquared >= Math::square(_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD1Distance())) {
559  lodLevel = 1;
560  }
561  if (lodLevel == 0) {
562  renderer->bindIndicesBufferObject(contextIdx, (*currentVBOBaseIds)[0]);
563  } else {
564  renderer->bindIndicesBufferObject(contextIdx, (*currentVBOLods)[lodLevel - 1]);
565  switch(lodLevel) {
566  case 3:
567  faces = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD3Indices().size() / 3) * firstObject->instances;
568  facesToRender = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD3Indices().size() / 3) * firstObject->enabledInstances;
569  break;
570  case 2:
571  faces = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD2Indices().size() / 3) * firstObject->instances;
572  facesToRender = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD2Indices().size() / 3) * firstObject->enabledInstances;
573  break;
574  case 1:
575  faces = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD1Indices().size() / 3) * firstObject->instances;
576  facesToRender = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD1Indices().size() / 3) * firstObject->enabledInstances;
577  break;
578  default: break;
579  }
580  }
581  currentLODLevel = lodLevel;
582  }
583  // bind tangent, bitangend buffers if not yet bound
584  auto currentVBONormalMappingIds = _objectNode->renderer->vboNormalMappingIds;
585  if ((renderTypes & RENDERTYPE_NORMALS) == RENDERTYPE_NORMALS &&
586  renderer->isNormalMappingAvailable() && currentVBONormalMappingIds != nullptr && currentVBONormalMappingIds != boundVBOTangentBitangentIds) {
587  // tangent
588  renderer->bindTangentsBufferObject(contextIdx, (*currentVBONormalMappingIds)[0]);
589  // bitangent
590  renderer->bindBitangentsBufferObject(contextIdx, (*currentVBONormalMappingIds)[1]);
591  }
592  // bind render node object origins
593  auto currentVBOOrigins = _objectNode->renderer->vboOrigins;
594  if (currentVBOOrigins != nullptr && currentVBOOrigins != boundVBOOrigins) {
595  renderer->bindOriginsBufferObject(contextIdx, (*currentVBOOrigins)[0]);
596  }
597  // set up local -> world transform matrix
599  _objectNode->mesh->skinning == true?
600  modelViewMatrix.identity():
601  modelViewMatrix.set(*_objectNode->nodeTransformMatrix).multiply(object->getTransformMatrix())
602  );
603  renderer->onUpdateModelViewMatrix(contextIdx);
604  // set up front face
605  auto objectFrontFace = objectRenderContext.rightHandedMatrix.isRightHanded(renderer->getModelViewMatrix()) == false ? renderer->FRONTFACE_CCW : renderer->FRONTFACE_CW;
606  if (objectFrontFace != currentFrontFace) {
607  renderer->setFrontFace(contextIdx, objectFrontFace);
608  currentFrontFace = objectFrontFace;
609  }
610  // set up effect color
611  if ((renderTypes & RENDERTYPE_EFFECTCOLORS) == RENDERTYPE_EFFECTCOLORS) {
612  renderer->getEffectColorMul(contextIdx) = object->effectColorMul.getArray();
613  renderer->getEffectColorAdd(contextIdx) = object->effectColorAdd.getArray();
614  renderer->onUpdateEffect(contextIdx);
615  }
616  // do transform start to shadow mapping
617  if ((renderTypes & RENDERTYPE_SHADOWMAPPING) == RENDERTYPE_SHADOWMAPPING &&
618  shadowMapping != nullptr) {
619  shadowMapping->startObjectTransform(
620  contextIdx,
621  _objectNode->mesh->skinning == true ?
622  modelViewMatrix.identity() :
623  modelViewMatrix.set(*_objectNode->nodeTransformMatrix).multiply(object->getTransformMatrix())
624  );
625  }
626  // set up texture matrix
627  // TODO: check if texture is in use
628  if ((renderTypes & RENDERTYPE_TEXTURES) == RENDERTYPE_TEXTURES ||
630  renderer->getTextureMatrix(contextIdx).set(_objectNode->textureMatricesByEntities[faceEntityIdx]);
631  renderer->onUpdateTextureMatrix(contextIdx);
632  }
633  EnvironmentMapping* environmentMappingEntity = nullptr;
634  // reflection source
635  if (object->getReflectionEnvironmentMappingId().empty() == false) {
636  auto environmentMappingEntityCandidate = engine->getEntity(object->getReflectionEnvironmentMappingId());
637  if (environmentMappingEntityCandidate != nullptr) {
638  if (environmentMappingEntityCandidate->getEntityType() == Entity::ENTITYTYPE_ENVIRONMENTMAPPING) {
639  environmentMappingEntity = static_cast<EnvironmentMapping*>(environmentMappingEntityCandidate);
640  } else
641  if (environmentMappingEntityCandidate->getEntityType() == Entity::ENTITYTYPE_ENTITYHIERARCHY) {
642  auto entityHierarchyEnvironmentMappingEntity = static_cast<EntityHierarchy*>(environmentMappingEntityCandidate)->getEntityByType(Entity::ENTITYTYPE_ENVIRONMENTMAPPING);
643  if (entityHierarchyEnvironmentMappingEntity != nullptr) environmentMappingEntity = static_cast<EnvironmentMapping*>(entityHierarchyEnvironmentMappingEntity);
644  }
645  }
646  if (environmentMappingEntity != nullptr) {
647  Vector3 environmentMappingTranslation;
648  object->getTransformMatrix().getTranslation(environmentMappingTranslation);
649  auto environmentMappingCubeMapTextureId = environmentMappingEntity->getCubeMapTextureId();
650  Vector3 environmentMappingCubeMapPosition = object->hasReflectionEnvironmentMappingPosition() == true?object->getReflectionEnvironmentMappingPosition():environmentMappingTranslation;
651  if (environmentMappingCubeMapTextureId != boundEnvironmentMappingCubeMapTextureId || environmentMappingCubeMapPosition.equals(boundEnvironmentMappingCubeMapPosition) == false) {
652  boundEnvironmentMappingCubeMapTextureId = environmentMappingCubeMapTextureId;
653  boundEnvironmentMappingCubeMapPosition = environmentMappingCubeMapPosition;
654  renderer->setEnvironmentMappingCubeMapPosition(contextIdx, environmentMappingCubeMapPosition.getArray());
655  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_ENVIRONMENT);
656  renderer->bindCubeMapTexture(contextIdx, environmentMappingCubeMapTextureId);
657  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_DIFFUSE);
658  }
659  }
660  }
661  if (environmentMappingEntity == nullptr && boundEnvironmentMappingCubeMapTextureId != -1) {
662  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_ENVIRONMENT);
664  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_DIFFUSE);
665  boundEnvironmentMappingCubeMapTextureId = -1;
666  }
667  // draw
668  renderer->drawIndexedTrianglesFromBufferObjects(contextIdx, facesToRender, faceIdx);
669  // do transform end to shadow mapping
670  if ((renderTypes & RENDERTYPE_SHADOWMAPPING) == RENDERTYPE_SHADOWMAPPING &&
671  shadowMapping != nullptr) {
672  shadowMapping->endObjectTransform();
673  }
674  }
675  // keep track of rendered faces
676  faceIdx += faces;
677  if (specularMaterialProperties != nullptr) {
678  if (material->isDoubleSided() == true ||
679  (specularMaterialProperties->hasDiffuseTextureTransparency() == true && specularMaterialProperties->hasDiffuseTextureMaskedTransparency() == true)) {
680  renderer->enableCulling(contextIdx);
681  }
682  }
683  }
684  }
685  // unbind buffers
686  renderer->unbindBufferObjects(contextIdx);
687  // restore model view matrix / view matrix
688  renderer->getModelViewMatrix().set(cameraMatrix);
689 }
690 
691 void EntityRenderer::renderObjectsOfSameTypeInstanced(int threadIdx, const vector<Object*>& objects, bool collectTransparentFaces, int32_t renderTypes, TransparentRenderFacesPool* transparentRenderFacesPool)
692 {
693  // contexts
694  auto& objectRenderContext = contexts[threadIdx];
695  auto contextIdx = threadIdx;
696 
697  //
698  RightHandedMatrix4x4 rightHandedMatrix;
699 
700  //
701  auto cameraMatrix = renderer->getCameraMatrix();
702  Vector3 objectCamFromAxis;
703  Matrix4x4 modelViewMatrixTemp;
704  Matrix4x4 modelViewMatrix;
705 
706  //
707  auto camera = engine->camera.get();
708  auto frontFace = -1;
709  auto cullingMode = 1;
710 
711  // render faces entities
712  auto firstObject = objects[0];
713 
714  // all objects share the same object node structure, so we just take the first one
715  for (auto objectNodeIdx = 0; objectNodeIdx < firstObject->objectNodes.size(); objectNodeIdx++) {
716  auto objectNode = firstObject->objectNodes[objectNodeIdx];
717  // render each faces entity
718  const auto& facesEntities = objectNode->node->getFacesEntities();
719  auto faceIdx = 0;
720  auto facesEntityIdxCount = facesEntities.size();
721  for (auto faceEntityIdx = 0; faceEntityIdx < facesEntityIdxCount; faceEntityIdx++) {
722  auto facesEntity = &facesEntities[faceEntityIdx];
723  auto isTextureCoordinatesAvailable = facesEntity->isTextureCoordinatesAvailable();
724  auto faces = facesEntity->getFaces().size() * firstObject->instances;
725  auto facesToRender = facesEntity->getFaces().size() * firstObject->enabledInstances;
726  // material
727  auto material = facesEntity->getMaterial();
728  auto specularMaterialProperties = material != nullptr?material->getSpecularMaterialProperties():nullptr;
729  // determine if transparent
730  auto transparentFacesEntity = false;
731  // via material
732  if (specularMaterialProperties != nullptr) {
733  if (specularMaterialProperties->hasColorTransparency() == true || specularMaterialProperties->hasTextureTransparency() == true) transparentFacesEntity = true;
734 
735  // skip, if requested
736  if (transparentFacesEntity == true) {
737  // add to transparent render faces, if requested
738  auto objectCount = objects.size();
739  for (auto objectIdx = 0; objectIdx < objectCount; objectIdx++) {
740  auto object = objects[objectIdx];
741  auto _objectNode = object->objectNodes[objectNodeIdx];
742  // set up textures
743  ObjectNode::setupTextures(renderer, contextIdx, objectNode, faceEntityIdx);
744  // set up transparent render faces
745  if (collectTransparentFaces == true) {
746  transparentRenderFacesPool->createTransparentRenderFaces(
747  (_objectNode->mesh->skinning == true?
748  modelViewMatrixTemp.identity() :
749  modelViewMatrixTemp.set(*_objectNode->nodeTransformMatrix).multiply(object->getTransformMatrix())
750  ).multiply(cameraMatrix),
751  object->objectNodes[objectNodeIdx],
752  faceEntityIdx,
753  faceIdx
754  );
755  }
756  }
757  // keep track of rendered faces
758  faceIdx += faces;
759  // skip to next entity
760  continue;
761  }
762 
763  if (material->isDoubleSided() == true ||
764  (specularMaterialProperties->hasDiffuseTextureTransparency() == true && specularMaterialProperties->hasDiffuseTextureMaskedTransparency() == true)) {
765  if (cullingMode != 0) {
766  renderer->disableCulling(contextIdx);
767  cullingMode = 0;
768  }
769  } else {
770  if (cullingMode != 1) {
771  renderer->enableCulling(contextIdx);
772  cullingMode = 1;
773  }
774  }
775  } else {
776  if (cullingMode != 1) {
777  renderer->enableCulling(contextIdx);
778  cullingMode = 1;
779  }
780  }
781 
782  // draw this faces entity for each object
783  objectRenderContext.objectsToRender = objects;
784  do {
785  auto hadFrontFaceSetup = false;
786  auto hadShaderSetup = false;
787 
788  Vector3 objectCamFromAxis;
789  Matrix4x4 modelViewMatrixTemp;
790  Matrix4x4 modelViewMatrix;
791 
792  FloatBuffer fbEffectColorMuls = objectRenderContext.bbEffectColorMuls->asFloatBuffer();
793  FloatBuffer fbEffectColorAdds = objectRenderContext.bbEffectColorAdds->asFloatBuffer();
794  FloatBuffer fbMvMatrices = objectRenderContext.bbMvMatrices->asFloatBuffer();
795 
796  string materialKey;
797  string shaderParametersHash;
798  bool materialUpdateOnly = false;
799  vector<int32_t>* boundVBOBaseIds = nullptr;
800  vector<int32_t>* boundVBOTangentBitangentIds = nullptr;
801  vector<int32_t>* boundVBOOrigins = nullptr;
802  auto currentLODLevel = -1;
803  int32_t boundEnvironmentMappingCubeMapTextureId = -1;
804  Vector3 boundEnvironmentMappingCubeMapPosition;
805  auto objectCount = objectRenderContext.objectsToRender.size();
806 
807  //
808  auto textureMatrix = objectRenderContext.objectsToRender[0]->objectNodes[objectNodeIdx]->textureMatricesByEntities[faceEntityIdx];
809 
810  // draw objects
811  for (auto objectIdx = 0; objectIdx < objectCount; objectIdx++) {
812  auto object = objectRenderContext.objectsToRender[objectIdx];
813  auto _objectNode = object->objectNodes[objectNodeIdx];
814 
815  // check transparency via effect
816  if (object->effectColorMul.getAlpha() < 1.0f - Math::EPSILON ||
817  object->effectColorAdd.getAlpha() < -Math::EPSILON) {
818  // add to transparent render faces, if requested
819  if (collectTransparentFaces == true) {
820  transparentRenderFacesPool->createTransparentRenderFaces(
821  (_objectNode->mesh->skinning == true ?
822  modelViewMatrixTemp.identity() :
823  modelViewMatrixTemp.set(*_objectNode->nodeTransformMatrix).multiply(object->getTransformMatrix())
824  ).multiply(cameraMatrix),
825  _objectNode,
826  faceEntityIdx,
827  faceIdx
828  );
829  }
830  // skip to next object
831  continue;
832  }
833 
834  // limit objects to render to INSTANCEDRENDERING_OBJECTS_MAX
835  if (fbMvMatrices.getPosition() / 16 == INSTANCEDRENDERING_OBJECTS_MAX) {
836  objectRenderContext.objectsNotRendered.push_back(object);
837  continue;
838  }
839 
840  // check if texture matrix did change
841  if (_objectNode->textureMatricesByEntities[faceEntityIdx].equals(textureMatrix) == false) {
842  objectRenderContext.objectsNotRendered.push_back(object);
843  continue;
844  }
845 
846  // shader
847  if (hadShaderSetup == false) {
848  if (object->getShader() != renderer->getShader(contextIdx)) {
849  renderer->setShader(contextIdx, object->getShader());
850  renderer->onUpdateShader(contextIdx);
851  for (auto j = 0; j < engine->lights.size(); j++) engine->lights[j]->update(contextIdx);
852  // issue upload matrices
853  renderer->onUpdateCameraMatrix(contextIdx);
854  renderer->onUpdateProjectionMatrix(contextIdx);
855  renderer->onUpdateTextureMatrix(contextIdx);
856  }
857  hadShaderSetup = true;
858  } else
859  if (object->getShader() != renderer->getShader(contextIdx)) {
860  objectRenderContext.objectsNotRendered.push_back(object);
861  continue;
862  }
863 
864  // set up material on first object and update on succeeding
865  auto materialKeyCurrent = materialKey;
866  if (materialUpdateOnly == false || checkMaterialChangable(_objectNode, faceEntityIdx, renderTypes) == true) {
867  setupMaterial(contextIdx, _objectNode, faceEntityIdx, renderTypes, materialUpdateOnly, materialKeyCurrent, materialKey);
868  // only update material for next material calls
869  if (materialUpdateOnly == false) {
870  materialKey = materialKeyCurrent;
871  materialUpdateOnly = true;
872  }
873  }
874 
875  // check if material key has not been set yet
876  if (materialKey != materialKeyCurrent) {
877  objectRenderContext.objectsNotRendered.push_back(object);
878  continue;
879  }
880 
881  // shader parameters
882  if (shaderParametersHash.empty() == true) {
883  renderer->setShaderParameters(contextIdx, object->shaderParameters);
884  renderer->onUpdateShaderParameters(contextIdx);
885  shaderParametersHash = renderer->getShaderParameters(contextIdx).getShaderParametersHash();
886  } else
887  if (shaderParametersHash != renderer->getShaderParameters(contextIdx).getShaderParametersHash()) {
888  objectRenderContext.objectsNotRendered.push_back(object);
889  }
890 
891  // bind buffer base objects if not bound yet
892  auto currentVBOBaseIds = _objectNode->renderer->vboBaseIds;
893  if (boundVBOBaseIds == nullptr) {
894  boundVBOBaseIds = currentVBOBaseIds;
895  // texture coordinates
896  if (isTextureCoordinatesAvailable == true &&
897  (((renderTypes & RENDERTYPE_TEXTUREARRAYS) == RENDERTYPE_TEXTUREARRAYS) ||
898  ((renderTypes & RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY && specularMaterialProperties != nullptr && specularMaterialProperties->hasDiffuseTextureMaskedTransparency() == true))) {
899  renderer->bindTextureCoordinatesBufferObject(contextIdx, (*currentVBOBaseIds)[3]);
900  }
901  // indices
902  renderer->bindIndicesBufferObject(contextIdx, (*currentVBOBaseIds)[0]);
903  // vertices
904  renderer->bindVerticesBufferObject(contextIdx, (*currentVBOBaseIds)[1]);
905  // normals
906  if ((renderTypes & RENDERTYPE_NORMALS) == RENDERTYPE_NORMALS) {
907  renderer->bindNormalsBufferObject(contextIdx, (*currentVBOBaseIds)[2]);
908  }
909  } else
910  // check if buffers did change, then skip and render in next step
911  if (boundVBOBaseIds != currentVBOBaseIds) {
912  objectRenderContext.objectsNotRendered.push_back(object);
913  continue;
914  }
915  auto currentVBOLods = _objectNode->renderer->vboLods;
916  if (currentVBOLods != nullptr) {
917  auto distanceSquared = objectCamFromAxis.set(object->getWorldBoundingBox()->computeClosestPointInBoundingBox(camera->getLookFrom())).sub(camera->getLookFrom()).computeLengthSquared();
918  // index buffer
919  auto lodLevel = 0;
920  if (currentVBOLods->size() >= 3 && distanceSquared >= Math::square(_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD3Distance())) {
921  lodLevel = 3;
922  } else
923  if (currentVBOLods->size() >= 2 && distanceSquared >= Math::square(_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD2Distance())) {
924  lodLevel = 2;
925  } else
926  if (currentVBOLods->size() >= 1 && distanceSquared >= Math::square(_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD1Distance())) {
927  lodLevel = 1;
928  }
929  if (currentLODLevel != -1 && lodLevel != currentLODLevel) {
930  objectRenderContext.objectsNotRendered.push_back(object);
931  continue;
932  }
933  if (lodLevel > 0) {
934  renderer->bindIndicesBufferObject(contextIdx, (*currentVBOLods)[lodLevel - 1]);
935  switch(lodLevel) {
936  case 3:
937  faces = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD3Indices().size() / 3) * firstObject->instances;
938  facesToRender = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD3Indices().size() / 3) * firstObject->enabledInstances;
939  break;
940  case 2:
941  faces = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD2Indices().size() / 3) * firstObject->instances;
942  facesToRender = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD2Indices().size() / 3) * firstObject->enabledInstances;
943  break;
944  case 1:
945  faces = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD1Indices().size() / 3) * firstObject->instances;
946  facesToRender = (_objectNode->node->getFacesEntities()[faceEntityIdx].getLOD1Indices().size() / 3) * firstObject->enabledInstances;
947  break;
948  default: break;
949  }
950  }
951  currentLODLevel = lodLevel;
952  }
953  // bind tangent, bitangend buffers
954  auto currentVBONormalMappingIds = _objectNode->renderer->vboNormalMappingIds;
955  if ((renderTypes & RENDERTYPE_NORMALS) == RENDERTYPE_NORMALS &&
956  renderer->isNormalMappingAvailable() == true && currentVBONormalMappingIds != nullptr) {
957  // bind tangent, bitangend buffers if not yet done
958  if (boundVBOTangentBitangentIds == nullptr) {
959  // tangent
960  renderer->bindTangentsBufferObject(contextIdx, (*currentVBONormalMappingIds)[0]);
961  // bitangent
962  renderer->bindBitangentsBufferObject(contextIdx, (*currentVBONormalMappingIds)[1]);
963  //
964  boundVBOTangentBitangentIds = currentVBONormalMappingIds;
965  } else
966  // check if buffers did change, then skip and render in next step
967  if (currentVBONormalMappingIds != boundVBOTangentBitangentIds) {
968  objectRenderContext.objectsNotRendered.push_back(object);
969  continue;
970  }
971  }
972 
973  // bind render node object origins
974  auto currentVBOOrigins = _objectNode->renderer->vboOrigins;
975  if (currentVBOOrigins != nullptr) {
976  // bind render node object origins if not yet done
977  if (boundVBOOrigins == nullptr) {
978  renderer->bindOriginsBufferObject(contextIdx, (*currentVBOOrigins)[0]);
979  //
980  boundVBOOrigins = currentVBOOrigins;
981  } else
982  // check if buffers did change, then skip and render in next step
983  if (currentVBOOrigins != boundVBOOrigins) {
984  objectRenderContext.objectsNotRendered.push_back(object);
985  continue;
986  }
987  }
988 
989  // set up local -> world transform matrix
990  modelViewMatrix.set(
991  _objectNode->mesh->skinning == true?
992  modelViewMatrixTemp.identity() :
993  modelViewMatrixTemp.set(*_objectNode->nodeTransformMatrix).
994  multiply(object->getTransformMatrix())
995  );
996 
997  // set up front face
998  auto objectFrontFace = rightHandedMatrix.isRightHanded(modelViewMatrix) == false ? renderer->FRONTFACE_CCW : renderer->FRONTFACE_CW;
999  // if front face changed just render in next step, this all makes only sense if culling is enabled
1000  if (cullingMode == 1) {
1001  if (hadFrontFaceSetup == false) {
1002  hadFrontFaceSetup = true;
1003  if (objectFrontFace != frontFace) {
1004  frontFace = objectFrontFace;
1005  renderer->setFrontFace(contextIdx, frontFace);
1006  }
1007  } else
1008  if (objectFrontFace != frontFace) {
1009  objectRenderContext.objectsNotRendered.push_back(object);
1010  continue;
1011  }
1012  }
1013 
1014  // reflection source
1015  if (object->getReflectionEnvironmentMappingId().empty() == false) {
1016  EnvironmentMapping* environmentMappingEntity = nullptr;
1017  // some note: engine->getEntity() is not thread safe if having multithreaded renderer, but at this time there should be no other access anyways
1018  auto environmentMappingEntityCandidate = engine->getEntity(object->getReflectionEnvironmentMappingId());
1019  if (environmentMappingEntityCandidate != nullptr) {
1020  if (environmentMappingEntityCandidate->getEntityType() == Entity::ENTITYTYPE_ENVIRONMENTMAPPING) {
1021  environmentMappingEntity = static_cast<EnvironmentMapping*>(environmentMappingEntityCandidate);
1022  } else
1023  if (environmentMappingEntityCandidate->getEntityType() == Entity::ENTITYTYPE_ENTITYHIERARCHY) {
1024  auto entityHierarchyEnvironmentMappingEntity = static_cast<EntityHierarchy*>(environmentMappingEntityCandidate)->getEntityByType(Entity::ENTITYTYPE_ENVIRONMENTMAPPING);
1025  if (entityHierarchyEnvironmentMappingEntity != nullptr) environmentMappingEntity = static_cast<EnvironmentMapping*>(entityHierarchyEnvironmentMappingEntity);
1026 
1027  }
1028  }
1029  if (environmentMappingEntity != nullptr) {
1030  Vector3 environmentMappingTranslation;
1031  object->getTransformMatrix().getTranslation(environmentMappingTranslation);
1032  auto environmentMappingCubeMapTextureId = environmentMappingEntity->getCubeMapTextureId();
1033  Vector3 environmentMappingCubeMapPosition = object->hasReflectionEnvironmentMappingPosition() == true?object->getReflectionEnvironmentMappingPosition():environmentMappingTranslation;
1034  if (boundEnvironmentMappingCubeMapTextureId == -1) {
1035  boundEnvironmentMappingCubeMapTextureId = environmentMappingCubeMapTextureId;
1036  boundEnvironmentMappingCubeMapPosition = environmentMappingCubeMapPosition;
1037  renderer->setEnvironmentMappingCubeMapPosition(contextIdx, environmentMappingCubeMapPosition.getArray());
1038  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_ENVIRONMENT);
1039  renderer->bindCubeMapTexture(contextIdx, environmentMappingCubeMapTextureId);
1040  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_DIFFUSE);
1041  } else
1042  if (boundEnvironmentMappingCubeMapTextureId != environmentMappingCubeMapTextureId || environmentMappingCubeMapPosition.equals(boundEnvironmentMappingCubeMapPosition) == false) {
1043  objectRenderContext.objectsNotRendered.push_back(object);
1044  continue;
1045  }
1046  }
1047  } else
1048  if (boundEnvironmentMappingCubeMapTextureId != -1) {
1049  objectRenderContext.objectsNotRendered.push_back(object);
1050  continue;
1051  }
1052  // set up effect color
1053  if ((renderTypes & RENDERTYPE_EFFECTCOLORS) == RENDERTYPE_EFFECTCOLORS) {
1054  fbEffectColorMuls.put(object->effectColorMul.getArray());
1055  fbEffectColorAdds.put(object->effectColorAdd.getArray());
1056  }
1057 
1058  // push mv, mvp to layouts
1059  fbMvMatrices.put(modelViewMatrix.getArray());
1060  }
1061 
1062  // it can happen that all faces to be rendered were transparent ones, check this and skip if feasible
1063  auto objectsToRenderIssue = fbMvMatrices.getPosition() / 16;
1064  if (objectsToRenderIssue > 0) {
1065  // upload model view matrices
1066  {
1067  renderer->uploadBufferObject(contextIdx, (*objectRenderContext.vboInstancedRenderingIds)[0], fbMvMatrices.getPosition() * sizeof(float), &fbMvMatrices);
1068  renderer->bindModelMatricesBufferObject(contextIdx, (*objectRenderContext.vboInstancedRenderingIds)[0]);
1069  }
1070 
1071  // upload effects
1072  if ((renderTypes & RENDERTYPE_EFFECTCOLORS) == RENDERTYPE_EFFECTCOLORS) {
1073  // upload effect color mul
1074  renderer->uploadBufferObject(contextIdx, (*objectRenderContext.vboInstancedRenderingIds)[1], fbEffectColorMuls.getPosition() * sizeof(float), &fbEffectColorMuls);
1075  renderer->bindEffectColorMulsBufferObject(contextIdx, (*objectRenderContext.vboInstancedRenderingIds)[1], 1);
1076  renderer->uploadBufferObject(contextIdx, (*objectRenderContext.vboInstancedRenderingIds)[2], fbEffectColorAdds.getPosition() * sizeof(float), &fbEffectColorAdds);
1077  renderer->bindEffectColorAddsBufferObject(contextIdx, (*objectRenderContext.vboInstancedRenderingIds)[2], 1);
1078  }
1079 
1080  // set up texture matrix
1081  // TODO: check if texture is in use
1082  if ((renderTypes & RENDERTYPE_TEXTURES) == RENDERTYPE_TEXTURES ||
1084  renderer->getTextureMatrix(contextIdx).set(textureMatrix);
1085  renderer->onUpdateTextureMatrix(contextIdx);
1086  }
1087 
1088  // draw
1089  renderer->drawInstancedIndexedTrianglesFromBufferObjects(contextIdx, facesToRender, faceIdx, objectsToRenderIssue);
1090  }
1091 
1092  // clear list of objects we did not render
1093  objectRenderContext.objectsToRender = objectRenderContext.objectsNotRendered;
1094  objectRenderContext.objectsNotRendered.clear();
1095 
1096  // TODO: improve me!
1097  if (boundEnvironmentMappingCubeMapTextureId != -1) {
1098  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_ENVIRONMENT);
1100  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_DIFFUSE);
1101  }
1102  } while (objectRenderContext.objectsToRender.size() > 0);
1103 
1104  // keep track of rendered faces
1105  faceIdx += faces;
1106  }
1107  }
1108 
1109  //
1110  if (cullingMode != 1) {
1111  renderer->enableCulling(contextIdx);
1112  cullingMode = 1;
1113  }
1114 
1115  // unbind buffers
1116  renderer->unbindBufferObjects(contextIdx);
1117 
1118  // reset objects to render
1119  objectRenderContext.objectsToRender.clear();
1120  objectRenderContext.objectsNotRendered.clear();
1121 }
1122 
1123 void EntityRenderer::setupMaterial(int contextIdx, ObjectNode* objectNode, int32_t facesEntityIdx, int32_t renderTypes, bool updateOnly, string& materialKey, const string& currentMaterialKey)
1124 {
1125  const auto& facesEntities = objectNode->node->getFacesEntities();
1126  auto material = facesEntities[facesEntityIdx].getMaterial();
1127  // get material or use default
1128  if (material == nullptr) material = Material::getDefaultMaterial();
1129  auto specularMaterialProperties = material->getSpecularMaterialProperties();
1130  auto pbrMaterialProperties = material->getPBRMaterialProperties();
1131 
1132  // material key
1133  materialKey = material->getId();
1134 
1135  // setup textures
1136  ObjectNode::setupTextures(renderer, contextIdx, objectNode, facesEntityIdx);
1137 
1138  //
1139  if (updateOnly == false) {
1140  if (renderer->getLighting(contextIdx) == renderer->LIGHTING_SPECULAR) {
1141  // apply materials
1142  if ((renderTypes & RENDERTYPE_MATERIALS) == RENDERTYPE_MATERIALS) {
1143  auto& rendererMaterial = renderer->getSpecularMaterial(contextIdx);
1144  rendererMaterial.ambient = specularMaterialProperties->getAmbientColor().getArray();
1145  rendererMaterial.diffuse = specularMaterialProperties->getDiffuseColor().getArray();
1146  rendererMaterial.specular = specularMaterialProperties->getSpecularColor().getArray();
1147  rendererMaterial.emission = specularMaterialProperties->getEmissionColor().getArray();
1148  rendererMaterial.shininess = specularMaterialProperties->getShininess();
1149  rendererMaterial.reflection = specularMaterialProperties->getReflection();
1150  rendererMaterial.diffuseTextureMaskedTransparency = specularMaterialProperties->hasDiffuseTextureMaskedTransparency() == true?1:0;
1151  rendererMaterial.diffuseTextureMaskedTransparencyThreshold = specularMaterialProperties->getDiffuseTextureMaskedTransparencyThreshold();
1152  renderer->onUpdateMaterial(contextIdx);
1153  }
1154  if ((renderTypes & RENDERTYPE_TEXTURES) == RENDERTYPE_TEXTURES) {
1155  // bind specular texture
1156  if (renderer->isSpecularMappingAvailable() == true) {
1157  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_SPECULAR);
1158  renderer->bindTexture(contextIdx, objectNode->specularMaterialSpecularTextureIdsByEntities[facesEntityIdx]);
1159  }
1160  // bind normal texture
1161  if (renderer->isNormalMappingAvailable() == true) {
1162  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_NORMAL);
1163  renderer->bindTexture(contextIdx, objectNode->specularMaterialNormalTextureIdsByEntities[facesEntityIdx]);
1164  }
1165  // switch back texture unit to diffuse unit
1166  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_DIFFUSE);
1167  }
1168  } else
1169  if (renderer->getLighting(contextIdx) == renderer->LIGHTING_PBR) {
1170  // apply materials
1171  if ((renderTypes & RENDERTYPE_MATERIALS) == RENDERTYPE_MATERIALS) {
1172  auto& rendererMaterial = renderer->getPBRMaterial(contextIdx);
1173  if (pbrMaterialProperties == nullptr) {
1174  rendererMaterial.baseColorFactor = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
1175  rendererMaterial.metallicFactor = 1.0f;
1176  rendererMaterial.roughnessFactor = 1.0f;
1177  rendererMaterial.normalScale = 1.0f;
1178  rendererMaterial.emissiveFactor = {{ 1.0f, 1.0f, 1.0f }};
1179  rendererMaterial.exposure = 1.0f;
1180  rendererMaterial.baseColorTextureMaskedTransparency = 0;
1181  rendererMaterial.baseColorTextureMaskedTransparencyThreshold = 0.0f;
1182  } else {
1183  rendererMaterial.baseColorFactor = pbrMaterialProperties->getBaseColorFactor().getArray();
1184  rendererMaterial.metallicFactor = pbrMaterialProperties->getMetallicFactor();
1185  rendererMaterial.roughnessFactor = pbrMaterialProperties->getRoughnessFactor();
1186  rendererMaterial.normalScale = pbrMaterialProperties->getNormalScale();
1187  rendererMaterial.emissiveFactor =
1188  {
1189  pbrMaterialProperties->getEmissiveFactor()[0],
1190  pbrMaterialProperties->getEmissiveFactor()[1],
1191  pbrMaterialProperties->getEmissiveFactor()[2]
1192  };
1193  rendererMaterial.exposure = pbrMaterialProperties->getExposure();
1194  rendererMaterial.baseColorTextureMaskedTransparency = pbrMaterialProperties->hasBaseColorTextureMaskedTransparency() == true?1:0;
1195  rendererMaterial.baseColorTextureMaskedTransparencyThreshold = pbrMaterialProperties->getBaseColorTextureMaskedTransparencyThreshold();
1196  }
1197  renderer->onUpdateMaterial(contextIdx);
1198  }
1199  if ((renderTypes & RENDERTYPE_TEXTURES) == RENDERTYPE_TEXTURES) {
1200  // bind metallic roughness texture
1201  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_METALLICROUGHNESS);
1202  renderer->bindTexture(contextIdx, objectNode->pbrMaterialMetallicRoughnessTextureIdsByEntities[facesEntityIdx]);
1203  // bind normal texture
1204  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_NORMAL);
1205  renderer->bindTexture(contextIdx, objectNode->pbrMaterialNormalTextureIdsByEntities[facesEntityIdx]);
1206  // bind emissive texture
1207  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_EMISSIVE);
1208  renderer->bindTexture(contextIdx, objectNode->pbrMaterialEmissiveTextureIdsByEntities[facesEntityIdx]);
1209  // switch back texture unit to base color unit
1210  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_BASECOLOR);
1211  }
1212  }
1213  }
1214 
1215  // bind diffuse/base color texture
1216  if ((renderTypes & RENDERTYPE_TEXTURES) == RENDERTYPE_TEXTURES ||
1218  if (renderer->getLighting(contextIdx) == renderer->LIGHTING_SPECULAR) {
1219  auto& rendererMaterial = renderer->getSpecularMaterial(contextIdx);
1220  auto diffuseTexture = specularMaterialProperties->getDiffuseTexture();
1221  rendererMaterial.diffuseTextureMaskedTransparency = specularMaterialProperties->hasDiffuseTextureMaskedTransparency() == true?1:0;
1222  rendererMaterial.diffuseTextureMaskedTransparencyThreshold = specularMaterialProperties->getDiffuseTextureMaskedTransparencyThreshold();
1223  rendererMaterial.textureAtlasSize = specularMaterialProperties->getTextureAtlasSize();
1224  rendererMaterial.textureAtlasPixelDimension = { 0.0f, 0.0f };
1225  if (rendererMaterial.textureAtlasSize > 1 && diffuseTexture != nullptr) {
1226  rendererMaterial.textureAtlasPixelDimension[0] = 1.0f / diffuseTexture->getTextureWidth();
1227  rendererMaterial.textureAtlasPixelDimension[1] = 1.0f / diffuseTexture->getTextureHeight();
1228  }
1229  renderer->onUpdateMaterial(contextIdx);
1230  if ((renderTypes & RENDERTYPE_TEXTURES) == RENDERTYPE_TEXTURES ||
1231  specularMaterialProperties->hasDiffuseTextureMaskedTransparency() == true) {
1232  auto diffuseTextureId =
1234  objectNode->specularMaterialDynamicDiffuseTextureIdsByEntities[facesEntityIdx] :
1235  objectNode->specularMaterialDiffuseTextureIdsByEntities[facesEntityIdx];
1236  materialKey+= ",";
1237  materialKey.append((const char*)&diffuseTextureId, sizeof(diffuseTextureId));
1238  if (updateOnly == false || currentMaterialKey.empty() == true) {
1239  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_DIFFUSE);
1240  renderer->bindTexture(contextIdx, diffuseTextureId);
1241  }
1242  }
1243  } else
1244  if (renderer->getLighting(contextIdx) == renderer->LIGHTING_PBR) {
1245  auto& rendererMaterial = renderer->getPBRMaterial(contextIdx);
1246  if (pbrMaterialProperties == nullptr) {
1247  rendererMaterial.baseColorTextureMaskedTransparency = 0;
1248  rendererMaterial.baseColorTextureMaskedTransparencyThreshold = 0.0f;
1249  } else {
1250  rendererMaterial.baseColorTextureMaskedTransparency = pbrMaterialProperties->hasBaseColorTextureMaskedTransparency() == true?1:0;
1251  rendererMaterial.baseColorTextureMaskedTransparencyThreshold = pbrMaterialProperties->getBaseColorTextureMaskedTransparencyThreshold();
1252  }
1253  renderer->onUpdateMaterial(contextIdx);
1254  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_BASECOLOR);
1255  renderer->bindTexture(contextIdx, objectNode->pbrMaterialBaseColorTextureIdsByEntities[facesEntityIdx]);
1256  }
1257  }
1258 }
1259 
1260 void EntityRenderer::clearMaterial(int contextIdx)
1261 {
1262  // TODO: optimize me! We do not need always to clear material
1263  if (renderer->getLighting(contextIdx) == renderer->LIGHTING_SPECULAR) {
1264  // unbind diffuse texture
1265  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_DIFFUSE);
1266  renderer->bindTexture(contextIdx, renderer->ID_NONE);
1267  // unbind specular texture
1268  if (renderer->isSpecularMappingAvailable() == true) {
1269  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_SPECULAR);
1270  renderer->bindTexture(contextIdx, renderer->ID_NONE);
1271  }
1272  // unbind normal texture
1274  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_NORMAL);
1275  renderer->bindTexture(contextIdx, renderer->ID_NONE);
1276  }
1277  // set diffuse texture unit
1278  renderer->setTextureUnit(contextIdx, LightingShaderConstants::SPECULAR_TEXTUREUNIT_DIFFUSE);
1279  } else
1280  if (renderer->getLighting(contextIdx) == renderer->LIGHTING_PBR) {
1281  // unbind base color texture
1282  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_BASECOLOR);
1283  renderer->bindTexture(contextIdx, renderer->ID_NONE);
1284  // unbind metallic roughness texture
1285  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_METALLICROUGHNESS);
1286  renderer->bindTexture(contextIdx, renderer->ID_NONE);
1287  // unbind normal texture
1288  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_NORMAL);
1289  renderer->bindTexture(contextIdx, renderer->ID_NONE);
1290  // unbind emissive texture
1291  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_EMISSIVE);
1292  renderer->bindTexture(contextIdx, renderer->ID_NONE);
1293  // set diffuse texture unit
1294  renderer->setTextureUnit(contextIdx, LightingShaderConstants::PBR_TEXTUREUNIT_BASECOLOR);
1295  }
1296 }
1297 
1298 void EntityRenderer::render(Entity::RenderPass renderPass, const vector<Entity*>& pses)
1299 {
1300  // TODO: Move me into own class
1301  if (pses.size() == 0) return;
1302 
1303  //
1304  struct PseParameters {
1305  const Color4* effectColorAdd;
1306  const Color4* effectColorMul;
1307  int32_t textureHorizontalSprites;
1308  int32_t textureVerticalSprites;
1309  float pointSize;
1310  int32_t atlasTextureIndex;
1311  };
1312  unordered_map<void*, PseParameters> rendererPseParameters;
1313 
1314  // use default context
1315  auto contextIdx = renderer->CONTEXTINDEX_DEFAULT;
1316 
1317  // store model view matrix
1318  Matrix4x4 modelViewMatrix;
1319  modelViewMatrix.set(renderer->getModelViewMatrix());
1320 
1321  // set up renderer state
1323  // model view matrix
1325  renderer->onUpdateModelViewMatrix(contextIdx);
1326 
1327  // switch back to texture unit 0, TODO: check where its set to another value but not set back
1328  renderer->setTextureUnit(contextIdx, 0);
1329 
1330  // merge pses, transform them into camera space and sort them
1331  const auto& cameraMatrix = renderer->getCameraMatrix();
1332  for (auto entity: pses) {
1333  if (entity->getRenderPass() != renderPass) continue;
1334  auto ppse = dynamic_cast<PointsParticleSystem*>(entity);
1335  if (ppse != nullptr) {
1336  int atlasTextureIndex = engine->ppsTextureAtlas.getTextureIdx(ppse->getTexture());
1337  if (atlasTextureIndex == TextureAtlas::TEXTURE_IDX_NONE) continue;
1338  rendererPseParameters[ppse] = {
1339  .effectColorAdd = &ppse->getEffectColorAdd(),
1340  .effectColorMul = &ppse->getEffectColorMul(),
1341  .textureHorizontalSprites = ppse->getTextureHorizontalSprites(),
1342  .textureVerticalSprites = ppse->getTextureVerticalSprites(),
1343  .pointSize = ppse->getPointSize(),
1344  .atlasTextureIndex = atlasTextureIndex
1345  };
1346  renderTransparentRenderPointsPool->merge(ppse->getRenderPointsPool(), cameraMatrix);
1347  } else {
1348  auto fpse = dynamic_cast<FogParticleSystem*>(entity);
1349  if (fpse != nullptr) {
1350  int atlasTextureIndex = engine->ppsTextureAtlas.getTextureIdx(fpse->getTexture());
1351  if (atlasTextureIndex == TextureAtlas::TEXTURE_IDX_NONE) continue;
1352  rendererPseParameters[fpse] = {
1353  .effectColorAdd = &fpse->getEffectColorAdd(),
1354  .effectColorMul = &fpse->getEffectColorMul(),
1355  .textureHorizontalSprites = fpse->getTextureHorizontalSprites(),
1356  .textureVerticalSprites = fpse->getTextureVerticalSprites(),
1357  .pointSize = fpse->getPointSize(),
1358  .atlasTextureIndex = atlasTextureIndex
1359  };
1360  renderTransparentRenderPointsPool->merge(fpse->getRenderPointsPool(), cameraMatrix);
1361  }
1362  }
1363  }
1364  if (renderTransparentRenderPointsPool->getTransparentRenderPointsCount() > 0) {
1366  // render
1367  auto points = renderTransparentRenderPointsPool->getTransparentRenderPoints();
1368  auto pseParameters = &rendererPseParameters.find(points[0]->particleSystem)->second;
1369  auto currentPpse = static_cast<void*>(points[0]->particleSystem);
1371  for (auto i = 0; i < renderTransparentRenderPointsPool->getTransparentRenderPointsCount(); i++) {
1372  auto point = points[i];
1373  if (point->particleSystem != (void*)currentPpse) {
1374  pseParameters = &rendererPseParameters.find(point->particleSystem)->second;
1375  currentPpse = point->particleSystem;
1376  }
1377  psePointBatchRenderer->addPoint(
1378  point,
1379  pseParameters->atlasTextureIndex,
1380  pseParameters->pointSize,
1381  *pseParameters->effectColorMul,
1382  *pseParameters->effectColorAdd,
1383  pseParameters->textureHorizontalSprites,
1384  pseParameters->textureVerticalSprites
1385  );
1386  }
1387  } else {
1388  for (auto i = 0; i < renderTransparentRenderPointsPool->getTransparentRenderPointsCount(); i++) {
1389  auto point = points[i];
1390  if (point->particleSystem != (void*)currentPpse) {
1391  pseParameters = &rendererPseParameters.find(point->particleSystem)->second;
1392  currentPpse = point->particleSystem;
1393  }
1394  psePointBatchRenderer->addPointNoInteger(
1395  point,
1396  pseParameters->atlasTextureIndex,
1397  pseParameters->pointSize,
1398  *pseParameters->effectColorMul,
1399  *pseParameters->effectColorAdd,
1400  pseParameters->textureHorizontalSprites,
1401  pseParameters->textureVerticalSprites
1402  );
1403  }
1404  }
1405 
1406  // texture atlas
1408 
1409  // render, clear
1410  psePointBatchRenderer->render(contextIdx);
1411  psePointBatchRenderer->clear();
1412 
1413  // done
1415  }
1416 
1417  // unset renderer state
1419  // restore renderer state
1420  renderer->unbindBufferObjects(contextIdx);
1421  renderer->getModelViewMatrix().set(modelViewMatrix);
1422 }
1423 
1424 void EntityRenderer::render(Entity::RenderPass renderPass, const vector<Lines*>& linesEntities) {
1425  // TODO: Move me into own class
1426  // TODO: check me performance wise again
1427  if (linesEntities.size() == 0) return;
1428 
1429  // use default context
1430  auto contextIdx = renderer->CONTEXTINDEX_DEFAULT;
1431 
1432  // switch back to texture unit 0, TODO: check where its set to another value but not set back
1433  renderer->setTextureUnit(contextIdx, 0);
1434 
1435  // store model view matrix
1436  Matrix4x4 modelViewMatrix;
1437  modelViewMatrix.set(renderer->getModelViewMatrix());
1438 
1439  // set up renderer state
1441 
1442  //
1443  for (auto entity: linesEntities) {
1444  if (entity->getRenderPass() != renderPass) continue;
1445 
1446  // model view matrix
1447  renderer->getModelViewMatrix().set(entity->getTransformMatrix()).multiply(renderer->getCameraMatrix());
1448  renderer->onUpdateModelViewMatrix(contextIdx);
1449 
1450  // render
1451  // issue rendering
1452  renderer->getEffectColorAdd(contextIdx) = entity->getEffectColorAdd().getArray();
1453  renderer->getEffectColorMul(contextIdx) = entity->getEffectColorMul().getArray();
1454  renderer->onUpdateEffect(contextIdx);
1455 
1456  // TODO: maybe use onBindTexture() or onUpdatePointSize()
1457  engine->getLinesShader()->setParameters(contextIdx, entity->getTextureId(), entity->getLineWidth());
1458 
1459  //
1460  renderer->bindVerticesBufferObject(contextIdx, (*entity->vboIds)[0]);
1461  renderer->bindColorsBufferObject(contextIdx, (*entity->vboIds)[1]);
1462  renderer->drawLinesFromBufferObjects(contextIdx, entity->points.size(), 0);
1463  }
1464 
1465  // unbind texture
1466  renderer->bindTexture(contextIdx, renderer->ID_NONE);
1467  // unset renderer state
1469  // restore renderer state
1470  renderer->unbindBufferObjects(contextIdx);
1471  renderer->getModelViewMatrix().set(modelViewMatrix);
1472 }
Color 4 definition class.
Definition: Color4.h:18
Engine main class.
Definition: Engine.h:131
TextureAtlas & getPointParticleSystemTextureAtlas()
Definition: Engine.h:518
ShadowMapping * getShadowMapping()
Definition: Engine.h:448
TextureAtlas ppsTextureAtlas
Definition: Engine.h:328
static Engine * getInstance()
Returns engine instance.
Definition: Engine.h:612
Camera * getCamera()
Definition: Engine.h:1071
static ParticlesShader * getParticlesShader()
Definition: Engine.h:455
static STATIC_DLL_IMPEXT unique_ptr< Queue< EngineThreadQueueElement > > engineThreadsQueue
Definition: Engine.h:428
static VBOManager * getVBOManager()
Definition: Engine.h:635
static STATIC_DLL_IMPEXT EngineThreadQueueElementPool engineThreadQueueElementPool
Definition: Engine.h:429
Entity * getEntity(const string &id)
Returns a entity by given id.
Definition: Engine.h:1175
static int getThreadCount()
Definition: Engine.h:670
unique_ptr< Camera > camera
Definition: Engine.h:286
static STATIC_DLL_IMPEXT vector< unique_ptr< EngineThread > > engineThreads
Definition: Engine.h:427
static LinesShader * getLinesShader()
Definition: Engine.h:462
static constexpr int ENGINETHREADSQUEUE_RENDER_DISPATCH_COUNT
Definition: Engine.h:189
array< unique_ptr< Light >, LIGHTS_MAX > lights
Definition: Engine.h:291
Entity hierarchy to be used with engine class.
Engine entity.
Definition: Entity.h:30
@ ENTITYTYPE_ENVIRONMENTMAPPING
Definition: Entity.h:90
@ ENTITYTYPE_ENTITYHIERARCHY
Definition: Entity.h:89
Environment mapping entity.
Fog particle system entity to be used with engine class.
Lines entity to be used with engine class.
Definition: Lines.h:38
Object to be used with engine class.
Definition: Object.h:60
Point particle system entity to be used with engine class.
Texture entity.
Definition: Texture.h:24
Represents a model face, consisting of vertex, normal, tangent and bitangent vectors,...
Definition: Face.h:18
Node faces entity A node can have multiple entities containing faces and a applied material.
Definition: FacesEntity.h:23
bool isTextureCoordinatesAvailable() const
Definition: FacesEntity.h:94
const Material * getMaterial() const
Definition: FacesEntity.h:74
Represents a material.
Definition: Material.h:23
Representation of a 3D model.
Definition: Model.h:35
Model node.
Definition: Node.h:32
const vector< Vector2 > & getTextureCoordinates() const
Definition: Node.h:190
const vector< FacesEntity > & getFacesEntities() const
Definition: Node.h:260
Represents specular material properties.
Represents specular material properties.
Interface to lighting shader program.
void setParameters(int contextIdx, int32_t textureId, float lineWidth)
Set parameters.
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
void setTextureAtlas(int contextIdx, TextureAtlas *textureAtlas)
Set texture atlas.
virtual void setTextureUnit(int contextIdx, int32_t textureUnit)=0
Sets up texture unit.
virtual void bindCubeMapTexture(int contextIdx, int32_t textureId)=0
Binds a cube map texture with given id or unbinds when using ID_NONE.
virtual void onUpdateProjectionMatrix(int contextIdx)=0
Update projection matrix event.
void setEnvironmentMappingCubeMapPosition(int contextIdx, const array< float, 3 > &position)
Set environment mapping cube map position.
Definition: Renderer.h:1370
array< float, 4 > & getEffectColorAdd(int contextIdx)
Get effect color add.
Definition: Renderer.h:1141
virtual void bindEffectColorMulsBufferObject(int contextIdx, int32_t bufferObjectId, int32_t divisor)=0
Bind effect color muls buffer object.
Matrix3x3 & getTextureMatrix(int contextIdx)
Get texture matrix.
Definition: Renderer.h:579
virtual void drawInstancedIndexedTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset, int32_t instances)=0
Draw instanced indexed triangles from buffer objects.
virtual void enableCulling(int contextIdx)=0
Enable culling.
virtual void drawLinesFromBufferObjects(int contextIdx, int32_t points, int32_t pointsOffset)=0
Draw lines from buffer objects.
virtual void onUpdateCameraMatrix(int contextIdx)=0
Update camera matrix event.
virtual void bindTangentsBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind tangents buffer object.
virtual void onUpdateShader(int contextIdx)=0
On update shader.
array< float, 4 > & getEffectColorMul(int contextIdx)
Get effect color mul.
Definition: Renderer.h:1131
virtual void unbindBufferObjects(int contextIdx)=0
Unbind buffer objects.
const string & getShader(int contextIdx)
Get shader.
Definition: Renderer.h:1182
virtual void enableBlending()=0
Enables blending.
virtual void disableBlending()=0
Disables blending.
const EntityShaderParameters & getShaderParameters(int contextIdx)
Get shader parameters.
Definition: Renderer.h:1209
virtual void onUpdateTextureMatrix(int contextIdx)=0
Update texture matrix for active texture unit event.
virtual void bindTexture(int contextIdx, int32_t textureId)=0
Binds a texture with given id or unbinds when using ID_NONE.
virtual void bindModelMatricesBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind model matrices buffer object.
virtual void bindIndicesBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind indices buffer object.
Renderer_SpecularMaterial & getSpecularMaterial(int contextIdx)
Get specular material.
Definition: Renderer.h:1157
virtual void setFrontFace(int contextIdx, int32_t frontFace)=0
Set up clock wise or counter clock wise faces as front face.
virtual bool isInstancedRenderingAvailable()=0
Checks if instanced rendering is available.
void setShader(int contextIdx, const string &id)
Set shader.
Definition: Renderer.h:1193
virtual void onUpdateModelViewMatrix(int contextIdx)=0
Update model view matrix event.
virtual void bindBitangentsBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind bitangents buffer object.
virtual void onUpdateShaderParameters(int contextIdx)=0
On update shader parameters.
int32_t getLighting(int contextIdx)
Get current lighting model.
Definition: Renderer.h:494
virtual void disableCulling(int contextIdx)=0
Disable culling.
virtual void drawIndexedTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset)=0
Draw indexed triangles from buffer objects.
virtual void uploadBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, FloatBuffer *data)=0
Uploads buffer data to buffer object.
virtual void bindTextureCoordinatesBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind texture coordinates buffer object.
virtual void onUpdateEffect(int contextIdx)=0
Update material.
Renderer_PBRMaterial & getPBRMaterial(int contextIdx)
Get PBR material.
Definition: Renderer.h:1167
virtual void onUpdateMaterial(int contextIdx)=0
On update material.
virtual void bindColorsBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind colors buffer object.
virtual void bindVerticesBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind vertices buffer object.
void setShaderParameters(int contextIdx, const EntityShaderParameters &parameters)
Set shader parameters.
Definition: Renderer.h:1219
virtual void bindEffectColorAddsBufferObject(int contextIdx, int32_t bufferObjectId, int32_t divisor)=0
Bind effect color adds buffer object.
virtual void bindNormalsBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind normals buffer object.
virtual void bindOriginsBufferObject(int contextIdx, int32_t bufferObjectId)=0
Bind origins buffer object.
Simple class to determine if a transform matrix is right handed.
bool isRightHanded(Matrix4x4 &matrix)
Check if matrix is right handed.
static constexpr int32_t RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY
void prepareTransparentFaces(const vector< TransparentRenderFace * > &transparentRenderFaces)
Renders transparent faces TODO: guess this should be optimized regarding GL commands skinned mesh is ...
bool checkMaterialChangable(ObjectNode *objectNode, int32_t facesEntityIdx, int32_t renderTypes)
Checks if a material could change when having multiple objects but same model.
void render(Entity::RenderPass renderPass, const vector< Object * > &objects, bool renderTransparentFaces, int32_t renderTypes)
Renders all given objects.
unique_ptr< RenderTransparentRenderPointsPool > renderTransparentRenderPointsPool
void renderFunction(int threadIdx, Entity::RenderPass renderPass, const vector< Object * > &objects, array< vector< Object * >, Engine::UNIQUEMODELID_MAX > &objectsByModels, bool renderTransparentFaces, int renderTypes, TransparentRenderFacesPool *transparentRenderFacesPool)
Render function.
unique_ptr< EntityRenderer_TransparentRenderFacesGroupPool > transparentRenderFacesGroupPool
array< vector< Object * >, Engine::UNIQUEMODELID_MAX > objectsByModels
static constexpr int32_t RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY
unique_ptr< TransparentRenderFacesPool > transparentRenderFacesPool
void setupMaterial(int contextIdx, ObjectNode *objectNode, int32_t facesEntityIdx, int32_t renderTypes, bool updateOnly, string &materialKey, const string &currentMaterialKey=string())
Set ups a material for rendering.
void renderObjectsOfSameTypeInstanced(int threadIdx, const vector< Object * > &objects, bool collectTransparentFaces, int32_t renderTypes, TransparentRenderFacesPool *transparentRenderFacesPool)
Renders multiple objects of same type(with same model) using instancing.
void releaseTransparentFacesGroups()
Release transparent faces groups.
unordered_map< tuple< Model *, ObjectNode *, int32_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, int32_t, const Material *, bool, uint8_t >, TransparentRenderFacesGroup *, TransparentRenderFacesGroup_Hash > transparentRenderFacesGroups
vector< unique_ptr< BatchRendererTriangles > > trianglesBatchRenderers
unique_ptr< BatchRendererPoints > psePointBatchRenderer
void renderTransparentFacesGroups(int contextIdx)
Render transparent faces groups.
vector< TransparentRenderFace * > nodeTransparentRenderFaces
void clearMaterial(int contextIdx)
Clear material for rendering.
void renderObjectsOfSameTypeNonInstanced(const vector< Object * > &objects, bool collectTransparentFaces, int32_t renderTypes)
Renders multiple objects of same type(with same model) not using instancing.
void renderTransparentFaces()
Renders collected transparent faces.
Buffers used to transfer data between main memory to graphics board memory.
Definition: ObjectBuffer.h:24
Object node mesh specifically for rendering.
Object node specifically for rendering.
Definition: ObjectNode.h:41
vector< int32_t > pbrMaterialBaseColorTextureIdsByEntities
Definition: ObjectNode.h:69
vector< int32_t > specularMaterialDiffuseTextureIdsByEntities
Definition: ObjectNode.h:65
vector< int32_t > specularMaterialDynamicDiffuseTextureIdsByEntities
Definition: ObjectNode.h:66
vector< int32_t > pbrMaterialMetallicRoughnessTextureIdsByEntities
Definition: ObjectNode.h:70
vector< int32_t > specularMaterialNormalTextureIdsByEntities
Definition: ObjectNode.h:68
vector< int32_t > specularMaterialSpecularTextureIdsByEntities
Definition: ObjectNode.h:67
vector< int32_t > pbrMaterialEmissiveTextureIdsByEntities
Definition: ObjectNode.h:72
static void setupTextures(Renderer *renderer, int contextIdx, ObjectNode *objectNode, int32_t facesEntityIdx)
Set up textures for given object node and faces entity.
Definition: ObjectNode.cpp:192
void addVertex(const Vector3 &vertex, const Vector3 &normal, const Vector2 &textureCoordinate)
Adds a vertex to this transparent render faces group.
void set(EntityRenderer *objectRenderer, Model *model, ObjectNode *objectNode, int32_t facesEntityIdx, const Color4 &effectColorAdd, const Color4 &effectColorMul, const Material *material, bool textureCoordinates, const string &shader)
Set transparent render faces group.
static const tuple< Model *, ObjectNode *, int32_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, int32_t, const Material *, bool, uint8_t > createKey(Model *model, ObjectNode *objectNode, int32_t facesEntityIdx, const Color4 &effectColorAdd, const Color4 &effectColorMul, const Material *material, bool textureCoordinates, uint8_t uniqueShaderId)
Creates a key for given transparent render faces group attributes.
Standard math functions.
Definition: Math.h:19
Matrix3x3 & identity()
Creates identity matrix.
Definition: Matrix3x3.h:128
Matrix3x3 & set(float r0c0, float r0c1, float r0c2, float r1c0, float r1c1, float r1c2, float r2c0, float r2c1, float r2c2)
Sets this matrix by its components.
Definition: Matrix3x3.h:88
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Definition: Matrix4x4.h:23
Matrix4x4 & identity()
Creates identity matrix.
Definition: Matrix4x4.h:158
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
Vector3 multiplyNoTranslation(const Vector3 &vector3) const
Multiplies this matrix with vector3 while ignoring translation.
Definition: Matrix4x4.h:238
Vector2 class representing vector2 mathematical structure and operations with x, y components.
Definition: Vector2.h:20
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
const array< float, 3 > & getArray() const
Definition: Vector3.h:366
float computeLengthSquared() const
Definition: Vector3.h:281
Vector3 & sub(float scalar)
Subtracts a scalar.
Definition: Vector3.h:177
Vector3 & set(float x, float y, float z)
Sets this vector3 by its components.
Definition: Vector3.h:70
bool equals(const Vector3 &vector3, float tolerance=Math::EPSILON) const
Compares this vector3 with given vector3.
Definition: Vector3.h:226
Base class for threads.
Definition: Thread.h:20
Byte buffer class.
Definition: ByteBuffer.h:27
Console class.
Definition: Console.h:29
Float buffer class.
Definition: FloatBuffer.h:18
FloatBuffer * put(float value)
Put a float value into float buffer.
Definition: FloatBuffer.h:67
virtual int64_t getPosition()
Definition: FloatBuffer.h:45
Pool template class.
Definition: Pool.h:20
T * allocate()
Allocate a new element from pool.
Definition: Pool.h:55
void reset()
Reset this pool.
Definition: Pool.h:98
int getTextureIdx(Texture *texture)
Returns specific atlas texture index within atlas.
Definition: TextureAtlas.h:60