From 10de1288c2690baa5d1472695085bf3d305c0694 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sun, 12 Nov 2023 23:04:18 -0800 Subject: [PATCH] fix view + projection, texture flipping, billboarding --- interface/src/avatar/MyAvatar.cpp | 3 +- .../src/RenderableEntityItem.cpp | 74 ++++++++++--------- .../src/RenderableGizmoEntityItem.cpp | 3 +- .../src/RenderableGridEntityItem.cpp | 3 +- .../src/RenderableImageEntityItem.cpp | 3 +- .../src/RenderableLineEntityItem.cpp | 3 +- .../src/RenderableMaterialEntityItem.cpp | 3 +- .../src/RenderablePolyLineEntityItem.cpp | 3 +- .../src/RenderablePolyVoxEntityItem.cpp | 3 +- .../src/RenderableShapeEntityItem.cpp | 3 +- .../src/RenderableTextEntityItem.cpp | 6 +- .../src/RenderableWebEntityItem.cpp | 3 +- .../src/CauterizedMeshPartPayload.cpp | 7 +- .../src/CauterizedMeshPartPayload.h | 2 +- .../render-utils/src/MeshPartPayload.cpp | 12 +-- libraries/render-utils/src/MeshPartPayload.h | 2 +- .../render-utils/src/RenderCommonTask.cpp | 21 ++++-- .../render-utils/src/RenderDeferredTask.cpp | 2 +- .../render-utils/src/RenderForwardTask.cpp | 2 +- .../render-utils/src/RenderHUDLayerTask.cpp | 4 +- .../src/ToneMapAndResampleTask.cpp | 6 +- .../render-utils/src/ToneMapAndResampleTask.h | 7 +- libraries/render/src/render/Args.h | 3 + libraries/render/src/render/CullTask.cpp | 18 ++--- libraries/render/src/render/ResampleTask.cpp | 3 +- libraries/render/src/render/ResampleTask.h | 4 +- 26 files changed, 118 insertions(+), 85 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 58c86e5e8a..32116343bf 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3530,8 +3530,9 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON_LOOK_AT || qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON; bool overrideAnim = _skeletonModel ? _skeletonModel->getRig().isPlayingOverrideAnimation() : false; + bool isInMirror = renderArgs->_mirrorDepth > 0; bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition()); - return !defaultMode || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); + return !defaultMode || isInMirror || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); } void MyAvatar::setRotationRecenterFilterLength(float length) { diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 108016a939..1fc9ed791f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -227,39 +227,13 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set& co } void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { - //glm::vec3 mirrorPosition; - //glm::quat mirrorRotation; - //withReadLock([&]{ - // mirrorPosition = _entity->getWorldPosition(); - // mirrorRotation = _entity->getWorldOrientation(); - //}); - - //glm::mat4 mirrorToWorld = glm::translate(mirrorPosition) * glm::mat4_cast(mirrorRotation); - //glm::mat4 worldToMirror = glm::inverse(mirrorToWorld); - - //// get mirror camera position by reflecting main camera position's z coordinate in mirror space - //glm::vec3 cameraPosition = viewFrustum.getPosition(); - //glm::quat cameraRotation = viewFrustum.getOrientation(); - //glm::vec3 localCameraPosition = glm::vec3(worldToMirror * glm::vec4(cameraPosition, 1.0f)); - //localCameraPosition.z *= -1.0f; - //glm::quat localCameraRotation = worldToMirror * glm::mat4_cast(cameraRotation); - //glm::vec3 localCameraRotationAngles = glm::eulerAngles(localCameraRotation); - //localCameraRotationAngles.y = M_PI - localCameraRotationAngles.y; - - //viewFrustum.setPosition(mirrorToWorld * glm::vec4(localCameraPosition, 1.0f)); - //viewFrustum.setOrientation(mirrorToWorld * glm::mat4_cast(glm::quat(localCameraRotationAngles))); - glm::vec3 mirrorPropertiesPosition; glm::quat mirrorPropertiesRotation; - glm::vec3 mirrorPropertiesDimensions; withReadLock([&]{ mirrorPropertiesPosition = _entity->getWorldPosition(); mirrorPropertiesRotation = _entity->getWorldOrientation(); - mirrorPropertiesDimensions = _entity->getScaledDimensions(); }); - glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions; - glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation); glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; @@ -275,19 +249,47 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { // get mirror camera rotation by reflecting main camera rotation in mirror space // TODO: we are assuming here that UP is world y-axis glm::quat mainCameraRotationWorld = viewFrustum.getOrientation(); - glm::mat4 mainCameraRotationMirror = mirrorFromWorld * glm::mat4_cast(mainCameraRotationWorld); - glm::mat4 mirrorCameraRotationMirror = mainCameraRotationMirror;// * glm::scale(vec3(-1.0f, 1.0f, -1.0f)); - glm::quat mirrorCameraRotationWorld = worldFromMirror * mirrorCameraRotationMirror; + glm::quat mainCameraRotationMirror = mirrorFromWorld * glm::mat4_cast(mainCameraRotationWorld); + glm::quat mirrorCameraRotationMirror = glm::quat(mainCameraRotationMirror.w, -mainCameraRotationMirror.x, -mainCameraRotationMirror.y, mainCameraRotationMirror.z) * + glm::angleAxis((float)M_PI, glm::vec3(0, 1, 0)); + glm::quat mirrorCameraRotationWorld = worldFromMirror * glm::mat4_cast(mirrorCameraRotationMirror); viewFrustum.setPosition(mirrorCameraPositionWorld); viewFrustum.setOrientation(mirrorCameraRotationWorld); - // build frustum using mirror space translation of mirrored camera - //float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; - //glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; - //glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; - //glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, viewFrustum.getFarClip()); - //viewFrustum.setProjection(frustum); + // modify the near clip plane to be the XY plane of the mirror + // from: https://terathon.com/lengyel/Lengyel-Oblique.pdf + glm::mat4 view = viewFrustum.getView(); + glm::mat4 projection = viewFrustum.getProjection(); + + //Find the camera-space 4D reflection plane vector + glm::vec3 cameraSpacePosition = glm::inverse(view) * glm::vec4(mirrorPropertiesPosition, 1.0f); + glm::vec3 cameraSpaceNormal = glm::transpose(view) * (worldFromMirrorRotation * glm::vec4(0, 0, -1, 0)); + glm::vec4 clipPlane = glm::vec4(cameraSpaceNormal, -glm::dot(cameraSpaceNormal, cameraSpacePosition)); + if (clipPlane.w > 0.0f) { + clipPlane *= -1.0f; + } + + // Calculate the clip-space corner point opposite the clipping plane + // as (sign(clipPlane.x), sign(clipPlane.y), 1, 1) and + // transform it into camera space by multiplying it + // by the inverse of the projection matrix + glm::vec4 q; + q.x = (glm::sign(clipPlane.x) + projection[0][2]) / projection[0][0]; + q.y = (glm::sign(clipPlane.y) + projection[1][2]) / projection[1][1]; + q.z = -1.0f; + q.w = (1.0f + projection[2][2]) / projection[2][3]; + + // Calculate the scaled plane vector + glm::vec4 c = (2.0f / glm::dot(clipPlane, q)) * clipPlane; + + // Replace the third row of the projection matrix + projection[0][2] = c.x; + projection[1][2] = c.y; + projection[2][2] = c.z + 1.0f; + projection[3][2] = c.w; + + viewFrustum.setProjection(projection); } void EntityRenderer::render(RenderArgs* args) { @@ -295,7 +297,7 @@ void EntityRenderer::render(RenderArgs* args) { return; } - if (_visible && (args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || !_cauterized)) { + if (_visible && (!_cauterized || args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || args->_mirrorDepth > 0)) { doRender(args); } } diff --git a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp index 42df1e2888..10ae144334 100644 --- a/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGizmoEntityItem.cpp @@ -263,8 +263,9 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) { bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp index e374fe29c0..3f40218d46 100644 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp @@ -103,8 +103,9 @@ void GridEntityRenderer::doRender(RenderArgs* args) { } else { transform.setTranslation(renderTransform.getTranslation()); } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch->setModelTransform(transform); auto minCorner = glm::vec2(-0.5f, -0.5f); diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index 9592a3e57f..4c18653d4f 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -147,8 +147,9 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { gpu::Batch* batch = args->_batch; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); float imageWidth = _texture->getWidth(); float imageHeight = _texture->getHeight(); diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index a36cdde212..1117c97c75 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -47,8 +47,9 @@ void LineEntityRenderer::doRender(RenderArgs* args) { const auto& modelTransform = getModelTransform(); Transform transform = Transform(); transform.setTranslation(modelTransform.getTranslation()); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (_linePoints.size() > 1) { DependencyManager::get()->bindSimpleProgram(batch, false, false, false, false, true, diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index b8f829f4ba..fe44c41094 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -303,8 +303,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { proceduralRender = true; } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (!proceduralRender) { diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index aca501985a..81f4c5fcb4 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -325,8 +325,9 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { buildPipelines(); } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 8331e016fd..26091a1ed4 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1860,8 +1860,9 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); gpu::Batch& batch = *args->_batch; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(_position, _orientation, _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform transform(glm::translate(_position) * rotation * _lastVoxelToLocalMatrix); batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index b8954f2ced..82350f54bf 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -118,8 +118,9 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), _shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron)); batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 2858e12afd..a3ccf78593 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -164,8 +164,9 @@ void TextEntityRenderer::doRender(RenderArgs* args) { transform = _renderTransform; }); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); @@ -352,8 +353,9 @@ void entities::TextPayload::render(RenderArgs* args) { return; } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), textRenderable->_billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); float scale = textRenderable->_lineHeight / textRenderer->getFontSize(); transform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z)); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index c98bfe7f63..77f6fe99f6 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -320,8 +320,9 @@ void WebEntityRenderer::doRender(RenderArgs* args) { batch.setResourceTexture(0, _texture); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); // Turn off jitter for these entities diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index dc1ffb7b67..78652bfb09 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -71,14 +71,15 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform _cauterizedTransform = renderTransform; } -void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { - bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; +void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { + bool useCauterizedMesh = _enableCauterization && (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && + mirrorDepth == 0; if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _cauterizedClusterBuffer); } batch.setModelTransform(_cauterizedTransform); } else { - ModelMeshPartPayload::bindTransform(batch, transform, renderMode); + ModelMeshPartPayload::bindTransform(batch, transform, renderMode, mirrorDepth); } } diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 430f41fc08..cef7b6d9b5 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -25,7 +25,7 @@ public: void updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning); - void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const override; + void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const override; void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 8d9d31390d..ad749b6d10 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -189,7 +189,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { if (_clusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer); } @@ -300,8 +300,9 @@ Item::Bound ModelMeshPartPayload::getBound(RenderArgs* args) const { auto worldBound = _adjustedLocalBound; auto parentTransform = _parentTransform; if (args) { + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; parentTransform.setRotation(BillboardModeHelpers::getBillboardRotation(parentTransform.getTranslation(), parentTransform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); } worldBound.transform(parentTransform); return worldBound; @@ -314,18 +315,19 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - if (!args || (args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && _cauterized)) { + if (!args || (_cauterized && args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && args->_mirrorDepth == 0)) { return; } gpu::Batch& batch = *(args->_batch); Transform transform = _parentTransform; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform modelTransform = transform.worldTransform(_localTransform); - bindTransform(batch, modelTransform, args->_renderMode); + bindTransform(batch, modelTransform, args->_renderMode, args->_mirrorDepth); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 3084d8ae01..6e0bb91a30 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -37,7 +37,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch); - virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const; + virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const; void drawCall(gpu::Batch& batch) const; void updateKey(const render::ItemKey& key); diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index f41ed6b21f..a3355ea805 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -277,7 +277,7 @@ public: using Outputs = render::VaryingSet4; using JobModel = render::Job::ModelIO; - SetupMirrorTask(size_t mirrorIndex) : _mirrorIndex(mirrorIndex) {} + SetupMirrorTask(size_t mirrorIndex, size_t depth) : _mirrorIndex(mirrorIndex), _depth(depth) {} void run(const render::RenderContextPointer& renderContext, const Input& inputs, Outputs& outputs) { auto args = renderContext->args; @@ -293,12 +293,17 @@ public: _mirrorFramebuffer.reset(gpu::Framebuffer::create("mirror" + _mirrorIndex, gpu::Element::COLOR_SRGBA_32, inputFramebuffer->getWidth(), inputFramebuffer->getHeight())); } + render::ItemBound mirror = items[_mirrorIndex]; + _cachedArgsPointer->_renderMode = args->_renderMode; _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; - args->_renderMode = RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE; - args->_blitFramebuffer = _mirrorFramebuffer; + _cachedArgsPointer->_ignoreItem = args->_ignoreItem; + _cachedArgsPointer->_mirrorDepth = args->_mirrorDepth; + + args->_blitFramebuffer = _mirrorFramebuffer; + args->_ignoreItem = mirror.id; + args->_mirrorDepth = _depth; - render::ItemBound mirror = items[_mirrorIndex]; ViewFrustum srcViewFrustum = args->getViewFrustum(); args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); @@ -317,6 +322,7 @@ protected: gpu::FramebufferPointer _mirrorFramebuffer { nullptr }; RenderArgsPointer _cachedArgsPointer { std::make_shared() }; size_t _mirrorIndex; + size_t _depth; }; @@ -377,6 +383,8 @@ public: // Restore the blit framebuffer after we've sampled from it if (cachedArgs) { args->_blitFramebuffer = cachedArgs->_blitFramebuffer; + args->_ignoreItem = cachedArgs->_ignoreItem; + args->_mirrorDepth = cachedArgs->_mirrorDepth; } } @@ -389,9 +397,10 @@ ShapePlumberPointer DrawMirrorTask::_forwardPipelines = std::make_shared(); void RenderMirrorTask::build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth) { - const auto setupOutput = task.addJob("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex); + size_t nextDepth = depth + 1; + const auto setupOutput = task.addJob("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex, nextDepth); - task.addJob("RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1, depth + 1); + task.addJob("RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1, nextDepth); task.addJob("DrawMirrorTask" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), setupOutput); } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 80157f9a42..92208450ef 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -244,7 +244,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Lighting Buffer ready for tone mapping const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer).asVarying(); - const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); + const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs, depth); // Debugging task is happening in the "over" layer after tone mapping and just before HUD { // Debug the bounds of the rendered items, still look at the zbuffer diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 12af18e44b..722ba2248c 100644 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -173,7 +173,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto destFramebuffer = static_cast(nullptr); const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer).asVarying(); - const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); + const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs, depth); // HUD Layer const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(toneMappedBuffer, lightingModel, hudOpaque, hudTransparent, hazeFrame).asVarying(); task.addJob("RenderHUDLayer", renderHUDLayerInputs); diff --git a/libraries/render-utils/src/RenderHUDLayerTask.cpp b/libraries/render-utils/src/RenderHUDLayerTask.cpp index 743e59eebc..8fee3d57bc 100644 --- a/libraries/render-utils/src/RenderHUDLayerTask.cpp +++ b/libraries/render-utils/src/RenderHUDLayerTask.cpp @@ -16,8 +16,8 @@ void CompositeHUD::run(const RenderContextPointer& renderContext, const gpu::Fra assert(renderContext->args); assert(renderContext->args->_context); - // We do not want to render HUD elements in secondary camera - if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) { + // We do not want to render HUD elements in secondary camera or mirrors + if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE || renderContext->args->_mirrorDepth > 0) { return; } diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.cpp b/libraries/render-utils/src/ToneMapAndResampleTask.cpp index 10312f7f2e..6ac5142e45 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.cpp +++ b/libraries/render-utils/src/ToneMapAndResampleTask.cpp @@ -25,9 +25,10 @@ using namespace shader::render_utils::program; gpu::PipelinePointer ToneMapAndResample::_pipeline; gpu::PipelinePointer ToneMapAndResample::_mirrorPipeline; -ToneMapAndResample::ToneMapAndResample() { +ToneMapAndResample::ToneMapAndResample(size_t depth) { Parameters parameters; _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Parameters), (const gpu::Byte*) ¶meters)); + _depth = depth; } void ToneMapAndResample::init() { @@ -95,7 +96,8 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In batch.setViewportTransform(destViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); + bool shouldMirror = _depth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(srcBufferSize, args->_viewport)); batch.setUniformBuffer(render_utils::slot::buffer::ToneMappingParams, _parametersBuffer); diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.h b/libraries/render-utils/src/ToneMapAndResampleTask.h index 1c7ef2cf48..3a812cf445 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.h +++ b/libraries/render-utils/src/ToneMapAndResampleTask.h @@ -49,11 +49,9 @@ signals: class ToneMapAndResample { public: - ToneMapAndResample(); + ToneMapAndResample(size_t depth); virtual ~ToneMapAndResample() {} - void render(RenderArgs* args, const gpu::TexturePointer& lightingBuffer, gpu::FramebufferPointer& destinationBuffer); - void setExposure(float exposure); float getExposure() const { return _parametersBuffer.get()._exposure; } @@ -75,7 +73,8 @@ protected: gpu::FramebufferPointer _destinationFrameBuffer; - float _factor{ 2.0f }; + float _factor { 2.0f }; + size_t _depth { 0 }; gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer); diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index d09b0d2f2f..60daa35729 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -159,6 +159,9 @@ namespace render { bool _takingSnapshot { false }; StencilMaskMode _stencilMaskMode { StencilMaskMode::NONE }; std::function _stencilMaskOperator; + + ItemID _ignoreItem { 0 }; + size_t _mirrorDepth { 0 }; }; } diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 039cf01c86..aeb7572746 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -82,7 +82,7 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const outItems.reserve(items.size()); for (auto& id : items) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { outItems.emplace_back(ItemBound(id, item.getBound(renderContext->args))); } } @@ -190,7 +190,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -205,7 +205,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -220,7 +220,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -235,7 +235,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -252,7 +252,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -267,7 +267,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -284,7 +284,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -301,7 +301,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index b868c53542..5206767bd2 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -167,7 +167,8 @@ void UpsampleToBlitFramebuffer::run(const RenderContextPointer& renderContext, c batch.setViewportTransform(viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); + bool shouldMirror = _depth % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); diff --git a/libraries/render/src/render/ResampleTask.h b/libraries/render/src/render/ResampleTask.h index 92f720c843..bf1e535949 100644 --- a/libraries/render/src/render/ResampleTask.h +++ b/libraries/render/src/render/ResampleTask.h @@ -73,7 +73,7 @@ namespace render { using Input = gpu::FramebufferPointer; using JobModel = Job::ModelIO; - UpsampleToBlitFramebuffer() {} + UpsampleToBlitFramebuffer(size_t depth) : _depth(depth) {} void run(const RenderContextPointer& renderContext, const Input& input, gpu::FramebufferPointer& resampledFrameBuffer); @@ -81,6 +81,8 @@ namespace render { static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _mirrorPipeline; + + size_t _depth; }; }