Merge pull request #11021 from Zvork/fade2

Fade dissolve effect  JUST AVATARS
This commit is contained in:
Sam Gateau 2017-08-10 13:48:30 -07:00 committed by GitHub
commit 79f3be1efe
91 changed files with 5069 additions and 371 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View file

@ -960,6 +960,53 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
// Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success.
DependencyManager::get<GeometryCache>()->initializeShapePipelines();
// sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value.
// The value will be 0 if the user blew away settings this session, which is both a feature and a bug.
static const QString TESTER = "HIFI_TESTER";
auto gpuIdent = GPUIdent::getInstance();
auto glContextData = getGLContextData();
QJsonObject properties = {
{ "version", applicationVersion() },
{ "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) },
{ "previousSessionCrashed", _previousSessionCrashed },
{ "previousSessionRuntime", sessionRunTime.get() },
{ "cpu_architecture", QSysInfo::currentCpuArchitecture() },
{ "kernel_type", QSysInfo::kernelType() },
{ "kernel_version", QSysInfo::kernelVersion() },
{ "os_type", QSysInfo::productType() },
{ "os_version", QSysInfo::productVersion() },
{ "gpu_name", gpuIdent->getName() },
{ "gpu_driver", gpuIdent->getDriver() },
{ "gpu_memory", static_cast<qint64>(gpuIdent->getMemory()) },
{ "gl_version_int", glVersionToInteger(glContextData.value("version").toString()) },
{ "gl_version", glContextData["version"] },
{ "gl_vender", glContextData["vendor"] },
{ "gl_sl_version", glContextData["sl_version"] },
{ "gl_renderer", glContextData["renderer"] },
{ "ideal_thread_count", QThread::idealThreadCount() }
};
auto macVersion = QSysInfo::macVersion();
if (macVersion != QSysInfo::MV_None) {
properties["os_osx_version"] = QSysInfo::macVersion();
}
auto windowsVersion = QSysInfo::windowsVersion();
if (windowsVersion != QSysInfo::WV_None) {
properties["os_win_version"] = QSysInfo::windowsVersion();
}
ProcessorInfo procInfo;
if (getProcessorInfo(procInfo)) {
properties["processor_core_count"] = procInfo.numProcessorCores;
properties["logical_processor_count"] = procInfo.numLogicalProcessors;
properties["processor_l1_cache_count"] = procInfo.numProcessorCachesL1;
properties["processor_l2_cache_count"] = procInfo.numProcessorCachesL2;
properties["processor_l3_cache_count"] = procInfo.numProcessorCachesL3;
}
// add firstRun flag from settings to launch event
Setting::Handle<bool> firstRun { Settings::firstRun, true };
// once the settings have been loaded, check if we need to flip the default for UserActivityLogger

View file

@ -273,19 +273,15 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
return;
}
const float SHRINK_RATE = 0.15f;
const float MIN_FADE_SCALE = MIN_AVATAR_SCALE;
QReadLocker locker(&_hashLock);
QVector<AvatarSharedPointer>::iterator avatarItr = _avatarsToFade.begin();
const render::ScenePointer& scene = qApp->getMain3DScene();
while (avatarItr != _avatarsToFade.end()) {
auto avatar = std::static_pointer_cast<Avatar>(*avatarItr);
avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE);
avatar->animateScaleChanges(deltaTime);
if (avatar->getTargetScale() <= MIN_FADE_SCALE) {
avatar->updateFadingStatus(scene);
if (!avatar->isFading()) {
// fading to zero is such a rare event we push a unique transaction for each
if (avatar->isInScene()) {
const render::ScenePointer& scene = qApp->getMain3DScene();
render::Transaction transaction;
avatar->removeFromScene(*avatarItr, scene, transaction);
scene->enqueueTransaction(transaction);
@ -323,6 +319,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar
// remove from node sets, if present
DependencyManager::get<NodeList>()->removeFromIgnoreMuteSets(avatar->getSessionUUID());
DependencyManager::get<UsersScriptingInterface>()->avatarDisconnected(avatar->getSessionUUID());
avatar->fadeOut(qApp->getMain3DScene(), removalReason);
}
_avatarsToFade.push_back(removedAvatar);
}

View file

@ -96,7 +96,7 @@ void Overlays::cleanupOverlaysToDelete() {
} while (!_overlaysToDelete.isEmpty());
}
if (transaction._removedItems.size() > 0) {
if (transaction.hasRemovedItems()) {
scene->enqueueTransaction(transaction);
}
}

View file

@ -30,6 +30,7 @@
#include <DebugDraw.h>
#include <shared/Camera.h>
#include <SoftAttachmentModel.h>
#include <render/TransitionStage.h>
#include "Logging.h"
@ -61,7 +62,7 @@ namespace render {
template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems) {
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
if (avatarPtr->getSkeletonModel()) {
auto metaSubItems = avatarPtr->getSkeletonModel()->fetchRenderItemIDs();
auto& metaSubItems = avatarPtr->getSkeletonModel()->fetchRenderItemIDs();
subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end());
return (uint32_t) metaSubItems.size();
}
@ -493,6 +494,48 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc
for (auto& attachmentModel : _attachmentModels) {
attachmentModel->addToScene(scene, transaction);
}
_mustFadeIn = true;
}
void Avatar::fadeIn(render::ScenePointer scene) {
render::Transaction transaction;
fade(transaction, render::Transition::USER_ENTER_DOMAIN);
scene->enqueueTransaction(transaction);
}
void Avatar::fadeOut(render::ScenePointer scene, KillAvatarReason reason) {
render::Transition::Type transitionType = render::Transition::USER_LEAVE_DOMAIN;
render::Transaction transaction;
if (reason == KillAvatarReason::YourAvatarEnteredTheirBubble) {
transitionType = render::Transition::BUBBLE_ISECT_TRESPASSER;
}
else if (reason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
transitionType = render::Transition::BUBBLE_ISECT_OWNER;
}
fade(transaction, transitionType);
scene->enqueueTransaction(transaction);
}
void Avatar::fade(render::Transaction& transaction, render::Transition::Type type) {
transaction.addTransitionToItem(_renderItemID, type);
for (auto& attachmentModel : _attachmentModels) {
for (auto itemId : attachmentModel->fetchRenderItemIDs()) {
transaction.addTransitionToItem(itemId, type, _renderItemID);
}
}
_isFading = true;
}
void Avatar::updateFadingStatus(render::ScenePointer scene) {
render::Transaction transaction;
transaction.queryTransitionOnItem(_renderItemID, [this](render::ItemID id, const render::Transition* transition) {
if (transition == nullptr || transition->isFinished) {
_isFading = false;
}
});
scene->enqueueTransaction(transaction);
}
void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
@ -629,6 +672,8 @@ void Avatar::render(RenderArgs* renderArgs) {
}
void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
bool canTryFade{ false };
_attachmentsToDelete.clear();
// check to see if when we added our models to the scene they were ready, if they were not ready, then
@ -637,6 +682,7 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
_skeletonModel->removeFromScene(scene, transaction);
_skeletonModel->addToScene(scene, transaction);
canTryFade = true;
}
for (auto attachmentModel : _attachmentModels) {
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
@ -645,6 +691,12 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
}
}
if (_mustFadeIn && canTryFade) {
// Do it now to be sure all the sub items are ready and the fade is sent to them too
fade(transaction, render::Transition::USER_ENTER_DOMAIN);
_mustFadeIn = false;
}
for (auto attachmentModelToRemove : _attachmentsToRemove) {
attachmentModelToRemove->removeFromScene(scene, transaction);
}

View file

@ -246,6 +246,11 @@ public:
void addPhysicsFlags(uint32_t flags);
bool isInPhysicsSimulation() const { return _physicsCallback != nullptr; }
void fadeIn(render::ScenePointer scene);
void fadeOut(render::ScenePointer scene, KillAvatarReason reason);
bool isFading() const { return _isFading; }
void updateFadingStatus(render::ScenePointer scene);
public slots:
// FIXME - these should be migrated to use Pose data instead
@ -297,6 +302,8 @@ protected:
// protected methods...
bool isLookingAtMe(AvatarSharedPointer avatar) const;
void fade(render::Transaction& transaction, render::Transition::Type type);
glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; }
void measureMotionDerivatives(float deltaTime);
@ -344,6 +351,8 @@ private:
bool _initialized { false };
bool _isLookAtTarget { false };
bool _isAnimatingScale { false };
bool _mustFadeIn { false };
bool _isFading { false };
static int _jointConesID;

View file

@ -130,3 +130,42 @@ void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status:
(unsigned char)RenderItemStatusIcon::CLIENT_ONLY);
});
}
bool SimplerRenderableEntitySupport::addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) {
_myItem = scene->allocateID();
auto renderData = std::make_shared<RenderableEntityItemProxy>(self, _myItem);
auto renderPayload = std::make_shared<RenderableEntityItemProxy::Payload>(renderData);
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(self, statusGetters);
renderPayload->addStatusGetters(statusGetters);
transaction.resetItem(_myItem, renderPayload);
return true;
}
void SimplerRenderableEntitySupport::removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) {
transaction.removeItem(_myItem);
render::Item::clearID(_myItem);
}
void SimplerRenderableEntitySupport::notifyChanged() {
if (!render::Item::isValidID(_myItem)) {
return;
}
render::Transaction transaction;
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
if (scene) {
transaction.updateItem<RenderableEntityItemProxy>(_myItem, [](RenderableEntityItemProxy& data) {
});
scene->enqueueTransaction(transaction);
}
else {
qCWarning(entitiesrenderer) << "SimpleRenderableEntityItem::notifyChanged(), Unexpected null scene, possibly during application shutdown";
}
}

View file

@ -70,44 +70,13 @@ namespace render {
// Mixin class for implementing basic single item rendering
class SimplerRenderableEntitySupport : public RenderableEntityInterface {
public:
bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override {
_myItem = scene->allocateID();
auto renderData = std::make_shared<RenderableEntityItemProxy>(self, _myItem);
auto renderPayload = std::make_shared<RenderableEntityItemProxy::Payload>(renderData);
bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
void notifyChanged();
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(self, statusGetters);
renderPayload->addStatusGetters(statusGetters);
protected:
transaction.resetItem(_myItem, renderPayload);
return true;
}
void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override {
transaction.removeItem(_myItem);
render::Item::clearID(_myItem);
}
void notifyChanged() {
if (!render::Item::isValidID(_myItem)) {
return;
}
render::Transaction transaction;
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
if (scene) {
transaction.updateItem<RenderableEntityItemProxy>(_myItem, [](RenderableEntityItemProxy& data) {
});
scene->enqueueTransaction(transaction);
} else {
qCWarning(entitiesrenderer) << "SimpleRenderableEntityItem::notifyChanged(), Unexpected null scene, possibly during application shutdown";
}
}
private:
render::ItemID _myItem { render::Item::INVALID_ITEM_ID };
};

View file

@ -23,6 +23,7 @@
#include <PerfStat.h>
#include <render/Scene.h>
#include <DependencyManager.h>
#include <AnimationCache.h>
#include <shared/QtHelpers.h>
#include "EntityTreeRenderer.h"
@ -218,8 +219,9 @@ namespace render {
}
template <> uint32_t metaFetchMetaSubItems(const RenderableModelEntityItemMeta::Pointer& payload, ItemIDs& subItems) {
auto modelEntity = std::static_pointer_cast<RenderableModelEntityItem>(payload->entity);
if (modelEntity->hasModel()) {
auto metaSubItems = modelEntity->getModelNotSafe()->fetchRenderItemIDs();
auto model = modelEntity->getModelNotSafe();
if (model && modelEntity->hasModel()) {
auto& metaSubItems = model->fetchRenderItemIDs();
subItems.insert(subItems.end(), metaSubItems.begin(), metaSubItems.end());
return (uint32_t) metaSubItems.size();
}
@ -242,6 +244,12 @@ bool RenderableModelEntityItem::addToScene(const EntityItemPointer& self, const
// note: we don't mind if the model fails to add, we'll retry (in render()) until it succeeds
_model->addToScene(scene, transaction, statusGetters);
#ifdef MODEL_ENTITY_USE_FADE_EFFECT
if (!_hasTransitioned) {
transaction.addTransitionToItem(_myMetaItem, render::Transition::ELEMENT_ENTER_DOMAIN);
_hasTransitioned = true;
}
#endif
}
// we've successfully added _myMetaItem so we always return true
@ -364,6 +372,7 @@ void RenderableModelEntityItem::updateModelBounds() {
// the per frame simulation/update that might be required if the models properties changed.
void RenderableModelEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RMEIrender");
assert(getType() == EntityTypes::Model);
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
@ -490,6 +499,12 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
_model->addToScene(scene, transaction, statusGetters);
#ifdef MODEL_ENTITY_USE_FADE_EFFECT
if (!_hasTransitioned) {
transaction.addTransitionToItem(_myMetaItem, render::Transition::ELEMENT_ENTER_DOMAIN);
_hasTransitioned = true;
}
#endif
scene->enqueueTransaction(transaction);
}

View file

@ -16,11 +16,14 @@
#include <QStringList>
#include <ModelEntityItem.h>
#include <AnimationCache.h>
#include "RenderableEntityItem.h"
class Model;
class EntityTreeRenderer;
//#define MODEL_ENTITY_USE_FADE_EFFECT
class RenderableModelEntityItem : public ModelEntityItem, RenderableEntityInterface {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
@ -133,7 +136,9 @@ private:
QVariantMap _originalTextures;
bool _originalTexturesRead = false;
bool _dimensionsInitialized = true;
#ifdef MODEL_ENTITY_USE_FADE_EFFECT
bool _hasTransitioned{ false };
#endif
AnimationPropertyGroup _renderAnimationProperties;
render::ItemID _myMetaItem{ render::Item::INVALID_ITEM_ID };

View file

@ -17,22 +17,101 @@
#include <PathUtils.h>
#include <PerfStat.h>
//#define POLYLINE_ENTITY_USE_FADE_EFFECT
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
# include <FadeEffect.h>
#endif
#include "RenderablePolyLineEntityItem.h"
#include "paintStroke_vert.h"
#include "paintStroke_frag.h"
#include "paintStroke_fade_vert.h"
#include "paintStroke_fade_frag.h"
uint8_t PolyLinePayload::CUSTOM_PIPELINE_NUMBER = 0;
gpu::PipelinePointer PolyLinePayload::_pipeline;
gpu::PipelinePointer PolyLinePayload::_fadePipeline;
const int32_t PolyLinePayload::PAINTSTROKE_TEXTURE_SLOT;
const int32_t PolyLinePayload::PAINTSTROKE_UNIFORM_SLOT;
render::ShapePipelinePointer PolyLinePayload::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) {
if (!_pipeline) {
auto VS = gpu::Shader::createVertex(std::string(paintStroke_vert));
auto PS = gpu::Shader::createPixel(std::string(paintStroke_frag));
gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS);
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
auto fadeVS = gpu::Shader::createVertex(std::string(paintStroke_fade_vert));
auto fadePS = gpu::Shader::createPixel(std::string(paintStroke_fade_frag));
gpu::ShaderPointer fadeProgram = gpu::Shader::createProgram(fadeVS, fadePS);
#endif
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("originalTexture"), PAINTSTROKE_TEXTURE_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("polyLineBuffer"), PAINTSTROKE_UNIFORM_SLOT));
gpu::Shader::makeProgram(*program, slotBindings);
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), PAINTSTROKE_TEXTURE_SLOT + 1));
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), PAINTSTROKE_UNIFORM_SLOT+1));
gpu::Shader::makeProgram(*fadeProgram, slotBindings);
#endif
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMask(*state);
state->setBlendFunction(true,
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);
_pipeline = gpu::Pipeline::create(program, state);
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
_fadePipeline = gpu::Pipeline::create(fadeProgram, state);
#endif
}
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
if (key.isFaded()) {
auto fadeEffect = DependencyManager::get<FadeEffect>();
return std::make_shared<render::ShapePipeline>(_fadePipeline, nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
} else {
#endif
return std::make_shared<render::ShapePipeline>(_pipeline, nullptr, nullptr, nullptr);
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
}
#endif
}
namespace render {
template <> const ItemKey payloadGetKey(const PolyLinePayload::Pointer& payload) {
return payloadGetKey(std::static_pointer_cast<RenderableEntityItemProxy>(payload));
}
template <> const Item::Bound payloadGetBound(const PolyLinePayload::Pointer& payload) {
return payloadGetBound(std::static_pointer_cast<RenderableEntityItemProxy>(payload));
}
template <> void payloadRender(const PolyLinePayload::Pointer& payload, RenderArgs* args) {
payloadRender(std::static_pointer_cast<RenderableEntityItemProxy>(payload), args);
}
template <> uint32_t metaFetchMetaSubItems(const PolyLinePayload::Pointer& payload, ItemIDs& subItems) {
return metaFetchMetaSubItems(std::static_pointer_cast<RenderableEntityItemProxy>(payload), subItems);
}
template <> const ShapeKey shapeGetShapeKey(const PolyLinePayload::Pointer& payload) {
auto shapeKey = ShapeKey::Builder().withCustom(PolyLinePayload::CUSTOM_PIPELINE_NUMBER);
return shapeKey.build();
}
}
struct PolyLineUniforms {
glm::vec3 color;
};
EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer entity{ new RenderablePolyLineEntityItem(entityID) };
entity->setProperties(properties);
// As we create the first PolyLine entity, let's register its special shapePipeline factory:
PolyLinePayload::registerShapePipeline();
return entity;
}
@ -45,12 +124,9 @@ _numVertices(0)
_uniformBuffer = std::make_shared<gpu::Buffer>(sizeof(PolyLineUniforms), (const gpu::Byte*) &uniforms);
}
gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline;
gpu::Stream::FormatPointer RenderablePolyLineEntityItem::_format;
const int32_t RenderablePolyLineEntityItem::PAINTSTROKE_TEXTURE_SLOT;
const int32_t RenderablePolyLineEntityItem::PAINTSTROKE_UNIFORM_SLOT;
void RenderablePolyLineEntityItem::createPipeline() {
void RenderablePolyLineEntityItem::createStreamFormat() {
static const int NORMAL_OFFSET = 12;
static const int TEXTURE_OFFSET = 24;
@ -58,23 +134,6 @@ void RenderablePolyLineEntityItem::createPipeline() {
_format->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
_format->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), NORMAL_OFFSET);
_format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), TEXTURE_OFFSET);
auto VS = gpu::Shader::createVertex(std::string(paintStroke_vert));
auto PS = gpu::Shader::createPixel(std::string(paintStroke_frag));
gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("originalTexture"), PAINTSTROKE_TEXTURE_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("polyLineBuffer"), PAINTSTROKE_UNIFORM_SLOT));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMask(*state);
state->setBlendFunction(true,
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);
_pipeline = gpu::Pipeline::create(program, state);
}
void RenderablePolyLineEntityItem::updateGeometry() {
@ -158,10 +217,7 @@ void RenderablePolyLineEntityItem::updateVertices() {
}
void RenderablePolyLineEntityItem::update(const quint64& now) {
PolyLineUniforms uniforms;
uniforms.color = toGlm(getXColor());
memcpy(&_uniformBuffer.edit<PolyLineUniforms>(), &uniforms, sizeof(PolyLineUniforms));
void RenderablePolyLineEntityItem::updateMesh() {
if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) {
QWriteLocker lock(&_quadReadWriteLock);
_empty = (_points.size() < 2 || _normals.size() < 2 || _strokeWidths.size() < 2);
@ -170,18 +226,46 @@ void RenderablePolyLineEntityItem::update(const quint64& now) {
updateGeometry();
}
}
}
void RenderablePolyLineEntityItem::update(const quint64& now) {
PolyLineUniforms uniforms;
uniforms.color = toGlm(getXColor());
memcpy(&_uniformBuffer.edit<PolyLineUniforms>(), &uniforms, sizeof(PolyLineUniforms));
updateMesh();
}
bool RenderablePolyLineEntityItem::addToScene(const EntityItemPointer& self,
const render::ScenePointer& scene,
render::Transaction& transaction) {
_myItem = scene->allocateID();
auto renderData = std::make_shared<PolyLinePayload>(self, _myItem);
auto renderPayload = std::make_shared<PolyLinePayload::Payload>(renderData);
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(self, statusGetters);
renderPayload->addStatusGetters(statusGetters);
transaction.resetItem(_myItem, renderPayload);
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
transaction.addTransitionToItem(_myItem, render::Transition::ELEMENT_ENTER_DOMAIN);
#endif
updateMesh();
return true;
}
void RenderablePolyLineEntityItem::render(RenderArgs* args) {
#ifndef POLYLINE_ENTITY_USE_FADE_EFFECT
checkFading();
#endif
if (_empty) {
return;
}
if (!_pipeline) {
createPipeline();
if (!_format) {
createStreamFormat();
}
if (!_texture || _texturesChangedFlag) {
@ -199,24 +283,26 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) {
Transform transform = Transform();
transform.setTranslation(getPosition());
transform.setRotation(getRotation());
batch.setUniformBuffer(PAINTSTROKE_UNIFORM_SLOT, _uniformBuffer);
batch.setUniformBuffer(PolyLinePayload::PAINTSTROKE_UNIFORM_SLOT, _uniformBuffer);
batch.setModelTransform(transform);
batch.setPipeline(_pipeline);
if (_texture->isLoaded()) {
batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, _texture->getGPUTexture());
batch.setResourceTexture(PolyLinePayload::PAINTSTROKE_TEXTURE_SLOT, _texture->getGPUTexture());
} else {
batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, nullptr);
batch.setResourceTexture(PolyLinePayload::PAINTSTROKE_TEXTURE_SLOT, nullptr);
}
batch.setInputFormat(_format);
batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);
#ifndef POLYLINE_ENTITY_USE_FADE_EFFECT
if (_isFading) {
batch._glColor4f(1.0f, 1.0f, 1.0f, Interpolate::calculateFadeRatio(_fadeStartTime));
} else {
}
else {
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
#endif
batch.draw(gpu::TRIANGLE_STRIP, _numVertices, 0);
};
}

View file

