diff --git a/interface/resources/images/fadeMask.png b/interface/resources/images/fadeMask.png new file mode 100644 index 0000000000..9c342ba788 Binary files /dev/null and b/interface/resources/images/fadeMask.png differ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cc9bace9aa..3d7df0d579 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -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()->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(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 firstRun { Settings::firstRun, true }; // once the settings have been loaded, check if we need to flip the default for UserActivityLogger diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index bd545c64e0..3d48540a64 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -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::iterator avatarItr = _avatarsToFade.begin(); + const render::ScenePointer& scene = qApp->getMain3DScene(); while (avatarItr != _avatarsToFade.end()) { auto avatar = std::static_pointer_cast(*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()->removeFromIgnoreMuteSets(avatar->getSessionUUID()); DependencyManager::get()->avatarDisconnected(avatar->getSessionUUID()); + avatar->fadeOut(qApp->getMain3DScene(), removalReason); } _avatarsToFade.push_back(removedAvatar); } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index b6c7dcbd46..fc9371935c 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -96,7 +96,7 @@ void Overlays::cleanupOverlaysToDelete() { } while (!_overlaysToDelete.isEmpty()); } - if (transaction._removedItems.size() > 0) { + if (transaction.hasRemovedItems()) { scene->enqueueTransaction(transaction); } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index d775fe05f0..c619656cd9 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "Logging.h" @@ -61,7 +62,7 @@ namespace render { template <> uint32_t metaFetchMetaSubItems(const AvatarSharedPointer& avatar, ItemIDs& subItems) { auto avatarPtr = static_pointer_cast(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); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 2c75012209..5b64d79484 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -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; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index f8d155600a..d44ec04e9f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -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(self, _myItem); + auto renderPayload = std::make_shared(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(_myItem, [](RenderableEntityItemProxy& data) { + }); + + scene->enqueueTransaction(transaction); + } + else { + qCWarning(entitiesrenderer) << "SimpleRenderableEntityItem::notifyChanged(), Unexpected null scene, possibly during application shutdown"; + } +} diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index c848b10f6a..93cd524acd 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -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(self, _myItem); - auto renderPayload = std::make_shared(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(_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 }; }; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 911fdf4184..6a2b7678a8 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #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(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); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index a5ba7bedda..63c212891f 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -16,11 +16,14 @@ #include #include -#include + +#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 }; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index d2bf8e3532..86c547dd2d 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -17,22 +17,101 @@ #include #include +//#define POLYLINE_ENTITY_USE_FADE_EFFECT +#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT +# include +#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(); + return std::make_shared(_fadePipeline, nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + } else { +#endif + return std::make_shared(_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(payload)); + } + template <> const Item::Bound payloadGetBound(const PolyLinePayload::Pointer& payload) { + return payloadGetBound(std::static_pointer_cast(payload)); + } + template <> void payloadRender(const PolyLinePayload::Pointer& payload, RenderArgs* args) { + payloadRender(std::static_pointer_cast(payload), args); + } + template <> uint32_t metaFetchMetaSubItems(const PolyLinePayload::Pointer& payload, ItemIDs& subItems) { + return metaFetchMetaSubItems(std::static_pointer_cast(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(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(), &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(), &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(self, _myItem); + auto renderPayload = std::make_shared(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); -}; +} diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 8a62a761e0..4dda6da489 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -22,15 +22,48 @@ #include +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 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; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 6687d4e721..566a7cd488 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -20,6 +20,10 @@ #include #include "ModelScriptingInterface.h" +#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT +# include +#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 PolyVoxPayload::_pipeline; -std::shared_ptr 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(); 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(); 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(_wireframePipeline, nullptr, nullptr, nullptr); +#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT + if (key.isFaded()) { + const auto& fadeEffect = DependencyManager::get(); + if (key.isWireframe()) { + return std::make_shared(_wireframePipelines[1], nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + } + else { + return std::make_shared(_pipelines[1], nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + } } else { - return std::make_shared(_pipeline, nullptr, nullptr, nullptr); +#endif + if (key.isWireframe()) { + return std::make_shared(_wireframePipelines[0], nullptr, nullptr, nullptr); + } + else { + return std::make_shared(_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; } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 8f20a7a298..5741931ea2 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -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 _pipeline; - static std::shared_ptr _wireframePipeline; + static gpu::PipelinePointer _pipelines[2]; + static gpu::PipelinePointer _wireframePipelines[2]; PolyVoxPayload(EntityItemPointer owner) : _owner(owner), _bounds(AABox()) { } typedef render::Payload 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* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, int x, int y, int z); + #endif // hifi_RenderablePolyVoxEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 3f9497741f..ddebf07d66 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -20,6 +20,11 @@ #include #include +//#define SHAPE_ENTITY_USE_FADE_EFFECT +#ifdef SHAPE_ENTITY_USE_FADE_EFFECT +# include +#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(payload)); + } + template <> const Item::Bound payloadGetBound(const ShapePayload::Pointer& payload) { + return payloadGetBound(std::static_pointer_cast(payload)); + } + template <> void payloadRender(const ShapePayload::Pointer& payload, RenderArgs* args) { + payloadRender(std::static_pointer_cast(payload), args); + } + template <> uint32_t metaFetchMetaSubItems(const ShapePayload::Pointer& payload, ItemIDs& subItems) { + return metaFetchMetaSubItems(std::static_pointer_cast(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(self, _myItem); + auto renderPayload = std::make_shared(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()->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(); - 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(); + 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()->getShapeTriangleCount(MAPPING[_shape]); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index d603cdedef..9fb8c96a4c 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -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 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; 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; diff --git a/libraries/entities-renderer/src/paintStroke_fade.slf b/libraries/entities-renderer/src/paintStroke_fade.slf new file mode 100644 index 0000000000..cc037aeac4 --- /dev/null +++ b/libraries/entities-renderer/src/paintStroke_fade.slf @@ -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); +} diff --git a/libraries/entities-renderer/src/paintStroke_fade.slv b/libraries/entities-renderer/src/paintStroke_fade.slv new file mode 100644 index 0000000000..9f10fa5d91 --- /dev/null +++ b/libraries/entities-renderer/src/paintStroke_fade.slv @@ -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)$> +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/polyvox_fade.slf b/libraries/entities-renderer/src/polyvox_fade.slf new file mode 100644 index 0000000000..7af43be53f --- /dev/null +++ b/libraries/entities-renderer/src/polyvox_fade.slf @@ -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); +} diff --git a/libraries/entities-renderer/src/polyvox_fade.slv b/libraries/entities-renderer/src/polyvox_fade.slv new file mode 100644 index 0000000000..506b5d16e7 --- /dev/null +++ b/libraries/entities-renderer/src/polyvox_fade.slv @@ -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; +} diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index eac74fbdf9..f138244fa2 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -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(); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp index ffc8140b25..0c1b6880cb 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp @@ -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"); diff --git a/libraries/gpu/src/gpu/Inputs.slh b/libraries/gpu/src/gpu/Inputs.slh index 843d1059f2..109762136e 100644 --- a/libraries/gpu/src/gpu/Inputs.slh +++ b/libraries/gpu/src/gpu/Inputs.slh @@ -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@> diff --git a/libraries/gpu/src/gpu/Stream.cpp b/libraries/gpu/src/gpu/Stream.cpp index cdb972d8bf..427af1e78d 100644 --- a/libraries/gpu/src/gpu/Stream.cpp +++ b/libraries/gpu/src/gpu/Stream.cpp @@ -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; } diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index 0642131edf..336e34ecb4 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -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 }; diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh new file mode 100644 index 0000000000..b85a824ca3 --- /dev/null +++ b/libraries/render-utils/src/Fade.slh @@ -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@> \ No newline at end of file diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp new file mode 100644 index 0000000000..c94fe717f1 --- /dev/null +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -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 + +FadeEffect::FadeEffect() { + auto texturePath = PathUtils::resourcesPath() + "images/fadeMask.png"; + _maskMap = DependencyManager::get()->getImageTexture(texturePath, image::TextureUsage::STRICT_TEXTURE); +} + +void FadeEffect::build(render::Task::TaskConcept& task, const task::Varying& editableItems) { + auto editedFadeCategory = task.addJob("Fade"); + auto& fadeJob = task._jobs.back(); + _configurations = fadeJob.get().getConfigurationBuffer(); + + const auto fadeEditInput = FadeEditJob::Input(editableItems, editedFadeCategory).asVarying(); + task.addJob("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::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::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; +} diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h new file mode 100644 index 0000000000..4b4e401332 --- /dev/null +++ b/libraries/render-utils/src/FadeEffect.h @@ -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 +#include + +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 diff --git a/libraries/render-utils/src/FadeEffectJobs.cpp b/libraries/render-utils/src/FadeEffectJobs.cpp new file mode 100644 index 0000000000..90459cf0e6 --- /dev/null +++ b/libraries/render-utils/src/FadeEffectJobs.cpp @@ -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 +#include +#include + +#include + +#include + +#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::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(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(renderContext->jobConfig.get()); + auto scene = renderContext->args->_scene; + auto transitionStage = scene->getStage(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; +} diff --git a/libraries/render-utils/src/FadeEffectJobs.h b/libraries/render-utils/src/FadeEffectJobs.h new file mode 100644 index 0000000000..f827bb6e99 --- /dev/null +++ b/libraries/render-utils/src/FadeEffectJobs.h @@ -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 +#include +#include +#include + +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; + using JobModel = render::Job::ModelI; + + 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(); + + 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; + + 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 diff --git a/libraries/render-utils/src/Fade_shared.slh b/libraries/render-utils/src/Fade_shared.slh new file mode 100644 index 0000000000..7d1c0fb8bc --- /dev/null +++ b/libraries/render-utils/src/Fade_shared.slh @@ -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@> +// diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 5f2acff16f..34557e7b75 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -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(); // 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 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(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()->getWhiteTexture()); - }, - nullptr - ); - GeometryCache::_simpleTransparentPipeline = - std::make_shared(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()->getWhiteTexture()); - }, - nullptr - ); - GeometryCache::_simpleWirePipeline = - std::make_shared(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(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()->getWhiteTexture()); + } + ); +} + +render::ShapePipelinePointer GeometryCache::getFadingShapePipeline(bool textured, bool transparent, bool culled, + bool unlit, bool depthBias) { + auto fadeEffect = DependencyManager::get(); + auto fadeBatchSetter = fadeEffect->getBatchSetter(); + auto fadeItemSetter = fadeEffect->getItemStoredSetter(); + return std::make_shared(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()->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(); 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()->renderWireShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]); - } else { + } + else { DependencyManager::get()->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()(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()->renderWireFadeShapeInstances(batch, shape, data.count(), + buffers[INSTANCE_COLOR_BUFFER], buffers[INSTANCE_FADE_BUFFER1], buffers[INSTANCE_FADE_BUFFER2], buffers[INSTANCE_FADE_BUFFER3]); + } + else { + DependencyManager::get()->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); } diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index fa558a1151..40aa829444 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -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 _lastRegisteredGridBuffer; QHash _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 _simplePrograms; + + static QHash _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 diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index f6cb55deed..517fe97dba 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -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; diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 5d12e60ce3..99c14510b5 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -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 { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 497346c138..63aeacf80c 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -116,6 +116,7 @@ public: const QVector& vertices, const QVector& 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& coefficients) { _blendshapeCoefficients = coefficients; } const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 20c999019b..3ce2f01705 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -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(); +} + +void RenderDeferredTask::configure(const Config& config) +{ +} void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { - auto items = input.get(); + const auto& items = input.get(); + auto fadeEffect = DependencyManager::get(); // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); - 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("BeginOpaqueRangeTimer", "DrawOpaques"); - const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).hasVarying(); + const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).asVarying(); const auto prepareDeferredOutputs = task.addJob("PrepareDeferred", prepareDeferredInputs); const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); @@ -86,7 +98,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("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("DrawOpaqueDeferred", opaqueInputs, shapePlumber); task.addJob("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("LinearDepth", linearDepthPassInputs); const auto linearDepthTarget = linearDepthPassOutputs.getN(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("SurfaceGeometry", surfaceGeometryPassInputs); const auto surfaceGeometryFramebuffer = surfaceGeometryPassOutputs.getN(0); const auto curvatureFramebuffer = surfaceGeometryPassOutputs.getN(1); @@ -111,7 +123,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto scatteringResource = task.addJob("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("AmbientOcclusion", ambientOcclusionInputs); const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN(0); const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN(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("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", deferredLightingInputs); @@ -139,12 +151,12 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("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("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", 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("DrawOverlay3DOpaque", overlayOpaquesInputs, true); task.addJob("DrawOverlay3DTransparent", overlayTransparentsInputs, false); @@ -181,10 +193,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DebugDeferredBuffer", debugFramebuffers); const auto debugSubsurfaceScatteringInputs = DebugSubsurfaceScattering::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, - surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying(); + surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).asVarying(); task.addJob("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", debugAmbientOcclusionInputs); // Scene Octree Debugging job @@ -209,7 +221,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("Antialiasing", primaryFramebuffer); // Draw 2DWeb non AA - const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).hasVarying(); + const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).asVarying(); task.addJob("Draw2DWebSurfaces", nonAAOverlaysInputs, false); task.addJob("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(); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index fd7c5eb23b..e7575a1c95 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -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; + using Config = RenderDeferredTaskConfig; + using JobModel = render::Task::ModelI; - RenderDeferredTask() {} + RenderDeferredTask(); + void configure(const Config& config); void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); + }; #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index a77d741aa5..296eea1da8 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -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"); diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 6c3a58b7e5..c5949cb336 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -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); } } diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 03a2a4f9b1..ac80c03873 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -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 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("ShadowSetup"); diff --git a/libraries/render-utils/src/UpdateSceneTask.cpp b/libraries/render-utils/src/UpdateSceneTask.cpp index 2daee5fb5a..0e0c3f087b 100644 --- a/libraries/render-utils/src/UpdateSceneTask.cpp +++ b/libraries/render-utils/src/UpdateSceneTask.cpp @@ -13,11 +13,13 @@ #include #include "LightStage.h" #include "BackgroundStage.h" +#include #include "DeferredLightingEffect.h" void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { task.addJob("LightStageSetup"); task.addJob("BackgroundStageSetup"); + task.addJob("TransitionStageSetup"); task.addJob("DefaultLightingSetup"); diff --git a/libraries/render-utils/src/model_fade.slf b/libraries/render-utils/src/model_fade.slf new file mode 100644 index 0000000000..d232667660 --- /dev/null +++ b/libraries/render-utils/src/model_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_fade.slv b/libraries/render-utils/src/model_fade.slv new file mode 100644 index 0000000000..4c6bc534a9 --- /dev/null +++ b/libraries/render-utils/src/model_fade.slv @@ -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)$> +} diff --git a/libraries/render-utils/src/model_lightmap_fade.slf b/libraries/render-utils/src/model_lightmap_fade.slf new file mode 100644 index 0000000000..92d00a2046 --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_lightmap_fade.slv b/libraries/render-utils/src/model_lightmap_fade.slv new file mode 100644 index 0000000000..561049d614 --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_fade.slv @@ -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)$> +} + diff --git a/libraries/render-utils/src/model_lightmap_normal_map_fade.slf b/libraries/render-utils/src/model_lightmap_normal_map_fade.slf new file mode 100644 index 0000000000..825e84d666 --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_normal_map_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_lightmap_normal_map_fade.slv b/libraries/render-utils/src/model_lightmap_normal_map_fade.slv new file mode 100644 index 0000000000..4049fb0077 --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_normal_map_fade.slv @@ -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)$> +} diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf new file mode 100644 index 0000000000..791d5bf552 --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_lightmap_specular_map_fade.slf b/libraries/render-utils/src/model_lightmap_specular_map_fade.slf new file mode 100644 index 0000000000..e82018eefb --- /dev/null +++ b/libraries/render-utils/src/model_lightmap_specular_map_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_normal_map_fade.slf b/libraries/render-utils/src/model_normal_map_fade.slf new file mode 100644 index 0000000000..d8b864260c --- /dev/null +++ b/libraries/render-utils/src/model_normal_map_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_normal_map_fade.slv b/libraries/render-utils/src/model_normal_map_fade.slv new file mode 100644 index 0000000000..a71900d5c3 --- /dev/null +++ b/libraries/render-utils/src/model_normal_map_fade.slv @@ -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)$> +} diff --git a/libraries/render-utils/src/model_normal_specular_map_fade.slf b/libraries/render-utils/src/model_normal_specular_map_fade.slf new file mode 100644 index 0000000000..5492b24763 --- /dev/null +++ b/libraries/render-utils/src/model_normal_specular_map_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_shadow_fade.slf b/libraries/render-utils/src/model_shadow_fade.slf new file mode 100644 index 0000000000..c00eed622c --- /dev/null +++ b/libraries/render-utils/src/model_shadow_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_shadow_fade.slv b/libraries/render-utils/src/model_shadow_fade.slv new file mode 100644 index 0000000000..8762f1dd90 --- /dev/null +++ b/libraries/render-utils/src/model_shadow_fade.slv @@ -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)$> +} diff --git a/libraries/render-utils/src/model_specular_map_fade.slf b/libraries/render-utils/src/model_specular_map_fade.slf new file mode 100644 index 0000000000..6eb56c0929 --- /dev/null +++ b/libraries/render-utils/src/model_specular_map_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_translucent_fade.slf b/libraries/render-utils/src/model_translucent_fade.slf new file mode 100644 index 0000000000..c46b396ebc --- /dev/null +++ b/libraries/render-utils/src/model_translucent_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_translucent_unlit_fade.slf b/libraries/render-utils/src/model_translucent_unlit_fade.slf new file mode 100644 index 0000000000..6a77efe4ca --- /dev/null +++ b/libraries/render-utils/src/model_translucent_unlit_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/model_unlit_fade.slf b/libraries/render-utils/src/model_unlit_fade.slf new file mode 100644 index 0000000000..0fe9f2ebac --- /dev/null +++ b/libraries/render-utils/src/model_unlit_fade.slf @@ -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()); +} diff --git a/libraries/render-utils/src/simple_fade.slf b/libraries/render-utils/src/simple_fade.slf new file mode 100644 index 0000000000..245d32e81e --- /dev/null +++ b/libraries/render-utils/src/simple_fade.slf @@ -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); + } + } +} diff --git a/libraries/render-utils/src/simple_fade.slv b/libraries/render-utils/src/simple_fade.slv new file mode 100644 index 0000000000..3d9eb2c812 --- /dev/null +++ b/libraries/render-utils/src/simple_fade.slv @@ -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()$> +} \ No newline at end of file diff --git a/libraries/render-utils/src/simple_textured_fade.slf b/libraries/render-utils/src/simple_textured_fade.slf new file mode 100644 index 0000000000..025fe5fca6 --- /dev/null +++ b/libraries/render-utils/src/simple_textured_fade.slf @@ -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); + } +} \ No newline at end of file diff --git a/libraries/render-utils/src/simple_textured_unlit_fade.slf b/libraries/render-utils/src/simple_textured_unlit_fade.slf new file mode 100644 index 0000000000..6f03c6746f --- /dev/null +++ b/libraries/render-utils/src/simple_textured_unlit_fade.slf @@ -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); + } +} \ No newline at end of file diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf new file mode 100644 index 0000000000..20c7907bbe --- /dev/null +++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf @@ -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); + +} \ No newline at end of file diff --git a/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf new file mode 100644 index 0000000000..1c42a1f724 --- /dev/null +++ b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf @@ -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); +} \ No newline at end of file diff --git a/libraries/render-utils/src/skin_model_fade.slv b/libraries/render-utils/src/skin_model_fade.slv new file mode 100644 index 0000000000..fa8e1f8991 --- /dev/null +++ b/libraries/render-utils/src/skin_model_fade.slv @@ -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)$> +} diff --git a/libraries/render-utils/src/skin_model_normal_map_fade.slv b/libraries/render-utils/src/skin_model_normal_map_fade.slv new file mode 100644 index 0000000000..4e638866fc --- /dev/null +++ b/libraries/render-utils/src/skin_model_normal_map_fade.slv @@ -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; +} diff --git a/libraries/render-utils/src/skin_model_shadow.slf b/libraries/render-utils/src/skin_model_shadow.slf index 178ea7b387..e464d6e6c8 100644 --- a/libraries/render-utils/src/skin_model_shadow.slf +++ b/libraries/render-utils/src/skin_model_shadow.slf @@ -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. diff --git a/libraries/render-utils/src/skin_model_shadow_fade.slf b/libraries/render-utils/src/skin_model_shadow_fade.slf new file mode 100644 index 0000000000..aaf29076b8 --- /dev/null +++ b/libraries/render-utils/src/skin_model_shadow_fade.slf @@ -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); +} diff --git a/libraries/render-utils/src/skin_model_shadow_fade.slv b/libraries/render-utils/src/skin_model_shadow_fade.slv new file mode 100644 index 0000000000..7b27263569 --- /dev/null +++ b/libraries/render-utils/src/skin_model_shadow_fade.slv @@ -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)$> +} diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index 6a91081c95..12f9506286 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -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 }; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index a3175ffdec..8372231597 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -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::Hash, render::ShapeKey::KeyEqual>; SortedPipelines sortedPipelines; SortedShapes sortedShapes; - std::vector ownPipelineBucket; + std::vector< std::tuple > 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) { diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index f6b765cd9d..19953f3399 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -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); diff --git a/libraries/render/src/render/IndexedContainer.h b/libraries/render/src/render/IndexedContainer.h index bb1a9b72b7..4b51f8eb3c 100644 --- a/libraries/render/src/render/IndexedContainer.h +++ b/libraries/render/src/render/IndexedContainer.h @@ -12,7 +12,9 @@ #ifndef hifi_render_IndexedContainer_h #define hifi_render_IndexedContainer_h +#include #include +#include 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]; } diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index f80563bf73..9e4fc09701 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -13,8 +13,13 @@ #include #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; +} \ No newline at end of file diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 007b34395d..16e9700a8f 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -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 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(_data); } virtual int getLayer() const override { return payloadGetLayer(_data); } - virtual void render(RenderArgs* args) override { payloadRender(_data, args); } // Shape Type interface diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index d735afa52d..b9f65f48a0 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -65,6 +65,5 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto overlayTransparents = task.addJob("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); } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index f32293f001..b25480ae3a 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -26,12 +26,12 @@ public: OVERLAY_OPAQUE_SHAPE, OVERLAY_TRANSPARENT_SHAPE, BACKGROUND, - SPATIAL_SELECTION, NUM_BUCKETS }; - using Output = std::array; + using BucketList = render::VaryingArray; + using Output = render::VaryingSet2; using JobModel = render::Task::ModelO; RenderFetchCullSortTask() {} diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index b8f93c52c3..d2d3ad6de6 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -13,13 +13,16 @@ #include #include #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::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::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::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)); diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 199d9ce224..3b61a20f24 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -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 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 void updateItem(ItemID id, std::function func) { updateItem(id, std::make_shared>(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; + using Remove = ItemID; + using Update = std::tuple; + using TransitionAdd = std::tuple; + using TransitionQuery = std::tuple; + using TransitionReApply = ItemID; + using SelectionReset = Selection; + + using Resets = std::vector; + using Removes = std::vector; + using Updates = std::vector; + using TransitionAdds = std::vector; + using TransitionQueries = std::vector; + using TransitionReApplies = std::vector; + using SelectionResets = std::vector; + + Resets _resetItems; + Removes _removedItems; + Updates _updatedItems; + TransitionAdds _addedTransitions; + TransitionQueries _queriedTransitions; + TransitionReApplies _reAppliedTransitions; + SelectionResets _resetSelections; }; typedef std::queue 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 _IDAllocator{ 1 }; // first valid itemID will be One std::atomic _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); diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index c83c0b44fc..762b7712d7 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -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(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()) { diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 13daac2db7..f0749504eb 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -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; @@ -266,7 +277,7 @@ public: using ItemSetter = std::function; - 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), diff --git a/libraries/render/src/render/Transition.h b/libraries/render/src/render/Transition.h new file mode 100644 index 0000000000..622e6f69ce --- /dev/null +++ b/libraries/render/src/render/Transition.h @@ -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 TransitionPointer; + typedef std::vector TransitionTypes; +} + +#endif // hifi_render_Transition_h \ No newline at end of file diff --git a/libraries/render/src/render/TransitionStage.cpp b/libraries/render/src/render/TransitionStage.cpp new file mode 100644 index 0000000000..33ef829c64 --- /dev/null +++ b/libraries/render/src/render/TransitionStage.cpp @@ -0,0 +1,42 @@ +#include "TransitionStage.h" + +#include + +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(); + renderContext->_scene->resetStage(TransitionStage::getName(), stage); + } +} + diff --git a/libraries/render/src/render/TransitionStage.h b/libraries/render/src/render/TransitionStage.h new file mode 100644 index 0000000000..8dfef1b78e --- /dev/null +++ b/libraries/render/src/render/TransitionStage.h @@ -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; + + static std::string _name; + + Transitions _transitions; + TransitionIdList _activeTransitionIds; + }; + using TransitionStagePointer = std::shared_ptr; + + class TransitionStageSetup { + public: + using JobModel = render::Job::Model; + + TransitionStageSetup(); + void run(const RenderContextPointer& renderContext); + + protected: + }; + +} + +#endif // hifi_render_TransitionStage_h diff --git a/libraries/render/src/task/Task.h b/libraries/render/src/task/Task.h index f76ba92546..e99b33305c 100644 --- a/libraries/render/src/task/Task.h +++ b/libraries/render/src/task/Task.h @@ -155,6 +155,12 @@ public: return concept->_data; } + template const T& get() const { + auto concept = std::static_pointer_cast(_concept); + assert(concept); + return concept->_data; + } + virtual void run(const ContextPointer& renderContext) { PerformanceTimer perfTimer(_name.c_str()); PROFILE_RANGE(render, _name.c_str()); diff --git a/libraries/render/src/task/Varying.h b/libraries/render/src/task/Varying.h index 50f4acd414..0144801701 100644 --- a/libraries/render/src/task/Varying.h +++ b/libraries/render/src/task/Varying.h @@ -40,6 +40,8 @@ public: template Varying getN (uint8_t index) const { return get()[index]; } template Varying editN (uint8_t index) { return edit()[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 @@ -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 @@ -236,7 +238,7 @@ public: const T5& get5() const { return std::get<5>((*this)).template get(); } T5& edit5() { return std::get<5>((*this)).template edit(); } - Varying hasVarying() const { return Varying((*this)); } + Varying asVarying() const { return Varying((*this)); } }; template @@ -269,7 +271,7 @@ public: const T6& get6() const { return std::get<6>((*this)).template get(); } T6& edit6() { return std::get<6>((*this)).template edit(); } - 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 list) { + assert(list.size() == NUM); + std::copy(list.begin(), list.end(), std::array::begin()); + } }; } diff --git a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml index 996cf4b34c..021365686a 100644 --- a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml +++ b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml @@ -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 diff --git a/scripts/developer/utilities/render/debugFade.js b/scripts/developer/utilities/render/debugFade.js new file mode 100644 index 0000000000..b01c4b5e1f --- /dev/null +++ b/scripts/developer/utilities/render/debugFade.js @@ -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(); }); diff --git a/scripts/developer/utilities/render/fade.qml b/scripts/developer/utilities/render/fade.qml new file mode 100644 index 0000000000..1dffd0fbbb --- /dev/null +++ b/scripts/developer/utilities/render/fade.qml @@ -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 + } +} diff --git a/tests/gpu-test/src/TestWindow.cpp b/tests/gpu-test/src/TestWindow.cpp index 39043805b8..9ae78527cc 100644 --- a/tests/gpu-test/src/TestWindow.cpp +++ b/tests/gpu-test/src/TestWindow.cpp @@ -24,7 +24,7 @@ #include #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->init(); - initDeferredPipelines(*_shapePlumber); + initDeferredPipelines(*_shapePlumber, nullptr, nullptr); #endif }