mirrors on models + text

This commit is contained in:
HifiExperiments 2023-11-18 23:04:17 -08:00
parent 093cf29778
commit a630a6f9c9
17 changed files with 142 additions and 54 deletions

View file

@ -2479,6 +2479,7 @@ Application::Application(
copyViewFrustum(viewFrustum);
return viewFrustum.getPosition();
});
MirrorModeHelpers::setComputeMirrorViewOperator(EntityRenderer::computeMirrorViewOperator);
DependencyManager::get<UsersScriptingInterface>()->setKickConfirmationOperator([this] (const QUuid& nodeID, unsigned int banFlags) { userKickConfirmation(nodeID, banFlags); });

View file

@ -1120,7 +1120,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const
batch.setModelTransform(textTransform);
{
PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderText");
displayNameRenderer->draw(batch, text_x, -text_y, glm::vec2(-1.0f), nameUTF8.data(), textColor, true, forward);
displayNameRenderer->draw(batch, { nameUTF8.data(), textColor, { text_x, -text_y }, glm::vec2(-1.0f), forward });
}
}
}

View file

@ -237,7 +237,11 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const {
mirrorMode = _mirrorMode;
portalExitID = _portalExitID;
});
computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID);
}
void EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation,
MirrorMode mirrorMode, const QUuid& portalExitID) {
glm::mat4 inToWorld = glm::translate(inPropertiesPosition) * glm::mat4_cast(inPropertiesRotation);
glm::mat4 worldToIn = glm::inverse(inToWorld);
@ -284,6 +288,7 @@ void EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const {
glm::vec3 cameraSpacePosition = glm::inverse(view) * glm::vec4(outPropertiesPosition, 1.0f);
glm::vec3 cameraSpaceNormal = glm::transpose(view) * (outPropertiesRotation * glm::vec4(0, 0, -1, 0));
glm::vec4 clipPlane = glm::vec4(cameraSpaceNormal, -glm::dot(cameraSpaceNormal, cameraSpacePosition));
// Make sure we pick the direction facing away from us
if (clipPlane.w > 0.0f) {
clipPlane *= -1.0f;
}

View file

@ -76,6 +76,8 @@ public:
virtual Item::Bound getBound(RenderArgs* args) override;
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override;
void computeMirrorView(ViewFrustum& viewFrustum) const override;
static void computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation,
MirrorMode mirrorMode, const QUuid& portalExitID);
protected:
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }

View file

@ -1085,10 +1085,6 @@ void ModelEntityRenderer::setKey(bool didVisualGeometryRequestSucceed, const Mod
builder.withSubMetaCulled();
}
if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) {
builder.withMirror();
}
if (didVisualGeometryRequestSucceed) {
_itemKey = builder.build();
} else {

View file

@ -181,7 +181,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
}
auto geometryCache = DependencyManager::get<GeometryCache>();
if (pipelineType == Pipeline::SIMPLE) {
if (pipelineType == Pipeline::SIMPLE || pipelineType == Pipeline::MIRROR) {
geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), backgroundColor, _geometryID);
} else {
geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), glm::vec2(0.0f), glm::vec2(1.0f), backgroundColor, _geometryID);
@ -261,6 +261,10 @@ ItemKey entities::TextPayload::getKey() const {
builder.withInvisible();
}
if (textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull())) {
builder.withMirror();
}
return builder;
}
}
@ -312,6 +316,16 @@ bool entities::TextPayload::passesZoneOcclusionTest(const std::unordered_set<QUu
return false;
}
void entities::TextPayload::computeMirrorView(ViewFrustum& viewFrustum) const {
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
if (entityTreeRenderer) {
auto renderable = entityTreeRenderer->renderableForEntityId(_entityID);
if (renderable) {
return renderable->computeMirrorView(viewFrustum);
}
}
}
void entities::TextPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("TextPayload::render");
Q_ASSERT(args->_batch);
@ -336,12 +350,15 @@ void entities::TextPayload::render(RenderArgs* args) {
glm::vec3 dimensions;
glm::vec4 textColor;
bool mirror;
textRenderable->withReadLock([&] {
transform = textRenderable->_renderTransform;
dimensions = textRenderable->_dimensions;
float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f;
textColor = glm::vec4(textRenderable->_textColor, fadeRatio * textRenderable->_textAlpha);
mirror = textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull());
});
bool forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD;
@ -363,9 +380,8 @@ void entities::TextPayload::render(RenderArgs* args) {
batch.setModelTransform(transform);
glm::vec2 bounds = glm::vec2(dimensions.x - (textRenderable->_leftMargin + textRenderable->_rightMargin), dimensions.y - (textRenderable->_topMargin + textRenderable->_bottomMargin));
textRenderer->draw(batch, textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale, bounds / scale, scale,
textRenderable->_text, textRenderable->_font, textColor, effectColor, textRenderable->_effectThickness, textRenderable->_effect,
textRenderable->_alignment, textRenderable->_unlit, forward);
textRenderer->draw(batch, textRenderable->_font, { textRenderable->_text, textColor, effectColor, { textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale },
bounds / scale, scale, textRenderable->_effectThickness, textRenderable->_effect, textRenderable->_alignment, textRenderable->_unlit, forward, mirror });
}
namespace render {
@ -401,4 +417,10 @@ template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Poi
return false;
}
template <> void payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum) {
if (payload) {
payload->computeMirrorView(viewFrustum);
}
}
}