@ -22,15 +22,48 @@
#include <QReadWriteLock>
class PolyLinePayload : public RenderableEntityItemProxy {
public:
static uint8_t CUSTOM_PIPELINE_NUMBER;
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key);
static void registerShapePipeline() {
if (!CUSTOM_PIPELINE_NUMBER) {
CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(shapePipelineFactory);
}
}
static gpu::PipelinePointer _pipeline;
static gpu::PipelinePointer _fadePipeline;
static const int32_t PAINTSTROKE_TEXTURE_SLOT{ 0 };
static const int32_t PAINTSTROKE_UNIFORM_SLOT{ 0 };
PolyLinePayload(const EntityItemPointer& entity, render::ItemID metaID)
: RenderableEntityItemProxy(entity, metaID) {}
typedef render::Payload<PolyLinePayload> Payload;
typedef Payload::DataPointer Pointer;
};
namespace render {
template <> const ItemKey payloadGetKey(const PolyLinePayload::Pointer& payload);
template <> const Item::Bound payloadGetBound(const PolyLinePayload::Pointer& payload);
template <> void payloadRender(const PolyLinePayload::Pointer& payload, RenderArgs* args);
template <> uint32_t metaFetchMetaSubItems(const PolyLinePayload::Pointer& payload, ItemIDs& subItems);
template <> const ShapeKey shapeGetShapeKey(const PolyLinePayload::Pointer& payload);
}
class RenderablePolyLineEntityItem : public PolyLineEntityItem, public SimplerRenderableEntitySupport {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static void createPipeline();
RenderablePolyLineEntityItem(const EntityItemID& entityItemID);
virtual void render(RenderArgs* args) override;
virtual void update(const quint64& now) override;
virtual bool needsToCallUpdate() const override { return true; }
virtual bool addToScene(const EntityItemPointer& self,
const render::ScenePointer& scene,
render::Transaction& transaction) override;
bool isTransparent() override { return true; }
@ -38,15 +71,15 @@ public:
NetworkTexturePointer _texture;
static gpu::PipelinePointer _pipeline;
static gpu::Stream::FormatPointer _format;
static const int32_t PAINTSTROKE_TEXTURE_SLOT { 0 };
static const int32_t PAINTSTROKE_UNIFORM_SLOT { 0 };
protected:
void updateGeometry();
void updateVertices();
void updateMesh();
static void createStreamFormat();
gpu::BufferPointer _verticesBuffer;
gpu::BufferView _uniformBuffer;
unsigned int _numVertices;

View file

@ -20,6 +20,10 @@
#include <model-networking/SimpleMeshProxy.h>
#include "ModelScriptingInterface.h"
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
# include <FadeEffect.h>
#endif
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdouble-promotion"
@ -56,6 +60,10 @@
#include "EntityTreeRenderer.h"
#include "polyvox_vert.h"
#include "polyvox_frag.h"
#include "polyvox_fade_vert.h"
#include "polyvox_fade_frag.h"
#include "RenderablePolyVoxEntityItem.h"
#include "EntityEditPacketSender.h"
#include "PhysicalEntitySimulation.h"
@ -803,6 +811,12 @@ bool RenderablePolyVoxEntityItem::addToScene(const EntityItemPointer& self,
renderPayload->addStatusGetters(statusGetters);
transaction.resetItem(_myItem, renderPayload);
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
if (_mesh && _mesh->getIndexBuffer()._buffer) {
transaction.addTransitionToItem(_myItem, render::Transition::ELEMENT_ENTER_DOMAIN);
_hasTransitioned = true;
}
#endif
return true;
}
@ -816,44 +830,64 @@ void RenderablePolyVoxEntityItem::removeFromScene(const EntityItemPointer& self,
uint8_t PolyVoxPayload::CUSTOM_PIPELINE_NUMBER = 0;
std::shared_ptr<gpu::Pipeline> PolyVoxPayload::_pipeline;
std::shared_ptr<gpu::Pipeline> PolyVoxPayload::_wireframePipeline;
gpu::PipelinePointer PolyVoxPayload::_pipelines[2] = { nullptr, nullptr };
gpu::PipelinePointer PolyVoxPayload::_wireframePipelines[2] = { nullptr, nullptr };
render::ShapePipelinePointer PolyVoxPayload::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) {
if (!_pipeline) {
gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert));
gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag));
if (!_pipelines[0]) {
gpu::ShaderPointer vertexShaders[2] = { gpu::Shader::createVertex(std::string(polyvox_vert)), gpu::Shader::createVertex(std::string(polyvox_fade_vert)) };
gpu::ShaderPointer pixelShaders[2] = { gpu::Shader::createPixel(std::string(polyvox_frag)), gpu::Shader::createPixel(std::string(polyvox_fade_frag)) };
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), PolyVoxPayload::MATERIAL_GPU_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("xMap"), 0));
slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1));
slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2));
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
gpu::Shader::makeProgram(*program, slotBindings);
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), 3));
#endif
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
PrepareStencil::testMaskDrawShape(*state);
_pipeline = gpu::Pipeline::create(program, state);
auto wireframeState = std::make_shared<gpu::State>();
wireframeState->setCullMode(gpu::State::CULL_BACK);
wireframeState->setDepthTest(true, true, gpu::LESS_EQUAL);
wireframeState->setFillMode(gpu::State::FILL_LINE);
PrepareStencil::testMaskDrawShape(*wireframeState);
_wireframePipeline = gpu::Pipeline::create(program, wireframeState);
// Two sets of pipelines: normal and fading
for (auto i = 0; i < 2; i++) {
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShaders[i], pixelShaders[i]);
gpu::Shader::makeProgram(*program, slotBindings);
_pipelines[i] = gpu::Pipeline::create(program, state);
_wireframePipelines[i] = gpu::Pipeline::create(program, wireframeState);
}
}
if (key.isWireframe()) {
return std::make_shared<render::ShapePipeline>(_wireframePipeline, nullptr, nullptr, nullptr);
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
if (key.isFaded()) {
const auto& fadeEffect = DependencyManager::get<FadeEffect>();
if (key.isWireframe()) {
return std::make_shared<render::ShapePipeline>(_wireframePipelines[1], nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
}
else {
return std::make_shared<render::ShapePipeline>(_pipelines[1], nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
}
} else {
return std::make_shared<render::ShapePipeline>(_pipeline, nullptr, nullptr, nullptr);
#endif
if (key.isWireframe()) {
return std::make_shared<render::ShapePipeline>(_wireframePipelines[0], nullptr, nullptr, nullptr);
}
else {
return std::make_shared<render::ShapePipeline>(_pipelines[0], nullptr, nullptr, nullptr);
}
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
}
#endif
}
namespace render {
@ -1368,6 +1402,16 @@ void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) {
if (neighborsNeedUpdate) {
bonkNeighbors();
}
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
if (!_hasTransitioned) {
render::Transaction transaction;
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
transaction.addTransitionToItem(_myItem, render::Transition::ELEMENT_ENTER_DOMAIN);
scene->enqueueTransaction(transaction);
_hasTransitioned = true;
}
#endif
}
void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
@ -1631,6 +1675,7 @@ void RenderablePolyVoxEntityItem::bonkNeighbors() {
void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
EntityItem::locationChanged(tellPhysics);
if (!render::Item::isValidID(_myItem)) {
return;
}

View file

@ -26,6 +26,8 @@
#include "RenderableEntityItem.h"
//#define POLYVOX_ENTITY_USE_FADE_EFFECT
class PolyVoxPayload {
public:
@ -38,8 +40,8 @@ public:
}
static const int MATERIAL_GPU_SLOT = 3;
static std::shared_ptr<gpu::Pipeline> _pipeline;
static std::shared_ptr<gpu::Pipeline> _wireframePipeline;
static gpu::PipelinePointer _pipelines[2];
static gpu::PipelinePointer _wireframePipelines[2];
PolyVoxPayload(EntityItemPointer owner) : _owner(owner), _bounds(AABox()) { }
typedef render::Payload<PolyVoxPayload> Payload;
@ -161,7 +163,7 @@ public:
void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; _meshReady = false; }); }
// Transparent polyvox didn't seem to be working so disable for now
// Transparent polyvox didn't seem to be working so disable for now.
bool isTransparent() override { return false; }
bool getMeshes(MeshProxyList& result) override;
@ -177,7 +179,9 @@ private:
gpu::Stream::FormatPointer _vertexFormat;
bool _meshDirty { true }; // does collision-shape need to be recomputed?
bool _meshReady { false };
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
bool _hasTransitioned{ false };
#endif
NetworkTexturePointer _xTexture;
NetworkTexturePointer _yTexture;
NetworkTexturePointer _zTexture;
@ -217,4 +221,5 @@ private:
bool inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
int x, int y, int z);
#endif // hifi_RenderablePolyVoxEntityItem_h

View file

@ -20,6 +20,11 @@
#include <render-utils/simple_vert.h>
#include <render-utils/simple_frag.h>
//#define SHAPE_ENTITY_USE_FADE_EFFECT
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
# include <FadeEffect.h>
#endif
// Sphere entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
static const float SPHERE_ENTITY_SCALE = 0.5f;
@ -73,6 +78,9 @@ void RenderableShapeEntityItem::setUserData(const QString& value) {
}
bool RenderableShapeEntityItem::isTransparent() {
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
return getLocalRenderAlpha() < 1.0f;
#else
if (_procedural && _procedural->isFading()) {
float isFading = Interpolate::calculateFadeRatio(_procedural->getFadeStartTime()) < 1.0f;
_procedural->setIsFading(isFading);
@ -80,6 +88,51 @@ bool RenderableShapeEntityItem::isTransparent() {
} else {
return getLocalRenderAlpha() < 1.0f || EntityItem::isTransparent();
}
#endif
}
namespace render {
template <> const ItemKey payloadGetKey(const ShapePayload::Pointer& payload) {
return payloadGetKey(std::static_pointer_cast<RenderableEntityItemProxy>(payload));
}
template <> const Item::Bound payloadGetBound(const ShapePayload::Pointer& payload) {
return payloadGetBound(std::static_pointer_cast<RenderableEntityItemProxy>(payload));
}
template <> void payloadRender(const ShapePayload::Pointer& payload, RenderArgs* args) {
payloadRender(std::static_pointer_cast<RenderableEntityItemProxy>(payload), args);
}
template <> uint32_t metaFetchMetaSubItems(const ShapePayload::Pointer& payload, ItemIDs& subItems) {
return metaFetchMetaSubItems(std::static_pointer_cast<RenderableEntityItemProxy>(payload), subItems);
}
template <> const ShapeKey shapeGetShapeKey(const ShapePayload::Pointer& payload) {
auto shapeKey = ShapeKey::Builder();
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
shapeKey.withCustom(GeometryCache::CUSTOM_PIPELINE_NUMBER);
#endif
auto entity = payload->_entity;
if (entity->getLocalRenderAlpha() < 1.f) {
shapeKey.withTranslucent();
}
return shapeKey.build();
}
}
bool RenderableShapeEntityItem::addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) {
_myItem = scene->allocateID();
auto renderData = std::make_shared<ShapePayload>(self, _myItem);
auto renderPayload = std::make_shared<ShapePayload::Payload>(renderData);
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(self, statusGetters);
renderPayload->addStatusGetters(statusGetters);
transaction.resetItem(_myItem, renderPayload);
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
transaction.addTransitionToItem(_myItem, render::Transition::ELEMENT_ENTER_DOMAIN);
#endif
return true;
}
void RenderableShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
@ -160,7 +213,9 @@ void RenderableShapeEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
//Q_ASSERT(getType() == EntityTypes::Shape);
Q_ASSERT(args->_batch);
#ifndef SHAPE_ENTITY_USE_FADE_EFFECT
checkFading();
#endif
if (!_procedural) {
_procedural.reset(new Procedural(getUserData()));
@ -188,7 +243,9 @@ void RenderableShapeEntityItem::render(RenderArgs* args) {
if (_procedural->ready()) {
_procedural->prepare(batch, getPosition(), getDimensions(), getOrientation());
auto outColor = _procedural->getColor(color);
#ifndef SHAPE_ENTITY_USE_FADE_EFFECT
outColor.a *= _procedural->isFading() ? Interpolate::calculateFadeRatio(_procedural->getFadeStartTime()) : 1.0f;
#endif
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
DependencyManager::get<GeometryCache>()->renderWireShape(batch, MAPPING[_shape]);
@ -197,15 +254,46 @@ void RenderableShapeEntityItem::render(RenderArgs* args) {
}
} else {
// FIXME, support instanced multi-shape rendering using multidraw indirect
color.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
auto geometryCache = DependencyManager::get<GeometryCache>();
auto pipeline = color.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
auto shapeKey = render::ShapeKey(args->_itemShapeKey);
assert(args->_shapePipeline != nullptr);
if (shapeKey.isFaded()) {
auto fadeEffect = DependencyManager::get<FadeEffect>();
auto fadeCategory = fadeEffect->getLastCategory();
auto fadeThreshold = fadeEffect->getLastThreshold();
auto fadeNoiseOffset = fadeEffect->getLastNoiseOffset();
auto fadeBaseOffset = fadeEffect->getLastBaseOffset();
auto fadeBaseInvSize = fadeEffect->getLastBaseInvSize();
if (shapeKey.isWireframe()) {
geometryCache->renderWireFadeShapeInstance(args, batch, MAPPING[_shape], color, fadeCategory, fadeThreshold,
fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, args->_shapePipeline);
}
else {
geometryCache->renderSolidFadeShapeInstance(args, batch, MAPPING[_shape], color, fadeCategory, fadeThreshold,
fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, args->_shapePipeline);
}
} else {
if (shapeKey.isWireframe()) {
geometryCache->renderWireShapeInstance(args, batch, MAPPING[_shape], color, args->_shapePipeline);
}
else {
geometryCache->renderSolidShapeInstance(args, batch, MAPPING[_shape], color, args->_shapePipeline);
}
}
#else
color.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
auto pipeline = color.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
geometryCache->renderWireShapeInstance(args, batch, MAPPING[_shape], color, pipeline);
} else {
}
else {
geometryCache->renderSolidShapeInstance(args, batch, MAPPING[_shape], color, pipeline);
}
#endif
}
static const auto triCount = DependencyManager::get<GeometryCache>()->getShapeTriangleCount(MAPPING[_shape]);

View file

@ -14,6 +14,23 @@
#include "RenderableEntityItem.h"
class ShapePayload : public RenderableEntityItemProxy {
public:
ShapePayload(const EntityItemPointer& entity, render::ItemID metaID)
: RenderableEntityItemProxy(entity, metaID) {}
typedef render::Payload<ShapePayload> Payload;
typedef Payload::DataPointer Pointer;
};
namespace render {
template <> const ItemKey payloadGetKey(const ShapePayload::Pointer& payload);
template <> const Item::Bound payloadGetBound(const ShapePayload::Pointer& payload);
template <> void payloadRender(const ShapePayload::Pointer& payload, RenderArgs* args);
template <> uint32_t metaFetchMetaSubItems(const ShapePayload::Pointer& payload, ItemIDs& subItems);
template <> const ShapeKey shapeGetShapeKey(const ShapePayload::Pointer& payload);
}
class RenderableShapeEntityItem : public ShapeEntityItem, private SimplerRenderableEntitySupport {
using Pointer = std::shared_ptr<RenderableShapeEntityItem>;
static Pointer baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties);
@ -23,6 +40,7 @@ public:
static EntityItemPointer sphereFactory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableShapeEntityItem(const EntityItemID& entityItemID) : ShapeEntityItem(entityItemID) {}
bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
void render(RenderArgs* args) override;
void setUserData(const QString& value) override;

View file

@ -0,0 +1,53 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// paintStroke_fade.slf
// fragment shader
//
// Created by Olivier Prat on 19/07/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include Fade.slh@>
<$declareFadeFragment()$>
// the albedo texture
uniform sampler2D originalTexture;
// the interpolated normal
in vec3 interpolatedNormal;
in vec2 varTexcoord;
in vec4 varColor;
in vec4 _worldPosition;
struct PolyLineUniforms {
vec3 color;
};
uniform polyLineBuffer {
PolyLineUniforms polyline;
};
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
vec4 texel = texture(originalTexture, varTexcoord);
int frontCondition = 1 -int(gl_FrontFacing) * 2;
vec3 color = varColor.rgb;
packDeferredFragmentTranslucent(
interpolatedNormal * frontCondition,
texel.a * varColor.a,
polyline.color * texel.rgb + fadeEmissive,
vec3(0.01, 0.01, 0.01),
10.0);
}

View file

@ -0,0 +1,43 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// paintStroke_fade.slv
// vertex shader
//
// Created by Olivier Prat on 19/07/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Color.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
// the interpolated normal
out vec3 interpolatedNormal;
//the diffuse texture
out vec2 varTexcoord;
out vec4 varColor;
out vec4 _worldPosition;
void main(void) {
varTexcoord = inTexCoord0.st;
// pass along the diffuse color
varColor = colorToLinearRGBA(inColor);
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$transformModelToEyeDir(cam, obj, inNormal.xyz, interpolatedNormal)$>
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
}

View file

@ -0,0 +1,64 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// polyvox_fade.frag
// fragment shader
//
// Created by Olivier Prat on 2017-06-08
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include model/Material.slh@>
<@include DeferredBufferWrite.slh@>
<@include Fade.slh@>
in vec3 _normal;
in vec4 _position;
in vec4 _worldPosition;
in vec4 _worldFadePosition;
uniform sampler2D xMap;
uniform sampler2D yMap;
uniform sampler2D zMap;
uniform vec3 voxelVolumeSize;
// Declare after all samplers to prevent sampler location mix up with voxel shading (sampler locations are hardcoded in RenderablePolyVoxEntityItem)
<$declareFadeFragment()$>
void main(void) {
vec3 emissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldFadePosition.xyz, emissive);
vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz));
worldNormal = normalize(worldNormal);
float inPositionX = (_worldPosition.x - 0.5) / voxelVolumeSize.x;
float inPositionY = (_worldPosition.y - 0.5) / voxelVolumeSize.y;
float inPositionZ = (_worldPosition.z - 0.5) / voxelVolumeSize.z;
vec4 xyDiffuse = texture(xMap, vec2(-inPositionX, -inPositionY));
vec4 xzDiffuse = texture(yMap, vec2(-inPositionX, inPositionZ));
vec4 yzDiffuse = texture(zMap, vec2(inPositionZ, -inPositionY));
vec3 xyDiffuseScaled = xyDiffuse.rgb * abs(worldNormal.z);
vec3 xzDiffuseScaled = xzDiffuse.rgb * abs(worldNormal.y);
vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x);
vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0);
packDeferredFragment(
_normal,
1.0,
vec3(diffuse),
DEFAULT_ROUGHNESS,
DEFAULT_METALLIC,
DEFAULT_EMISSIVE+emissive,
DEFAULT_OCCLUSION,
DEFAULT_SCATTERING);
}

View file

@ -0,0 +1,33 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// polyvox_fade.vert
// vertex shader
//
// Created by Seth Alves on 2015-8-3
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
out vec4 _position;
out vec4 _worldPosition;
out vec4 _worldFadePosition;
out vec3 _normal;
void main(void) {
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
<$transformModelToWorldPos(obj, inPosition, _worldFadePosition)$>
_worldPosition = inPosition;
}

View file

@ -455,7 +455,7 @@ void GLBackend::do_glUniform1i(const Batch& batch, size_t paramOffset) {
}
updatePipeline();
glUniform1f(
glUniform1i(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
batch._params[paramOffset + 0]._int);
(void)CHECK_GL_ERROR();

View file

@ -485,9 +485,15 @@ void GLBackend::makeProgramBindings(ShaderObject& shaderObject) {
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent");
}
loc = glGetAttribLocation(glprogram, "inTexCoord1");
if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) {
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1");
char attribName[] = "inTexCoordn";
for (auto i = 0; i < 4; i++) {
auto streamId = gpu::Stream::TEXCOORD1 + i;
attribName[strlen(attribName) - 1] = '1' + i;
loc = glGetAttribLocation(glprogram, attribName);
if (loc >= 0 && loc != streamId) {
glBindAttribLocation(glprogram, streamId, attribName);
}
}
loc = glGetAttribLocation(glprogram, "inSkinClusterIndex");

View file

@ -18,4 +18,7 @@ layout(location = 4) in vec4 inTangent;
layout(location = 5) in ivec4 inSkinClusterIndex;
layout(location = 6) in vec4 inSkinClusterWeight;
layout(location = 7) in vec4 inTexCoord1;
layout(location = 8) in vec4 inTexCoord2;
layout(location = 9) in vec4 inTexCoord3;
layout(location = 10) in vec4 inTexCoord4;
<@endif@>

View file

@ -36,8 +36,14 @@ const ElementArray& getDefaultElements() {
//SKIN_CLUSTER_WEIGHT = 6,
Element::VEC4F_XYZW,
//TEXCOORD1 = 7,
Element::VEC2F_UV
}};
Element::VEC2F_UV,
//TEXCOORD2 = 7,
Element::VEC4F_XYZW,
//TEXCOORD3 = 7,
Element::VEC4F_XYZW,
//TEXCOORD4 = 7,
Element::VEC4F_XYZW
}};
return defaultElements;
}

View file

@ -38,8 +38,11 @@ public:
SKIN_CLUSTER_INDEX = 5,
SKIN_CLUSTER_WEIGHT = 6,
TEXCOORD1 = 7,
NUM_INPUT_SLOTS = TEXCOORD1 + 1,
TEXCOORD2 = 8,
TEXCOORD3 = 9,
TEXCOORD4 = 10,
NUM_INPUT_SLOTS,
DRAW_CALL_INFO = 15, // Reserve last input slot for draw call infos
};

View file

@ -0,0 +1,169 @@
// Generated on <$_SCRIBE_DATE$>
//
// Created by Olivier Prat on 04/12/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@if not FADE_SLH@>
<@def FADE_SLH@>
<@func declareFadeFragmentCommon()@>
#define CATEGORY_COUNT 5
<@include Fade_shared.slh@>
layout(std140) uniform fadeParametersBuffer {
FadeParameters fadeParameters[CATEGORY_COUNT];
};
uniform sampler2D fadeMaskMap;
struct FadeObjectParams {
int category;
float threshold;
vec3 noiseOffset;
vec3 baseOffset;
vec3 baseInvSize;
};
vec2 hash2D(vec3 position) {
return position.xy* vec2(0.1677, 0.221765) + position.z*0.561;
}
float noise3D(vec3 position) {
float n = textureLod(fadeMaskMap, hash2D(position), 0).r;
return pow(n, 1.0/2.2); // Remove sRGB. Need to fix this later directly in the texture
}
float evalFadeNoiseGradient(FadeObjectParams params, vec3 position) {
// Do tri-linear interpolation
vec3 noisePosition = position * fadeParameters[params.category]._noiseInvSizeAndLevel.xyz + params.noiseOffset;
vec3 noisePositionFloored = floor(noisePosition);
vec3 noisePositionFraction = fract(noisePosition);
noisePositionFraction = noisePositionFraction*noisePositionFraction*(3 - 2*noisePositionFraction);
float noiseLowXLowYLowZ = noise3D(noisePositionFloored);
float noiseLowXHighYLowZ = noise3D(noisePositionFloored+vec3(0,1,0));
float noiseHighXLowYLowZ = noise3D(noisePositionFloored+vec3(1,0,0));
float noiseHighXHighYLowZ = noise3D(noisePositionFloored+vec3(1,1,0));
float noiseLowXLowYHighZ = noise3D(noisePositionFloored+vec3(0,0,1));
float noiseLowXHighYHighZ = noise3D(noisePositionFloored+vec3(0,1,1));
float noiseHighXLowYHighZ = noise3D(noisePositionFloored+vec3(1,0,1));
float noiseHighXHighYHighZ = noise3D(noisePositionFloored+vec3(1,1,1));
vec4 maskLowZ = vec4(noiseLowXLowYLowZ, noiseLowXHighYLowZ, noiseHighXLowYLowZ, noiseHighXHighYLowZ);
vec4 maskHighZ = vec4(noiseLowXLowYHighZ, noiseLowXHighYHighZ, noiseHighXLowYHighZ, noiseHighXHighYHighZ);
vec4 maskXY = mix(maskLowZ, maskHighZ, noisePositionFraction.z);
vec2 maskY = mix(maskXY.xy, maskXY.zw, noisePositionFraction.x);
float noise = mix(maskY.x, maskY.y, noisePositionFraction.y);
noise -= 0.5; // Center on value 0
return noise * fadeParameters[params.category]._noiseInvSizeAndLevel.w;
}
float evalFadeBaseGradient(FadeObjectParams params, vec3 position) {
float gradient = length((position - params.baseOffset) * params.baseInvSize.xyz);
gradient = gradient-0.5; // Center on value 0.5
gradient *= fadeParameters[params.category]._baseLevel;
return gradient;
}
float evalFadeGradient(FadeObjectParams params, vec3 position) {
float baseGradient = evalFadeBaseGradient(params, position);
float noiseGradient = evalFadeNoiseGradient(params, position);
float gradient = noiseGradient+baseGradient+0.5;
return gradient;
}
float evalFadeAlpha(FadeObjectParams params, vec3 position) {
return evalFadeGradient(params, position)-params.threshold;
}
void applyFadeClip(FadeObjectParams params, vec3 position) {
if (evalFadeAlpha(params, position) < 0) {
discard;
}
}
void applyFade(FadeObjectParams params, vec3 position, out vec3 emissive) {
float alpha = evalFadeAlpha(params, position);
if (fadeParameters[params.category]._isInverted!=0) {
alpha = -alpha;
}
if (alpha < 0) {
discard;
}
float edgeMask = alpha * fadeParameters[params.category]._edgeWidthInvWidth.y;
float edgeAlpha = 1.0-clamp(edgeMask, 0, 1);
edgeMask = step(edgeMask, 1.f);
edgeAlpha *= edgeAlpha; // Square to have a nice ease out
vec4 color = mix(fadeParameters[params.category]._innerEdgeColor, fadeParameters[params.category]._outerEdgeColor, edgeAlpha);
emissive = color.rgb * edgeMask * color.a;
}
<@endfunc@>
<@func declareFadeFragmentUniform()@>
uniform int fadeCategory;
uniform vec3 fadeNoiseOffset;
uniform vec3 fadeBaseOffset;
uniform vec3 fadeBaseInvSize;
uniform float fadeThreshold;
<@endfunc@>
<@func fetchFadeObjectParams(fadeParams)@>
<$fadeParams$>.category = fadeCategory;
<$fadeParams$>.threshold = fadeThreshold;
<$fadeParams$>.noiseOffset = fadeNoiseOffset;
<$fadeParams$>.baseOffset = fadeBaseOffset;
<$fadeParams$>.baseInvSize = fadeBaseInvSize;
<@endfunc@>
<@func declareFadeFragmentVertexInput()@>
in vec4 _fadeData1;
in vec4 _fadeData2;
in vec4 _fadeData3;
<@endfunc@>
<@func fetchFadeObjectParamsInstanced(fadeParams)@>
<$fadeParams$>.category = int(_fadeData1.w);
<$fadeParams$>.threshold = _fadeData2.w;
<$fadeParams$>.noiseOffset = _fadeData1.xyz;
<$fadeParams$>.baseOffset = _fadeData2.xyz;
<$fadeParams$>.baseInvSize = _fadeData3.xyz;
<@endfunc@>
<@func declareFadeFragment()@>
<$declareFadeFragmentCommon()$>
<$declareFadeFragmentUniform()$>
<@endfunc@>
<@func declareFadeFragmentInstanced()@>
<$declareFadeFragmentCommon()$>
<$declareFadeFragmentVertexInput()$>
<@endfunc@>
<@func declareFadeVertexInstanced()@>
out vec4 _fadeData1;
out vec4 _fadeData2;
out vec4 _fadeData3;
<@endfunc@>
<@func passThroughFadeObjectParams()@>
_fadeData1 = inTexCoord2;
_fadeData2 = inTexCoord3;
_fadeData3 = inTexCoord4;
<@endfunc@>
<@endif@>

View file

