fix view + projection, texture flipping, billboarding

This commit is contained in:
HifiExperiments 2023-11-12 23:04:18 -08:00
parent 89e6cbbfa4
commit 10de1288c2
26 changed files with 118 additions and 85 deletions

View file

@ -3530,8 +3530,9 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON_LOOK_AT || bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON_LOOK_AT ||
qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON; qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON;
bool overrideAnim = _skeletonModel ? _skeletonModel->getRig().isPlayingOverrideAnimation() : false; bool overrideAnim = _skeletonModel ? _skeletonModel->getRig().isPlayingOverrideAnimation() : false;
bool isInMirror = renderArgs->_mirrorDepth > 0;
bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition()); bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition());
return !defaultMode || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); return !defaultMode || isInMirror || (!firstPerson && !insideHead) || (overrideAnim && !insideHead);
} }
void MyAvatar::setRotationRecenterFilterLength(float length) { void MyAvatar::setRotationRecenterFilterLength(float length) {

View file

@ -227,39 +227,13 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set<QUuid>& co
} }
void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { 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::vec3 mirrorPropertiesPosition;
glm::quat mirrorPropertiesRotation; glm::quat mirrorPropertiesRotation;
glm::vec3 mirrorPropertiesDimensions;
withReadLock([&]{ withReadLock([&]{
mirrorPropertiesPosition = _entity->getWorldPosition(); mirrorPropertiesPosition = _entity->getWorldPosition();
mirrorPropertiesRotation = _entity->getWorldOrientation(); mirrorPropertiesRotation = _entity->getWorldOrientation();
mirrorPropertiesDimensions = _entity->getScaledDimensions();
}); });
glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions;
glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation); glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation);
glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition);
glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; 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 // get mirror camera rotation by reflecting main camera rotation in mirror space
// TODO: we are assuming here that UP is world y-axis // TODO: we are assuming here that UP is world y-axis
glm::quat mainCameraRotationWorld = viewFrustum.getOrientation(); glm::quat mainCameraRotationWorld = viewFrustum.getOrientation();
glm::mat4 mainCameraRotationMirror = mirrorFromWorld * glm::mat4_cast(mainCameraRotationWorld); glm::quat mainCameraRotationMirror = mirrorFromWorld * glm::mat4_cast(mainCameraRotationWorld);
glm::mat4 mirrorCameraRotationMirror = mainCameraRotationMirror;// * glm::scale(vec3(-1.0f, 1.0f, -1.0f)); glm::quat mirrorCameraRotationMirror = glm::quat(mainCameraRotationMirror.w, -mainCameraRotationMirror.x, -mainCameraRotationMirror.y, mainCameraRotationMirror.z) *
glm::quat mirrorCameraRotationWorld = worldFromMirror * mirrorCameraRotationMirror; glm::angleAxis((float)M_PI, glm::vec3(0, 1, 0));
glm::quat mirrorCameraRotationWorld = worldFromMirror * glm::mat4_cast(mirrorCameraRotationMirror);
viewFrustum.setPosition(mirrorCameraPositionWorld); viewFrustum.setPosition(mirrorCameraPositionWorld);
viewFrustum.setOrientation(mirrorCameraRotationWorld); viewFrustum.setOrientation(mirrorCameraRotationWorld);
// build frustum using mirror space translation of mirrored camera // modify the near clip plane to be the XY plane of the mirror
//float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; // from: https://terathon.com/lengyel/Lengyel-Oblique.pdf
//glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; glm::mat4 view = viewFrustum.getView();
//glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; glm::mat4 projection = viewFrustum.getProjection();
//glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, viewFrustum.getFarClip());
//viewFrustum.setProjection(frustum); //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) { void EntityRenderer::render(RenderArgs* args) {
@ -295,7 +297,7 @@ void EntityRenderer::render(RenderArgs* args) {
return; 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); doRender(args);
} }
} }

View file

@ -263,8 +263,9 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; 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, 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); batch.setModelTransform(transform);
Pipeline pipelineType = getPipelineType(materials); Pipeline pipelineType = getPipelineType(materials);

View file