View file

@ -101,6 +101,7 @@ public:
ShapeKey getShapeKey() const;
void render(RenderArgs* args);
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const;
void computeMirrorView(ViewFrustum& viewFrustum) const;
protected:
QUuid _entityID;
@ -117,6 +118,7 @@ namespace render {
template <> const ShapeKey shapeGetShapeKey(const entities::TextPayload::Pointer& payload);
template <> void payloadRender(const entities::TextPayload::Pointer& payload, RenderArgs* args);
template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
template <> void payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum);
}
#endif // hifi_RenderableTextEntityItem_h

View file

@ -221,6 +221,10 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
builder.withSubMetaCulled();
}
if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) {
builder.withMirror();
}
_itemKey = builder.build();
}
@ -349,7 +353,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created,
ProceduralProgramKey(outColor.a < 1.0f, _shapeKey.isDeformed(), _shapeKey.isDualQuatSkinned()));
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
} else {
} else if (!_itemKey.isMirror()) {
// apply material properties
if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) {
args->_details._materialSwitches++;
@ -381,7 +385,9 @@ bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set<QUui
}
void ModelMeshPartPayload::computeMirrorView(ViewFrustum& viewFrustum) const {
return;
Transform transform = _parentTransform;
transform = transform.worldTransform(_localTransform);
MirrorModeHelpers::computeMirrorView(viewFrustum, transform.getTranslation(), transform.getRotation(), _mirrorMode, _portalExitID);
}
void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes) {

View file

@ -1078,9 +1078,11 @@ void Model::setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& sce
}
render::Transaction transaction;
auto renderItemsKey = _renderItemKeyGlobalFlags;
for (auto item : _modelMeshRenderItemIDs) {
transaction.updateItem<ModelMeshPartPayload>(item, [mirrorMode](ModelMeshPartPayload& data) {
transaction.updateItem<ModelMeshPartPayload>(item, [mirrorMode, renderItemsKey](ModelMeshPartPayload& data) {
data.setMirrorMode(mirrorMode);
data.updateKey(renderItemsKey);
});
}
scene->enqueueTransaction(transaction);
@ -1096,9 +1098,11 @@ void Model::setPortalExitID(const QUuid& portalExitID, const render::ScenePointe
}
render::Transaction transaction;
auto renderItemsKey = _renderItemKeyGlobalFlags;
for (auto item : _modelMeshRenderItemIDs) {
transaction.updateItem<ModelMeshPartPayload>(item, [portalExitID](ModelMeshPartPayload& data) {
transaction.updateItem<ModelMeshPartPayload>(item, [portalExitID, renderItemsKey](ModelMeshPartPayload& data) {
data.setPortalExitID(portalExitID);
data.updateKey(renderItemsKey);
});
}
scene->enqueueTransaction(transaction);

View file

@ -40,21 +40,18 @@ float TextRenderer3D::getFontSize() const {
return 0.0f;
}
void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds,
const QString& str, const glm::vec4& color, bool unlit, bool forward) {
void TextRenderer3D::draw(gpu::Batch& batch, const Font::DrawProps& props) {
if (_font) {
_font->drawString(batch, _drawInfo, str, color, glm::vec3(0.0f), 0, TextEffect::NO_EFFECT, TextAlignment::LEFT, { x, y }, bounds, 1.0f, unlit, forward);
_font->drawString(batch, _drawInfo, props);
}
}
void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale,
const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor,
float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward) {
void TextRenderer3D::draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props) {
if (font != _family) {
_family = font;
_font = Font::load(_family);
}
if (_font) {
_font->drawString(batch, _drawInfo, str, color, effectColor, effectThickness, effect, alignment, { x, y }, bounds, scale, unlit, forward);
_font->drawString(batch, _drawInfo, props);
}
}

View file

@ -26,12 +26,9 @@ public:
glm::vec2 computeExtent(const QString& str) const;
float getFontSize() const; // Pixel size
void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds,
const QString& str, const glm::vec4& color, bool unlit, bool forward);
void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale,
const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor,
float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward);
void draw(gpu::Batch& batch, const Font::DrawProps& props);
void draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props);
private:
TextRenderer3D(const char* family);