@ -0,0 +1,104 @@
//
// FadeEffect.cpp
// Created by Olivier Prat on 17/07/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "FadeEffect.h"
#include "FadeEffectJobs.h"
#include "TextureCache.h"
#include "render/TransitionStage.h"
#include <PathUtils.h>
FadeEffect::FadeEffect() {
auto texturePath = PathUtils::resourcesPath() + "images/fadeMask.png";
_maskMap = DependencyManager::get<TextureCache>()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE);
}
void FadeEffect::build(render::Task::TaskConcept& task, const task::Varying& editableItems) {
auto editedFadeCategory = task.addJob<FadeJob>("Fade");
auto& fadeJob = task._jobs.back();
_configurations = fadeJob.get<FadeJob>().getConfigurationBuffer();
const auto fadeEditInput = FadeEditJob::Input(editableItems, editedFadeCategory).asVarying();
task.addJob<FadeEditJob>("FadeEdit", fadeEditInput);
}
render::ShapePipeline::BatchSetter FadeEffect::getBatchSetter() const {
return [this](const render::ShapePipeline& shapePipeline, gpu::Batch& batch, render::Args*) {
auto program = shapePipeline.pipeline->getProgram();
auto maskMapLocation = program->getTextures().findLocation("fadeMaskMap");
auto bufferLocation = program->getUniformBuffers().findLocation("fadeParametersBuffer");
batch.setResourceTexture(maskMapLocation, _maskMap);
batch.setUniformBuffer(bufferLocation, _configurations);
};
}
render::ShapePipeline::ItemSetter FadeEffect::getItemUniformSetter() const {
return [](const render::ShapePipeline& shapePipeline, render::Args* args, const render::Item& item) {
if (!render::TransitionStage::isIndexInvalid(item.getTransitionId())) {
auto scene = args->_scene;
auto batch = args->_batch;
auto transitionStage = scene->getStage<render::TransitionStage>(render::TransitionStage::getName());
auto& transitionState = transitionStage->getTransition(item.getTransitionId());
auto program = shapePipeline.pipeline->getProgram();
auto& uniforms = program->getUniforms();
auto fadeNoiseOffsetLocation = uniforms.findLocation("fadeNoiseOffset");
auto fadeBaseOffsetLocation = uniforms.findLocation("fadeBaseOffset");
auto fadeBaseInvSizeLocation = uniforms.findLocation("fadeBaseInvSize");
auto fadeThresholdLocation = uniforms.findLocation("fadeThreshold");
auto fadeCategoryLocation = uniforms.findLocation("fadeCategory");
if (fadeNoiseOffsetLocation >= 0 || fadeBaseInvSizeLocation >= 0 || fadeBaseOffsetLocation >= 0 || fadeThresholdLocation >= 0 || fadeCategoryLocation >= 0) {
const auto fadeCategory = FadeJob::transitionToCategory[transitionState.eventType];
batch->_glUniform1i(fadeCategoryLocation, fadeCategory);
batch->_glUniform1f(fadeThresholdLocation, transitionState.threshold);
batch->_glUniform3f(fadeNoiseOffsetLocation, transitionState.noiseOffset.x, transitionState.noiseOffset.y, transitionState.noiseOffset.z);
batch->_glUniform3f(fadeBaseOffsetLocation, transitionState.baseOffset.x, transitionState.baseOffset.y, transitionState.baseOffset.z);
batch->_glUniform3f(fadeBaseInvSizeLocation, transitionState.baseInvSize.x, transitionState.baseInvSize.y, transitionState.baseInvSize.z);
}
}
};
}
render::ShapePipeline::ItemSetter FadeEffect::getItemStoredSetter() {
return [this](const render::ShapePipeline& shapePipeline, render::Args* args, const render::Item& item) {
if (!render::TransitionStage::isIndexInvalid(item.getTransitionId())) {
auto scene = args->_scene;
auto transitionStage = scene->getStage<render::TransitionStage>(render::TransitionStage::getName());
auto& transitionState = transitionStage->getTransition(item.getTransitionId());
const auto fadeCategory = FadeJob::transitionToCategory[transitionState.eventType];
_lastCategory = fadeCategory;
_lastThreshold = transitionState.threshold;
_lastNoiseOffset = transitionState.noiseOffset;
_lastBaseOffset = transitionState.baseOffset;
_lastBaseInvSize = transitionState.baseInvSize;
}
};
}
void FadeEffect::packToAttributes(const int category, const float threshold, const glm::vec3& noiseOffset,
const glm::vec3& baseOffset, const glm::vec3& baseInvSize,
glm::vec4& packedData1, glm::vec4& packedData2, glm::vec4& packedData3) {
packedData1.x = noiseOffset.x;
packedData1.y = noiseOffset.y;
packedData1.z = noiseOffset.z;
packedData1.w = (float)(category+0.1f); // GLSL hack so that casting back from float to int in fragment shader returns the correct value.
packedData2.x = baseOffset.x;
packedData2.y = baseOffset.y;
packedData2.z = baseOffset.z;
packedData2.w = threshold;
packedData3.x = baseInvSize.x;
packedData3.y = baseInvSize.y;
packedData3.z = baseInvSize.z;
packedData3.w = 0.f;
}

View file

@ -0,0 +1,54 @@
//
// FadeEffect.h
// Created by Olivier Prat on 17/07/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_render_utils_FadeEffect_h
#define hifi_render_utils_FadeEffect_h
#include <DependencyManager.h>
#include <render/Engine.h>
class FadeEffect : public Dependency {
SINGLETON_DEPENDENCY;
public:
void build(render::Task::TaskConcept& task, const task::Varying& editableItems);
render::ShapePipeline::BatchSetter getBatchSetter() const;
render::ShapePipeline::ItemSetter getItemUniformSetter() const;
render::ShapePipeline::ItemSetter getItemStoredSetter();
int getLastCategory() const { return _lastCategory; }
float getLastThreshold() const { return _lastThreshold; }
const glm::vec3& getLastNoiseOffset() const { return _lastNoiseOffset; }
const glm::vec3& getLastBaseOffset() const { return _lastBaseOffset; }
const glm::vec3& getLastBaseInvSize() const { return _lastBaseInvSize; }
static void packToAttributes(const int category, const float threshold, const glm::vec3& noiseOffset,
const glm::vec3& baseOffset, const glm::vec3& baseInvSize,
glm::vec4& packedData1, glm::vec4& packedData2, glm::vec4& packedData3);
private:
gpu::BufferView _configurations;
gpu::TexturePointer _maskMap;
// The last fade set through the stored item setter
int _lastCategory { 0 };
float _lastThreshold { 0.f };
glm::vec3 _lastNoiseOffset { 0.f, 0.f, 0.f };
glm::vec3 _lastBaseOffset { 0.f, 0.f, 0.f };
glm::vec3 _lastBaseInvSize { 1.f, 1.f, 1.f };
explicit FadeEffect();
virtual ~FadeEffect() { }
};
#endif // hifi_render_utils_FadeEffect_h

View file

@ -0,0 +1,733 @@
//
// FadeEffectJobs.cpp
// Created by Olivier Prat on 07/07/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "FadeEffectJobs.h"
#include "render/Logging.h"
#include "render/TransitionStage.h"
#include <NumericalConstants.h>
#include <Interpolate.h>
#include <gpu/Context.h>
#include <QJsonArray>
#include <PathUtils.h>
#define FADE_MIN_SCALE 0.001
#define FADE_MAX_SCALE 10000.0
#define FADE_MAX_SPEED 50.f
inline float parameterToValuePow(float parameter, const double minValue, const double maxOverMinValue) {
return (float)(minValue * pow(maxOverMinValue, double(parameter)));
}
inline float valueToParameterPow(float value, const double minValue, const double maxOverMinValue) {
return (float)(log(double(value) / minValue) / log(maxOverMinValue));
}
void FadeEditJob::configure(const Config& config) {
_isEditEnabled = config.editFade;
}
void FadeEditJob::run(const render::RenderContextPointer& renderContext, const FadeEditJob::Input& inputs) {
auto scene = renderContext->_scene;
if (_isEditEnabled) {
float minIsectDistance = std::numeric_limits<float>::max();
auto& itemBounds = inputs.get0();
auto editedItem = findNearestItem(renderContext, itemBounds, minIsectDistance);
render::Transaction transaction;
bool hasTransaction{ false };
if (editedItem != _editedItem && render::Item::isValidID(_editedItem)) {
// Remove transition from previously edited item as we've changed edited item
hasTransaction = true;
transaction.removeTransitionFromItem(_editedItem);
}
_editedItem = editedItem;
if (render::Item::isValidID(_editedItem)) {
static const render::Transition::Type categoryToTransition[FADE_CATEGORY_COUNT] = {
render::Transition::ELEMENT_ENTER_DOMAIN,
render::Transition::BUBBLE_ISECT_OWNER,
render::Transition::BUBBLE_ISECT_TRESPASSER,
render::Transition::USER_ENTER_DOMAIN,
render::Transition::AVATAR_CHANGE
};
auto transitionType = categoryToTransition[inputs.get1()];
transaction.queryTransitionOnItem(_editedItem, [transitionType, scene](render::ItemID id, const render::Transition* transition) {
if (transition == nullptr || transition->isFinished || transition->eventType!=transitionType) {
// Relaunch transition
render::Transaction transaction;
transaction.addTransitionToItem(id, transitionType);
scene->enqueueTransaction(transaction);
}
});
hasTransaction = true;
}
if (hasTransaction) {
scene->enqueueTransaction(transaction);
}
}
else if (render::Item::isValidID(_editedItem)) {
// Remove transition from previously edited item as we've disabled fade edition
render::Transaction transaction;
transaction.removeTransitionFromItem(_editedItem);
scene->enqueueTransaction(transaction);
_editedItem = render::Item::INVALID_ITEM_ID;
}
}
render::ItemID FadeEditJob::findNearestItem(const render::RenderContextPointer& renderContext, const render::ItemBounds& inputs, float& minIsectDistance) const {
const glm::vec3 rayOrigin = renderContext->args->getViewFrustum().getPosition();
const glm::vec3 rayDirection = renderContext->args->getViewFrustum().getDirection();
BoxFace face;
glm::vec3 normal;
float isectDistance;
render::ItemID nearestItem = render::Item::INVALID_ITEM_ID;
const float minDistance = 1.f;
const float maxDistance = 50.f;
for (const auto& itemBound : inputs) {
if (!itemBound.bound.contains(rayOrigin) && itemBound.bound.findRayIntersection(rayOrigin, rayDirection, isectDistance, face, normal)) {
auto& item = renderContext->_scene->getItem(itemBound.id);
if (item.getKey().isWorldSpace() && isectDistance>minDistance && isectDistance < minIsectDistance && isectDistance<maxDistance) {
nearestItem = itemBound.id;
minIsectDistance = isectDistance;
}
}
}
return nearestItem;
}
FadeConfig::FadeConfig()
{
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].noiseSize = glm::vec3{ 0.75f, 0.75f, 0.75f };
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].noiseLevel = 1.f;
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].noiseSpeed = glm::vec3{ 0.0f, 0.0f, 0.0f };
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].timing = FadeConfig::LINEAR;
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].baseSize = glm::vec3{ 1.0f, 1.0f, 1.0f };
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].baseLevel = 0.f;
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].isInverted = false;
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].duration = 4.f;
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].edgeWidth = 0.1f;
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].edgeInnerColor = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 0.0f };
events[FADE_ELEMENT_ENTER_LEAVE_DOMAIN].edgeOuterColor = glm::vec4{ 78.f / 255.f, 215.f / 255.f, 255.f / 255.f, 1.0f };
events[FADE_BUBBLE_ISECT_OWNER].noiseSize = glm::vec3{ 1.5f, 1.0f / 25.f, 0.5f };
events[FADE_BUBBLE_ISECT_OWNER].noiseLevel = 0.37f;
events[FADE_BUBBLE_ISECT_OWNER].noiseSpeed = glm::vec3{ 1.0f, 0.2f, 1.0f };
events[FADE_BUBBLE_ISECT_OWNER].timing = FadeConfig::LINEAR;
events[FADE_BUBBLE_ISECT_OWNER].baseSize = glm::vec3{ 2.0f, 2.0f, 2.0f };
events[FADE_BUBBLE_ISECT_OWNER].baseLevel = 1.f;
events[FADE_BUBBLE_ISECT_OWNER].isInverted = false;
events[FADE_BUBBLE_ISECT_OWNER].duration = 4.f;
events[FADE_BUBBLE_ISECT_OWNER].edgeWidth = 0.02f;
events[FADE_BUBBLE_ISECT_OWNER].edgeInnerColor = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f };
events[FADE_BUBBLE_ISECT_OWNER].edgeOuterColor = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f };
events[FADE_BUBBLE_ISECT_TRESPASSER].noiseSize = glm::vec3{ 0.5f, 1.0f / 25.f, 0.5f };
events[FADE_BUBBLE_ISECT_TRESPASSER].noiseLevel = 1.f;
events[FADE_BUBBLE_ISECT_TRESPASSER].noiseSpeed = glm::vec3{ 1.0f, -5.f, 1.0f };
events[FADE_BUBBLE_ISECT_TRESPASSER].timing = FadeConfig::LINEAR;
events[FADE_BUBBLE_ISECT_TRESPASSER].baseSize = glm::vec3{ 2.0f, 2.0f, 2.0f };
events[FADE_BUBBLE_ISECT_TRESPASSER].baseLevel = 0.f;
events[FADE_BUBBLE_ISECT_TRESPASSER].isInverted = false;
events[FADE_BUBBLE_ISECT_TRESPASSER].duration = 4.f;
events[FADE_BUBBLE_ISECT_TRESPASSER].edgeWidth = 0.025f;
events[FADE_BUBBLE_ISECT_TRESPASSER].edgeInnerColor = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 1.0f };
events[FADE_BUBBLE_ISECT_TRESPASSER].edgeOuterColor = glm::vec4{ 31.f / 255.f, 198.f / 255.f, 166.f / 255.f, 2.0f };
events[FADE_USER_ENTER_LEAVE_DOMAIN].noiseSize = glm::vec3{ 10.f, 0.01f, 10.0f };
events[FADE_USER_ENTER_LEAVE_DOMAIN].noiseLevel = 0.3f;
events[FADE_USER_ENTER_LEAVE_DOMAIN].noiseSpeed = glm::vec3{ 0.0f, -5.0f, 0.0f };
events[FADE_USER_ENTER_LEAVE_DOMAIN].timing = FadeConfig::LINEAR;
events[FADE_USER_ENTER_LEAVE_DOMAIN].baseSize = glm::vec3{ 10000.f, 1.0f, 10000.0f };
events[FADE_USER_ENTER_LEAVE_DOMAIN].baseLevel = 1.f;
events[FADE_USER_ENTER_LEAVE_DOMAIN].isInverted = true;
events[FADE_USER_ENTER_LEAVE_DOMAIN].duration = 2.f;
events[FADE_USER_ENTER_LEAVE_DOMAIN].edgeWidth = 0.229f;
events[FADE_USER_ENTER_LEAVE_DOMAIN].edgeInnerColor = glm::vec4{ 1.f, 0.63f, 0.13f, 0.5f };
events[FADE_USER_ENTER_LEAVE_DOMAIN].edgeOuterColor = glm::vec4{ 1.f, 1.f, 1.f, 1.0f };
events[FADE_AVATAR_CHANGE].noiseSize = glm::vec3{ 0.4f, 0.4f, 0.4f };
events[FADE_AVATAR_CHANGE].noiseLevel = 1.f;
events[FADE_AVATAR_CHANGE].noiseSpeed = glm::vec3{ 0.0f, 0.0f, 0.0f };
events[FADE_AVATAR_CHANGE].timing = FadeConfig::LINEAR;
events[FADE_AVATAR_CHANGE].baseSize = glm::vec3{ 0.4f, 0.4f, 0.4f };
events[FADE_AVATAR_CHANGE].baseLevel = 1.f;
events[FADE_AVATAR_CHANGE].isInverted = false;
events[FADE_AVATAR_CHANGE].duration = 3.f;
events[FADE_AVATAR_CHANGE].edgeWidth = 0.05f;
events[FADE_AVATAR_CHANGE].edgeInnerColor = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f };
events[FADE_AVATAR_CHANGE].edgeOuterColor = glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f };
}
void FadeConfig::setEditedCategory(int value) {
assert(value < FADE_CATEGORY_COUNT);
editedCategory = std::min<int>(FADE_CATEGORY_COUNT, value);
emit dirtyCategory();
emit dirty();
}
void FadeConfig::setDuration(float value) {
events[editedCategory].duration = value;
emit dirty();
}
float FadeConfig::getDuration() const {
return events[editedCategory].duration;
}
void FadeConfig::setBaseSizeX(float value) {
events[editedCategory].baseSize.x = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE);
emit dirty();
}
float FadeConfig::getBaseSizeX() const {
return valueToParameterPow(events[editedCategory].baseSize.x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
}
void FadeConfig::setBaseSizeY(float value) {
events[editedCategory].baseSize.y = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
emit dirty();
}
float FadeConfig::getBaseSizeY() const {
return valueToParameterPow(events[editedCategory].baseSize.y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
}
void FadeConfig::setBaseSizeZ(float value) {
events[editedCategory].baseSize.z = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
emit dirty();
}
float FadeConfig::getBaseSizeZ() const {
return valueToParameterPow(events[editedCategory].baseSize.z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
}
void FadeConfig::setBaseLevel(float value) {
events[editedCategory].baseLevel = value;
emit dirty();
}
void FadeConfig::setInverted(bool value) {
events[editedCategory].isInverted = value;
emit dirty();
}
bool FadeConfig::isInverted() const {
return events[editedCategory].isInverted;
}
void FadeConfig::setNoiseSizeX(float value) {
events[editedCategory].noiseSize.x = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
emit dirty();
}
float FadeConfig::getNoiseSizeX() const {
return valueToParameterPow(events[editedCategory].noiseSize.x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
}
void FadeConfig::setNoiseSizeY(float value) {
events[editedCategory].noiseSize.y = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
emit dirty();
}
float FadeConfig::getNoiseSizeY() const {
return valueToParameterPow(events[editedCategory].noiseSize.y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
}
void FadeConfig::setNoiseSizeZ(float value) {
events[editedCategory].noiseSize.z = parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
emit dirty();
}
float FadeConfig::getNoiseSizeZ() const {
return valueToParameterPow(events[editedCategory].noiseSize.z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);
}
void FadeConfig::setNoiseLevel(float value) {
events[editedCategory].noiseLevel = value;
emit dirty();
}
void FadeConfig::setNoiseSpeedX(float value) {
events[editedCategory].noiseSpeed.x = powf(value, 3.f)*FADE_MAX_SPEED;
emit dirty();
}
float FadeConfig::getNoiseSpeedX() const {
return powf(events[editedCategory].noiseSpeed.x / FADE_MAX_SPEED, 1.f / 3.f);
}
void FadeConfig::setNoiseSpeedY(float value) {
events[editedCategory].noiseSpeed.y = powf(value, 3.f)*FADE_MAX_SPEED;
emit dirty();
}
float FadeConfig::getNoiseSpeedY() const {
return powf(events[editedCategory].noiseSpeed.y / FADE_MAX_SPEED, 1.f / 3.f);
}
void FadeConfig::setNoiseSpeedZ(float value) {
events[editedCategory].noiseSpeed.z = powf(value, 3.f)*FADE_MAX_SPEED;
emit dirty();
}
float FadeConfig::getNoiseSpeedZ() const {
return powf(events[editedCategory].noiseSpeed.z / FADE_MAX_SPEED, 1.f / 3.f);
}
void FadeConfig::setEdgeWidth(float value) {
events[editedCategory].edgeWidth = value * value;
emit dirty();
}
float FadeConfig::getEdgeWidth() const {
return sqrtf(events[editedCategory].edgeWidth);
}
void FadeConfig::setEdgeInnerColorR(float value) {
events[editedCategory].edgeInnerColor.r = value;
emit dirty();
}
void FadeConfig::setEdgeInnerColorG(float value) {
events[editedCategory].edgeInnerColor.g = value;
emit dirty();
}
void FadeConfig::setEdgeInnerColorB(float value) {
events[editedCategory].edgeInnerColor.b = value;
emit dirty();
}
void FadeConfig::setEdgeInnerIntensity(float value) {
events[editedCategory].edgeInnerColor.a = value;
emit dirty();
}
void FadeConfig::setEdgeOuterColorR(float value) {
events[editedCategory].edgeOuterColor.r = value;
emit dirty();
}
void FadeConfig::setEdgeOuterColorG(float value) {
events[editedCategory].edgeOuterColor.g = value;
emit dirty();
}
void FadeConfig::setEdgeOuterColorB(float value) {
events[editedCategory].edgeOuterColor.b = value;
emit dirty();
}
void FadeConfig::setEdgeOuterIntensity(float value) {
events[editedCategory].edgeOuterColor.a = value;
emit dirty();
}
void FadeConfig::setTiming(int value) {
assert(value < TIMING_COUNT);
events[editedCategory].timing = value;
emit dirty();
}
QString FadeConfig::eventNames[FADE_CATEGORY_COUNT] = {
"element_enter_leave_domain",
"bubble_isect_owner",
"bubble_isect_trespasser",
"user_enter_leave_domain",
"avatar_change",
};
void FadeConfig::save() const {
assert(editedCategory < FADE_CATEGORY_COUNT);
QJsonObject lProperties;
const QString configFile = "config/" + eventNames[editedCategory] + ".json";
QUrl path(PathUtils::resourcesPath() + configFile);
QFile file(path.toString());
if (!file.open(QFile::WriteOnly | QFile::Text)) {
qWarning() << "Fade event configuration file " << path << " cannot be opened";
}
else {
const auto& event = events[editedCategory];
lProperties["edgeInnerColor"] = QJsonArray{ event.edgeInnerColor.r, event.edgeInnerColor.g, event.edgeInnerColor.b, event.edgeInnerColor.a };
lProperties["edgeOuterColor"] = QJsonArray{ event.edgeOuterColor.r, event.edgeOuterColor.g, event.edgeOuterColor.b, event.edgeOuterColor.a };
lProperties["noiseSize"] = QJsonArray{ event.noiseSize.x, event.noiseSize.y, event.noiseSize.z };
lProperties["noiseSpeed"] = QJsonArray{ event.noiseSpeed.x, event.noiseSpeed.y, event.noiseSpeed.z };
lProperties["baseSize"] = QJsonArray{ event.baseSize.x, event.baseSize.y, event.baseSize.z };
lProperties["noiseLevel"] = event.noiseLevel;
lProperties["baseLevel"] = event.baseLevel;
lProperties["duration"] = event.duration;
lProperties["edgeWidth"] = event.edgeWidth;
lProperties["timing"] = event.timing;
lProperties["isInverted"] = event.isInverted;
file.write( QJsonDocument(lProperties).toJson() );
file.close();
}
}
void FadeConfig::load() {
const QString configFile = "config/" + eventNames[editedCategory] + ".json";
QUrl path(PathUtils::resourcesPath() + configFile);
QFile file(path.toString());
if (!file.exists()) {
qWarning() << "Fade event configuration file " << path << " does not exist";
}
else if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "Fade event configuration file " << path << " cannot be opened";
}
else {
QString fileData = file.readAll();
file.close();
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(fileData.toUtf8(), &error);
if (error.error == error.NoError) {
QJsonObject jsonObject = doc.object();
QJsonValue value;
auto& event = events[editedCategory];
qCDebug(renderlogging) << "Fade event configuration file" << path << "loaded";
value = jsonObject["edgeInnerColor"];
if (value.isArray()) {
QJsonArray data = value.toArray();
if (data.size() < 4) {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeInnerColor' field. Expected array of size 4";
}
else {
event.edgeInnerColor.r = (float)data.at(0).toDouble();
event.edgeInnerColor.g = (float)data.at(1).toDouble();
event.edgeInnerColor.b = (float)data.at(2).toDouble();
event.edgeInnerColor.a = (float)data.at(3).toDouble();
}
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeInnerColor' field. Expected array of size 4";
}
value = jsonObject["edgeOuterColor"];
if (value.isArray()) {
QJsonArray data = value.toArray();
if (data.size() < 4) {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeOuterColor' field. Expected array of size 4";
}
else {
event.edgeOuterColor.r = (float)data.at(0).toDouble();
event.edgeOuterColor.g = (float)data.at(1).toDouble();
event.edgeOuterColor.b = (float)data.at(2).toDouble();
event.edgeOuterColor.a = (float)data.at(3).toDouble();
}
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeOuterColor' field. Expected array of size 4";
}
value = jsonObject["noiseSize"];
if (value.isArray()) {
QJsonArray data = value.toArray();
if (data.size() < 3) {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseSize' field. Expected array of size 3";
}
else {
event.noiseSize.x = (float)data.at(0).toDouble();
event.noiseSize.y = (float)data.at(1).toDouble();
event.noiseSize.z = (float)data.at(2).toDouble();
}
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseSize' field. Expected array of size 3";
}
value = jsonObject["noiseSpeed"];
if (value.isArray()) {
QJsonArray data = value.toArray();
if (data.size() < 3) {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseSpeed' field. Expected array of size 3";
}
else {
event.noiseSpeed.x = (float)data.at(0).toDouble();
event.noiseSpeed.y = (float)data.at(1).toDouble();
event.noiseSpeed.z = (float)data.at(2).toDouble();
}
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseSpeed' field. Expected array of size 3";
}
value = jsonObject["baseSize"];
if (value.isArray()) {
QJsonArray data = value.toArray();
if (data.size() < 3) {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'baseSize' field. Expected array of size 3";
}
else {
event.baseSize.x = (float)data.at(0).toDouble();
event.baseSize.y = (float)data.at(1).toDouble();
event.baseSize.z = (float)data.at(2).toDouble();
}
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'baseSize' field. Expected array of size 3";
}
value = jsonObject["noiseLevel"];
if (value.isDouble()) {
event.noiseLevel = (float)value.toDouble();
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'noiseLevel' field. Expected float value";
}
value = jsonObject["baseLevel"];
if (value.isDouble()) {
event.baseLevel = (float)value.toDouble();
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'baseLevel' field. Expected float value";
}
value = jsonObject["duration"];
if (value.isDouble()) {
event.duration = (float)value.toDouble();
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'duration' field. Expected float value";
}
value = jsonObject["edgeWidth"];
if (value.isDouble()) {
event.edgeWidth = std::min(1.f, std::max(0.f, (float)value.toDouble()));
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'edgeWidth' field. Expected float value";
}
value = jsonObject["timing"];
if (value.isDouble()) {
event.timing = std::max(0, std::min(TIMING_COUNT - 1, value.toInt()));
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'timing' field. Expected integer value";
}
value = jsonObject["isInverted"];
if (value.isBool()) {
event.isInverted = value.toBool();
}
else {
qWarning() << "Fade event configuration file " << path << " contains an invalid 'isInverted' field. Expected boolean value";
}
emit dirty();
}
else {
qWarning() << "Fade event configuration file" << path << "failed to load:" <<
error.errorString() << "at offset" << error.offset;
}
}
}
FadeJob::FadeJob() {
_previousTime = usecTimestampNow();
}
void FadeJob::configure(const Config& config) {
auto& configurations = _configurations.edit();
for (auto i = 0; i < FADE_CATEGORY_COUNT; i++) {
auto& eventParameters = configurations.parameters[i];
const auto& eventConfig = config.events[i];
eventParameters._baseLevel = eventConfig.baseLevel;
eventParameters._noiseInvSizeAndLevel.x = 1.f / eventConfig.noiseSize.x;
eventParameters._noiseInvSizeAndLevel.y = 1.f / eventConfig.noiseSize.y;
eventParameters._noiseInvSizeAndLevel.z = 1.f / eventConfig.noiseSize.z;
eventParameters._noiseInvSizeAndLevel.w = eventConfig.noiseLevel;
eventParameters._isInverted = eventConfig.isInverted & 1;
eventParameters._edgeWidthInvWidth.x = eventConfig.edgeWidth;
eventParameters._edgeWidthInvWidth.y = 1.f / eventParameters._edgeWidthInvWidth.x;
eventParameters._innerEdgeColor = eventConfig.edgeInnerColor;
eventParameters._outerEdgeColor = eventConfig.edgeOuterColor;
_thresholdScale[i] = 1.f + (eventParameters._edgeWidthInvWidth.x + std::max(0.f, (eventConfig.noiseLevel + eventConfig.baseLevel)*0.5f - 0.5f));
}
}
void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Output& output) {
Config* jobConfig = static_cast<Config*>(renderContext->jobConfig.get());
auto scene = renderContext->args->_scene;
auto transitionStage = scene->getStage<render::TransitionStage>(render::TransitionStage::getName());
uint64_t now = usecTimestampNow();
const double deltaTime = (int64_t(now) - int64_t(_previousTime)) / double(USECS_PER_SECOND);
render::Transaction transaction;
bool isFirstItem = true;
bool hasTransaction = false;
output = (FadeCategory) jobConfig->editedCategory;
// And now update fade effect
for (auto transitionId : *transitionStage) {
auto& state = transitionStage->editTransition(transitionId);
#ifdef DEBUG
auto& item = scene->getItem(state.itemId);
assert(item.getTransitionId() == transitionId);
#endif
if (update(*jobConfig, scene, transaction, state, deltaTime)) {
hasTransaction = true;
}
if (isFirstItem) {
jobConfig->setProperty("threshold", state.threshold);
isFirstItem = false;
}
}
_previousTime = now;
if (hasTransaction) {
scene->enqueueTransaction(transaction);
}
}
const FadeCategory FadeJob::transitionToCategory[render::Transition::TYPE_COUNT] = {
FADE_ELEMENT_ENTER_LEAVE_DOMAIN,
FADE_ELEMENT_ENTER_LEAVE_DOMAIN,
FADE_BUBBLE_ISECT_OWNER,
FADE_BUBBLE_ISECT_TRESPASSER,
FADE_USER_ENTER_LEAVE_DOMAIN,
FADE_USER_ENTER_LEAVE_DOMAIN,
FADE_AVATAR_CHANGE
};
bool FadeJob::update(const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const {
const auto fadeCategory = transitionToCategory[transition.eventType];
auto& eventConfig = config.events[fadeCategory];
auto item = scene->getItemSafe(transition.itemId);
const double eventDuration = (double)eventConfig.duration;
const FadeConfig::Timing timing = (FadeConfig::Timing) eventConfig.timing;
if (item.exist()) {
auto aabb = item.getBound();
if (render::Item::isValidID(transition.boundItemId)) {
auto boundItem = scene->getItemSafe(transition.boundItemId);
if (boundItem.exist()) {
aabb = boundItem.getBound();
}
}
auto& dimensions = aabb.getDimensions();
assert(timing < FadeConfig::TIMING_COUNT);
transition.noiseOffset = aabb.calcCenter();
transition.baseInvSize.x = 1.f / eventConfig.baseSize.x;
transition.baseInvSize.y = 1.f / eventConfig.baseSize.y;
transition.baseInvSize.z = 1.f / eventConfig.baseSize.z;
switch (transition.eventType) {
case render::Transition::ELEMENT_ENTER_DOMAIN:
case render::Transition::ELEMENT_LEAVE_DOMAIN:
{
transition.threshold = computeElementEnterRatio(transition.time, eventDuration, timing);
transition.baseOffset = transition.noiseOffset;
transition.baseInvSize.x = 1.f / dimensions.x;
transition.baseInvSize.y = 1.f / dimensions.y;
transition.baseInvSize.z = 1.f / dimensions.z;
transition.isFinished += (transition.threshold >= 1.f) & 1;
if (transition.eventType == render::Transition::ELEMENT_ENTER_DOMAIN) {
transition.threshold = 1.f - transition.threshold;
}
}
break;
case render::Transition::BUBBLE_ISECT_OWNER:
{
transition.threshold = 0.5f;
transition.baseOffset = transition.noiseOffset;
}
break;
case render::Transition::BUBBLE_ISECT_TRESPASSER:
{
transition.threshold = 0.5f;
transition.baseOffset = transition.noiseOffset;
}
break;
case render::Transition::USER_ENTER_DOMAIN:
case render::Transition::USER_LEAVE_DOMAIN:
{
transition.threshold = computeElementEnterRatio(transition.time, eventDuration, timing);
transition.baseOffset = transition.noiseOffset - dimensions.y / 2.f;
transition.baseInvSize.y = 1.f / dimensions.y;
transition.isFinished += (transition.threshold >= 1.f) & 1;
if (transition.eventType == render::Transition::USER_LEAVE_DOMAIN) {
transition.threshold = 1.f - transition.threshold;
}
}
break;
case render::Transition::AVATAR_CHANGE:
break;
default:
assert(false);
}
}
transition.noiseOffset += eventConfig.noiseSpeed * (float)transition.time;
if (config.manualFade) {
transition.threshold = config.manualThreshold;
}
transition.threshold = std::max(0.f, std::min(1.f, transition.threshold));
transition.threshold = (transition.threshold - 0.5f)*_thresholdScale[fadeCategory] + 0.5f;
transition.time += deltaTime;
// If the transition is finished for more than a number of frames (here 1), garbage collect it.
if (transition.isFinished > 1) {
transaction.removeTransitionFromItem(transition.itemId);
return true;
}
return false;
}
float FadeJob::computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing) {
assert(period > 0.0);
float fadeAlpha = 1.0f;
const double INV_FADE_PERIOD = 1.0 / period;
double fraction = time * INV_FADE_PERIOD;
fraction = std::max(fraction, 0.0);
if (fraction < 1.0) {
switch (timing) {
default:
fadeAlpha = (float)fraction;
break;
case FadeConfig::EASE_IN:
fadeAlpha = (float)(fraction*fraction*fraction);
break;
case FadeConfig::EASE_OUT:
fadeAlpha = 1.f - (float)fraction;
fadeAlpha = 1.f- fadeAlpha*fadeAlpha*fadeAlpha;
break;
case FadeConfig::EASE_IN_OUT:
fadeAlpha = (float)(fraction*fraction*fraction*(fraction*(fraction * 6 - 15) + 10));
break;
}
}
return fadeAlpha;
}

View file

@ -0,0 +1,248 @@
//
// FadeEffectJobs.h
// Created by Olivier Prat on 07/07/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_render_utils_FadeEffectJobs_h
#define hifi_render_utils_FadeEffectJobs_h
#include "FadeEffect.h"
#include <gpu/Pipeline.h>
#include <render/ShapePipeline.h>
#include <render/RenderFetchCullSortTask.h>
#include <render/Transition.h>
enum FadeCategory {
FADE_ELEMENT_ENTER_LEAVE_DOMAIN = 0,
FADE_BUBBLE_ISECT_OWNER,
FADE_BUBBLE_ISECT_TRESPASSER,
FADE_USER_ENTER_LEAVE_DOMAIN,
FADE_AVATAR_CHANGE,
// Don't forget to modify Fade.slh to reflect the change in number of categories
FADE_CATEGORY_COUNT,
};
class FadeEditConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool editFade MEMBER editFade NOTIFY dirty)
public:
bool editFade{ false };
signals:
void dirty();
};
class FadeConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int editedCategory MEMBER editedCategory WRITE setEditedCategory NOTIFY dirtyCategory)
Q_PROPERTY(float duration READ getDuration WRITE setDuration NOTIFY dirty)
Q_PROPERTY(float baseSizeX READ getBaseSizeX WRITE setBaseSizeX NOTIFY dirty)
Q_PROPERTY(float baseSizeY READ getBaseSizeY WRITE setBaseSizeY NOTIFY dirty)
Q_PROPERTY(float baseSizeZ READ getBaseSizeZ WRITE setBaseSizeZ NOTIFY dirty)
Q_PROPERTY(float baseLevel READ getBaseLevel WRITE setBaseLevel NOTIFY dirty)
Q_PROPERTY(bool _isInverted READ isInverted WRITE setInverted NOTIFY dirty)
Q_PROPERTY(float noiseSizeX READ getNoiseSizeX WRITE setNoiseSizeX NOTIFY dirty)
Q_PROPERTY(float noiseSizeY READ getNoiseSizeY WRITE setNoiseSizeY NOTIFY dirty)
Q_PROPERTY(float noiseSizeZ READ getNoiseSizeZ WRITE setNoiseSizeZ NOTIFY dirty)
Q_PROPERTY(float noiseLevel READ getNoiseLevel WRITE setNoiseLevel NOTIFY dirty)
Q_PROPERTY(float edgeWidth READ getEdgeWidth WRITE setEdgeWidth NOTIFY dirty)
Q_PROPERTY(float edgeInnerColorR READ getEdgeInnerColorR WRITE setEdgeInnerColorR NOTIFY dirty)
Q_PROPERTY(float edgeInnerColorG READ getEdgeInnerColorG WRITE setEdgeInnerColorG NOTIFY dirty)
Q_PROPERTY(float edgeInnerColorB READ getEdgeInnerColorB WRITE setEdgeInnerColorB NOTIFY dirty)
Q_PROPERTY(float edgeInnerIntensity READ getEdgeInnerIntensity WRITE setEdgeInnerIntensity NOTIFY dirty)
Q_PROPERTY(float edgeOuterColorR READ getEdgeOuterColorR WRITE setEdgeOuterColorR NOTIFY dirty)
Q_PROPERTY(float edgeOuterColorG READ getEdgeOuterColorG WRITE setEdgeOuterColorG NOTIFY dirty)
Q_PROPERTY(float edgeOuterColorB READ getEdgeOuterColorB WRITE setEdgeOuterColorB NOTIFY dirty)
Q_PROPERTY(float edgeOuterIntensity READ getEdgeOuterIntensity WRITE setEdgeOuterIntensity NOTIFY dirty)
Q_PROPERTY(int timing READ getTiming WRITE setTiming NOTIFY dirty)
Q_PROPERTY(float noiseSpeedX READ getNoiseSpeedX WRITE setNoiseSpeedX NOTIFY dirty)
Q_PROPERTY(float noiseSpeedY READ getNoiseSpeedY WRITE setNoiseSpeedY NOTIFY dirty)
Q_PROPERTY(float noiseSpeedZ READ getNoiseSpeedZ WRITE setNoiseSpeedZ NOTIFY dirty)
Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty)
Q_PROPERTY(bool manualFade MEMBER manualFade NOTIFY dirty)
Q_PROPERTY(float manualThreshold MEMBER manualThreshold NOTIFY dirty)
public:
enum Timing {
LINEAR,
EASE_IN,
EASE_OUT,
EASE_IN_OUT,
TIMING_COUNT
};
FadeConfig();
void setEditedCategory(int value);
void setDuration(float value);
float getDuration() const;
void setBaseSizeX(float value);
float getBaseSizeX() const;
void setBaseSizeY(float value);
float getBaseSizeY() const;
void setBaseSizeZ(float value);
float getBaseSizeZ() const;
void setBaseLevel(float value);
float getBaseLevel() const { return events[editedCategory].baseLevel; }
void setInverted(bool value);
bool isInverted() const;
void setNoiseSizeX(float value);
float getNoiseSizeX() const;
void setNoiseSizeY(float value);
float getNoiseSizeY() const;
void setNoiseSizeZ(float value);
float getNoiseSizeZ() const;
void setNoiseLevel(float value);
float getNoiseLevel() const { return events[editedCategory].noiseLevel; }
void setNoiseSpeedX(float value);
float getNoiseSpeedX() const;
void setNoiseSpeedY(float value);
float getNoiseSpeedY() const;
void setNoiseSpeedZ(float value);
float getNoiseSpeedZ() const;
void setEdgeWidth(float value);
float getEdgeWidth() const;
void setEdgeInnerColorR(float value);
float getEdgeInnerColorR() const { return events[editedCategory].edgeInnerColor.r; }
void setEdgeInnerColorG(float value);
float getEdgeInnerColorG() const { return events[editedCategory].edgeInnerColor.g; }
void setEdgeInnerColorB(float value);
float getEdgeInnerColorB() const { return events[editedCategory].edgeInnerColor.b; }
void setEdgeInnerIntensity(float value);
float getEdgeInnerIntensity() const { return events[editedCategory].edgeInnerColor.a; }
void setEdgeOuterColorR(float value);
float getEdgeOuterColorR() const { return events[editedCategory].edgeOuterColor.r; }
void setEdgeOuterColorG(float value);
float getEdgeOuterColorG() const { return events[editedCategory].edgeOuterColor.g; }
void setEdgeOuterColorB(float value);
float getEdgeOuterColorB() const { return events[editedCategory].edgeOuterColor.b; }
void setEdgeOuterIntensity(float value);
float getEdgeOuterIntensity() const { return events[editedCategory].edgeOuterColor.a; }
void setTiming(int value);
int getTiming() const { return events[editedCategory].timing; }
struct Event {
glm::vec4 edgeInnerColor;
glm::vec4 edgeOuterColor;
glm::vec3 noiseSize;
glm::vec3 noiseSpeed;
glm::vec3 baseSize;
float noiseLevel;
float baseLevel;
float duration;
float edgeWidth;
int timing;
bool isInverted;
};
Event events[FADE_CATEGORY_COUNT];
int editedCategory{ FADE_ELEMENT_ENTER_LEAVE_DOMAIN };
float threshold{ 0.f };
float manualThreshold{ 0.f };
bool manualFade{ false };
Q_INVOKABLE void save() const;
Q_INVOKABLE void load();
static QString eventNames[FADE_CATEGORY_COUNT];
signals:
void dirty();
void dirtyCategory();
};
class FadeEditJob {
public:
using Config = FadeEditConfig;
using Input = render::VaryingSet2<render::ItemBounds, FadeCategory>;
using JobModel = render::Job::ModelI<FadeEditJob, Input, Config>;
FadeEditJob() {}
void configure(const Config& config);
void run(const render::RenderContextPointer& renderContext, const FadeEditJob::Input& inputs);
private:
bool _isEditEnabled{ false };
render::ItemID _editedItem{ render::Item::INVALID_ITEM_ID };
render::ItemID findNearestItem(const render::RenderContextPointer& renderContext, const render::ItemBounds& inputs, float& minIsectDistance) const;
};
class FadeJob {
public:
static const FadeCategory transitionToCategory[render::Transition::TYPE_COUNT];
using Config = FadeConfig;
using Output = FadeCategory;
using JobModel = render::Job::ModelO<FadeJob, Output, Config>;
FadeJob();
void configure(const Config& config);
void run(const render::RenderContextPointer& renderContext, FadeJob::Output& output);
gpu::BufferView getConfigurationBuffer() const { return _configurations; }
private:
#include "Fade_shared.slh"
struct FadeConfiguration
{
FadeParameters parameters[FADE_CATEGORY_COUNT];
};
using FadeConfigurationBuffer = gpu::StructBuffer<FadeConfiguration>;
FadeConfigurationBuffer _configurations;
float _thresholdScale[FADE_CATEGORY_COUNT];
uint64_t _previousTime{ 0 };
bool update(const Config& config, const render::ScenePointer& scene, render::Transaction& transaction, render::Transition& transition, const double deltaTime) const;
static float computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing);
};
#endif // hifi_render_utils_FadeEffectJobs_h

