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