View file

@ -1 +1 @@
DEFINES (translucent unlit:f)/forward
DEFINES (translucent unlit:f)/forward mirror:f

View file

@ -41,6 +41,12 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
#define _texCoord1 _texCoord01.zw
layout(location=RENDER_UTILS_ATTR_FADE1) flat in vec4 _glyphBounds; // we're reusing the fade texcoord locations here
<@if HIFI_USE_MIRROR@>
<@include graphics/ShaderConstants.h@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap;
<@endif@>
void main() {
vec4 color = evalSDFSuperSampled(_texCoord0, _glyphBounds);
@ -51,13 +57,17 @@ void main() {
}
<@endif@>
<@if HIFI_USE_MIRROR@>
color.rgb = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb;
<@endif@>
<@if HIFI_USE_UNLIT@>
<@if HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@>
_fragColor0 = vec4(color.rgb * isUnlitEnabled(), color.a);
_fragColor0 = vec4(color.rgb * isUnlitEnabled(), 1.0);
<@else@>
packDeferredFragmentUnlit(
normalize(_normalWS),
color.a,
1.0,
color.rgb);
<@endif@>
<@else@>

View file

@ -29,7 +29,7 @@
static std::mutex fontMutex;
std::map<std::tuple<bool, bool, bool>, gpu::PipelinePointer> Font::_pipelines;
std::map<std::tuple<bool, bool, bool, bool>, gpu::PipelinePointer> Font::_pipelines;
gpu::Stream::FormatPointer Font::_format;
struct TextureVertex {
@ -277,6 +277,7 @@ void Font::setupGPU() {
if (_pipelines.empty()) {
using namespace shader::render_utils::program;
// transparent, unlit, forward
static const std::vector<std::tuple<bool, bool, bool, uint32_t>> keys = {
std::make_tuple(false, false, false, sdf_text3D), std::make_tuple(true, false, false, sdf_text3D_translucent),
std::make_tuple(false, true, false, sdf_text3D_unlit), std::make_tuple(true, true, false, sdf_text3D_translucent_unlit),
@ -284,18 +285,23 @@ void Font::setupGPU() {
std::make_tuple(false, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_unlit_forward*/), std::make_tuple(true, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_translucent_unlit_forward*/)
};
for (auto& key : keys) {
bool transparent = std::get<0>(key);
bool unlit = std::get<1>(key);
bool forward = std::get<2>(key);
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, !std::get<0>(key), gpu::LESS_EQUAL);
state->setBlendFunction(std::get<0>(key),
state->setDepthTest(true, !transparent, gpu::LESS_EQUAL);
state->setBlendFunction(transparent,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
if (std::get<0>(key)) {
if (transparent) {
PrepareStencil::testMask(*state);
} else {
PrepareStencil::testMaskDrawShape(*state);
}
_pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key))] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state);
_pipelines[std::make_tuple(transparent, unlit, forward, false)] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state);
_pipelines[std::make_tuple(transparent, unlit, forward, true)] = gpu::Pipeline::create(gpu::Shader::createProgram(forward ? sdf_text3D_forward_mirror : sdf_text3D_mirror), state);
}
// Sanity checks
@ -444,32 +450,30 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm
}
}
void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color,
const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment,
const glm::vec2& origin, const glm::vec2& bounds, float scale, bool unlit, bool forward) {
if (!_loaded || str == "") {
void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const DrawProps& props) {
if (!_loaded || props.str == "") {
return;
}
int textEffect = (int)effect;
int textEffect = (int)props.effect;
const int SHADOW_EFFECT = (int)TextEffect::SHADOW_EFFECT;
// If we're switching to or from shadow effect mode, we need to rebuild the vertices
if (str != drawInfo.string || bounds != drawInfo.bounds || origin != drawInfo.origin || alignment != _alignment ||
if (props.str != drawInfo.string || props.bounds != drawInfo.bounds || props.origin != drawInfo.origin || props.alignment != _alignment ||
(drawInfo.params.effect != textEffect && (textEffect == SHADOW_EFFECT || drawInfo.params.effect == SHADOW_EFFECT)) ||
(textEffect == SHADOW_EFFECT && scale != _scale)) {
_scale = scale;
_alignment = alignment;
buildVertices(drawInfo, str, origin, bounds, scale, textEffect == SHADOW_EFFECT, alignment);
(textEffect == SHADOW_EFFECT && props.scale != _scale)) {
_scale = props.scale;
_alignment = props.alignment;
buildVertices(drawInfo, props.str, props.origin, props.bounds, props.scale, textEffect == SHADOW_EFFECT, props.alignment);
}
setupGPU();
if (!drawInfo.paramsBuffer || drawInfo.params.color != color || drawInfo.params.effectColor != effectColor ||
drawInfo.params.effectThickness != effectThickness || drawInfo.params.effect != textEffect) {
drawInfo.params.color = color;
drawInfo.params.effectColor = effectColor;
drawInfo.params.effectThickness = effectThickness;
if (!drawInfo.paramsBuffer || drawInfo.params.color != props.color || drawInfo.params.effectColor != props.effectColor ||
drawInfo.params.effectThickness != props.effectThickness || drawInfo.params.effect != textEffect) {
drawInfo.params.color = props.color;
drawInfo.params.effectColor = props.effectColor;
drawInfo.params.effectThickness = props.effectThickness;
drawInfo.params.effect = textEffect;
// need the gamma corrected color here
@ -484,7 +488,7 @@ void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString
drawInfo.paramsBuffer->setSubData(0, sizeof(DrawParams), (const gpu::Byte*)&gpuDrawParams);
}
batch.setPipeline(_pipelines[std::make_tuple(color.a < 1.0f, unlit, forward)]);
batch.setPipeline(_pipelines[std::make_tuple(props.color.a < 1.0f, props.unlit, props.forward, props.mirror)]);
batch.setInputFormat(_format);
batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride);
batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture);

View file

@ -57,10 +57,30 @@ public:
glm::vec2 computeExtent(const QString& str) const;
float getFontSize() const { return _fontSize; }
struct DrawProps {
DrawProps(const QString& str, const glm::vec4& color, const glm::vec3& effectColor, const glm::vec2& origin, const glm::vec2& bounds,
float scale, float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward, bool mirror) :
str(str), color(color), effectColor(effectColor), origin(origin), bounds(bounds), scale(scale), effectThickness(effectThickness),
effect(effect), alignment(alignment), unlit(unlit), forward(forward), mirror(mirror) {}
DrawProps(const QString& str, const glm::vec4& color, const glm::vec2& origin, const glm::vec2& bounds, bool forward) :
str(str), color(color), origin(origin), bounds(bounds), forward(forward) {}
const QString& str;
const glm::vec4& color;
const glm::vec3& effectColor { glm::vec3(0.0f) };
const glm::vec2& origin;
const glm::vec2& bounds;
float scale { 1.0f };
float effectThickness { 0.0f };
TextEffect effect { TextEffect::NO_EFFECT };
TextAlignment alignment { TextAlignment::LEFT };
bool unlit = true;
bool forward;
bool mirror = false;
};
// Render string to batch
void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str, const glm::vec4& color,
const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment,
const glm::vec2& origin, const glm::vec2& bound, float scale, bool unlit, bool forward);
void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const DrawProps& props);
static Pointer load(const QString& family);
@ -105,7 +125,7 @@ private:
gpu::TexturePointer _texture;
gpu::BufferStreamPointer _stream;
static std::map<std::tuple<bool, bool, bool>, gpu::PipelinePointer> _pipelines;
static std::map<std::tuple<bool, bool, bool, bool>, gpu::PipelinePointer> _pipelines;
static gpu::Stream::FormatPointer _format;
};