View file

@ -0,0 +1,27 @@
// glsl / C++ compatible source as interface for FadeEffect
#ifdef __cplusplus
# define VEC4 glm::vec4
# define VEC2 glm::vec2
# define FLOAT32 glm::float32
# define INT32 glm::int32
#else
# define VEC4 vec4
# define VEC2 vec2
# define FLOAT32 float
# define INT32 int
#endif
struct FadeParameters
{
VEC4 _noiseInvSizeAndLevel;
VEC4 _innerEdgeColor;
VEC4 _outerEdgeColor;
VEC2 _edgeWidthInvWidth;
FLOAT32 _baseLevel;
INT32 _isInverted;
};
// <@if 1@>
// Trigger Scribe include
// <@endif@> <!def that !>
//

View file

@ -25,6 +25,7 @@
#include "TextureCache.h"
#include "RenderUtilsLogging.h"
#include "StencilMaskPass.h"
#include "FadeEffect.h"
#include "gpu/StandardShaderLib.h"
@ -37,6 +38,9 @@
#include "simple_vert.h"
#include "simple_textured_frag.h"
#include "simple_textured_unlit_frag.h"
#include "simple_fade_vert.h"
#include "simple_textured_fade_frag.h"
#include "simple_textured_unlit_fade_frag.h"
#include "simple_opaque_web_browser_frag.h"
#include "simple_opaque_web_browser_overlay_frag.h"
#include "simple_transparent_web_browser_frag.h"
@ -56,9 +60,11 @@ static const int VERTICES_PER_TRIANGLE = 3;
static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA };
static const gpu::Element TEXCOORD4_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::XYZW };
static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT;
static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT;
static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
@ -447,34 +453,64 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() {
return INSTANCED_SOLID_STREAM_FORMAT;
}
gpu::Stream::FormatPointer& getInstancedSolidFadeStreamFormat() {
if (!INSTANCED_SOLID_FADE_STREAM_FORMAT) {
INSTANCED_SOLID_FADE_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD2, gpu::Stream::TEXCOORD2, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD3, gpu::Stream::TEXCOORD3, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD4, gpu::Stream::TEXCOORD4, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
}
return INSTANCED_SOLID_FADE_STREAM_FORMAT;
}
QHash<SimpleProgramKey, gpu::PipelinePointer> GeometryCache::_simplePrograms;
gpu::ShaderPointer GeometryCache::_simpleShader;
gpu::ShaderPointer GeometryCache::_unlitShader;
gpu::ShaderPointer GeometryCache::_simpleFadeShader;
gpu::ShaderPointer GeometryCache::_unlitFadeShader;
render::ShapePipelinePointer GeometryCache::_simpleOpaquePipeline;
render::ShapePipelinePointer GeometryCache::_simpleTransparentPipeline;
render::ShapePipelinePointer GeometryCache::_simpleOpaqueFadePipeline;
render::ShapePipelinePointer GeometryCache::_simpleTransparentFadePipeline;
render::ShapePipelinePointer GeometryCache::_simpleWirePipeline;
uint8_t GeometryCache::CUSTOM_PIPELINE_NUMBER = 0;
render::ShapePipelinePointer GeometryCache::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) {
initializeShapePipelines();
if (key.isWireframe()) {
return _simpleWirePipeline;
}
if (key.isFaded()) {
if (key.isTranslucent()) {
return _simpleTransparentFadePipeline;
}
else {
return _simpleOpaqueFadePipeline;
}
}
else {
if (key.isTranslucent()) {
return _simpleTransparentPipeline;
}
else {
return _simpleOpaquePipeline;
}
}
}
GeometryCache::GeometryCache() :
_nextID(0) {
// Let's register its special shapePipeline factory:
registerShapePipeline();
buildShapes();
GeometryCache::_simpleOpaquePipeline =
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, false), nullptr,
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {
// Set the defaults needed for a simple program
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
DependencyManager::get<TextureCache>()->getWhiteTexture());
},
nullptr
);
GeometryCache::_simpleTransparentPipeline =
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, true, true, false), nullptr,
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {
// Set the defaults needed for a simple program
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
DependencyManager::get<TextureCache>()->getWhiteTexture());
},
nullptr
);
GeometryCache::_simpleWirePipeline =
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, true), nullptr,
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {}, nullptr);
}
GeometryCache::~GeometryCache() {
@ -514,9 +550,46 @@ void GeometryCache::releaseID(int id) {
_registeredGridBuffers.remove(id);
}
void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer) {
gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT);
batch.setInputBuffer(gpu::Stream::COLOR, colorView);
void GeometryCache::initializeShapePipelines() {
if (!_simpleOpaquePipeline) {
_simpleOpaquePipeline = getShapePipeline(false, false, true, false);
_simpleTransparentPipeline = getShapePipeline(false, true, true, false);
_simpleOpaqueFadePipeline = getFadingShapePipeline(false, false, false, false, false);
_simpleTransparentFadePipeline = getFadingShapePipeline(false, true, false, false, false);
_simpleWirePipeline = getShapePipeline(false, false, true, true);
}
}
render::ShapePipelinePointer GeometryCache::getShapePipeline(bool textured, bool transparent, bool culled,
bool unlit, bool depthBias) {
return std::make_shared<render::ShapePipeline>(getSimplePipeline(textured, transparent, culled, unlit, depthBias, false), nullptr,
[](const render::ShapePipeline& , gpu::Batch& batch, render::Args*) {
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, DependencyManager::get<TextureCache>()->getWhiteTexture());
}
);
}
render::ShapePipelinePointer GeometryCache::getFadingShapePipeline(bool textured, bool transparent, bool culled,
bool unlit, bool depthBias) {
auto fadeEffect = DependencyManager::get<FadeEffect>();
auto fadeBatchSetter = fadeEffect->getBatchSetter();
auto fadeItemSetter = fadeEffect->getItemStoredSetter();
return std::make_shared<render::ShapePipeline>(getSimplePipeline(textured, transparent, culled, unlit, depthBias, true), nullptr,
[fadeBatchSetter, fadeItemSetter](const render::ShapePipeline& shapePipeline, gpu::Batch& batch, render::Args* args) {
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO, DependencyManager::get<TextureCache>()->getWhiteTexture());
fadeBatchSetter(shapePipeline, batch, args);
},
fadeItemSetter
);
}
render::ShapePipelinePointer GeometryCache::getOpaqueShapePipeline(bool isFading) {
return isFading ? _simpleOpaqueFadePipeline : _simpleOpaquePipeline;
}
render::ShapePipelinePointer GeometryCache::getTransparentShapePipeline(bool isFading) {
return isFading ? _simpleTransparentFadePipeline : _simpleTransparentPipeline;
}
void GeometryCache::renderShape(gpu::Batch& batch, Shape shape) {
@ -529,6 +602,11 @@ void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape) {
_shapes[shape].drawWire(batch);
}
void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer) {
gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT);
batch.setInputBuffer(gpu::Stream::COLOR, colorView);
}
void GeometryCache::renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer) {
batch.setInputFormat(getInstancedSolidStreamFormat());
setupBatchInstance(batch, colorBuffer);
@ -541,6 +619,32 @@ void GeometryCache::renderWireShapeInstances(gpu::Batch& batch, Shape shape, siz
_shapes[shape].drawWireInstances(batch, count);
}
void setupBatchFadeInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer,
gpu::BufferPointer fadeBuffer1, gpu::BufferPointer fadeBuffer2, gpu::BufferPointer fadeBuffer3) {
gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT);
gpu::BufferView texCoord2View(fadeBuffer1, TEXCOORD4_ELEMENT);
gpu::BufferView texCoord3View(fadeBuffer2, TEXCOORD4_ELEMENT);
gpu::BufferView texCoord4View(fadeBuffer3, TEXCOORD4_ELEMENT);
batch.setInputBuffer(gpu::Stream::COLOR, colorView);
batch.setInputBuffer(gpu::Stream::TEXCOORD2, texCoord2View);
batch.setInputBuffer(gpu::Stream::TEXCOORD3, texCoord3View);
batch.setInputBuffer(gpu::Stream::TEXCOORD4, texCoord4View);
}
void GeometryCache::renderFadeShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer,
gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3) {
batch.setInputFormat(getInstancedSolidFadeStreamFormat());
setupBatchFadeInstance(batch, colorBuffer, fadeBuffer1, fadeBuffer2, fadeBuffer3);
_shapes[shape].drawInstances(batch, count);
}
void GeometryCache::renderWireFadeShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer,
gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3) {
batch.setInputFormat(getInstancedSolidFadeStreamFormat());
setupBatchFadeInstance(batch, colorBuffer, fadeBuffer1, fadeBuffer2, fadeBuffer3);
_shapes[shape].drawWireInstances(batch, count);
}
void GeometryCache::renderCube(gpu::Batch& batch) {
renderShape(batch, Cube);
}
@ -1770,6 +1874,7 @@ public:
IS_CULLED_FLAG,
IS_UNLIT_FLAG,
HAS_DEPTH_BIAS_FLAG,
IS_FADING_FLAG,
NUM_FLAGS,
};
@ -1780,6 +1885,7 @@ public:
IS_CULLED = (1 << IS_CULLED_FLAG),
IS_UNLIT = (1 << IS_UNLIT_FLAG),
HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG),
IS_FADING = (1 << IS_FADING_FLAG),
};
typedef unsigned short Flags;
@ -1790,6 +1896,7 @@ public:
bool isCulled() const { return isFlag(IS_CULLED); }
bool isUnlit() const { return isFlag(IS_UNLIT); }
bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); }
bool isFading() const { return isFlag(IS_FADING); }
Flags _flags = 0;
short _spare = 0;
@ -1798,9 +1905,9 @@ public:
SimpleProgramKey(bool textured = false, bool transparent = false, bool culled = true,
bool unlit = false, bool depthBias = false) {
bool unlit = false, bool depthBias = false, bool fading = false) {
_flags = (textured ? IS_TEXTURED : 0) | (transparent ? IS_TRANSPARENT : 0) | (culled ? IS_CULLED : 0) |
(unlit ? IS_UNLIT : 0) | (depthBias ? HAS_DEPTH_BIAS : 0);
(unlit ? IS_UNLIT : 0) | (depthBias ? HAS_DEPTH_BIAS : 0) | (fading ? IS_FADING : 0);
}
SimpleProgramKey(int bitmask) : _flags(bitmask) {}
@ -1879,23 +1986,8 @@ void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool tra
}
}
gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transparent, bool culled, bool unlit, bool depthBiased) {
SimpleProgramKey config { textured, transparent, culled, unlit, depthBiased };
// Compile the shaders
static std::once_flag once;
std::call_once(once, [&]() {
auto VS = gpu::Shader::createVertex(std::string(simple_vert));
auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag));
auto PSUnlit = gpu::Shader::createPixel(std::string(simple_textured_unlit_frag));
_simpleShader = gpu::Shader::createProgram(VS, PS);
_unlitShader = gpu::Shader::createProgram(VS, PSUnlit);
gpu::Shader::BindingSet slotBindings;
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
gpu::Shader::makeProgram(*_unlitShader, slotBindings);
});
gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transparent, bool culled, bool unlit, bool depthBiased, bool fading) {
SimpleProgramKey config { textured, transparent, culled, unlit, depthBiased, fading };
// If the pipeline already exists, return it
auto it = _simplePrograms.find(config);
@ -1903,6 +1995,40 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp
return it.value();
}
// Compile the shaders
if (!fading) {
static std::once_flag once;
std::call_once(once, [&]() {
auto VS = gpu::Shader::createVertex(std::string(simple_vert));
auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag));
auto PSUnlit = gpu::Shader::createPixel(std::string(simple_textured_unlit_frag));
_simpleShader = gpu::Shader::createProgram(VS, PS);
_unlitShader = gpu::Shader::createProgram(VS, PSUnlit);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("originalTexture"), render::ShapePipeline::Slot::MAP::ALBEDO));
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
gpu::Shader::makeProgram(*_unlitShader, slotBindings);
});
} else {
static std::once_flag once;
std::call_once(once, [&]() {
auto VS = gpu::Shader::createVertex(std::string(simple_fade_vert));
auto PS = gpu::Shader::createPixel(std::string(simple_textured_fade_frag));
auto PSUnlit = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag));
_simpleFadeShader = gpu::Shader::createProgram(VS, PS);
_unlitFadeShader = gpu::Shader::createProgram(VS, PSUnlit);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("originalTexture"), render::ShapePipeline::Slot::MAP::ALBEDO));
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), render::ShapePipeline::Slot::MAP::FADE_MASK));
gpu::Shader::makeProgram(*_simpleFadeShader, slotBindings);
gpu::Shader::makeProgram(*_unlitFadeShader, slotBindings);
});
}
// If the pipeline did not exist, make it
auto state = std::make_shared<gpu::State>();
if (config.isCulled()) {
@ -1921,11 +2047,12 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp
if (config.isTransparent()) {
PrepareStencil::testMask(*state);
} else {
}
else {
PrepareStencil::testMaskDrawShape(*state);
}
gpu::ShaderPointer program = (config.isUnlit()) ? _unlitShader : _simpleShader;
gpu::ShaderPointer program = (config.isUnlit()) ? (config.isFading() ? _unlitFadeShader : _unlitShader) : (config.isFading() ? _simpleFadeShader : _simpleShader);
gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state);
_simplePrograms.insert(config, pipeline);
return pipeline;
@ -1960,26 +2087,93 @@ void renderInstances(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color
if (isWire) {
DependencyManager::get<GeometryCache>()->renderWireShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]);
} else {
}
else {
DependencyManager::get<GeometryCache>()->renderShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]);
}
});
}
static const size_t INSTANCE_FADE_BUFFER1 = 1;
static const size_t INSTANCE_FADE_BUFFER2 = 2;
static const size_t INSTANCE_FADE_BUFFER3 = 3;
void renderFadeInstances(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, int fadeCategory, float fadeThreshold,
const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize, bool isWire,
const render::ShapePipelinePointer& pipeline, GeometryCache::Shape shape) {
// Add pipeline to name
std::string instanceName = (isWire ? "wire_shapes_" : "solid_shapes_") + std::to_string(shape) + "_" + std::to_string(std::hash<render::ShapePipelinePointer>()(pipeline));
// Add color to named buffer
{
gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(instanceName, INSTANCE_COLOR_BUFFER);
auto compactColor = toCompactColor(color);
instanceColorBuffer->append(compactColor);
}
// Add fade parameters to named buffers
{
gpu::BufferPointer fadeBuffer1 = batch.getNamedBuffer(instanceName, INSTANCE_FADE_BUFFER1);
gpu::BufferPointer fadeBuffer2 = batch.getNamedBuffer(instanceName, INSTANCE_FADE_BUFFER2);
gpu::BufferPointer fadeBuffer3 = batch.getNamedBuffer(instanceName, INSTANCE_FADE_BUFFER3);
// Pack parameters in 3 vec4s
glm::vec4 fadeData1;
glm::vec4 fadeData2;
glm::vec4 fadeData3;
FadeEffect::packToAttributes(fadeCategory, fadeThreshold, fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize,
fadeData1, fadeData2, fadeData3);
fadeBuffer1->append(fadeData1);
fadeBuffer2->append(fadeData2);
fadeBuffer3->append(fadeData3);
}
// Add call to named buffer
batch.setupNamedCalls(instanceName, [args, isWire, pipeline, shape](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
auto& buffers = data.buffers;
batch.setPipeline(pipeline->pipeline);
pipeline->prepare(batch, args);
if (isWire) {
DependencyManager::get<GeometryCache>()->renderWireFadeShapeInstances(batch, shape, data.count(),
buffers[INSTANCE_COLOR_BUFFER], buffers[INSTANCE_FADE_BUFFER1], buffers[INSTANCE_FADE_BUFFER2], buffers[INSTANCE_FADE_BUFFER3]);
}
else {
DependencyManager::get<GeometryCache>()->renderFadeShapeInstances(batch, shape, data.count(),
buffers[INSTANCE_COLOR_BUFFER], buffers[INSTANCE_FADE_BUFFER1], buffers[INSTANCE_FADE_BUFFER2], buffers[INSTANCE_FADE_BUFFER3]);
}
});
}
void GeometryCache::renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
assert(pipeline != nullptr);
renderInstances(args, batch, color, false, pipeline, shape);
}
void GeometryCache::renderWireShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
assert(pipeline != nullptr);
renderInstances(args, batch, color, true, pipeline, shape);
}
void GeometryCache::renderSolidFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color,
int fadeCategory, float fadeThreshold, const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
const render::ShapePipelinePointer& pipeline) {
assert(pipeline != nullptr);
renderFadeInstances(args, batch, color, fadeCategory, fadeThreshold, fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, false, pipeline, shape);
}
void GeometryCache::renderWireFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, GeometryCache::Shape shape, const glm::vec4& color,
int fadeCategory, float fadeThreshold, const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
const render::ShapePipelinePointer& pipeline) {
assert(pipeline != nullptr);
renderFadeInstances(args, batch, color, fadeCategory, fadeThreshold, fadeNoiseOffset, fadeBaseOffset, fadeBaseInvSize, true, pipeline, shape);
}
void GeometryCache::renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
assert(pipeline != nullptr);
renderInstances(args, batch, color, false, pipeline, GeometryCache::Sphere);
}
void GeometryCache::renderWireSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
assert(pipeline != nullptr);
renderInstances(args, batch, color, true, pipeline, GeometryCache::Sphere);
}
@ -1987,7 +2181,9 @@ void GeometryCache::renderWireSphereInstance(RenderArgs* args, gpu::Batch& batch
// available shape types, both solid and wireframes
//#define DEBUG_SHAPES
void GeometryCache::renderSolidCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
assert(pipeline != nullptr);
#ifdef DEBUG_SHAPES
static auto startTime = usecTimestampNow();
renderInstances(INSTANCE_NAME, batch, color, pipeline, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {
@ -2027,5 +2223,6 @@ void GeometryCache::renderSolidCubeInstance(RenderArgs* args, gpu::Batch& batch,
void GeometryCache::renderWireCubeInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) {
static const std::string INSTANCE_NAME = __FUNCTION__;
assert(pipeline != nullptr);
renderInstances(args, batch, color, true, pipeline, GeometryCache::Cube);
}

View file

@ -147,6 +147,14 @@ public:
NUM_SHAPES,
};
static uint8_t CUSTOM_PIPELINE_NUMBER;
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key);
static void registerShapePipeline() {
if (!CUSTOM_PIPELINE_NUMBER) {
CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(shapePipelineFactory);
}
}
int allocateID() { return _nextID++; }
void releaseID(int id);
static const int UNKNOWN_ID;
@ -155,8 +163,8 @@ public:
void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool transparent = false, bool culled = true,
bool unlit = false, bool depthBias = false);
// Get the pipeline to render static geometry
gpu::PipelinePointer getSimplePipeline(bool textured = false, bool transparent = false, bool culled = true,
bool unlit = false, bool depthBias = false);
static gpu::PipelinePointer getSimplePipeline(bool textured = false, bool transparent = false, bool culled = true,
bool unlit = false, bool depthBias = false, bool fading = false);
void bindOpaqueWebBrowserProgram(gpu::Batch& batch, bool isAA);
gpu::PipelinePointer getOpaqueWebBrowserProgram(bool isAA);
@ -164,14 +172,26 @@ public:
void bindTransparentWebBrowserProgram(gpu::Batch& batch, bool isAA);
gpu::PipelinePointer getTransparentWebBrowserProgram(bool isAA);
render::ShapePipelinePointer getOpaqueShapePipeline() { return GeometryCache::_simpleOpaquePipeline; }
render::ShapePipelinePointer getTransparentShapePipeline() { return GeometryCache::_simpleTransparentPipeline; }
render::ShapePipelinePointer getWireShapePipeline() { return GeometryCache::_simpleWirePipeline; }
static void initializeShapePipelines();
render::ShapePipelinePointer getOpaqueShapePipeline() { assert(_simpleOpaquePipeline != nullptr); return _simpleOpaquePipeline; }
render::ShapePipelinePointer getTransparentShapePipeline() { assert(_simpleTransparentPipeline != nullptr); return _simpleTransparentPipeline; }
render::ShapePipelinePointer getOpaqueFadeShapePipeline() { assert(_simpleOpaqueFadePipeline != nullptr); return _simpleOpaqueFadePipeline; }
render::ShapePipelinePointer getTransparentFadeShapePipeline() { assert(_simpleTransparentFadePipeline != nullptr); return _simpleTransparentFadePipeline; }
render::ShapePipelinePointer getOpaqueShapePipeline(bool isFading);
render::ShapePipelinePointer getTransparentShapePipeline(bool isFading);
render::ShapePipelinePointer getWireShapePipeline() { assert(_simpleWirePipeline != nullptr); return GeometryCache::_simpleWirePipeline; }
// Static (instanced) geometry
void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
void renderFadeShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer,
gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3);
void renderWireFadeShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer,
gpu::BufferPointer& fadeBuffer1, gpu::BufferPointer& fadeBuffer2, gpu::BufferPointer& fadeBuffer3);
void renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color = glm::vec4(1),
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
void renderSolidShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec3& color,
@ -186,6 +206,13 @@ public:
renderWireShapeInstance(args, batch, shape, glm::vec4(color, 1.0f), pipeline);
}
void renderSolidFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color, int fadeCategory, float fadeThreshold,
const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
const render::ShapePipelinePointer& pipeline);
void renderWireFadeShapeInstance(RenderArgs* args, gpu::Batch& batch, Shape shape, const glm::vec4& color, int fadeCategory, float fadeThreshold,
const glm::vec3& fadeNoiseOffset, const glm::vec3& fadeBaseOffset, const glm::vec3& fadeBaseInvSize,
const render::ShapePipelinePointer& pipeline);
void renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec4& color,
const render::ShapePipelinePointer& pipeline = _simpleOpaquePipeline);
void renderSolidSphereInstance(RenderArgs* args, gpu::Batch& batch, const glm::vec3& color,
@ -416,15 +443,20 @@ private:
QHash<int, Vec2FloatPairPair> _lastRegisteredGridBuffer;
QHash<int, GridBuffer> _registeredGridBuffers;
gpu::ShaderPointer _simpleShader;
gpu::ShaderPointer _unlitShader;
static gpu::ShaderPointer _simpleShader;
static gpu::ShaderPointer _unlitShader;
static gpu::ShaderPointer _simpleFadeShader;
static gpu::ShaderPointer _unlitFadeShader;
static render::ShapePipelinePointer _simpleOpaquePipeline;
static render::ShapePipelinePointer _simpleTransparentPipeline;
static render::ShapePipelinePointer _simpleOpaqueFadePipeline;
static render::ShapePipelinePointer _simpleTransparentFadePipeline;
static render::ShapePipelinePointer _simpleOpaqueOverlayPipeline;
static render::ShapePipelinePointer _simpleTransparentOverlayPipeline;
static render::ShapePipelinePointer _simpleWirePipeline;
gpu::PipelinePointer _glowLinePipeline;
QHash<SimpleProgramKey, gpu::PipelinePointer> _simplePrograms;
static QHash<SimpleProgramKey, gpu::PipelinePointer> _simplePrograms;
gpu::ShaderPointer _simpleOpaqueWebBrowserShader;
gpu::PipelinePointer _simpleOpaqueWebBrowserPipeline;
@ -435,6 +467,11 @@ private:
gpu::PipelinePointer _simpleOpaqueWebBrowserOverlayPipeline;
gpu::ShaderPointer _simpleTransparentWebBrowserOverlayShader;
gpu::PipelinePointer _simpleTransparentWebBrowserOverlayPipeline;
static render::ShapePipelinePointer getShapePipeline(bool textured = false, bool transparent = false, bool culled = true,
bool unlit = false, bool depthBias = false);
static render::ShapePipelinePointer getFadingShapePipeline(bool textured = false, bool transparent = false, bool culled = true,
bool unlit = false, bool depthBias = false);
};
#endif // hifi_GeometryCache_h