@ -103,8 +103,9 @@ void GridEntityRenderer::doRender(RenderArgs* args) {
} else { } else {
transform.setTranslation(renderTransform.getTranslation()); 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, 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->setModelTransform(transform);
auto minCorner = glm::vec2(-0.5f, -0.5f); auto minCorner = glm::vec2(-0.5f, -0.5f);

View file

@ -147,8 +147,9 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch* batch = args->_batch; 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, 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 imageWidth = _texture->getWidth();
float imageHeight = _texture->getHeight(); float imageHeight = _texture->getHeight();

View file

@ -47,8 +47,9 @@ void LineEntityRenderer::doRender(RenderArgs* args) {
const auto& modelTransform = getModelTransform(); const auto& modelTransform = getModelTransform();
Transform transform = Transform(); Transform transform = Transform();
transform.setTranslation(modelTransform.getTranslation()); 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, 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); batch.setModelTransform(transform);
if (_linePoints.size() > 1) { if (_linePoints.size() > 1) {
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, false, true, DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, false, false, true,

View file

@ -303,8 +303,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
proceduralRender = true; proceduralRender = true;
} }
bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0;
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, 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.setModelTransform(transform);
if (!proceduralRender) { if (!proceduralRender) {

View file

@ -325,8 +325,9 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
buildPipelines(); buildPipelines();
} }
bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0;
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, 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.setModelTransform(transform);
batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]); batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]);

View file

@ -1860,8 +1860,9 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render");
gpu::Batch& batch = *args->_batch; 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, 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); Transform transform(glm::translate(_position) * rotation * _lastVoxelToLocalMatrix);
batch.setModelTransform(transform); batch.setModelTransform(transform);

View file

@ -118,8 +118,9 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; 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, 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)); _shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron));
batch.setModelTransform(transform); batch.setModelTransform(transform);

View file

@ -164,8 +164,9 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
transform = _renderTransform; transform = _renderTransform;
}); });
bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0;
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, 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.setModelTransform(transform);
Pipeline pipelineType = getPipelineType(materials); Pipeline pipelineType = getPipelineType(materials);
@ -352,8 +353,9 @@ void entities::TextPayload::render(RenderArgs* args) {
return; return;
} }
bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0;
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), textRenderable->_billboardMode, 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(); float scale = textRenderable->_lineHeight / textRenderer->getFontSize();
transform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z)); transform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z));

View file

@ -320,8 +320,9 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
batch.setResourceTexture(0, _texture); 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, 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.setModelTransform(transform);
// Turn off jitter for these entities // Turn off jitter for these entities

View file

@ -71,14 +71,15 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform
_cauterizedTransform = renderTransform; _cauterizedTransform = renderTransform;
} }
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const {
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; bool useCauterizedMesh = _enableCauterization && (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) &&
mirrorDepth == 0;
if (useCauterizedMesh) { if (useCauterizedMesh) {
if (_cauterizedClusterBuffer) { if (_cauterizedClusterBuffer) {
batch.setUniformBuffer(graphics::slot::buffer::Skinning, _cauterizedClusterBuffer); batch.setUniformBuffer(graphics::slot::buffer::Skinning, _cauterizedClusterBuffer);
} }
batch.setModelTransform(_cauterizedTransform); batch.setModelTransform(_cauterizedTransform);
} else { } else {
ModelMeshPartPayload::bindTransform(batch, transform, renderMode); ModelMeshPartPayload::bindTransform(batch, transform, renderMode, mirrorDepth);
} }
} }

View file

@ -25,7 +25,7 @@ public:
void updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning); 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; } void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; }

View file