View file

@ -15,6 +15,8 @@ const char* MirrorModeNames[] = {
};
static const size_t MIRROR_MODE_NAMES = (sizeof(MirrorModeNames) / sizeof(MirrorModeNames[0]));
std::function<void(ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&)> MirrorModeHelpers::_computeMirrorViewOperator =
[](ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&) { return; };
QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) {
if (((int)mode <= 0) || ((int)mode >= (int)MIRROR_MODE_NAMES)) {
@ -23,3 +25,12 @@ QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) {
return MirrorModeNames[(int)mode];
}
void MirrorModeHelpers::setComputeMirrorViewOperator(std::function<void(ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&)> computeMirrorViewOperator) {
_computeMirrorViewOperator = computeMirrorViewOperator;
}
void MirrorModeHelpers::computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation,
MirrorMode mirrorMode, const QUuid& portalExitID) {
_computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID);
}

View file

@ -9,8 +9,12 @@
#ifndef hifi_MirrorMode_h
#define hifi_MirrorMode_h
#include <functional>
#include "QString"
#include "ViewFrustum.h"
/*@jsdoc
* <p>If an entity is rendered as a mirror, a portal, or normally.</p>
* <table>
@ -35,6 +39,13 @@ enum class MirrorMode {
class MirrorModeHelpers {
public:
static QString getNameForMirrorMode(MirrorMode mode);
static void setComputeMirrorViewOperator(std::function<void(ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&)> computeMirrorViewOperator);
static void computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation,
MirrorMode mirrorMode, const QUuid& portalExitID);
private:
static std::function<void(ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&)> _computeMirrorViewOperator;
};
#endif // hifi_MirrorMode_h