View file

@ -318,6 +318,7 @@ template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer&
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
}
}
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
@ -327,6 +328,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int _meshIndex, i
assert(model && model->isLoaded());
_model = model;
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
updateMeshPart(modelMesh, partIndex);
updateTransform(transform, offsetTransform);
@ -390,10 +392,6 @@ ItemKey ModelMeshPartPayload::getKey() const {
builder.withTransparent();
}
}
if (_fadeState != FADE_COMPLETE) {
builder.withTransparent();
}
}
return builder.build();
}
@ -465,7 +463,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const {
ShapeKey::Builder builder;
builder.withMaterial();
if (isTranslucent || _fadeState != FADE_COMPLETE) {
if (isTranslucent) {
builder.withTranslucent();
}
if (hasTangents) {
@ -510,9 +508,8 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
}
}
if (_fadeState != FADE_COMPLETE) {
batch._glColor4f(1.0f, 1.0f, 1.0f, computeFadeAlpha());
} else if (!_hasColorAttrib) {
// TODO: Get rid of that extra call
if (!_hasColorAttrib) {
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
}
@ -525,45 +522,17 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline:
batch.setModelTransform(_transform);
}
float ModelMeshPartPayload::computeFadeAlpha() {
if (_fadeState == FADE_WAITING_TO_START) {
return 0.0f;
}
float fadeAlpha = 1.0f;
const float INV_FADE_PERIOD = 1.0f / (float)(1 * USECS_PER_SECOND);
float fraction = (float)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD;
if (fraction < 1.0f) {
fadeAlpha = Interpolate::simpleNonLinearBlend(fraction);
}
if (fadeAlpha >= 1.0f) {
_fadeState = FADE_COMPLETE;
// when fade-in completes we flag model for one last "render item update"
ModelPointer model = _model.lock();
if (model) {
model->setRenderItemsNeedUpdate();
}
return 1.0f;
}
return Interpolate::simpleNonLinearBlend(fadeAlpha);
}
void ModelMeshPartPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
ModelPointer model = _model.lock();
if (!model || !model->addedToScene() || !model->isVisible()) {
if (!model || !model->isAddedToScene() || !model->isVisible()) {
return; // bail asap
}
if (_fadeState == FADE_WAITING_TO_START) {
if (_state == WAITING_TO_START) {
if (model->isLoaded()) {
// FIXME as far as I can tell this is the ONLY reason render-util depends on entities.
if (EntityItem::getEntitiesShouldFadeFunction()()) {
_fadeStartTime = usecTimestampNow();
_fadeState = FADE_IN_PROGRESS;
} else {
_fadeState = FADE_COMPLETE;
}
_state = STARTED;
model->setRenderItemsNeedUpdate();
} else {
return;

View file

@ -23,10 +23,6 @@
#include "Model.h"
const uint8_t FADE_WAITING_TO_START = 0;
const uint8_t FADE_IN_PROGRESS = 1;
const uint8_t FADE_COMPLETE = 2;
class Model;
class MeshPartPayload {
@ -95,8 +91,6 @@ public:
const Transform& boundTransform,
const gpu::BufferPointer& buffer);
float computeFadeAlpha();
// Render Item interface
render::ItemKey getKey() const override;
int getLayer() const;
@ -122,8 +116,13 @@ public:
bool _materialNeedsUpdate { true };
private:
quint64 _fadeStartTime { 0 };
uint8_t _fadeState { FADE_WAITING_TO_START };
enum State : uint8_t {
WAITING_TO_START = 0,
STARTED = 1,
};
mutable State _state { WAITING_TO_START } ;
};
namespace render {

View file

@ -116,6 +116,7 @@ public:
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); }
bool isAddedToScene() const { return _addedToScene; }
void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
bool isWireframe() const { return _isWireframe; }
@ -267,7 +268,6 @@ signals:
void setCollisionModelURLFinished(bool success);
protected:
bool addedToScene() const { return _addedToScene; }
void setBlendshapeCoefficients(const QVector<float>& coefficients) { _blendshapeCoefficients = coefficients; }
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }

View file

@ -34,6 +34,7 @@
#include "FramebufferCache.h"
#include "TextureCache.h"
#include "ZoneRenderer.h"
#include "FadeEffect.h"
#include "AmbientOcclusionEffect.h"
#include "AntialiasingEffect.h"
@ -45,24 +46,35 @@
using namespace render;
extern void initOverlay3DPipelines(render::ShapePlumber& plumber);
extern void initDeferredPipelines(render::ShapePlumber& plumber);
extern void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter);
RenderDeferredTask::RenderDeferredTask() {
DependencyManager::set<FadeEffect>();
}
void RenderDeferredTask::configure(const Config& config)
{
}
void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) {
auto items = input.get<Input>();
const auto& items = input.get<Input>();
auto fadeEffect = DependencyManager::get<FadeEffect>();
// Prepare the ShapePipelines
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
initDeferredPipelines(*shapePlumber);
initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
// Extract opaques / transparents / lights / metas / overlays / background
const auto opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE];
const auto transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
const auto lights = items[RenderFetchCullSortTask::LIGHT];
const auto metas = items[RenderFetchCullSortTask::META];
const auto overlayOpaques = items[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE];
const auto overlayTransparents = items[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE];
const auto background = items[RenderFetchCullSortTask::BACKGROUND];
const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION];
const auto& opaques = items.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE];
const auto& transparents = items.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
const auto& lights = items.get0()[RenderFetchCullSortTask::LIGHT];
const auto& metas = items.get0()[RenderFetchCullSortTask::META];
const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE];
const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE];
//const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND];
const auto& spatialSelection = items[1];
fadeEffect->build(task, opaques);
// Filter the non antialiaased overlays
const int LAYER_NO_AA = 3;
@ -77,7 +89,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto opaqueRangeTimer = task.addJob<BeginGPURangeTimer>("BeginOpaqueRangeTimer", "DrawOpaques");
const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).hasVarying();
const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).asVarying();
const auto prepareDeferredOutputs = task.addJob<PrepareDeferred>("PrepareDeferred", prepareDeferredInputs);
const auto deferredFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(0);
const auto lightingFramebuffer = prepareDeferredOutputs.getN<PrepareDeferred::Outputs>(1);
@ -86,7 +98,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<PrepareStencil>("PrepareStencil", primaryFramebuffer);
// Render opaque objects in DeferredBuffer
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying();
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).asVarying();
task.addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaqueInputs, shapePlumber);
task.addJob<EndGPURangeTimer>("OpaqueRangeTimer", opaqueRangeTimer);
@ -95,12 +107,12 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
// Opaque all rendered
// Linear Depth Pass
const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).hasVarying();
const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).asVarying();
const auto linearDepthPassOutputs = task.addJob<LinearDepthPass>("LinearDepth", linearDepthPassInputs);
const auto linearDepthTarget = linearDepthPassOutputs.getN<LinearDepthPass::Outputs>(0);
// Curvature pass
const auto surfaceGeometryPassInputs = SurfaceGeometryPass::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying();
const auto surfaceGeometryPassInputs = SurfaceGeometryPass::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).asVarying();
const auto surfaceGeometryPassOutputs = task.addJob<SurfaceGeometryPass>("SurfaceGeometry", surfaceGeometryPassInputs);
const auto surfaceGeometryFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(0);
const auto curvatureFramebuffer = surfaceGeometryPassOutputs.getN<SurfaceGeometryPass::Outputs>(1);
@ -111,7 +123,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto scatteringResource = task.addJob<SubsurfaceScattering>("Scattering");
// AO job
const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying();
const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).asVarying();
const auto ambientOcclusionOutputs = task.addJob<AmbientOcclusionEffect>("AmbientOcclusion", ambientOcclusionInputs);
const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Outputs>(0);
const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN<AmbientOcclusionEffect::Outputs>(1);
@ -125,13 +137,13 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
// Light Clustering
// Create the cluster grid of lights, cpu job for now
const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).hasVarying();
const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).asVarying();
const auto lightClusters = task.addJob<LightClusteringPass>("LightClustering", lightClusteringPassInputs);
// DeferredBuffer is complete, now let's shade it into the LightingBuffer
const auto deferredLightingInputs = RenderDeferred::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel,
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource, lightClusters).hasVarying();
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource, lightClusters).asVarying();
task.addJob<RenderDeferred>("RenderDeferred", deferredLightingInputs);
@ -139,12 +151,12 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<DrawBackgroundStage>("DrawBackgroundDeferred", lightingModel);
// Render transparent objects forward in LightingBuffer
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying();
const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying();
task.addJob<DrawDeferred>("DrawTransparentDeferred", transparentsInputs, shapePlumber);
// LIght Cluster Grid Debuging job
{
const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).hasVarying();
const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).asVarying();
task.addJob<DebugLightClusters>("DebugLightClusters", debugLightClustersInputs);
}
@ -164,8 +176,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
}
// Overlays
const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).hasVarying();
const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).hasVarying();
const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).asVarying();
const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).asVarying();
task.addJob<DrawOverlay3D>("DrawOverlay3DOpaque", overlayOpaquesInputs, true);
task.addJob<DrawOverlay3D>("DrawOverlay3DTransparent", overlayTransparentsInputs, false);
@ -181,10 +193,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
const auto debugSubsurfaceScatteringInputs = DebugSubsurfaceScattering::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel,
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying();
surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).asVarying();
task.addJob<DebugSubsurfaceScattering>("DebugScattering", debugSubsurfaceScatteringInputs);
const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying();
const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).asVarying();
task.addJob<DebugAmbientOcclusion>("DebugAmbientOcclusion", debugAmbientOcclusionInputs);
// Scene Octree Debugging job
@ -209,7 +221,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<Antialiasing>("Antialiasing", primaryFramebuffer);
// Draw 2DWeb non AA
const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).hasVarying();
const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).asVarying();
task.addJob<DrawOverlay3D>("Draw2DWebSurfaces", nonAAOverlaysInputs, false);
task.addJob<EndGPURangeTimer>("ToneAndPostRangeTimer", toneAndPostRangeTimer);
@ -269,6 +281,7 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs&
if (lightingModel->isWireframeEnabled()) {
keyBuilder.withWireframe();
}
ShapeKey globalKey = keyBuilder.build();
args->_globalShapeKey = globalKey._flags.to_ulong();
@ -310,11 +323,12 @@ void DrawStateSortDeferred::run(const RenderContextPointer& renderContext, const
// Setup lighting model for all items;
batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer());
// From the lighting model define a global shapKey ORED with individiual keys
// From the lighting model define a global shapeKey ORED with individiual keys
ShapeKey::Builder keyBuilder;
if (lightingModel->isWireframeEnabled()) {
keyBuilder.withWireframe();
}
ShapeKey globalKey = keyBuilder.build();
args->_globalShapeKey = globalKey._flags.to_ulong();

View file

@ -44,12 +44,11 @@ public:
protected:
};
class DrawConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY newStats)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
public:
int getNumDrawn() { return _numDrawn; }
@ -163,14 +162,34 @@ public:
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer);
};
class RenderDeferredTaskConfig : public render::Task::Config {
Q_OBJECT
Q_PROPERTY(float fadeScale MEMBER fadeScale NOTIFY dirty)
Q_PROPERTY(float fadeDuration MEMBER fadeDuration NOTIFY dirty)
Q_PROPERTY(bool debugFade MEMBER debugFade NOTIFY dirty)
Q_PROPERTY(float debugFadePercent MEMBER debugFadePercent NOTIFY dirty)
public:
float fadeScale{ 0.5f };
float fadeDuration{ 3.0f };
float debugFadePercent{ 0.f };
bool debugFade{ false };
signals:
void dirty();
};
class RenderDeferredTask {
public:
using Input = RenderFetchCullSortTask::Output;
using JobModel = render::Task::ModelI<RenderDeferredTask, Input>;
using Config = RenderDeferredTaskConfig;
using JobModel = render::Task::ModelI<RenderDeferredTask, Input, Config>;
RenderDeferredTask() {}
RenderDeferredTask();
void configure(const Config& config);
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
};
#endif // hifi_RenderDeferredTask_h