@ -189,7 +189,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setInputStream(0, _drawMesh->getVertexStream()); 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) { if (_clusterBuffer) {
batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer); batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer);
} }
@ -300,8 +300,9 @@ Item::Bound ModelMeshPartPayload::getBound(RenderArgs* args) const {
auto worldBound = _adjustedLocalBound; auto worldBound = _adjustedLocalBound;
auto parentTransform = _parentTransform; auto parentTransform = _parentTransform;
if (args) { if (args) {
bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0;
parentTransform.setRotation(BillboardModeHelpers::getBillboardRotation(parentTransform.getTranslation(), parentTransform.getRotation(), _billboardMode, 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); worldBound.transform(parentTransform);
return worldBound; return worldBound;
@ -314,18 +315,19 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const {
void ModelMeshPartPayload::render(RenderArgs* args) { void ModelMeshPartPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("ModelMeshPartPayload::render"); 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; return;
} }
gpu::Batch& batch = *(args->_batch); gpu::Batch& batch = *(args->_batch);
Transform transform = _parentTransform; Transform transform = _parentTransform;
bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0;
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, 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); 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 //Bind the index buffer and vertex buffer and Blend shapes if needed
bindMesh(batch); bindMesh(batch);

View file

@ -37,7 +37,7 @@ public:
// ModelMeshPartPayload functions to perform render // ModelMeshPartPayload functions to perform render
void bindMesh(gpu::Batch& batch); 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 drawCall(gpu::Batch& batch) const;
void updateKey(const render::ItemKey& key); void updateKey(const render::ItemKey& key);

View file

@ -277,7 +277,7 @@ public:
using Outputs = render::VaryingSet4<render::ItemBound, gpu::FramebufferPointer, RenderArgsPointer, glm::vec2>; using Outputs = render::VaryingSet4<render::ItemBound, gpu::FramebufferPointer, RenderArgsPointer, glm::vec2>;
using JobModel = render::Job::ModelIO<SetupMirrorTask, Input, Outputs>; using JobModel = render::Job::ModelIO<SetupMirrorTask, Input, Outputs>;
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) { void run(const render::RenderContextPointer& renderContext, const Input& inputs, Outputs& outputs) {
auto args = renderContext->args; 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())); _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->_renderMode = args->_renderMode;
_cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer;
args->_renderMode = RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE; _cachedArgsPointer->_ignoreItem = args->_ignoreItem;
args->_blitFramebuffer = _mirrorFramebuffer; _cachedArgsPointer->_mirrorDepth = args->_mirrorDepth;
args->_blitFramebuffer = _mirrorFramebuffer;
args->_ignoreItem = mirror.id;
args->_mirrorDepth = _depth;
render::ItemBound mirror = items[_mirrorIndex];
ViewFrustum srcViewFrustum = args->getViewFrustum(); ViewFrustum srcViewFrustum = args->getViewFrustum();
args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum);
@ -317,6 +322,7 @@ protected:
gpu::FramebufferPointer _mirrorFramebuffer { nullptr }; gpu::FramebufferPointer _mirrorFramebuffer { nullptr };
RenderArgsPointer _cachedArgsPointer { std::make_shared<RenderArgs>() }; RenderArgsPointer _cachedArgsPointer { std::make_shared<RenderArgs>() };
size_t _mirrorIndex; size_t _mirrorIndex;
size_t _depth;
}; };
@ -377,6 +383,8 @@ public:
// Restore the blit framebuffer after we've sampled from it // Restore the blit framebuffer after we've sampled from it
if (cachedArgs) { if (cachedArgs) {
args->_blitFramebuffer = cachedArgs->_blitFramebuffer; args->_blitFramebuffer = cachedArgs->_blitFramebuffer;
args->_ignoreItem = cachedArgs->_ignoreItem;
args->_mirrorDepth = cachedArgs->_mirrorDepth;
} }
} }
@ -389,9 +397,10 @@ ShapePlumberPointer DrawMirrorTask::_forwardPipelines = std::make_shared<ShapePl
ShapePlumberPointer DrawMirrorTask::_deferredPipelines = std::make_shared<ShapePlumber>(); ShapePlumberPointer DrawMirrorTask::_deferredPipelines = std::make_shared<ShapePlumber>();
void RenderMirrorTask::build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth) { 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<SetupMirrorTask>("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex); size_t nextDepth = depth + 1;
const auto setupOutput = task.addJob<SetupMirrorTask>("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex, nextDepth);
task.addJob<RenderViewTask>("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<RenderViewTask>("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>("DrawMirrorTask" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), setupOutput); task.addJob<DrawMirrorTask>("DrawMirrorTask" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), setupOutput);
} }

View file

@ -244,7 +244,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
// Lighting Buffer ready for tone mapping // Lighting Buffer ready for tone mapping
const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer).asVarying(); const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer).asVarying();
const auto toneMappedBuffer = task.addJob<ToneMapAndResample>("ToneMapping", toneMappingInputs); const auto toneMappedBuffer = task.addJob<ToneMapAndResample>("ToneMapping", toneMappingInputs, depth);
// Debugging task is happening in the "over" layer after tone mapping and just before HUD // 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 { // Debug the bounds of the rendered items, still look at the zbuffer

View file

@ -173,7 +173,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
const auto destFramebuffer = static_cast<gpu::FramebufferPointer>(nullptr); const auto destFramebuffer = static_cast<gpu::FramebufferPointer>(nullptr);
const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer).asVarying(); const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer).asVarying();
const auto toneMappedBuffer = task.addJob<ToneMapAndResample>("ToneMapping", toneMappingInputs); const auto toneMappedBuffer = task.addJob<ToneMapAndResample>("ToneMapping", toneMappingInputs, depth);
// HUD Layer // HUD Layer
const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(toneMappedBuffer, lightingModel, hudOpaque, hudTransparent, hazeFrame).asVarying(); const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(toneMappedBuffer, lightingModel, hudOpaque, hudTransparent, hazeFrame).asVarying();
task.addJob<RenderHUDLayerTask>("RenderHUDLayer", renderHUDLayerInputs); task.addJob<RenderHUDLayerTask>("RenderHUDLayer", renderHUDLayerInputs);