View file

@ -36,14 +36,14 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
initForwardPipelines(*shapePlumber);
// Extract opaques / transparents / lights / metas / overlays / background
const auto opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE];
const auto transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
const auto lights = items[RenderFetchCullSortTask::LIGHT];
const auto metas = items[RenderFetchCullSortTask::META];
const auto overlayOpaques = items[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE];
const auto overlayTransparents = items[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE];
const auto background = items[RenderFetchCullSortTask::BACKGROUND];
const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION];
const auto& opaques = items.get0()[RenderFetchCullSortTask::OPAQUE_SHAPE];
// const auto& transparents = items.get0()[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
// const auto& lights = items.get0()[RenderFetchCullSortTask::LIGHT];
// const auto& metas = items.get0()[RenderFetchCullSortTask::META];
// const auto& overlayOpaques = items.get0()[RenderFetchCullSortTask::OVERLAY_OPAQUE_SHAPE];
// const auto& overlayTransparents = items.get0()[RenderFetchCullSortTask::OVERLAY_TRANSPARENT_SHAPE];
const auto& background = items.get0()[RenderFetchCullSortTask::BACKGROUND];
// const auto& spatialSelection = items[1];
const auto framebuffer = task.addJob<PrepareFramebuffer>("PrepareFramebuffer");

View file

@ -29,12 +29,25 @@
#include "skin_model_shadow_vert.h"
#include "skin_model_normal_map_vert.h"
#include "model_shadow_fade_vert.h"
#include "model_lightmap_fade_vert.h"
#include "model_lightmap_normal_map_fade_vert.h"
#include "skin_model_fade_vert.h"
#include "skin_model_shadow_fade_vert.h"
#include "skin_model_normal_map_fade_vert.h"
#include "simple_vert.h"
#include "simple_textured_frag.h"
#include "simple_textured_unlit_frag.h"
#include "simple_transparent_textured_frag.h"
#include "simple_transparent_textured_unlit_frag.h"
#include "simple_fade_vert.h"
#include "simple_textured_fade_frag.h"
#include "simple_textured_unlit_fade_frag.h"
#include "simple_transparent_textured_fade_frag.h"
#include "simple_transparent_textured_unlit_fade_frag.h"
#include "model_frag.h"
#include "model_unlit_frag.h"
#include "model_shadow_frag.h"
@ -42,6 +55,16 @@
#include "model_normal_specular_map_frag.h"
#include "model_specular_map_frag.h"
#include "model_fade_vert.h"
#include "model_normal_map_fade_vert.h"
#include "model_fade_frag.h"
#include "model_shadow_fade_frag.h"
#include "model_unlit_fade_frag.h"
#include "model_normal_map_fade_frag.h"
#include "model_normal_specular_map_fade_frag.h"
#include "model_specular_map_fade_frag.h"
#include "forward_model_frag.h"
#include "forward_model_unlit_frag.h"
#include "forward_model_normal_map_frag.h"
@ -55,6 +78,13 @@
#include "model_translucent_frag.h"
#include "model_translucent_unlit_frag.h"
#include "model_lightmap_fade_frag.h"
#include "model_lightmap_normal_map_fade_frag.h"
#include "model_lightmap_normal_specular_map_fade_frag.h"
#include "model_lightmap_specular_map_fade_frag.h"
#include "model_translucent_fade_frag.h"
#include "model_translucent_unlit_fade_frag.h"
#include "overlay3D_vert.h"
#include "overlay3D_frag.h"
#include "overlay3D_model_frag.h"
@ -70,11 +100,12 @@ using namespace render;
using namespace std::placeholders;
void initOverlay3DPipelines(ShapePlumber& plumber);
void initDeferredPipelines(ShapePlumber& plumber);
void initDeferredPipelines(ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter);
void initForwardPipelines(ShapePlumber& plumber);
void addPlumberPipeline(ShapePlumber& plumber,
const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel);
const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel,
const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter);
void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args);
void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args);
@ -140,7 +171,7 @@ void initOverlay3DPipelines(ShapePlumber& plumber) {
}
}
void initDeferredPipelines(render::ShapePlumber& plumber) {
void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter) {
// Vertex shaders
auto simpleVertex = gpu::Shader::createVertex(std::string(simple_vert));
auto modelVertex = gpu::Shader::createVertex(std::string(model_vert));
@ -151,6 +182,16 @@ void initDeferredPipelines(render::ShapePlumber& plumber) {
auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert));
auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert));
auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert));
auto modelLightmapFadeVertex = gpu::Shader::createVertex(std::string(model_lightmap_fade_vert));
auto modelLightmapNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_fade_vert));
auto skinModelFadeVertex = gpu::Shader::createVertex(std::string(skin_model_fade_vert));
auto skinModelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_fade_vert));
auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_fade_vert));
auto modelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_normal_map_fade_vert));
auto simpleFadeVertex = gpu::Shader::createVertex(std::string(simple_fade_vert));
auto modelShadowFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert));
auto skinModelShadowFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert));
// Pixel shaders
auto simplePixel = gpu::Shader::createPixel(std::string(simple_textured_frag));
@ -169,104 +210,220 @@ void initDeferredPipelines(render::ShapePlumber& plumber) {
auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag));
auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag));
auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag));
auto modelLightmapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_fade_frag));
auto modelLightmapNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_fade_frag));
auto modelLightmapSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_fade_frag));
auto modelLightmapNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_fade_frag));
auto modelFadePixel = gpu::Shader::createPixel(std::string(model_fade_frag));
auto modelUnlitFadePixel = gpu::Shader::createPixel(std::string(model_unlit_fade_frag));
auto modelNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_map_fade_frag));
auto modelSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_specular_map_fade_frag));
auto modelNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_fade_frag));
auto modelShadowFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag));
auto modelTranslucentFadePixel = gpu::Shader::createPixel(std::string(model_translucent_fade_frag));
auto modelTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_fade_frag));
auto simpleFadePixel = gpu::Shader::createPixel(std::string(simple_textured_fade_frag));
auto simpleUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag));
auto simpleTranslucentFadePixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_fade_frag));
auto simpleTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_unlit_fade_frag));
using Key = render::ShapeKey;
auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3);
auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3, _4, _5);
// TODO: Refactor this to use a filter
// Opaques
addPipeline(
Key::Builder().withMaterial(),
modelVertex, modelPixel);
modelVertex, modelPixel, nullptr, nullptr);
addPipeline(
Key::Builder(),
simpleVertex, simplePixel);
simpleVertex, simplePixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withUnlit(),
modelVertex, modelUnlitPixel);
modelVertex, modelUnlitPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withUnlit(),
simpleVertex, simpleUnlitPixel);
simpleVertex, simpleUnlitPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withTangents(),
modelNormalMapVertex, modelNormalMapPixel);
modelNormalMapVertex, modelNormalMapPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withSpecular(),
modelVertex, modelSpecularMapPixel);
modelVertex, modelSpecularMapPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withTangents().withSpecular(),
modelNormalMapVertex, modelNormalSpecularMapPixel);
modelNormalMapVertex, modelNormalSpecularMapPixel, nullptr, nullptr);
// Same thing but with Fade on
addPipeline(
Key::Builder().withMaterial().withFade(),
modelFadeVertex, modelFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withFade(),
simpleFadeVertex, simpleFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withUnlit().withFade(),
modelFadeVertex, modelUnlitFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withUnlit().withFade(),
simpleFadeVertex, simpleUnlitFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withTangents().withFade(),
modelNormalMapFadeVertex, modelNormalMapFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withSpecular().withFade(),
modelFadeVertex, modelSpecularMapFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withTangents().withSpecular().withFade(),
modelNormalMapFadeVertex, modelNormalSpecularMapFadePixel, batchSetter, itemSetter);
// Translucents
addPipeline(
Key::Builder().withMaterial().withTranslucent(),
modelVertex, modelTranslucentPixel);
modelVertex, modelTranslucentPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withTranslucent(),
simpleVertex, simpleTranslucentPixel);
simpleVertex, simpleTranslucentPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withTranslucent().withUnlit(),
modelVertex, modelTranslucentUnlitPixel);
modelVertex, modelTranslucentUnlitPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withTranslucent().withUnlit(),
simpleVertex, simpleTranslucentUnlitPixel);
simpleVertex, simpleTranslucentUnlitPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withTranslucent().withTangents(),
modelNormalMapVertex, modelTranslucentPixel);
modelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withTranslucent().withSpecular(),
modelVertex, modelTranslucentPixel);
modelVertex, modelTranslucentPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular(),
modelNormalMapVertex, modelTranslucentPixel);
modelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr);
addPipeline(
// FIXME: Ignore lightmap for translucents meshpart
Key::Builder().withMaterial().withTranslucent().withLightmap(),
modelVertex, modelTranslucentPixel);
modelVertex, modelTranslucentPixel, nullptr, nullptr);
// Same thing but with Fade on
addPipeline(
Key::Builder().withMaterial().withTranslucent().withFade(),
modelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withTranslucent().withFade(),
simpleFadeVertex, simpleTranslucentFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withTranslucent().withUnlit().withFade(),
modelFadeVertex, modelTranslucentUnlitFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withTranslucent().withUnlit().withFade(),
simpleFadeVertex, simpleTranslucentUnlitFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withTranslucent().withTangents().withFade(),
modelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withTranslucent().withSpecular().withFade(),
modelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withTranslucent().withTangents().withSpecular().withFade(),
modelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
addPipeline(
// FIXME: Ignore lightmap for translucents meshpart
Key::Builder().withMaterial().withTranslucent().withLightmap().withFade(),
modelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
// Lightmapped
addPipeline(
Key::Builder().withMaterial().withLightmap(),
modelLightmapVertex, modelLightmapPixel);
modelLightmapVertex, modelLightmapPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withLightmap().withTangents(),
modelLightmapNormalMapVertex, modelLightmapNormalMapPixel);
modelLightmapNormalMapVertex, modelLightmapNormalMapPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withLightmap().withSpecular(),
modelLightmapVertex, modelLightmapSpecularMapPixel);
modelLightmapVertex, modelLightmapSpecularMapPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withLightmap().withTangents().withSpecular(),
modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel);
modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel, nullptr, nullptr);
// Same thing but with Fade on
addPipeline(
Key::Builder().withMaterial().withLightmap().withFade(),
modelLightmapFadeVertex, modelLightmapFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withLightmap().withTangents().withFade(),
modelLightmapNormalMapFadeVertex, modelLightmapNormalMapFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withLightmap().withSpecular().withFade(),
modelLightmapFadeVertex, modelLightmapSpecularMapFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withLightmap().withTangents().withSpecular().withFade(),
modelLightmapNormalMapFadeVertex, modelLightmapNormalSpecularMapFadePixel, batchSetter, itemSetter);
// Skinned
addPipeline(
Key::Builder().withMaterial().withSkinned(),
skinModelVertex, modelPixel);
skinModelVertex, modelPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTangents(),
skinModelNormalMapVertex, modelNormalMapPixel);
skinModelNormalMapVertex, modelNormalMapPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withSkinned().withSpecular(),
skinModelVertex, modelSpecularMapPixel);
skinModelVertex, modelSpecularMapPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTangents().withSpecular(),
skinModelNormalMapVertex, modelNormalSpecularMapPixel);
skinModelNormalMapVertex, modelNormalSpecularMapPixel, nullptr, nullptr);
// Same thing but with Fade on
addPipeline(
Key::Builder().withMaterial().withSkinned().withFade(),
skinModelFadeVertex, modelFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTangents().withFade(),
skinModelNormalMapFadeVertex, modelNormalMapFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withSkinned().withSpecular().withFade(),
skinModelFadeVertex, modelSpecularMapFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTangents().withSpecular().withFade(),
skinModelNormalMapFadeVertex, modelNormalSpecularMapFadePixel, batchSetter, itemSetter);
// Skinned and Translucent
addPipeline(
Key::Builder().withMaterial().withSkinned().withTranslucent(),
skinModelVertex, modelTranslucentPixel);
skinModelVertex, modelTranslucentPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents(),
skinModelNormalMapVertex, modelTranslucentPixel);
skinModelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular(),
skinModelVertex, modelTranslucentPixel);
skinModelVertex, modelTranslucentPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular(),
skinModelNormalMapVertex, modelTranslucentPixel);
skinModelNormalMapVertex, modelTranslucentPixel, nullptr, nullptr);
// Same thing but with Fade on
addPipeline(
Key::Builder().withMaterial().withSkinned().withTranslucent().withFade(),
skinModelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withFade(),
skinModelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTranslucent().withSpecular().withFade(),
skinModelFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withMaterial().withSkinned().withTranslucent().withTangents().withSpecular().withFade(),
skinModelNormalMapFadeVertex, modelTranslucentFadePixel, batchSetter, itemSetter);
// Depth-only
addPipeline(
Key::Builder().withDepthOnly(),
modelShadowVertex, modelShadowPixel);
modelShadowVertex, modelShadowPixel, nullptr, nullptr);
addPipeline(
Key::Builder().withSkinned().withDepthOnly(),
skinModelShadowVertex, modelShadowPixel);
skinModelShadowVertex, modelShadowPixel, nullptr, nullptr);
// Same thing but with Fade on
addPipeline(
Key::Builder().withDepthOnly().withFade(),
modelShadowFadeVertex, modelShadowFadePixel, batchSetter, itemSetter);
addPipeline(
Key::Builder().withSkinned().withDepthOnly().withFade(),
skinModelShadowFadeVertex, modelShadowFadePixel, batchSetter, itemSetter);
}
void initForwardPipelines(render::ShapePlumber& plumber) {
@ -284,7 +441,7 @@ void initForwardPipelines(render::ShapePlumber& plumber) {
auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(forward_model_normal_specular_map_frag));
using Key = render::ShapeKey;
auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3);
auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3, nullptr, nullptr);
// Opaques
addPipeline(
Key::Builder().withMaterial(),
@ -317,7 +474,8 @@ void initForwardPipelines(render::ShapePlumber& plumber) {
}
void addPlumberPipeline(ShapePlumber& plumber,
const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel) {
const ShapeKey& key, const gpu::ShaderPointer& vertex, const gpu::ShaderPointer& pixel,
const render::ShapePipeline::BatchSetter& extraBatchSetter, const render::ShapePipeline::ItemSetter& itemSetter) {
// These key-values' pipelines are added by this functor in addition to the key passed
assert(!key.isWireframe());
assert(!key.isDepthBiased());
@ -354,8 +512,18 @@ void addPlumberPipeline(ShapePlumber& plumber,
state->setDepthBiasSlopeScale(1.0f);
}
plumber.addPipeline(builder.build(), program, state,
key.isTranslucent() ? &lightBatchSetter : &batchSetter);
auto baseBatchSetter = key.isTranslucent() ? &lightBatchSetter : &batchSetter;
render::ShapePipeline::BatchSetter finalBatchSetter;
if (extraBatchSetter) {
finalBatchSetter = [baseBatchSetter, extraBatchSetter](const ShapePipeline& pipeline, gpu::Batch& batch, render::Args* args) {
baseBatchSetter(pipeline, batch, args);
extraBatchSetter(pipeline, batch, args);
};
}
else {
finalBatchSetter = baseBatchSetter;
}
plumber.addPipeline(builder.build(), program, state, finalBatchSetter, itemSetter);
}
}

View file

@ -28,6 +28,12 @@
#include "model_shadow_frag.h"
#include "skin_model_shadow_frag.h"
#include "model_shadow_fade_vert.h"
#include "skin_model_shadow_fade_vert.h"
#include "model_shadow_fade_frag.h"
#include "skin_model_shadow_fade_frag.h"
using namespace render;
void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
@ -46,6 +52,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
const auto& fbo = shadow->framebuffer;
RenderArgs* args = renderContext->args;
ShapeKey::Builder defaultKeyBuilder;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
batch.enableStereo(false);
@ -62,8 +70,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
batch.setProjectionTransform(shadow->getProjection());
batch.setViewTransform(shadow->getView(), false);
auto shadowPipeline = _shapePlumber->pickPipeline(args, ShapeKey());
auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, ShapeKey::Builder().withSkinned());
auto shadowPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
std::vector<ShapeKey> skinnedShapeKeys{};
@ -104,15 +112,29 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel);
shapePlumber->addPipeline(
ShapeKey::Filter::Builder().withoutSkinned(),
ShapeKey::Filter::Builder().withoutSkinned().withoutFade(),
modelProgram, state);
auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert));
auto skinPixel = gpu::Shader::createPixel(std::string(skin_model_shadow_frag));
gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, skinPixel);
shapePlumber->addPipeline(
ShapeKey::Filter::Builder().withSkinned(),
ShapeKey::Filter::Builder().withSkinned().withoutFade(),
skinProgram, state);
auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert));
auto modelFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag));
gpu::ShaderPointer modelFadeProgram = gpu::Shader::createProgram(modelFadeVertex, modelFadePixel);
shapePlumber->addPipeline(
ShapeKey::Filter::Builder().withoutSkinned().withFade(),
modelFadeProgram, state);
auto skinFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert));
auto skinFadePixel = gpu::Shader::createPixel(std::string(skin_model_shadow_fade_frag));
gpu::ShaderPointer skinFadeProgram = gpu::Shader::createProgram(skinFadeVertex, skinFadePixel);
shapePlumber->addPipeline(
ShapeKey::Filter::Builder().withSkinned().withFade(),
skinFadeProgram, state);
}
const auto cachedMode = task.addJob<RenderShadowSetup>("ShadowSetup");

View file

@ -13,11 +13,13 @@
#include <render/SceneTask.h>
#include "LightStage.h"
#include "BackgroundStage.h"
#include <render/TransitionStage.h>
#include "DeferredLightingEffect.h"
void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render::Varying& output) {
task.addJob<LightStageSetup>("LightStageSetup");
task.addJob<BackgroundStageSetup>("BackgroundStageSetup");
task.addJob<render::TransitionStageSetup>("TransitionStageSetup");
task.addJob<DefaultLightingSetup>("DefaultLightingSetup");

View file

@ -0,0 +1,70 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// model_fade.frag
// fragment shader
//
// Created by Olivier Prat on 04/19/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec4 _position;
in vec4 _worldPosition;
in vec3 _normal;
in vec3 _color;
in vec2 _texCoord0;
in vec2 _texCoord1;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color;
float roughness = getMaterialRoughness(mat);
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
emissive += fadeEmissive;
float scattering = getMaterialScattering(mat);
packDeferredFragment(
normalize(_normal.xyz),
opacity,
albedo,
roughness,
getMaterialMetallic(mat),
emissive,
occlusionTex,
scattering);
}

View file

@ -0,0 +1,44 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// model_fade.slv
// vertex shader
//
// Created by Olivier Prat on 04/24/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Color.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
out float _alpha;
out vec2 _texCoord0;
out vec2 _texCoord1;
out vec4 _position;
out vec4 _worldPosition;
out vec3 _normal;
out vec3 _color;
void main(void) {
_color = colorToLinearRGB(inColor.xyz);
_alpha = inColor.w;
TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
}

View file

@ -0,0 +1,54 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_lightmap_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS)$>
<$declareMaterialLightmap()$>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec4 _position;
in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal;
in vec3 _color;
in vec4 _worldPosition;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
packDeferredFragmentLightmap(
normalize(_normal),
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
getMaterialAlbedo(mat) * albedo.rgb * _color,
getMaterialRoughness(mat) * roughness,
getMaterialMetallic(mat),
getMaterialFresnel(mat),
lightmapVal+fadeEmissive);
}

View file

@ -0,0 +1,46 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_lightmap_fade.vert
// vertex shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Color.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
out vec4 _position;
out vec2 _texCoord0;
out vec2 _texCoord1;
out vec3 _normal;
out vec3 _color;
out vec4 _worldPosition;
void main(void) {
// pass along the color in linear space
_color = colorToLinearRGB(inColor.xyz);
// and the texture coordinates
TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord1)$>
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
}

View file

@ -0,0 +1,57 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_lightmap_normal_map_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL)$>
<$declareMaterialLightmap()$>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec4 _position;
in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal;
in vec3 _tangent;
in vec3 _color;
in vec4 _worldPosition;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$>
packDeferredFragmentLightmap(
normalize(viewNormal.xyz),
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
getMaterialAlbedo(mat) * albedo.rgb * _color,
getMaterialRoughness(mat),
getMaterialMetallic(mat),
getMaterialFresnel(mat),
lightmapVal+fadeEmissive);
}

View file

@ -0,0 +1,46 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_lightmap_normal_map_fade.vert
// vertex shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Color.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
out vec4 _position;
out vec2 _texCoord0;
out vec2 _texCoord1;
out vec3 _normal;
out vec3 _tangent;
out vec3 _color;
out vec4 _worldPosition;
void main(void) {
// pass along the color in linear space
_color = colorToLinearRGB(inColor.xyz);
TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord1)$>
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
<$transformModelToWorldDir(cam, obj, inTangent.xyz, _tangent)$>
}

View file

@ -0,0 +1,57 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_lightmap_normal_specular_map_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC)$>
<$declareMaterialLightmap()$>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec4 _position;
in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal;
in vec3 _tangent;
in vec3 _color;
in vec4 _worldPosition;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTexel, _normal, _tangent, viewNormal)$>
packDeferredFragmentLightmap(
normalize(viewNormal.xyz),
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
getMaterialAlbedo(mat) * albedo.rgb * _color,
getMaterialRoughness(mat) * roughness,
getMaterialMetallic(mat) * metallicTex,
/*specular, // no use of */ getMaterialFresnel(mat),
lightmapVal+fadeEmissive);
}

View file

@ -0,0 +1,53 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_lightmap_specular_map_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC)$>
<$declareMaterialLightmap()$>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec4 _position;
in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal;
in vec3 _color;
in vec4 _worldPosition;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedo, roughness, _SCRIBE_NULL, metallicTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmapVal)$>
packDeferredFragmentLightmap(
normalize(_normal),
evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a),
getMaterialAlbedo(mat) * albedo.rgb * _color,
getMaterialRoughness(mat) * roughness,
getMaterialMetallic(mat) * metallicTex,
/*metallicTex, // no use of */getMaterialFresnel(mat),
lightmapVal+fadeEmissive);
}

View file

@ -0,0 +1,74 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_normal_map_fade.frag
// fragment shader
//
// Created by Olivier Prat on 04/19/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION, SCATTERING)$>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec4 _position;
in vec4 _worldPosition;
in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal;
in vec3 _tangent;
in vec3 _color;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex, scatteringTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color;
float roughness = getMaterialRoughness(mat);
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
float scattering = getMaterialScattering(mat);
<$evalMaterialScattering(scatteringTex, scattering, matKey, scattering)$>;
packDeferredFragment(
viewNormal,
opacity,
albedo,
roughness,
getMaterialMetallic(mat),
emissive+fadeEmissive,
occlusionTex,
scattering);
}

View file

@ -0,0 +1,48 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_normal_map_fade.vert
// vertex shader
//
// Created by Olivier Prat on 04/24/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Color.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
out vec4 _position;
out vec4 _worldPosition;
out vec2 _texCoord0;
out vec2 _texCoord1;
out vec3 _normal;
out vec3 _tangent;
out vec3 _color;
out float _alpha;
void main(void) {
// pass along the color
_color = colorToLinearRGB(inColor.rgb);
_alpha = inColor.a;
TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
<$transformModelToWorldDir(cam, obj, inTangent.xyz, _tangent)$>
}

View file

@ -0,0 +1,76 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_normal_specular_map_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC, EMISSIVE, OCCLUSION)$>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec4 _position;
in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal;
in vec3 _tangent;
in vec3 _color;
in vec4 _worldPosition;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, metallicTex, emissiveTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>;
<$discardTransparent(opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color;
float roughness = getMaterialRoughness(mat);
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
vec3 viewNormal;
<$tangentToViewSpaceLOD(_position, normalTex, _normal, _tangent, viewNormal)$>
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
float scattering = getMaterialScattering(mat);
packDeferredFragment(
normalize(viewNormal.xyz),
opacity,
albedo,
roughness,
metallic,
emissive+fadeEmissive,
occlusionTex,
scattering);
}

View file

@ -0,0 +1,30 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_shadow_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include Fade.slh@>
<$declareFadeFragment()$>
layout(location = 0) out vec4 _fragColor;
in vec4 _worldPosition;
void main(void) {
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFadeClip(fadeParams, _worldPosition.xyz);
// pass-through to set z-buffer
_fragColor = vec4(1.0, 1.0, 1.0, 0.0);
}

View file

@ -0,0 +1,29 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_shadow_fade.vert
// vertex shader
//
// Created by Olivier Prat on 06/045/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
out vec4 _worldPosition;
void main(void) {
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
}

View file

@ -0,0 +1,72 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_specular_map_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC, EMISSIVE, OCCLUSION)$>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec4 _position;
in vec2 _texCoord0;
in vec2 _texCoord1;
in vec3 _normal;
in vec3 _color;
in vec4 _worldPosition;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex, emissiveTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color;
float roughness = getMaterialRoughness(mat);
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
float scattering = getMaterialScattering(mat);
packDeferredFragment(
normalize(_normal),
opacity,
albedo,
roughness,
metallic,
emissive+fadeEmissive,
occlusionTex,
scattering);
}

View file

@ -0,0 +1,91 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_translucent_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include model/Material.slh@>
<@include DeferredGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlended()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec2 _texCoord0;
in vec2 _texCoord1;
in vec4 _position;
in vec3 _normal;
in vec3 _color;
in float _alpha;
in vec4 _worldPosition;
out vec4 _fragColor;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex)$>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = getMaterialOpacity(mat) * _alpha;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color;
float roughness = getMaterialRoughness(mat);
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
float metallic = getMaterialMetallic(mat);
vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value
if (metallic <= 0.5) {
metallic = 0.0;
} else {
fresnel = albedo;
metallic = 1.0;
}
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
vec3 fragPosition = _position.xyz;
vec3 fragNormal = normalize(_normal);
TransformCamera cam = getTransformCamera();
_fragColor = vec4(evalGlobalLightingAlphaBlended(
cam._viewInverse,
1.0,
occlusionTex,
fragPosition,
fragNormal,
albedo,
fresnel,
metallic,
emissive+fadeEmissive,
roughness, opacity),
opacity);
}

View file

@ -0,0 +1,50 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_translucent_unlit_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include model/Material.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
<@include LightingModel.slh@>
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec2 _texCoord0;
in vec3 _color;
in float _alpha;
in vec4 _worldPosition;
out vec4 _fragColor;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
float opacity = getMaterialOpacity(mat) * _alpha;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color;
albedo += fadeEmissive;
_fragColor = vec4(albedo * isUnlitEnabled(), opacity);
}

View file

@ -0,0 +1,54 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_unlit_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include LightingModel.slh@>
<@include model/Material.slh@>
<@include Fade.slh@>
<$declareFadeFragment()$>
<@include MaterialTextures.slh@>
<$declareMaterialTextures(ALBEDO)$>
in vec2 _texCoord0;
in vec3 _normal;
in vec3 _color;
in float _alpha;
in vec4 _worldPosition;
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material mat = getMaterial();
int matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color;
albedo += fadeEmissive;
packDeferredFragmentUnlit(
normalize(_normal),
opacity,
albedo * isUnlitEnabled());
}

View file

@ -0,0 +1,101 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// simple_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include Fade.slh@>
<$declareFadeFragmentInstanced()$>
// the interpolated normal
in vec3 _normal;
in vec3 _modelNormal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _position;
in vec4 _worldPosition;
//PROCEDURAL_COMMON_BLOCK
#line 1001
//PROCEDURAL_BLOCK
#line 2030
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParamsInstanced(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
Material material = getMaterial();
vec3 normal = normalize(_normal.xyz);
vec3 diffuse = _color.rgb;
vec3 specular = DEFAULT_SPECULAR;
float shininess = DEFAULT_SHININESS;
float emissiveAmount = 0.0;
#ifdef PROCEDURAL
#ifdef PROCEDURAL_V1
specular = getProceduralColor().rgb;
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
//specular = pow(specular, vec3(2.2));
emissiveAmount = 1.0;
#else
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
#endif
#endif
const float ALPHA_THRESHOLD = 0.999;
if (_color.a < ALPHA_THRESHOLD) {
if (emissiveAmount > 0.0) {
packDeferredFragmentTranslucent(
normal,
_color.a,
specular+fadeEmissive,
DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS);
} else {
packDeferredFragmentTranslucent(
normal,
_color.a,
diffuse+fadeEmissive,
DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS);
}
} else {
if (emissiveAmount > 0.0) {
packDeferredFragmentLightmap(
normal,
1.0,
diffuse+fadeEmissive,
max(0, 1.0 - shininess / 128.0),
DEFAULT_METALLIC,
specular,
specular);
} else {
packDeferredFragment(
normal,
1.0,
diffuse,
max(0, 1.0 - shininess / 128.0),
length(specular),
DEFAULT_EMISSIVE+fadeEmissive,
DEFAULT_OCCLUSION,
DEFAULT_SCATTERING);
}
}
}

View file

@ -0,0 +1,44 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// simple_fade.vert
// vertex shader
//
// Created by Olivier Prat on 06/04/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Color.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include Fade.slh@>
<$declareFadeVertexInstanced()$>
// the interpolated normal
out vec3 _normal;
out vec3 _modelNormal;
out vec4 _color;
out vec2 _texCoord0;
out vec4 _position;
out vec4 _worldPosition;
void main(void) {
_color = colorToLinearRGBA(inColor);
_texCoord0 = inTexCoord0.st;
_position = inPosition;
_modelNormal = inNormal.xyz;
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$transformModelToWorldPos(obj, inPosition, _worldPosition)$>
<$transformModelToWorldDir(cam, obj, inNormal.xyz, _normal)$>
<$passThroughFadeObjectParams()$>
}

View file

@ -0,0 +1,66 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// simple_textured_fade.slf
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Color.slh@>
<@include DeferredBufferWrite.slh@>
<@include model/Material.slh@>
<@include Fade.slh@>
// the albedo texture
uniform sampler2D originalTexture;
// the interpolated normal
in vec3 _normal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _worldPosition;
// Declare after all samplers to prevent sampler location mix up with originalTexture
<$declareFadeFragmentInstanced()$>
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParamsInstanced(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
vec4 texel = texture(originalTexture, _texCoord0);
float colorAlpha = _color.a;
if (_color.a <= 0.0) {
texel = colorToLinearRGBA(texel);
colorAlpha = -_color.a;
}
const float ALPHA_THRESHOLD = 0.999;
if (colorAlpha * texel.a < ALPHA_THRESHOLD) {
packDeferredFragmentTranslucent(
normalize(_normal),
colorAlpha * texel.a,
_color.rgb * texel.rgb + fadeEmissive,
DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS);
} else {
packDeferredFragment(
normalize(_normal),
1.0,
_color.rgb * texel.rgb,
DEFAULT_ROUGHNESS,
DEFAULT_METALLIC,
DEFAULT_EMISSIVE + fadeEmissive,
DEFAULT_OCCLUSION,
DEFAULT_SCATTERING);
}
}

View file

@ -0,0 +1,60 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// simple_textured_unlit_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Color.slh@>
<@include DeferredBufferWrite.slh@>
<@include Fade.slh@>
// the albedo texture
uniform sampler2D originalTexture;
// the interpolated normal
in vec3 _normal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _worldPosition;
// Declare after all samplers to prevent sampler location mix up with originalTexture
<$declareFadeFragmentInstanced()$>
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParamsInstanced(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
vec4 texel = texture(originalTexture, _texCoord0.st);
float colorAlpha = _color.a;
if (_color.a <= 0.0) {
texel = colorToLinearRGBA(texel);
colorAlpha = -_color.a;
}
const float ALPHA_THRESHOLD = 0.999;
if (colorAlpha * texel.a < ALPHA_THRESHOLD) {
packDeferredFragmentTranslucent(
normalize(_normal),
colorAlpha * texel.a,
_color.rgb * texel.rgb+fadeEmissive,
DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS);
} else {
packDeferredFragmentUnlit(
normalize(_normal),
1.0,
_color.rgb * texel.rgb+fadeEmissive);
}
}

View file

@ -0,0 +1,74 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// simple_transparent_textured_fade.slf
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Color.slh@>
<@include DeferredBufferWrite.slh@>
<@include DeferredGlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlended()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
<@include Fade.slh@>
// the albedo texture
uniform sampler2D originalTexture;
// the interpolated normal
in vec4 _position;
in vec3 _normal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _worldPosition;
// Declare after all samplers to prevent sampler location mix up with originalTexture
<$declareFadeFragmentInstanced()$>
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParamsInstanced(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
vec4 texel = texture(originalTexture, _texCoord0.st);
float opacity = _color.a;
if (_color.a <= 0.0) {
texel = colorToLinearRGBA(texel);
opacity = -_color.a;
}
opacity *= texel.a;
vec3 albedo = _color.rgb * texel.rgb;
vec3 fragPosition = _position.xyz;
vec3 fragNormal = normalize(_normal);
TransformCamera cam = getTransformCamera();
_fragColor0 = vec4(evalGlobalLightingAlphaBlended(
cam._viewInverse,
1.0,
1.0,
fragPosition,
fragNormal,
albedo,
DEFAULT_FRESNEL,
0.0f,
fadeEmissive,
DEFAULT_ROUGHNESS,
opacity),
opacity);
}

View file

@ -0,0 +1,47 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// simple_transparent_textured_unlit_fade.slf
// fragment shader
//
// Created by Olivier Prat on 06/05/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Color.slh@>
<@include Fade.slh@>
// the albedo texture
uniform sampler2D originalTexture;
// the interpolated normal
in vec3 _normal;
in vec4 _color;
in vec2 _texCoord0;
in vec4 _worldPosition;
layout(location = 0) out vec4 _fragColor0;
// Declare after all samplers to prevent sampler location mix up with originalTexture
<$declareFadeFragmentInstanced()$>
void main(void) {
vec3 fadeEmissive;
FadeObjectParams fadeParams;
<$fetchFadeObjectParamsInstanced(fadeParams)$>
applyFade(fadeParams, _worldPosition.xyz, fadeEmissive);
vec4 texel = texture(originalTexture, _texCoord0.st);
float colorAlpha = _color.a;
if (_color.a <= 0.0) {
texel = colorToLinearRGBA(texel);
colorAlpha = -_color.a;
}
_fragColor0 = vec4(_color.rgb * texel.rgb+fadeEmissive, colorAlpha * texel.a);
}

View file

@ -0,0 +1,53 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// skin_model_fade.vert
// vertex shader
//
// Created by Olivier Prat on 06/045/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Color.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include Skinning.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
out vec4 _position;
out vec2 _texCoord0;
out vec2 _texCoord1;
out vec3 _normal;
out vec3 _color;
out float _alpha;
out vec4 _worldPosition;
void main(void) {
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
vec3 interpolatedNormal = vec3(0.0, 0.0, 0.0);
skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal);
// pass along the color
_color = colorToLinearRGB(inColor.rgb);
_alpha = inColor.a;
TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$>
<$transformModelToWorldPos(obj, position, _worldPosition)$>
<$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, _normal.xyz)$>
}

View file

@ -0,0 +1,62 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// skin_model_normal_map_fade.vert
// vertex shader
//
// Created by Olivier Prat on 06/045/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Color.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include Skinning.slh@>
<@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
out vec4 _position;
out vec2 _texCoord0;
out vec2 _texCoord1;
out vec3 _normal;
out vec3 _tangent;
out vec3 _color;
out float _alpha;
out vec4 _worldPosition;
void main(void) {
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0);
vec4 interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0);
skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz);
// pass along the color
_color = colorToLinearRGB(inColor.rgb);
_alpha = inColor.a;
TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord0, _texCoord1)$>
interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0);
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToEyeAndClipPos(cam, obj, position, _position, gl_Position)$>
<$transformModelToWorldPos(obj, position, _worldPosition)$>
<$transformModelToWorldDir(cam, obj, interpolatedNormal.xyz, interpolatedNormal.xyz)$>
<$transformModelToWorldDir(cam, obj, interpolatedTangent.xyz, interpolatedTangent.xyz)$>
_normal = interpolatedNormal.xyz;
_tangent = interpolatedTangent.xyz;
}

View file

@ -2,7 +2,7 @@
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// model_shadow.frag
// skin_model_shadow.frag
// fragment shader
//
// Created by Andrzej Kapolka on 3/24/14.

View file

@ -0,0 +1,30 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// skin_model_shadow_fade.frag
// fragment shader
//
// Created by Olivier Prat on 06/08/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include Fade.slh@>
<$declareFadeFragment()$>
in vec4 _worldPosition;
layout(location = 0) out vec4 _fragColor;
void main(void) {
FadeObjectParams fadeParams;
<$fetchFadeObjectParams(fadeParams)$>
applyFadeClip(fadeParams, _worldPosition.xyz);
// pass-through to set z-buffer
_fragColor = vec4(1.0, 1.0, 1.0, 0.0);
}

View file

@ -0,0 +1,32 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// skin_model_shadow_fade.vert
// vertex shader
//
// Created by Olivier Prat on 06/045/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
<@include Skinning.slh@>
out vec4 _worldPosition;
void main(void) {
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
skinPosition(inSkinClusterIndex, inSkinClusterWeight, inPosition, position);
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, position, gl_Position)$>
<$transformModelToWorldPos(obj, position, _worldPosition)$>
}

View file

@ -119,9 +119,12 @@ namespace render {
DebugFlags _debugFlags { RENDER_DEBUG_NONE };
gpu::Batch* _batch = nullptr;
uint32_t _globalShapeKey { 0 };
uint32_t _globalShapeKey{ 0 };
uint32_t _itemShapeKey{ 0 };
bool _enableTexturing { true };
bool _enableFade{ false };
RenderDetails _details;
render::ScenePointer _scene;
int8_t _cameraMode { -1 };

View file

@ -42,6 +42,7 @@ void render::renderItems(const RenderContextPointer& renderContext, const ItemBo
void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, const Item& item, const ShapeKey& globalKey) {
assert(item.getKey().isShape());
auto key = item.getShapeKey() | globalKey;
args->_itemShapeKey = key._flags.to_ulong();
if (key.isValid() && !key.hasOwnPipeline()) {
args->_shapePipeline = shapeContext->pickPipeline(args, key);
if (args->_shapePipeline) {
@ -54,6 +55,7 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons
} else {
qCDebug(renderlogging) << "Item could not be rendered with invalid key" << key;
}
args->_itemShapeKey = 0;
}
void render::renderShapes(const RenderContextPointer& renderContext,
@ -85,10 +87,10 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext,
using SortedShapes = std::unordered_map<render::ShapeKey, std::vector<Item>, render::ShapeKey::Hash, render::ShapeKey::KeyEqual>;
SortedPipelines sortedPipelines;
SortedShapes sortedShapes;
std::vector<Item> ownPipelineBucket;
std::vector< std::tuple<Item,ShapeKey> > ownPipelineBucket;
for (auto i = 0; i < numItemsToDraw; ++i) {
auto item = scene->getItem(inItems[i].id);
auto& item = scene->getItem(inItems[i].id);
{
assert(item.getKey().isShape());
@ -100,7 +102,7 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext,
}
bucket.push_back(item);
} else if (key.hasOwnPipeline()) {
ownPipelineBucket.push_back(item);
ownPipelineBucket.push_back( std::make_tuple(item, key) );
} else {
qCDebug(renderlogging) << "Item could not be rendered with invalid key" << key;
}
@ -114,15 +116,19 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext,
if (!args->_shapePipeline) {
continue;
}
args->_itemShapeKey = pipelineKey._flags.to_ulong();
for (auto& item : bucket) {
args->_shapePipeline->prepareShapeItem(args, pipelineKey, item);
item.render(args);
}
}
args->_shapePipeline = nullptr;
for (auto& item : ownPipelineBucket) {
for (auto& itemAndKey : ownPipelineBucket) {
auto& item = std::get<0>(itemAndKey);
args->_itemShapeKey = std::get<1>(itemAndKey)._flags.to_ulong();
item.render(args);
}
args->_itemShapeKey = 0;
}
void DrawLight::run(const RenderContextPointer& renderContext, const ItemBounds& inLights) {

View file

@ -28,7 +28,7 @@ void FilterLayeredItems::run(const RenderContextPointer& renderContext, const It
outItems.clear();
// For each item, filter it into one bucket
for (auto itemBound : inItems) {
for (auto& itemBound : inItems) {
auto& item = scene->getItem(itemBound.id);
if (item.getLayer() == _keepLayer) {
outItems.emplace_back(itemBound);

View file

@ -12,7 +12,9 @@
#ifndef hifi_render_IndexedContainer_h
#define hifi_render_IndexedContainer_h
#include <cassert>
#include <vector>
#include <algorithm>
namespace render {
namespace indexed_container {
@ -97,6 +99,10 @@ namespace indexed_container {
return _elements[index];
}
bool isElementFreed(Index index) const {
return std::find(_allocator._freeIndices.begin(), _allocator._freeIndices.end(), index) != _allocator._freeIndices.end();
}
const Element& get(Index index) const {
return _elements[index];
}

View file

@ -13,8 +13,13 @@
#include <numeric>
#include "gpu/Batch.h"
#include "TransitionStage.h"
using namespace render;
const Item::ID Item::INVALID_ITEM_ID = 0;
const ItemCell Item::INVALID_CELL = -1;
const Item::Status::Value Item::Status::Value::INVALID = Item::Status::Value();
const float Item::Status::Value::RED = 0.0f;
@ -78,3 +83,12 @@ void Item::resetPayload(const PayloadPointer& payload) {
_key = _payload->getKey();
}
}
const ShapeKey Item::getShapeKey() const {
auto shapeKey = _payload->getShapeKey();
if (!TransitionStage::isIndexInvalid(_transitionId)) {
// Objects that are fading are rendered double-sided to give a sense of volume
return ShapeKey::Builder(shapeKey).withFade().withoutCullFace();
}
return shapeKey;
}

View file

@ -28,9 +28,11 @@
#include "model/Material.h"
#include "ShapePipeline.h"
namespace render {
typedef int32_t Index;
const Index INVALID_INDEX{ -1 };
class Context;
// Key is the KEY to filter Items and create specialized lists
@ -69,6 +71,7 @@ public:
Flags _flags{ 0 };
public:
Builder() {}
Builder(const ItemKey& key) : _flags{ key._flags } {}
ItemKey build() const { return ItemKey(_flags); }
@ -241,8 +244,8 @@ public:
typedef std::vector<Item> Vector;
typedef ItemID ID;
static const ID INVALID_ITEM_ID = 0;
static const ItemCell INVALID_CELL = -1;
static const ID INVALID_ITEM_ID;
static const ItemCell INVALID_CELL;
// Convenient function to clear an ID or check it s valid
static void clearID(ID& id) { id = INVALID_ITEM_ID; }
@ -316,7 +319,6 @@ public:
virtual const ItemKey getKey() const = 0;
virtual const Bound getBound() const = 0;
virtual int getLayer() const = 0;
virtual void render(RenderArgs* args) = 0;
virtual const ShapeKey getShapeKey() const = 0;
@ -368,7 +370,7 @@ public:
void render(RenderArgs* args) const { _payload->render(args); }
// Shape Type Interface
const ShapeKey getShapeKey() const { return _payload->getShapeKey(); }
const ShapeKey getShapeKey() const;
// Meta Type Interface
uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); }
@ -376,10 +378,14 @@ public:
// Access the status
const StatusPointer& getStatus() const { return _payload->getStatus(); }
void setTransitionId(Index id) { _transitionId = id; }
Index getTransitionId() const { return _transitionId; }
protected:
PayloadPointer _payload;
ItemKey _key;
ItemCell _cell{ INVALID_CELL };
Index _transitionId{ INVALID_INDEX };
friend class Scene;
};
@ -436,7 +442,6 @@ public:
virtual const Item::Bound getBound() const override { return payloadGetBound<T>(_data); }
virtual int getLayer() const override { return payloadGetLayer<T>(_data); }
virtual void render(RenderArgs* args) override { payloadRender<T>(_data, args); }
// Shape Type interface

View file

@ -65,6 +65,5 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
const auto overlayTransparents = task.addJob<DepthSortItems>("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false));
const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET];
output = Varying(Output{{
opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background, spatialSelection }});
output = Output(BucketList{ opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background }, spatialSelection);
}

View file

@ -26,12 +26,12 @@ public:
OVERLAY_OPAQUE_SHAPE,
OVERLAY_TRANSPARENT_SHAPE,
BACKGROUND,
SPATIAL_SELECTION,
NUM_BUCKETS
};
using Output = std::array<render::Varying, Buckets::NUM_BUCKETS>;
using BucketList = render::VaryingArray<render::ItemBounds, Buckets::NUM_BUCKETS>;
using Output = render::VaryingSet2<BucketList, render::ItemSpatialTree::ItemSelection>;
using JobModel = render::Task::ModelO<RenderFetchCullSortTask, Output>;
RenderFetchCullSortTask() {}

View file

@ -13,13 +13,16 @@
#include <numeric>
#include <gpu/Batch.h>
#include "Logging.h"
#include "TransitionStage.h"
// Comment this to disable transitions (fades)
#define SCENE_ENABLE_TRANSITIONS
using namespace render;
void Transaction::resetItem(ItemID id, const PayloadPointer& payload) {
if (payload) {
_resetItems.emplace_back(id);
_resetPayloads.emplace_back(payload);
_resetItems.emplace_back(Reset{ id, payload });
} else {
qCDebug(renderlogging) << "WARNING: Transaction::resetItem with a null payload!";
removeItem(id);
@ -30,9 +33,24 @@ void Transaction::removeItem(ItemID id) {
_removedItems.emplace_back(id);
}
void Transaction::addTransitionToItem(ItemID id, Transition::Type transition, ItemID boundId) {
_addedTransitions.emplace_back(TransitionAdd{ id, transition, boundId });
}
void Transaction::removeTransitionFromItem(ItemID id) {
_addedTransitions.emplace_back(TransitionAdd{ id, Transition::NONE, render::Item::INVALID_ITEM_ID });
}
void Transaction::reApplyTransitionToItem(ItemID id) {
_reAppliedTransitions.emplace_back(TransitionReApply{ id });
}
void Transaction::queryTransitionOnItem(ItemID id, TransitionQueryFunc func) {
_queriedTransitions.emplace_back(TransitionQuery{ id, func });
}
void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) {
_updatedItems.emplace_back(id);
_updateFunctors.emplace_back(functor);
_updatedItems.emplace_back(Update{ id, functor });
}
void Transaction::resetSelection(const Selection& selection) {
@ -41,11 +59,12 @@ void Transaction::resetSelection(const Selection& selection) {
void Transaction::merge(const Transaction& transaction) {
_resetItems.insert(_resetItems.end(), transaction._resetItems.begin(), transaction._resetItems.end());
_resetPayloads.insert(_resetPayloads.end(), transaction._resetPayloads.begin(), transaction._resetPayloads.end());
_removedItems.insert(_removedItems.end(), transaction._removedItems.begin(), transaction._removedItems.end());
_updatedItems.insert(_updatedItems.end(), transaction._updatedItems.begin(), transaction._updatedItems.end());
_updateFunctors.insert(_updateFunctors.end(), transaction._updateFunctors.begin(), transaction._updateFunctors.end());
_resetSelections.insert(_resetSelections.end(), transaction._resetSelections.begin(), transaction._resetSelections.end());
_addedTransitions.insert(_addedTransitions.end(), transaction._addedTransitions.begin(), transaction._addedTransitions.end());
_queriedTransitions.insert(_queriedTransitions.end(), transaction._queriedTransitions.begin(), transaction._queriedTransitions.end());
_reAppliedTransitions.insert(_reAppliedTransitions.end(), transaction._reAppliedTransitions.begin(), transaction._reAppliedTransitions.end());
}
@ -104,17 +123,23 @@ void Scene::processTransactionQueue() {
// capture anything coming from the transaction
// resets and potential NEW items
resetItems(consolidatedTransaction._resetItems, consolidatedTransaction._resetPayloads);
resetItems(consolidatedTransaction._resetItems);
// Update the numItemsAtomic counter AFTER the reset changes went through
_numAllocatedItems.exchange(maxID);
// updates
updateItems(consolidatedTransaction._updatedItems, consolidatedTransaction._updateFunctors);
updateItems(consolidatedTransaction._updatedItems);
// removes
removeItems(consolidatedTransaction._removedItems);
#ifdef SCENE_ENABLE_TRANSITIONS
// add transitions
transitionItems(consolidatedTransaction._addedTransitions);
reApplyTransitions(consolidatedTransaction._reAppliedTransitions);
queryTransitionItems(consolidatedTransaction._queriedTransitions);
#endif
// Update the numItemsAtomic counter AFTER the pending changes went through
_numAllocatedItems.exchange(maxID);
}
@ -127,34 +152,31 @@ void Scene::processTransactionQueue() {
}
}
void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) {
auto resetPayload = payloads.begin();
for (auto resetID : ids) {
void Scene::resetItems(const Transaction::Resets& transactions) {
for (auto& reset : transactions) {
// Access the true item
auto& item = _items[resetID];
auto itemId = std::get<0>(reset);
auto& item = _items[itemId];
auto oldKey = item.getKey();
auto oldCell = item.getCell();
// Reset the item with a new payload
item.resetPayload(*resetPayload);
item.resetPayload(std::get<1>(reset));
auto newKey = item.getKey();
// Update the item's container
assert((oldKey.isSpatial() == newKey.isSpatial()) || oldKey._flags.none());
if (newKey.isSpatial()) {
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), resetID, newKey);
auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), itemId, newKey);
item.resetCell(newCell, newKey.isSmall());
} else {
_masterNonspatialSet.insert(resetID);
_masterNonspatialSet.insert(itemId);
}
// next loop
resetPayload++;
}
}
void Scene::removeItems(const ItemIDs& ids) {
for (auto removedID :ids) {
void Scene::removeItems(const Transaction::Removes& transactions) {
for (auto removedID : transactions) {
// Access the true item
auto& item = _items[removedID];
auto oldCell = item.getCell();
@ -167,17 +189,18 @@ void Scene::removeItems(const ItemIDs& ids) {
_masterNonspatialSet.erase(removedID);
}
// Remove the transition to prevent updating it for nothing
resetItemTransition(removedID);
// Kill it
item.kill();
}
}
void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
auto updateFunctor = functors.begin();
for (auto updateID : ids) {
void Scene::updateItems(const Transaction::Updates& transactions) {
for (auto& update : transactions) {
auto updateID = std::get<0>(update);
if (updateID == Item::INVALID_ITEM_ID) {
updateFunctor++;
continue;
}
@ -187,7 +210,7 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
auto oldKey = item.getKey();
// Update the item
item.update((*updateFunctor));
item.update(std::get<1>(update));
auto newKey = item.getKey();
// Update the item's container
@ -209,10 +232,107 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) {
_masterNonspatialSet.insert(updateID);
}
}
}
}
void Scene::transitionItems(const Transaction::TransitionAdds& transactions) {
auto transitionStage = getStage<TransitionStage>(TransitionStage::getName());
// next loop
updateFunctor++;
for (auto& add : transactions) {
auto itemId = std::get<0>(add);
// Access the true item
const auto& item = _items[itemId];
auto transitionId = item.getTransitionId();
auto transitionType = std::get<1>(add);
auto boundId = std::get<2>(add);
// Remove pre-existing transition, if need be
if (!TransitionStage::isIndexInvalid(transitionId)) {
transitionStage->removeTransition(transitionId);
transitionId = TransitionStage::INVALID_INDEX;
}
// Add a new one.
if (transitionType != Transition::NONE) {
transitionId = transitionStage->addTransition(itemId, transitionType, boundId);
}
setItemTransition(itemId, transitionId);
}
}
void Scene::reApplyTransitions(const Transaction::TransitionReApplies& transactions) {
for (auto itemId : transactions) {
// Access the true item
const auto& item = _items[itemId];
auto transitionId = item.getTransitionId();
setItemTransition(itemId, transitionId);
}
}
void Scene::queryTransitionItems(const Transaction::TransitionQueries& transactions) {
auto transitionStage = getStage<TransitionStage>(TransitionStage::getName());
for (auto& query : transactions) {
auto itemId = std::get<0>(query);
// Access the true item
const auto& item = _items[itemId];
auto func = std::get<1>(query);
if (item.exist() && func != nullptr) {
auto transitionId = item.getTransitionId();
if (!TransitionStage::isIndexInvalid(transitionId)) {
auto& transition = transitionStage->getTransition(transitionId);
func(itemId, &transition);
} else {
func(itemId, nullptr);
}
}
}
}
void Scene::collectSubItems(ItemID parentId, ItemIDs& subItems) const {
// Access the true item
auto& item = _items[parentId];
if (item.exist()) {
// Recursivelly collect the subitems
auto subItemBeginIndex = subItems.size();
auto subItemCount = item.fetchMetaSubItems(subItems);
for (auto i = subItemBeginIndex; i < (subItemBeginIndex + subItemCount); i++) {
auto subItemId = subItems[i];
// Bizarrely, subItemId == parentId can happen for metas... See metaFetchMetaSubItems in RenderableEntityItem.cpp
if (subItemId != parentId) {
collectSubItems(subItemId, subItems);
}
}
}
}
void Scene::setItemTransition(ItemID itemId, Index transitionId) {
// Access the true item
auto& item = _items[itemId];
item.setTransitionId(transitionId);
if (item.exist()) {
ItemIDs subItems;
// Sub-items share the same transition Id
collectSubItems(itemId, subItems);
for (auto subItemId : subItems) {
// Curiously... this can happen
if (subItemId != itemId) {
setItemTransition(subItemId, transitionId);
}
}
}
}
void Scene::resetItemTransition(ItemID itemId) {
auto& item = _items[itemId];
if (!render::TransitionStage::isIndexInvalid(item.getTransitionId())) {
auto transitionStage = getStage<TransitionStage>(TransitionStage::getName());
transitionStage->removeTransition(item.getTransitionId());
setItemTransition(itemId, render::TransitionStage::INVALID_INDEX);
}
}
@ -227,8 +347,8 @@ Selection Scene::getSelection(const Selection::Name& name) const {
}
}
void Scene::resetSelections(const Selections& selections) {
for (auto selection : selections) {
void Scene::resetSelections(const Transaction::SelectionResets& transactions) {
for (auto selection : transactions) {
auto found = _selections.find(selection.getName());
if (found == _selections.end()) {
_selections.insert(SelectionMap::value_type(selection.getName(), selection));

View file

@ -16,10 +16,12 @@
#include "SpatialTree.h"
#include "Stage.h"
#include "Selection.h"
#include "Transition.h"
namespace render {
class Engine;
class Scene;
// Transaction is the mechanism to make any change to the scene.
// Whenever a new item need to be reset,
@ -31,13 +33,23 @@ class Engine;
// of updating the scene before it s rendered.
//
class Transaction {
friend class Scene;
public:
typedef std::function<void(ItemID, const Transition*)> TransitionQueryFunc;
Transaction() {}
~Transaction() {}
// Item transactions
void resetItem(ItemID id, const PayloadPointer& payload);
void removeItem(ItemID id);
bool hasRemovedItems() const { return !_removedItems.empty(); }
void addTransitionToItem(ItemID id, Transition::Type transition, ItemID boundId = render::Item::INVALID_ITEM_ID);
void removeTransitionFromItem(ItemID id);
void reApplyTransitionToItem(ItemID id);
void queryTransitionOnItem(ItemID id, TransitionQueryFunc func);
template <class T> void updateItem(ItemID id, std::function<void(T&)> func) {
updateItem(id, std::make_shared<UpdateFunctor<T>>(func));
@ -54,15 +66,31 @@ public:
// Checkers if there is work to do when processing the transaction
bool touchTransactions() const { return !_resetSelections.empty(); }
ItemIDs _resetItems;
Payloads _resetPayloads;
ItemIDs _removedItems;
ItemIDs _updatedItems;
UpdateFunctors _updateFunctors;
Selections _resetSelections;
protected:
using Reset = std::tuple<ItemID, PayloadPointer>;
using Remove = ItemID;
using Update = std::tuple<ItemID, UpdateFunctorPointer>;
using TransitionAdd = std::tuple<ItemID, Transition::Type, ItemID>;
using TransitionQuery = std::tuple<ItemID, TransitionQueryFunc>;
using TransitionReApply = ItemID;
using SelectionReset = Selection;
using Resets = std::vector<Reset>;
using Removes = std::vector<Remove>;
using Updates = std::vector<Update>;
using TransitionAdds = std::vector<TransitionAdd>;
using TransitionQueries = std::vector<TransitionQuery>;
using TransitionReApplies = std::vector<TransitionReApply>;
using SelectionResets = std::vector<SelectionReset>;
Resets _resetItems;
Removes _removedItems;
Updates _updatedItems;
TransitionAdds _addedTransitions;
TransitionQueries _queriedTransitions;
TransitionReApplies _reAppliedTransitions;
SelectionResets _resetSelections;
};
typedef std::queue<Transaction> TransactionQueue;
@ -123,8 +151,11 @@ public:
}
void resetStage(const Stage::Name& name, const StagePointer& stage);
void setItemTransition(ItemID id, Index transitionId);
void resetItemTransition(ItemID id);
protected:
// Thread safe elements that can be accessed from anywhere
std::atomic<unsigned int> _IDAllocator{ 1 }; // first valid itemID will be One
std::atomic<unsigned int> _numAllocatedItems{ 1 }; // num of allocated items, matching the _items.size()
@ -138,15 +169,20 @@ protected:
ItemSpatialTree _masterSpatialTree;
ItemIDSet _masterNonspatialSet;
void resetItems(const ItemIDs& ids, Payloads& payloads);
void removeItems(const ItemIDs& ids);
void updateItems(const ItemIDs& ids, UpdateFunctors& functors);
void resetItems(const Transaction::Resets& transactions);
void removeItems(const Transaction::Removes& transactions);
void updateItems(const Transaction::Updates& transactions);
void transitionItems(const Transaction::TransitionAdds& transactions);
void reApplyTransitions(const Transaction::TransitionReApplies& transactions);
void queryTransitionItems(const Transaction::TransitionQueries& transactions);
void collectSubItems(ItemID parentId, ItemIDs& subItems) const;
// The Selection map
mutable std::mutex _selectionsMutex; // mutable so it can be used in the thread safe getSelection const method
SelectionMap _selections;
void resetSelections(const Selections& selections);
void resetSelections(const Transaction::SelectionResets& transactions);
// More actions coming to selections soon:
// void removeFromSelection(const Selection& selection);
// void appendToSelection(const Selection& selection);

View file

@ -85,6 +85,8 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::BUFFER::LIGHT));
slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), Slot::BUFFER::LIGHT_AMBIENT_BUFFER));
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK));
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
gpu::Shader::makeProgram(*program, slotBindings);
@ -103,7 +105,9 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
locations->lightBufferUnit = program->getUniformBuffers().findLocation("lightBuffer");
locations->lightAmbientBufferUnit = program->getUniformBuffers().findLocation("lightAmbientBuffer");
locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap");
locations->fadeMaskTextureUnit = program->getTextures().findLocation("fadeMaskMap");
locations->fadeParameterBufferUnit = program->getUniformBuffers().findLocation("fadeParametersBuffer");
ShapeKey key{filter._flags};
auto gpuPipeline = gpu::Pipeline::create(program, state);
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter, itemSetter);
@ -117,7 +121,7 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke
PerformanceTimer perfTimer("ShapePlumber::pickPipeline");
const auto& pipelineIterator = _pipelineMap.find(key);
auto pipelineIterator = _pipelineMap.find(key);
if (pipelineIterator == _pipelineMap.end()) {
// The first time we can't find a pipeline, we should try things to solve that
if (_missingKeys.find(key) == _missingKeys.end()) {

View file

@ -36,6 +36,7 @@ public:
DEPTH_BIAS,
WIREFRAME,
NO_CULL_FACE,
FADE,
OWN_PIPELINE,
INVALID,
@ -83,6 +84,7 @@ public:
Builder& withDepthBias() { _flags.set(DEPTH_BIAS); return (*this); }
Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); }
Builder& withoutCullFace() { _flags.set(NO_CULL_FACE); return (*this); }
Builder& withFade() { _flags.set(FADE); return (*this); }
Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); }
Builder& invalidate() { _flags.set(INVALID); return (*this); }
@ -143,6 +145,9 @@ public:
Builder& withCullFace() { _flags.reset(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); }
Builder& withoutCullFace() { _flags.set(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); }
Builder& withFade() { _flags.set(FADE); _mask.set(FADE); return (*this); }
Builder& withoutFade() { _flags.reset(FADE); _mask.set(FADE); return (*this); }
Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); _mask |= (CUSTOM_MASK); return (*this); }
Builder& withoutCustom() { _flags &= (~CUSTOM_MASK); _mask |= (CUSTOM_MASK); return (*this); }
@ -170,6 +175,7 @@ public:
bool isDepthBiased() const { return _flags[DEPTH_BIAS]; }
bool isWireframe() const { return _flags[WIREFRAME]; }
bool isCullFace() const { return !_flags[NO_CULL_FACE]; }
bool isFaded() const { return _flags[FADE]; }
bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; }
bool isValid() const { return !_flags[INVALID]; }
@ -209,6 +215,7 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& key) {
<< "isDepthBiased:" << key.isDepthBiased()
<< "isWireframe:" << key.isWireframe()
<< "isCullFace:" << key.isCullFace()
<< "isFaded:" << key.isFaded()
<< "]";
}
} else {
@ -230,6 +237,7 @@ public:
LIGHTING_MODEL,
LIGHT,
LIGHT_AMBIENT_BUFFER,
FADE_PARAMETERS,
};
enum MAP {
@ -241,6 +249,7 @@ public:
OCCLUSION,
SCATTERING,
LIGHT_AMBIENT,
FADE_MASK,
};
};
@ -259,6 +268,8 @@ public:
int lightBufferUnit;
int lightAmbientBufferUnit;
int lightAmbientMapUnit;
int fadeMaskTextureUnit;
int fadeParameterBufferUnit;
};
using LocationsPointer = std::shared_ptr<Locations>;
@ -266,7 +277,7 @@ public:
using ItemSetter = std::function<void(const ShapePipeline&, render::Args*, const render::Item&)>;
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter, ItemSetter itemSetter) :
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter = nullptr, ItemSetter itemSetter = nullptr) :
pipeline(pipeline),
locations(locations),
_batchSetter(batchSetter),