View file

@ -16,8 +16,8 @@ void CompositeHUD::run(const RenderContextPointer& renderContext, const gpu::Fra
assert(renderContext->args); assert(renderContext->args);
assert(renderContext->args->_context); assert(renderContext->args->_context);
// We do not want to render HUD elements in secondary camera // We do not want to render HUD elements in secondary camera or mirrors
if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) { if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE || renderContext->args->_mirrorDepth > 0) {
return; return;
} }

View file

@ -25,9 +25,10 @@ using namespace shader::render_utils::program;
gpu::PipelinePointer ToneMapAndResample::_pipeline; gpu::PipelinePointer ToneMapAndResample::_pipeline;
gpu::PipelinePointer ToneMapAndResample::_mirrorPipeline; gpu::PipelinePointer ToneMapAndResample::_mirrorPipeline;
ToneMapAndResample::ToneMapAndResample() { ToneMapAndResample::ToneMapAndResample(size_t depth) {
Parameters parameters; Parameters parameters;
_parametersBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Parameters), (const gpu::Byte*) &parameters)); _parametersBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Parameters), (const gpu::Byte*) &parameters));
_depth = depth;
} }
void ToneMapAndResample::init() { void ToneMapAndResample::init() {
@ -95,7 +96,8 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In
batch.setViewportTransform(destViewport); batch.setViewportTransform(destViewport);
batch.setProjectionTransform(glm::mat4()); batch.setProjectionTransform(glm::mat4());
batch.resetViewTransform(); 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.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(srcBufferSize, args->_viewport));
batch.setUniformBuffer(render_utils::slot::buffer::ToneMappingParams, _parametersBuffer); batch.setUniformBuffer(render_utils::slot::buffer::ToneMappingParams, _parametersBuffer);

View file

@ -49,11 +49,9 @@ signals:
class ToneMapAndResample { class ToneMapAndResample {
public: public:
ToneMapAndResample(); ToneMapAndResample(size_t depth);
virtual ~ToneMapAndResample() {} virtual ~ToneMapAndResample() {}
void render(RenderArgs* args, const gpu::TexturePointer& lightingBuffer, gpu::FramebufferPointer& destinationBuffer);
void setExposure(float exposure); void setExposure(float exposure);
float getExposure() const { return _parametersBuffer.get<Parameters>()._exposure; } float getExposure() const { return _parametersBuffer.get<Parameters>()._exposure; }
@ -75,7 +73,8 @@ protected:
gpu::FramebufferPointer _destinationFrameBuffer; gpu::FramebufferPointer _destinationFrameBuffer;
float _factor{ 2.0f }; float _factor { 2.0f };
size_t _depth { 0 };
gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer); gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer);

View file

@ -159,6 +159,9 @@ namespace render {
bool _takingSnapshot { false }; bool _takingSnapshot { false };
StencilMaskMode _stencilMaskMode { StencilMaskMode::NONE }; StencilMaskMode _stencilMaskMode { StencilMaskMode::NONE };
std::function<void(gpu::Batch&)> _stencilMaskOperator; std::function<void(gpu::Batch&)> _stencilMaskOperator;
ItemID _ignoreItem { 0 };
size_t _mirrorDepth { 0 };
}; };
} }

View file