View file

@ -0,0 +1,51 @@
//
// Transition.h
// Created by Olivier Prat on 07/07/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_render_Transition_h
#define hifi_render_Transition_h
#include "Item.h"
namespace render {
// This holds the current state for all transition event types applied to a render item
class Transition {
public:
enum Type {
ELEMENT_ENTER_DOMAIN = 0,
ELEMENT_LEAVE_DOMAIN,
BUBBLE_ISECT_OWNER,
BUBBLE_ISECT_TRESPASSER,
USER_ENTER_DOMAIN,
USER_LEAVE_DOMAIN,
AVATAR_CHANGE,
// Don't forget to modify Fade.slh to reflect the change in number of categories
TYPE_COUNT,
NONE = TYPE_COUNT
};
Type eventType{ ELEMENT_ENTER_DOMAIN };
ItemID itemId{ Item::INVALID_ITEM_ID };
ItemID boundItemId{ Item::INVALID_ITEM_ID };
double time{ 0.0 };
glm::vec3 noiseOffset{ 0.f, 0.f, 0.f };
glm::vec3 baseOffset{ 0.f, 0.f, 0.f };
glm::vec3 baseInvSize{ 1.f, 1.f, 1.f };
float threshold{ 0.f };
uint8_t isFinished{ 0 };
};
typedef std::shared_ptr<Transition> TransitionPointer;
typedef std::vector<Transition::Type> TransitionTypes;
}
#endif // hifi_render_Transition_h

View file

@ -0,0 +1,42 @@
#include "TransitionStage.h"
#include <algorithm>
using namespace render;
std::string TransitionStage::_name("Transition");
TransitionStage::Index TransitionStage::addTransition(ItemID itemId, Transition::Type type, ItemID boundId) {
Transition transition;
Index id;
transition.eventType = type;
transition.itemId = itemId;
transition.boundItemId = boundId;
id = _transitions.newElement(transition);
_activeTransitionIds.push_back(id);
return id;
}
void TransitionStage::removeTransition(Index index) {
TransitionIdList::iterator idIterator = std::find(_activeTransitionIds.begin(), _activeTransitionIds.end(), index);
if (idIterator != _activeTransitionIds.end()) {
_activeTransitionIds.erase(idIterator);
}
if (!_transitions.isElementFreed(index)) {
_transitions.freeElement(index);
}
}
TransitionStageSetup::TransitionStageSetup() {
}
void TransitionStageSetup::run(const RenderContextPointer& renderContext) {
auto stage = renderContext->_scene->getStage(TransitionStage::getName());
if (!stage) {
stage = std::make_shared<TransitionStage>();
renderContext->_scene->resetStage(TransitionStage::getName(), stage);
}
}

View file

@ -0,0 +1,68 @@
//
// TransitionStage.h
// Created by Olivier Prat on 07/07/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_render_TransitionStage_h
#define hifi_render_TransitionStage_h
#include "Stage.h"
#include "IndexedContainer.h"
#include "Engine.h"
#include "Transition.h"
namespace render {
// Transition stage to set up Transition-related effects
class TransitionStage : public render::Stage {
public:
static const std::string& getName() { return _name; }
using Index = indexed_container::Index;
static const Index INVALID_INDEX{ indexed_container::INVALID_INDEX };
using TransitionIdList = indexed_container::Indices;
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
bool checkTransitionId(Index index) const { return _transitions.checkIndex(index); }
const Transition& getTransition(Index TransitionId) const { return _transitions.get(TransitionId); }
Transition& editTransition(Index TransitionId) { return _transitions.edit(TransitionId); }
Index addTransition(ItemID itemId, Transition::Type type, ItemID boundId);
void removeTransition(Index index);
TransitionIdList::iterator begin() { return _activeTransitionIds.begin(); }
TransitionIdList::iterator end() { return _activeTransitionIds.end(); }
private:
using Transitions = indexed_container::IndexedVector<Transition>;
static std::string _name;
Transitions _transitions;
TransitionIdList _activeTransitionIds;
};
using TransitionStagePointer = std::shared_ptr<TransitionStage>;
class TransitionStageSetup {
public:
using JobModel = render::Job::Model<TransitionStageSetup>;
TransitionStageSetup();
void run(const RenderContextPointer& renderContext);
protected:
};
}
#endif // hifi_render_TransitionStage_h

View file

@ -155,6 +155,12 @@ public:
return concept->_data;
}
template <class T> const T& get() const {
auto concept = std::static_pointer_cast<typename T::JobModel>(_concept);
assert(concept);
return concept->_data;
}
virtual void run(const ContextPointer& renderContext) {
PerformanceTimer perfTimer(_name.c_str());
PROFILE_RANGE(render, _name.c_str());

View file

@ -40,6 +40,8 @@ public:
template <class T> Varying getN (uint8_t index) const { return get<T>()[index]; }
template <class T> Varying editN (uint8_t index) { return edit<T>()[index]; }
bool isNull() const { return _concept == nullptr; }
protected:
class Concept {
public:
@ -93,7 +95,7 @@ public:
}
virtual uint8_t length() const { return 2; }
Varying hasVarying() const { return Varying((*this)); }
Varying asVarying() const { return Varying((*this)); }
};
@ -126,7 +128,7 @@ public:
}
virtual uint8_t length() const { return 3; }
Varying hasVarying() const { return Varying((*this)); }
Varying asVarying() const { return Varying((*this)); }
};
template <class T0, class T1, class T2, class T3>
@ -163,7 +165,7 @@ public:
}
virtual uint8_t length() const { return 4; }
Varying hasVarying() const { return Varying((*this)); }
Varying asVarying() const { return Varying((*this)); }
};
@ -206,7 +208,7 @@ public:
}
virtual uint8_t length() const { return 5; }
Varying hasVarying() const { return Varying((*this)); }
Varying asVarying() const { return Varying((*this)); }
};
template <class T0, class T1, class T2, class T3, class T4, class T5>
@ -236,7 +238,7 @@ public:
const T5& get5() const { return std::get<5>((*this)).template get<T5>(); }
T5& edit5() { return std::get<5>((*this)).template edit<T5>(); }
Varying hasVarying() const { return Varying((*this)); }
Varying asVarying() const { return Varying((*this)); }
};
template <class T0, class T1, class T2, class T3, class T4, class T5, class T6>
@ -269,7 +271,7 @@ public:
const T6& get6() const { return std::get<6>((*this)).template get<T6>(); }
T6& edit6() { return std::get<6>((*this)).template edit<T6>(); }
Varying hasVarying() const { return Varying((*this)); }
Varying asVarying() const { return Varying((*this)); }
};
@ -281,6 +283,11 @@ public:
(*this)[i] = Varying(T());
}
}
VaryingArray(std::initializer_list<Varying> list) {
assert(list.size() == NUM);
std::copy(list.begin(), list.end(), std::array<Varying, NUM>::begin());
}
};
}

View file

@ -38,11 +38,12 @@ Item {
}
Label {
id: labelValue
text: sliderControl.value.toFixed(root.integral ? 0 : 2)
anchors.left: root.left
anchors.leftMargin: 200
anchors.top: root.top
anchors.topMargin: 7
anchors.topMargin: 15
}
Binding {
@ -56,7 +57,7 @@ Item {
Slider {
id: sliderControl
stepSize: root.integral ? 1.0 : 0.0
width: 150
width: root.width-130
height: 20
anchors.right: root.right
anchors.rightMargin: 8

View file

@ -0,0 +1,21 @@
//
// debugFade.js
// developer/utilities/render
//
// Olivier Prat, created on 30/04/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Set up the qml ui
var qml = Script.resolvePath('fade.qml');
var window = new OverlayWindow({
title: 'Fade',
source: qml,
width: 910,
height: 610,
});
window.setPosition(50, 50);
window.closed.connect(function() { Script.stop(); });

View file

@ -0,0 +1,397 @@
//
// fade.qml
// developer/utilities/render
//
// Olivier Prat, created on 30/04/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import "configSlider"
import "../lib/plotperf"
Column {
id: root
property var config: Render.getConfig("RenderMainView.Fade");
property var configEdit: Render.getConfig("RenderMainView.FadeEdit");
spacing: 8
Row {
spacing: 8
CheckBox {
text: "Edit Fade"
checked: root.configEdit["editFade"]
onCheckedChanged: {
root.configEdit["editFade"] = checked;
Render.getConfig("RenderMainView.DrawFadedOpaqueBounds").enabled = checked;
}
}
ComboBox {
id: categoryBox
width: 400
model: ["Elements enter/leave domain", "Bubble isect. - Owner POV", "Bubble isect. - Trespasser POV", "Another user leaves/arrives", "Changing an avatar"]
Timer {
id: postpone
interval: 100; running: false; repeat: false
onTriggered: { paramWidgetLoader.sourceComponent = paramWidgets }
}
onCurrentIndexChanged: {
root.config["editedCategory"] = currentIndex;
// This is a hack to be sure the widgets below properly reflect the change of category: delete the Component
// by setting the loader source to Null and then recreate it 100ms later
paramWidgetLoader.sourceComponent = undefined;
postpone.interval = 100
postpone.start()
}
}
}
Row {
spacing: 8
CheckBox {
text: "Manual"
checked: root.config["manualFade"]
onCheckedChanged: {
root.config["manualFade"] = checked;
}
}
ConfigSlider {
label: "Threshold"
integral: false
config: root.config
property: "manualThreshold"
max: 1.0
min: 0.0
width: 400
}
}
Action {
id: saveAction
text: "Save"
onTriggered: {
root.config.save()
}
}
Action {
id: loadAction
text: "Load"
onTriggered: {
root.config.load()
// This is a hack to be sure the widgets below properly reflect the change of category: delete the Component
// by setting the loader source to Null and then recreate it 500ms later
paramWidgetLoader.sourceComponent = undefined;
postpone.interval = 500
postpone.start()
}
}
Component {
id: paramWidgets
Column {
spacing: 8
CheckBox {
text: "Invert"
checked: root.config["isInverted"]
onCheckedChanged: { root.config["isInverted"] = checked }
}
Row {
spacing: 8
GroupBox {
title: "Base Gradient"
width: 450
Column {
spacing: 8
ConfigSlider {
label: "Size X"
integral: false
config: root.config
property: "baseSizeX"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Size Y"
integral: false
config: root.config
property: "baseSizeY"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Size Z"
integral: false
config: root.config
property: "baseSizeZ"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Level"
integral: false
config: root.config
property: "baseLevel"
max: 1.0
min: 0.0
width: 400
}
}
}
GroupBox {
title: "Noise Gradient"
width: 450
Column {
spacing: 8
ConfigSlider {
label: "Size X"
integral: false
config: root.config
property: "noiseSizeX"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Size Y"
integral: false
config: root.config
property: "noiseSizeY"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Size Z"
integral: false
config: root.config
property: "noiseSizeZ"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Level"
integral: false
config: root.config
property: "noiseLevel"
max: 1.0
min: 0.0
width: 400
}
}
}
}
Row {
spacing: 8
GroupBox {
title: "Edge"
width: 450
Column {
spacing: 8
ConfigSlider {
label: "Width"
integral: false
config: root.config
property: "edgeWidth"
max: 1.0
min: 0.0
width: 400
}
GroupBox {
title: "Inner color"
Column {
spacing: 8
ConfigSlider {
label: "Color R"
integral: false
config: root.config
property: "edgeInnerColorR"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Color G"
integral: false
config: root.config
property: "edgeInnerColorG"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Color B"
integral: false
config: root.config
property: "edgeInnerColorB"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Color intensity"
integral: false
config: root.config
property: "edgeInnerIntensity"
max: 5.0
min: 0.0
width: 400
}
}
}
GroupBox {
title: "Outer color"
Column {
spacing: 8
ConfigSlider {
label: "Color R"
integral: false
config: root.config
property: "edgeOuterColorR"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Color G"
integral: false
config: root.config
property: "edgeOuterColorG"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Color B"
integral: false
config: root.config
property: "edgeOuterColorB"
max: 1.0
min: 0.0
width: 400
}
ConfigSlider {
label: "Color intensity"
integral: false
config: root.config
property: "edgeOuterIntensity"
max: 5.0
min: 0.0
width: 400
}
}
}
}
}
Column {
GroupBox {
title: "Timing"
width: 450
Column {
spacing: 8
ConfigSlider {
label: "Duration"
integral: false
config: root.config
property: "duration"
max: 10.0
min: 0.1
width: 400
}
ComboBox {
width: 400
model: ["Linear", "Ease In", "Ease Out", "Ease In / Out"]
currentIndex: root.config["timing"]
onCurrentIndexChanged: {
root.config["timing"] = currentIndex;
}
}
GroupBox {
title: "Noise Animation"
Column {
spacing: 8
ConfigSlider {
label: "Speed X"
integral: false
config: root.config
property: "noiseSpeedX"
max: 1.0
min: -1.0
width: 400
}
ConfigSlider {
label: "Speed Y"
integral: false
config: root.config
property: "noiseSpeedY"
max: 1.0
min: -1.0
width: 400
}
ConfigSlider {
label: "Speed Z"
integral: false
config: root.config
property: "noiseSpeedZ"
max: 1.0
min: -1.0
width: 400
}
}
}
PlotPerf {
title: "Threshold"
height: parent.evalEvenHeight()
object: config
valueUnit: "%"
valueScale: 0.01
valueNumDigits: "1"
plots: [
{
prop: "threshold",
label: "Threshold",
color: "#FFBB77"
}
]
}
}
}
Row {
spacing: 8
Button {
action: saveAction
}
Button {
action: loadAction
}
}
}
}
}
}
Loader {
id: paramWidgetLoader
sourceComponent: paramWidgets
}
}

View file

@ -24,7 +24,7 @@
#include <TextureCache.h>
#ifdef DEFERRED_LIGHTING
extern void initDeferredPipelines(render::ShapePlumber& plumber);
extern void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter);
extern void initStencilPipeline(gpu::PipelinePointer& pipeline);
#endif
@ -77,7 +77,7 @@ void TestWindow::initGl() {
#ifdef DEFERRED_LIGHTING
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
deferredLightingEffect->init();
initDeferredPipelines(*_shapePlumber);
initDeferredPipelines(*_shapePlumber, nullptr, nullptr);
#endif
}