@ -82,7 +82,7 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const
outItems.reserve(items.size()); outItems.reserve(items.size());
for (auto& id : items) { for (auto& id : items) {
auto& item = scene->getItem(id); 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))); outItems.emplace_back(ItemBound(id, item.getBound(renderContext->args)));
} }
} }
@ -190,7 +190,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
PerformanceTimer perfTimer("insideFitItems"); PerformanceTimer perfTimer("insideFitItems");
for (auto id : inSelection.insideItems) { for (auto id : inSelection.insideItems) {
auto& item = scene->getItem(id); 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)); ItemBound itemBound(id, item.getBound(args));
outItems.emplace_back(itemBound); outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) { if (item.getKey().isMetaCullGroup()) {
@ -205,7 +205,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
PerformanceTimer perfTimer("insideSmallItems"); PerformanceTimer perfTimer("insideSmallItems");
for (auto id : inSelection.insideSubcellItems) { for (auto id : inSelection.insideSubcellItems) {
auto& item = scene->getItem(id); 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)); ItemBound itemBound(id, item.getBound(args));
outItems.emplace_back(itemBound); outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) { if (item.getKey().isMetaCullGroup()) {
@ -220,7 +220,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
PerformanceTimer perfTimer("partialFitItems"); PerformanceTimer perfTimer("partialFitItems");
for (auto id : inSelection.partialItems) { for (auto id : inSelection.partialItems) {
auto& item = scene->getItem(id); 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)); ItemBound itemBound(id, item.getBound(args));
outItems.emplace_back(itemBound); outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) { if (item.getKey().isMetaCullGroup()) {
@ -235,7 +235,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
PerformanceTimer perfTimer("partialSmallItems"); PerformanceTimer perfTimer("partialSmallItems");
for (auto id : inSelection.partialSubcellItems) { for (auto id : inSelection.partialSubcellItems) {
auto& item = scene->getItem(id); 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)); ItemBound itemBound(id, item.getBound(args));
outItems.emplace_back(itemBound); outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) { if (item.getKey().isMetaCullGroup()) {
@ -252,7 +252,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
PerformanceTimer perfTimer("insideFitItems"); PerformanceTimer perfTimer("insideFitItems");
for (auto id : inSelection.insideItems) { for (auto id : inSelection.insideItems) {
auto& item = scene->getItem(id); 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)); ItemBound itemBound(id, item.getBound(args));
outItems.emplace_back(itemBound); outItems.emplace_back(itemBound);
if (item.getKey().isMetaCullGroup()) { if (item.getKey().isMetaCullGroup()) {
@ -267,7 +267,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
PerformanceTimer perfTimer("insideSmallItems"); PerformanceTimer perfTimer("insideSmallItems");
for (auto id : inSelection.insideSubcellItems) { for (auto id : inSelection.insideSubcellItems) {
auto& item = scene->getItem(id); 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)); ItemBound itemBound(id, item.getBound(args));
if (test.solidAngleTest(itemBound.bound)) { if (test.solidAngleTest(itemBound.bound)) {
outItems.emplace_back(itemBound); outItems.emplace_back(itemBound);
@ -284,7 +284,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
PerformanceTimer perfTimer("partialFitItems"); PerformanceTimer perfTimer("partialFitItems");
for (auto id : inSelection.partialItems) { for (auto id : inSelection.partialItems) {
auto& item = scene->getItem(id); 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)); ItemBound itemBound(id, item.getBound(args));
if (test.frustumTest(itemBound.bound)) { if (test.frustumTest(itemBound.bound)) {
outItems.emplace_back(itemBound); outItems.emplace_back(itemBound);
@ -301,7 +301,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
PerformanceTimer perfTimer("partialSmallItems"); PerformanceTimer perfTimer("partialSmallItems");
for (auto id : inSelection.partialSubcellItems) { for (auto id : inSelection.partialSubcellItems) {
auto& item = scene->getItem(id); 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)); ItemBound itemBound(id, item.getBound(args));
if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) { if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) {
outItems.emplace_back(itemBound); outItems.emplace_back(itemBound);

View file

@ -167,7 +167,8 @@ void UpsampleToBlitFramebuffer::run(const RenderContextPointer& renderContext, c
batch.setViewportTransform(viewport); batch.setViewportTransform(viewport);
batch.setProjectionTransform(glm::mat4()); batch.setProjectionTransform(glm::mat4());
batch.resetViewTransform(); 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.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport));
batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0));

View file

@ -73,7 +73,7 @@ namespace render {
using Input = gpu::FramebufferPointer; using Input = gpu::FramebufferPointer;
using JobModel = Job::ModelIO<UpsampleToBlitFramebuffer, Input, gpu::FramebufferPointer>; using JobModel = Job::ModelIO<UpsampleToBlitFramebuffer, Input, gpu::FramebufferPointer>;
UpsampleToBlitFramebuffer() {} UpsampleToBlitFramebuffer(size_t depth) : _depth(depth) {}
void run(const RenderContextPointer& renderContext, const Input& input, gpu::FramebufferPointer& resampledFrameBuffer); void run(const RenderContextPointer& renderContext, const Input& input, gpu::FramebufferPointer& resampledFrameBuffer);
@ -81,6 +81,8 @@ namespace render {
static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _pipeline;
static gpu::PipelinePointer _mirrorPipeline; static gpu::PipelinePointer _mirrorPipeline;
size_t _depth;
}; };
} }