From 4bf93f66df02f64aed7bdc9c49841a41af1ac7a7 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 26 Aug 2016 17:47:20 -0700 Subject: [PATCH 001/104] Cleaning up the lights and the light stage --- .../src/RenderableLightEntityItem.cpp | 73 +++++-- .../src/RenderableLightEntityItem.h | 79 ++++++- .../render-utils/src/DebugDeferredBuffer.cpp | 69 +++---- .../src/DeferredLightingEffect.cpp | 43 ++-- .../render-utils/src/DeferredLightingEffect.h | 3 + libraries/render-utils/src/LightStage.cpp | 38 +++- libraries/render-utils/src/LightStage.h | 192 +++++++++++++++++- .../render-utils/src/RenderShadowTask.cpp | 23 ++- .../render-utils/src/SubsurfaceScattering.cpp | 6 +- 9 files changed, 430 insertions(+), 96 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index b7f32cca65..3264ecb077 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -25,31 +25,70 @@ EntityItemPointer RenderableLightEntityItem::factory(const EntityItemID& entityI return entity; } +RenderableLightEntityItem::RenderableLightEntityItem(const EntityItemID& entityItemID) : LightEntityItem(entityItemID), + _light(std::make_shared()), + _lightStamp(-1) +{ +} + +namespace render { + template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload) { + return ItemKey::Builder::light(); + } + + template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload) { + if (payload) { + return payload->_bound; + } + return render::Item::Bound(); + } + template <> void payloadRender(const LightPayload::Pointer& payload, RenderArgs* args) { + if (args) { + if (payload) { + payload->render(args); + } + } + } +} + +void RenderableLightEntityItem::updateLightFromEntity() { + _light->setPosition(getPosition()); + _light->setOrientation(getRotation()); + + glm::vec3 dimensions = getDimensions(); + float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); + _light->setMaximumRadius(largestDiameter / 2.0f); + + _light->setColor(toGlm(getXColor())); + + float intensity = getIntensity() * (_isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f); + _light->setIntensity(intensity); + + _light->setFalloffRadius(getFalloffRadius()); + + + float exponent = getExponent(); + float cutoff = glm::radians(getCutoff()); + if (!_isSpotlight) { + _light->setType(model::Light::POINT); + } else { + _light->setType(model::Light::SPOT); + + _light->setSpotAngle(cutoff); + _light->setSpotExponent(exponent); + } +} + void RenderableLightEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableLightEntityItem::render"); assert(getType() == EntityTypes::Light); checkFading(); - glm::vec3 position = getPosition(); - glm::vec3 dimensions = getDimensions(); - glm::quat rotation = getRotation(); - float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); - glm::vec3 color = toGlm(getXColor()); + updateLightFromEntity(); - float intensity = getIntensity() * (_isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f); - float falloffRadius = getFalloffRadius(); - float exponent = getExponent(); - float cutoff = glm::radians(getCutoff()); + DependencyManager::get()->addLight(_light); - if (_isSpotlight) { - DependencyManager::get()->addSpotLight(position, largestDiameter / 2.0f, - color, intensity, falloffRadius, rotation, exponent, cutoff); - } else { - DependencyManager::get()->addPointLight(position, largestDiameter / 2.0f, - color, intensity, falloffRadius); - } - #ifdef WANT_DEBUG Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index 2db913db0d..c6e6aa7216 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -13,12 +13,32 @@ #define hifi_RenderableLightEntityItem_h #include +#include #include "RenderableEntityItem.h" + +class LightRenderItem { +public: + using Payload = render::Payload; + using Pointer = Payload::DataPointer; + + model::LightPointer _light; + + render::Item::Bound _bound; + + void render(RenderArgs* args); +}; + +namespace render { + template <> const ItemKey payloadGetKey(const LightRenderItem::Pointer& payload); + template <> const Item::Bound payloadGetBound(const LightRenderItem::Pointer& payload); + template <> void payloadRender(const LightRenderItem::Pointer& payload, RenderArgs* args); +} + class RenderableLightEntityItem : public LightEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - RenderableLightEntityItem(const EntityItemID& entityItemID) : LightEntityItem(entityItemID) { } + RenderableLightEntityItem(const EntityItemID& entityItemID); virtual void render(RenderArgs* args) override; virtual bool supportsDetailedRayIntersection() const override { return true; } @@ -27,7 +47,62 @@ public: BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override; - SIMPLE_RENDERABLE(); + void updateLightFromEntity(); + + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { + _myItem = scene->allocateID(); + auto renderPayload = std::make_shared(); + + render::Item::Status::Getters statusGetters; + makeEntityItemStatusGetters(self, statusGetters); + renderPayload->addStatusGetters(statusGetters); + + pendingChanges.resetItem(_myItem, renderPayload); + + return true; + } + + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { + pendingChanges.removeItem(_myItem); + render::Item::clearID(_myItem); + } + + virtual void locationChanged(bool tellPhysics = true) override { + EntityItem::locationChanged(tellPhysics); + if (!render::Item::isValidID(_myItem)) { + return; + } + + render::PendingChanges pendingChanges; + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); + + pendingChanges.updateItem(_myItem, [](RenderableEntityItemProxy& data) { + }); + + scene->enqueuePendingChanges(pendingChanges); + } + + virtual void dimensionsChanged() override { + EntityItem::dimensionsChanged(); + _renderHelper.notifyChanged(); + } + + void checkFading() { + bool transparent = isTransparent(); + if (transparent != _prevIsTransparent) { + _renderHelper.notifyChanged(); + _isFading = false; + _prevIsTransparent = transparent; + } + } + +private: + SimpleRenderableEntityItem _renderHelper; + bool _prevIsTransparent { isTransparent() }; + render::ItemID _myItem { render::Item::INVALID_ITEM_ID }; + + + }; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index e807ea429b..6278117b32 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -403,51 +403,48 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setPipeline(getPipeline(_mode, first)); - if (deferredFramebuffer) { - batch.setResourceTexture(Albedo, deferredFramebuffer->getDeferredColorTexture()); - batch.setResourceTexture(Normal, deferredFramebuffer->getDeferredNormalTexture()); - batch.setResourceTexture(Specular, deferredFramebuffer->getDeferredSpecularTexture()); - batch.setResourceTexture(Depth, deferredFramebuffer->getPrimaryDepthTexture()); - batch.setResourceTexture(Lighting, deferredFramebuffer->getLightingTexture()); - } - if (!lightStage.lights.empty()) { - batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getDepthStencilBuffer()); - } + if (deferredFramebuffer) { + batch.setResourceTexture(Albedo, deferredFramebuffer->getDeferredColorTexture()); + batch.setResourceTexture(Normal, deferredFramebuffer->getDeferredNormalTexture()); + batch.setResourceTexture(Specular, deferredFramebuffer->getDeferredSpecularTexture()); + batch.setResourceTexture(Depth, deferredFramebuffer->getPrimaryDepthTexture()); + batch.setResourceTexture(Lighting, deferredFramebuffer->getLightingTexture()); + } - if (linearDepthTarget) { - batch.setResourceTexture(LinearDepth, linearDepthTarget->getLinearDepthTexture()); - batch.setResourceTexture(HalfLinearDepth, linearDepthTarget->getHalfLinearDepthTexture()); - batch.setResourceTexture(HalfNormal, linearDepthTarget->getHalfNormalTexture()); - } - if (surfaceGeometryFramebuffer) { - batch.setResourceTexture(Curvature, surfaceGeometryFramebuffer->getCurvatureTexture()); - batch.setResourceTexture(DiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture()); - } - if (ambientOcclusionFramebuffer) { - batch.setResourceTexture(AmbientOcclusion, ambientOcclusionFramebuffer->getOcclusionTexture()); - batch.setResourceTexture(AmbientOcclusionBlurred, ambientOcclusionFramebuffer->getOcclusionBlurredTexture()); - } + if (linearDepthTarget) { + batch.setResourceTexture(LinearDepth, linearDepthTarget->getLinearDepthTexture()); + batch.setResourceTexture(HalfLinearDepth, linearDepthTarget->getHalfLinearDepthTexture()); + batch.setResourceTexture(HalfNormal, linearDepthTarget->getHalfNormalTexture()); + } + if (surfaceGeometryFramebuffer) { + batch.setResourceTexture(Curvature, surfaceGeometryFramebuffer->getCurvatureTexture()); + batch.setResourceTexture(DiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture()); + } + if (ambientOcclusionFramebuffer) { + batch.setResourceTexture(AmbientOcclusion, ambientOcclusionFramebuffer->getOcclusionTexture()); + batch.setResourceTexture(AmbientOcclusionBlurred, ambientOcclusionFramebuffer->getOcclusionBlurredTexture()); + } const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); const glm::vec2 bottomLeft(_size.x, _size.y); const glm::vec2 topRight(_size.z, _size.w); geometryBuffer->renderQuad(batch, bottomLeft, topRight, color); - batch.setResourceTexture(Albedo, nullptr); - batch.setResourceTexture(Normal, nullptr); - batch.setResourceTexture(Specular, nullptr); - batch.setResourceTexture(Depth, nullptr); - batch.setResourceTexture(Lighting, nullptr); - batch.setResourceTexture(Shadow, nullptr); - batch.setResourceTexture(LinearDepth, nullptr); - batch.setResourceTexture(HalfLinearDepth, nullptr); - batch.setResourceTexture(HalfNormal, nullptr); + batch.setResourceTexture(Albedo, nullptr); + batch.setResourceTexture(Normal, nullptr); + batch.setResourceTexture(Specular, nullptr); + batch.setResourceTexture(Depth, nullptr); + batch.setResourceTexture(Lighting, nullptr); + batch.setResourceTexture(Shadow, nullptr); + batch.setResourceTexture(LinearDepth, nullptr); + batch.setResourceTexture(HalfLinearDepth, nullptr); + batch.setResourceTexture(HalfNormal, nullptr); - batch.setResourceTexture(Curvature, nullptr); - batch.setResourceTexture(DiffusedCurvature, nullptr); + batch.setResourceTexture(Curvature, nullptr); + batch.setResourceTexture(DiffusedCurvature, nullptr); - batch.setResourceTexture(AmbientOcclusion, nullptr); - batch.setResourceTexture(AmbientOcclusionBlurred, nullptr); + batch.setResourceTexture(AmbientOcclusion, nullptr); + batch.setResourceTexture(AmbientOcclusionBlurred, nullptr); }); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 5dd4c0a232..800bf18a2c 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -99,20 +99,28 @@ void DeferredLightingEffect::init() { loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations); // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light - _globalLights.push_back(0); _allocatedLights.push_back(std::make_shared()); - model::LightPointer lp = _allocatedLights[0]; lp->setType(model::Light::SUN); - - // Add the global light to the light stage (for later shadow rendering) - _lightStage.addLight(lp); - lp->setDirection(glm::vec3(-1.0f)); lp->setColor(glm::vec3(1.0f)); lp->setIntensity(1.0f); lp->setType(model::Light::SUN); lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset::OLD_TOWN_SQUARE); + + // Add the global light to the light stage (for later shadow rendering) + _globalLights.push_back(_lightStage.addLight(lp)); + +} + +void DeferredLightingEffect::addLight(const model::LightPointer& light) { + assert(light); + auto lightID = _lightStage.addLight(light); + if (light->getType() == model::Light::POINT) { + _pointLights.push_back(lightID); + } else { + _spotLights.push_back(lightID); + } } void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color, @@ -459,11 +467,14 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c // Global directional light and ambient pass - assert(deferredLightingEffect->getLightStage().lights.size() > 0); - const auto& globalShadow = deferredLightingEffect->getLightStage().lights[0]->shadow; + assert(deferredLightingEffect->getLightStage().getNumLights() > 0); + auto lightAndShadow = deferredLightingEffect->getLightStage().getLightAndShadow(0); + const auto& globalShadow = lightAndShadow.second; // Bind the shadow buffer - batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow.map); + if (globalShadow) { + batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow->map); + } auto& program = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadow : deferredLightingEffect->_directionalLight; LightLocationsPtr locations = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadowLocations : deferredLightingEffect->_directionalLightLocations; @@ -492,7 +503,9 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c } if (locations->shadowTransformBuffer >= 0) { - batch.setUniformBuffer(locations->shadowTransformBuffer, globalShadow.getBuffer()); + if (globalShadow) { + batch.setUniformBuffer(locations->shadowTransformBuffer, globalShadow->getBuffer()); + } } batch.setPipeline(program); } @@ -573,7 +586,10 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform)); for (auto lightID : deferredLightingEffect->_pointLights) { - auto& light = deferredLightingEffect->_allocatedLights[lightID]; + auto light = deferredLightingEffect->getLightStage().getLight(lightID); + if (!light) { + continue; + } // IN DEBUG: light->setShowContour(true); batch.setUniformBuffer(deferredLightingEffect->_pointLightLocations->lightBufferUnit, light->getSchemaBuffer()); @@ -613,7 +629,10 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, auto& conePart = mesh->getPartBuffer().get(0); for (auto lightID : deferredLightingEffect->_spotLights) { - auto light = deferredLightingEffect->_allocatedLights[lightID]; + auto light = deferredLightingEffect->getLightStage().getLight(lightID); + if (!light) { + continue; + } // IN DEBUG: // light->setShowContour(true); batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, light->getSchemaBuffer()); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 466c58c36e..9c8d627610 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -43,6 +43,8 @@ class DeferredLightingEffect : public Dependency { public: void init(); + void addLight(const model::LightPointer& light); + /// Adds a point light to render for the current frame. void addPointLight(const glm::vec3& position, float radius, const glm::vec3& color = glm::vec3(0.0f, 0.0f, 0.0f), float intensity = 0.5f, float falloffRadius = 0.01f); @@ -58,6 +60,7 @@ public: void setGlobalLight(const model::LightPointer& light); const LightStage& getLightStage() { return _lightStage; } + void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; }; void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; } bool isAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; } diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index f1726feca6..5db1f99532 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -87,10 +87,36 @@ const glm::mat4& LightStage::Shadow::getProjection() const { return _frustum->getProjection(); } -const LightStage::LightPointer LightStage::addLight(model::LightPointer light) { - // Shadow stageShadow{light}; - LightPointer stageLight = std::make_shared(Shadow(light)); - stageLight->light = light; - lights.push_back(stageLight); - return stageLight; +LightStage::Index LightStage::findLight(const LightPointer& light) const { + auto found = _lightMap.find(light); + if (found != _lightMap.end()) { + return INVALID_INDEX; + } else { + return (*found).second; + } + +} + +LightStage::Index LightStage::addLight(const LightPointer& light) { + + auto found = _lightMap.find(light); + if (found == _lightMap.end()) { + auto lightId = _lights.newElement(light); + // Avoid failing to allocate a light, just pass + if (lightId != INVALID_INDEX) { + + // Allocate the matching Desc to the light + if (lightId >= _descs.size()) { + _descs.emplace_back(Desc()); + } else { + _descs.emplace(_descs.begin() + lightId, Desc()); + } + + // INsert the light and its index in the reverese map + _lightMap.insert(LightMap::value_type(light, lightId)); + } + return lightId; + } else { + return (*found).second; + } } diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 76d9a3b268..c6c09b9520 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -12,15 +12,161 @@ #ifndef hifi_render_utils_LightStage_h #define hifi_render_utils_LightStage_h +#include +#include + #include "gpu/Framebuffer.h" #include "model/Light.h" class ViewFrustum; +namespace indexed_elements { + + using Index = int32_t; + const Index MAXIMUM_INDEX { 1 << 30 }; + const Index INVALID_INDEX { -1 }; + using Indices = std::vector< Index >; + + template + class Allocator { + public: + Allocator() {} + Indices _freeIndices; + Index _nextNewIndex { 0 }; + + bool checkIndex(Index index) const { return ((index >= 0) && (index < _nextNewIndex)); } + Index getNumIndices() const { return _nextNewIndex - _freeIndices.size(); } + + Index allocateIndex() { + if (_freeIndices.empty()) { + Index index = _nextNewIndex; + if (index >= MaxNumElements) { + // abort! we are trying to go overboard with the total number of allocated elements + assert(false); + // This should never happen because Bricks are allocated along with the cells and there + // is already a cap on the cells allocation + return INVALID_INDEX; + } + _nextNewIndex++; + return index; + } else { + Index index = _freeIndices.back(); + _freeIndices.pop_back(); + return index; + } + } + + void freeIndex(Index index) { + if (checkIndex(index)) { + _freeIndices.push_back(index); + } + } + + void clear() { + _freeIndices.clear(); + _nextNewIndex = 0; + } + }; + + template + class IndexedVector { + Allocator _allocator; + public: + using Element = T; + using Elements = std::vector; + + Elements _elements; + + bool checkIndex(Index index) const { return _allocator.checkIndex(index); }; + Index getNumElements() const { return _allocator.getNumIndices(); } + + Index newElement(const Element& e) { + Index index = _allocator.allocateIndex(); + if (index != INVALID_INDEX) { + if (index < _elements.size()) { + _elements.emplace(_elements.begin() + index, e); + } else { + assert(index == _elements.size()); + _elements.emplace_back(e); + } + } + return index; + } + + const Element& freeElement(Index index) { + _allocator.freeIndex(index); + return _elements[index]; + } + + const Element& get(Index index) const { + return _elements[index]; + } + Element& edit(Index index) { + return _elements[index]; + } + }; + + template + class IndexedPointerVector { + Allocator _allocator; + public: + using Data = T; + using ElementPtr = std::shared_ptr; + using Elements = std::vector; + + Elements _elements; + + bool checkIndex(Index index) const { return _allocator.checkIndex(index); }; + Index getNumElements() const { return _allocator.getNumIndices(); } + + Index newElement(const ElementPtr& e) { + Index index = _allocator.allocateIndex(); + if (index != INVALID_INDEX) { + if (index < _elements.size()) { + _elements.emplace(_elements.begin() + index, e); + } else { + assert(index == _elements.size()); + _elements.emplace_back(e); + } + } + return index; + } + + ElementPtr freeElement(Index index) { + ElementPtr freed; + if (checkIndex(index)) { + _allocator.freeIndex(index); + freed = _elements[index]; + _elements[index].reset(); // really forget it + } + return freed; + } + + ElementPtr get(Index index) const { + if (checkIndex(index)) { + return _elements[index]; + } else { + return ElementPtr(); + } + } + }; + + + +}; + + // Light stage to set up light-related rendering tasks class LightStage { public: + using Index = indexed_elements::Index; + static const Index INVALID_INDEX { indexed_elements::INVALID_INDEX }; + + using LightPointer = model::LightPointer; + using Lights = indexed_elements::IndexedPointerVector; + using LightMap = std::unordered_map; + class Shadow { public: using UniformBufferView = gpu::BufferView; @@ -56,21 +202,45 @@ public: friend class Light; }; using ShadowPointer = std::shared_ptr; + using Shadows = indexed_elements::IndexedPointerVector; - class Light { - public: - Light(Shadow&& shadow) : shadow{ shadow } {} - - model::LightPointer light; - Shadow shadow; + struct Desc { + Index shadowId { INVALID_INDEX }; }; - using LightPointer = std::shared_ptr; - using Lights = std::vector; + using Descs = std::vector; - const LightPointer addLight(model::LightPointer light); - // TODO: removeLight - Lights lights; + Index findLight(const LightPointer& light) const; + Index addLight(const LightPointer& light); + + bool checkLightId(Index index) const { return _lights.checkIndex(index); } + + Index getNumLights() const { return _lights.getNumElements(); } + + LightPointer getLight(Index lightId) const { + return _lights.get(lightId); + } + Index getShadowId(Index lightId) const { + if (checkLightId(lightId)) { + return _descs[lightId].shadowId; + } else { + return INVALID_INDEX; + } + } + ShadowPointer getShadow(Index lightId) const { + return _shadows.get(getShadowId(lightId)); + } + + using LightAndShadow = std::pair; + LightAndShadow getLightAndShadow(Index lightId) const { + return LightAndShadow(getLight(lightId), getShadow(lightId)); + } + + Lights _lights; + LightMap _lightMap; + Descs _descs; + + Shadows _shadows; }; #endif diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 237c01cf28..2efbe7bf89 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -37,9 +37,14 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const assert(renderContext->args->hasViewFrustum()); const auto& lightStage = DependencyManager::get()->getLightStage(); - const auto globalLight = lightStage.lights[0]; - const auto& shadow = globalLight->shadow; - const auto& fbo = shadow.framebuffer; + + LightStage::Index globalLightIndex { 0 }; + + const auto globalLight = lightStage.getLight(globalLightIndex); + const auto shadow = lightStage.getShadow(globalLightIndex); + if (!shadow) return; + + const auto& fbo = shadow->framebuffer; RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { @@ -54,8 +59,8 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, true); - batch.setProjectionTransform(shadow.getProjection()); - batch.setViewTransform(shadow.getView(), false); + batch.setProjectionTransform(shadow->getProjection()); + batch.setViewTransform(shadow->getView(), false); auto shadowPipeline = _shapePlumber->pickPipeline(args, ShapeKey()); auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, ShapeKey::Builder().withSkinned()); @@ -140,10 +145,10 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const render } const auto& lightStage = DependencyManager::get()->getLightStage(); - const auto globalLight = lightStage.lights[0]; + const auto globalShadow = lightStage.getShadow(0); // If the global light is not set, bail - if (!globalLight) { + if (!globalShadow) { return; } @@ -153,10 +158,10 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const render auto nearClip = args->getViewFrustum().getNearClip(); float nearDepth = -args->_boomOffset.z; const int SHADOW_FAR_DEPTH = 20; - globalLight->shadow.setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH); + globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH); // Set the keylight render args - args->pushViewFrustum(*(globalLight->shadow.getFrustum())); + args->pushViewFrustum(*(globalShadow->getFrustum())); args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; // TODO: Allow runtime manipulation of culling ShouldRenderFunctor diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index f1aec66433..d78cbdb304 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -530,7 +530,7 @@ void DebugSubsurfaceScattering::run(const render::SceneContextPointer& sceneCont - const auto theLight = DependencyManager::get()->getLightStage().lights[0]; + const auto light = DependencyManager::get()->getLightStage().getLight(0); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); @@ -564,8 +564,8 @@ void DebugSubsurfaceScattering::run(const render::SceneContextPointer& sceneCont batch.setUniformBuffer(ScatteringTask_FrameTransformSlot, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(ScatteringTask_ParamSlot, scatteringResource->getParametersBuffer()); - if (theLight->light) { - batch.setUniformBuffer(ScatteringTask_LightSlot, theLight->light->getSchemaBuffer()); + if (light) { + batch.setUniformBuffer(ScatteringTask_LightSlot, light->getSchemaBuffer()); } batch.setResourceTexture(ScatteringTask_ScatteringTableSlot, scatteringTable); batch.setResourceTexture(ScatteringTask_CurvatureMapSlot, curvatureFramebuffer->getRenderBuffer(0)); From 3755a3fc32282942f244fc5ba329bf9e0a600fc4 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 29 Aug 2016 17:54:17 -0700 Subject: [PATCH 002/104] Add batch timing information vs gpu --- .../src/RenderableLightEntityItem.cpp | 135 +++++++++++------- .../src/RenderableLightEntityItem.h | 52 ++++--- libraries/entities/src/EntityItem.h | 3 + .../gpu-gl/src/gpu/gl/GLBackendQuery.cpp | 7 +- libraries/gpu-gl/src/gpu/gl/GLQuery.h | 1 + libraries/gpu/src/gpu/Query.cpp | 21 ++- libraries/gpu/src/gpu/Query.h | 11 +- .../src/AmbientOcclusionEffect.cpp | 4 +- .../render-utils/src/AmbientOcclusionEffect.h | 5 +- .../src/DeferredLightingEffect.cpp | 3 +- .../render-utils/src/DeferredLightingEffect.h | 5 +- .../render-utils/src/RenderDeferredTask.cpp | 2 +- .../render-utils/src/RenderDeferredTask.h | 20 ++- .../render-utils/src/SurfaceGeometryPass.cpp | 8 +- .../render-utils/src/SurfaceGeometryPass.h | 10 +- .../developer/utilities/render/statsGPU.qml | 41 ++++++ 16 files changed, 230 insertions(+), 98 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 3264ecb077..4a62a5b652 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -25,69 +25,29 @@ EntityItemPointer RenderableLightEntityItem::factory(const EntityItemID& entityI return entity; } -RenderableLightEntityItem::RenderableLightEntityItem(const EntityItemID& entityItemID) : LightEntityItem(entityItemID), - _light(std::make_shared()), - _lightStamp(-1) +RenderableLightEntityItem::RenderableLightEntityItem(const EntityItemID& entityItemID) : LightEntityItem(entityItemID) { } -namespace render { - template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload) { - return ItemKey::Builder::light(); +void RenderableLightEntityItem::updateLightFromEntity(render::PendingChanges& pendingChanges) { + if (!render::Item::isValidID(_myItem)) { + return; } - template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload) { - if (payload) { - return payload->_bound; - } - return render::Item::Bound(); - } - template <> void payloadRender(const LightPayload::Pointer& payload, RenderArgs* args) { - if (args) { - if (payload) { - payload->render(args); - } - } - } + + pendingChanges.updateItem(_myItem, [this](LightRenderItem& data) { + data.updateLightFromEntity(this); + }); } - -void RenderableLightEntityItem::updateLightFromEntity() { - _light->setPosition(getPosition()); - _light->setOrientation(getRotation()); - - glm::vec3 dimensions = getDimensions(); - float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); - _light->setMaximumRadius(largestDiameter / 2.0f); - - _light->setColor(toGlm(getXColor())); - - float intensity = getIntensity() * (_isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f); - _light->setIntensity(intensity); - - _light->setFalloffRadius(getFalloffRadius()); - - - float exponent = getExponent(); - float cutoff = glm::radians(getCutoff()); - if (!_isSpotlight) { - _light->setType(model::Light::POINT); - } else { - _light->setType(model::Light::SPOT); - - _light->setSpotAngle(cutoff); - _light->setSpotExponent(exponent); - } -} - +/* void RenderableLightEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableLightEntityItem::render"); assert(getType() == EntityTypes::Light); checkFading(); - updateLightFromEntity(); - DependencyManager::get()->addLight(_light); + // DependencyManager::get()->addLight(_light); #ifdef WANT_DEBUG Q_ASSERT(args->_batch); @@ -96,6 +56,7 @@ void RenderableLightEntityItem::render(RenderArgs* args) { DependencyManager::get()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f)); #endif }; +*/ bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, @@ -109,3 +70,77 @@ bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& ori // fix this mechanism. return _lightsArePickable; } + + + +namespace render { + template <> const ItemKey payloadGetKey(const LightRenderItem::Pointer& payload) { + return ItemKey::Builder::light(); + } + + template <> const Item::Bound payloadGetBound(const LightRenderItem::Pointer& payload) { + if (payload) { + return payload->_bound; + } + return render::Item::Bound(); + } + template <> void payloadRender(const LightRenderItem::Pointer& payload, RenderArgs* args) { + if (args) { + if (payload) { + payload->render(args); + } + } + } +} + +LightRenderItem::LightRenderItem() : +_light(std::make_shared()) +{ +} + +void LightRenderItem::updateLightFromEntity(RenderableLightEntityItem* entity) { + _light->setPosition(entity->getPosition()); + _light->setOrientation(entity->getRotation()); + + bool success; + _bound = entity->getAABox(success); + if (!success) { + _bound = render::Item::Bound(); + } + + glm::vec3 dimensions = entity->getDimensions(); + float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); + _light->setMaximumRadius(largestDiameter / 2.0f); + + _light->setColor(toGlm(entity->getXColor())); + + float intensity = entity->getIntensity();//* entity->getFadingRatio(); + _light->setIntensity(intensity); + + _light->setFalloffRadius(entity->getFalloffRadius()); + + + float exponent = entity->getExponent(); + float cutoff = glm::radians(entity->getCutoff()); + if (!entity->getIsSpotlight()) { + _light->setType(model::Light::POINT); + } else { + _light->setType(model::Light::SPOT); + + _light->setSpotAngle(cutoff); + _light->setSpotExponent(exponent); + } + +} + + +void LightRenderItem::render(RenderArgs* args) { + + //updateLightFromEntity(); + + DependencyManager::get()->addLight(_light); + +} + + + diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index c6e6aa7216..1b6deae6ad 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -16,6 +16,7 @@ #include #include "RenderableEntityItem.h" +class RenderableLightEntityItem; class LightRenderItem { public: @@ -26,7 +27,11 @@ public: render::Item::Bound _bound; + LightRenderItem(); void render(RenderArgs* args); + + void updateLightFromEntity(RenderableLightEntityItem* entity); + }; namespace render { @@ -40,18 +45,22 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableLightEntityItem(const EntityItemID& entityItemID); - virtual void render(RenderArgs* args) override; + virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override; - void updateLightFromEntity(); + void updateLightFromEntity(render::PendingChanges& pendingChanges); virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { _myItem = scene->allocateID(); - auto renderPayload = std::make_shared(); + + auto renderItem = std::make_shared(); + renderItem->updateLightFromEntity(this); + + auto renderPayload = std::make_shared(renderItem); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(self, statusGetters); @@ -69,6 +78,25 @@ public: virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); + notifyChanged(); + } + + virtual void dimensionsChanged() override { + EntityItem::dimensionsChanged(); + notifyChanged(); + } + + void checkFading() { + bool transparent = isTransparent(); + if (transparent != _prevIsTransparent) { + notifyChanged(); + _isFading = false; + _prevIsTransparent = transparent; + } + } + + void notifyChanged() { + if (!render::Item::isValidID(_myItem)) { return; } @@ -76,28 +104,12 @@ public: render::PendingChanges pendingChanges; render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - pendingChanges.updateItem(_myItem, [](RenderableEntityItemProxy& data) { - }); + updateLightFromEntity(pendingChanges); scene->enqueuePendingChanges(pendingChanges); } - virtual void dimensionsChanged() override { - EntityItem::dimensionsChanged(); - _renderHelper.notifyChanged(); - } - - void checkFading() { - bool transparent = isTransparent(); - if (transparent != _prevIsTransparent) { - _renderHelper.notifyChanged(); - _isFading = false; - _prevIsTransparent = transparent; - } - } - private: - SimpleRenderableEntityItem _renderHelper; bool _prevIsTransparent { isTransparent() }; render::ItemID _myItem { render::Item::INVALID_ITEM_ID }; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e572bf4de8..bbc0a1728c 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -446,6 +446,9 @@ public: virtual void setProxyWindow(QWindow* proxyWindow) {} virtual QObject* getEventHandler() { return nullptr; } + bool isFading() const { return _isFading; } + float getFadingRatio() const { return (isFading() ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f); } + protected: void setSimulated(bool simulated) { _simulated = simulated; } diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp index 60b204ba60..b693991f1c 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp @@ -25,6 +25,7 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) { auto query = batch._queries.get(batch._params[paramOffset]._uint); GLQuery* glquery = syncGPUObject(*query); if (glquery) { + glGetInteger64v(GL_TIMESTAMP, (GLint64*) &glquery->_batchTimeRange); if (timeElapsed) { glBeginQuery(GL_TIME_ELAPSED, glquery->_endqo); } else { @@ -43,6 +44,10 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) { } else { glQueryCounter(glquery->_endqo, GL_TIMESTAMP); } + GLint64 now; + glGetInteger64v(GL_TIMESTAMP, &now); + glquery->_batchTimeRange = now - glquery->_batchTimeRange; + (void)CHECK_GL_ERROR(); } } @@ -61,7 +66,7 @@ void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) { glGetQueryObjectui64v(glquery->_endqo, GL_QUERY_RESULT, &end); glquery->_result = end - start; } - query->triggerReturnHandler(glquery->_result); + query->triggerReturnHandler(glquery->_result, ((double) glquery->_batchTimeRange) / 1000000.0); } (void)CHECK_GL_ERROR(); } diff --git a/libraries/gpu-gl/src/gpu/gl/GLQuery.h b/libraries/gpu-gl/src/gpu/gl/GLQuery.h index 4bed659ba3..61efd20e78 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLQuery.h +++ b/libraries/gpu-gl/src/gpu/gl/GLQuery.h @@ -48,6 +48,7 @@ public: const GLuint& _endqo = { _id }; const GLuint _beginqo = { 0 }; GLuint64 _result { (GLuint64)-1 }; + GLuint64 _batchTimeRange; protected: GLQuery(const std::weak_ptr& backend, const Query& query, GLuint endId, GLuint beginId) : Parent(backend, query, endId), _beginqo(beginId) {} diff --git a/libraries/gpu/src/gpu/Query.cpp b/libraries/gpu/src/gpu/Query.cpp index 76c239b1e0..e5653a74f4 100644 --- a/libraries/gpu/src/gpu/Query.cpp +++ b/libraries/gpu/src/gpu/Query.cpp @@ -28,8 +28,14 @@ double Query::getElapsedTime() const { return ((double)_queryResult) / 1000000.0; } -void Query::triggerReturnHandler(uint64_t queryResult) { +double Query::getBatchPerformTime() const { + return _batchPerformTime; +} + +void Query::triggerReturnHandler(uint64_t queryResult, double cpuTime) { _queryResult = queryResult; + _batchPerformTime = cpuTime; + if (_returnHandler) { _returnHandler(*this); } @@ -41,7 +47,10 @@ RangeTimer::RangeTimer() { _timerQueries.push_back(std::make_shared([&, i] (const Query& query) { _tailIndex ++; auto elapsedTime = query.getElapsedTime(); - _movingAverage.addSample(elapsedTime); + _movingAverageGPU.addSample(elapsedTime); + + auto elapsedTimeCPU = query.getBatchPerformTime(); + _movingAverageCPU.addSample(elapsedTimeCPU); })); } } @@ -66,6 +75,10 @@ void RangeTimer::end(gpu::Batch& batch) { } } -double RangeTimer::getAverage() const { - return _movingAverage.average; +double RangeTimer::getAverageGPU() const { + return _movingAverageGPU.average; +} + +double RangeTimer::getAverageCPU() const { + return _movingAverageCPU.average; } \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h index 48b9d0a0d5..9bcedb9d17 100644 --- a/libraries/gpu/src/gpu/Query.h +++ b/libraries/gpu/src/gpu/Query.h @@ -32,12 +32,15 @@ namespace gpu { double getElapsedTime() const; + double getBatchPerformTime() const; + const GPUObjectPointer gpuObject {}; - void triggerReturnHandler(uint64_t queryResult); + void triggerReturnHandler(uint64_t queryResult, double cpuTime); protected: Handler _returnHandler; uint64_t _queryResult = 0; + double _batchPerformTime { 0.0 }; }; typedef std::shared_ptr QueryPointer; @@ -53,7 +56,8 @@ namespace gpu { void begin(gpu::Batch& batch); void end(gpu::Batch& batch); - double getAverage() const; + double getAverageGPU() const; + double getAverageCPU() const; protected: @@ -62,7 +66,8 @@ namespace gpu { gpu::Queries _timerQueries; int _headIndex = -1; int _tailIndex = -1; - MovingAverage _movingAverage; + MovingAverage _movingAverageCPU; + MovingAverage _movingAverageGPU; int rangeIndex(int index) const { return (index % QUERY_QUEUE_SIZE); } }; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 86223e9877..d419f619cb 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -432,7 +432,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext }); // Update the timer - std::static_pointer_cast(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage(); + auto config = std::static_pointer_cast(renderContext->jobConfig); + config->gpuTime = _gpuTimer.getAverageGPU(); + config->gpuBatchTime = _gpuTimer.getAverageCPU(); } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 8bb4600d3c..e10d5fd0c7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -69,6 +69,7 @@ class AmbientOcclusionEffectConfig : public render::Job::Config::Persistent { Q_PROPERTY(int resolutionLevel MEMBER resolutionLevel WRITE setResolutionLevel) Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius) Q_PROPERTY(double gpuTime READ getGpuTime) + Q_PROPERTY(double gpuBatchTime READ getGpuBatchTime) public: AmbientOcclusionEffectConfig() : render::Job::Config::Persistent("Ambient Occlusion", false) {} @@ -85,6 +86,7 @@ public: void setResolutionLevel(int level) { resolutionLevel = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL)); emit dirty(); } void setBlurRadius(int radius) { blurRadius = std::max(0, std::min(MAX_BLUR_RADIUS, radius)); emit dirty(); } double getGpuTime() { return gpuTime; } + double getGpuBatchTime() { return gpuBatchTime; } float radius{ 0.5f }; float perspectiveScale{ 1.0f }; @@ -99,7 +101,8 @@ public: bool ditheringEnabled{ true }; // randomize the distribution of taps per pixel, should always be true bool borderingEnabled{ true }; // avoid evaluating information from non existing pixels out of the frame, should always be true bool fetchMipsEnabled{ true }; // fetch taps in sub mips to otpimize cache, should always be true - double gpuTime{ 0.0 }; + double gpuTime { 0.0 }; + double gpuBatchTime { 0.0 }; signals: void dirty(); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 800bf18a2c..331762f9ac 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -733,5 +733,6 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo }); auto config = std::static_pointer_cast(renderContext->jobConfig); - config->gpuTime = _gpuTimer.getAverage(); + config->gpuTime = _gpuTimer.getAverageGPU(); + config->gpuBatchTime = _gpuTimer.getAverageCPU(); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 9c8d627610..83c8a8e6b9 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -168,12 +168,15 @@ public: class RenderDeferredConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(double gpuTime READ getGpuTime) + Q_PROPERTY(double gpuBatchTime READ getGpuBatchTime) public: RenderDeferredConfig() : render::Job::Config(true) {} double getGpuTime() { return gpuTime; } + double getGpuBatchTime() { return gpuBatchTime; } - double gpuTime{ 0.0 }; + double gpuTime { 0.0 }; + double gpuBatchTime { 0.0 }; signals: void dirty(); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index cedc2ef45e..2ff122ab1a 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -245,7 +245,7 @@ void EndGPURangeTimer::run(const render::SceneContextPointer& sceneContext, cons }); auto config = std::static_pointer_cast(renderContext->jobConfig); - config->gpuTime = timer->getAverage(); + config->setTime(timer->getAverageGPU(), timer->getAverageCPU()); } diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 749cc09edc..5b321abc54 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -33,12 +33,19 @@ protected: class GPURangeTimerConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(double gpuTime READ getGpuTime) + Q_PROPERTY(double gpuBatchTime READ getGpuBatchTime) public: double getGpuTime() { return gpuTime; } + double getGpuBatchTime() { return gpuBatchTime; } + void setTime(double gpu, double batch) { + gpuTime = gpu; + gpuBatchTime = batch; + } + protected: - friend class EndGPURangeTimer; double gpuTime; + double gpuBatchTime; }; class EndGPURangeTimer { @@ -143,16 +150,7 @@ protected: gpu::PipelinePointer getOpaquePipeline(); }; -class DrawBackgroundDeferredConfig : public render::Job::Config { - Q_OBJECT - Q_PROPERTY(double gpuTime READ getGpuTime) -public: - double getGpuTime() { return gpuTime; } - -protected: - friend class DrawBackgroundDeferred; - double gpuTime; -}; +using DrawBackgroundDeferredConfig = GPURangeTimerConfig; class DrawBackgroundDeferred { public: diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 7a5a34c756..9f37f72e3a 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -201,7 +201,9 @@ void LinearDepthPass::run(const render::SceneContextPointer& sceneContext, const }); auto config = std::static_pointer_cast(renderContext->jobConfig); - config->gpuTime = _gpuTimer.getAverage(); + config->gpuTime = _gpuTimer.getAverageGPU(); + config->gpuBatchTime = _gpuTimer.getAverageCPU(); + } @@ -524,8 +526,8 @@ void SurfaceGeometryPass::run(const render::SceneContextPointer& sceneContext, c auto config = std::static_pointer_cast(renderContext->jobConfig); - config->gpuTime = _gpuTimer.getAverage(); -} + config->gpuTime = _gpuTimer.getAverageGPU(); + config->gpuBatchTime = _gpuTimer.getAverageCPU(); } const gpu::PipelinePointer& SurfaceGeometryPass::getCurvaturePipeline() { diff --git a/libraries/render-utils/src/SurfaceGeometryPass.h b/libraries/render-utils/src/SurfaceGeometryPass.h index 24f0c56cdd..09d9876fc6 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.h +++ b/libraries/render-utils/src/SurfaceGeometryPass.h @@ -66,12 +66,16 @@ using LinearDepthFramebufferPointer = std::shared_ptr; class LinearDepthPassConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(double gpuTime READ getGpuTime) + Q_PROPERTY(double gpuBatchTime READ getGpuBatchTime) + public: LinearDepthPassConfig() : render::Job::Config(true) {} double getGpuTime() { return gpuTime; } + double getGpuBatchTime() { return gpuBatchTime; } double gpuTime{ 0.0 }; + double gpuBatchTime { 0.0 }; signals: void dirty(); @@ -159,6 +163,8 @@ class SurfaceGeometryPassConfig : public render::Job::Config { Q_PROPERTY(float diffuseDepthThreshold MEMBER diffuseDepthThreshold NOTIFY dirty) Q_PROPERTY(double gpuTime READ getGpuTime) + Q_PROPERTY(double gpuBatchTime READ getGpuBatchTime) + public: SurfaceGeometryPassConfig() : render::Job::Config(true) {} @@ -170,8 +176,10 @@ public: float diffuseDepthThreshold{ 1.0f }; double getGpuTime() { return gpuTime; } + double getGpuBatchTime() { return gpuBatchTime; } - double gpuTime{ 0.0 }; + double gpuTime { 0.0 }; + double gpuBatchTime { 0.0 }; signals: void dirty(); diff --git a/scripts/developer/utilities/render/statsGPU.qml b/scripts/developer/utilities/render/statsGPU.qml index 74bd376a00..81e70892d4 100644 --- a/scripts/developer/utilities/render/statsGPU.qml +++ b/scripts/developer/utilities/render/statsGPU.qml @@ -69,6 +69,47 @@ Item { } ] } + + PlotPerf { + title: "Batch Timing" + height: parent.evalEvenHeight() + object: parent.drawOpaqueConfig + valueUnit: "ms" + valueScale: 1 + valueNumDigits: "4" + plots: [ + { + object: Render.getConfig("OpaqueRangeTimer"), + prop: "gpuBatchTime", + label: "Opaque", + color: "#FFFFFF" + }, + { + object: Render.getConfig("LinearDepth"), + prop: "gpuBatchTime", + label: "LinearDepth", + color: "#00FF00" + },{ + object: Render.getConfig("SurfaceGeometry"), + prop: "gpuBatchTime", + label: "SurfaceGeometry", + color: "#00FFFF" + }, + { + object: Render.getConfig("RenderDeferred"), + prop: "gpuBatchTime", + label: "DeferredLighting", + color: "#FF00FF" + } + , + { + object: Render.getConfig("ToneAndPostRangeTimer"), + prop: "gpuBatchTime", + label: "tone and post", + color: "#FF0000" + } + ] + } } } From 93aec28c7b2912d52f025134a7f0904c0ba96a3d Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 30 Aug 2016 14:54:58 -0700 Subject: [PATCH 003/104] Less warning --- libraries/render-utils/src/DeferredLightingEffect.cpp | 2 ++ libraries/render-utils/src/LightStage.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 331762f9ac..b21bee91da 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -710,6 +710,8 @@ void RenderDeferred::configure(const Config& config) { } void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const Inputs& inputs) { + PROFILE_RANGE("DeferredLighting"); + auto deferredTransform = inputs.get0(); auto deferredFramebuffer = inputs.get1(); auto lightingModel = inputs.get2(); diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index c6c09b9520..a050bb393f 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -36,7 +36,7 @@ namespace indexed_elements { Index _nextNewIndex { 0 }; bool checkIndex(Index index) const { return ((index >= 0) && (index < _nextNewIndex)); } - Index getNumIndices() const { return _nextNewIndex - _freeIndices.size(); } + Index getNumIndices() const { return _nextNewIndex - (Index) _freeIndices.size(); } Index allocateIndex() { if (_freeIndices.empty()) { From b563e280e4d683a48ee2ddaf1024dea509c18136 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 31 Aug 2016 13:55:41 -0700 Subject: [PATCH 004/104] Commuting the LIghtEntityItem changes correctly to the LightRenderItem --- .../src/RenderableLightEntityItem.h | 10 ++++-- libraries/entities/src/EntityItem.cpp | 4 +++ libraries/entities/src/EntityItem.h | 7 ++++ libraries/entities/src/LightEntityItem.cpp | 34 +++++++++++++------ libraries/entities/src/LightEntityItem.h | 26 ++++++++++++-- libraries/shared/src/shared/NsightHelpers.cpp | 9 +++-- 6 files changed, 72 insertions(+), 18 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index 1b6deae6ad..883af056aa 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -45,7 +45,6 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableLightEntityItem(const EntityItemID& entityItemID); - virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, @@ -71,6 +70,13 @@ public: return true; } + virtual void somethingChangedNotification() override { + if (_lightPropertiesChanged) { + notifyChanged(); + } + LightEntityItem::somethingChangedNotification(); + } + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { pendingChanges.removeItem(_myItem); render::Item::clearID(_myItem); @@ -113,7 +119,7 @@ private: bool _prevIsTransparent { isTransparent() }; render::ItemID _myItem { render::Item::INVALID_ITEM_ID }; - + // Dirty flag turn true when either setSubClassProperties or readEntitySubclassDataFromBuffer is changing a value }; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 68636415f8..849019fc4b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1313,6 +1313,10 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { somethingChanged = true; } + // Now check the sub classes + somethingChanged |= setSubClassProperties(properties); + + // Finally notify if change detected if (somethingChanged) { uint64_t now = usecTimestampNow(); #ifdef WANT_DEBUG diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index bbc0a1728c..85080ccc0a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -90,7 +90,14 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; /// returns true if something changed + // THis function calls setSubClass properties and detects if any property changes value. + // If something changed then the "somethingChangedNotification" calls happens virtual bool setProperties(const EntityItemProperties& properties); + + // Set properties for sub class so they can add their own properties + // it does nothing in the root eclass + virtual bool setSubClassProperties(const EntityItemProperties& properties) { return false; } + // Update properties with empty parent id and globalized/absolute values (applying offset), and apply (non-empty) log template to args id, name-or-type, parent id. void globalizeProperties(EntityItemProperties& properties, const QString& messageTemplate = QString(), const glm::vec3& offset = glm::vec3(0.0f)) const; diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 1be133463c..ad05b33e3d 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -70,6 +70,7 @@ EntityItemProperties LightEntityItem::getProperties(EntityPropertyFlags desiredP void LightEntityItem::setFalloffRadius(float value) { _falloffRadius = glm::max(value, 0.0f); + _lightPropertiesChanged = true; } void LightEntityItem::setIsSpotlight(bool value) { @@ -85,6 +86,7 @@ void LightEntityItem::setIsSpotlight(bool value) { float maxDimension = glm::max(dimensions.x, dimensions.y, dimensions.z); setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); } + _lightPropertiesChanged = true; } } @@ -98,10 +100,26 @@ void LightEntityItem::setCutoff(float value) { const float width = length * glm::sin(glm::radians(_cutoff)); setDimensions(glm::vec3(width, width, length)); } + _lightPropertiesChanged = true; } bool LightEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "LightEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties.getLastEdited()); + } + return somethingChanged; +} + +bool LightEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = EntityItem::setSubClassProperties(properties); // set the properties in our base class SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); @@ -110,19 +128,10 @@ bool LightEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(cutoff, setCutoff); SET_ENTITY_PROPERTY_FROM_PROPERTIES(falloffRadius, setFalloffRadius); - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "LightEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } return somethingChanged; } + int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -193,3 +202,8 @@ void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_CUTOFF, getCutoff()); APPEND_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, getFalloffRadius()); } + +void LightEntityItem::somethingChangedNotification() { + EntityItem::somethingChangedNotification(); + _lightPropertiesChanged = false; +} diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 31ef012f6a..cb23c2357f 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -31,9 +31,16 @@ public: /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately virtual void setDimensions(const glm::vec3& value) override; + virtual bool setProperties(const EntityItemProperties& properties) override; + virtual bool setSubClassProperties(const EntityItemProperties& properties) override; + // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; - virtual bool setProperties(const EntityItemProperties& properties) override; + + /// Override this in your derived class if you'd like to be informed when something about the state of the entity + /// has changed. This will be called with properties change or when new data is loaded from a stream + /// Overriding this function to capture the information that a light properties has changed + virtual void somethingChangedNotification() override; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; @@ -60,6 +67,7 @@ public: _color[RED_INDEX] = value.red; _color[GREEN_INDEX] = value.green; _color[BLUE_INDEX] = value.blue; + _lightPropertiesChanged = true; } bool getIsSpotlight() const { return _isSpotlight; } @@ -69,13 +77,19 @@ public: void setIgnoredAttenuation(float value) { } float getIntensity() const { return _intensity; } - void setIntensity(float value) { _intensity = value; } + void setIntensity(float value) { + _intensity = value; + _lightPropertiesChanged = true; + } float getFalloffRadius() const { return _falloffRadius; } void setFalloffRadius(float value); float getExponent() const { return _exponent; } - void setExponent(float value) { _exponent = value; } + void setExponent(float value) { + _exponent = value; + _lightPropertiesChanged = true; + } float getCutoff() const { return _cutoff; } void setCutoff(float value); @@ -85,6 +99,7 @@ public: protected: + // properties of a light rgbColor _color; bool _isSpotlight { DEFAULT_IS_SPOTLIGHT }; @@ -93,6 +108,11 @@ protected: float _exponent { DEFAULT_EXPONENT }; float _cutoff { DEFAULT_CUTOFF }; + // Dirty flag turn true when either light properties is changing values. + // THis gets back to false in the somethingChangedNotification() call + // Which is called after a setProperties() or a readEntitySubClassFromBUfferCall on the entity. + bool _lightPropertiesChanged { false }; + static bool _lightsArePickable; }; diff --git a/libraries/shared/src/shared/NsightHelpers.cpp b/libraries/shared/src/shared/NsightHelpers.cpp index 84fde7887b..9720edd820 100644 --- a/libraries/shared/src/shared/NsightHelpers.cpp +++ b/libraries/shared/src/shared/NsightHelpers.cpp @@ -22,7 +22,8 @@ bool nsightActive() { } ProfileRange::ProfileRange(const char *name) { - _rangeId = nvtxRangeStart(name); + //_rangeId = nvtxRangeStart(name); + _rangeId = nvtxRangePush(name); } ProfileRange::ProfileRange(const char *name, uint32_t argbColor, uint64_t payload) { @@ -36,11 +37,13 @@ ProfileRange::ProfileRange(const char *name, uint32_t argbColor, uint64_t payloa eventAttrib.payload.llValue = payload; eventAttrib.payloadType = NVTX_PAYLOAD_TYPE_UNSIGNED_INT64; - _rangeId = nvtxRangeStartEx(&eventAttrib); + //_rangeId = nvtxRangeStartEx(&eventAttrib); + _rangeId = nvtxRangePushEx(&eventAttrib); } ProfileRange::~ProfileRange() { - nvtxRangeEnd(_rangeId); + // nvtxRangeEnd(_rangeId); + nvtxRangePop(); } #else From 354cbbc92749b056e22ce3e8e4953799aebc0e78 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 31 Aug 2016 19:14:35 -0700 Subject: [PATCH 005/104] Investigate why the disable depth Bclamp doesn't work --- .../gpu-gl/src/gpu/gl/GLBackendQuery.cpp | 11 ++++++-- libraries/gpu-gl/src/gpu/gl/GLQuery.h | 1 + libraries/gpu/src/gpu/Query.cpp | 10 ++++--- libraries/gpu/src/gpu/Query.h | 9 +++++-- .../src/AmbientOcclusionEffect.cpp | 10 ++++--- .../render-utils/src/AmbientOcclusionEffect.h | 3 ++- .../src/DeferredLightingEffect.cpp | 21 +++++++++------ .../render-utils/src/DeferredLightingEffect.h | 2 +- .../render-utils/src/RenderDeferredTask.cpp | 14 +++++----- .../render-utils/src/RenderDeferredTask.h | 6 ++--- .../render-utils/src/SurfaceGeometryPass.cpp | 26 ++++++++++++------- .../render-utils/src/SurfaceGeometryPass.h | 4 +-- libraries/render-utils/src/spot_light.slf | 9 +++++-- libraries/shared/src/shared/NsightHelpers.cpp | 22 ++++++++++++++-- libraries/shared/src/shared/NsightHelpers.h | 12 +++++++++ tests/render-perf/src/main.cpp | 2 +- 16 files changed, 115 insertions(+), 47 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp index 19d008da2c..5fd1c4c6a3 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp @@ -25,7 +25,10 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) { auto query = batch._queries.get(batch._params[paramOffset]._uint); GLQuery* glquery = syncGPUObject(*query); if (glquery) { - glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime); + PROFILE_RANGE_BEGIN(glquery->_profileRangeId, query->getName().c_str(), 0xFFFF7F00); + + //glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime); + glquery->_batchElapsedTime = usecTimestampNow() * 1000; if (timeElapsed) { glBeginQuery(GL_TIME_ELAPSED, glquery->_endqo); } else { @@ -45,9 +48,13 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) { glQueryCounter(glquery->_endqo, GL_TIMESTAMP); } GLint64 now; - glGetInteger64v(GL_TIMESTAMP, &now); + //glGetInteger64v(GL_TIMESTAMP, &now); + now = usecTimestampNow() * 1000; + glquery->_batchElapsedTime = now - glquery->_batchElapsedTime; + PROFILE_RANGE_END(glquery->_profileRangeId); + (void)CHECK_GL_ERROR(); } } diff --git a/libraries/gpu-gl/src/gpu/gl/GLQuery.h b/libraries/gpu-gl/src/gpu/gl/GLQuery.h index bf10d002e6..1189891967 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLQuery.h +++ b/libraries/gpu-gl/src/gpu/gl/GLQuery.h @@ -49,6 +49,7 @@ public: const GLuint _beginqo = { 0 }; GLuint64 _result { (GLuint64)-1 }; GLuint64 _batchElapsedTime { (GLuint64) 0 }; + uint64_t _profileRangeId { 0 }; protected: GLQuery(const std::weak_ptr& backend, const Query& query, GLuint endId, GLuint beginId) : Parent(backend, query, endId), _beginqo(beginId) {} diff --git a/libraries/gpu/src/gpu/Query.cpp b/libraries/gpu/src/gpu/Query.cpp index 1056193215..38a9d6db8c 100644 --- a/libraries/gpu/src/gpu/Query.cpp +++ b/libraries/gpu/src/gpu/Query.cpp @@ -15,8 +15,9 @@ using namespace gpu; -Query::Query(const Handler& returnHandler) : - _returnHandler(returnHandler) +Query::Query(const Handler& returnHandler, const std::string& name) : + _returnHandler(returnHandler), + _name(name) { } @@ -41,14 +42,15 @@ void Query::triggerReturnHandler(uint64_t queryResult, uint64_t batchElapsedTime } -RangeTimer::RangeTimer() { +RangeTimer::RangeTimer(const std::string& name) : + _name(name) { for (int i = 0; i < QUERY_QUEUE_SIZE; i++) { _timerQueries.push_back(std::make_shared([&, i] (const Query& query) { _tailIndex ++; _movingAverageGPU.addSample(query.getGPUElapsedTime()); _movingAverageBatch.addSample(query.getBatchElapsedTime()); - })); + }, _name)); } } diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h index 13b660fc2c..26553d67b3 100644 --- a/libraries/gpu/src/gpu/Query.h +++ b/libraries/gpu/src/gpu/Query.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "Format.h" @@ -27,18 +28,21 @@ namespace gpu { public: using Handler = std::function; - Query(const Handler& returnHandler); + Query(const Handler& returnHandler, const std::string& name = "gpu::query"); ~Query(); double getGPUElapsedTime() const; double getBatchElapsedTime() const; + const std::string& getName() const { return _name; } + // Only for gpu::Context const GPUObjectPointer gpuObject {}; void triggerReturnHandler(uint64_t queryResult, uint64_t batchElapsedTime); protected: Handler _returnHandler; + std::string _name; uint64_t _queryResult { 0 }; uint64_t _usecBatchElapsedTime { 0 }; }; @@ -52,7 +56,7 @@ namespace gpu { // The result is always a late average of the time spent for that same task a few cycles ago. class RangeTimer { public: - RangeTimer(); + RangeTimer(const std::string& name); void begin(gpu::Batch& batch); void end(gpu::Batch& batch); @@ -63,6 +67,7 @@ namespace gpu { static const int QUERY_QUEUE_SIZE { 4 }; + std::string _name; gpu::Queries _timerQueries; int _headIndex = -1; int _tailIndex = -1; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 3bf887e1b6..61a8c1f994 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -351,6 +351,10 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext auto sourceViewport = args->_viewport; auto occlusionViewport = sourceViewport; + if (!_gpuTimer) { + _gpuTimer = std::make_shared < gpu::RangeTimer>(__FUNCTION__); + } + if (!_framebuffer) { _framebuffer = std::make_shared(); } @@ -384,7 +388,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); - _gpuTimer.begin(batch); + _gpuTimer->begin(batch); batch.setViewportTransform(occlusionViewport); batch.setProjectionTransform(glm::mat4()); @@ -428,12 +432,12 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, nullptr); batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, nullptr); - _gpuTimer.end(batch); + _gpuTimer->end(batch); }); // Update the timer auto config = std::static_pointer_cast(renderContext->jobConfig); - config->setGPUBatchRunTime(_gpuTimer.getGPUAverage(), _gpuTimer.getBatchAverage()); + config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 1a828cb2c0..80904c80a3 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -12,6 +12,7 @@ #ifndef hifi_AmbientOcclusionEffect_h #define hifi_AmbientOcclusionEffect_h +#include #include #include "render/DrawTask.h" @@ -188,7 +189,7 @@ private: AmbientOcclusionFramebufferPointer _framebuffer; - gpu::RangeTimer _gpuTimer; + gpu::RangeTimerPointer _gpuTimer; friend class DebugAmbientOcclusion; }; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index c158d6c180..0f09d7ee4f 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -219,8 +219,9 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo if (lightVolume) { state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setDepthClampEnable(true); // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases // additive blending state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); @@ -598,11 +599,11 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... - if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { + /* if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { sphereParam.w = 0.0f; batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->sphereParam, 1, reinterpret_cast< const float* >(&sphereParam)); batch.draw(gpu::TRIANGLE_STRIP, 4); - } else { + } else*/ { sphereParam.w = 1.0f; batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->sphereParam, 1, reinterpret_cast< const float* >(&sphereParam)); @@ -647,12 +648,12 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... const float OVER_CONSERVATIVE_SCALE = 1.1f; - if ((eyeHalfPlaneDistance > -nearRadius) && + /* if ((eyeHalfPlaneDistance > -nearRadius) && (glm::distance(eyePoint, glm::vec3(light->getPosition())) < (expandedRadius * OVER_CONSERVATIVE_SCALE) + nearRadius)) { coneParam.w = 0.0f; batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); batch.draw(gpu::TRIANGLE_STRIP, 4); - } else { + } else*/ { coneParam.w = 1.0f; batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); @@ -720,8 +721,12 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo auto subsurfaceScatteringResource = inputs.get5(); auto args = renderContext->args; + if (!_gpuTimer) { + _gpuTimer = std::make_shared < gpu::RangeTimer>(__FUNCTION__); + } + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - _gpuTimer.begin(batch); + _gpuTimer->begin(batch); }); setupJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, ssaoFramebuffer, subsurfaceScatteringResource); @@ -731,9 +736,9 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo cleanupJob.run(sceneContext, renderContext); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - _gpuTimer.end(batch); + _gpuTimer->end(batch); }); auto config = std::static_pointer_cast(renderContext->jobConfig); - config->setGPUBatchRunTime(_gpuTimer.getGPUAverage(), _gpuTimer.getBatchAverage()); + config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index e4f3f455fa..ff0db1330f 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -183,7 +183,7 @@ public: RenderDeferredCleanup cleanupJob; protected: - gpu::RangeTimer _gpuTimer; + gpu::RangeTimerPointer _gpuTimer; }; #endif // hifi_DeferredLightingEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 1e63cba8da..32aa2b6e16 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -101,7 +101,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { const auto primaryFramebuffer = addJob("PreparePrimaryBuffer"); // const auto fullFrameRangeTimer = addJob("BeginRangeTimer"); - const auto opaqueRangeTimer = addJob("BeginOpaqueRangeTimer"); + const auto opaqueRangeTimer = addJob("BeginOpaqueRangeTimer", "DrawOpaques"); const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).hasVarying(); const auto prepareDeferredOutputs = addJob("PrepareDeferred", prepareDeferredInputs); @@ -146,8 +146,8 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { addJob("DrawLight", lights); const auto deferredLightingInputs = RenderDeferred::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, - surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying(); - + surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying(); + // DeferredBuffer is complete, now let's shade it into the LightingBuffer addJob("RenderDeferred", deferredLightingInputs); @@ -159,7 +159,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying(); addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); - const auto toneAndPostRangeTimer = addJob("BeginToneAndPostRangeTimer"); + const auto toneAndPostRangeTimer = addJob("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing"); // Lighting Buffer ready for tone mapping const auto toneMappingInputs = render::Varying(ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer)); @@ -174,9 +174,9 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { // Debugging stages { - // Debugging Deferred buffer job - const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); - addJob("DebugDeferredBuffer", debugFramebuffers); + // Debugging Deferred buffer job + const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); + addJob("DebugDeferredBuffer", debugFramebuffers); addJob("DebugScattering", deferredLightingInputs); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index e379e42445..fb15e34569 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -21,7 +21,7 @@ class BeginGPURangeTimer { public: using JobModel = render::Job::ModelO; - BeginGPURangeTimer() : _gpuTimer(std::make_shared()) {} + BeginGPURangeTimer(const std::string& name) : _gpuTimer(std::make_shared(name)) {} void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer); @@ -146,7 +146,7 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: - gpu::RangeTimer _gpuTimer; + gpu::RangeTimerPointer _gpuTimer; }; class DrawOverlay3DConfig : public render::Job::Config { @@ -205,7 +205,7 @@ public: using JobModel = Model; protected: - gpu::RangeTimer _gpuTimer; + gpu::RangeTimerPointer _gpuTimer; }; #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 1957f8456a..70ada8b4a0 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -61,9 +61,9 @@ void LinearDepthFramebuffer::updatePrimaryDepth(const gpu::TexturePointer& depth void LinearDepthFramebuffer::clear() { _linearDepthFramebuffer.reset(); _linearDepthTexture.reset(); - _downsampleFramebuffer.reset(); - _halfLinearDepthTexture.reset(); - _halfNormalTexture.reset(); + _downsampleFramebuffer.reset(); + _halfLinearDepthTexture.reset(); + _halfNormalTexture.reset(); } void LinearDepthFramebuffer::allocate() { @@ -142,6 +142,10 @@ void LinearDepthPass::run(const render::SceneContextPointer& sceneContext, const const auto frameTransform = inputs.get0(); const auto deferredFramebuffer = inputs.get1(); + if (!_gpuTimer) { + _gpuTimer = std::make_shared < gpu::RangeTimer>(__FUNCTION__); + } + if (!_linearDepthFramebuffer) { _linearDepthFramebuffer = std::make_shared(); } @@ -171,7 +175,7 @@ void LinearDepthPass::run(const render::SceneContextPointer& sceneContext, const float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f; gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - _gpuTimer.begin(batch); + _gpuTimer->begin(batch); batch.enableStereo(false); batch.setViewportTransform(depthViewport); @@ -197,11 +201,11 @@ void LinearDepthPass::run(const render::SceneContextPointer& sceneContext, const batch.setPipeline(downsamplePipeline); batch.draw(gpu::TRIANGLE_STRIP, 4); - _gpuTimer.end(batch); + _gpuTimer->end(batch); }); auto config = std::static_pointer_cast(renderContext->jobConfig); - config->setGPUBatchRunTime(_gpuTimer.getGPUAverage(), _gpuTimer.getBatchAverage()); + config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); } @@ -406,6 +410,10 @@ void SurfaceGeometryPass::run(const render::SceneContextPointer& sceneContext, c RenderArgs* args = renderContext->args; + if (!_gpuTimer) { + _gpuTimer = std::make_shared < gpu::RangeTimer>(__FUNCTION__); + } + const auto frameTransform = inputs.get0(); const auto deferredFramebuffer = inputs.get1(); const auto linearDepthFramebuffer = inputs.get2(); @@ -458,7 +466,7 @@ void SurfaceGeometryPass::run(const render::SceneContextPointer& sceneContext, c gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - _gpuTimer.begin(batch); + _gpuTimer->begin(batch); batch.enableStereo(false); batch.setProjectionTransform(glm::mat4()); @@ -519,12 +527,12 @@ void SurfaceGeometryPass::run(const render::SceneContextPointer& sceneContext, c batch.setResourceTexture(BlurTask_DepthSlot, nullptr); batch.setUniformBuffer(BlurTask_ParamsSlot, nullptr); - _gpuTimer.end(batch); + _gpuTimer->end(batch); }); auto config = std::static_pointer_cast(renderContext->jobConfig); - config->setGPUBatchRunTime(_gpuTimer.getGPUAverage(), _gpuTimer.getBatchAverage()); + config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); } diff --git a/libraries/render-utils/src/SurfaceGeometryPass.h b/libraries/render-utils/src/SurfaceGeometryPass.h index 3bc6b45c7c..6d830f9a28 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.h +++ b/libraries/render-utils/src/SurfaceGeometryPass.h @@ -87,7 +87,7 @@ private: const gpu::PipelinePointer& getDownsamplePipeline(); gpu::PipelinePointer _downsamplePipeline; - gpu::RangeTimer _gpuTimer; + gpu::RangeTimerPointer _gpuTimer; }; @@ -202,7 +202,7 @@ private: render::BlurGaussianDepthAware _diffusePass; - gpu::RangeTimer _gpuTimer; + gpu::RangeTimerPointer _gpuTimer; }; #endif // hifi_SurfaceGeometryPass_h diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 4d4ad71413..0aa56947f7 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -31,14 +31,14 @@ in vec4 _texCoord0; out vec4 _fragColor; void main(void) { - + _fragColor = vec4(1.0, 0.0, 0.0, 1.0);// + return; DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); // Grab the fragment data from the uv vec2 texCoord = _texCoord0.st / _texCoord0.q; texCoord *= texcoordFrameTransform.zw; texCoord += texcoordFrameTransform.xy; - DeferredFragment frag = unpackDeferredFragment(deferredTransform, texCoord); if (frag.mode == FRAG_MODE_UNLIT) { @@ -66,6 +66,11 @@ void main(void) { discard; } + + + + + // Frag to eye vec vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); diff --git a/libraries/shared/src/shared/NsightHelpers.cpp b/libraries/shared/src/shared/NsightHelpers.cpp index 9720edd820..fa853029be 100644 --- a/libraries/shared/src/shared/NsightHelpers.cpp +++ b/libraries/shared/src/shared/NsightHelpers.cpp @@ -21,8 +21,26 @@ bool nsightActive() { return nsightLaunched; } + +uint64_t ProfileRange::beginRange(const char* name, uint32_t argbColor) { + nvtxEventAttributes_t eventAttrib = { 0 }; + eventAttrib.version = NVTX_VERSION; + eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; + eventAttrib.colorType = NVTX_COLOR_ARGB; + eventAttrib.color = argbColor; + eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; + eventAttrib.message.ascii = name; + return nvtxRangeStartEx(&eventAttrib); + // return nvtxRangePushEx(&eventAttrib); +} + +void ProfileRange::endRange(uint64_t rangeId) { + nvtxRangeEnd(rangeId); + // nvtxRangePop(); +} + ProfileRange::ProfileRange(const char *name) { - //_rangeId = nvtxRangeStart(name); + // _rangeId = nvtxRangeStart(name); _rangeId = nvtxRangePush(name); } @@ -42,7 +60,7 @@ ProfileRange::ProfileRange(const char *name, uint32_t argbColor, uint64_t payloa } ProfileRange::~ProfileRange() { - // nvtxRangeEnd(_rangeId); + // nvtxRangeEnd(_rangeId); nvtxRangePop(); } diff --git a/libraries/shared/src/shared/NsightHelpers.h b/libraries/shared/src/shared/NsightHelpers.h index 94cb8d5263..294ffe0f7d 100644 --- a/libraries/shared/src/shared/NsightHelpers.h +++ b/libraries/shared/src/shared/NsightHelpers.h @@ -19,15 +19,27 @@ public: ProfileRange(const char *name); ProfileRange(const char *name, uint32_t argbColor, uint64_t payload); ~ProfileRange(); + + static uint64_t beginRange(const char* name, uint32_t argbColor); + static void endRange(uint64_t rangeId); private: uint64_t _rangeId{ 0 }; }; #define PROFILE_RANGE(name) ProfileRange profileRangeThis(name); #define PROFILE_RANGE_EX(name, argbColor, payload) ProfileRange profileRangeThis(name, argbColor, (uint64_t)payload); + +#define PROFILE_RANGE_BEGIN(rangeId, name, argbColor) rangeId = ProfileRange::beginRange(name, argbColor) +#define PROFILE_RANGE_END(rangeId) ProfileRange::endRange(rangeId) + #else #define PROFILE_RANGE(name) #define PROFILE_RANGE_EX(name, argbColor, payload) + + +#define PROFILE_RANGE_BEGIN(rangeId, name, argbColor) +#define PROFILE_RANGE_END(rangeId) + #endif #endif diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index c6cca74c69..030a39a1cd 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -526,7 +526,7 @@ public: _octree->init(); // Prevent web entities from rendering REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, WebEntityItem::factory); - REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, LightEntityItem::factory); +// REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, LightEntityItem::factory); DependencyManager::set(_octree->getTree()); getEntities()->setViewFrustum(_viewFrustum); From a537f40158346e1737ce7c37688003bdfcc16ad3 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 1 Sep 2016 12:10:15 -0700 Subject: [PATCH 006/104] Moving to a simpler lighting shader --- libraries/render-utils/src/DeferredLightingEffect.cpp | 6 +++--- libraries/render-utils/src/point_light.slf | 4 ++-- libraries/render-utils/src/spot_light.slf | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 0f09d7ee4f..df80065ff5 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -218,10 +218,10 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); if (lightVolume) { - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setCullMode(gpu::State::CULL_FRONT); + state->setDepthTest(true, false, gpu::GREATER_EQUAL); - state->setDepthClampEnable(true); + //state->setDepthClampEnable(true); // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases // additive blending state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index 80b2e62b8a..b92f18255c 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -46,10 +46,10 @@ void main(void) { } // Kill if in front of the light volume - float depth = frag.depthVal; +/* float depth = frag.depthVal; if (depth < gl_FragCoord.z) { discard; - } + }*/ // Need the light now Light light = getLight(); diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 0aa56947f7..058e0dadea 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -31,8 +31,8 @@ in vec4 _texCoord0; out vec4 _fragColor; void main(void) { - _fragColor = vec4(1.0, 0.0, 0.0, 1.0);// - return; + /* _fragColor = vec4(1.0, 0.0, 0.0, 1.0);// + return;*/ DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); // Grab the fragment data from the uv @@ -47,9 +47,9 @@ void main(void) { // Kill if in front of the light volume float depth = frag.depthVal; - if (depth < gl_FragCoord.z) { + /* if (depth < gl_FragCoord.z) { discard; - } + }*/ // Need the light now Light light = getLight(); From 96935504a14cb48779812bae7d646a709caaf892 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 1 Sep 2016 15:20:14 -0700 Subject: [PATCH 007/104] Streamlining the lighting phase for better performances --- libraries/model/src/model/Light.cpp | 22 ++++++++++++++ libraries/model/src/model/Light.h | 7 ++++- libraries/model/src/model/Light.slh | 6 ++++ .../src/DeferredLightingEffect.cpp | 20 ++++++------- .../src/deferred_light_limited.slv | 29 +++++-------------- .../render-utils/src/deferred_light_spot.slv | 11 ++++--- libraries/render-utils/src/point_light.slf | 6 ---- libraries/render-utils/src/spot_light.slf | 13 --------- 8 files changed, 59 insertions(+), 55 deletions(-) diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index 1762b0a9fb..4421864569 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -37,6 +37,13 @@ Light& Light::operator= (const Light& light) { Light::~Light() { } +void Light::setType(Type type) { + editSchema()._control.x = float(type); + updateLightRadius(); + updateVolumeGeometry(); +} + + void Light::setPosition(const Vec3& position) { _transform.setTranslation(position); editSchema()._position = Vec4(position, 1.f); @@ -82,6 +89,7 @@ void Light::setMaximumRadius(float radius) { } editSchema()._attenuation.y = radius; updateLightRadius(); + updateVolumeGeometry(); } void Light::updateLightRadius() { @@ -117,6 +125,8 @@ void Light::setSpotAngle(float angle) { editSchema()._spot.x = (float) std::abs(cosAngle); editSchema()._spot.y = (float) std::abs(sinAngle); editSchema()._spot.z = (float) angle; + + updateVolumeGeometry(); } void Light::setSpotExponent(float exponent) { @@ -153,3 +163,15 @@ void Light::setAmbientMap(gpu::TexturePointer ambientMap) { void Light::setAmbientMapNumMips(uint16_t numMips) { editSchema()._ambientMapNumMips = (float)numMips; } + +void Light::updateVolumeGeometry() { + // enlarge the scales slightly to account for tesselation + const float SCALE_EXPANSION = 0.05f; + glm::vec4 volumeGeometry(0.0f, 0.0f, 0.0f, 1.0f); // getMaximumRadius() * (1.0f + SCALE_EXPANSION)); + + if (getType() == SPOT) { + const float TANGENT_LENGTH_SCALE = 0.666f; + volumeGeometry = glm::vec4(getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * getSpotAngle()), volumeGeometry.w); + } + editSchema()._volumeGeometry = volumeGeometry; +} diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 3b320e08fd..058d4d4741 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -54,7 +54,7 @@ public: Light& operator= (const Light& light); virtual ~Light(); - void setType(Type type) { editSchema()._control.x = float(type); } + void setType(Type type); Type getType() const { return Type((int) getSchema()._control.x); } void setPosition(const Vec3& position); @@ -126,9 +126,12 @@ public: Vec4 _spot{0.0f, 0.0f, 0.0f, 0.0f}; Vec4 _shadow{0.0f}; + float _ambientMapNumMips{ 0.0f }; Vec3 _control{ 0.0f, 0.0f, 0.0f }; + Vec4 _volumeGeometry { 1.f }; + gpu::SphericalHarmonics _ambientSphere; }; @@ -146,6 +149,8 @@ protected: Schema& editSchema() { return _schemaBuffer.edit(); } void updateLightRadius(); + void updateVolumeGeometry(); + }; typedef std::shared_ptr< Light > LightPointer; diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 5e9d3d30c0..de2ca97088 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -56,6 +56,8 @@ struct Light { vec4 _shadow; vec4 _control; + vec4 _volumeGeometry; + SphericalHarmonics _ambientSphere; }; @@ -98,6 +100,10 @@ float getLightShowContour(Light l) { return l._control.w; } +vec4 getLightVolumeGeometry(Light l) { + return l._volumeGeometry; +} + // Light is the light source its self, d is the light's distance calculated as length(unnormalized light vector). float evalLightAttenuation(Light l, float d) { float radius = getLightRadius(l); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index df80065ff5..af98422b92 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -594,18 +594,18 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // IN DEBUG: light->setShowContour(true); batch.setUniformBuffer(deferredLightingEffect->_pointLightLocations->lightBufferUnit, light->getSchemaBuffer()); - float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); - glm::vec4 sphereParam(expandedRadius, 0.0f, 0.0f, 1.0f); + float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); + // glm::vec4 sphereParam(expandedRadius, 0.0f, 0.0f, 1.0f); // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... - /* if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { + /* if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { sphereParam.w = 0.0f; batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->sphereParam, 1, reinterpret_cast< const float* >(&sphereParam)); batch.draw(gpu::TRIANGLE_STRIP, 4); } else*/ { - sphereParam.w = 1.0f; - batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->sphereParam, 1, reinterpret_cast< const float* >(&sphereParam)); + // sphereParam.w = 1.0f; + // batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->sphereParam, 1, reinterpret_cast< const float* >(&sphereParam)); Transform model; model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z)); @@ -638,7 +638,7 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // light->setShowContour(true); batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, light->getSchemaBuffer()); - auto eyeLightPos = eyePoint - light->getPosition(); + /* auto eyeLightPos = eyePoint - light->getPosition(); auto eyeHalfPlaneDistance = glm::dot(eyeLightPos, light->getDirection()); const float TANGENT_LENGTH_SCALE = 0.666f; @@ -648,19 +648,19 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... const float OVER_CONSERVATIVE_SCALE = 1.1f; - /* if ((eyeHalfPlaneDistance > -nearRadius) && + if ((eyeHalfPlaneDistance > -nearRadius) && (glm::distance(eyePoint, glm::vec3(light->getPosition())) < (expandedRadius * OVER_CONSERVATIVE_SCALE) + nearRadius)) { coneParam.w = 0.0f; batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); batch.draw(gpu::TRIANGLE_STRIP, 4); } else*/ { - coneParam.w = 1.0f; - batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); + // coneParam.w = 1.0f; + // batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); Transform model; model.setTranslation(light->getPosition()); model.postRotate(light->getOrientation()); - model.postScale(glm::vec3(expandedRadius, expandedRadius, expandedRadius)); + // model.postScale(glm::vec3(expandedRadius, expandedRadius, expandedRadius)); batch.setModelTransform(model); diff --git a/libraries/render-utils/src/deferred_light_limited.slv b/libraries/render-utils/src/deferred_light_limited.slv index 81ec882bdf..7168d5386d 100644 --- a/libraries/render-utils/src/deferred_light_limited.slv +++ b/libraries/render-utils/src/deferred_light_limited.slv @@ -18,17 +18,21 @@ <$declareStandardTransform()$> -uniform vec4 sphereParam; +!> + out vec4 _texCoord0; void main(void) { - if (sphereParam.w != 0.0) { + vec4 sphereVertex = inPosition; + // vec4 sphereParam = getLightVolumeGeometry(getLight()); - // standard transform + // sphereVertex.xyz *= sphereParam.w; + + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>; + <$transformModelToClipPos(cam, obj, sphereVertex, gl_Position)$>; vec4 projected = gl_Position / gl_Position.w; projected.xy = (projected.xy + 1.0) * 0.5; @@ -37,21 +41,4 @@ void main(void) { projected.x = 0.5 * (projected.x + cam_getStereoSide()); } _texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w; - } else { - const float depth = -1.0; //Draw at near plane - const vec4 UNIT_QUAD[4] = vec4[4]( - vec4(-1.0, -1.0, depth, 1.0), - vec4(1.0, -1.0, depth, 1.0), - vec4(-1.0, 1.0, depth, 1.0), - vec4(1.0, 1.0, depth, 1.0) - ); - vec4 pos = UNIT_QUAD[gl_VertexID]; - - _texCoord0 = vec4((pos.xy + 1) * 0.5, 0.0, 1.0); - - if (cam_isStereo()) { - _texCoord0.x = 0.5 * (_texCoord0.x + cam_getStereoSide()); - } - gl_Position = pos; - } } diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index 6ae133b7a5..e48f8ba907 100755 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -18,13 +18,15 @@ <$declareStandardTransform()$> -uniform vec4 coneParam; +<@include model/Light.slh@> + out vec4 _texCoord0; void main(void) { vec4 coneVertex = inPosition; - if (coneParam.w != 0.0) { + // if (coneParam.w != 0.0) { + vec4 coneParam = getLightVolumeGeometry(getLight()); if(coneVertex.z >= 0.0) { // Evaluate the true position of the spot volume vec2 dir = float(coneVertex.z < 0.5f) * (coneParam.xy @@ -38,6 +40,7 @@ void main(void) { coneVertex.z = 0.0; } + coneVertex.xyz *= coneParam.w; // standard transform TransformCamera cam = getTransformCamera(); @@ -50,7 +53,7 @@ void main(void) { projected.x = 0.5 * (projected.x + cam_getStereoSide()); } _texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w; - } else { + /* } else { const float depth = -1.0; //Draw at near plane const vec4 UNIT_QUAD[4] = vec4[4]( vec4(-1.0, -1.0, depth, 1.0), @@ -65,5 +68,5 @@ void main(void) { _texCoord0.x = 0.5 * (_texCoord0.x + cam_getStereoSide()); } gl_Position = pos; - } + }*/ } diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index b92f18255c..6aab2489be 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -45,12 +45,6 @@ void main(void) { discard; } - // Kill if in front of the light volume -/* float depth = frag.depthVal; - if (depth < gl_FragCoord.z) { - discard; - }*/ - // Need the light now Light light = getLight(); diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 058e0dadea..c2d99259db 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -31,8 +31,6 @@ in vec4 _texCoord0; out vec4 _fragColor; void main(void) { - /* _fragColor = vec4(1.0, 0.0, 0.0, 1.0);// - return;*/ DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); // Grab the fragment data from the uv @@ -45,12 +43,6 @@ void main(void) { discard; } - // Kill if in front of the light volume - float depth = frag.depthVal; - /* if (depth < gl_FragCoord.z) { - discard; - }*/ - // Need the light now Light light = getLight(); @@ -66,11 +58,6 @@ void main(void) { discard; } - - - - - // Frag to eye vec vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); From e72791233db1fd200ecee452bc99b34b4276101f Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 1 Sep 2016 18:08:36 -0700 Subject: [PATCH 008/104] overall clean up of th elocal light drawing to avoid the in/out pipeline case, still seeing big cost on gpu from the spot lights --- libraries/model/src/model/Light.cpp | 2 +- .../src/DeferredLightingEffect.cpp | 130 +++++++++--------- .../render-utils/src/DeferredLightingEffect.h | 2 + libraries/render-utils/src/LightPoint.slh | 4 +- libraries/render-utils/src/LightSpot.slh | 2 +- .../src/deferred_light_limited.slv | 24 ++-- .../render-utils/src/deferred_light_spot.slv | 61 +++----- libraries/render-utils/src/spot_light.slf | 2 + 8 files changed, 107 insertions(+), 120 deletions(-) diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index 4421864569..c073e397dd 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -167,7 +167,7 @@ void Light::setAmbientMapNumMips(uint16_t numMips) { void Light::updateVolumeGeometry() { // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; - glm::vec4 volumeGeometry(0.0f, 0.0f, 0.0f, 1.0f); // getMaximumRadius() * (1.0f + SCALE_EXPANSION)); + glm::vec4 volumeGeometry(0.0f, 0.0f, 0.0f, getMaximumRadius() * (1.0f + SCALE_EXPANSION)); if (getType() == SPOT) { const float TANGENT_LENGTH_SCALE = 0.666f; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index af98422b92..e8b50b61ce 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -245,11 +245,50 @@ void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) { globalLight->setAmbientMap(light->getAmbientMap()); } +#include + +model::MeshPointer DeferredLightingEffect::getPointLightMesh() { + if (!_pointLightMesh) { + _pointLightMesh = std::make_shared(); + + // let's use a icosahedron + auto solid = geometry::icosahedron(); + solid.fitDimension(1.05f); // scaled to 1.05 meters, it will be scaled by the shader accordingly to the light size + + int verticesSize = solid.vertices.size() * 3 * sizeof(float); + float* vertexData = (float*) solid.vertices.data(); + + _pointLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ)); + + auto nbIndices = solid.faces.size() * 3; + + gpu::uint16* indexData = new gpu::uint16[nbIndices]; + gpu::uint16* index = indexData; + for (auto face : solid.faces) { + *(index++) = face[0]; + *(index++) = face[1]; + *(index++) = face[2]; + } + + _pointLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * nbIndices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16)); + delete[] indexData; + + + std::vector parts; + parts.push_back(model::Mesh::Part(0, nbIndices, 0, model::Mesh::TRIANGLES)); + parts.push_back(model::Mesh::Part(0, nbIndices, 0, model::Mesh::LINE_STRIP)); // outline version + + + _pointLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); + } + return _pointLightMesh; +} + model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { if (!_spotLightMesh) { _spotLightMesh = std::make_shared(); - int slices = 32; + int slices = 16; int rings = 3; int vertices = 2 + rings * slices; int originVertex = vertices - 2; @@ -544,41 +583,30 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) - auto monoViewport = args->_viewport; + auto viewport = args->_viewport; // The view frustum is the mono frustum base auto viewFrustum = args->getViewFrustum(); // Eval the mono projection - mat4 monoProjMat; - viewFrustum.evalProjectionMatrix(monoProjMat); + mat4 projMat; + viewFrustum.evalProjectionMatrix(projMat); - // The mono view transform - Transform monoViewTransform; - viewFrustum.evalViewTransform(monoViewTransform); + // The view transform + Transform viewTransform; + viewFrustum.evalViewTransform(viewTransform); - // THe mono view matrix coming from the mono view transform - glm::mat4 monoViewMat; - monoViewTransform.getMatrix(monoViewMat); - - auto geometryCache = DependencyManager::get(); - - auto eyePoint = viewFrustum.getPosition(); - float nearRadius = glm::distance(eyePoint, viewFrustum.getNearTopLeft()); auto deferredLightingEffect = DependencyManager::get(); - // Render in this side's viewport - batch.setViewportTransform(monoViewport); - batch.setStateScissorRect(monoViewport); + // Render in this viewport + batch.setViewportTransform(viewport); + batch.setStateScissorRect(viewport); - // enlarge the scales slightly to account for tesselation - const float SCALE_EXPANSION = 0.05f; + auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), viewport); - auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), monoViewport); - - batch.setProjectionTransform(monoProjMat); - batch.setViewTransform(monoViewTransform, true); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewTransform, true); // Splat Point lights if (points && !deferredLightingEffect->_pointLights.empty()) { @@ -586,32 +614,26 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch.setPipeline(deferredLightingEffect->_pointLight); batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform)); + // Pojnt mesh + auto mesh = deferredLightingEffect->getPointLightMesh(); + batch.setIndexBuffer(mesh->getIndexBuffer()); + batch.setInputBuffer(0, mesh->getVertexBuffer()); + batch.setInputFormat(mesh->getVertexFormat()); + auto& spherePart = mesh->getPartBuffer().get(0); + for (auto lightID : deferredLightingEffect->_pointLights) { auto light = deferredLightingEffect->getLightStage().getLight(lightID); if (!light) { continue; } - // IN DEBUG: light->setShowContour(true); batch.setUniformBuffer(deferredLightingEffect->_pointLightLocations->lightBufferUnit, light->getSchemaBuffer()); - - float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); - // glm::vec4 sphereParam(expandedRadius, 0.0f, 0.0f, 1.0f); - - // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, - // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... - /* if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { - sphereParam.w = 0.0f; - batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->sphereParam, 1, reinterpret_cast< const float* >(&sphereParam)); - batch.draw(gpu::TRIANGLE_STRIP, 4); - } else*/ { - // sphereParam.w = 1.0f; - // batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->sphereParam, 1, reinterpret_cast< const float* >(&sphereParam)); - + { Transform model; model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z)); - batch.setModelTransform(model.postScale(expandedRadius)); - batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - geometryCache->renderSphere(batch); + batch.setModelTransform(model); + + batch.drawIndexed(model::Mesh::topologyToPrimitive(spherePart._topology), spherePart._numIndices, spherePart._startIndex); + } } } @@ -634,34 +656,12 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, if (!light) { continue; } - // IN DEBUG: - // light->setShowContour(true); batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, light->getSchemaBuffer()); - - /* auto eyeLightPos = eyePoint - light->getPosition(); - auto eyeHalfPlaneDistance = glm::dot(eyeLightPos, light->getDirection()); - - const float TANGENT_LENGTH_SCALE = 0.666f; - glm::vec4 coneParam(light->getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * light->getSpotAngle()), 1.0f); - - float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); - // TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume, - // we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working... - const float OVER_CONSERVATIVE_SCALE = 1.1f; - if ((eyeHalfPlaneDistance > -nearRadius) && - (glm::distance(eyePoint, glm::vec3(light->getPosition())) < (expandedRadius * OVER_CONSERVATIVE_SCALE) + nearRadius)) { - coneParam.w = 0.0f; - batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); - batch.draw(gpu::TRIANGLE_STRIP, 4); - } else*/ { - // coneParam.w = 1.0f; - // batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam)); + { Transform model; model.setTranslation(light->getPosition()); model.postRotate(light->getOrientation()); - // model.postScale(glm::vec3(expandedRadius, expandedRadius, expandedRadius)); - batch.setModelTransform(model); batch.drawIndexed(model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index ff0db1330f..9e53bd5cbc 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -73,6 +73,8 @@ private: bool _shadowMapEnabled{ false }; bool _ambientOcclusionEnabled{ false }; + model::MeshPointer _pointLightMesh; + model::MeshPointer getPointLightMesh(); model::MeshPointer _spotLightMesh; model::MeshPointer getSpotLightMesh(); diff --git a/libraries/render-utils/src/LightPoint.slh b/libraries/render-utils/src/LightPoint.slh index 5c9e66dd24..767a96fb51 100644 --- a/libraries/render-utils/src/LightPoint.slh +++ b/libraries/render-utils/src/LightPoint.slh @@ -39,10 +39,10 @@ void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light, if (isShowLightContour() > 0.0) { // Show edge - float edge = abs(2.0 * ((getLightRadius(light) - fragLightDistance) / (0.1)) - 1.0); + float edge = abs(2.0 * ((getLightCutoffRadius(light) - fragLightDistance) / (0.1)) - 1.0); if (edge < 1) { float edgeCoord = exp2(-8.0*edge*edge); - diffuse = vec3(edgeCoord * edgeCoord * getLightShowContour(light) * getLightColor(light)); + diffuse = vec3(edgeCoord * edgeCoord * getLightColor(light)); } } } diff --git a/libraries/render-utils/src/LightSpot.slh b/libraries/render-utils/src/LightSpot.slh index 8a17a5ef4d..65a417110a 100644 --- a/libraries/render-utils/src/LightSpot.slh +++ b/libraries/render-utils/src/LightSpot.slh @@ -40,7 +40,7 @@ void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light, if (isShowLightContour() > 0.0) { // Show edges - float edgeDistR = (getLightRadius(light) - fragLightDistance); + float edgeDistR = (getLightCutoffRadius(light) - fragLightDistance); float edgeDistS = dot(fragLightDistance * vec2(cosSpotAngle, sqrt(1.0 - cosSpotAngle * cosSpotAngle)), -getLightSpotOutsideNormal2(light)); float edgeDist = min(edgeDistR, edgeDistS); float edge = abs(2.0 * (edgeDist / (0.1)) - 1.0); diff --git a/libraries/render-utils/src/deferred_light_limited.slv b/libraries/render-utils/src/deferred_light_limited.slv index 7168d5386d..0284e12458 100644 --- a/libraries/render-utils/src/deferred_light_limited.slv +++ b/libraries/render-utils/src/deferred_light_limited.slv @@ -18,27 +18,27 @@ <$declareStandardTransform()$> -!> +<@include model/Light.slh@> out vec4 _texCoord0; void main(void) { vec4 sphereVertex = inPosition; - // vec4 sphereParam = getLightVolumeGeometry(getLight()); + vec4 sphereParam = getLightVolumeGeometry(getLight()); - // sphereVertex.xyz *= sphereParam.w; + sphereVertex.xyz *= sphereParam.w; // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, sphereVertex, gl_Position)$>; + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, sphereVertex, gl_Position)$>; - vec4 projected = gl_Position / gl_Position.w; - projected.xy = (projected.xy + 1.0) * 0.5; + vec4 projected = gl_Position / gl_Position.w; + projected.xy = (projected.xy + 1.0) * 0.5; - if (cam_isStereo()) { - projected.x = 0.5 * (projected.x + cam_getStereoSide()); - } - _texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w; + if (cam_isStereo()) { + projected.x = 0.5 * (projected.x + cam_getStereoSide()); + } + _texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w; } diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index e48f8ba907..ef019f5a16 100755 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -20,53 +20,36 @@ <@include model/Light.slh@> - out vec4 _texCoord0; void main(void) { vec4 coneVertex = inPosition; - // if (coneParam.w != 0.0) { vec4 coneParam = getLightVolumeGeometry(getLight()); - if(coneVertex.z >= 0.0) { - // Evaluate the true position of the spot volume - vec2 dir = float(coneVertex.z < 0.5f) * (coneParam.xy - + vec2(coneParam.y, -coneParam.x) * coneParam.z * float(coneVertex.z > 0.0f)) - + float(coneVertex.z > 0.5f) * (vec2(1.0, 0.0) - + vec2(0.0, coneParam.z) * float(coneVertex.z < 1.0f)); - coneVertex.xy *= dir.y; - coneVertex.z = -dir.x; - } else { - coneVertex.z = 0.0; - } + if(coneVertex.z >= 0.0) { + // Evaluate the true position of the spot volume + vec2 dir = float(coneVertex.z < 0.5f) * (coneParam.xy + + vec2(coneParam.y, -coneParam.x) * coneParam.z * float(coneVertex.z > 0.0f)) + + float(coneVertex.z > 0.5f) * (vec2(1.0, 0.0) + + vec2(0.0, coneParam.z) * float(coneVertex.z < 1.0f)); - coneVertex.xyz *= coneParam.w; + coneVertex.xy *= dir.y; + coneVertex.z = -dir.x; + } else { + coneVertex.z = 0.0; + } - // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, coneVertex, gl_Position)$>; - vec4 projected = gl_Position / gl_Position.w; - projected.xy = (projected.xy + 1.0) * 0.5; + coneVertex.xyz *= coneParam.w; - if (cam_isStereo()) { - projected.x = 0.5 * (projected.x + cam_getStereoSide()); - } - _texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w; - /* } else { - const float depth = -1.0; //Draw at near plane - const vec4 UNIT_QUAD[4] = vec4[4]( - vec4(-1.0, -1.0, depth, 1.0), - vec4(1.0, -1.0, depth, 1.0), - vec4(-1.0, 1.0, depth, 1.0), - vec4(1.0, 1.0, depth, 1.0) - ); - vec4 pos = UNIT_QUAD[gl_VertexID]; + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, coneVertex, gl_Position)$>; + vec4 projected = gl_Position / gl_Position.w; + projected.xy = (projected.xy + 1.0) * 0.5; - _texCoord0 = vec4((pos.xy + 1) * 0.5, 0.0, 1.0); - if (cam_isStereo()) { - _texCoord0.x = 0.5 * (_texCoord0.x + cam_getStereoSide()); - } - gl_Position = pos; - }*/ + if (cam_isStereo()) { + projected.x = 0.5 * (projected.x + cam_getStereoSide()); + } + _texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w; } diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index c2d99259db..1c249e716f 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -77,5 +77,7 @@ void main(void) { _fragColor.rgb += diffuse; _fragColor.rgb += specular; + + // _fragColor.rgb = vec3(0.0, 1.0, 1.0); } From 560163bb754d0ec0d9b23ece0af1c761ddae9d66 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 2 Sep 2016 10:51:19 -0700 Subject: [PATCH 009/104] removing a warning --- tests/render-perf/src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 030a39a1cd..d1eaba5f25 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -526,7 +526,6 @@ public: _octree->init(); // Prevent web entities from rendering REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, WebEntityItem::factory); -// REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, LightEntityItem::factory); DependencyManager::set(_octree->getTree()); getEntities()->setViewFrustum(_viewFrustum); From d2a15ca82cfb249c5406974bbc7cc8dd310de07c Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 2 Sep 2016 17:51:35 -0700 Subject: [PATCH 010/104] Trying to migrate to a light array instead of each individual lights --- libraries/gpu/src/gpu/Transform.slh | 8 ++++ libraries/model/src/model/Light.slh | 14 ++++++ .../render-utils/src/DeferredBufferRead.slh | 48 +++++++++++++++++++ .../render-utils/src/DeferredGlobalLight.slh | 1 + .../src/DeferredLightingEffect.cpp | 29 ++++++++--- .../render-utils/src/DeferredLightingEffect.h | 7 ++- libraries/render-utils/src/LightStage.cpp | 21 ++++++++ libraries/render-utils/src/LightStage.h | 3 ++ .../src/deferred_light_limited.slv | 1 + .../render-utils/src/deferred_light_spot.slv | 20 ++++++-- libraries/render-utils/src/overlay3D.slf | 1 + .../src/overlay3D_translucent.slf | 1 + libraries/render-utils/src/point_light.slf | 1 + libraries/render-utils/src/spot_light.slf | 25 +++++++--- .../subsurfaceScattering_drawScattering.slf | 1 + 15 files changed, 161 insertions(+), 20 deletions(-) diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 12a1cd10f1..0f13a6b4d1 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -128,6 +128,14 @@ TransformObject getTransformObject() { } <@endfunc@> + +<@func transformWorldToClipPos(cameraTransform, worldPos, clipPos)@> + { // transformWorldToClipPos + vec4 eyeWAPos = <$worldPos$> - vec4(<$cameraTransform$>._viewInverse[3].xyz, 0.0); + <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; + } +<@endfunc@> + <@func transformModelToWorldPos(objectTransform, modelPos, worldPos)@> { // transformModelToWorldPos <$worldPos$> = (<$objectTransform$>._model * <$modelPos$>); diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index de2ca97088..59e986e14a 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -131,7 +131,17 @@ float getLightAmbientMapNumMips(Light l) { return l._control.x; } +<@func declareLightBuffer(N)@> +<@if N@> +uniform lightBuffer { + Light lightArray[<$N$>]; +}; + +Light getLight(int index) { + return lightArray[index]; +} +<@else@> uniform lightBuffer { Light light; }; @@ -139,6 +149,10 @@ Light getLight() { return light; } +<@endif@> + +<@endfunc@> + diff --git a/libraries/render-utils/src/DeferredBufferRead.slh b/libraries/render-utils/src/DeferredBufferRead.slh index 6b5060cc5f..d7eee23c1f 100644 --- a/libraries/render-utils/src/DeferredBufferRead.slh +++ b/libraries/render-utils/src/DeferredBufferRead.slh @@ -24,6 +24,7 @@ uniform sampler2D specularMap; // the depth texture uniform sampler2D depthMap; +uniform sampler2D linearZeyeMap; // the obscurance texture uniform sampler2D obscuranceMap; @@ -86,6 +87,40 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) { } +DeferredFragment unpackDeferredFragmentNoPositionNoAmbient(vec2 texcoord) { + vec4 normalVal; + vec4 diffuseVal; + + DeferredFragment frag; + frag.depthVal = -1; + normalVal = texture(normalMap, texcoord); + diffuseVal = texture(albedoMap, texcoord); + + // Unpack the normal from the map + frag.normal = unpackNormal(normalVal.xyz); + frag.roughness = normalVal.a; + + // Diffuse color and unpack the mode and the metallicness + frag.albedo = diffuseVal.xyz; + frag.scattering = 0.0; + unpackModeMetallic(diffuseVal.w, frag.mode, frag.metallic); + + //frag.emissive = specularVal.xyz; + frag.obscurance = 1.0; + + + if (frag.metallic <= 0.5) { + frag.metallic = 0.0; + frag.fresnel = vec3(0.03); // Default Di-electric fresnel value + } else { + frag.fresnel = vec3(diffuseVal.xyz); + frag.metallic = 1.0; + } + + return frag; +} + + <@include DeferredTransform.slh@> <$declareDeferredFrameTransform()$> @@ -103,6 +138,19 @@ vec4 unpackDeferredPosition(DeferredFrameTransform deferredTransform, float dept return vec4(evalEyePositionFromZeye(side, Zeye, texcoord), 1.0); } +vec4 unpackDeferredPositionFromZeye(vec2 texcoord) { + float Zeye = -texture(linearZeyeMap, texcoord).x; + int side = 0; + if (isStereo()) { + if (texcoord.x > 0.5) { + texcoord.x -= 0.5; + side = 1; + } + texcoord.x *= 2.0; + } + return vec4(evalEyePositionFromZeye(side, Zeye, texcoord), 1.0); +} + DeferredFragment unpackDeferredFragment(DeferredFrameTransform deferredTransform, vec2 texcoord) { float depthValue = texture(depthMap, texcoord).r; diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 16cdab535c..cb5dd9dc48 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -14,6 +14,7 @@ <@include model/Light.slh@> <@include LightingModel.slh@> +<$declareLightBuffer()$> <@include LightAmbient.slh@> <@include LightDirectional.slh@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e8b50b61ce..30b7f83072 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -44,9 +44,8 @@ struct LightLocations { int radius{ -1 }; int ambientSphere{ -1 }; int lightBufferUnit{ -1 }; + int lightIndexBufferUnit { -1 }; int texcoordFrameTransform{ -1 }; - int sphereParam{ -1 }; - int coneParam{ -1 }; int deferredFrameTransformBuffer{ -1 }; int subsurfaceScatteringParametersBuffer{ -1 }; int shadowTransformBuffer{ -1 }; @@ -60,6 +59,7 @@ enum DeferredShader_MapSlot { DEFERRED_BUFFER_OBSCURANCE_UNIT = 4, SHADOW_MAP_UNIT = 5, SKYBOX_MAP_UNIT = 6, + DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, DEFERRED_BUFFER_CURVATURE_UNIT, DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, SCATTERING_LUT_UNIT, @@ -71,6 +71,7 @@ enum DeferredShader_BufferSlot { SCATTERING_PARAMETERS_BUFFER_SLOT, LIGHTING_MODEL_BUFFER_SLOT = render::ShapePipeline::Slot::LIGHTING_MODEL, LIGHT_GPU_SLOT = render::ShapePipeline::Slot::LIGHT, + LIGHT_INDEX_GPU_SLOT, }; static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); @@ -184,6 +185,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), SHADOW_MAP_UNIT)); slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), SKYBOX_MAP_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("linearZeyeMap"), DEFERRED_BUFFER_LINEAR_DEPTH_UNIT)); slotBindings.insert(gpu::Shader::Binding(std::string("curvatureMap"), DEFERRED_BUFFER_CURVATURE_UNIT)); slotBindings.insert(gpu::Shader::Binding(std::string("diffusedCurvatureMap"), DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT)); slotBindings.insert(gpu::Shader::Binding(std::string("scatteringLUT"), SCATTERING_LUT_UNIT)); @@ -195,6 +197,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), LIGHTING_MODEL_BUFFER_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("subsurfaceScatteringParametersBuffer"), SCATTERING_PARAMETERS_BUFFER_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightIndexBuffer"), LIGHT_INDEX_GPU_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); @@ -203,10 +206,9 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00"); locations->texcoordFrameTransform = program->getUniforms().findLocation("texcoordFrameTransform"); - locations->sphereParam = program->getUniforms().findLocation("sphereParam"); - locations->coneParam = program->getUniforms().findLocation("coneParam"); locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); + locations->lightIndexBufferUnit = program->getBuffers().findLocation("lightIndexBuffer"); locations->deferredFrameTransformBuffer = program->getBuffers().findLocation("deferredFrameTransformBuffer"); locations->subsurfaceScatteringParametersBuffer = program->getBuffers().findLocation("subsurfaceScatteringParametersBuffer"); locations->shadowTransformBuffer = program->getBuffers().findLocation("shadowTransformBuffer"); @@ -496,6 +498,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c // Subsurface scattering specific if (surfaceGeometryFramebuffer) { + batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, surfaceGeometryFramebuffer->getLinearDepthTexture()); batch.setResourceTexture(DEFERRED_BUFFER_CURVATURE_UNIT, surfaceGeometryFramebuffer->getCurvatureTexture()); batch.setResourceTexture(DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, surfaceGeometryFramebuffer->getLowCurvatureTexture()); } @@ -571,7 +574,8 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform, const DeferredFramebufferPointer& deferredFramebuffer, - const LightingModelPointer& lightingModel) { + const LightingModelPointer& lightingModel, + const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer) { bool points = lightingModel->isPointLightEnabled(); bool spots = lightingModel->isSpotLightEnabled(); @@ -638,8 +642,13 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, } } + // Splat spot lights if (spots && !deferredLightingEffect->_spotLights.empty()) { + + + _spotLightsBuffer._buffer->setData(deferredLightingEffect->_spotLights.size() * sizeof(int), (const gpu::Byte*) deferredLightingEffect->_spotLights.data()); + // Spot light pipeline batch.setPipeline(deferredLightingEffect->_spotLight); batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform)); @@ -651,6 +660,11 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch.setInputFormat(mesh->getVertexFormat()); auto& conePart = mesh->getPartBuffer().get(0); + + batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()._lightArrayBuffer); + batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightIndexBufferUnit, _spotLightsBuffer); + batch.drawIndexedInstanced(deferredLightingEffect->_spotLights.size(), model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex); + /* for (auto lightID : deferredLightingEffect->_spotLights) { auto light = deferredLightingEffect->getLightStage().getLight(lightID); if (!light) { @@ -666,7 +680,7 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch.drawIndexed(model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex); } - } + }*/ } }); } @@ -681,6 +695,7 @@ void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext, batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, nullptr); batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, nullptr); + batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); batch.setResourceTexture(DEFERRED_BUFFER_CURVATURE_UNIT, nullptr); batch.setResourceTexture(DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, nullptr); batch.setResourceTexture(SCATTERING_LUT_UNIT, nullptr); @@ -731,7 +746,7 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo setupJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, ssaoFramebuffer, subsurfaceScatteringResource); - lightsJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel); + lightsJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer); cleanupJob.run(sceneContext, renderContext); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 9e53bd5cbc..018ff698eb 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -106,6 +106,7 @@ private: std::vector _globalLights; std::vector _pointLights; std::vector _spotLights; + friend class RenderDeferredSetup; friend class RenderDeferredLocals; @@ -155,7 +156,11 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform, const DeferredFramebufferPointer& deferredFramebuffer, - const LightingModelPointer& lightingModel); + const LightingModelPointer& lightingModel, + const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer); + + gpu::BufferView _spotLightsBuffer; + }; diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 5db1f99532..8909284a02 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -114,9 +114,30 @@ LightStage::Index LightStage::addLight(const LightPointer& light) { // INsert the light and its index in the reverese map _lightMap.insert(LightMap::value_type(light, lightId)); + + updateLightArrayBuffer(lightId); } return lightId; } else { return (*found).second; } } + +void LightStage::updateLightArrayBuffer(Index lightId) { + if (!_lightArrayBuffer) { + _lightArrayBuffer = std::make_shared(); + } + + assert(checkLightId(lightId)); + auto lightSize = sizeof(model::Light::Schema); + + if (lightId > _lightArrayBuffer->getTypedSize()) { + _lightArrayBuffer->resize(lightSize * (lightId + 10)); + } + + // lightArray is big enough so we can remap + auto& light = _lights._elements[lightId]; + auto lightSchema = light->getSchemaBuffer().get(); + _lightArrayBuffer->setSubData(lightId, lightSchema); +} + diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index a050bb393f..dc80375f36 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -240,6 +240,9 @@ public: LightMap _lightMap; Descs _descs; + gpu::BufferPointer _lightArrayBuffer; + void updateLightArrayBuffer(Index lightId); + Shadows _shadows; }; diff --git a/libraries/render-utils/src/deferred_light_limited.slv b/libraries/render-utils/src/deferred_light_limited.slv index 0284e12458..4598447335 100644 --- a/libraries/render-utils/src/deferred_light_limited.slv +++ b/libraries/render-utils/src/deferred_light_limited.slv @@ -19,6 +19,7 @@ <$declareStandardTransform()$> <@include model/Light.slh@> +<$declareLightBuffer()$> out vec4 _texCoord0; diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index ef019f5a16..b05e9719f4 100755 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -19,12 +19,16 @@ <$declareStandardTransform()$> <@include model/Light.slh@> +<$declareLightBuffer(32)$> out vec4 _texCoord0; void main(void) { vec4 coneVertex = inPosition; - vec4 coneParam = getLightVolumeGeometry(getLight()); + + Light light = getLight(gl_InstanceID); + vec3 lightPos = getLightPosition(light); + vec4 coneParam = getLightVolumeGeometry(light); if(coneVertex.z >= 0.0) { // Evaluate the true position of the spot volume @@ -37,15 +41,21 @@ void main(void) { coneVertex.z = -dir.x; } else { coneVertex.z = 0.0; - } + } coneVertex.xyz *= coneParam.w; + coneVertex.xyz += lightPos; + // standard transform TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, coneVertex, gl_Position)$>; - vec4 projected = gl_Position / gl_Position.w; + + ; !> + + <$transformWorldToClipPos(cam, coneVertex, gl_Position)$>; + + vec4 projected = gl_Position / gl_Position.w; projected.xy = (projected.xy + 1.0) * 0.5; if (cam_isStereo()) { diff --git a/libraries/render-utils/src/overlay3D.slf b/libraries/render-utils/src/overlay3D.slf index b29b9baf64..1a629dedf1 100644 --- a/libraries/render-utils/src/overlay3D.slf +++ b/libraries/render-utils/src/overlay3D.slf @@ -13,6 +13,7 @@ <@include model/Light.slh@> +<$declareLightBuffer()$> <@include LightingModel.slh@> diff --git a/libraries/render-utils/src/overlay3D_translucent.slf b/libraries/render-utils/src/overlay3D_translucent.slf index ce5bbf3589..f45aa897f9 100644 --- a/libraries/render-utils/src/overlay3D_translucent.slf +++ b/libraries/render-utils/src/overlay3D_translucent.slf @@ -13,6 +13,7 @@ // <@include model/Light.slh@> +<$declareLightBuffer()$> <@include LightingModel.slh@> diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index 6aab2489be..018d6ca79b 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -19,6 +19,7 @@ // Everything about light <@include model/Light.slh@> +<$declareLightBuffer()$> <@include LightingModel.slh@> diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 1c249e716f..08d8589706 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -19,6 +19,7 @@ // Everything about light <@include model/Light.slh@> +<$declareLightBuffer(32)$> <@include LightingModel.slh@> @@ -27,28 +28,27 @@ uniform vec4 texcoordFrameTransform; + + in vec4 _texCoord0; out vec4 _fragColor; void main(void) { - DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); +// DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); // Grab the fragment data from the uv vec2 texCoord = _texCoord0.st / _texCoord0.q; texCoord *= texcoordFrameTransform.zw; texCoord += texcoordFrameTransform.xy; - DeferredFragment frag = unpackDeferredFragment(deferredTransform, texCoord); - if (frag.mode == FRAG_MODE_UNLIT) { - discard; - } + vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord); // Need the light now - Light light = getLight(); + Light light = getLight(0); // Frag pos in world mat4 invViewMat = getViewInverse(); - vec4 fragPos = invViewMat * frag.position; + vec4 fragPos = invViewMat * fragPosition; // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space vec4 fragLightVecLen2; @@ -58,6 +58,17 @@ void main(void) { discard; } + // _fragColor.rgb = vec3(0.0, 1.0, 1.0); + // return; + + DeferredFragment frag = unpackDeferredFragmentNoPositionNoAmbient(texCoord); + // frag.depthVal = depthValue; + frag.position = fragPosition; + + if (frag.mode == FRAG_MODE_UNLIT) { + discard; + } + // Frag to eye vec vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); diff --git a/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf b/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf index 7ee65e27e3..981993615c 100644 --- a/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf +++ b/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf @@ -13,6 +13,7 @@ <@include DeferredBufferRead.slh@> <@include model/Light.slh@> +<$declareLightBuffer()$> <$declareDeferredCurvature()$> From b81dfefbebea104da9a02b0461301f0e4853f00a Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 3 Sep 2016 12:08:53 -0700 Subject: [PATCH 011/104] pack all the lights in a single buffer and shade the opaque with a single full screen path --- libraries/model/src/model/Light.slh | 5 + .../src/DeferredLightingEffect.cpp | 62 +++++++++++-- .../render-utils/src/DeferredLightingEffect.h | 2 + .../render-utils/src/deferred_light_spot.slv | 8 +- libraries/render-utils/src/spot_light.slf | 92 +++++++++++-------- 5 files changed, 123 insertions(+), 46 deletions(-) diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 59e986e14a..2b6e55cf7e 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -60,6 +60,11 @@ struct Light { SphericalHarmonics _ambientSphere; }; +const int LIGHT_SPOT = 2; + +bool light_isSpot(Light l) { + return bool(l._control.y >= 2.f); +} vec3 getLightPosition(Light l) { return l._position.xyz; } vec3 getLightDirection(Light l) { return l._direction.xyz; } // direction is -Z axis diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 30b7f83072..b7e34095c1 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -97,7 +97,7 @@ void DeferredLightingEffect::init() { loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations); - loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations); + loadLightProgram(deferred_light_vert, spot_light_frag, false, _spotLight, _spotLightLocations); // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light _allocatedLights.push_back(std::make_shared()); @@ -571,6 +571,11 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c } +RenderDeferredLocals::RenderDeferredLocals() : +_spotLightsBuffer(std::make_shared()) { + +} + void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform, const DeferredFramebufferPointer& deferredFramebuffer, @@ -585,6 +590,8 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, } auto args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + // Framebuffer copy operations cannot function as multipass stereo operations. + batch.enableStereo(false); // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) auto viewport = args->_viewport; @@ -609,9 +616,46 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), viewport); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewTransform, true); + // batch.setProjectionTransform(projMat); + // batch.setViewTransform(viewTransform, true); + // gather lights + auto& srcPointLights = deferredLightingEffect->_pointLights; + auto& srcSpotLights = deferredLightingEffect->_spotLights; + std::vector lightIndices(srcPointLights.size() + srcSpotLights.size() + 1); + lightIndices[0] = 0; + + if (points && !srcPointLights.empty()) { + memcpy(lightIndices.data() + (lightIndices[0] + 1), srcPointLights.data(), srcPointLights.size() * sizeof(int)); + lightIndices[0] += srcPointLights.size(); + } + if (spots && !srcSpotLights.empty()) { + memcpy(lightIndices.data() + (lightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int)); + lightIndices[0] += srcSpotLights.size(); + } + + if (lightIndices[0] > 0) { + _spotLightsBuffer._buffer->setData(lightIndices.size() * sizeof(int), (const gpu::Byte*) lightIndices.data()); + _spotLightsBuffer._size = lightIndices.size() * sizeof(int); + + // Spot light pipeline + batch.setPipeline(deferredLightingEffect->_spotLight); + batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform)); + + // Spot mesh + auto mesh = deferredLightingEffect->getSpotLightMesh(); + batch.setIndexBuffer(mesh->getIndexBuffer()); + batch.setInputBuffer(0, mesh->getVertexBuffer()); + batch.setInputFormat(mesh->getVertexFormat()); + auto& conePart = mesh->getPartBuffer().get(0); + + + batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()._lightArrayBuffer); + batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightIndexBufferUnit, _spotLightsBuffer); + // batch.drawIndexedInstanced(deferredLightingEffect->_spotLights.size(), model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex); + + batch.draw(gpu::TRIANGLE_STRIP, 4); + /* // Splat Point lights if (points && !deferredLightingEffect->_pointLights.empty()) { // POint light pipeline @@ -645,9 +689,11 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // Splat spot lights if (spots && !deferredLightingEffect->_spotLights.empty()) { - - - _spotLightsBuffer._buffer->setData(deferredLightingEffect->_spotLights.size() * sizeof(int), (const gpu::Byte*) deferredLightingEffect->_spotLights.data()); + std::vector again(deferredLightingEffect->_spotLights.size() + 1); + again[0] = deferredLightingEffect->_spotLights.size(); + memcpy(again.data() + 1, deferredLightingEffect->_spotLights.data(), deferredLightingEffect->_spotLights.size() * sizeof(int)); + _spotLightsBuffer._buffer->setData(again.size() * sizeof(int), (const gpu::Byte*) again.data()); + _spotLightsBuffer._size = again.size() * sizeof(int); // Spot light pipeline batch.setPipeline(deferredLightingEffect->_spotLight); @@ -663,7 +709,9 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()._lightArrayBuffer); batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightIndexBufferUnit, _spotLightsBuffer); - batch.drawIndexedInstanced(deferredLightingEffect->_spotLights.size(), model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex); + // batch.drawIndexedInstanced(deferredLightingEffect->_spotLights.size(), model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex); + + batch.draw(gpu::TRIANGLE_STRIP, 4); /* for (auto lightID : deferredLightingEffect->_spotLights) { auto light = deferredLightingEffect->getLightStage().getLight(lightID); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 018ff698eb..1d0eb1cb15 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -161,6 +161,8 @@ public: gpu::BufferView _spotLightsBuffer; + RenderDeferredLocals(); + }; diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index b05e9719f4..e99142d8ea 100755 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -21,12 +21,16 @@ <@include model/Light.slh@> <$declareLightBuffer(32)$> +uniform lightIndexBuffer { + int lightIndex[32]; +}; out vec4 _texCoord0; +flat out int instanceID; void main(void) { vec4 coneVertex = inPosition; - - Light light = getLight(gl_InstanceID); + instanceID = lightIndex[gl_InstanceID]; + Light light = getLight(instanceID); vec3 lightPos = getLightPosition(light); vec4 coneParam = getLightVolumeGeometry(light); diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 08d8589706..7e1ed9d01e 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -20,75 +20,93 @@ // Everything about light <@include model/Light.slh@> <$declareLightBuffer(32)$> - +uniform lightIndexBuffer { + int lightIndex[32]; +}; <@include LightingModel.slh@> +<@include LightPoint.slh@> +<$declareLightingPoint(supportScattering)$> <@include LightSpot.slh@> <$declareLightingSpot(supportScattering)$> -uniform vec4 texcoordFrameTransform; +//uniform vec4 texcoordFrameTransform; in vec4 _texCoord0; +//flat in int instanceID; out vec4 _fragColor; void main(void) { // DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); // Grab the fragment data from the uv - vec2 texCoord = _texCoord0.st / _texCoord0.q; + vec2 texCoord = _texCoord0.st;/* / _texCoord0.q; texCoord *= texcoordFrameTransform.zw; - texCoord += texcoordFrameTransform.xy; + texCoord += texcoordFrameTransform.xy;*/ vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord); - - // Need the light now - Light light = getLight(0); - - // Frag pos in world - mat4 invViewMat = getViewInverse(); - vec4 fragPos = invViewMat * fragPosition; - - // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space - vec4 fragLightVecLen2; - vec4 fragLightDirLen; - float cosSpotAngle; - if (!clipFragToLightVolumeSpot(light, fragPos.xyz, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) { - discard; - } - - // _fragColor.rgb = vec3(0.0, 1.0, 1.0); - // return; - DeferredFragment frag = unpackDeferredFragmentNoPositionNoAmbient(texCoord); - // frag.depthVal = depthValue; - frag.position = fragPosition; if (frag.mode == FRAG_MODE_UNLIT) { discard; } - // Frag to eye vec - vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); - vec3 fragEyeDir = normalize(fragEyeVector.xyz); + // frag.depthVal = depthValue; + frag.position = fragPosition; - vec3 diffuse; - vec3 specular; vec4 midNormalCurvature; vec4 lowNormalCurvature; if (frag.mode == FRAG_MODE_SCATTERING) { unpackMidLowNormalCurvature(texCoord, midNormalCurvature, lowNormalCurvature); } - evalLightingSpot(diffuse, specular, light, - fragLightDirLen.xyzw, cosSpotAngle, fragEyeDir, frag.normal, frag.roughness, - frag.metallic, frag.fresnel, frag.albedo, 1.0, - frag.scattering, midNormalCurvature, lowNormalCurvature); - _fragColor.rgb += diffuse; - _fragColor.rgb += specular; + // Frag pos in world + mat4 invViewMat = getViewInverse(); + vec4 fragPos = invViewMat * fragPosition; - // _fragColor.rgb = vec3(0.0, 1.0, 1.0); + // Frag to eye vec + vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); + vec3 fragEyeDir = normalize(fragEyeVector.xyz); + + int numLights = lightIndex[0]; + for (int i = 0; i < numLights; i++) { + // Need the light now + Light light = getLight(lightIndex[i + 1]); + bool isSpot = light_isSpot(light); + // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space + vec4 fragLightVecLen2; + vec4 fragLightDirLen; + float cosSpotAngle; + if (isSpot) { + if (!clipFragToLightVolumeSpot(light, fragPos.xyz, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) { + continue; + } + } else { + if (!clipFragToLightVolumePoint(light, fragPos.xyz, fragLightVecLen2)) { + continue; + } + } + + vec3 diffuse; + vec3 specular; + + if (isSpot) { + evalLightingSpot(diffuse, specular, light, + fragLightDirLen.xyzw, cosSpotAngle, fragEyeDir, frag.normal, frag.roughness, + frag.metallic, frag.fresnel, frag.albedo, 1.0, + frag.scattering, midNormalCurvature, lowNormalCurvature); + } else { + evalLightingPoint(diffuse, specular, light, + fragLightVecLen2.xyz, fragEyeDir, frag.normal, frag.roughness, + frag.metallic, frag.fresnel, frag.albedo, 1.0, + frag.scattering, midNormalCurvature, lowNormalCurvature); + } + + _fragColor.rgb += diffuse; + _fragColor.rgb += specular; + } } From 0c45627d9427989a3bf6cbb2378bbc970ff12d00 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Sep 2016 12:39:48 -0700 Subject: [PATCH 012/104] CLeaning up the code for the RenderableLightEntityItem --- .../src/RenderableLightEntityItem.cpp | 127 +++++++++++------- .../src/RenderableLightEntityItem.h | 90 ++----------- .../src/DeferredLightingEffect.cpp | 35 +++-- libraries/render-utils/src/LightPayload.cpp | 45 +++++++ libraries/render-utils/src/LightPayload.h | 41 ++++++ libraries/render-utils/src/spot_light.slf | 2 +- .../developer/utilities/render/statsGPU.qml | 41 ------ 7 files changed, 198 insertions(+), 183 deletions(-) create mode 100644 libraries/render-utils/src/LightPayload.cpp create mode 100644 libraries/render-utils/src/LightPayload.h diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 4a62a5b652..eeb6914026 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -11,9 +11,7 @@ #include -#include -#include #include #include @@ -29,16 +27,68 @@ RenderableLightEntityItem::RenderableLightEntityItem(const EntityItemID& entityI { } -void RenderableLightEntityItem::updateLightFromEntity(render::PendingChanges& pendingChanges) { +bool RenderableLightEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { + _myItem = scene->allocateID(); + + auto renderItem = std::make_shared(); + updateRenderItemFromEntity(renderItem.get()); + + auto renderPayload = std::make_shared(renderItem); + + render::Item::Status::Getters statusGetters; + makeEntityItemStatusGetters(self, statusGetters); + renderPayload->addStatusGetters(statusGetters); + + pendingChanges.resetItem(_myItem, renderPayload); + + return true; +} + +void RenderableLightEntityItem::somethingChangedNotification() { + if (_lightPropertiesChanged) { + notifyChanged(); + } + LightEntityItem::somethingChangedNotification(); +} + +void RenderableLightEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { + pendingChanges.removeItem(_myItem); + render::Item::clearID(_myItem); +} + +void RenderableLightEntityItem::locationChanged(bool tellPhysics) { + EntityItem::locationChanged(tellPhysics); + notifyChanged(); +} + +void RenderableLightEntityItem::dimensionsChanged() { + EntityItem::dimensionsChanged(); + notifyChanged(); +} + +void RenderableLightEntityItem::checkFading() { + bool transparent = isTransparent(); + if (transparent != _prevIsTransparent) { + notifyChanged(); + _isFading = false; + _prevIsTransparent = transparent; + } +} + +void RenderableLightEntityItem::notifyChanged() { + if (!render::Item::isValidID(_myItem)) { return; } + render::PendingChanges pendingChanges; + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - pendingChanges.updateItem(_myItem, [this](LightRenderItem& data) { - data.updateLightFromEntity(this); - }); + updateLightFromEntity(pendingChanges); + + scene->enqueuePendingChanges(pendingChanges); } + /* void RenderableLightEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableLightEntityItem::render"); @@ -72,75 +122,54 @@ bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& ori } - -namespace render { - template <> const ItemKey payloadGetKey(const LightRenderItem::Pointer& payload) { - return ItemKey::Builder::light(); +void RenderableLightEntityItem::updateLightFromEntity(render::PendingChanges& pendingChanges) { + if (!render::Item::isValidID(_myItem)) { + return; } - template <> const Item::Bound payloadGetBound(const LightRenderItem::Pointer& payload) { - if (payload) { - return payload->_bound; - } - return render::Item::Bound(); - } - template <> void payloadRender(const LightRenderItem::Pointer& payload, RenderArgs* args) { - if (args) { - if (payload) { - payload->render(args); - } - } - } + + pendingChanges.updateItem(_myItem, [this](LightPayload& data) { + this->updateRenderItemFromEntity(&data); + }); } -LightRenderItem::LightRenderItem() : -_light(std::make_shared()) -{ -} - -void LightRenderItem::updateLightFromEntity(RenderableLightEntityItem* entity) { - _light->setPosition(entity->getPosition()); - _light->setOrientation(entity->getRotation()); +void RenderableLightEntityItem::updateRenderItemFromEntity(LightPayload* lightPayload) { + auto entity = this; + auto light = lightPayload->editLight(); + light->setPosition(entity->getPosition()); + light->setOrientation(entity->getRotation()); bool success; - _bound = entity->getAABox(success); + lightPayload->editBound() = entity->getAABox(success); if (!success) { - _bound = render::Item::Bound(); + lightPayload->editBound() = render::Item::Bound(); } glm::vec3 dimensions = entity->getDimensions(); float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); - _light->setMaximumRadius(largestDiameter / 2.0f); + light->setMaximumRadius(largestDiameter / 2.0f); - _light->setColor(toGlm(entity->getXColor())); + light->setColor(toGlm(entity->getXColor())); float intensity = entity->getIntensity();//* entity->getFadingRatio(); - _light->setIntensity(intensity); + light->setIntensity(intensity); - _light->setFalloffRadius(entity->getFalloffRadius()); + light->setFalloffRadius(entity->getFalloffRadius()); float exponent = entity->getExponent(); float cutoff = glm::radians(entity->getCutoff()); if (!entity->getIsSpotlight()) { - _light->setType(model::Light::POINT); + light->setType(model::Light::POINT); } else { - _light->setType(model::Light::SPOT); + light->setType(model::Light::SPOT); - _light->setSpotAngle(cutoff); - _light->setSpotExponent(exponent); + light->setSpotAngle(cutoff); + light->setSpotExponent(exponent); } } -void LightRenderItem::render(RenderArgs* args) { - - //updateLightFromEntity(); - - DependencyManager::get()->addLight(_light); - -} - diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index 883af056aa..d37fa30318 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -13,32 +13,9 @@ #define hifi_RenderableLightEntityItem_h #include -#include +#include #include "RenderableEntityItem.h" -class RenderableLightEntityItem; - -class LightRenderItem { -public: - using Payload = render::Payload; - using Pointer = Payload::DataPointer; - - model::LightPointer _light; - - render::Item::Bound _bound; - - LightRenderItem(); - void render(RenderArgs* args); - - void updateLightFromEntity(RenderableLightEntityItem* entity); - -}; - -namespace render { - template <> const ItemKey payloadGetKey(const LightRenderItem::Pointer& payload); - template <> const Item::Bound payloadGetBound(const LightRenderItem::Pointer& payload); - template <> void payloadRender(const LightRenderItem::Pointer& payload, RenderArgs* args); -} class RenderableLightEntityItem : public LightEntityItem { public: @@ -53,67 +30,18 @@ public: void updateLightFromEntity(render::PendingChanges& pendingChanges); - virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { - _myItem = scene->allocateID(); + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; - auto renderItem = std::make_shared(); - renderItem->updateLightFromEntity(this); + virtual void somethingChangedNotification() override; + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; - auto renderPayload = std::make_shared(renderItem); + virtual void locationChanged(bool tellPhysics = true) override; - render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(self, statusGetters); - renderPayload->addStatusGetters(statusGetters); + virtual void dimensionsChanged() override; - pendingChanges.resetItem(_myItem, renderPayload); + void checkFading(); - return true; - } - - virtual void somethingChangedNotification() override { - if (_lightPropertiesChanged) { - notifyChanged(); - } - LightEntityItem::somethingChangedNotification(); - } - - virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { - pendingChanges.removeItem(_myItem); - render::Item::clearID(_myItem); - } - - virtual void locationChanged(bool tellPhysics = true) override { - EntityItem::locationChanged(tellPhysics); - notifyChanged(); - } - - virtual void dimensionsChanged() override { - EntityItem::dimensionsChanged(); - notifyChanged(); - } - - void checkFading() { - bool transparent = isTransparent(); - if (transparent != _prevIsTransparent) { - notifyChanged(); - _isFading = false; - _prevIsTransparent = transparent; - } - } - - void notifyChanged() { - - if (!render::Item::isValidID(_myItem)) { - return; - } - - render::PendingChanges pendingChanges; - render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - - updateLightFromEntity(pendingChanges); - - scene->enqueuePendingChanges(pendingChanges); - } + void notifyChanged(); private: bool _prevIsTransparent { isTransparent() }; @@ -121,6 +49,8 @@ private: // Dirty flag turn true when either setSubClassProperties or readEntitySubclassDataFromBuffer is changing a value + void updateRenderItemFromEntity(LightPayload* lightPayload); + }; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index b7e34095c1..84ac7b2c9c 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -425,7 +425,6 @@ void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderC outputs.edit0() = _deferredFramebuffer; outputs.edit1() = _deferredFramebuffer->getLightingFramebuffer(); - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); batch.setViewportTransform(args->_viewport); @@ -457,7 +456,8 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource) { auto args = renderContext->args; - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + auto& batch = (*args->_batch); + // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { // Framebuffer copy operations cannot function as multipass stereo operations. batch.enableStereo(false); @@ -567,7 +567,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr); } batch.setResourceTexture(SHADOW_MAP_UNIT, nullptr); - }); + // }); } @@ -589,9 +589,10 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, return; } auto args = renderContext->args; - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + auto& batch = (*args->_batch); + // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { // Framebuffer copy operations cannot function as multipass stereo operations. - batch.enableStereo(false); + /// batch.enableStereo(false); // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) auto viewport = args->_viewport; @@ -730,12 +731,13 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, } }*/ } - }); + // }); } void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { auto args = renderContext->args; - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + auto& batch = (*args->_batch); + // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { // Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, nullptr); batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, nullptr); @@ -752,7 +754,7 @@ void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext, batch.setUniformBuffer(SCATTERING_PARAMETERS_BUFFER_SLOT, nullptr); // batch.setUniformBuffer(LIGHTING_MODEL_BUFFER_SLOT, nullptr); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); - }); + // }); auto deferredLightingEffect = DependencyManager::get(); @@ -788,9 +790,14 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo _gpuTimer = std::make_shared < gpu::RangeTimer>(__FUNCTION__); } - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + auto previousBatch = args->_batch; + gpu::Batch batch; + // f(batch); + args->_batch = &batch; + + // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { _gpuTimer->begin(batch); - }); + // }); setupJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, ssaoFramebuffer, subsurfaceScatteringResource); @@ -798,10 +805,14 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo cleanupJob.run(sceneContext, renderContext); - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { _gpuTimer->end(batch); - }); + // }); + args->_context->appendFrameBatch(batch); + args->_batch = previousBatch; + + auto config = std::static_pointer_cast(renderContext->jobConfig); config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); } diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp new file mode 100644 index 0000000000..8bb9a57145 --- /dev/null +++ b/libraries/render-utils/src/LightPayload.cpp @@ -0,0 +1,45 @@ +// +// LightPayload.cpp +// +// Created by Sam Gateau on 9/6/16. +// Copyright 2016 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 "LightPayload.h" + + +#include +#include "DeferredLightingEffect.h" + + +namespace render { + template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload) { + return ItemKey::Builder::light(); + } + + template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload) { + if (payload) { + return payload->editBound(); + } + return render::Item::Bound(); + } + template <> void payloadRender(const LightPayload::Pointer& payload, RenderArgs* args) { + if (args) { + if (payload) { + payload->render(args); + } + } + } +} + +LightPayload::LightPayload() : +_light(std::make_shared()) +{ +} + +void LightPayload::render(RenderArgs* args) { + + DependencyManager::get()->addLight(_light); +} \ No newline at end of file diff --git a/libraries/render-utils/src/LightPayload.h b/libraries/render-utils/src/LightPayload.h new file mode 100644 index 0000000000..2f065e4b5b --- /dev/null +++ b/libraries/render-utils/src/LightPayload.h @@ -0,0 +1,41 @@ +// +// LightPayload.h +// +// Created by Sam Gateau on 9/6/16. +// Copyright 2016 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_LightPayload_h +#define hifi_LightPayload_h + + +#include +#include + + +class LightPayload { +public: + using Payload = render::Payload; + using Pointer = Payload::DataPointer; + + LightPayload(); + void render(RenderArgs* args); + + model::LightPointer editLight() { return _light; } + render::Item::Bound& editBound() { return _bound; } + +protected: + model::LightPointer _light; + render::Item::Bound _bound; +}; + +namespace render { + template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload); + template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload); + template <> void payloadRender(const LightPayload::Pointer& payload, RenderArgs* args); +} + +#endif \ No newline at end of file diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 7e1ed9d01e..d12db826c0 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -47,7 +47,7 @@ void main(void) { texCoord += texcoordFrameTransform.xy;*/ vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord); - DeferredFragment frag = unpackDeferredFragmentNoPositionNoAmbient(texCoord); + DeferredFragment frag = unpackDeferredFragmentNoPosition(texCoord); if (frag.mode == FRAG_MODE_UNLIT) { discard; diff --git a/scripts/developer/utilities/render/statsGPU.qml b/scripts/developer/utilities/render/statsGPU.qml index 4a6ec29e2f..3d23c2c6dc 100644 --- a/scripts/developer/utilities/render/statsGPU.qml +++ b/scripts/developer/utilities/render/statsGPU.qml @@ -109,47 +109,6 @@ Item { } ] } - - PlotPerf { - title: "Batch Timing" - height: parent.evalEvenHeight() - object: parent.drawOpaqueConfig - valueUnit: "ms" - valueScale: 1 - valueNumDigits: "4" - plots: [ - { - object: Render.getConfig("OpaqueRangeTimer"), - prop: "gpuBatchTime", - label: "Opaque", - color: "#FFFFFF" - }, - { - object: Render.getConfig("LinearDepth"), - prop: "gpuBatchTime", - label: "LinearDepth", - color: "#00FF00" - },{ - object: Render.getConfig("SurfaceGeometry"), - prop: "gpuBatchTime", - label: "SurfaceGeometry", - color: "#00FFFF" - }, - { - object: Render.getConfig("RenderDeferred"), - prop: "gpuBatchTime", - label: "DeferredLighting", - color: "#FF00FF" - } - , - { - object: Render.getConfig("ToneAndPostRangeTimer"), - prop: "gpuBatchTime", - label: "tone and post", - color: "#FF0000" - } - ] - } } } From 1165c54f671126713b5501f7be637897f4d95a93 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Sep 2016 16:24:03 -0700 Subject: [PATCH 013/104] cleaning up the IndexedContainer in its own file and removing warnings --- libraries/gpu/src/gpu/Buffer.h | 2 +- .../src/DeferredLightingEffect.cpp | 8 +- libraries/render-utils/src/LightStage.h | 145 +---------------- .../render/src/render/IndexedContainer.h | 150 ++++++++++++++++++ 4 files changed, 160 insertions(+), 145 deletions(-) create mode 100644 libraries/render/src/render/IndexedContainer.h diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h index 981424de2f..047903a537 100644 --- a/libraries/gpu/src/gpu/Buffer.h +++ b/libraries/gpu/src/gpu/Buffer.h @@ -177,7 +177,7 @@ protected: public: using Size = Resource::Size; - using Index = int; + using Index = int32_t; BufferPointer _buffer; Size _offset { 0 }; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 84ac7b2c9c..55af6fd5de 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -257,12 +257,12 @@ model::MeshPointer DeferredLightingEffect::getPointLightMesh() { auto solid = geometry::icosahedron(); solid.fitDimension(1.05f); // scaled to 1.05 meters, it will be scaled by the shader accordingly to the light size - int verticesSize = solid.vertices.size() * 3 * sizeof(float); + int verticesSize = (int) (solid.vertices.size() * 3 * sizeof(float)); float* vertexData = (float*) solid.vertices.data(); _pointLightMesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(verticesSize, (gpu::Byte*) vertexData), gpu::Element::VEC3F_XYZ)); - auto nbIndices = solid.faces.size() * 3; + int nbIndices = (int) solid.faces.size() * 3; gpu::uint16* indexData = new gpu::uint16[nbIndices]; gpu::uint16* index = indexData; @@ -628,11 +628,11 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, if (points && !srcPointLights.empty()) { memcpy(lightIndices.data() + (lightIndices[0] + 1), srcPointLights.data(), srcPointLights.size() * sizeof(int)); - lightIndices[0] += srcPointLights.size(); + lightIndices[0] += (int) srcPointLights.size(); } if (spots && !srcSpotLights.empty()) { memcpy(lightIndices.data() + (lightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int)); - lightIndices[0] += srcSpotLights.size(); + lightIndices[0] += (int) srcSpotLights.size(); } if (lightIndices[0] > 0) { diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index dc80375f36..4319eb80ba 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -14,6 +14,7 @@ #include #include +#include #include "gpu/Framebuffer.h" @@ -21,150 +22,14 @@ class ViewFrustum; -namespace indexed_elements { - - using Index = int32_t; - const Index MAXIMUM_INDEX { 1 << 30 }; - const Index INVALID_INDEX { -1 }; - using Indices = std::vector< Index >; - - template - class Allocator { - public: - Allocator() {} - Indices _freeIndices; - Index _nextNewIndex { 0 }; - - bool checkIndex(Index index) const { return ((index >= 0) && (index < _nextNewIndex)); } - Index getNumIndices() const { return _nextNewIndex - (Index) _freeIndices.size(); } - - Index allocateIndex() { - if (_freeIndices.empty()) { - Index index = _nextNewIndex; - if (index >= MaxNumElements) { - // abort! we are trying to go overboard with the total number of allocated elements - assert(false); - // This should never happen because Bricks are allocated along with the cells and there - // is already a cap on the cells allocation - return INVALID_INDEX; - } - _nextNewIndex++; - return index; - } else { - Index index = _freeIndices.back(); - _freeIndices.pop_back(); - return index; - } - } - - void freeIndex(Index index) { - if (checkIndex(index)) { - _freeIndices.push_back(index); - } - } - - void clear() { - _freeIndices.clear(); - _nextNewIndex = 0; - } - }; - - template - class IndexedVector { - Allocator _allocator; - public: - using Element = T; - using Elements = std::vector; - - Elements _elements; - - bool checkIndex(Index index) const { return _allocator.checkIndex(index); }; - Index getNumElements() const { return _allocator.getNumIndices(); } - - Index newElement(const Element& e) { - Index index = _allocator.allocateIndex(); - if (index != INVALID_INDEX) { - if (index < _elements.size()) { - _elements.emplace(_elements.begin() + index, e); - } else { - assert(index == _elements.size()); - _elements.emplace_back(e); - } - } - return index; - } - - const Element& freeElement(Index index) { - _allocator.freeIndex(index); - return _elements[index]; - } - - const Element& get(Index index) const { - return _elements[index]; - } - Element& edit(Index index) { - return _elements[index]; - } - }; - - template - class IndexedPointerVector { - Allocator _allocator; - public: - using Data = T; - using ElementPtr = std::shared_ptr; - using Elements = std::vector; - - Elements _elements; - - bool checkIndex(Index index) const { return _allocator.checkIndex(index); }; - Index getNumElements() const { return _allocator.getNumIndices(); } - - Index newElement(const ElementPtr& e) { - Index index = _allocator.allocateIndex(); - if (index != INVALID_INDEX) { - if (index < _elements.size()) { - _elements.emplace(_elements.begin() + index, e); - } else { - assert(index == _elements.size()); - _elements.emplace_back(e); - } - } - return index; - } - - ElementPtr freeElement(Index index) { - ElementPtr freed; - if (checkIndex(index)) { - _allocator.freeIndex(index); - freed = _elements[index]; - _elements[index].reset(); // really forget it - } - return freed; - } - - ElementPtr get(Index index) const { - if (checkIndex(index)) { - return _elements[index]; - } else { - return ElementPtr(); - } - } - }; - - - -}; - - // Light stage to set up light-related rendering tasks class LightStage { public: - using Index = indexed_elements::Index; - static const Index INVALID_INDEX { indexed_elements::INVALID_INDEX }; + using Index = render::indexed_container::Index; + static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX }; using LightPointer = model::LightPointer; - using Lights = indexed_elements::IndexedPointerVector; + using Lights = render::indexed_container::IndexedPointerVector; using LightMap = std::unordered_map; class Shadow { @@ -202,7 +67,7 @@ public: friend class Light; }; using ShadowPointer = std::shared_ptr; - using Shadows = indexed_elements::IndexedPointerVector; + using Shadows = render::indexed_container::IndexedPointerVector; struct Desc { Index shadowId { INVALID_INDEX }; diff --git a/libraries/render/src/render/IndexedContainer.h b/libraries/render/src/render/IndexedContainer.h new file mode 100644 index 0000000000..c5357791d8 --- /dev/null +++ b/libraries/render/src/render/IndexedContainer.h @@ -0,0 +1,150 @@ +// +// IndexedContainer.h +// render +// +// Created by Sam Gateau on 9/6/2016. +// Copyright 2016 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_IndexedContainer_h +#define hifi_render_IndexedContainer_h + +#include + +namespace render { +namespace indexed_container { + + using Index = int32_t; + const Index MAXIMUM_INDEX { 1 << 30 }; + const Index INVALID_INDEX { -1 }; + using Indices = std::vector< Index >; + + template + class Allocator { + public: + Allocator() {} + Indices _freeIndices; + Index _nextNewIndex { 0 }; + + bool checkIndex(Index index) const { return ((index >= 0) && (index < _nextNewIndex)); } + Index getNumIndices() const { return _nextNewIndex - (Index) _freeIndices.size(); } + + Index allocateIndex() { + if (_freeIndices.empty()) { + Index index = _nextNewIndex; + if (index >= MaxNumElements) { + // abort! we are trying to go overboard with the total number of allocated elements + assert(false); + // This should never happen because Bricks are allocated along with the cells and there + // is already a cap on the cells allocation + return INVALID_INDEX; + } + _nextNewIndex++; + return index; + } else { + Index index = _freeIndices.back(); + _freeIndices.pop_back(); + return index; + } + } + + void freeIndex(Index index) { + if (checkIndex(index)) { + _freeIndices.push_back(index); + } + } + + void clear() { + _freeIndices.clear(); + _nextNewIndex = 0; + } + }; + + template + class IndexedVector { + Allocator _allocator; + public: + using Element = T; + using Elements = std::vector; + + Elements _elements; + + bool checkIndex(Index index) const { return _allocator.checkIndex(index); }; + Index getNumElements() const { return _allocator.getNumIndices(); } + + Index newElement(const Element& e) { + Index index = _allocator.allocateIndex(); + if (index != INVALID_INDEX) { + if (index < _elements.size()) { + _elements.emplace(_elements.begin() + index, e); + } else { + assert(index == _elements.size()); + _elements.emplace_back(e); + } + } + return index; + } + + const Element& freeElement(Index index) { + _allocator.freeIndex(index); + return _elements[index]; + } + + const Element& get(Index index) const { + return _elements[index]; + } + Element& edit(Index index) { + return _elements[index]; + } + }; + + template + class IndexedPointerVector { + Allocator _allocator; + public: + using Data = T; + using ElementPtr = std::shared_ptr; + using Elements = std::vector; + + Elements _elements; + + bool checkIndex(Index index) const { return _allocator.checkIndex(index); }; + Index getNumElements() const { return _allocator.getNumIndices(); } + + Index newElement(const ElementPtr& e) { + Index index = _allocator.allocateIndex(); + if (index != INVALID_INDEX) { + if (index < _elements.size()) { + _elements.emplace(_elements.begin() + index, e); + } else { + assert(index == _elements.size()); + _elements.emplace_back(e); + } + } + return index; + } + + ElementPtr freeElement(Index index) { + ElementPtr freed; + if (checkIndex(index)) { + _allocator.freeIndex(index); + freed = _elements[index]; + _elements[index].reset(); // really forget it + } + return freed; + } + + ElementPtr get(Index index) const { + if (checkIndex(index)) { + return _elements[index]; + } else { + return ElementPtr(); + } + } + }; +}; +} +#endif \ No newline at end of file From e2a9751cf5bed24498ce6882ade9b7161683e212 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Sep 2016 16:35:28 -0700 Subject: [PATCH 014/104] REmove warnings --- libraries/gpu/src/gpu/Buffer.h | 2 +- libraries/render-utils/src/LightStage.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h index 047903a537..3233dad8a9 100644 --- a/libraries/gpu/src/gpu/Buffer.h +++ b/libraries/gpu/src/gpu/Buffer.h @@ -60,7 +60,7 @@ public: // The size in bytes of data stored in the buffer Size getSize() const override; template - Size getTypedSize() const { return getSize() / sizeof(T); }; + Size getNumTypedElements() const { return getSize() / sizeof(T); }; const Byte* getData() const { return getSysmem().readData(); } diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 8909284a02..bcdee5c0a9 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -106,7 +106,7 @@ LightStage::Index LightStage::addLight(const LightPointer& light) { if (lightId != INVALID_INDEX) { // Allocate the matching Desc to the light - if (lightId >= _descs.size()) { + if (lightId >= (Index) _descs.size()) { _descs.emplace_back(Desc()); } else { _descs.emplace(_descs.begin() + lightId, Desc()); @@ -131,7 +131,7 @@ void LightStage::updateLightArrayBuffer(Index lightId) { assert(checkLightId(lightId)); auto lightSize = sizeof(model::Light::Schema); - if (lightId > _lightArrayBuffer->getTypedSize()) { + if (lightId > (Index) _lightArrayBuffer->getNumTypedElements()) { _lightArrayBuffer->resize(lightSize * (lightId + 10)); } From 9bed047b752980bd7687e40266cc3f188a6730c2 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Sep 2016 16:42:01 -0700 Subject: [PATCH 015/104] Less warnings --- .../render-utils/src/DebugDeferredBuffer.cpp | 1 - .../src/DeferredLightingEffect.cpp | 132 +++--------------- 2 files changed, 17 insertions(+), 116 deletions(-) diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 6278117b32..09dd4ff82a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -388,7 +388,6 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren const auto geometryBuffer = DependencyManager::get(); const auto framebufferCache = DependencyManager::get(); const auto textureCache = DependencyManager::get(); - const auto& lightStage = DependencyManager::get()->getLightStage(); glm::mat4 projMat; Transform viewMat; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 55af6fd5de..99d1431f20 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -454,11 +454,10 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer, const AmbientOcclusionFramebufferPointer& ambientOcclusionFramebuffer, const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource) { - + auto args = renderContext->args; auto& batch = (*args->_batch); - // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - + { // Framebuffer copy operations cannot function as multipass stereo operations. batch.enableStereo(false); @@ -567,8 +566,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr); } batch.setResourceTexture(SHADOW_MAP_UNIT, nullptr); - // }); - + } } RenderDeferredLocals::RenderDeferredLocals() : @@ -590,10 +588,7 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, } auto args = renderContext->args; auto& batch = (*args->_batch); - // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - // Framebuffer copy operations cannot function as multipass stereo operations. - /// batch.enableStereo(false); - + { // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) auto viewport = args->_viewport; @@ -617,9 +612,6 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), viewport); - // batch.setProjectionTransform(projMat); - // batch.setViewTransform(viewTransform, true); - // gather lights auto& srcPointLights = deferredLightingEffect->_pointLights; auto& srcSpotLights = deferredLightingEffect->_spotLights; @@ -628,11 +620,11 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, if (points && !srcPointLights.empty()) { memcpy(lightIndices.data() + (lightIndices[0] + 1), srcPointLights.data(), srcPointLights.size() * sizeof(int)); - lightIndices[0] += (int) srcPointLights.size(); + lightIndices[0] += (int)srcPointLights.size(); } if (spots && !srcSpotLights.empty()) { memcpy(lightIndices.data() + (lightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int)); - lightIndices[0] += (int) srcSpotLights.size(); + lightIndices[0] += (int)srcSpotLights.size(); } if (lightIndices[0] > 0) { @@ -641,103 +633,20 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // Spot light pipeline batch.setPipeline(deferredLightingEffect->_spotLight); - batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform)); - - // Spot mesh - auto mesh = deferredLightingEffect->getSpotLightMesh(); - batch.setIndexBuffer(mesh->getIndexBuffer()); - batch.setInputBuffer(0, mesh->getVertexBuffer()); - batch.setInputFormat(mesh->getVertexFormat()); - auto& conePart = mesh->getPartBuffer().get(0); - + batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); + // Bind the global list of lights and the visible lights this frame batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()._lightArrayBuffer); batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightIndexBufferUnit, _spotLightsBuffer); - // batch.drawIndexedInstanced(deferredLightingEffect->_spotLights.size(), model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex); - batch.draw(gpu::TRIANGLE_STRIP, 4); - /* - // Splat Point lights - if (points && !deferredLightingEffect->_pointLights.empty()) { - // POint light pipeline - batch.setPipeline(deferredLightingEffect->_pointLight); - batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform)); - - // Pojnt mesh - auto mesh = deferredLightingEffect->getPointLightMesh(); - batch.setIndexBuffer(mesh->getIndexBuffer()); - batch.setInputBuffer(0, mesh->getVertexBuffer()); - batch.setInputFormat(mesh->getVertexFormat()); - auto& spherePart = mesh->getPartBuffer().get(0); - - for (auto lightID : deferredLightingEffect->_pointLights) { - auto light = deferredLightingEffect->getLightStage().getLight(lightID); - if (!light) { - continue; - } - batch.setUniformBuffer(deferredLightingEffect->_pointLightLocations->lightBufferUnit, light->getSchemaBuffer()); - { - Transform model; - model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z)); - batch.setModelTransform(model); - - batch.drawIndexed(model::Mesh::topologyToPrimitive(spherePart._topology), spherePart._numIndices, spherePart._startIndex); - - } - } } - - - // Splat spot lights - if (spots && !deferredLightingEffect->_spotLights.empty()) { - std::vector again(deferredLightingEffect->_spotLights.size() + 1); - again[0] = deferredLightingEffect->_spotLights.size(); - memcpy(again.data() + 1, deferredLightingEffect->_spotLights.data(), deferredLightingEffect->_spotLights.size() * sizeof(int)); - _spotLightsBuffer._buffer->setData(again.size() * sizeof(int), (const gpu::Byte*) again.data()); - _spotLightsBuffer._size = again.size() * sizeof(int); - - // Spot light pipeline - batch.setPipeline(deferredLightingEffect->_spotLight); - batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform)); - - // Spot mesh - auto mesh = deferredLightingEffect->getSpotLightMesh(); - batch.setIndexBuffer(mesh->getIndexBuffer()); - batch.setInputBuffer(0, mesh->getVertexBuffer()); - batch.setInputFormat(mesh->getVertexFormat()); - auto& conePart = mesh->getPartBuffer().get(0); - - - batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()._lightArrayBuffer); - batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightIndexBufferUnit, _spotLightsBuffer); - // batch.drawIndexedInstanced(deferredLightingEffect->_spotLights.size(), model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex); - - batch.draw(gpu::TRIANGLE_STRIP, 4); - /* - for (auto lightID : deferredLightingEffect->_spotLights) { - auto light = deferredLightingEffect->getLightStage().getLight(lightID); - if (!light) { - continue; - } - batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, light->getSchemaBuffer()); - { - - Transform model; - model.setTranslation(light->getPosition()); - model.postRotate(light->getOrientation()); - batch.setModelTransform(model); - - batch.drawIndexed(model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex); - } - }*/ - } - // }); + } } void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { auto args = renderContext->args; auto& batch = (*args->_batch); - // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + { // Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, nullptr); batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, nullptr); @@ -750,12 +659,12 @@ void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext, batch.setResourceTexture(DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, nullptr); batch.setResourceTexture(SCATTERING_LUT_UNIT, nullptr); batch.setResourceTexture(SCATTERING_SPECULAR_UNIT, nullptr); - + batch.setUniformBuffer(SCATTERING_PARAMETERS_BUFFER_SLOT, nullptr); - // batch.setUniformBuffer(LIGHTING_MODEL_BUFFER_SLOT, nullptr); + // batch.setUniformBuffer(LIGHTING_MODEL_BUFFER_SLOT, nullptr); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); - // }); - + } + auto deferredLightingEffect = DependencyManager::get(); // End of the Lighting pass @@ -792,23 +701,16 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo auto previousBatch = args->_batch; gpu::Batch batch; - // f(batch); args->_batch = &batch; - - // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - _gpuTimer->begin(batch); - // }); + _gpuTimer->begin(batch); setupJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, ssaoFramebuffer, subsurfaceScatteringResource); lightsJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer); cleanupJob.run(sceneContext, renderContext); - - // gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - _gpuTimer->end(batch); - // }); - + + _gpuTimer->end(batch); args->_context->appendFrameBatch(batch); args->_batch = previousBatch; From edb456aa8f7d049b59c2c6545936a31d65d0b169 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Sep 2016 17:16:54 -0700 Subject: [PATCH 016/104] ANd again --- libraries/render/src/render/IndexedContainer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render/src/render/IndexedContainer.h b/libraries/render/src/render/IndexedContainer.h index c5357791d8..847fb53bdf 100644 --- a/libraries/render/src/render/IndexedContainer.h +++ b/libraries/render/src/render/IndexedContainer.h @@ -78,7 +78,7 @@ namespace indexed_container { Index newElement(const Element& e) { Index index = _allocator.allocateIndex(); if (index != INVALID_INDEX) { - if (index < _elements.size()) { + if (index < (Index) _elements.size()) { _elements.emplace(_elements.begin() + index, e); } else { assert(index == _elements.size()); From 665a79f10033748fd8bc2e024e16e9ba2bb90a11 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Sep 2016 18:59:26 -0700 Subject: [PATCH 017/104] Creating a separate shader for the locallighting pass --- .../src/DeferredLightingEffect.cpp | 16 +-- .../render-utils/src/DeferredLightingEffect.h | 5 +- .../render-utils/src/local_lights_shading.slf | 102 ++++++++++++++++++ 3 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 libraries/render-utils/src/local_lights_shading.slf diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 99d1431f20..49979180b3 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -35,6 +35,7 @@ #include "directional_ambient_light_shadow_frag.h" #include "directional_skybox_light_shadow_frag.h" +#include "local_lights_shading_frag.h" #include "point_light_frag.h" #include "spot_light_frag.h" @@ -96,6 +97,7 @@ void DeferredLightingEffect::init() { loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_frag, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations); loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); + loadLightProgram(deferred_light_vert, local_lights_shading_frag, false, _localLight, _localLightLocations); loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations); loadLightProgram(deferred_light_vert, spot_light_frag, false, _spotLight, _spotLightLocations); @@ -570,7 +572,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c } RenderDeferredLocals::RenderDeferredLocals() : -_spotLightsBuffer(std::make_shared()) { +_localLightsBuffer(std::make_shared()) { } @@ -628,16 +630,16 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, } if (lightIndices[0] > 0) { - _spotLightsBuffer._buffer->setData(lightIndices.size() * sizeof(int), (const gpu::Byte*) lightIndices.data()); - _spotLightsBuffer._size = lightIndices.size() * sizeof(int); + _localLightsBuffer._buffer->setData(lightIndices.size() * sizeof(int), (const gpu::Byte*) lightIndices.data()); + _localLightsBuffer._size = lightIndices.size() * sizeof(int); // Spot light pipeline - batch.setPipeline(deferredLightingEffect->_spotLight); - batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); + batch.setPipeline(deferredLightingEffect->_localLight); + batch._glUniform4fv(deferredLightingEffect->_localLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); // Bind the global list of lights and the visible lights this frame - batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()._lightArrayBuffer); - batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightIndexBufferUnit, _spotLightsBuffer); + batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()._lightArrayBuffer); + batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightIndexBufferUnit, _localLightsBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); } } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 1d0eb1cb15..0cff4c355c 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -86,6 +86,8 @@ private: gpu::PipelinePointer _directionalAmbientSphereLightShadow; gpu::PipelinePointer _directionalLightShadow; + gpu::PipelinePointer _localLight; + gpu::PipelinePointer _pointLight; gpu::PipelinePointer _spotLight; @@ -97,6 +99,7 @@ private: LightLocationsPtr _directionalAmbientSphereLightShadowLocations; LightLocationsPtr _directionalLightShadowLocations; + LightLocationsPtr _localLightLocations; LightLocationsPtr _pointLightLocations; LightLocationsPtr _spotLightLocations; @@ -159,7 +162,7 @@ public: const LightingModelPointer& lightingModel, const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer); - gpu::BufferView _spotLightsBuffer; + gpu::BufferView _localLightsBuffer; RenderDeferredLocals(); diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf new file mode 100644 index 0000000000..d5a759d7c0 --- /dev/null +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -0,0 +1,102 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// local_lights_shading.frag +// fragment shader +// +// Created by Sam Gateau on 9/6/2016. +// Copyright 2014 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 +// + +// Everything about deferred buffer +<@include DeferredBufferRead.slh@> + +<$declareDeferredCurvature()$> + +// Everything about light +<@include model/Light.slh@> +<$declareLightBuffer(32)$> +uniform lightIndexBuffer { + int lightIndex[32]; +}; +<@include LightingModel.slh@> + +<@include LightPoint.slh@> +<$declareLightingPoint(supportScattering)$> +<@include LightSpot.slh@> +<$declareLightingSpot(supportScattering)$> + +in vec4 _texCoord0; +out vec4 _fragColor; + +void main(void) { + + // Grab the fragment data from the uv + vec2 texCoord = _texCoord0.st; + + vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord); + DeferredFragment frag = unpackDeferredFragmentNoPosition(texCoord); + + if (frag.mode == FRAG_MODE_UNLIT) { + discard; + } + + frag.position = fragPosition; + + vec4 midNormalCurvature; + vec4 lowNormalCurvature; + if (frag.mode == FRAG_MODE_SCATTERING) { + unpackMidLowNormalCurvature(texCoord, midNormalCurvature, lowNormalCurvature); + } + + // Frag pos in world + mat4 invViewMat = getViewInverse(); + vec4 fragPos = invViewMat * fragPosition; + + // Frag to eye vec + vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); + vec3 fragEyeDir = normalize(fragEyeVector.xyz); + + int numLights = lightIndex[0]; + for (int i = 0; i < numLights; i++) { + // Need the light now + Light light = getLight(lightIndex[i + 1]); + bool isSpot = light_isSpot(light); + // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space + vec4 fragLightVecLen2; + vec4 fragLightDirLen; + float cosSpotAngle; + if (isSpot) { + if (!clipFragToLightVolumeSpot(light, fragPos.xyz, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) { + continue; + } + } else { + if (!clipFragToLightVolumePoint(light, fragPos.xyz, fragLightVecLen2)) { + continue; + } + } + + vec3 diffuse; + vec3 specular; + + if (isSpot) { + evalLightingSpot(diffuse, specular, light, + fragLightDirLen.xyzw, cosSpotAngle, fragEyeDir, frag.normal, frag.roughness, + frag.metallic, frag.fresnel, frag.albedo, 1.0, + frag.scattering, midNormalCurvature, lowNormalCurvature); + } else { + evalLightingPoint(diffuse, specular, light, + fragLightVecLen2.xyz, fragEyeDir, frag.normal, frag.roughness, + frag.metallic, frag.fresnel, frag.albedo, 1.0, + frag.scattering, midNormalCurvature, lowNormalCurvature); + } + + _fragColor.rgb += diffuse; + _fragColor.rgb += specular; + } +} + From 34f40e08285ef626d28d21dd39c422d52a771247 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 6 Sep 2016 19:01:13 -0700 Subject: [PATCH 018/104] Creating a separate shader for the locallighting pass --- libraries/render-utils/src/DeferredLightingEffect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 49979180b3..8f0e7ace83 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -86,6 +86,7 @@ void DeferredLightingEffect::init() { _directionalAmbientSphereLightShadowLocations = std::make_shared(); _directionalSkyboxLightShadowLocations = std::make_shared(); + _localLightLocations = std::make_shared(); _pointLightLocations = std::make_shared(); _spotLightLocations = std::make_shared(); From 139ba1b71c42cc816cbd73c17e77ffd0bdf790ea Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 7 Sep 2016 14:56:01 -0700 Subject: [PATCH 019/104] REnaming the shaders correctly --- .../src/DeferredLightingEffect.cpp | 139 +++++++++++++++++- .../render-utils/src/DeferredLightingEffect.h | 6 +- ...t_limited.slv => deferred_light_point.slv} | 11 +- .../render-utils/src/deferred_light_spot.slv | 4 +- libraries/render-utils/src/point_light.slf | 8 +- libraries/render-utils/src/spot_light.slf | 17 ++- tests/shaders/src/main.cpp | 7 +- 7 files changed, 166 insertions(+), 26 deletions(-) rename libraries/render-utils/src/{deferred_light_limited.slv => deferred_light_point.slv} (82%) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 8f0e7ace83..4f14b76ac0 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -24,7 +24,7 @@ #include "FramebufferCache.h" #include "deferred_light_vert.h" -#include "deferred_light_limited_vert.h" +#include "deferred_light_point_vert.h" #include "deferred_light_spot_vert.h" #include "directional_light_frag.h" @@ -76,6 +76,7 @@ enum DeferredShader_BufferSlot { }; static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); +static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& program, LightLocationsPtr& locations); void DeferredLightingEffect::init() { _directionalLightLocations = std::make_shared(); @@ -99,8 +100,11 @@ void DeferredLightingEffect::init() { loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); loadLightProgram(deferred_light_vert, local_lights_shading_frag, false, _localLight, _localLightLocations); - loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations); - loadLightProgram(deferred_light_vert, spot_light_frag, false, _spotLight, _spotLightLocations); + + loadLightVolumeProgram(deferred_light_point_vert, point_light_frag, false, _pointLightBack, _pointLightLocations); + loadLightVolumeProgram(deferred_light_point_vert, point_light_frag, true, _pointLightFront, _pointLightLocations); + loadLightVolumeProgram(deferred_light_spot_vert, spot_light_frag, false, _spotLightBack, _spotLightLocations); + loadLightVolumeProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLightFront, _spotLightLocations); // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light _allocatedLights.push_back(std::make_shared()); @@ -240,6 +244,77 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo } + +static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { + auto VS = gpu::Shader::createVertex(std::string(vertSource)); + auto PS = gpu::Shader::createPixel(std::string(fragSource)); + + gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), DEFERRED_BUFFER_COLOR_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), DEFERRED_BUFFER_NORMAL_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), DEFERRED_BUFFER_EMISSIVE_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), DEFERRED_BUFFER_DEPTH_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("obscuranceMap"), DEFERRED_BUFFER_OBSCURANCE_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), SHADOW_MAP_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), SKYBOX_MAP_UNIT)); + + slotBindings.insert(gpu::Shader::Binding(std::string("linearZeyeMap"), DEFERRED_BUFFER_LINEAR_DEPTH_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("curvatureMap"), DEFERRED_BUFFER_CURVATURE_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("diffusedCurvatureMap"), DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("scatteringLUT"), SCATTERING_LUT_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("scatteringSpecularBeckmann"), SCATTERING_SPECULAR_UNIT)); + + + slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), CAMERA_CORRECTION_BUFFER_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), LIGHTING_MODEL_BUFFER_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("subsurfaceScatteringParametersBuffer"), SCATTERING_PARAMETERS_BUFFER_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightIndexBuffer"), LIGHT_INDEX_GPU_SLOT)); + + + gpu::Shader::makeProgram(*program, slotBindings); + + locations->radius = program->getUniforms().findLocation("radius"); + locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00"); + + locations->texcoordFrameTransform = program->getUniforms().findLocation("texcoordFrameTransform"); + + locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); + locations->lightIndexBufferUnit = program->getBuffers().findLocation("lightIndexBuffer"); + locations->deferredFrameTransformBuffer = program->getBuffers().findLocation("deferredFrameTransformBuffer"); + locations->subsurfaceScatteringParametersBuffer = program->getBuffers().findLocation("subsurfaceScatteringParametersBuffer"); + locations->shadowTransformBuffer = program->getBuffers().findLocation("shadowTransformBuffer"); + + auto state = std::make_shared(); + state->setColorWriteMask(true, true, true, false); + // state->setColorWriteMask(false, false, false, false); + + // Stencil test all the light passes for objects pixels only, not the background + + if (front) { + state->setCullMode(gpu::State::CULL_FRONT); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_INCR, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR)); + + //state->setDepthClampEnable(true); + // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases + // additive blending + // state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + } else { + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, false, gpu::GREATER_EQUAL); + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_INCR, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR)); + // additive blending + // state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + } + pipeline = gpu::Pipeline::create(program, state); + +} + void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) { auto globalLight = _allocatedLights.front(); globalLight->setDirection(light->getDirection()); @@ -618,7 +693,12 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // gather lights auto& srcPointLights = deferredLightingEffect->_pointLights; auto& srcSpotLights = deferredLightingEffect->_spotLights; - std::vector lightIndices(srcPointLights.size() + srcSpotLights.size() + 1); + int numPointLights = (int) srcPointLights.size(); + int offsetPointLights = 0; + int numSpotLights = (int) srcSpotLights.size(); + int offsetSpotLights = numPointLights; + + std::vector lightIndices(numPointLights + numSpotLights + 1); lightIndices[0] = 0; if (points && !srcPointLights.empty()) { @@ -634,13 +714,56 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, _localLightsBuffer._buffer->setData(lightIndices.size() * sizeof(int), (const gpu::Byte*) lightIndices.data()); _localLightsBuffer._size = lightIndices.size() * sizeof(int); - // Spot light pipeline - batch.setPipeline(deferredLightingEffect->_localLight); - batch._glUniform4fv(deferredLightingEffect->_localLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); - // Bind the global list of lights and the visible lights this frame batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()._lightArrayBuffer); batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightIndexBufferUnit, _localLightsBuffer); + + + // before we get to the real lighting, let s try to cull down the number of pixels + { + /* if (numPointLights > 0) { + auto mesh = deferredLightingEffect->getPointLightMesh(); + batch.setIndexBuffer(mesh->getIndexBuffer()); + batch.setInputBuffer(0, mesh->getVertexBuffer()); + batch.setInputFormat(mesh->getVertexFormat()); + auto& pointPart = mesh->getPartBuffer().get(0); + + // Point light pipeline + batch.setPipeline(deferredLightingEffect->_pointLightBack); + batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); + + batch.drawIndexedInstanced(numPointLights, model::Mesh::topologyToPrimitive(pointPart._topology), pointPart._numIndices, pointPart._startIndex, offsetPointLights); + + batch.setPipeline(deferredLightingEffect->_pointLightFront); + batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); + + batch.drawIndexedInstanced(numPointLights, model::Mesh::topologyToPrimitive(pointPart._topology), pointPart._numIndices, pointPart._startIndex, offsetPointLights); + } */ + /* + if (numSpotLights > 0) { + auto mesh = deferredLightingEffect->getSpotLightMesh(); + batch.setIndexBuffer(mesh->getIndexBuffer()); + batch.setInputBuffer(0, mesh->getVertexBuffer()); + batch.setInputFormat(mesh->getVertexFormat()); + auto& conePart = mesh->getPartBuffer().get(0); + + // Spot light pipeline + batch.setPipeline(deferredLightingEffect->_spotLightBack); + batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); + + batch.drawIndexedInstanced(numSpotLights, model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex, offsetSpotLights); + + batch.setPipeline(deferredLightingEffect->_spotLightFront); + batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); + + batch.drawIndexedInstanced(numSpotLights, model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex, offsetSpotLights); + }*/ + } + + // Local light pipeline + batch.setPipeline(deferredLightingEffect->_localLight); + batch._glUniform4fv(deferredLightingEffect->_localLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); + batch.draw(gpu::TRIANGLE_STRIP, 4); } } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 0cff4c355c..cbf5ff6ab3 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -88,8 +88,10 @@ private: gpu::PipelinePointer _localLight; - gpu::PipelinePointer _pointLight; - gpu::PipelinePointer _spotLight; + gpu::PipelinePointer _pointLightBack; + gpu::PipelinePointer _pointLightFront; + gpu::PipelinePointer _spotLightBack; + gpu::PipelinePointer _spotLightFront; LightLocationsPtr _directionalSkyboxLightLocations; LightLocationsPtr _directionalAmbientSphereLightLocations; diff --git a/libraries/render-utils/src/deferred_light_limited.slv b/libraries/render-utils/src/deferred_light_point.slv similarity index 82% rename from libraries/render-utils/src/deferred_light_limited.slv rename to libraries/render-utils/src/deferred_light_point.slv index 4598447335..f6d4de3954 100644 --- a/libraries/render-utils/src/deferred_light_limited.slv +++ b/libraries/render-utils/src/deferred_light_point.slv @@ -19,14 +19,21 @@ <$declareStandardTransform()$> <@include model/Light.slh@> -<$declareLightBuffer()$> +<$declareLightBuffer(120)$> + +uniform lightIndexBuffer { + int lightIndex[120]; +}; out vec4 _texCoord0; void main(void) { + + instanceID = lightIndex[gl_InstanceID]; + Light light = getLight(instanceID); vec4 sphereVertex = inPosition; - vec4 sphereParam = getLightVolumeGeometry(getLight()); + vec4 sphereParam = getLightVolumeGeometry(light); sphereVertex.xyz *= sphereParam.w; diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index e99142d8ea..cd70724e1f 100755 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -19,10 +19,10 @@ <$declareStandardTransform()$> <@include model/Light.slh@> -<$declareLightBuffer(32)$> +<$declareLightBuffer(120)$> uniform lightIndexBuffer { - int lightIndex[32]; + int lightIndex[120]; }; out vec4 _texCoord0; flat out int instanceID; diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index 018d6ca79b..239cbd5c91 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -11,7 +11,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - + @@ -29,10 +29,13 @@ uniform vec4 texcoordFrameTransform; -in vec4 _texCoord0; +in vec4 _texCoord0;!> out vec4 _fragColor; void main(void) { + _fragColor = vec4(1.0, 1.0, 1.0, 1.0); + + } diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index d12db826c0..9d71832f15 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -13,7 +13,7 @@ // // Everything about deferred buffer -<@include DeferredBufferRead.slh@> + <$declareDeferredCurvature()$> @@ -31,21 +31,23 @@ uniform lightIndexBuffer { <$declareLightingSpot(supportScattering)$> //uniform vec4 texcoordFrameTransform; +!> - -in vec4 _texCoord0; +//in vec4 _texCoord0; //flat in int instanceID; out vec4 _fragColor; void main(void) { + _fragColor = vec4(1.0, 1.0, 1.0, 1.0); + // DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); - + // Grab the fragment data from the uv - vec2 texCoord = _texCoord0.st;/* / _texCoord0.q; - texCoord *= texcoordFrameTransform.zw; + //vec2 texCoord = _texCoord0.st;/* / _texCoord0.q; + /*texCoord *= texcoordFrameTransform.zw; texCoord += texcoordFrameTransform.xy;*/ - + /* vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord); DeferredFragment frag = unpackDeferredFragmentNoPosition(texCoord); @@ -108,5 +110,6 @@ void main(void) { _fragColor.rgb += diffuse; _fragColor.rgb += specular; } + */ } diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index 9744d8c78d..8a239f0728 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -28,7 +28,8 @@ #include #include -#include +#include +#include #include #include @@ -157,8 +158,8 @@ void QTestWindow::draw() { testShaderBuild(deferred_light_vert, directional_light_frag); testShaderBuild(deferred_light_vert, directional_ambient_light_frag); testShaderBuild(deferred_light_vert, directional_skybox_light_frag); - testShaderBuild(deferred_light_limited_vert, point_light_frag); - testShaderBuild(deferred_light_limited_vert, spot_light_frag); + testShaderBuild(deferred_light_point_vert, point_light_frag); + testShaderBuild(deferred_light_spot_vert, spot_light_frag); testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag); testShaderBuild(standardTransformPNTC_vert, DrawTextureOpaque_frag); From 6a08c74463a94cc3658c5e822317c43c322c3aa4 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 7 Sep 2016 18:39:07 -0700 Subject: [PATCH 020/104] Several experimetations without success --- libraries/audio/src/AudioInjector.cpp | 2 +- .../gpu-gl/src/gpu/gl/GLBackendState.cpp | 6 +- .../src/DeferredLightingEffect.cpp | 81 +++++++++++++------ libraries/render-utils/src/LightingModel.h | 3 +- .../render-utils/src/RenderDeferredTask.cpp | 2 +- .../render-utils/src/deferred_light_point.slv | 8 +- .../render-utils/src/deferred_light_spot.slv | 7 +- 7 files changed, 68 insertions(+), 41 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index c6368259c0..5fc07adb8d 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -26,7 +26,7 @@ #include "SoundCache.h" #include "AudioSRC.h" -int audioInjectorPtrMetaTypeId = qRegisterMetaType(); +//int audioInjectorPtrMetaTypeId = qRegisterMetaType(); AudioInjectorState operator& (AudioInjectorState lhs, AudioInjectorState rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp index f41570ef7b..1b40af6174 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp @@ -213,13 +213,13 @@ void GLBackend::do_setStateStencil(State::StencilActivation activation, State::S GL_DECR }; if (testFront != testBack) { - glStencilOpSeparate(GL_FRONT, STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getPassOp()], STENCIL_OPS[testFront.getDepthFailOp()]); + glStencilOpSeparate(GL_FRONT, STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getDepthFailOp()], STENCIL_OPS[testFront.getPassOp()]); glStencilFuncSeparate(GL_FRONT, COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask()); - glStencilOpSeparate(GL_BACK, STENCIL_OPS[testBack.getFailOp()], STENCIL_OPS[testBack.getPassOp()], STENCIL_OPS[testBack.getDepthFailOp()]); + glStencilOpSeparate(GL_BACK, STENCIL_OPS[testBack.getFailOp()], STENCIL_OPS[testBack.getDepthFailOp()], STENCIL_OPS[testBack.getPassOp()]); glStencilFuncSeparate(GL_BACK, COMPARISON_TO_GL[testBack.getFunction()], testBack.getReference(), testBack.getReadMask()); } else { - glStencilOp(STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getPassOp()], STENCIL_OPS[testFront.getDepthFailOp()]); + glStencilOp(STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getDepthFailOp()], STENCIL_OPS[testFront.getPassOp()]); glStencilFunc(COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask()); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 4f14b76ac0..3c6608b011 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -78,6 +78,31 @@ enum DeferredShader_BufferSlot { static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& program, LightLocationsPtr& locations); +const char no_light_frag[] = +R"SCRIBE( +//PC 410 core +// Generated on Wed Sep 07 12:11:58 2016 +// +// point_light.frag +// fragment shader +// +// Created by Sam Gateau on 9/18/15. +// Copyright 2014 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 +// +out vec4 _fragColor; + +void main(void) { + _fragColor = vec4(1.0, 1.0, 1.0, 1.0); + + } + + +)SCRIBE" +; + void DeferredLightingEffect::init() { _directionalLightLocations = std::make_shared(); _directionalAmbientSphereLightLocations = std::make_shared(); @@ -99,12 +124,12 @@ void DeferredLightingEffect::init() { loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_frag, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations); loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); - loadLightProgram(deferred_light_vert, local_lights_shading_frag, false, _localLight, _localLightLocations); + loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations); - loadLightVolumeProgram(deferred_light_point_vert, point_light_frag, false, _pointLightBack, _pointLightLocations); - loadLightVolumeProgram(deferred_light_point_vert, point_light_frag, true, _pointLightFront, _pointLightLocations); - loadLightVolumeProgram(deferred_light_spot_vert, spot_light_frag, false, _spotLightBack, _spotLightLocations); - loadLightVolumeProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLightFront, _spotLightLocations); + loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, false, _pointLightBack, _pointLightLocations); + loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, true, _pointLightFront, _pointLightLocations); + loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, false, _spotLightBack, _spotLightLocations); + loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, true, _spotLightFront, _spotLightLocations); // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light _allocatedLights.push_back(std::make_shared()); @@ -223,12 +248,14 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo auto state = std::make_shared(); state->setColorWriteMask(true, true, true, false); - // Stencil test all the light passes for objects pixels only, not the background - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + // state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); if (lightVolume) { - state->setCullMode(gpu::State::CULL_FRONT); - state->setDepthTest(true, false, gpu::GREATER_EQUAL); + state->setStencilTest(true, 0x00, gpu::State::StencilTest(1, 0xFF, gpu::GREATER_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + + state->setCullMode(gpu::State::CULL_BACK); + // state->setCullMode(gpu::State::CULL_FRONT); + // state->setDepthTest(true, false, gpu::GREATER_EQUAL); //state->setDepthClampEnable(true); // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases @@ -236,6 +263,9 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } else { + // Stencil test all the light passes for objects pixels only, not the background + state->setStencilTest(true, 0x00, gpu::State::StencilTest(0, 0x01, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + state->setCullMode(gpu::State::CULL_BACK); // additive blending state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); @@ -289,25 +319,25 @@ static void loadLightVolumeProgram(const char* vertSource, const char* fragSourc locations->shadowTransformBuffer = program->getBuffers().findLocation("shadowTransformBuffer"); auto state = std::make_shared(); - state->setColorWriteMask(true, true, true, false); - // state->setColorWriteMask(false, false, false, false); + // state->setColorWriteMask(true, true, true, false); + state->setColorWriteMask(false, false, false, false); // Stencil test all the light passes for objects pixels only, not the background if (front) { - state->setCullMode(gpu::State::CULL_FRONT); + state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, false, gpu::LESS_EQUAL); - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_INCR, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR)); + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_DECR)); - //state->setDepthClampEnable(true); + // state->setDepthClampEnable(true); // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases // additive blending // state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } else { - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, false, gpu::GREATER_EQUAL); - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_INCR, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR)); + state->setCullMode(gpu::State::CULL_FRONT); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR)); // additive blending // state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } @@ -690,6 +720,9 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), viewport); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewTransform, true); + // gather lights auto& srcPointLights = deferredLightingEffect->_pointLights; auto& srcSpotLights = deferredLightingEffect->_spotLights; @@ -720,8 +753,8 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // before we get to the real lighting, let s try to cull down the number of pixels - { - /* if (numPointLights > 0) { + if (false) { + if (numPointLights > 0) { auto mesh = deferredLightingEffect->getPointLightMesh(); batch.setIndexBuffer(mesh->getIndexBuffer()); batch.setInputBuffer(0, mesh->getVertexBuffer()); @@ -730,16 +763,14 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // Point light pipeline batch.setPipeline(deferredLightingEffect->_pointLightBack); - batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); batch.drawIndexedInstanced(numPointLights, model::Mesh::topologyToPrimitive(pointPart._topology), pointPart._numIndices, pointPart._startIndex, offsetPointLights); batch.setPipeline(deferredLightingEffect->_pointLightFront); - batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); batch.drawIndexedInstanced(numPointLights, model::Mesh::topologyToPrimitive(pointPart._topology), pointPart._numIndices, pointPart._startIndex, offsetPointLights); - } */ - /* + } + if (numSpotLights > 0) { auto mesh = deferredLightingEffect->getSpotLightMesh(); batch.setIndexBuffer(mesh->getIndexBuffer()); @@ -749,15 +780,13 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // Spot light pipeline batch.setPipeline(deferredLightingEffect->_spotLightBack); - batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); batch.drawIndexedInstanced(numSpotLights, model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex, offsetSpotLights); batch.setPipeline(deferredLightingEffect->_spotLightFront); - batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); batch.drawIndexedInstanced(numSpotLights, model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex, offsetSpotLights); - }*/ + } } // Local light pipeline diff --git a/libraries/render-utils/src/LightingModel.h b/libraries/render-utils/src/LightingModel.h index 87a6703dc6..5bb0e621a4 100644 --- a/libraries/render-utils/src/LightingModel.h +++ b/libraries/render-utils/src/LightingModel.h @@ -143,7 +143,8 @@ public: bool enablePointLight{ true }; bool enableSpotLight{ true }; - bool showLightContour{ false }; // false by default + // bool showLightContour { false }; // false by default + bool showLightContour { true }; // false by default signals: void dirty(); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 32aa2b6e16..942419a8a4 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -390,7 +390,7 @@ gpu::PipelinePointer DrawStencilDeferred::getOpaquePipeline() { auto state = std::make_shared(); state->setDepthTest(true, false, gpu::LESS_EQUAL); - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_OPAQUE, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE)); + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_OPAQUE, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_KEEP)); state->setColorWriteMask(0); _opaquePipeline = gpu::Pipeline::create(program, state); diff --git a/libraries/render-utils/src/deferred_light_point.slv b/libraries/render-utils/src/deferred_light_point.slv index f6d4de3954..6bdc6fe42f 100644 --- a/libraries/render-utils/src/deferred_light_point.slv +++ b/libraries/render-utils/src/deferred_light_point.slv @@ -30,17 +30,19 @@ out vec4 _texCoord0; void main(void) { - instanceID = lightIndex[gl_InstanceID]; + int instanceID = lightIndex[gl_InstanceID]; Light light = getLight(instanceID); vec4 sphereVertex = inPosition; + vec3 lightOrigin = getLightPosition(light); vec4 sphereParam = getLightVolumeGeometry(light); sphereVertex.xyz *= sphereParam.w; + sphereVertex.xyz += lightOrigin; + // standard transform TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, sphereVertex, gl_Position)$>; + <$transformWorldToClipPos(cam, sphereVertex, gl_Position)$>; vec4 projected = gl_Position / gl_Position.w; projected.xy = (projected.xy + 1.0) * 0.5; diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index cd70724e1f..c120fa28b1 100755 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -25,11 +25,10 @@ uniform lightIndexBuffer { int lightIndex[120]; }; out vec4 _texCoord0; -flat out int instanceID; void main(void) { vec4 coneVertex = inPosition; - instanceID = lightIndex[gl_InstanceID]; + int instanceID = lightIndex[gl_InstanceID]; Light light = getLight(instanceID); vec3 lightPos = getLightPosition(light); vec4 coneParam = getLightVolumeGeometry(light); @@ -53,10 +52,6 @@ void main(void) { // standard transform TransformCamera cam = getTransformCamera(); - - ; !> - <$transformWorldToClipPos(cam, coneVertex, gl_Position)$>; vec4 projected = gl_Position / gl_Position.w; From a4df8a84b7c26ef5a0ddba3a55741cb44dc8be9d Mon Sep 17 00:00:00 2001 From: sam Date: Thu, 8 Sep 2016 00:11:54 -0700 Subject: [PATCH 021/104] introducing the light Clusters --- .../src/DeferredLightingEffect.cpp | 69 +++---------------- libraries/render-utils/src/LightClusters.cpp | 12 ++++ libraries/render-utils/src/LightClusters.h | 28 ++++++++ 3 files changed, 50 insertions(+), 59 deletions(-) create mode 100644 libraries/render-utils/src/LightClusters.cpp create mode 100644 libraries/render-utils/src/LightClusters.h diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 3c6608b011..94c12f7d99 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -80,26 +80,11 @@ static void loadLightVolumeProgram(const char* vertSource, const char* fragSourc const char no_light_frag[] = R"SCRIBE( -//PC 410 core -// Generated on Wed Sep 07 12:11:58 2016 -// -// point_light.frag -// fragment shader -// -// Created by Sam Gateau on 9/18/15. -// Copyright 2014 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 -// out vec4 _fragColor; void main(void) { _fragColor = vec4(1.0, 1.0, 1.0, 1.0); - - } - - +} )SCRIBE" ; @@ -201,8 +186,7 @@ void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBuff batch.setResourceTexture(skyboxCubemapUnit, keyLight->getAmbientMap()); } } - -static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { +static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* fragSource, LightLocationsPtr& locations) { auto VS = gpu::Shader::createVertex(std::string(vertSource)); auto PS = gpu::Shader::createPixel(std::string(fragSource)); @@ -245,6 +229,13 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo locations->subsurfaceScatteringParametersBuffer = program->getBuffers().findLocation("subsurfaceScatteringParametersBuffer"); locations->shadowTransformBuffer = program->getBuffers().findLocation("shadowTransformBuffer"); + return program; +} + +static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { + + gpu::ShaderPointer program = makeLightProgram(vertSource, fragSource, locations); + auto state = std::make_shared(); state->setColorWriteMask(true, true, true, false); @@ -276,47 +267,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo static void loadLightVolumeProgram(const char* vertSource, const char* fragSource, bool front, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { - auto VS = gpu::Shader::createVertex(std::string(vertSource)); - auto PS = gpu::Shader::createPixel(std::string(fragSource)); - - gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), DEFERRED_BUFFER_COLOR_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), DEFERRED_BUFFER_NORMAL_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), DEFERRED_BUFFER_EMISSIVE_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), DEFERRED_BUFFER_DEPTH_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("obscuranceMap"), DEFERRED_BUFFER_OBSCURANCE_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), SHADOW_MAP_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), SKYBOX_MAP_UNIT)); - - slotBindings.insert(gpu::Shader::Binding(std::string("linearZeyeMap"), DEFERRED_BUFFER_LINEAR_DEPTH_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("curvatureMap"), DEFERRED_BUFFER_CURVATURE_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("diffusedCurvatureMap"), DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("scatteringLUT"), SCATTERING_LUT_UNIT)); - slotBindings.insert(gpu::Shader::Binding(std::string("scatteringSpecularBeckmann"), SCATTERING_SPECULAR_UNIT)); - - - slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), CAMERA_CORRECTION_BUFFER_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), LIGHTING_MODEL_BUFFER_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("subsurfaceScatteringParametersBuffer"), SCATTERING_PARAMETERS_BUFFER_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); - slotBindings.insert(gpu::Shader::Binding(std::string("lightIndexBuffer"), LIGHT_INDEX_GPU_SLOT)); - - - gpu::Shader::makeProgram(*program, slotBindings); - - locations->radius = program->getUniforms().findLocation("radius"); - locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00"); - - locations->texcoordFrameTransform = program->getUniforms().findLocation("texcoordFrameTransform"); - - locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); - locations->lightIndexBufferUnit = program->getBuffers().findLocation("lightIndexBuffer"); - locations->deferredFrameTransformBuffer = program->getBuffers().findLocation("deferredFrameTransformBuffer"); - locations->subsurfaceScatteringParametersBuffer = program->getBuffers().findLocation("subsurfaceScatteringParametersBuffer"); - locations->shadowTransformBuffer = program->getBuffers().findLocation("shadowTransformBuffer"); + gpu::ShaderPointer program = makeLightProgram(vertSource, fragSource, locations); auto state = std::make_shared(); // state->setColorWriteMask(true, true, true, false); diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp new file mode 100644 index 0000000000..f266be988a --- /dev/null +++ b/libraries/render-utils/src/LightClusters.cpp @@ -0,0 +1,12 @@ +// +// LightClusters.cpp +// +// Created by Sam Gateau on 9/7/2016. +// 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 "LightClusters.h" + diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h new file mode 100644 index 0000000000..3557ec0ed0 --- /dev/null +++ b/libraries/render-utils/src/LightClusters.h @@ -0,0 +1,28 @@ +// +// LightClusters.h +// +// Created by Sam Gateau on 9/7/2016. +// 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 +// + +#ifndef hifi_render_utils_LightClusters_h +#define hifi_render_utils_LightClusters_h + +#include "gpu/Framebuffer.h" + +#include "LightStage.h" + +class ViewFrustum; + +class LightClusters { +public: + + LightStagePointer _lightStage; + + gpu::BufferPointer _lightIndicesBuffer; +}; + +#endif From 25616be7c1b51858fbb5d9ead6603a8debc15682 Mon Sep 17 00:00:00 2001 From: sam Date: Thu, 8 Sep 2016 02:16:13 -0700 Subject: [PATCH 022/104] introducing the light Clusters --- libraries/render-utils/src/LightClusters.h | 52 +++++++++++++++++++++- libraries/render-utils/src/LightStage.h | 2 +- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 3557ec0ed0..b3a2271b2e 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -15,11 +15,61 @@ #include "LightStage.h" -class ViewFrustum; +#include +/* +class FrustumGrid { +public: + float _near { 0.1f }; + float _nearPrime { 1.0f }; + float _farPrime { 400.0f }; + float _far { 10000.0f }; + glm::uvec3 _dims { 16, 16, 16 }; + + float viewToLinearDepth(float depth) const { + float nDepth = -depth; + float ldepth = (nDepth - _nearPrime) / (_farPrime - _nearPrime); + + if (ldepth < 0.0f) { + return (nDepth - _near) / (_nearPrime - _near) - 1.0f; + } + if (ldepth > 1.0f) { + return (nDepth - _farPrime) / (_far - _farPrime) + 1.0f; + } + return ldepth; + } + + float linearToGridDepth(float depth) const { + return depth / (float) _dims.z; + } + + glm::vec2 linearToGridXY(const glm::vec3& cpos) const { + return glm::vec2(cpos.x / (float) _dims.x, cpos.y / (float) _dims.y); + } + + int gridDepthToLayer(float gridDepth) const { + return (int) gridDepth; + } + + glm::ivec3 viewToGridPos(const glm::vec3& pos) const { + + return glm::ivec3(0); + } + +}; +*/ class LightClusters { public: + LightClusters(); + + + void updateFrustum(const ViewFrustum& frustum); + + + + ViewFrustum _frustum; + LightStagePointer _lightStage; gpu::BufferPointer _lightIndicesBuffer; diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 4319eb80ba..b0d5c1749f 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -110,5 +110,5 @@ public: Shadows _shadows; }; - +using LightStagePointer = std::shared_ptr; #endif From 61de063b29ebc0f93ee88a3a245dbe2cce45b8a7 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 8 Sep 2016 18:02:35 -0700 Subject: [PATCH 023/104] Developping the Light Clusters, adding visualization --- libraries/gpu/src/gpu/Buffer.h | 17 +++ .../src/AmbientOcclusionEffect.cpp | 30 ++--- .../render-utils/src/AmbientOcclusionEffect.h | 24 +--- .../src/DeferredLightingEffect.cpp | 40 +++++-- .../render-utils/src/DeferredLightingEffect.h | 11 +- libraries/render-utils/src/LightClusters.cpp | 111 ++++++++++++++++++ libraries/render-utils/src/LightClusters.h | 98 ++++++++++++++-- libraries/render-utils/src/LightStage.h | 2 + .../render-utils/src/RenderDeferredTask.cpp | 5 + .../render-utils/src/RenderShadowTask.cpp | 10 +- .../render-utils/src/SubsurfaceScattering.cpp | 2 +- .../src/lightClusters_drawGrid.slf | 19 +++ .../src/lightClusters_drawGrid.slv | 89 ++++++++++++++ libraries/shared/src/ViewFrustum.cpp | 20 ++++ libraries/shared/src/ViewFrustum.h | 3 + 15 files changed, 412 insertions(+), 69 deletions(-) create mode 100644 libraries/render-utils/src/lightClusters_drawGrid.slf create mode 100644 libraries/render-utils/src/lightClusters_drawGrid.slv diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h index 3233dad8a9..e8e04f471a 100644 --- a/libraries/gpu/src/gpu/Buffer.h +++ b/libraries/gpu/src/gpu/Buffer.h @@ -380,6 +380,23 @@ public: } }; + + template class StructBuffer : public gpu::BufferView { + public: + + static BufferPointer makeBuffer() { + T t; + return std::make_shared(sizeof(T), (const gpu::Byte*) &t); + } + ~StructBuffer() {}; + StructBuffer() : gpu::BufferView(makeBuffer()) {} + + const T* operator ->() const { return &get(); } + T& edit() { + return BufferView::edit(0); + } + + }; }; #endif diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 61a8c1f994..4d8403fc4d 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -184,46 +184,46 @@ void AmbientOcclusionEffect::configure(const Config& config) { const double RADIUS_POWER = 6.0; const auto& radius = config.radius; if (radius != _parametersBuffer->getRadius()) { - auto& current = _parametersBuffer->radiusInfo; + auto& current = _parametersBuffer.edit().radiusInfo; current.x = radius; current.y = radius * radius; current.z = (float)(1.0 / pow((double)radius, RADIUS_POWER)); } if (config.obscuranceLevel != _parametersBuffer->getObscuranceLevel()) { - auto& current = _parametersBuffer->radiusInfo; + auto& current = _parametersBuffer.edit().radiusInfo; current.w = config.obscuranceLevel; } if (config.falloffBias != _parametersBuffer->getFalloffBias()) { - auto& current = _parametersBuffer->ditheringInfo; + auto& current = _parametersBuffer.edit().ditheringInfo; current.z = config.falloffBias; } if (config.edgeSharpness != _parametersBuffer->getEdgeSharpness()) { - auto& current = _parametersBuffer->blurInfo; + auto& current = _parametersBuffer.edit().blurInfo; current.x = config.edgeSharpness; } if (config.blurDeviation != _parametersBuffer->getBlurDeviation()) { - auto& current = _parametersBuffer->blurInfo; + auto& current = _parametersBuffer.edit().blurInfo; current.z = config.blurDeviation; shouldUpdateGaussian = true; } if (config.numSpiralTurns != _parametersBuffer->getNumSpiralTurns()) { - auto& current = _parametersBuffer->sampleInfo; + auto& current = _parametersBuffer.edit().sampleInfo; current.z = config.numSpiralTurns; } if (config.numSamples != _parametersBuffer->getNumSamples()) { - auto& current = _parametersBuffer->sampleInfo; + auto& current = _parametersBuffer.edit().sampleInfo; current.x = config.numSamples; current.y = 1.0f / config.numSamples; } if (config.fetchMipsEnabled != _parametersBuffer->isFetchMipsEnabled()) { - auto& current = _parametersBuffer->sampleInfo; + auto& current = _parametersBuffer.edit().sampleInfo; current.w = (float)config.fetchMipsEnabled; } @@ -232,26 +232,26 @@ void AmbientOcclusionEffect::configure(const Config& config) { } if (config.perspectiveScale != _parametersBuffer->getPerspectiveScale()) { - _parametersBuffer->resolutionInfo.z = config.perspectiveScale; + _parametersBuffer.edit().resolutionInfo.z = config.perspectiveScale; } if (config.resolutionLevel != _parametersBuffer->getResolutionLevel()) { - auto& current = _parametersBuffer->resolutionInfo; + auto& current = _parametersBuffer.edit().resolutionInfo; current.x = (float) config.resolutionLevel; } if (config.blurRadius != _parametersBuffer->getBlurRadius()) { - auto& current = _parametersBuffer->blurInfo; + auto& current = _parametersBuffer.edit().blurInfo; current.y = (float)config.blurRadius; shouldUpdateGaussian = true; } if (config.ditheringEnabled != _parametersBuffer->isDitheringEnabled()) { - auto& current = _parametersBuffer->ditheringInfo; + auto& current = _parametersBuffer.edit().ditheringInfo; current.x = (float)config.ditheringEnabled; } if (config.borderingEnabled != _parametersBuffer->isBorderingEnabled()) { - auto& current = _parametersBuffer->ditheringInfo; + auto& current = _parametersBuffer.edit().ditheringInfo; current.w = (float)config.borderingEnabled; } @@ -334,7 +334,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { } void AmbientOcclusionEffect::updateGaussianDistribution() { - auto coefs = _parametersBuffer->_gaussianCoefs; + auto coefs = _parametersBuffer.edit()._gaussianCoefs; GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, _parametersBuffer->getBlurRadius(), _parametersBuffer->getBlurDeviation()); } @@ -451,7 +451,7 @@ void DebugAmbientOcclusion::configure(const Config& config) { auto cursorPos = glm::vec2(_parametersBuffer->pixelInfo); if (cursorPos != config.debugCursorTexcoord) { - _parametersBuffer->pixelInfo = glm::vec4(config.debugCursorTexcoord, 0.0f, 0.0f); + _parametersBuffer.edit().pixelInfo = glm::vec4(config.debugCursorTexcoord, 0.0f, 0.0f); } } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 80904c80a3..4e41926f9f 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -104,26 +104,6 @@ signals: void dirty(); }; - -namespace gpu { -template class UniformBuffer : public gpu::BufferView { - public: - - static BufferPointer makeBuffer() { - T t; - return std::make_shared(sizeof(T), (const gpu::Byte*) &t); - } - ~UniformBuffer() {}; - UniformBuffer() : gpu::BufferView(makeBuffer()) {} - - const T* operator ->() const { return &get(); } - T* operator ->() { - return &edit(0); - } - -}; -} - class AmbientOcclusionEffect { public: using Inputs = render::VaryingSet3; @@ -172,7 +152,7 @@ public: bool isDitheringEnabled() const { return ditheringInfo.x; } bool isBorderingEnabled() const { return ditheringInfo.w; } }; - using ParametersBuffer = gpu::UniformBuffer; + using ParametersBuffer = gpu::StructBuffer; private: void updateGaussianDistribution(); @@ -232,7 +212,7 @@ private: Parameters() {} }; - gpu::UniformBuffer _parametersBuffer; + gpu::StructBuffer _parametersBuffer; const gpu::PipelinePointer& getDebugPipeline(); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 94c12f7d99..7c81aeea22 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -116,6 +116,11 @@ void DeferredLightingEffect::init() { loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, false, _spotLightBack, _spotLightLocations); loadLightVolumeProgram(deferred_light_spot_vert, no_light_frag, true, _spotLightFront, _spotLightLocations); + // Light Stage and clusters + _lightStage = std::make_shared(); + _lightClusters = std::make_shared(); + _lightClusters->updateLightStage(_lightStage); + // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light _allocatedLights.push_back(std::make_shared()); model::LightPointer lp = _allocatedLights[0]; @@ -127,13 +132,13 @@ void DeferredLightingEffect::init() { lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset::OLD_TOWN_SQUARE); // Add the global light to the light stage (for later shadow rendering) - _globalLights.push_back(_lightStage.addLight(lp)); + _globalLights.push_back(_lightStage->addLight(lp)); } void DeferredLightingEffect::addLight(const model::LightPointer& light) { assert(light); - auto lightID = _lightStage.addLight(light); + auto lightID = _lightStage->addLight(light); if (light->getType() == model::Light::POINT) { _pointLights.push_back(lightID); } else { @@ -239,10 +244,8 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo auto state = std::make_shared(); state->setColorWriteMask(true, true, true, false); - // state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); - if (lightVolume) { - state->setStencilTest(true, 0x00, gpu::State::StencilTest(1, 0xFF, gpu::GREATER_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + state->setStencilTest(true, 0x00, gpu::State::StencilTest(1, 0xFF, gpu::LESS_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); state->setCullMode(gpu::State::CULL_BACK); // state->setCullMode(gpu::State::CULL_FRONT); @@ -270,27 +273,29 @@ static void loadLightVolumeProgram(const char* vertSource, const char* fragSourc gpu::ShaderPointer program = makeLightProgram(vertSource, fragSource, locations); auto state = std::make_shared(); - // state->setColorWriteMask(true, true, true, false); - state->setColorWriteMask(false, false, false, false); // Stencil test all the light passes for objects pixels only, not the background if (front) { state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, false, gpu::LESS_EQUAL); - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_DECR)); + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_DECR, gpu::State::STENCIL_OP_KEEP)); // state->setDepthClampEnable(true); // TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases // additive blending // state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + //state->setColorWriteMask(true, true, true, false); + state->setColorWriteMask(false, false, false, false); } else { state->setCullMode(gpu::State::CULL_FRONT); state->setDepthTest(true, false, gpu::LESS_EQUAL); - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR)); + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_INCR, gpu::State::STENCIL_OP_KEEP)); // additive blending // state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + // state->setColorWriteMask(true, true, true, false); + state->setColorWriteMask(false, false, false, false); } pipeline = gpu::Pipeline::create(program, state); @@ -568,8 +573,8 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c // Global directional light and ambient pass - assert(deferredLightingEffect->getLightStage().getNumLights() > 0); - auto lightAndShadow = deferredLightingEffect->getLightStage().getLightAndShadow(0); + assert(deferredLightingEffect->getLightStage()->getNumLights() > 0); + auto lightAndShadow = deferredLightingEffect->getLightStage()->getLightAndShadow(0); const auto& globalShadow = lightAndShadow.second; // Bind the shadow buffer @@ -682,6 +687,8 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, int numSpotLights = (int) srcSpotLights.size(); int offsetSpotLights = numPointLights; + auto lightClusters = deferredLightingEffect->_lightClusters; + std::vector lightIndices(numPointLights + numSpotLights + 1); lightIndices[0] = 0; @@ -695,11 +702,20 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, } if (lightIndices[0] > 0) { + static int frame = 0; + frame++; + + if (frame % 1000 == 0) { + lightClusters->updateFrustum(viewFrustum); + + lightClusters->updateVisibleLights(lightIndices); + } _localLightsBuffer._buffer->setData(lightIndices.size() * sizeof(int), (const gpu::Byte*) lightIndices.data()); _localLightsBuffer._size = lightIndices.size() * sizeof(int); + // Bind the global list of lights and the visible lights this frame - batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()._lightArrayBuffer); + batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()->_lightArrayBuffer); batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightIndexBufferUnit, _localLightsBuffer); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index cbf5ff6ab3..ce29480950 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -28,6 +28,8 @@ #include "LightingModel.h" #include "LightStage.h" +#include "LightClusters.h" + #include "SurfaceGeometryPass.h" #include "SubsurfaceScattering.h" #include "AmbientOcclusionEffect.h" @@ -59,7 +61,8 @@ public: // update global lighting void setGlobalLight(const model::LightPointer& light); - const LightStage& getLightStage() { return _lightStage; } + const LightStagePointer getLightStage() { return _lightStage; } + const LightClustersPointer getLightClusters() { return _lightClusters; } void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; }; void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; } @@ -68,7 +71,9 @@ public: private: DeferredLightingEffect() = default; - LightStage _lightStage; + LightStagePointer _lightStage; + + LightClustersPointer _lightClusters; bool _shadowMapEnabled{ false }; bool _ambientOcclusionEnabled{ false }; @@ -200,4 +205,6 @@ protected: gpu::RangeTimerPointer _gpuTimer; }; + + #endif // hifi_DeferredLightingEffect_h diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index f266be988a..77fe7fa798 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -10,3 +10,114 @@ #include "LightClusters.h" + +#include +#include "lightClusters_drawGrid_vert.h" +#include "lightClusters_drawGrid_frag.h" + +enum LightClusterGridShader_BufferSlot { + LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT = 0, +}; + +#include "DeferredLightingEffect.h" + +LightClusters::LightClusters() { +} + +void LightClusters::updateFrustum(const ViewFrustum& frustum) { + _frustum = frustum; + + _frustrumGridBuffer.edit().updateFrustrum(frustum); +} + +void LightClusters::updateLightStage(const LightStagePointer& lightStage) { + _lightStage = lightStage; +} + +void LightClusters::updateVisibleLights(const LightStage::LightIndices& visibleLights) { + +} + + + + + +DebugLightClusters::DebugLightClusters() { + +} + + +void DebugLightClusters::configure(const Config& config) { +} + +const gpu::PipelinePointer DebugLightClusters::getDrawClusterGridPipeline() { + if (!_drawClusterGrid) { + auto vs = gpu::Shader::createVertex(std::string(lightClusters_drawGrid_vert)); + auto ps = gpu::Shader::createPixel(std::string(lightClusters_drawGrid_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("frustrumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT)); + + gpu::Shader::makeProgram(*program, slotBindings); + + + auto state = std::make_shared(); + + state->setDepthTest(true, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + + // Good to go add the brand new pipeline + _drawClusterGrid = gpu::Pipeline::create(program, state); + } + return _drawClusterGrid; +} + +void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { + auto deferredLightingEffect = DependencyManager::get(); + auto lightClusters = deferredLightingEffect->getLightClusters(); + + + /* auto deferredTransform = inputs.get0(); + auto deferredFramebuffer = inputs.get1(); + auto lightingModel = inputs.get2(); + auto surfaceGeometryFramebuffer = inputs.get3(); + auto ssaoFramebuffer = inputs.get4(); + auto subsurfaceScatteringResource = inputs.get5(); + */ + auto args = renderContext->args; + + + auto drawPipeline = getDrawClusterGridPipeline(); + + gpu::Batch batch; + + + // Assign the camera transform + batch.setViewportTransform(args->_viewport); + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat, true); + + + // Then the actual ClusterGrid attributes + batch.setModelTransform(Transform()); + + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustrumGridBuffer); + + // bind the one gpu::Pipeline we need + batch.setPipeline(drawPipeline); + + if (true) { + batch.draw(gpu::LINES, 24, 0); + } + + + args->_context->appendFrameBatch(batch); + +} \ No newline at end of file diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index b3a2271b2e..9cec0786ed 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -11,12 +11,12 @@ #ifndef hifi_render_utils_LightClusters_h #define hifi_render_utils_LightClusters_h -#include "gpu/Framebuffer.h" - +#include +#include #include "LightStage.h" #include -/* + class FrustumGrid { public: float _near { 0.1f }; @@ -25,6 +25,12 @@ public: float _far { 10000.0f }; glm::uvec3 _dims { 16, 16, 16 }; + float spare; + + glm::mat4 _eyeToGridProj; + glm::mat4 _eyeToGridProjInv; + glm::mat4 _worldToEyeMat; + glm::mat4 _eyeToWorldMat; float viewToLinearDepth(float depth) const { float nDepth = -depth; @@ -43,36 +49,104 @@ public: return depth / (float) _dims.z; } - glm::vec2 linearToGridXY(const glm::vec3& cpos) const { - return glm::vec2(cpos.x / (float) _dims.x, cpos.y / (float) _dims.y); - } - int gridDepthToLayer(float gridDepth) const { return (int) gridDepth; } + glm::vec2 ndcToGridXY(const glm::vec3& ncpos) const { + return 0.5f * glm::vec2((ncpos.x + 1.0f) / (float)_dims.x, (ncpos.y + 1.0f) / (float)_dims.y); + } + glm::ivec3 viewToGridPos(const glm::vec3& pos) const { - - return glm::ivec3(0); + float z = linearToGridDepth(viewToLinearDepth(pos.z)); + + auto cpos = _eyeToGridProj * glm::vec4(pos, 1.0f); + + glm::vec3 ncpos(cpos); + ncpos /= cpos.w; + + + return glm::ivec3(ndcToGridXY(ncpos), (int) linearToGridDepth(z)); + } + + void updateFrustrum(const ViewFrustum& frustum) { + _eyeToGridProj = frustum.evalProjectionMatrixRange(_nearPrime, _farPrime); + _eyeToGridProjInv = glm::inverse(_eyeToGridProj); + + Transform view; + frustum.evalViewTransform(view); + _eyeToWorldMat = view.getMatrix(); + _worldToEyeMat = view.getInverseMatrix(); } }; -*/ + class LightClusters { public: LightClusters(); - void updateFrustum(const ViewFrustum& frustum); - + void updateLightStage(const LightStagePointer& lightStage); + + void updateVisibleLights(const LightStage::LightIndices& visibleLights); + + + // FrustumGrid _grid; ViewFrustum _frustum; LightStagePointer _lightStage; + + + gpu::StructBuffer _frustrumGridBuffer; + + gpu::BufferPointer _lightIndicesBuffer; }; +using LightClustersPointer = std::shared_ptr; + + + +class DebugLightClustersConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) + Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) +public: + DebugLightClustersConfig() : render::Job::Config(true){} + + int getNumDrawn() { return numDrawn; } + void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); } + + int maxDrawn { -1 }; + +signals: + void numDrawnChanged(); + void dirty(); + +protected: + int numDrawn { 0 }; +}; + +class DebugLightClusters { +public: + // using Inputs = render::VaryingSet6 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer, SubsurfaceScatteringResourcePointer>; + using Config = DebugLightClustersConfig; + using JobModel = render::Job::Model; + + DebugLightClusters(); + + void configure(const Config& config); + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + +protected: + gpu::BufferPointer _gridBuffer; + gpu::PipelinePointer _drawClusterGrid; + const gpu::PipelinePointer getDrawClusterGridPipeline(); +}; + #endif diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index b0d5c1749f..c0632a0ebf 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -32,6 +32,8 @@ public: using Lights = render::indexed_container::IndexedPointerVector; using LightMap = std::unordered_map; + using LightIndices = std::vector; + class Shadow { public: using UniformBufferView = gpu::BufferView; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 942419a8a4..6076cf697d 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -190,6 +190,11 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { addJob("DrawItemSelection", spatialSelection); } + // LIght Cluster Grid Debuging job + { + addJob("DebugLightClusters"); + } + // Status icon rendering job { // Grab a texture map representing the different status icons and assign that to the drawStatsuJob diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 2efbe7bf89..aed360823d 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -36,12 +36,12 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); - const auto& lightStage = DependencyManager::get()->getLightStage(); + auto lightStage = DependencyManager::get()->getLightStage(); LightStage::Index globalLightIndex { 0 }; - const auto globalLight = lightStage.getLight(globalLightIndex); - const auto shadow = lightStage.getShadow(globalLightIndex); + const auto globalLight = lightStage->getLight(globalLightIndex); + const auto shadow = lightStage->getShadow(globalLightIndex); if (!shadow) return; const auto& fbo = shadow->framebuffer; @@ -144,8 +144,8 @@ void RenderShadowTask::run(const SceneContextPointer& sceneContext, const render return; } - const auto& lightStage = DependencyManager::get()->getLightStage(); - const auto globalShadow = lightStage.getShadow(0); + auto lightStage = DependencyManager::get()->getLightStage(); + const auto globalShadow = lightStage->getShadow(0); // If the global light is not set, bail if (!globalShadow) { diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index d78cbdb304..d49c388da3 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -530,7 +530,7 @@ void DebugSubsurfaceScattering::run(const render::SceneContextPointer& sceneCont - const auto light = DependencyManager::get()->getLightStage().getLight(0); + const auto light = DependencyManager::get()->getLightStage()->getLight(0); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); diff --git a/libraries/render-utils/src/lightClusters_drawGrid.slf b/libraries/render-utils/src/lightClusters_drawGrid.slf new file mode 100644 index 0000000000..33c8cc56b8 --- /dev/null +++ b/libraries/render-utils/src/lightClusters_drawGrid.slf @@ -0,0 +1,19 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// lightClusters_drawGrid.slf +// +// Created by Sam Gateau on 9/8/2016. +// 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 +// + +in vec4 varColor; +out vec4 outFragColor; + + +void main(void) { + outFragColor = varColor; +} diff --git a/libraries/render-utils/src/lightClusters_drawGrid.slv b/libraries/render-utils/src/lightClusters_drawGrid.slv new file mode 100644 index 0000000000..db7006322c --- /dev/null +++ b/libraries/render-utils/src/lightClusters_drawGrid.slv @@ -0,0 +1,89 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// lightClusters_drawGrid.slv +// Vertex shader +// +// Created by Sam Gateau on 9/8/2016 +// 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/Transform.slh@> + +<$declareStandardTransform()$> + +<@include gpu/Color.slh@> +<$declareColorWheel()$> + + +struct FrustrumGrid { + vec4 nearFarRange; + ivec4 dims; + mat4 eyeToGridProj; + mat4 eyeToGridProjInv; + mat4 worldToEyeMat; + mat4 eyeToWorldMat; +}; + +uniform frustrumGridBuffer { + FrustrumGrid frustrumGrid; +}; + +//uniform ivec4 inClusterLocation; + +out vec4 varColor; + + +void main(void) { + const vec4 UNIT_BOX[8] = vec4[8]( + vec4(0.0, 0.0, 0.0, 1.0), + vec4(1.0, 0.0, 0.0, 1.0), + vec4(0.0, 1.0, 0.0, 1.0), + vec4(1.0, 1.0, 0.0, 1.0), + vec4(0.0, 0.0, 1.0, 1.0), + vec4(1.0, 0.0, 1.0, 1.0), + vec4(0.0, 1.0, 1.0, 1.0), + vec4(1.0, 1.0, 1.0, 1.0) + ); + const int UNIT_BOX_LINE_INDICES[24] = int[24]( + 0, 1, + 1, 3, + 3, 2, + 2, 0, + 4, 5, + 5, 7, + 7, 6, + 6, 4, + 2, 6, + 3, 7, + 0, 4, + 1, 5 + ); + vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; + + // pos.z -= 10.0f; + + + vec4 eyePos = frustrumGrid.eyeToGridProjInv * (pos); + + eyePos.xyz *= eyePos.w; + + vec4 worldPos = frustrumGrid.eyeToWorldMat * vec4(eyePos.xyz, 1.0); + + /* + int cellIsEmpty = sign(inClusterLocation.w); + ivec4 cellLocation = ivec4(inClusterLocation.xyz, (inClusterLocation.w < 0 ? -inClusterLocation.w : inClusterLocation.w)); + vec4 cellBound = evalBound(cellLocation); + + pos.xyz = cellBound.xyz + vec3(cellBound.w) * pos.xyz; + */ + // standard transform + TransformCamera cam = getTransformCamera(); + <$transformWorldToClipPos(cam, worldPos, gl_Position)$> + + varColor = vec4(colorWheel(fract(float(gl_VertexID) / 24.0)), 0.9); +} \ No newline at end of file diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index 4a7d4eff95..0a1a41ace1 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -657,6 +657,26 @@ void ViewFrustum::evalProjectionMatrix(glm::mat4& proj) const { proj = _projection; } +glm::mat4 ViewFrustum::evalProjectionMatrixRange(float rangeNear, float rangeFar) const { + + // make sure range near far make sense + assert(rangeNear > 0.0); + assert(rangeFar > rangeNear); + + // recreate a projection matrix for only a range of depth of this frustum. + + // take the current projection + glm::mat4 rangeProj = _projection; + + float A = -(rangeFar + rangeNear) / (rangeFar - rangeNear); + float B = -2 * rangeFar*rangeNear / ((rangeFar - rangeNear)); + + rangeProj[2][2] = A; + rangeProj[3][2] = B; + return rangeProj; +} + + void ViewFrustum::evalViewTransform(Transform& view) const { view.setTranslation(getPosition()); view.setRotation(getOrientation()); diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index 48d45ab455..091aff7a92 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -129,6 +129,9 @@ public: float distanceToCamera(const glm::vec3& point) const; void evalProjectionMatrix(glm::mat4& proj) const; + + glm::mat4 evalProjectionMatrixRange(float rangeNear, float rangeFar) const; + void evalViewTransform(Transform& view) const; enum PlaneIndex { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE, NUM_PLANES }; From 9bcaca057723fdf2cf9d1f78b3e0bdadef296e8e Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 8 Sep 2016 19:12:11 -0700 Subject: [PATCH 024/104] Developping the Light Clusters, adding visualization --- .../src/lightClusters_drawGrid.slv | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/lightClusters_drawGrid.slv b/libraries/render-utils/src/lightClusters_drawGrid.slv index db7006322c..4c32be6d5c 100644 --- a/libraries/render-utils/src/lightClusters_drawGrid.slv +++ b/libraries/render-utils/src/lightClusters_drawGrid.slv @@ -33,6 +33,18 @@ uniform frustrumGridBuffer { FrustrumGrid frustrumGrid; }; +float getProjectionNear(mat4 projection) { + float planeC = projection[2][3] + projection[2][2]; + float planeD = projection[3][2]; + return planeD / planeC; +} +float getProjectionFar(mat4 projection) { + //float planeA = projection[0][3] - projection[0][2]; + //float planeB = projection[1][3] - projection[1][2]; + float planeC = projection[2][3] - projection[2][2]; + float planeD = /*projection[3][3]*/ - projection[3][2]; + return planeD / planeC; +} //uniform ivec4 inClusterLocation; out vec4 varColor; @@ -66,14 +78,24 @@ void main(void) { vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; // pos.z -= 10.0f; + vec3 cpos = vec3(1, 0, 1); + // float z = frustrumGrid.nearFarRange.y * (1 - pos.z) + frustrumGrid.nearFarRange.z * (pos.z); + vec3 gridScale = vec3(0.5, 0.5, 1.0) / vec3(frustrumGrid.dims.xyz); - vec4 eyePos = frustrumGrid.eyeToGridProjInv * (pos); + vec3 cvpos = cpos + pos.xyz; + + vec3 clusterStart = vec3(-1.0 + cvpos.x * gridScale.x, -1.0 + cvpos.y * gridScale.y, cvpos.z * gridScale.z); + + float z = getProjectionNear(frustrumGrid.eyeToGridProj) * (1 - clusterStart.z) + getProjectionFar(frustrumGrid.eyeToGridProj) * (clusterStart.z); + + vec4 eyePos = frustrumGrid.eyeToGridProjInv * (vec4(clusterStart.xy, 1.0, 1.0) * z); eyePos.xyz *= eyePos.w; vec4 worldPos = frustrumGrid.eyeToWorldMat * vec4(eyePos.xyz, 1.0); + /* int cellIsEmpty = sign(inClusterLocation.w); ivec4 cellLocation = ivec4(inClusterLocation.xyz, (inClusterLocation.w < 0 ? -inClusterLocation.w : inClusterLocation.w)); From a0d09e3316bcf0764a700ed4b0d6ce2789852982 Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 10 Sep 2016 10:14:31 -0700 Subject: [PATCH 025/104] Fixing the vizualisation shader for world to cluster space --- .../src/DeferredLightingEffect.cpp | 2 +- .../src/LightClusterGrid_shared.slh | 171 +++++++++--------- libraries/render-utils/src/LightClusters.cpp | 24 +-- libraries/render-utils/src/LightClusters.h | 13 +- .../render-utils/src/RenderDeferredTask.cpp | 14 +- .../lightClusters_drawClusterFromDepth.slf | 64 ++++--- .../render-utils/src/local_lights_shading.slf | 2 +- .../render/src/render/IndexedContainer.h | 4 +- 8 files changed, 162 insertions(+), 132 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index c1f011fd79..7c81aeea22 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -705,7 +705,7 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, static int frame = 0; frame++; - if (frame % 2000 == 0) { + if (frame % 1000 == 0) { lightClusters->updateFrustum(viewFrustum); lightClusters->updateVisibleLights(lightIndices); diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index c89d0e4c9b..37addee004 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -1,91 +1,98 @@ - // glsl / C++ compatible source as interface for FrustrumGrid +// glsl / C++ compatible source as interface for FrustrumGrid - int frustumGrid_numClusters() { - return frustumGrid.dims.x * frustumGrid.dims.y * frustumGrid.dims.z; +int frustumGrid_numClusters() { + return frustumGrid.dims.x * frustumGrid.dims.y * frustumGrid.dims.z; +} + + +float frustumGrid_depthRamp(float linear) { + // return linear; + return linear * linear; +} +float frustumGrid_depthRampInverse(float volume) { + // return volume; + return sqrt(volume); +} + +vec3 frustumGrid_gridToVolume(vec3 pos, ivec3 dims) { + vec3 gridScale = vec3(1.0, 1.0, 1.0) / vec3(dims); + vec3 volumePos = pos * gridScale; + volumePos.z = frustumGrid_depthRamp(volumePos.z); + return volumePos; +} + + +vec3 frustumGrid_volumeToGrid(vec3 vpos, ivec3 dims) { + vec3 gridPos = vec3(vpos.x, vpos.y, frustumGrid_depthRampInverse(vpos.z)) * vec3(dims); + return gridPos; +} + +vec4 frustumGrid_volumeToClip(vec3 vpos, float rangeNear, float rangeFar) { + vec3 ndcPos = vec3(-1.0 + 2.0 * vpos.x, -1.0 + 2.0 * vpos.y, vpos.z); + float depth = rangeNear * (1 - ndcPos.z) + rangeFar * (ndcPos.z); + vec4 clipPos = vec4(ndcPos.x * depth, ndcPos.y * depth, 1.0, depth); + return clipPos; +} + +vec3 frustumGrid_clipToEye(vec4 clipPos, mat4 projection) { + return vec3( + (clipPos.x + projection[2][0] * clipPos.w) / projection[0][0], + (clipPos.y + projection[2][1] * clipPos.w) / projection[1][1], + -clipPos.w + //, (clipPos.z - projection[3][3] * clipPos.w) / projection[3][2] + ); +} + +vec3 frustumGrid_volumeToEye(vec3 vpos, mat4 projection, float rangeNear, float rangeFar) { + return frustumGrid_clipToEye(frustumGrid_volumeToClip(vpos, rangeNear, rangeFar), projection); +} + + +vec3 frustumGrid_eyeToVolume(vec3 epos, mat4 projection, float rangeNear, float rangeFar) { + vec4 clipPos = vec4(epos.x * projection[0][0] + epos.z * projection[2][0], + epos.y * projection[1][1] + epos.z * projection[2][1], + epos.z * projection[2][2] + projection[2][3], + -epos.z); + vec4 ndcPos = clipPos / clipPos.w; + + vec3 volumePos = vec3(0.5 * (ndcPos.x + 1.0), 0.5 * (ndcPos.y + 1.0), (clipPos.w - rangeNear) / (rangeFar - rangeNear)); + return volumePos; +} + + +vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) { + + vec3 cvpos = vec3(clusterPos) + offset; + + + vec3 volumePos = frustumGrid_gridToVolume(cvpos, frustumGrid.dims); + + vec3 eyePos = frustumGrid_volumeToEye(volumePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar); + + return eyePos; +} + + +ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { + if ((eyePos.z > -frustumGrid.frustumNear) || (eyePos.z < -frustumGrid.frustumFar)) { + return ivec3(-1); } + + vec3 volumePos = frustumGrid_eyeToVolume(eyePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar); + + vec3 gridPos = frustumGrid_volumeToGrid(volumePos, frustumGrid.dims); - float frustumGrid_depthRamp(float linear) { - // return linear; - return linear * linear; - } - float frustumGrid_depthRampInverse(float volume) { - // return volume; - return sqrt(volume); - } + return ivec3(gridPos); +} - vec3 frustumGrid_gridToVolume(vec3 pos, ivec3 dims) { - vec3 gridScale = vec3(1.0, 1.0, 1.0) / vec3(dims); - vec3 volumePos = pos * gridScale; - volumePos.z = frustumGrid_depthRamp(volumePos.z); - return volumePos; - } +vec4 frustumGrid_eyeToWorld(vec4 eyePos) { + return frustumGrid.eyeToWorldMat * eyePos; +} - - vec3 frustumGrid_volumeToGrid(vec3 vpos, ivec3 dims) { - vec3 gridPos = vec3(vpos.x, vpos.y, frustumGrid_depthRampInverse(vpos.z)) * vec3(dims); - return gridPos; - } - - vec4 frustumGrid_volumeToClip(vec3 vpos, float rangeNear, float rangeFar) { - vec3 ndcPos = vec3(-1.0 + 2.0 * vpos.x, -1.0 + 2.0 * vpos.y, vpos.z); - float depth = rangeNear * (1 - ndcPos.z) + rangeFar * (ndcPos.z); - vec4 clipPos = vec4(ndcPos.x * depth, ndcPos.y * depth, 1.0, depth); - return clipPos; - } - - vec3 frustumGrid_clipToEye(vec4 clipPos, mat4 projection) { - return vec3( - (clipPos.x + projection[2][0] * clipPos.w) / projection[0][0], - (clipPos.y + projection[2][1] * clipPos.w) / projection[1][1], - -clipPos.w - //, (clipPos.z - projection[3][3] * clipPos.w) / projection[3][2] - ); - } - - vec3 frustumGrid_volumeToEye(vec3 vpos, mat4 projection, float rangeNear, float rangeFar) { - return frustumGrid_clipToEye(frustumGrid_volumeToClip(vpos, rangeNear, rangeFar), projection); - } - - - vec3 frustumGrid_eyeToVolume(vec3 epos, mat4 projection, float rangeNear, float rangeFar) { - vec4 clipPos = vec4(epos.x * projection[0][0] + epos.z * projection[2][0], - epos.y * projection[1][1] + epos.z * projection[2][1], - epos.z * projection[2][2] + projection[2][3], - -epos.z); - vec4 ndcPos = clipPos / clipPos.w; - - vec3 volumePos = vec3(0.5 * (ndcPos.x + 1.0), 0.5 * (ndcPos.y + 1.0), (clipPos.w - rangeNear) / (rangeFar - rangeNear)); - return volumePos; - } - - - vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset = vec3(0.5)) { - - vec3 cvpos = vec3(clusterPos) + offset; - - - vec3 volumePos = frustumGrid_gridToVolume(cvpos, frustumGrid.dims); - - vec3 eyePos = frustumGrid_volumeToEye(volumePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar); - - return eyePos; - } - - - ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { - - vec3 volumePos = frustumGrid_eyeToVolume(eyePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar); - - vec3 gridPos = frustumGrid_volumeToGrid(volumePos, frustumGrid.dims); - - - return ivec3(gridPos); - } - - vec4 frustumGrid_eyeToWorld(vec4 eyePos) { - return frustumGrid.eyeToWorldMat * eyePos; - } +vec4 frustumGrid_worldToEye(vec4 worldPos) { + return frustumGrid.worldToEyeMat * worldPos; +} // <@if 1@> // Trigger Scribe include diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index faf50129c5..54902a104d 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -22,7 +22,7 @@ #include "lightClusters_drawClusterFromDepth_frag.h" enum LightClusterGridShader_MapSlot { - DEFERRED_BUFFER_LINEAR_DEPTH_UNIT = 7, + DEFERRED_BUFFER_LINEAR_DEPTH_UNIT = 0, }; enum LightClusterGridShader_BufferSlot { @@ -126,7 +126,7 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co auto deferredTransform = inputs.get0(); auto deferredFramebuffer = inputs.get1(); auto lightingModel = inputs.get2(); - auto surfaceGeometryFramebuffer = inputs.get3(); + auto linearDepthTarget = inputs.get3(); auto args = renderContext->args; @@ -149,21 +149,14 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co - if (true) { - // bind the one gpu::Pipeline we need - batch.setPipeline(getDrawClusterGridPipeline()); - auto dims = lightClusters->_frustumGridBuffer->dims; - glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x); - batch.drawInstanced(summedDims.x, gpu::LINES, 24, 0); - } if (true) { batch.setPipeline(getDrawClusterFromDepthPipeline()); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer()); - if (surfaceGeometryFramebuffer) { - batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, surfaceGeometryFramebuffer->getLinearDepthTexture()); + if (linearDepthTarget) { + batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, linearDepthTarget->getLinearDepthTexture()); } batch.draw(gpu::TRIANGLE_STRIP, 4, 0); @@ -173,7 +166,14 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); } - + if (true) { + // bind the one gpu::Pipeline we need + batch.setPipeline(getDrawClusterGridPipeline()); + + auto dims = lightClusters->_frustumGridBuffer->dims; + glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x); + batch.drawInstanced(summedDims.x, gpu::LINES, 24, 0); + } args->_context->appendFrameBatch(batch); } \ No newline at end of file diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 4491f5459d..474b238907 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -19,25 +19,28 @@ class FrustumGrid { public: - float _near { 0.1f }; + float frustumNear { 0.1f }; float rangeNear { 1.0f }; float rangeFar { 100.0f }; - float _far { 10000.0f }; + float frustumFar { 10000.0f }; glm::ivec3 dims { 8, 8, 8 }; float spare; glm::mat4 eyeToGridProj; - glm::mat4 _worldToEyeMat; + glm::mat4 worldToEyeMat; glm::mat4 eyeToWorldMat; void updateFrustum(const ViewFrustum& frustum) { + frustumNear = frustum.getNearClip(); + frustumFar = frustum.getFarClip(); + eyeToGridProj = frustum.evalProjectionMatrixRange(rangeNear, rangeFar); Transform view; frustum.evalViewTransform(view); eyeToWorldMat = view.getMatrix(); - _worldToEyeMat = view.getInverseMatrix(); + worldToEyeMat = view.getInverseMatrix(); } // Copy paste of the slh functions @@ -105,7 +108,7 @@ protected: class DebugLightClusters { public: - using Inputs = render::VaryingSet4 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer>; + using Inputs = render::VaryingSet4 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, LinearDepthFramebufferPointer>; using Config = DebugLightClustersConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index f0438088ad..c683301c90 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -154,7 +154,13 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { // Use Stencil and draw background in Lighting buffer to complete filling in the opaque const auto backgroundInputs = DrawBackgroundDeferred::Inputs(background, lightingModel).hasVarying(); addJob("DrawBackgroundDeferred", backgroundInputs); - + + // LIght Cluster Grid Debuging job + { + const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget).hasVarying(); + addJob("DebugLightClusters", debugLightClustersInputs); + } + // Render transparent objects forward in LightingBuffer const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying(); addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); @@ -190,11 +196,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { addJob("DrawItemSelection", spatialSelection); } - // LIght Cluster Grid Debuging job - { - const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget).hasVarying(); - addJob("DebugLightClusters", debugLightClustersInputs); - } + // Status icon rendering job { diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index a30fa78680..272f80c99f 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -21,7 +21,7 @@ <$declareColorWheel()$> -in vec4 varTexCoord0; +in vec2 varTexCoord0; out vec4 _fragColor; void main(void) { @@ -30,32 +30,50 @@ void main(void) { vec2 texCoord = varTexCoord0.st; float Zeye = texture(linearZeyeMap, texCoord).x; - _fragColor = vec4(vec3(0.1 * (10 - Zeye)), 1.0); - // return; + if (Zeye <= 0.1) { + return; + } + + // _fragColor = vec4(colorWheel(fract(0.1 * Zeye)),.5); + // return; vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord); - -// return; - - ivec3 dims = frustumGrid.dims.xyz; - - ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); - - - vec3 eyePos = fragPosition.xyz; - + // Frag pos in world + vec4 fragWorldPos = getViewInverse() * fragPosition; + + // From frag world pos find the cluster + //vec3 fragEyePos = fragPosition.xyz; + // vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0)); + vec4 clusterEyePos = frustumGrid_worldToEye(fragWorldPos); + ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); - ivec3 clusterPos = frustumGrid_eyeToClusterPos(eyePos); - - - // standard transform - // TransformCamera cam = getTransformCamera(); - // <$transformWorldToClipPos(cam, worldPos, gl_Position)$> - - _fragColor = vec4(colorWheel(fract(float(clusterPos.z * summedDims.x + clusterPos.y * summedDims.y + clusterPos.x) / float(frustumGrid_numClusters()))), 0.9); - _fragColor = vec4(abs(fract(eyePos * 0.5)), 0.9); - + ivec3 dims = frustumGrid.dims.xyz; + ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); + + if (clusterPos.x < 0 || clusterPos.x >= dims.x) { + _fragColor = vec4(0.0); + return; + } + + if (clusterPos.y < 0 || clusterPos.y >= dims.y) { + _fragColor = vec4(0.0); + return; + } + if (clusterPos.z < 0 || clusterPos.z >= dims.z) { + _fragColor = vec4(0.0); + return; + } + + float relClusterId = float(clusterPos.z * summedDims.x + clusterPos.y * summedDims.y + clusterPos.x) / float(frustumGrid_numClusters()); + + if (relClusterId < 0.0) { + _fragColor = vec4(0.0); + } else if (relClusterId >= 1.0) { + _fragColor = vec4(vec3(1.0), 0.5); + } else { + _fragColor = vec4(colorWheel(fract(relClusterId)), 0.9); + } } diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index d5a759d7c0..c3e41fb672 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -30,7 +30,7 @@ uniform lightIndexBuffer { <@include LightSpot.slh@> <$declareLightingSpot(supportScattering)$> -in vec4 _texCoord0; +in vec2 _texCoord0; out vec4 _fragColor; void main(void) { diff --git a/libraries/render/src/render/IndexedContainer.h b/libraries/render/src/render/IndexedContainer.h index 847fb53bdf..6250d4f4f1 100644 --- a/libraries/render/src/render/IndexedContainer.h +++ b/libraries/render/src/render/IndexedContainer.h @@ -117,10 +117,10 @@ namespace indexed_container { Index newElement(const ElementPtr& e) { Index index = _allocator.allocateIndex(); if (index != INVALID_INDEX) { - if (index < _elements.size()) { + if (index < (Index) _elements.size()) { _elements.emplace(_elements.begin() + index, e); } else { - assert(index == _elements.size()); + assert(index == (Index) _elements.size()); _elements.emplace_back(e); } } From 7a7a60a5c497b89d78f1f3ba6a0c1a53657e9c66 Mon Sep 17 00:00:00 2001 From: samcake Date: Sun, 11 Sep 2016 00:17:34 -0700 Subject: [PATCH 026/104] INtroducing a true stage for updating the light cluster and ui to debug --- .../src/DeferredLightingEffect.cpp | 41 ++++----- .../render-utils/src/DeferredLightingEffect.h | 7 +- .../src/LightClusterGrid_shared.slh | 18 ++-- libraries/render-utils/src/LightClusters.cpp | 88 ++++++++++++++++--- libraries/render-utils/src/LightClusters.h | 79 +++++++++++++---- .../render-utils/src/RenderDeferredTask.cpp | 24 +++-- .../lightClusters_drawClusterFromDepth.slf | 20 +---- .../render-utils/src/local_lights_shading.slf | 4 +- libraries/render/src/render/Task.h | 34 +++++++ .../utilities/render/lightClustering.js | 21 +++++ .../utilities/render/lightClustering.qml | 45 ++++++++++ 11 files changed, 292 insertions(+), 89 deletions(-) create mode 100644 scripts/developer/utilities/render/lightClustering.js create mode 100644 scripts/developer/utilities/render/lightClustering.qml diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 7c81aeea22..e6ca901376 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -634,7 +634,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c } RenderDeferredLocals::RenderDeferredLocals() : -_localLightsBuffer(std::make_shared()) { + _localLightsBuffer(std::make_shared()) { } @@ -642,7 +642,7 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, const DeferredFrameTransformPointer& frameTransform, const DeferredFramebufferPointer& deferredFramebuffer, const LightingModelPointer& lightingModel, - const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer) { + const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer, const LightClustersPointer& lightClusters) { bool points = lightingModel->isPointLightEnabled(); bool spots = lightingModel->isSpotLightEnabled(); @@ -676,18 +676,17 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), viewport); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewTransform, true); + // batch.setProjectionTransform(projMat); + // batch.setViewTransform(viewTransform, true); // gather lights - auto& srcPointLights = deferredLightingEffect->_pointLights; + /* auto& srcPointLights = deferredLightingEffect->_pointLights; auto& srcSpotLights = deferredLightingEffect->_spotLights; int numPointLights = (int) srcPointLights.size(); int offsetPointLights = 0; int numSpotLights = (int) srcSpotLights.size(); int offsetSpotLights = numPointLights; - auto lightClusters = deferredLightingEffect->_lightClusters; std::vector lightIndices(numPointLights + numSpotLights + 1); lightIndices[0] = 0; @@ -699,28 +698,21 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, if (spots && !srcSpotLights.empty()) { memcpy(lightIndices.data() + (lightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int)); lightIndices[0] += (int)srcSpotLights.size(); - } - - if (lightIndices[0] > 0) { - static int frame = 0; - frame++; - - if (frame % 1000 == 0) { - lightClusters->updateFrustum(viewFrustum); - - lightClusters->updateVisibleLights(lightIndices); - } - _localLightsBuffer._buffer->setData(lightIndices.size() * sizeof(int), (const gpu::Byte*) lightIndices.data()); - _localLightsBuffer._size = lightIndices.size() * sizeof(int); + }*/ + //auto lightClusters = deferredLightingEffect->_lightClusters; + auto& lightIndices = lightClusters->_visibleLightIndices; + if (!lightIndices.empty() && lightIndices[0] > 0) { + // _localLightsBuffer._buffer->setData(lightIndices.size() * sizeof(int), (const gpu::Byte*) lightIndices.data()); + // _localLightsBuffer._size = lightIndices.size() * sizeof(int); // Bind the global list of lights and the visible lights this frame - batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, deferredLightingEffect->getLightStage()->_lightArrayBuffer); - batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightIndexBufferUnit, _localLightsBuffer); + batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, lightClusters->_lightStage->_lightArrayBuffer); + batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightIndexBufferUnit, lightClusters->_lightIndicesBuffer); // before we get to the real lighting, let s try to cull down the number of pixels - if (false) { + if (false) {/* if (numPointLights > 0) { auto mesh = deferredLightingEffect->getPointLightMesh(); batch.setIndexBuffer(mesh->getIndexBuffer()); @@ -753,7 +745,7 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch.setPipeline(deferredLightingEffect->_spotLightFront); batch.drawIndexedInstanced(numSpotLights, model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex, offsetSpotLights); - } + }*/ } // Local light pipeline @@ -815,6 +807,7 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo auto surfaceGeometryFramebuffer = inputs.get3(); auto ssaoFramebuffer = inputs.get4(); auto subsurfaceScatteringResource = inputs.get5(); + auto lightClusters = inputs.get6(); auto args = renderContext->args; if (!_gpuTimer) { @@ -828,7 +821,7 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo setupJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, ssaoFramebuffer, subsurfaceScatteringResource); - lightsJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer); + lightsJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, lightClusters); cleanupJob.run(sceneContext, renderContext); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index ce29480950..a66a2ed2ed 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -117,7 +117,7 @@ private: std::vector _pointLights; std::vector _spotLights; - + friend class LightClusteringPass; friend class RenderDeferredSetup; friend class RenderDeferredLocals; friend class RenderDeferredCleanup; @@ -167,7 +167,8 @@ public: const DeferredFrameTransformPointer& frameTransform, const DeferredFramebufferPointer& deferredFramebuffer, const LightingModelPointer& lightingModel, - const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer); + const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer, + const LightClustersPointer& lightClusters); gpu::BufferView _localLightsBuffer; @@ -187,7 +188,7 @@ using RenderDeferredConfig = render::GPUJobConfig; class RenderDeferred { public: - using Inputs = render::VaryingSet6 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer, SubsurfaceScatteringResourcePointer>; + using Inputs = render::VaryingSet7 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer, SubsurfaceScatteringResourcePointer, LightClustersPointer>; using Config = RenderDeferredConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 37addee004..5ccba9a786 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -1,10 +1,5 @@ // glsl / C++ compatible source as interface for FrustrumGrid -int frustumGrid_numClusters() { - return frustumGrid.dims.x * frustumGrid.dims.y * frustumGrid.dims.z; -} - - float frustumGrid_depthRamp(float linear) { // return linear; return linear * linear; @@ -60,6 +55,11 @@ vec3 frustumGrid_eyeToVolume(vec3 epos, mat4 projection, float rangeNear, float } + +int frustumGrid_numClusters() { + return frustumGrid.dims.x * frustumGrid.dims.y * (frustumGrid.dims.z); +} + vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) { vec3 cvpos = vec3(clusterPos) + offset; @@ -78,9 +78,17 @@ ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { return ivec3(-1); } + if (eyePos.z > -frustumGrid.rangeNear) { + return ivec3(0,0,-1); + } + vec3 volumePos = frustumGrid_eyeToVolume(eyePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar); vec3 gridPos = frustumGrid_volumeToGrid(volumePos, frustumGrid.dims); + + if (gridPos.z >= frustumGrid.dims.z) { + gridPos.z = frustumGrid.dims.z; + } return ivec3(gridPos); diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 54902a104d..e98322da4d 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -35,7 +35,8 @@ enum LightClusterGridShader_BufferSlot { #include "DeferredLightingEffect.h" -LightClusters::LightClusters() { +LightClusters::LightClusters() : +_lightIndicesBuffer(std::make_shared()) { } void LightClusters::updateFrustum(const ViewFrustum& frustum) { @@ -49,12 +50,77 @@ void LightClusters::updateLightStage(const LightStagePointer& lightStage) { } void LightClusters::updateVisibleLights(const LightStage::LightIndices& visibleLights) { - + + _visibleLightIndices.clear(); + // _lightClusters->_visibleLightIndices.push_back(0); + _visibleLightIndices = visibleLights; + _lightIndicesBuffer._buffer->setData(_visibleLightIndices.size() * sizeof(int), (const gpu::Byte*) _visibleLightIndices.data()); + _lightIndicesBuffer._size = _visibleLightIndices.size() * sizeof(int); } +LightClusteringPass::LightClusteringPass() { +} +void LightClusteringPass::configure(const Config& config) { + if (_lightClusters) { + if (_lightClusters->_frustumGridBuffer->rangeNear != config.rangeNear) { + _lightClusters->_frustumGridBuffer.edit().rangeNear = config.rangeNear; + } + if (_lightClusters->_frustumGridBuffer->rangeFar != config.rangeFar) { + _lightClusters->_frustumGridBuffer.edit().rangeFar = config.rangeFar; + } + } + + _freeze = config.freeze; +} + +void LightClusteringPass::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) { + auto args = renderContext->args; + + auto deferredTransform = inputs.get0(); + auto lightingModel = inputs.get1(); + auto surfaceGeometryFramebuffer = inputs.get2(); + + bool points = lightingModel->isPointLightEnabled(); + bool spots = lightingModel->isSpotLightEnabled(); + auto deferredLightingEffect = DependencyManager::get(); + + if (!_lightClusters) { + _lightClusters = deferredLightingEffect->getLightClusters(); + } + + // first update the Grid with the new frustum + if (!_freeze) { + _lightClusters->updateFrustum(args->getViewFrustum()); + } + + // Now gather the lights + // gather lights + auto& srcPointLights = deferredLightingEffect->_pointLights; + auto& srcSpotLights = deferredLightingEffect->_spotLights; + int numPointLights = (int) srcPointLights.size(); + int offsetPointLights = 0; + int numSpotLights = (int) srcSpotLights.size(); + int offsetSpotLights = numPointLights; + + std::vector lightIndices(numPointLights + numSpotLights + 1); + lightIndices[0] = 0; + + if (points && !srcPointLights.empty()) { + memcpy(lightIndices.data() + (lightIndices[0] + 1), srcPointLights.data(), srcPointLights.size() * sizeof(int)); + lightIndices[0] += (int)srcPointLights.size(); + } + if (spots && !srcSpotLights.empty()) { + memcpy(lightIndices.data() + (lightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int)); + lightIndices[0] += (int)srcSpotLights.size(); + } + + _lightClusters->updateVisibleLights(lightIndices); + + output = _lightClusters; +} DebugLightClusters::DebugLightClusters() { @@ -62,6 +128,9 @@ DebugLightClusters::DebugLightClusters() { void DebugLightClusters::configure(const Config& config) { + doDrawGrid = config.doDrawGrid; + doDrawClusterFromDepth = config.doDrawClusterFromDepth; + } const gpu::PipelinePointer DebugLightClusters::getDrawClusterGridPipeline() { @@ -119,15 +188,12 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterFromDepthPipeline() } void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs) { - auto deferredLightingEffect = DependencyManager::get(); - auto lightClusters = deferredLightingEffect->getLightClusters(); - - auto deferredTransform = inputs.get0(); auto deferredFramebuffer = inputs.get1(); auto lightingModel = inputs.get2(); auto linearDepthTarget = inputs.get3(); - + auto lightClusters = inputs.get4(); + auto args = renderContext->args; gpu::Batch batch; @@ -148,10 +214,7 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer); - - - - if (true) { + if (doDrawClusterFromDepth) { batch.setPipeline(getDrawClusterFromDepthPipeline()); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer()); @@ -166,7 +229,8 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); } - if (true) { + + if (doDrawGrid) { // bind the one gpu::Pipeline we need batch.setPipeline(getDrawClusterGridPipeline()); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 474b238907..0cfaea5ef5 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -72,43 +72,84 @@ public: gpu::StructBuffer _frustumGridBuffer; - - gpu::BufferPointer _lightIndicesBuffer; + LightStage::LightIndices _visibleLightIndices; + + gpu::BufferView _lightIndicesBuffer; }; using LightClustersPointer = std::shared_ptr; -class DebugLightClustersConfig : public render::Job::Config { +class LightClusteringPassConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) - Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) + Q_PROPERTY(float rangeNear MEMBER rangeNear NOTIFY dirty) + Q_PROPERTY(float rangeFar MEMBER rangeFar NOTIFY dirty) + + Q_PROPERTY(bool freeze MEMBER freeze NOTIFY dirty) public: - DebugLightClustersConfig() : render::Job::Config(true){} - - int getNumDrawn() { return numDrawn; } - void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); } - - int maxDrawn { -1 }; - + LightClusteringPassConfig() : render::Job::Config(true){} + float rangeNear{ 1.0f }; + float rangeFar{ 512.0f }; + bool freeze{ false }; + signals: - void numDrawnChanged(); void dirty(); - + protected: - int numDrawn { 0 }; }; - #include "DeferredFrameTransform.h" -#include "DeferredFramebuffer.h" #include "LightingModel.h" #include "SurfaceGeometryPass.h" +class LightClusteringPass { +public: + using Inputs = render::VaryingSet3; + using Outputs = LightClustersPointer; + using Config = LightClusteringPassConfig; + using JobModel = render::Job::ModelIO; + + LightClusteringPass(); + + void configure(const Config& config); + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output); + +protected: + LightClustersPointer _lightClusters; + bool _freeze; +}; + + + + + + + +class DebugLightClustersConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(bool doDrawGrid MEMBER doDrawGrid NOTIFY dirty) + Q_PROPERTY(bool doDrawClusterFromDepth MEMBER doDrawClusterFromDepth NOTIFY dirty) +public: + DebugLightClustersConfig() : render::Job::Config(true){} + + + bool doDrawGrid{ false }; + bool doDrawClusterFromDepth{ false }; + +signals: + void dirty(); + +protected: +}; + + +#include "DeferredFramebuffer.h" + class DebugLightClusters { public: - using Inputs = render::VaryingSet4 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, LinearDepthFramebufferPointer>; + using Inputs = render::VaryingSet5 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, LinearDepthFramebufferPointer, LightClustersPointer>; using Config = DebugLightClustersConfig; using JobModel = render::Job::ModelI; @@ -124,6 +165,8 @@ protected: gpu::PipelinePointer _drawClusterFromDepth; const gpu::PipelinePointer getDrawClusterGridPipeline(); const gpu::PipelinePointer getDrawClusterFromDepthPipeline(); + bool doDrawGrid{ false }; + bool doDrawClusterFromDepth{ false }; }; #endif diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c683301c90..c959743b57 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -142,29 +142,37 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN(0); const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN(1); + // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. addJob("DrawLight", lights); - const auto deferredLightingInputs = RenderDeferred::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, - surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying(); + // Light Clustering + // Create the cluster grid of lights, cpu job for now + const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).hasVarying(); + const auto lightClusters = 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(); + addJob("RenderDeferred", deferredLightingInputs); // Use Stencil and draw background in Lighting buffer to complete filling in the opaque const auto backgroundInputs = DrawBackgroundDeferred::Inputs(background, lightingModel).hasVarying(); addJob("DrawBackgroundDeferred", backgroundInputs); - // LIght Cluster Grid Debuging job - { - const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget).hasVarying(); - addJob("DebugLightClusters", debugLightClustersInputs); - } // Render transparent objects forward in LightingBuffer const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying(); addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); + // LIght Cluster Grid Debuging job + { + const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).hasVarying(); + addJob("DebugLightClusters", debugLightClustersInputs); + } + const auto toneAndPostRangeTimer = addJob("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing"); // Lighting Buffer ready for tone mapping @@ -196,8 +204,6 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { addJob("DrawItemSelection", spatialSelection); } - - // Status icon rendering job { // Grab a texture map representing the different status icons and assign that to the drawStatsuJob diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index 272f80c99f..cd4f7fee63 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -29,27 +29,15 @@ void main(void) { // Grab the fragment data from the uv vec2 texCoord = varTexCoord0.st; - float Zeye = texture(linearZeyeMap, texCoord).x; - if (Zeye <= 0.1) { - return; - } - - // _fragColor = vec4(colorWheel(fract(0.1 * Zeye)),.5); - // return; - - vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord); - - // Frag pos in world - vec4 fragWorldPos = getViewInverse() * fragPosition; + vec4 fragEyePos = unpackDeferredPositionFromZeye(texCoord); + vec4 fragWorldPos = getViewInverse() * fragEyePos; // From frag world pos find the cluster - //vec3 fragEyePos = fragPosition.xyz; - - // vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0)); vec4 clusterEyePos = frustumGrid_worldToEye(fragWorldPos); ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); ivec3 dims = frustumGrid.dims.xyz; + dims.z +=1; ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); if (clusterPos.x < 0 || clusterPos.x >= dims.x) { @@ -61,7 +49,7 @@ void main(void) { _fragColor = vec4(0.0); return; } - if (clusterPos.z < 0 || clusterPos.z >= dims.z) { + if (clusterPos.z < 0 || clusterPos.z > dims.z) { _fragColor = vec4(0.0); return; } diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index c3e41fb672..b002382c91 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -19,9 +19,9 @@ // Everything about light <@include model/Light.slh@> -<$declareLightBuffer(32)$> +<$declareLightBuffer(128)$> uniform lightIndexBuffer { - int lightIndex[32]; + int lightIndex[128]; }; <@include LightingModel.slh@> diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index df24a08c05..16315de523 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -254,6 +254,40 @@ public: Varying hasVarying() const { return Varying((*this)); } }; +template +class VaryingSet7 : public std::tuple{ +public: + using Parent = std::tuple; + + VaryingSet7() : Parent(Varying(T0()), Varying(T1()), Varying(T2()), Varying(T3()), Varying(T4()), Varying(T5()), Varying(T6())) {} + VaryingSet7(const VaryingSet7& src) : Parent(std::get<0>(src), std::get<1>(src), std::get<2>(src), std::get<3>(src), std::get<4>(src), std::get<5>(src), std::get<6>(src)) {} + VaryingSet7(const Varying& first, const Varying& second, const Varying& third, const Varying& fourth, const Varying& fifth, const Varying& sixth, const Varying& seventh) : Parent(first, second, third, fourth, fifth, sixth, seventh) {} + + const T0& get0() const { return std::get<0>((*this)).template get(); } + T0& edit0() { return std::get<0>((*this)).template edit(); } + + const T1& get1() const { return std::get<1>((*this)).template get(); } + T1& edit1() { return std::get<1>((*this)).template edit(); } + + const T2& get2() const { return std::get<2>((*this)).template get(); } + T2& edit2() { return std::get<2>((*this)).template edit(); } + + const T3& get3() const { return std::get<3>((*this)).template get(); } + T3& edit3() { return std::get<3>((*this)).template edit(); } + + const T4& get4() const { return std::get<4>((*this)).template get(); } + T4& edit4() { return std::get<4>((*this)).template edit(); } + + const T5& get5() const { return std::get<5>((*this)).template get(); } + T5& edit5() { return std::get<5>((*this)).template edit(); } + + 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)); } +}; + + template < class T, int NUM > class VaryingArray : public std::array { public: diff --git a/scripts/developer/utilities/render/lightClustering.js b/scripts/developer/utilities/render/lightClustering.js new file mode 100644 index 0000000000..bad023a64f --- /dev/null +++ b/scripts/developer/utilities/render/lightClustering.js @@ -0,0 +1,21 @@ +// +// lightClustering.js +// examples/utilities/tools/render +// +// Sam Gateau, created on 9/9/2016. +// Copyright 2016 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('lightClustering.qml'); +var window = new OverlayWindow({ + title: 'Light Clustering', + source: qml, + width: 400, + height: 200 +}); +window.setPosition(Window.innerWidth - 420, 50 + 250 + 50); +window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/scripts/developer/utilities/render/lightClustering.qml b/scripts/developer/utilities/render/lightClustering.qml new file mode 100644 index 0000000000..be252441db --- /dev/null +++ b/scripts/developer/utilities/render/lightClustering.qml @@ -0,0 +1,45 @@ +// +// lightClustering.qml +// +// Created by Sam Gateau on 9/9/2016 +// Copyright 2016 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" + +Column { + spacing: 8 + Column { + id: lightClustering + spacing: 10 + + Column{ + ConfigSlider { + label: qsTr("Range Near [m]") + integral: false + config: Render.getConfig("LightClustering") + property: "rangeNear" + max: 20.0 + min: 0.1 + } + ConfigSlider { + label: qsTr("Range Far [m]") + integral: false + config: Render.getConfig("LightClustering") + property: "rangeFar" + max: 500.0 + min: 100.0 + } + + CheckBox { + text: "Freeze" + checked: Render.getConfig("LightClustering")["freeze"] + onCheckedChanged: { Render.getConfig("LightClustering")["freeze"] = checked } + } + } + } +} From 821072bb763aba451235166e2f2e51119d0b8f39 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 12 Sep 2016 11:07:55 -0700 Subject: [PATCH 027/104] REarrange the light stage construction and light frame usage to produce the light clusters --- libraries/model/src/model/Light.h | 2 +- libraries/model/src/model/Light.slh | 2 +- .../src/DeferredLightingEffect.cpp | 11 +++- .../render-utils/src/DeferredLightingEffect.h | 3 - libraries/render-utils/src/LightClusters.cpp | 65 ++++++++++--------- libraries/render-utils/src/LightClusters.h | 5 +- libraries/render-utils/src/LightPayload.cpp | 31 +++++++-- libraries/render-utils/src/LightPayload.h | 12 ++-- libraries/render-utils/src/LightStage.cpp | 10 +++ libraries/render-utils/src/LightStage.h | 31 ++++++++- .../utilities/render/lightClustering.qml | 10 +++ 11 files changed, 130 insertions(+), 52 deletions(-) diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 058d4d4741..c091026ba2 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -124,7 +124,7 @@ public: float _intensity{1.0f}; Vec4 _attenuation{0.1f, 1.0f, 0.0f, 0.0f}; Vec4 _spot{0.0f, 0.0f, 0.0f, 0.0f}; - Vec4 _shadow{0.0f}; + //Vec4 _shadow{0.0f}; float _ambientMapNumMips{ 0.0f }; diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 2b6e55cf7e..888abf5038 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -53,7 +53,7 @@ struct Light { vec4 _attenuation; vec4 _spot; - vec4 _shadow; + // vec4 _shadow; vec4 _control; vec4 _volumeGeometry; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e6ca901376..1a0a072256 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -118,9 +118,7 @@ void DeferredLightingEffect::init() { // Light Stage and clusters _lightStage = std::make_shared(); - _lightClusters = std::make_shared(); - _lightClusters->updateLightStage(_lightStage); - + // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light _allocatedLights.push_back(std::make_shared()); model::LightPointer lp = _allocatedLights[0]; @@ -146,6 +144,7 @@ void DeferredLightingEffect::addLight(const model::LightPointer& light) { } } + void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color, float intensity, float falloffRadius) { addSpotLight(position, radius, color, intensity, falloffRadius); @@ -472,6 +471,7 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con } _primaryFramebuffer->resize(frameSize.x, frameSize.y); + primaryFramebuffer = _primaryFramebuffer; } @@ -508,6 +508,11 @@ void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderC // For the rest of the rendering, bind the lighting model batch.setUniformBuffer(LIGHTING_MODEL_BUFFER_SLOT, lightingModel->getParametersBuffer()); }); + + + // Prepare a fresh Light Frame + auto deferredLightingEffect = DependencyManager::get(); + deferredLightingEffect->getLightStage()->_currentFrame.clear(); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index a66a2ed2ed..690d6ce5e0 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -62,7 +62,6 @@ public: void setGlobalLight(const model::LightPointer& light); const LightStagePointer getLightStage() { return _lightStage; } - const LightClustersPointer getLightClusters() { return _lightClusters; } void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; }; void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; } @@ -73,8 +72,6 @@ private: LightStagePointer _lightStage; - LightClustersPointer _lightClusters; - bool _shadowMapEnabled{ false }; bool _ambientOcclusionEnabled{ false }; diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index e98322da4d..97f91657df 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -47,13 +47,36 @@ void LightClusters::updateFrustum(const ViewFrustum& frustum) { void LightClusters::updateLightStage(const LightStagePointer& lightStage) { _lightStage = lightStage; -} - -void LightClusters::updateVisibleLights(const LightStage::LightIndices& visibleLights) { + } + +void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool points, bool spots) { + + // start fresh _visibleLightIndices.clear(); - // _lightClusters->_visibleLightIndices.push_back(0); - _visibleLightIndices = visibleLights; + + // Now gather the lights + // gather lights + auto& srcPointLights = lightFrame._pointLights; + auto& srcSpotLights = lightFrame._spotLights; + int numPointLights = (int) srcPointLights.size(); + // int offsetPointLights = 0; + int numSpotLights = (int) srcSpotLights.size(); + // int offsetSpotLights = numPointLights; + + _visibleLightIndices.resize(numPointLights + numSpotLights + 1); + + _visibleLightIndices[0] = 0; + + if (points && !srcPointLights.empty()) { + memcpy(_visibleLightIndices.data() + (_visibleLightIndices[0] + 1), srcPointLights.data(), srcPointLights.size() * sizeof(int)); + _visibleLightIndices[0] += (int)srcPointLights.size(); + } + if (spots && !srcSpotLights.empty()) { + memcpy(_visibleLightIndices.data() + (_visibleLightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int)); + _visibleLightIndices[0] += (int)srcSpotLights.size(); + } + _lightIndicesBuffer._buffer->setData(_visibleLightIndices.size() * sizeof(int), (const gpu::Byte*) _visibleLightIndices.data()); _lightIndicesBuffer._size = _visibleLightIndices.size() * sizeof(int); } @@ -83,12 +106,9 @@ void LightClusteringPass::run(const render::SceneContextPointer& sceneContext, c auto lightingModel = inputs.get1(); auto surfaceGeometryFramebuffer = inputs.get2(); - bool points = lightingModel->isPointLightEnabled(); - bool spots = lightingModel->isSpotLightEnabled(); - auto deferredLightingEffect = DependencyManager::get(); if (!_lightClusters) { - _lightClusters = deferredLightingEffect->getLightClusters(); + _lightClusters = std::make_shared(); } // first update the Grid with the new frustum @@ -96,28 +116,11 @@ void LightClusteringPass::run(const render::SceneContextPointer& sceneContext, c _lightClusters->updateFrustum(args->getViewFrustum()); } - // Now gather the lights - // gather lights - auto& srcPointLights = deferredLightingEffect->_pointLights; - auto& srcSpotLights = deferredLightingEffect->_spotLights; - int numPointLights = (int) srcPointLights.size(); - int offsetPointLights = 0; - int numSpotLights = (int) srcSpotLights.size(); - int offsetSpotLights = numPointLights; - - std::vector lightIndices(numPointLights + numSpotLights + 1); - lightIndices[0] = 0; - - if (points && !srcPointLights.empty()) { - memcpy(lightIndices.data() + (lightIndices[0] + 1), srcPointLights.data(), srcPointLights.size() * sizeof(int)); - lightIndices[0] += (int)srcPointLights.size(); - } - if (spots && !srcSpotLights.empty()) { - memcpy(lightIndices.data() + (lightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int)); - lightIndices[0] += (int)srcSpotLights.size(); - } - - _lightClusters->updateVisibleLights(lightIndices); + // From the LightStage and the current frame, update the light cluster Grid + auto deferredLightingEffect = DependencyManager::get(); + auto lightStage = deferredLightingEffect->getLightStage(); + _lightClusters->updateLightStage(lightStage); + _lightClusters->updateLightFrame(lightStage->_currentFrame, lightingModel->isPointLightEnabled(), lightingModel->isSpotLightEnabled()); output = _lightClusters; } diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 0cfaea5ef5..60b4d50ced 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -61,9 +61,8 @@ public: void updateLightStage(const LightStagePointer& lightStage); - void updateVisibleLights(const LightStage::LightIndices& visibleLights); - - + void updateLightFrame(const LightStage::Frame& lightFrame, bool points = true, bool spots = true); + ViewFrustum _frustum; LightStagePointer _lightStage; diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp index 8bb9a57145..e8d9e0d5bd 100644 --- a/libraries/render-utils/src/LightPayload.cpp +++ b/libraries/render-utils/src/LightPayload.cpp @@ -35,11 +35,34 @@ namespace render { } LightPayload::LightPayload() : -_light(std::make_shared()) + _light(std::make_shared()) { } -void LightPayload::render(RenderArgs* args) { - DependencyManager::get()->addLight(_light); -} \ No newline at end of file +LightPayload::~LightPayload() { + if (!LightStage::isIndexInvalid(_index)) { + if (_stage) { + _stage->removeLight(_index); + } + } +} + +void LightPayload::render(RenderArgs* args) { + if (!_stage) { + _stage = DependencyManager::get()->getLightStage(); + } + // Do we need to allocate the light in the stage ? + if (LightStage::isIndexInvalid(_index)) { + _index = _stage->addLight(_light); + } + // Need an update ? + if (_needUpdate) { + _stage->updateLightArrayBuffer(_index); + _needUpdate = false; + } + + // FInally, push the light visible in the frame + _stage->_currentFrame.pushLight(_index, _light->getType()); +} + diff --git a/libraries/render-utils/src/LightPayload.h b/libraries/render-utils/src/LightPayload.h index 2f065e4b5b..fba4ff15cb 100644 --- a/libraries/render-utils/src/LightPayload.h +++ b/libraries/render-utils/src/LightPayload.h @@ -14,7 +14,7 @@ #include #include - +#include "LightStage.h" class LightPayload { public: @@ -22,14 +22,18 @@ public: using Pointer = Payload::DataPointer; LightPayload(); + ~LightPayload(); void render(RenderArgs* args); - model::LightPointer editLight() { return _light; } - render::Item::Bound& editBound() { return _bound; } - + model::LightPointer editLight() { _needUpdate = true; return _light; } + render::Item::Bound& editBound() { _needUpdate = true; return _bound; } + protected: model::LightPointer _light; render::Item::Bound _bound; + LightStagePointer _stage; + LightStage::Index _index { LightStage::INVALID_INDEX }; + bool _needUpdate { true }; }; namespace render { diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index bcdee5c0a9..8c8c9406e0 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -123,6 +123,16 @@ LightStage::Index LightStage::addLight(const LightPointer& light) { } } +LightStage::LightPointer LightStage::removeLight(Index index) { + LightPointer removed = _lights.freeElement(index); + + if (removed) { + _lightMap.erase(removed); + _descs[index] = Desc(); + } + return removed; +} + void LightStage::updateLightArrayBuffer(Index lightId) { if (!_lightArrayBuffer) { _lightArrayBuffer = std::make_shared(); diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index c0632a0ebf..34575596dd 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -27,7 +27,8 @@ class LightStage { public: using Index = render::indexed_container::Index; static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX }; - + static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } + using LightPointer = model::LightPointer; using Lights = render::indexed_container::IndexedPointerVector; using LightMap = std::unordered_map; @@ -79,7 +80,8 @@ public: Index findLight(const LightPointer& light) const; Index addLight(const LightPointer& light); - + LightPointer removeLight(Index index); + bool checkLightId(Index index) const { return _lights.checkIndex(index); } Index getNumLights() const { return _lights.getNumElements(); } @@ -107,10 +109,35 @@ public: LightMap _lightMap; Descs _descs; + class Frame { + public: + Frame() {} + + void clear() { _pointLights.clear(); _spotLights.clear(); } + void pushLight(LightStage::Index index, model::Light::Type type) { + switch (type) { + case model::Light::POINT: { pushPointLight(index); break; } + case model::Light::SPOT: { pushSpotLight(index); break; } + default: { break; } + } + } + void pushPointLight(LightStage::Index index) { _pointLights.emplace_back(index); } + void pushSpotLight(LightStage::Index index) { _spotLights.emplace_back(index); } + + LightStage::LightIndices _pointLights; + LightStage::LightIndices _spotLights; + }; + + Frame _currentFrame; + gpu::BufferPointer _lightArrayBuffer; void updateLightArrayBuffer(Index lightId); Shadows _shadows; }; using LightStagePointer = std::shared_ptr; + + + + #endif diff --git a/scripts/developer/utilities/render/lightClustering.qml b/scripts/developer/utilities/render/lightClustering.qml index be252441db..9adb137b0f 100644 --- a/scripts/developer/utilities/render/lightClustering.qml +++ b/scripts/developer/utilities/render/lightClustering.qml @@ -40,6 +40,16 @@ Column { checked: Render.getConfig("LightClustering")["freeze"] onCheckedChanged: { Render.getConfig("LightClustering")["freeze"] = checked } } + CheckBox { + text: "Draw Grid" + checked: Render.getConfig("DebugLightClusters")["doDrawGrid"] + onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawGrid"] = checked } + } + CheckBox { + text: "Draw Cluster From Depth" + checked: Render.getConfig("DebugLightClusters")["doDrawClusterFromDepth"] + onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawClusterFromDepth"] = checked } + } } } } From efc4406b472f537ec2732aa6d0de21830de691df Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 12 Sep 2016 19:46:18 -0700 Subject: [PATCH 028/104] Debugging the grid content --- libraries/gpu/src/gpu/Buffer.h | 7 +- libraries/gpu/src/gpu/Format.cpp | 3 +- libraries/gpu/src/gpu/Format.h | 1 + .../render-utils/src/LightClusterGrid.slh | 9 + .../src/LightClusterGrid_shared.slh | 32 ++- libraries/render-utils/src/LightClusters.cpp | 219 +++++++++++++++++- libraries/render-utils/src/LightClusters.h | 22 +- libraries/render-utils/src/LightPayload.cpp | 1 + libraries/render-utils/src/LightStage.cpp | 10 +- .../render-utils/src/RenderDeferredTask.cpp | 4 +- .../src/lightClusters_drawClusterContent.slf | 19 ++ .../src/lightClusters_drawClusterContent.slv | 74 ++++++ 12 files changed, 379 insertions(+), 22 deletions(-) create mode 100644 libraries/render-utils/src/lightClusters_drawClusterContent.slf create mode 100644 libraries/render-utils/src/lightClusters_drawClusterContent.slv diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h index e8e04f471a..2079c60605 100644 --- a/libraries/gpu/src/gpu/Buffer.h +++ b/libraries/gpu/src/gpu/Buffer.h @@ -391,11 +391,14 @@ public: ~StructBuffer() {}; StructBuffer() : gpu::BufferView(makeBuffer()) {} - const T* operator ->() const { return &get(); } + T& edit() { return BufferView::edit(0); } - + const T& get() const { + return BufferView::get(0); + } + const T* operator ->() const { return &get(); } }; }; diff --git a/libraries/gpu/src/gpu/Format.cpp b/libraries/gpu/src/gpu/Format.cpp index 83b2a59a73..2a8185bf94 100644 --- a/libraries/gpu/src/gpu/Format.cpp +++ b/libraries/gpu/src/gpu/Format.cpp @@ -18,6 +18,7 @@ const Element Element::VEC2F_UV{ VEC2, FLOAT, UV }; const Element Element::VEC2F_XY{ VEC2, FLOAT, XY }; const Element Element::VEC3F_XYZ{ VEC3, FLOAT, XYZ }; const Element Element::VEC4F_XYZW{ VEC4, FLOAT, XYZW }; -const Element Element::INDEX_UINT16{ SCALAR, UINT16, INDEX }; +const Element Element::INDEX_UINT16 { SCALAR, UINT16, INDEX }; +const Element Element::INDEX_INT32 { SCALAR, INT32, INDEX }; const Element Element::PART_DRAWCALL{ VEC4, UINT32, PART }; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index ad630e8e43..13809a41e6 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -236,6 +236,7 @@ public: static const Element VEC3F_XYZ; static const Element VEC4F_XYZW; static const Element INDEX_UINT16; + static const Element INDEX_INT32; static const Element PART_DRAWCALL; protected: diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 004339ff34..5b1b765e0f 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -46,4 +46,13 @@ float projection_getFar(mat4 projection) { // end of hybrid include + +uniform clusterGridBuffer { + int _clusterGridTable[10000]; +}; + +uniform clusterContentBuffer { + int _clusterGridContent[10000]; +}; + <@endif@> diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 5ccba9a786..5577b2e612 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -17,11 +17,16 @@ vec3 frustumGrid_gridToVolume(vec3 pos, ivec3 dims) { } +float frustumGrid_volumeToGridDepth(float vposZ, ivec3 dims) { + return frustumGrid_depthRampInverse(vposZ) * float(dims.z); +} + vec3 frustumGrid_volumeToGrid(vec3 vpos, ivec3 dims) { vec3 gridPos = vec3(vpos.x, vpos.y, frustumGrid_depthRampInverse(vpos.z)) * vec3(dims); return gridPos; } + vec4 frustumGrid_volumeToClip(vec3 vpos, float rangeNear, float rangeFar) { vec3 ndcPos = vec3(-1.0 + 2.0 * vpos.x, -1.0 + 2.0 * vpos.y, vpos.z); float depth = rangeNear * (1 - ndcPos.z) + rangeFar * (ndcPos.z); @@ -42,6 +47,10 @@ vec3 frustumGrid_volumeToEye(vec3 vpos, mat4 projection, float rangeNear, float return frustumGrid_clipToEye(frustumGrid_volumeToClip(vpos, rangeNear, rangeFar), projection); } +float frustumGrid_eyeToVolumeDepth(float eposZ, float rangeNear, float rangeFar) { + return (-eposZ - rangeNear) / (rangeFar - rangeNear); +} + vec3 frustumGrid_eyeToVolume(vec3 epos, mat4 projection, float rangeNear, float rangeFar) { vec4 clipPos = vec4(epos.x * projection[0][0] + epos.z * projection[2][0], @@ -57,7 +66,7 @@ vec3 frustumGrid_eyeToVolume(vec3 epos, mat4 projection, float rangeNear, float int frustumGrid_numClusters() { - return frustumGrid.dims.x * frustumGrid.dims.y * (frustumGrid.dims.z); + return frustumGrid.dims.x * frustumGrid.dims.y * (frustumGrid.dims.z + 1); } vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) { @@ -73,6 +82,27 @@ vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) { } +int frustumGrid_eyeDepthToClusterLayer(float eyeZ) { + if ((eyeZ > -frustumGrid.frustumNear) || (eyeZ < -frustumGrid.frustumFar)) { + return -1; + } + + if (eyeZ > -frustumGrid.rangeNear) { + return -1; + } + + float volumeZ = frustumGrid_eyeToVolumeDepth(eyeZ, frustumGrid.rangeNear, frustumGrid.rangeFar); + + float gridZ = frustumGrid_volumeToGridDepth(volumeZ, frustumGrid.dims); + + if (gridZ >= frustumGrid.dims.z) { + gridZ = frustumGrid.dims.z; + } + + + return int(gridZ); +} + ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { if ((eyePos.z > -frustumGrid.frustumNear) || (eyePos.z < -frustumGrid.frustumFar)) { return ivec3(-1); diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 97f91657df..ff9362eb3e 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -21,6 +21,10 @@ //#include "lightClusters_drawClusterFromDepth_vert.h" #include "lightClusters_drawClusterFromDepth_frag.h" + +#include "lightClusters_drawClusterContent_vert.h" +#include "lightClusters_drawClusterContent_frag.h" + enum LightClusterGridShader_MapSlot { DEFERRED_BUFFER_LINEAR_DEPTH_UNIT = 0, }; @@ -31,14 +35,32 @@ enum LightClusterGridShader_BufferSlot { CAMERA_CORRECTION_BUFFER_SLOT, LIGHT_GPU_SLOT = render::ShapePipeline::Slot::LIGHT, LIGHT_INDEX_GPU_SLOT, + + LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, + LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, }; #include "DeferredLightingEffect.h" LightClusters::LightClusters() : -_lightIndicesBuffer(std::make_shared()) { + _lightIndicesBuffer(std::make_shared()), + _clusterGridBuffer(std::make_shared(), gpu::Element::INDEX_INT32), + _clusterContentBuffer(std::make_shared(), gpu::Element::INDEX_INT32) { + setDimensions(_frustumGridBuffer->dims, 10000); } +void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { + _frustumGridBuffer.edit().dims = gridDims; + + _numClusters = _frustumGridBuffer.edit().frustumGrid_numClusters(); + + _clusterGridBuffer._size = _clusterGridBuffer._buffer->resize(_numClusters * sizeof(uint32_t)); + _clusterContentBuffer._size = _clusterContentBuffer._buffer->resize(listBudget * sizeof(uint32_t)); + _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); + _clusterContent.resize(listBudget, INVALID_LIGHT); +} + + void LightClusters::updateFrustum(const ViewFrustum& frustum) { _frustum = frustum; @@ -51,23 +73,23 @@ void LightClusters::updateLightStage(const LightStagePointer& lightStage) { } void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool points, bool spots) { - + // start fresh _visibleLightIndices.clear(); - + // Now gather the lights // gather lights auto& srcPointLights = lightFrame._pointLights; auto& srcSpotLights = lightFrame._spotLights; - int numPointLights = (int) srcPointLights.size(); - // int offsetPointLights = 0; - int numSpotLights = (int) srcSpotLights.size(); - // int offsetSpotLights = numPointLights; - + int numPointLights = (int)srcPointLights.size(); + // int offsetPointLights = 0; + int numSpotLights = (int)srcSpotLights.size(); + // int offsetSpotLights = numPointLights; + _visibleLightIndices.resize(numPointLights + numSpotLights + 1); - + _visibleLightIndices[0] = 0; - + if (points && !srcPointLights.empty()) { memcpy(_visibleLightIndices.data() + (_visibleLightIndices[0] + 1), srcPointLights.data(), srcPointLights.size() * sizeof(int)); _visibleLightIndices[0] += (int)srcPointLights.size(); @@ -76,11 +98,144 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p memcpy(_visibleLightIndices.data() + (_visibleLightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int)); _visibleLightIndices[0] += (int)srcSpotLights.size(); } - + _lightIndicesBuffer._buffer->setData(_visibleLightIndices.size() * sizeof(int), (const gpu::Byte*) _visibleLightIndices.data()); _lightIndicesBuffer._size = _visibleLightIndices.size() * sizeof(int); } +void LightClusters::updateClusters() { + // Clean up last info + std::vector< std::vector< uint32_t > > clusterGrid(_numClusters); + + _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); + uint32_t maxNumIndices = _clusterContent.size(); + _clusterContent.resize(maxNumIndices, INVALID_LIGHT); + + auto theFrustumGrid(_frustumGridBuffer.get()); + + glm::ivec3 gridPosToOffset(1, theFrustumGrid.dims.x, theFrustumGrid.dims.x * theFrustumGrid.dims.y); + + uint32_t numClusterTouched = 0; + for (size_t lightNum = 1; lightNum < _visibleLightIndices.size(); ++lightNum) { + auto lightId = _visibleLightIndices[lightNum]; + auto light = _lightStage->getLight(lightId); + if (!light) + continue; + + auto worldOri = light->getPosition(); + auto radius = light->getMaximumRadius(); + + // Bring into frustum eye space + auto eyeOri = theFrustumGrid.frustumGrid_worldToEye(glm::vec4(worldOri, 1.0f)); + + // Remove light that slipped through and is not in the z range + float eyeZMax = eyeOri.z - radius; + if (eyeZMax > -theFrustumGrid.rangeNear) { + continue; + } + float eyeZMin = eyeOri.z + radius; + if (eyeZMin < -theFrustumGrid.rangeFar) { + continue; + } + + // Get z slices + int zMin = theFrustumGrid.frustumGrid_eyeDepthToClusterLayer(eyeZMin); + int zMax = theFrustumGrid.frustumGrid_eyeDepthToClusterLayer(eyeZMax); + // That should never happen + if (zMin == -1 && zMax == -1) { + continue; + } + + + // + float eyeOriLen2 = glm::length2(eyeOri); + + // CLamp the z range + zMin = std::max(0, zMin); + + + + // find 2D corners of the sphere in grid + int xMin { 0 }; + int xMax { theFrustumGrid.dims.x - 1 }; + int yMin { 0 }; + int yMax { theFrustumGrid.dims.y - 1 }; + + float radius2 = radius * radius; + auto eyeOriH = eyeOri; + auto eyeOriV = eyeOri; + + eyeOriH.y = 0.0f; + eyeOriV.x = 0.0f; + + float eyeOriLen2H = glm::length2(eyeOriH); + float eyeOriLen2V = glm::length2(eyeOriV); + + if ((eyeOriLen2H > radius2) && (eyeOriLen2V > radius2)) { + float eyeOriLenH = sqrt(eyeOriLen2H); + float eyeOriLenV = sqrt(eyeOriLen2V); + + auto eyeOriDirH = glm::vec3(eyeOriH) / eyeOriLenH; + auto eyeOriDirV = glm::vec3(eyeOriV) / eyeOriLenV; + + + + float eyeToTangentCircleLenH = sqrt(eyeOriLen2H - radius2); + float eyeToTangentCircleLenV = sqrt(eyeOriLen2V - radius2); + + float eyeToTangentCircleTanH = radius / eyeToTangentCircleLenH; + float eyeToTangentCircleTanV = radius / eyeToTangentCircleLenV; + + float eyeToTangentCircleCosH = eyeToTangentCircleLenH / eyeOriLenH; + float eyeToTangentCircleCosV = eyeToTangentCircleLenV / eyeOriLenV; + + float eyeToTangentCircleSinH = radius / eyeOriLenH; + float eyeToTangentCircleSinV = radius / eyeOriLenV; + + + // rotate the eyeToOriDir (H & V) in both directions + glm::vec3 leftDir(eyeOriDirH.x * eyeToTangentCircleCosH - eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); + glm::vec3 rightDir(eyeOriDirH.x * eyeToTangentCircleCosH + eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * -eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); + glm::vec3 bottomDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV - eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); + glm::vec3 topDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV + eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * -eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); + + } + + // now voxelize + for (auto z = zMin; z <= zMax; z++) { + for (auto y = yMin; y <= yMax; y++) { + for (auto x = xMin; x <= xMax; x++) { + auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; + clusterGrid[index].emplace_back(lightId); + numClusterTouched++; + } + } + } + } + + // Lights have been gathered now reexpress in terms of 2 sequential buffers + + uint16_t indexOffset = 0; + for (int i = 0; i < clusterGrid.size(); i++) { + auto& cluster = clusterGrid[i]; + uint16_t numLights = ((uint16_t)cluster.size()); + uint16_t offset = indexOffset; + + _clusterGrid[i] = (uint32_t)((numLights << 16) | offset); + + if (numLights) { + memcpy(_clusterContent.data() + indexOffset, cluster.data(), numLights * sizeof(uint32_t)); + } + + indexOffset += numLights; + } + + // update the buffers + _clusterGridBuffer._buffer->setData(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()); + _clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(uint32_t), (gpu::Byte*) _clusterContent.data()); +} + + LightClusteringPass::LightClusteringPass() { } @@ -122,6 +277,8 @@ void LightClusteringPass::run(const render::SceneContextPointer& sceneContext, c _lightClusters->updateLightStage(lightStage); _lightClusters->updateLightFrame(lightStage->_currentFrame, lightingModel->isPointLightEnabled(), lightingModel->isSpotLightEnabled()); + _lightClusters->updateClusters(); + output = _lightClusters; } @@ -190,6 +347,35 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterFromDepthPipeline() return _drawClusterFromDepth; } +const gpu::PipelinePointer DebugLightClusters::getDrawClusterContentPipeline() { + if (!_drawClusterContent) { + auto vs = gpu::Shader::createVertex(std::string(lightClusters_drawClusterContent_vert)); + auto ps = gpu::Shader::createPixel(std::string(lightClusters_drawClusterContent_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT)); + + + gpu::Shader::makeProgram(*program, slotBindings); + + + auto state = std::make_shared(); + + state->setDepthTest(true, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + + // Good to go add the brand new pipeline + _drawClusterContent = gpu::Pipeline::create(program, state); + } + return _drawClusterContent; +} + + void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs) { auto deferredTransform = inputs.get0(); auto deferredFramebuffer = inputs.get1(); @@ -232,6 +418,17 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); } + + if (doDrawContent) { + // bind the one gpu::Pipeline we need + batch.setPipeline(getDrawClusterContentPipeline()); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer); + + auto dims = lightClusters->_frustumGridBuffer->dims; + glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x); + batch.drawInstanced(summedDims.x, gpu::LINES, 24, 0); + } if (doDrawGrid) { // bind the one gpu::Pipeline we need diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 60b4d50ced..9930eda731 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -57,12 +57,16 @@ public: LightClusters(); + void setDimensions(glm::uvec3 gridDims, uint32_t listBudget); + void updateFrustum(const ViewFrustum& frustum); void updateLightStage(const LightStagePointer& lightStage); void updateLightFrame(const LightStage::Frame& lightFrame, bool points = true, bool spots = true); - + + void updateClusters(); + ViewFrustum _frustum; LightStagePointer _lightStage; @@ -72,8 +76,17 @@ public: gpu::StructBuffer _frustumGridBuffer; LightStage::LightIndices _visibleLightIndices; - gpu::BufferView _lightIndicesBuffer; + + uint32_t _numClusters { 0 }; + + const uint32_t EMPTY_CLUSTER { 0x0000FFFF }; + const uint32_t INVALID_LIGHT { 0xFFFFFFFF }; + + std::vector _clusterGrid; + std::vector _clusterContent; + gpu::BufferView _clusterGridBuffer; + gpu::BufferView _clusterContentBuffer; }; using LightClustersPointer = std::shared_ptr; @@ -162,10 +175,13 @@ protected: gpu::BufferPointer _gridBuffer; gpu::PipelinePointer _drawClusterGrid; gpu::PipelinePointer _drawClusterFromDepth; + gpu::PipelinePointer _drawClusterContent; const gpu::PipelinePointer getDrawClusterGridPipeline(); const gpu::PipelinePointer getDrawClusterFromDepthPipeline(); + const gpu::PipelinePointer getDrawClusterContentPipeline(); bool doDrawGrid{ false }; - bool doDrawClusterFromDepth{ false }; + bool doDrawClusterFromDepth { false }; + bool doDrawContent { true }; }; #endif diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp index e8d9e0d5bd..8f7b893f6a 100644 --- a/libraries/render-utils/src/LightPayload.cpp +++ b/libraries/render-utils/src/LightPayload.cpp @@ -55,6 +55,7 @@ void LightPayload::render(RenderArgs* args) { // Do we need to allocate the light in the stage ? if (LightStage::isIndexInvalid(_index)) { _index = _stage->addLight(_light); + _needUpdate = false; } // Need an update ? if (_needUpdate) { diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 8c8c9406e0..357e7f46f7 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -146,8 +146,12 @@ void LightStage::updateLightArrayBuffer(Index lightId) { } // lightArray is big enough so we can remap - auto& light = _lights._elements[lightId]; - auto lightSchema = light->getSchemaBuffer().get(); - _lightArrayBuffer->setSubData(lightId, lightSchema); + auto light = _lights._elements[lightId]; + if (light) { + auto lightSchema = light->getSchemaBuffer().get(); + _lightArrayBuffer->setSubData(lightId, lightSchema); + } else { + // this should not happen ? + } } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c959743b57..d8f3b325f1 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -192,7 +192,9 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); addJob("DebugDeferredBuffer", debugFramebuffers); - addJob("DebugScattering", deferredLightingInputs); + const auto debugSubsurfaceScatteringInputs = DebugSubsurfaceScattering::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, + surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying(); + addJob("DebugScattering", debugSubsurfaceScatteringInputs); const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying(); addJob("DebugAmbientOcclusion", debugAmbientOcclusionInputs); diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slf b/libraries/render-utils/src/lightClusters_drawClusterContent.slf new file mode 100644 index 0000000000..b31479554f --- /dev/null +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slf @@ -0,0 +1,19 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// lightClusters_drawClusterContent.slf +// +// Created by Sam Gateau on 9/8/2016. +// 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 +// + +in vec4 varColor; +out vec4 outFragColor; + + +void main(void) { + outFragColor = varColor; +} diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv new file mode 100644 index 0000000000..1e4246da1c --- /dev/null +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -0,0 +1,74 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// lightClusters_drawClusterContent.slv +// Vertex shader +// +// Created by Sam Gateau on 9/8/2016 +// 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/Transform.slh@> +<$declareStandardTransform()$> + +<@include LightClusterGrid.slh@> + +<@include gpu/Color.slh@> +<$declareColorWheel()$> + + + + +out vec4 varColor; + + +void main(void) { + const vec4 UNIT_BOX[8] = vec4[8]( + vec4(0.0, 0.0, 0.0, 1.0), + vec4(1.0, 0.0, 0.0, 1.0), + vec4(0.0, 1.0, 0.0, 1.0), + vec4(1.0, 1.0, 0.0, 1.0), + vec4(0.0, 0.0, 1.0, 1.0), + vec4(1.0, 0.0, 1.0, 1.0), + vec4(0.0, 1.0, 1.0, 1.0), + vec4(1.0, 1.0, 1.0, 1.0) + ); + const int UNIT_BOX_LINE_INDICES[24] = int[24]( + 0, 1, + 1, 3, + 3, 2, + 2, 0, + 4, 5, + 5, 7, + 7, 6, + 6, 4, + 2, 6, + 3, 7, + 0, 4, + 1, 5 + ); + vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; + + ivec3 dims = frustumGrid.dims.xyz; + + ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); + + int layer = gl_InstanceID / summedDims.x; + int offsetInLayer = gl_InstanceID % summedDims.x; + ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); + + + vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz); + vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0)); + + + // standard transform + TransformCamera cam = getTransformCamera(); + <$transformWorldToClipPos(cam, worldPos, gl_Position)$> + + varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), 0.9); +} \ No newline at end of file From e9bf19840c0d5bf3a6399eb869f3e796a628b3d7 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 13 Sep 2016 08:58:07 -0700 Subject: [PATCH 029/104] minor fixes on mac --- libraries/render-utils/src/LightClusterGrid.slh | 8 ++++---- .../render-utils/src/lightClusters_drawClusterContent.slv | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 5b1b765e0f..5287695b10 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -47,12 +47,12 @@ float projection_getFar(mat4 projection) { // end of hybrid include -uniform clusterGridBuffer { - int _clusterGridTable[10000]; +layout (std140) uniform clusterGridBuffer { + int _clusterGridTable[4096]; }; -uniform clusterContentBuffer { - int _clusterGridContent[10000]; +layout (std140) uniform clusterContentBuffer { + int _clusterGridContent[4096]; }; <@endif@> diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index 1e4246da1c..a971bb5d2c 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -53,6 +53,12 @@ void main(void) { ); vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; + int clusterDesc = _clusterGridTable[gl_InstanceID]; + int numLights = 0xFFFF & (clusterDesc >> 16); + + if (numLights <= 0) { + return; + } ivec3 dims = frustumGrid.dims.xyz; ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); From e8c2dc10f1ca1812514dbd320e0e002066c4cb3b Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 13 Sep 2016 14:59:23 -0700 Subject: [PATCH 030/104] best state for now --- .../src/gpu/gl45/GL45BackendTexture.cpp | 2 +- libraries/gpu/src/gpu/Batch.h | 4 +- .../src/DeferredLightingEffect.cpp | 15 +++++- .../render-utils/src/LightClusterGrid.slh | 24 ++++++++-- .../src/LightClusterGrid_shared.slh | 3 +- libraries/render-utils/src/LightClusters.cpp | 46 ++++++++++++++++--- libraries/render-utils/src/LightClusters.h | 19 ++++++-- .../src/lightClusters_drawClusterContent.slv | 20 +++----- .../lightClusters_drawClusterFromDepth.slf | 10 +++- .../render-utils/src/local_lights_shading.slf | 46 +++++++++++++++++-- .../utilities/render/lightClustering.qml | 30 +++++++++++- 11 files changed, 180 insertions(+), 39 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index b511ed7811..3c15194d0f 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -24,7 +24,7 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; -#define SPARSE_TEXTURES 1 +#define SPARSE_TEXTURES 0 // Allocate 1 MB of buffer space for paged transfers #define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 8a52eef4ea..f2dbe62b39 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -32,11 +32,11 @@ namespace gpu { enum ReservedSlot { #ifdef GPU_SSBO_DRAW_CALL_INFO - TRANSFORM_OBJECT_SLOT = 6, + TRANSFORM_OBJECT_SLOT = 14, #else TRANSFORM_OBJECT_SLOT = 31, #endif - TRANSFORM_CAMERA_SLOT = 7, + TRANSFORM_CAMERA_SLOT = 15, }; // The named batch data provides a mechanism for accumulating data into buffers over the course diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 1a0a072256..d6cf9f9408 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -73,6 +73,10 @@ enum DeferredShader_BufferSlot { LIGHTING_MODEL_BUFFER_SLOT = render::ShapePipeline::Slot::LIGHTING_MODEL, LIGHT_GPU_SLOT = render::ShapePipeline::Slot::LIGHT, LIGHT_INDEX_GPU_SLOT, + LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, + LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, + LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, + }; static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); @@ -218,7 +222,11 @@ static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* f slotBindings.insert(gpu::Shader::Binding(std::string("subsurfaceScatteringParametersBuffer"), SCATTERING_PARAMETERS_BUFFER_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("lightIndexBuffer"), LIGHT_INDEX_GPU_SLOT)); - + + + slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); @@ -716,6 +724,11 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightIndexBufferUnit, lightClusters->_lightIndicesBuffer); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer); + + // before we get to the real lighting, let s try to cull down the number of pixels if (false) {/* if (numPointLights > 0) { diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 5287695b10..c70d0d2c6b 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -47,12 +47,30 @@ float projection_getFar(mat4 projection) { // end of hybrid include -layout (std140) uniform clusterGridBuffer { +uniform clusterGridBuffer { int _clusterGridTable[4096]; }; -layout (std140) uniform clusterContentBuffer { - int _clusterGridContent[4096]; +uniform clusterContentBuffer { + int _clusterGridContent[10000]; }; +int clusterGrid_clusterToIndex(ivec3 pos) { + return pos.x + (pos.y + pos.z * frustumGrid.dims.y) * frustumGrid.dims.x; +} +ivec3 clusterGrid_indexToCluster(int index) { + ivec3 summedDims = ivec3(frustumGrid.dims.x * frustumGrid.dims.y, frustumGrid.dims.x, 1); + int layer = index / summedDims.x; + int offsetInLayer = index % summedDims.x; + ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); + return clusterPos; +} + +ivec2 clusterGrid_getCluster(int index) { + int clusterDesc = _clusterGridTable[index]; + int numLights = 0xFFFF & (clusterDesc >> 16); + int contentOffset = 0xFFFF & (clusterDesc); + return ivec2(numLights, contentOffset); +} + <@endif@> diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 5577b2e612..4ce469deba 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -1,5 +1,4 @@ // glsl / C++ compatible source as interface for FrustrumGrid - float frustumGrid_depthRamp(float linear) { // return linear; return linear * linear; @@ -132,6 +131,8 @@ vec4 frustumGrid_worldToEye(vec4 worldPos) { return frustumGrid.worldToEyeMat * worldPos; } + + // <@if 1@> // Trigger Scribe include // <@endif@> End C++ compatible \ No newline at end of file diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index ff9362eb3e..a2feb2e471 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -194,10 +194,27 @@ void LightClusters::updateClusters() { // rotate the eyeToOriDir (H & V) in both directions - glm::vec3 leftDir(eyeOriDirH.x * eyeToTangentCircleCosH - eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); - glm::vec3 rightDir(eyeOriDirH.x * eyeToTangentCircleCosH + eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * -eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); - glm::vec3 bottomDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV - eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); - glm::vec3 topDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV + eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * -eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); + glm::vec3 leftDir(eyeOriDirH.x * eyeToTangentCircleCosH + eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * -eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); + glm::vec3 rightDir(eyeOriDirH.x * eyeToTangentCircleCosH - eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); + glm::vec3 bottomDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV + eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * -eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); + glm::vec3 topDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV - eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); + + + glm::vec3 leftPosAtNear = leftDir * theFrustumGrid.rangeNear * 2.0f; + glm::vec3 rightPosAtNear = rightDir * theFrustumGrid.rangeNear * 2.0f; + glm::vec3 bottomPosAtNear = bottomDir * theFrustumGrid.rangeNear * 2.0f; + glm::vec3 topPosAtNear = topDir * theFrustumGrid.rangeNear * 2.0f; + + auto lc = theFrustumGrid.frustumGrid_eyeToClusterPos(leftPosAtNear); + auto rc = theFrustumGrid.frustumGrid_eyeToClusterPos(rightPosAtNear); + auto bc = theFrustumGrid.frustumGrid_eyeToClusterPos(bottomPosAtNear); + auto tc = theFrustumGrid.frustumGrid_eyeToClusterPos(topPosAtNear); + + xMin = std::max(0, lc.x); + xMax = std::max(0, std::min(rc.x, xMax)); + yMin = std::max(0, bc.y); + yMax = std::max(0, std::min(tc.y, yMax)); + } @@ -249,6 +266,16 @@ void LightClusteringPass::configure(const Config& config) { if (_lightClusters->_frustumGridBuffer->rangeFar != config.rangeFar) { _lightClusters->_frustumGridBuffer.edit().rangeFar = config.rangeFar; } + + ivec3 configDimensions; + configDimensions.x = std::max(0, std::min(16, config.dimX)); + configDimensions.y = std::max(0, std::min(16, config.dimY)); + configDimensions.z = std::max(0, std::min(15, config.dimZ)); + + auto& dims = _lightClusters->_frustumGridBuffer->dims; + if ((dims.x != configDimensions.x) || (dims.y != configDimensions.y) || (dims.z != configDimensions.z)) { + _lightClusters->setDimensions(configDimensions, 10000); + } } _freeze = config.freeze; @@ -290,6 +317,7 @@ DebugLightClusters::DebugLightClusters() { void DebugLightClusters::configure(const Config& config) { doDrawGrid = config.doDrawGrid; doDrawClusterFromDepth = config.doDrawClusterFromDepth; + doDrawContent = config.doDrawContent; } @@ -301,6 +329,9 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterGridPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT)); + gpu::Shader::makeProgram(*program, slotBindings); @@ -327,6 +358,8 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterFromDepthPipeline() gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("linearZeyeMap"), DEFERRED_BUFFER_LINEAR_DEPTH_UNIT)); slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), CAMERA_CORRECTION_BUFFER_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT)); @@ -401,6 +434,9 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co batch.setModelTransform(Transform()); batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer); + if (doDrawClusterFromDepth) { @@ -422,8 +458,6 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co if (doDrawContent) { // bind the one gpu::Pipeline we need batch.setPipeline(getDrawClusterContentPipeline()); - batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer); - batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer); auto dims = lightClusters->_frustumGridBuffer->dims; glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 9930eda731..bef28a498a 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -24,7 +24,7 @@ public: float rangeFar { 100.0f }; float frustumFar { 10000.0f }; - glm::ivec3 dims { 8, 8, 8 }; + glm::ivec3 dims { 8, 8, 12 }; float spare; glm::mat4 eyeToGridProj; @@ -97,12 +97,21 @@ class LightClusteringPassConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(float rangeNear MEMBER rangeNear NOTIFY dirty) Q_PROPERTY(float rangeFar MEMBER rangeFar NOTIFY dirty) + + Q_PROPERTY(int dimX MEMBER dimX NOTIFY dirty) + Q_PROPERTY(int dimY MEMBER dimY NOTIFY dirty) + Q_PROPERTY(int dimZ MEMBER dimZ NOTIFY dirty) Q_PROPERTY(bool freeze MEMBER freeze NOTIFY dirty) public: LightClusteringPassConfig() : render::Job::Config(true){} float rangeNear{ 1.0f }; float rangeFar{ 512.0f }; + + int dimX { 8 }; + int dimY { 8 }; + int dimZ { 12 }; + bool freeze{ false }; signals: @@ -143,12 +152,14 @@ class DebugLightClustersConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(bool doDrawGrid MEMBER doDrawGrid NOTIFY dirty) Q_PROPERTY(bool doDrawClusterFromDepth MEMBER doDrawClusterFromDepth NOTIFY dirty) + Q_PROPERTY(bool doDrawContent MEMBER doDrawContent NOTIFY dirty) public: DebugLightClustersConfig() : render::Job::Config(true){} bool doDrawGrid{ false }; - bool doDrawClusterFromDepth{ false }; + bool doDrawClusterFromDepth { false }; + bool doDrawContent { false }; signals: void dirty(); @@ -179,9 +190,9 @@ protected: const gpu::PipelinePointer getDrawClusterGridPipeline(); const gpu::PipelinePointer getDrawClusterFromDepthPipeline(); const gpu::PipelinePointer getDrawClusterContentPipeline(); - bool doDrawGrid{ false }; + bool doDrawGrid { false }; bool doDrawClusterFromDepth { false }; - bool doDrawContent { true }; + bool doDrawContent { false }; }; #endif diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index a971bb5d2c..f976c7e245 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -53,22 +53,16 @@ void main(void) { ); vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - int clusterDesc = _clusterGridTable[gl_InstanceID]; - int numLights = 0xFFFF & (clusterDesc >> 16); - - if (numLights <= 0) { - return; - } - ivec3 dims = frustumGrid.dims.xyz; + - ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); + ivec2 cluster = clusterGrid_getCluster(gl_InstanceID); + int numLights = cluster.x; + float numLightsScale = clamp(numLights * 0.1, 0.01, 1.0); - int layer = gl_InstanceID / summedDims.x; - int offsetInLayer = gl_InstanceID % summedDims.x; - ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); + ivec3 clusterPos = clusterGrid_indexToCluster(gl_InstanceID); - - vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz); + float boxScale = 0.99; + vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3((1.0 - boxScale) * 0.5 + (1.0 - numLightsScale) * boxScale * 0.5) + numLightsScale * boxScale * pos.xyz); vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0)); diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index cd4f7fee63..bf98595399 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -36,6 +36,12 @@ void main(void) { vec4 clusterEyePos = frustumGrid_worldToEye(fragWorldPos); ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); + + ivec2 cluster = clusterGrid_getCluster(clusterGrid_clusterToIndex(clusterPos)); + int numLights = cluster.x; + float numLightsScale = clamp(numLights * 0.1, 0.01, 1.0); + + ivec3 dims = frustumGrid.dims.xyz; dims.z +=1; ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); @@ -59,9 +65,9 @@ void main(void) { if (relClusterId < 0.0) { _fragColor = vec4(0.0); } else if (relClusterId >= 1.0) { - _fragColor = vec4(vec3(1.0), 0.5); + _fragColor = vec4(vec3(1.0), 0.2); } else { - _fragColor = vec4(colorWheel(fract(relClusterId)), 0.9); + _fragColor = vec4(colorWheel(fract(relClusterId)), 0.05 + 0.95 * numLightsScale); } } diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index b002382c91..4a27a258fb 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -25,11 +25,15 @@ uniform lightIndexBuffer { }; <@include LightingModel.slh@> + <@include LightPoint.slh@> <$declareLightingPoint(supportScattering)$> <@include LightSpot.slh@> <$declareLightingSpot(supportScattering)$> +<@include LightClusterGrid.slh@> + + in vec2 _texCoord0; out vec4 _fragColor; @@ -47,24 +51,54 @@ void main(void) { frag.position = fragPosition; + + // Frag pos in world + mat4 invViewMat = getViewInverse(); + vec4 fragPos = invViewMat * fragPosition; + + // From frag world pos find the cluster + vec4 clusterEyePos = frustumGrid_worldToEye(fragPos); + ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); + + + ivec2 cluster = clusterGrid_getCluster(clusterGrid_clusterToIndex(clusterPos)); + int numLights = cluster.x; + if (numLights <= 0) { + discard; + } + + ivec3 dims = frustumGrid.dims.xyz; + if (clusterPos.x < 0 || clusterPos.x >= dims.x) { + discard; + } + + if (clusterPos.y < 0 || clusterPos.y >= dims.y) { + discard; + } + if (clusterPos.z < 0 || clusterPos.z > dims.z) { + discard; + } + + int lightClusterOffset = cluster.y; + + + vec4 midNormalCurvature; vec4 lowNormalCurvature; if (frag.mode == FRAG_MODE_SCATTERING) { unpackMidLowNormalCurvature(texCoord, midNormalCurvature, lowNormalCurvature); } - // Frag pos in world - mat4 invViewMat = getViewInverse(); - vec4 fragPos = invViewMat * fragPosition; // Frag to eye vec vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - int numLights = lightIndex[0]; + // int numLights = lightIndex[0]; for (int i = 0; i < numLights; i++) { // Need the light now - Light light = getLight(lightIndex[i + 1]); + int theLightIndex = _clusterGridContent[lightClusterOffset + i]; + Light light = getLight(theLightIndex); bool isSpot = light_isSpot(light); // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space vec4 fragLightVecLen2; @@ -98,5 +132,7 @@ void main(void) { _fragColor.rgb += diffuse; _fragColor.rgb += specular; } + + // _fragColor.rgb += vec3(0.05, 0.0, 0.0); } diff --git a/scripts/developer/utilities/render/lightClustering.qml b/scripts/developer/utilities/render/lightClustering.qml index 9adb137b0f..622d858c62 100644 --- a/scripts/developer/utilities/render/lightClustering.qml +++ b/scripts/developer/utilities/render/lightClustering.qml @@ -34,7 +34,30 @@ Column { max: 500.0 min: 100.0 } - + ConfigSlider { + label: qsTr("Grid X") + integral: true + config: Render.getConfig("LightClustering") + property: "dimX" + max: 16 + min: 1 + } + ConfigSlider { + label: qsTr("Grid Y") + integral: true + config: Render.getConfig("LightClustering") + property: "dimY" + max: 16 + min: 1 + } + ConfigSlider { + label: qsTr("Grid Z") + integral: true + config: Render.getConfig("LightClustering") + property: "dimZ" + max: 15 + min: 1 + } CheckBox { text: "Freeze" checked: Render.getConfig("LightClustering")["freeze"] @@ -50,6 +73,11 @@ Column { checked: Render.getConfig("DebugLightClusters")["doDrawClusterFromDepth"] onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawClusterFromDepth"] = checked } } + CheckBox { + text: "Draw Content" + checked: Render.getConfig("DebugLightClusters")["doDrawContent"] + onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawContent"] = checked } + } } } } From fea5f8b03bd745b29868a952a1a5ff83b8abb626 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 13 Sep 2016 16:03:57 -0700 Subject: [PATCH 031/104] best state for now --- libraries/render-utils/src/LightClusters.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index a2feb2e471..fabfffd439 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -108,7 +108,7 @@ void LightClusters::updateClusters() { std::vector< std::vector< uint32_t > > clusterGrid(_numClusters); _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); - uint32_t maxNumIndices = _clusterContent.size(); + uint32_t maxNumIndices = (uint32_t) _clusterContent.size(); _clusterContent.resize(maxNumIndices, INVALID_LIGHT); auto theFrustumGrid(_frustumGridBuffer.get()); From 124060d31af42bd87c8b909526a94cf544aa2363 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 13 Sep 2016 17:44:19 -0700 Subject: [PATCH 032/104] Cleaning up a bit --- .../render-utils/src/LightClusterGrid.slh | 2 +- libraries/render-utils/src/LightClusters.cpp | 55 ++++++--- libraries/render-utils/src/LightClusters.h | 9 +- .../src/lightClusters_drawClusterContent.slv | 5 +- .../lightClusters_drawClusterFromDepth.slf | 2 +- .../utilities/render/lightClustering.js | 4 +- .../utilities/render/lightClustering.qml | 109 +++++++++++------- 7 files changed, 118 insertions(+), 68 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index c70d0d2c6b..af046ce11d 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -52,7 +52,7 @@ uniform clusterGridBuffer { }; uniform clusterContentBuffer { - int _clusterGridContent[10000]; + int _clusterGridContent[16384]; }; int clusterGrid_clusterToIndex(ivec3 pos) { diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index fabfffd439..4de51af6da 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -42,22 +42,43 @@ enum LightClusterGridShader_BufferSlot { #include "DeferredLightingEffect.h" +const glm::uvec4 LightClusters::MAX_GRID_DIMENSIONS { 16, 16, 15, 16384 }; + + LightClusters::LightClusters() : _lightIndicesBuffer(std::make_shared()), _clusterGridBuffer(std::make_shared(), gpu::Element::INDEX_INT32), _clusterContentBuffer(std::make_shared(), gpu::Element::INDEX_INT32) { - setDimensions(_frustumGridBuffer->dims, 10000); + setDimensions(_frustumGridBuffer->dims, MAX_GRID_DIMENSIONS.w); } void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { - _frustumGridBuffer.edit().dims = gridDims; + ivec3 configDimensions; + configDimensions.x = std::min(MAX_GRID_DIMENSIONS.x, gridDims.x); + configDimensions.y = std::min(MAX_GRID_DIMENSIONS.y, gridDims.y); + configDimensions.z = std::min(MAX_GRID_DIMENSIONS.z, gridDims.z); - _numClusters = _frustumGridBuffer.edit().frustumGrid_numClusters(); + auto configListBudget = std::min(MAX_GRID_DIMENSIONS.w, listBudget); - _clusterGridBuffer._size = _clusterGridBuffer._buffer->resize(_numClusters * sizeof(uint32_t)); - _clusterContentBuffer._size = _clusterContentBuffer._buffer->resize(listBudget * sizeof(uint32_t)); - _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); - _clusterContent.resize(listBudget, INVALID_LIGHT); + auto& dims = _frustumGridBuffer->dims; + if ((dims.x != configDimensions.x) || (dims.y != configDimensions.y) || (dims.z != configDimensions.z)) { + _frustumGridBuffer.edit().dims = configDimensions; + } + + auto numClusters = _frustumGridBuffer.edit().frustumGrid_numClusters(); + if (numClusters != _numClusters) { + _numClusters = numClusters; + _clusterGrid.clear(); + _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); + _clusterGridBuffer._size = _clusterGridBuffer._buffer->resize(_numClusters * sizeof(uint32_t)); + } + + + if (configListBudget != _clusterContentBuffer.getNumElements()) { + _clusterContent.clear(); + _clusterContent.resize(configListBudget, INVALID_LIGHT); + _clusterContentBuffer._size = _clusterContentBuffer._buffer->resize(configListBudget * sizeof(LightID)); + } } @@ -105,7 +126,7 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p void LightClusters::updateClusters() { // Clean up last info - std::vector< std::vector< uint32_t > > clusterGrid(_numClusters); + std::vector< std::vector< LightID > > clusterGrid(_numClusters); _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); uint32_t maxNumIndices = (uint32_t) _clusterContent.size(); @@ -228,6 +249,10 @@ void LightClusters::updateClusters() { } } } + + if (numClusterTouched >= maxNumIndices) { + break; + } } // Lights have been gathered now reexpress in terms of 2 sequential buffers @@ -241,7 +266,7 @@ void LightClusters::updateClusters() { _clusterGrid[i] = (uint32_t)((numLights << 16) | offset); if (numLights) { - memcpy(_clusterContent.data() + indexOffset, cluster.data(), numLights * sizeof(uint32_t)); + memcpy(_clusterContent.data() + indexOffset, cluster.data(), numLights * sizeof(LightID)); } indexOffset += numLights; @@ -249,7 +274,7 @@ void LightClusters::updateClusters() { // update the buffers _clusterGridBuffer._buffer->setData(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()); - _clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(uint32_t), (gpu::Byte*) _clusterContent.data()); + _clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(LightID), (gpu::Byte*) _clusterContent.data()); } @@ -267,15 +292,7 @@ void LightClusteringPass::configure(const Config& config) { _lightClusters->_frustumGridBuffer.edit().rangeFar = config.rangeFar; } - ivec3 configDimensions; - configDimensions.x = std::max(0, std::min(16, config.dimX)); - configDimensions.y = std::max(0, std::min(16, config.dimY)); - configDimensions.z = std::max(0, std::min(15, config.dimZ)); - - auto& dims = _lightClusters->_frustumGridBuffer->dims; - if ((dims.x != configDimensions.x) || (dims.y != configDimensions.y) || (dims.z != configDimensions.z)) { - _lightClusters->setDimensions(configDimensions, 10000); - } + _lightClusters->setDimensions(glm::uvec3(config.dimX, config.dimY, config.dimZ), 10000); } _freeze = config.freeze; diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index bef28a498a..5d64b17ca1 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -54,7 +54,10 @@ public: class LightClusters { public: - + using LightID = LightStage::Index; + + static const glm::uvec4 MAX_GRID_DIMENSIONS; + LightClusters(); void setDimensions(glm::uvec3 gridDims, uint32_t listBudget); @@ -81,10 +84,10 @@ public: uint32_t _numClusters { 0 }; const uint32_t EMPTY_CLUSTER { 0x0000FFFF }; - const uint32_t INVALID_LIGHT { 0xFFFFFFFF }; + const LightID INVALID_LIGHT { LightStage::INVALID_INDEX }; std::vector _clusterGrid; - std::vector _clusterContent; + std::vector _clusterContent; gpu::BufferView _clusterGridBuffer; gpu::BufferView _clusterContentBuffer; }; diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index f976c7e245..af3cf3e3ac 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -57,7 +57,8 @@ void main(void) { ivec2 cluster = clusterGrid_getCluster(gl_InstanceID); int numLights = cluster.x; - float numLightsScale = clamp(numLights * 0.1, 0.01, 1.0); + + float numLightsScale = clamp(numLights * 0.1, 0.0, 1.0); ivec3 clusterPos = clusterGrid_indexToCluster(gl_InstanceID); @@ -70,5 +71,5 @@ void main(void) { TransformCamera cam = getTransformCamera(); <$transformWorldToClipPos(cam, worldPos, gl_Position)$> - varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), 0.9); + varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), (numLights >0 ? 0.9 : 0.1)); } \ No newline at end of file diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index bf98595399..e711c6fc64 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -67,7 +67,7 @@ void main(void) { } else if (relClusterId >= 1.0) { _fragColor = vec4(vec3(1.0), 0.2); } else { - _fragColor = vec4(colorWheel(fract(relClusterId)), 0.05 + 0.95 * numLightsScale); + _fragColor = vec4(colorWheel(fract(relClusterId)), (numLights > 0 ? 0.05 + 0.95 * numLightsScale : 0.0)); } } diff --git a/scripts/developer/utilities/render/lightClustering.js b/scripts/developer/utilities/render/lightClustering.js index bad023a64f..7fb9416d40 100644 --- a/scripts/developer/utilities/render/lightClustering.js +++ b/scripts/developer/utilities/render/lightClustering.js @@ -15,7 +15,7 @@ var window = new OverlayWindow({ title: 'Light Clustering', source: qml, width: 400, - height: 200 + height: 300 }); -window.setPosition(Window.innerWidth - 420, 50 + 250 + 50); +window.setPosition(Window.innerWidth - 420, 50 + 250 + 50 + 250 + 50 ); window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/scripts/developer/utilities/render/lightClustering.qml b/scripts/developer/utilities/render/lightClustering.qml index 622d858c62..562e7c5556 100644 --- a/scripts/developer/utilities/render/lightClustering.qml +++ b/scripts/developer/utilities/render/lightClustering.qml @@ -10,6 +10,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "configSlider" +import "../lib/plotperf" Column { spacing: 8 @@ -18,46 +19,73 @@ Column { spacing: 10 Column{ - ConfigSlider { - label: qsTr("Range Near [m]") - integral: false - config: Render.getConfig("LightClustering") - property: "rangeNear" - max: 20.0 - min: 0.1 - } - ConfigSlider { - label: qsTr("Range Far [m]") - integral: false - config: Render.getConfig("LightClustering") - property: "rangeFar" - max: 500.0 - min: 100.0 - } - ConfigSlider { - label: qsTr("Grid X") - integral: true - config: Render.getConfig("LightClustering") - property: "dimX" - max: 16 - min: 1 - } - ConfigSlider { - label: qsTr("Grid Y") - integral: true - config: Render.getConfig("LightClustering") - property: "dimY" - max: 16 - min: 1 - } - ConfigSlider { - label: qsTr("Grid Z") - integral: true - config: Render.getConfig("LightClustering") - property: "dimZ" - max: 15 - min: 1 - } + PlotPerf { + title: "Light CLustering Timing" + height: 50 + object: Render.getConfig("LightClustering") + valueUnit: "ms" + valueScale: 1 + valueNumDigits: "4" + plots: [ + { + object: Render.getConfig("LightClustering"), + prop: "cpuRunTime", + label: "time", + scale: 1, + color: "#FFFFFF" + }, + { + object: Render.getConfig("DrawLight"), + prop: "numDrawn", + unit: "", + scale: 0.01, + numDigits: 0, + label: "Lights", + color: "#FED959" + } + ] + } + + ConfigSlider { + label: qsTr("Range Near [m]") + integral: false + config: Render.getConfig("LightClustering") + property: "rangeNear" + max: 20.0 + min: 0.1 + } + ConfigSlider { + label: qsTr("Range Far [m]") + integral: false + config: Render.getConfig("LightClustering") + property: "rangeFar" + max: 500.0 + min: 100.0 + } + ConfigSlider { + label: qsTr("Grid X") + integral: true + config: Render.getConfig("LightClustering") + property: "dimX" + max: 16 + min: 1 + } + ConfigSlider { + label: qsTr("Grid Y") + integral: true + config: Render.getConfig("LightClustering") + property: "dimY" + max: 16 + min: 1 + } + ConfigSlider { + label: qsTr("Grid Z") + integral: true + config: Render.getConfig("LightClustering") + property: "dimZ" + max: 15 + min: 1 + } CheckBox { text: "Freeze" checked: Render.getConfig("LightClustering")["freeze"] @@ -78,6 +106,7 @@ Column { checked: Render.getConfig("DebugLightClusters")["doDrawContent"] onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawContent"] = checked } } + } } } From c622849481525e1c578d59dcc43c88f1c963066a Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 13 Sep 2016 17:59:06 -0700 Subject: [PATCH 033/104] Splitting the frustum culling test horizontal and vertical --- libraries/render-utils/src/LightClusters.cpp | 47 +++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 4de51af6da..ef584ae104 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -192,51 +192,64 @@ void LightClusters::updateClusters() { float eyeOriLen2H = glm::length2(eyeOriH); float eyeOriLen2V = glm::length2(eyeOriV); - if ((eyeOriLen2H > radius2) && (eyeOriLen2V > radius2)) { + if ((eyeOriLen2H > radius2)) { float eyeOriLenH = sqrt(eyeOriLen2H); - float eyeOriLenV = sqrt(eyeOriLen2V); auto eyeOriDirH = glm::vec3(eyeOriH) / eyeOriLenH; - auto eyeOriDirV = glm::vec3(eyeOriV) / eyeOriLenV; - - float eyeToTangentCircleLenH = sqrt(eyeOriLen2H - radius2); - float eyeToTangentCircleLenV = sqrt(eyeOriLen2V - radius2); float eyeToTangentCircleTanH = radius / eyeToTangentCircleLenH; - float eyeToTangentCircleTanV = radius / eyeToTangentCircleLenV; float eyeToTangentCircleCosH = eyeToTangentCircleLenH / eyeOriLenH; - float eyeToTangentCircleCosV = eyeToTangentCircleLenV / eyeOriLenV; float eyeToTangentCircleSinH = radius / eyeOriLenH; - float eyeToTangentCircleSinV = radius / eyeOriLenV; // rotate the eyeToOriDir (H & V) in both directions glm::vec3 leftDir(eyeOriDirH.x * eyeToTangentCircleCosH + eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * -eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); glm::vec3 rightDir(eyeOriDirH.x * eyeToTangentCircleCosH - eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); - glm::vec3 bottomDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV + eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * -eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); - glm::vec3 topDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV - eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); glm::vec3 leftPosAtNear = leftDir * theFrustumGrid.rangeNear * 2.0f; glm::vec3 rightPosAtNear = rightDir * theFrustumGrid.rangeNear * 2.0f; - glm::vec3 bottomPosAtNear = bottomDir * theFrustumGrid.rangeNear * 2.0f; - glm::vec3 topPosAtNear = topDir * theFrustumGrid.rangeNear * 2.0f; auto lc = theFrustumGrid.frustumGrid_eyeToClusterPos(leftPosAtNear); auto rc = theFrustumGrid.frustumGrid_eyeToClusterPos(rightPosAtNear); - auto bc = theFrustumGrid.frustumGrid_eyeToClusterPos(bottomPosAtNear); - auto tc = theFrustumGrid.frustumGrid_eyeToClusterPos(topPosAtNear); xMin = std::max(0, lc.x); xMax = std::max(0, std::min(rc.x, xMax)); + } + + if ((eyeOriLen2V > radius2)) { + float eyeOriLenV = sqrt(eyeOriLen2V); + + auto eyeOriDirV = glm::vec3(eyeOriV) / eyeOriLenV; + + + + float eyeToTangentCircleLenV = sqrt(eyeOriLen2V - radius2); + + float eyeToTangentCircleTanV = radius / eyeToTangentCircleLenV; + + float eyeToTangentCircleCosV = eyeToTangentCircleLenV / eyeOriLenV; + + float eyeToTangentCircleSinV = radius / eyeOriLenV; + + + // rotate the eyeToOriDir (H & V) in both directions + glm::vec3 bottomDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV + eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * -eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); + glm::vec3 topDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV - eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); + + + glm::vec3 bottomPosAtNear = bottomDir * theFrustumGrid.rangeNear * 2.0f; + glm::vec3 topPosAtNear = topDir * theFrustumGrid.rangeNear * 2.0f; + + auto bc = theFrustumGrid.frustumGrid_eyeToClusterPos(bottomPosAtNear); + auto tc = theFrustumGrid.frustumGrid_eyeToClusterPos(topPosAtNear); + yMin = std::max(0, bc.y); yMax = std::max(0, std::min(tc.y, yMax)); - - } // now voxelize From af48d4f0bdf999a59d5109a7f5ff83f94c102a49 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 14 Sep 2016 09:28:51 -0700 Subject: [PATCH 034/104] fetch the cluster content through a function to be able to change the implementation --- libraries/render-utils/src/LightClusterGrid.slh | 4 ++++ libraries/render-utils/src/local_lights_shading.slf | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index af046ce11d..ceb3f79e89 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -73,4 +73,8 @@ ivec2 clusterGrid_getCluster(int index) { return ivec2(numLights, contentOffset); } +int clusterGrid_getClusterLightId(int index, ivec2 cluster) { + return _clusterGridContent[cluster.y + index]; +} + <@endif@> diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index 4a27a258fb..2b8beb67c3 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -97,7 +97,7 @@ void main(void) { // int numLights = lightIndex[0]; for (int i = 0; i < numLights; i++) { // Need the light now - int theLightIndex = _clusterGridContent[lightClusterOffset + i]; + int theLightIndex = clusterGrid_getClusterLightId(i, cluster); Light light = getLight(theLightIndex); bool isSpot = light_isSpot(light); // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space From fdba78db6f3badc8789c8c910420ec53e8db1625 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 14 Sep 2016 16:36:01 -0700 Subject: [PATCH 035/104] Better vizualization, first set of culling improvment --- .../src/LightClusterGrid_shared.slh | 32 +++++++++ libraries/render-utils/src/LightClusters.cpp | 67 ++++++++++--------- libraries/render-utils/src/LightClusters.h | 2 +- .../src/lightClusters_drawClusterContent.slv | 8 +-- .../src/lightClusters_drawGrid.slv | 13 ++-- 5 files changed, 76 insertions(+), 46 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 4ce469deba..da4931a91e 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -123,6 +123,38 @@ ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { return ivec3(gridPos); } +int frustumGrid_eyeToClusterDirH(vec3 eyeDir) { + if (eyeDir.z >= 0.0) { + return (eyeDir.x > 0 ? frustumGrid.dims.x : -1); + } + + float eyeDepth = -eyeDir.z; + float nclipDir = eyeDir.x / eyeDepth; + float ndcDir = nclipDir * frustumGrid.eyeToGridProj[0][0] - frustumGrid.eyeToGridProj[2][0]; + float volumeDir = 0.5 * (ndcDir + 1.0); + float gridPos = volumeDir * float(frustumGrid.dims.x); + + return int(gridPos); +} + +int frustumGrid_eyeToClusterDirV(vec3 eyeDir) { + if (eyeDir.z >= 0.0) { + return (eyeDir.y > 0 ? frustumGrid.dims.y : -1); + } + + float eyeDepth = -eyeDir.z; + float nclipDir = eyeDir.y / eyeDepth; + float ndcDir = nclipDir * frustumGrid.eyeToGridProj[1][1] - frustumGrid.eyeToGridProj[2][1]; + float volumeDir = 0.5 * (ndcDir + 1.0); + float gridPos = volumeDir * float(frustumGrid.dims.y); + + return int(gridPos); +} + +ivec2 frustumGrid_eyeToClusterDir(vec3 eyeDir) { + return ivec2(frustumGrid_eyeToClusterDirH(eyeDir), frustumGrid_eyeToClusterDirV(eyeDir)); +} + vec4 frustumGrid_eyeToWorld(vec4 eyePos) { return frustumGrid.eyeToWorldMat * eyePos; } diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index ef584ae104..707e82ae2f 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -124,6 +124,27 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p _lightIndicesBuffer._size = _visibleLightIndices.size() * sizeof(int); } +bool scanLightVolume(FrustumGrid& grid, int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, + uint32_t& numClustersTouched, int maxNumIndices, std::vector< std::vector>& clusterGrid) { + glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); + + bool hasBudget = true; + for (auto z = zMin; (z <= zMax) && hasBudget; z++) { + for (auto y = yMin; (y <= yMax) && hasBudget; y++) { + for (auto x = xMin; (x <= xMax) && hasBudget; x++) { + auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; + clusterGrid[index].emplace_back(lightId); + numClustersTouched++; + if (numClustersTouched >= maxNumIndices) { + hasBudget = false; + } + } + } + } + + return hasBudget; +} + void LightClusters::updateClusters() { // Clean up last info std::vector< std::vector< LightID > > clusterGrid(_numClusters); @@ -167,7 +188,8 @@ void LightClusters::updateClusters() { continue; } - + // is it a light whose origin is behind the near ? + bool behindLight = (eyeOri.z >= -theFrustumGrid.rangeNear); // float eyeOriLen2 = glm::length2(eyeOri); @@ -199,8 +221,6 @@ void LightClusters::updateClusters() { float eyeToTangentCircleLenH = sqrt(eyeOriLen2H - radius2); - float eyeToTangentCircleTanH = radius / eyeToTangentCircleLenH; - float eyeToTangentCircleCosH = eyeToTangentCircleLenH / eyeOriLenH; float eyeToTangentCircleSinH = radius / eyeOriLenH; @@ -210,15 +230,11 @@ void LightClusters::updateClusters() { glm::vec3 leftDir(eyeOriDirH.x * eyeToTangentCircleCosH + eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * -eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); glm::vec3 rightDir(eyeOriDirH.x * eyeToTangentCircleCosH - eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); + auto lc = theFrustumGrid.frustumGrid_eyeToClusterDirH(leftDir); + auto rc = theFrustumGrid.frustumGrid_eyeToClusterDirH(rightDir); - glm::vec3 leftPosAtNear = leftDir * theFrustumGrid.rangeNear * 2.0f; - glm::vec3 rightPosAtNear = rightDir * theFrustumGrid.rangeNear * 2.0f; - - auto lc = theFrustumGrid.frustumGrid_eyeToClusterPos(leftPosAtNear); - auto rc = theFrustumGrid.frustumGrid_eyeToClusterPos(rightPosAtNear); - - xMin = std::max(0, lc.x); - xMax = std::max(0, std::min(rc.x, xMax)); + xMin = std::max(xMin, lc); + xMax = std::max(0, std::min(rc, xMax)); } if ((eyeOriLen2V > radius2)) { @@ -226,12 +242,8 @@ void LightClusters::updateClusters() { auto eyeOriDirV = glm::vec3(eyeOriV) / eyeOriLenV; - - float eyeToTangentCircleLenV = sqrt(eyeOriLen2V - radius2); - float eyeToTangentCircleTanV = radius / eyeToTangentCircleLenV; - float eyeToTangentCircleCosV = eyeToTangentCircleLenV / eyeOriLenV; float eyeToTangentCircleSinV = radius / eyeOriLenV; @@ -241,29 +253,17 @@ void LightClusters::updateClusters() { glm::vec3 bottomDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV + eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * -eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); glm::vec3 topDir(0.0f, eyeOriDirV.y * eyeToTangentCircleCosV - eyeOriDirV.z * eyeToTangentCircleSinV, eyeOriDirV.y * eyeToTangentCircleSinV + eyeOriDirV.z * eyeToTangentCircleCosV); + auto bc = theFrustumGrid.frustumGrid_eyeToClusterDirV(bottomDir); + auto tc = theFrustumGrid.frustumGrid_eyeToClusterDirV(topDir); - glm::vec3 bottomPosAtNear = bottomDir * theFrustumGrid.rangeNear * 2.0f; - glm::vec3 topPosAtNear = topDir * theFrustumGrid.rangeNear * 2.0f; - - auto bc = theFrustumGrid.frustumGrid_eyeToClusterPos(bottomPosAtNear); - auto tc = theFrustumGrid.frustumGrid_eyeToClusterPos(topPosAtNear); - - yMin = std::max(0, bc.y); - yMax = std::max(0, std::min(tc.y, yMax)); + yMin = std::max(yMin, bc); + yMax = std::max(yMin, std::min(tc, yMax)); } // now voxelize - for (auto z = zMin; z <= zMax; z++) { - for (auto y = yMin; y <= yMax; y++) { - for (auto x = xMin; x <= xMax; x++) { - auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; - clusterGrid[index].emplace_back(lightId); - numClusterTouched++; - } - } - } + bool hasBudget = scanLightVolume(theFrustumGrid, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), numClusterTouched, maxNumIndices, clusterGrid); - if (numClusterTouched >= maxNumIndices) { + if (!hasBudget) { break; } } @@ -486,6 +486,7 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co } if (doDrawContent) { + // bind the one gpu::Pipeline we need batch.setPipeline(getDrawClusterContentPipeline()); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 5d64b17ca1..e5d0275d85 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -74,7 +74,7 @@ public: LightStagePointer _lightStage; - + gpu::StructBuffer _frustumGridBuffer; diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index af3cf3e3ac..d146d8b691 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -1,4 +1,4 @@ -<@include gpu/Config.slh@> +<@include gpu / Config.slh@> <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // @@ -12,17 +12,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include gpu/Transform.slh@> +<@include gpu / Transform.slh@> <$declareStandardTransform()$> <@include LightClusterGrid.slh@> -<@include gpu/Color.slh@> +<@include gpu / Color.slh@> <$declareColorWheel()$> - - out vec4 varColor; diff --git a/libraries/render-utils/src/lightClusters_drawGrid.slv b/libraries/render-utils/src/lightClusters_drawGrid.slv index 9eb80cb28e..0eec0d04ee 100644 --- a/libraries/render-utils/src/lightClusters_drawGrid.slv +++ b/libraries/render-utils/src/lightClusters_drawGrid.slv @@ -53,16 +53,15 @@ void main(void) { ); vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - ivec3 dims = frustumGrid.dims.xyz; - ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); + ivec2 cluster = clusterGrid_getCluster(gl_InstanceID); + int numLights = cluster.x; - int layer = gl_InstanceID / summedDims.x; - int offsetInLayer = gl_InstanceID % summedDims.x; - ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); + ivec3 clusterPos = clusterGrid_indexToCluster(gl_InstanceID); - vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz); + float boxScale = 1.0; + vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(1.0 - boxScale) * 0.5 + boxScale * pos.xyz); vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0)); @@ -70,5 +69,5 @@ void main(void) { TransformCamera cam = getTransformCamera(); <$transformWorldToClipPos(cam, worldPos, gl_Position)$> - varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), 0.9); + varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), (numLights > 0 ? 0.9 : 0.0)); } \ No newline at end of file From e0536a84e2485926c520eb394c6be6b3b9b1c5d7 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 14 Sep 2016 17:18:39 -0700 Subject: [PATCH 036/104] Minor fix for compilation --- libraries/render-utils/src/LightClusters.cpp | 26 ++++++++++++++++--- libraries/render-utils/src/LightClusters.h | 10 +++++++ .../src/lightClusters_drawClusterContent.slv | 6 ++--- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 707e82ae2f..cbea9a2a2a 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -40,6 +40,23 @@ enum LightClusterGridShader_BufferSlot { LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, }; + +void FrustumGrid::generateGridPlanes(Planes& xPlanes, Planes& yPlanes, Planes& zPlanes) { + xPlanes.resize(dims.x + 1); + yPlanes.resize(dims.y + 1); + zPlanes.resize(dims.z + 1); + + + for (int z = 0; z < xPlanes.size(); z++) { + ivec3 pos(0, 0, z); + zPlanes[z] = glm::vec4(0.0f, 0.0f, -1.0f, frustumGrid_clusterPosToEye(pos, vec3(0.0)).z); + } + + for (int x = 0; x < xPlanes.size(); x++) { + + } +} + #include "DeferredLightingEffect.h" const glm::uvec4 LightClusters::MAX_GRID_DIMENSIONS { 16, 16, 15, 16384 }; @@ -49,7 +66,9 @@ LightClusters::LightClusters() : _lightIndicesBuffer(std::make_shared()), _clusterGridBuffer(std::make_shared(), gpu::Element::INDEX_INT32), _clusterContentBuffer(std::make_shared(), gpu::Element::INDEX_INT32) { - setDimensions(_frustumGridBuffer->dims, MAX_GRID_DIMENSIONS.w); + auto dims = _frustumGridBuffer.edit().dims; + _frustumGridBuffer.edit().dims = ivec3(0); // make sure we go through the full reset of the dimensionts ion the setDImensions call + setDimensions(dims, MAX_GRID_DIMENSIONS.w); } void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { @@ -63,6 +82,7 @@ void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { auto& dims = _frustumGridBuffer->dims; if ((dims.x != configDimensions.x) || (dims.y != configDimensions.y) || (dims.z != configDimensions.z)) { _frustumGridBuffer.edit().dims = configDimensions; + _frustumGridBuffer.edit().generateGridPlanes(_gridPlanes[0], _gridPlanes[1], _gridPlanes[2]); } auto numClusters = _frustumGridBuffer.edit().frustumGrid_numClusters(); @@ -124,7 +144,7 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p _lightIndicesBuffer._size = _visibleLightIndices.size() * sizeof(int); } -bool scanLightVolume(FrustumGrid& grid, int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, +bool scanLightVolume(const FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, uint32_t& numClustersTouched, int maxNumIndices, std::vector< std::vector>& clusterGrid) { glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); @@ -261,7 +281,7 @@ void LightClusters::updateClusters() { } // now voxelize - bool hasBudget = scanLightVolume(theFrustumGrid, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), numClusterTouched, maxNumIndices, clusterGrid); + bool hasBudget = scanLightVolume(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), numClusterTouched, maxNumIndices, clusterGrid); if (!hasBudget) { break; diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index e5d0275d85..9cafd6b186 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -50,8 +50,13 @@ public: #define frustumGrid (*this) #include "LightClusterGrid_shared.slh" + + using Planes = std::vector < glm::vec4 >; + void generateGridPlanes(Planes& xPlanes, Planes& yPlanes, Planes& zPlanes); }; + + class LightClusters { public: using LightID = LightStage::Index; @@ -78,6 +83,8 @@ public: gpu::StructBuffer _frustumGridBuffer; + FrustumGrid::Planes _gridPlanes[3]; + LightStage::LightIndices _visibleLightIndices; gpu::BufferView _lightIndicesBuffer; @@ -90,6 +97,9 @@ public: std::vector _clusterContent; gpu::BufferView _clusterGridBuffer; gpu::BufferView _clusterContentBuffer; + + + }; using LightClustersPointer = std::shared_ptr; diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index d146d8b691..616171b775 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -1,4 +1,4 @@ -<@include gpu / Config.slh@> +<@include gpu/Config.slh@> <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // @@ -12,12 +12,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include gpu / Transform.slh@> +<@include gpu/Transform.slh@> <$declareStandardTransform()$> <@include LightClusterGrid.slh@> -<@include gpu / Color.slh@> +<@include gpu/Color.slh@> <$declareColorWheel()$> From f789f566e0eafb06e30825bfc678019c8f4b5bb3 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 14 Sep 2016 17:34:17 -0700 Subject: [PATCH 037/104] Minor fix for compilation --- libraries/render-utils/src/LightClusters.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index cbea9a2a2a..78fc7035a4 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -145,7 +145,7 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p } bool scanLightVolume(const FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, - uint32_t& numClustersTouched, int maxNumIndices, std::vector< std::vector>& clusterGrid) { + uint32_t& numClustersTouched, uint32_t maxNumIndices, std::vector< std::vector>& clusterGrid) { glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); bool hasBudget = true; From 3616a6fc12e2632c916f55b51d8eeca1086031bf Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 14 Sep 2016 19:13:53 -0700 Subject: [PATCH 038/104] Startign implementing the tighter culling for sphere but not done yet --- .../src/LightClusterGrid_shared.slh | 8 ++- libraries/render-utils/src/LightClusters.cpp | 61 +++++++++++++++++-- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index da4931a91e..b124798131 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -68,9 +68,9 @@ int frustumGrid_numClusters() { return frustumGrid.dims.x * frustumGrid.dims.y * (frustumGrid.dims.z + 1); } -vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) { +vec3 frustumGrid_clusterPosToEye(vec3 clusterPos) { - vec3 cvpos = vec3(clusterPos) + offset; + vec3 cvpos = clusterPos; vec3 volumePos = frustumGrid_gridToVolume(cvpos, frustumGrid.dims); @@ -80,6 +80,10 @@ vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) { return eyePos; } +vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) { + vec3 cvpos = vec3(clusterPos) + offset; + return frustumGrid_clusterPosToEye(cvpos); +} int frustumGrid_eyeDepthToClusterLayer(float eyeZ) { if ((eyeZ > -frustumGrid.frustumNear) || (eyeZ < -frustumGrid.frustumFar)) { diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 78fc7035a4..09061e8dc6 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -46,15 +46,26 @@ void FrustumGrid::generateGridPlanes(Planes& xPlanes, Planes& yPlanes, Planes& z yPlanes.resize(dims.y + 1); zPlanes.resize(dims.z + 1); + float centerY = float(dims.y) * 0.5; + float centerX = float(dims.x) * 0.5; - for (int z = 0; z < xPlanes.size(); z++) { + for (int z = 0; z < zPlanes.size(); z++) { ivec3 pos(0, 0, z); zPlanes[z] = glm::vec4(0.0f, 0.0f, -1.0f, frustumGrid_clusterPosToEye(pos, vec3(0.0)).z); } for (int x = 0; x < xPlanes.size(); x++) { - + auto slicePos = frustumGrid_clusterPosToEye(glm::vec3((float)x, centerY, 0.0)); + auto sliceDir = glm::normalize(slicePos); + xPlanes[x] = glm::vec4(sliceDir.z, 0.0, -sliceDir.x, 0.0); } + + for (int y = 0; y < yPlanes.size(); y++) { + auto slicePos = frustumGrid_clusterPosToEye(glm::vec3(centerX, (float)y, 0.0)); + auto sliceDir = glm::normalize(slicePos); + yPlanes[y] = glm::vec4(0.0, sliceDir.z, -sliceDir.x, 0.0); + } + } #include "DeferredLightingEffect.h" @@ -144,14 +155,42 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p _lightIndicesBuffer._size = _visibleLightIndices.size() * sizeof(int); } +glm::vec4 projectToPlane(glm::vec4& sphere, const glm::vec4& plane) { + float distance = sphere.x * plane.x + sphere.y *plane.y + sphere.z * plane.z + plane.w; + + if (distance < sphere.w) { + return glm::vec4(sphere.x - distance * plane.x, sphere.y - distance * plane.y, sphere.z - distance * plane.z, sqrt(sphere.w * sphere.w - distance * distance)); + } else { + return sphere; + } +} + bool scanLightVolume(const FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, uint32_t& numClustersTouched, uint32_t maxNumIndices, std::vector< std::vector>& clusterGrid) { glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); + int center_z = (zMax + zMin) >> 1; + int center_y = (yMax + yMin) >> 1; bool hasBudget = true; for (auto z = zMin; (z <= zMax) && hasBudget; z++) { + auto zSphere = eyePosRadius; + if (z != center_z) { + auto& plane = (z < center_z) ? planes[2][z + 1] : -planes[2][z]; + zSphere = projectToPlane(zSphere, plane); + } for (auto y = yMin; (y <= yMax) && hasBudget; y++) { - for (auto x = xMin; (x <= xMax) && hasBudget; x++) { + auto ySphere = zSphere; + if (y != center_y) { + auto& plane = (y < center_y) ? planes[1][y + 1] : -planes[1][y]; + ySphere = projectToPlane(ySphere, plane); + } + + auto x = xMin; + do { ++x; } while ((x < xMax) && (glm::dot(planes[0][x], glm::vec4(ySphere.x, ySphere.y, ySphere.z, 1.0)) >= ySphere.w)); + auto xs = xMax; + do { --xs; } while ((xs >= x) && (-glm::dot(planes[0][xs], glm::vec4(ySphere.x, ySphere.y, ySphere.z, 1.0)) >= ySphere.w)); + + for (--x; (x <= xs) && hasBudget; x++) { auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; clusterGrid[index].emplace_back(lightId); numClustersTouched++; @@ -281,7 +320,21 @@ void LightClusters::updateClusters() { } // now voxelize - bool hasBudget = scanLightVolume(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), numClusterTouched, maxNumIndices, clusterGrid); + // bool hasBudget = scanLightVolume(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), numClusterTouched, maxNumIndices, clusterGrid); + + bool hasBudget = true; + for (auto z = zMin; (z <= zMax) && hasBudget; z++) { + for (auto y = yMin; (y <= yMax) && hasBudget; y++) { + for (auto x = xMin; (x <= xMax) && hasBudget; x++) { + auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; + clusterGrid[index].emplace_back(lightId); + numClusterTouched++; + if (numClusterTouched >= maxNumIndices) { + hasBudget = false; + } + } + } + } if (!hasBudget) { break; From a0862820e692f80420191812af4c61ad094d64fc Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 27 Sep 2016 18:38:15 -0700 Subject: [PATCH 039/104] MOre refinements? --- .../render-utils/src/LightClusterGrid.slh | 11 -- .../src/LightClusterGrid_shared.slh | 43 ++++-- libraries/render-utils/src/LightClusters.cpp | 122 +++++++++++------- libraries/render-utils/src/LightClusters.h | 8 +- .../src/lightClusters_drawClusterContent.slv | 2 +- .../lightClusters_drawClusterFromDepth.slf | 2 +- .../lightClusters_drawClusterFromDepth.slv | 10 +- .../src/lightClusters_drawGrid.slv | 2 +- .../render-utils/src/local_lights_shading.slf | 2 +- 9 files changed, 116 insertions(+), 86 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index cd94b49ddd..7964d09142 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -55,17 +55,6 @@ uniform clusterContentBuffer { int _clusterGridContent[16384]; }; -int clusterGrid_clusterToIndex(ivec3 pos) { - return pos.x + (pos.y + pos.z * frustumGrid.dims.y) * frustumGrid.dims.x; -} -ivec3 clusterGrid_indexToCluster(int index) { - ivec3 summedDims = ivec3(frustumGrid.dims.x * frustumGrid.dims.y, frustumGrid.dims.x, 1); - int layer = index / summedDims.x; - int offsetInLayer = index % summedDims.x; - ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); - return clusterPos; -} - ivec2 clusterGrid_getCluster(int index) { int clusterDesc = _clusterGridTable[index]; int numLights = 0xFFFF & (clusterDesc >> 16); diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index b124798131..54281d010e 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -1,27 +1,33 @@ // glsl / C++ compatible source as interface for FrustrumGrid -float frustumGrid_depthRamp(float linear) { - // return linear; - return linear * linear; +float frustumGrid_depthRampGridToVolume(float ngrid) { + if (ngrid < 0.0) + return ngrid; + // return ngrid; + // return sqrt(ngrid); + return exp2(ngrid) - 1.0; } -float frustumGrid_depthRampInverse(float volume) { - // return volume; - return sqrt(volume); +float frustumGrid_depthRampInverseVolumeToGrid(float nvolume) { + if (nvolume < 0.0) + return nvolume; + // return nvolume; + // return nvolume * nvolume; + return log2(nvolume + 1.0); } vec3 frustumGrid_gridToVolume(vec3 pos, ivec3 dims) { vec3 gridScale = vec3(1.0, 1.0, 1.0) / vec3(dims); vec3 volumePos = pos * gridScale; - volumePos.z = frustumGrid_depthRamp(volumePos.z); + volumePos.z = frustumGrid_depthRampGridToVolume(volumePos.z); return volumePos; } float frustumGrid_volumeToGridDepth(float vposZ, ivec3 dims) { - return frustumGrid_depthRampInverse(vposZ) * float(dims.z); + return frustumGrid_depthRampInverseVolumeToGrid(vposZ) * float(dims.z); } vec3 frustumGrid_volumeToGrid(vec3 vpos, ivec3 dims) { - vec3 gridPos = vec3(vpos.x, vpos.y, frustumGrid_depthRampInverse(vpos.z)) * vec3(dims); + vec3 gridPos = vec3(vpos.x, vpos.y, frustumGrid_depthRampInverseVolumeToGrid(vpos.z)) * vec3(dims); return gridPos; } @@ -68,6 +74,21 @@ int frustumGrid_numClusters() { return frustumGrid.dims.x * frustumGrid.dims.y * (frustumGrid.dims.z + 1); } +int frustumGrid_clusterToIndex(ivec3 pos) { + return pos.x + (pos.y + pos.z * frustumGrid.dims.y) * frustumGrid.dims.x; +} +ivec3 frustumGrid_indexToCluster(int index) { + if (index <= 0) { + return ivec3(0, 0, -1); + } + index -= 1; + ivec3 summedDims = ivec3(frustumGrid.dims.x * frustumGrid.dims.y, frustumGrid.dims.x, 1); + int layer = index / summedDims.x; + int offsetInLayer = index % summedDims.x; + ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); + return clusterPos; +} + vec3 frustumGrid_clusterPosToEye(vec3 clusterPos) { vec3 cvpos = clusterPos; @@ -87,7 +108,7 @@ vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset) { int frustumGrid_eyeDepthToClusterLayer(float eyeZ) { if ((eyeZ > -frustumGrid.frustumNear) || (eyeZ < -frustumGrid.frustumFar)) { - return -1; + return -2; } if (eyeZ > -frustumGrid.rangeNear) { @@ -108,7 +129,7 @@ int frustumGrid_eyeDepthToClusterLayer(float eyeZ) { ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { if ((eyePos.z > -frustumGrid.frustumNear) || (eyePos.z < -frustumGrid.frustumFar)) { - return ivec3(-1); + return ivec3(-2); } if (eyePos.z > -frustumGrid.rangeNear) { diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 362e6c3665..651ba4957d 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -49,18 +49,18 @@ void FrustumGrid::generateGridPlanes(Planes& xPlanes, Planes& yPlanes, Planes& z float centerY = float(dims.y) * 0.5; float centerX = float(dims.x) * 0.5; - for (int z = 0; z < zPlanes.size(); z++) { + for (int z = 0; z < (int) zPlanes.size(); z++) { ivec3 pos(0, 0, z); zPlanes[z] = glm::vec4(0.0f, 0.0f, 1.0f, -frustumGrid_clusterPosToEye(pos, vec3(0.0)).z); } - for (int x = 0; x < xPlanes.size(); x++) { + for (int x = 0; x < (int) xPlanes.size(); x++) { auto slicePos = frustumGrid_clusterPosToEye(glm::vec3((float)x, centerY, 0.0)); auto sliceDir = glm::normalize(slicePos); xPlanes[x] = glm::vec4(sliceDir.z, 0.0, -sliceDir.x, 0.0); } - for (int y = 0; y < yPlanes.size(); y++) { + for (int y = 0; y < (int) yPlanes.size(); y++) { auto slicePos = frustumGrid_clusterPosToEye(glm::vec3(centerX, (float)y, 0.0)); auto sliceDir = glm::normalize(slicePos); yPlanes[y] = glm::vec4(0.0, sliceDir.z, -sliceDir.y, 0.0); @@ -177,72 +177,95 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p } float distanceToPlane(const glm::vec3& point, const glm::vec4& plane) { - return glm::dot(plane, glm::vec4(point.x, point.y, point.z, -1.0)); + return plane.x * point.x + plane.y * point.y + plane.z * point.z + plane.w; } -glm::vec4 projectToPlane(glm::vec4& sphere, const glm::vec4& plane) { +bool reduceSphereToPlane(const glm::vec4& sphere, const glm::vec4& plane, glm::vec4& reducedSphere) { float distance = distanceToPlane(glm::vec3(sphere), plane); - if (distance < sphere.w) { - return glm::vec4(sphere.x - distance * plane.x, sphere.y - distance * plane.y, sphere.z - distance * plane.z, sqrt(sphere.w * sphere.w - distance * distance)); - } else { - return sphere; + if (abs(distance) <= sphere.w) { + reducedSphere = glm::vec4(sphere.x - distance * plane.x, sphere.y - distance * plane.y, sphere.z - distance * plane.z, sqrt(sphere.w * sphere.w - distance * distance)); + return true; } + + return false; } -bool scanLightVolume(const FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, - uint32_t& numClustersTouched, uint32_t maxNumIndices, std::vector< std::vector>& clusterGrid) { +uint32_t scanLightVolumeBox(FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, + std::vector< std::vector>& clusterGrid) { glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); + uint32_t numClustersTouched = 0; + for (auto z = zMin; (z <= zMax); z++) { + for (auto y = yMin; (y <= yMax); y++) { + for (auto x = xMin; (x <= xMax); x++) { + auto index = 1 + x + gridPosToOffset.y * y + gridPosToOffset.z * z; + clusterGrid[index].emplace_back(lightId); + numClustersTouched++; + } + } + } + + return numClustersTouched; +} + +uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, + std::vector< std::vector>& clusterGrid) { + glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); + uint32_t numClustersTouched = 0; const auto& xPlanes = planes[0]; const auto& yPlanes = planes[1]; const auto& zPlanes = planes[2]; - int center_z = (zMax + zMin) >> 1; + int center_z = grid.frustumGrid_eyeDepthToClusterLayer(eyePosRadius.z); int center_y = (yMax + yMin) >> 1; - bool hasBudget = true; - for (auto z = zMin; (z <= zMax) && hasBudget; z++) { + for (auto z = zMin; (z <= zMax); z++) { auto zSphere = eyePosRadius; if (z != center_z) { auto& plane = (z < center_z) ? zPlanes[z + 1] : -zPlanes[z]; - zSphere = projectToPlane(zSphere, plane); + if (!reduceSphereToPlane(zSphere, plane, zSphere)) { + // pass this slice! + continue; + } } - for (auto y = yMin; (y <= yMax) && hasBudget; y++) { + for (auto y = yMin; (y <= yMax); y++) { auto ySphere = zSphere; if (y != center_y) { auto& plane = (y < center_y) ? yPlanes[y + 1] : -yPlanes[y]; - ySphere = projectToPlane(ySphere, plane); + if (!reduceSphereToPlane(ySphere, plane, ySphere)) { + // pass this slice! + continue; + } } + glm::vec3 spherePoint(ySphere); + auto x = xMin; for (; (x < xMax); ++x) { auto& plane = xPlanes[x + 1]; - auto testDistance = glm::dot(plane, glm::vec4(ySphere.x, ySphere.y, ySphere.z, -1.0)) + ySphere.w; - if (testDistance >= 0.0f ) { + auto testDistance = distanceToPlane(spherePoint, plane) + ySphere.w; + if (testDistance >= 0.0f) { break; } } auto xs = xMax; for (; (xs >= x); --xs) { auto& plane = -xPlanes[xs]; - auto testDistance = glm::dot(plane, glm::vec4(ySphere.x, ySphere.y, ySphere.z, -1.0)) + ySphere.w; + auto testDistance = distanceToPlane(spherePoint, plane) + ySphere.w; if (testDistance >= 0.0f) { break; } } - for (; (x <= xs) && hasBudget; x++) { - auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; + for (; (x <= xs); x++) { + auto index = grid.frustumGrid_clusterToIndex(ivec3(x, y, z)); clusterGrid[index].emplace_back(lightId); numClustersTouched++; - if (numClustersTouched >= maxNumIndices) { - hasBudget = false; - } } } } - return hasBudget; + return numClustersTouched; } void LightClusters::updateClusters() { @@ -284,7 +307,18 @@ void LightClusters::updateClusters() { int zMin = theFrustumGrid.frustumGrid_eyeDepthToClusterLayer(eyeZMin); int zMax = theFrustumGrid.frustumGrid_eyeDepthToClusterLayer(eyeZMax); // That should never happen - if (zMin == -1 && zMax == -1) { + if (zMin == -2 && zMax == -2) { + continue; + } + + // Firt slice volume ? + /* if (zMin == -1) { + clusterGrid[0].emplace_back(lightId); + numClusterTouched++; + } */ + + // Stop there with this light if zmax is in near range + if (zMax == -1) { continue; } @@ -361,37 +395,31 @@ void LightClusters::updateClusters() { } // now voxelize - bool hasBudget = scanLightVolume(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), numClusterTouched, maxNumIndices, clusterGrid); - - /* bool hasBudget = true; - for (auto z = zMin; (z <= zMax) && hasBudget; z++) { - for (auto y = yMin; (y <= yMax) && hasBudget; y++) { - for (auto x = xMin; (x <= xMax) && hasBudget; x++) { - auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; - clusterGrid[index].emplace_back(lightId); - numClusterTouched++; - if (numClusterTouched >= maxNumIndices) { - hasBudget = false; - } - } - } - }*/ - - if (!hasBudget) { - break; - } + numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); } // Lights have been gathered now reexpress in terms of 2 sequential buffers - + // Start filling from near to far and stops if it overflows + bool checkBudget = false; + if (numClusterTouched > maxNumIndices) { + checkBudget = true; + } uint16_t indexOffset = 0; for (int i = 0; i < clusterGrid.size(); i++) { auto& cluster = clusterGrid[i]; uint16_t numLights = ((uint16_t)cluster.size()); uint16_t offset = indexOffset; + // Check for overflow + if (checkBudget) { + if (indexOffset + numLights > maxNumIndices) { + break; + } + } + _clusterGrid[i] = (uint32_t)((numLights << 16) | offset); + if (numLights) { memcpy(_clusterContent.data() + indexOffset, cluster.data(), numLights * sizeof(LightIndex)); } diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 88583da31e..02ea436718 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -89,7 +89,7 @@ public: LightStage::LightIndices _visibleLightIndices; gpu::BufferView _lightIndicesBuffer; - uint32_t _numClusters { 0 }; + int32_t _numClusters { 0 }; const uint32_t EMPTY_CLUSTER { 0x0000FFFF }; const LightID INVALID_LIGHT { LightStage::INVALID_INDEX }; @@ -124,9 +124,9 @@ public: float rangeNear{ 1.0f }; float rangeFar{ 512.0f }; - int dimX { 8 }; - int dimY { 8 }; - int dimZ { 12 }; + int dimX { 16 }; + int dimY { 16 }; + int dimZ { 16 }; bool freeze{ false }; diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index 616171b775..5bf6a0bf18 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -58,7 +58,7 @@ void main(void) { float numLightsScale = clamp(numLights * 0.1, 0.0, 1.0); - ivec3 clusterPos = clusterGrid_indexToCluster(gl_InstanceID); + ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID); float boxScale = 0.99; vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3((1.0 - boxScale) * 0.5 + (1.0 - numLightsScale) * boxScale * 0.5) + numLightsScale * boxScale * pos.xyz); diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index e711c6fc64..1820d3113b 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -37,7 +37,7 @@ void main(void) { ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); - ivec2 cluster = clusterGrid_getCluster(clusterGrid_clusterToIndex(clusterPos)); + ivec2 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); int numLights = cluster.x; float numLightsScale = clamp(numLights * 0.1, 0.01, 1.0); diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv index fa082d880f..93fd13b2f5 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slv @@ -53,15 +53,7 @@ void main(void) { ); vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - ivec3 dims = frustumGrid.dims.xyz; - - ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); - - int layer = gl_InstanceID / summedDims.x; - int offsetInLayer = gl_InstanceID % summedDims.x; - ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer); - - + ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID); vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz); vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0)); diff --git a/libraries/render-utils/src/lightClusters_drawGrid.slv b/libraries/render-utils/src/lightClusters_drawGrid.slv index 0eec0d04ee..15fa8ac38a 100644 --- a/libraries/render-utils/src/lightClusters_drawGrid.slv +++ b/libraries/render-utils/src/lightClusters_drawGrid.slv @@ -57,7 +57,7 @@ void main(void) { ivec2 cluster = clusterGrid_getCluster(gl_InstanceID); int numLights = cluster.x; - ivec3 clusterPos = clusterGrid_indexToCluster(gl_InstanceID); + ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID); float boxScale = 1.0; diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index 2b8beb67c3..eba65c39af 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -61,7 +61,7 @@ void main(void) { ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); - ivec2 cluster = clusterGrid_getCluster(clusterGrid_clusterToIndex(clusterPos)); + ivec2 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); int numLights = cluster.x; if (numLights <= 0) { discard; From cd9dff57bed1fd48cc1c7c093dc0a5411f9ab680 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 28 Sep 2016 10:03:51 -0700 Subject: [PATCH 040/104] back to normal --- libraries/render-utils/src/LightClusterGrid_shared.slh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 54281d010e..ec27b11a3f 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -78,10 +78,6 @@ int frustumGrid_clusterToIndex(ivec3 pos) { return pos.x + (pos.y + pos.z * frustumGrid.dims.y) * frustumGrid.dims.x; } ivec3 frustumGrid_indexToCluster(int index) { - if (index <= 0) { - return ivec3(0, 0, -1); - } - index -= 1; ivec3 summedDims = ivec3(frustumGrid.dims.x * frustumGrid.dims.y, frustumGrid.dims.x, 1); int layer = index / summedDims.x; int offsetInLayer = index % summedDims.x; From b09151f2a22a5cfcf188cae47e0e9374a73b77eb Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 28 Sep 2016 18:32:35 -0700 Subject: [PATCH 041/104] Rearrange the light struc description in the shader side, needs the c++ to match now --- libraries/model/src/model/Light.h | 38 ++++ libraries/model/src/model/Light.slh | 197 ++++++------------ .../render-utils/src/DeferredGlobalLight.slh | 22 +- libraries/render-utils/src/LightAmbient.slh | 18 +- .../render-utils/src/LightDirectional.slh | 6 +- libraries/render-utils/src/LightPoint.slh | 4 +- libraries/render-utils/src/LightSpot.slh | 6 +- .../render-utils/src/deferred_light_point.slv | 2 +- .../render-utils/src/deferred_light_spot.slv | 2 +- .../render-utils/src/local_lights_shading.slf | 13 +- libraries/render-utils/src/overlay3D.slf | 10 +- .../src/overlay3D_translucent.slf | 10 +- libraries/render-utils/src/point_light.slf | 2 +- 13 files changed, 166 insertions(+), 164 deletions(-) diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index c091026ba2..f1c68bb93a 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -26,8 +26,46 @@ typedef glm::vec3 Vec3; typedef glm::vec4 Vec4; typedef glm::quat Quat; + class Light { public: + + struct LightVolume { + vec3 position; + float radius; + vec3 direction; + float spotCos; + + bool isPoint() { return bool(spotCos < 0.f); } + bool isSpot() { return bool(spotCos >= 0.f); } + + vec3 getPosition() { return position; } + float getRadius() { return radius; } + float getRadiusSquare() { return radius * radius; } + vec3 getDirection() { return direction; } + + float getSpotAngleCos() { return spotCos; } + }; + + + struct LightIrradiance { + vec3 color; + float intensity; + float falloffRadius; + float falloffSpot; + float spare1; + float spare2; + + vec3 getColor() { return color; } + float getIntensity() { return intensity; } + vec3 getIrradiance() { return color * intensity; } + float getFalloffRadius() { return falloffRadius; } + float getFalloffRadiusSquare() { return falloffRadius * falloffRadius; } + float getFalloffSpot() { return falloffSpot; } + }; + + + enum Type { SUN = 0, POINT, diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 888abf5038..6e9f92e67f 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -11,129 +11,74 @@ <@if not MODEL_LIGHT_SLH@> <@def MODEL_LIGHT_SLH@> -struct SphericalHarmonics { - vec4 L00; - vec4 L1m1; - vec4 L10; - vec4 L11; - vec4 L2m2; - vec4 L2m1; - vec4 L20; - vec4 L21; - vec4 L22; -}; +<@include model/SphericalHarmonics.shared.slh@> +<@include model/LightVolume.shared.slh@> +<@include model/LightIrradiance.shared.slh@> -vec4 evalSphericalLight(SphericalHarmonics sh, vec3 direction ) { - - vec3 dir = direction.xyz; - - const float C1 = 0.429043; - const float C2 = 0.511664; - const float C3 = 0.743125; - const float C4 = 0.886227; - const float C5 = 0.247708; - - vec4 value = C1 * sh.L22 * (dir.x * dir.x - dir.y * dir.y) + - C3 * sh.L20 * dir.z * dir.z + - C4 * sh.L00 - C5 * sh.L20 + - 2.0 * C1 * ( sh.L2m2 * dir.x * dir.y + - sh.L21 * dir.x * dir.z + - sh.L2m1 * dir.y * dir.z ) + - 2.0 * C2 * ( sh.L11 * dir.x + - sh.L1m1 * dir.y + - sh.L10 * dir.z ) ; - return value; -} +// NOw lets define Light struct Light { - vec4 _position; - vec4 _direction; - vec4 _color; - vec4 _attenuation; - vec4 _spot; - - // vec4 _shadow; - vec4 _control; - - vec4 _volumeGeometry; - - SphericalHarmonics _ambientSphere; + LightVolume volume; + LightIrradiance irradiance; }; -const int LIGHT_SPOT = 2; - -bool light_isSpot(Light l) { - return bool(l._control.y >= 2.f); -} - -vec3 getLightPosition(Light l) { return l._position.xyz; } -vec3 getLightDirection(Light l) { return l._direction.xyz; } // direction is -Z axis - -vec3 getLightColor(Light l) { return l._color.rgb; } -float getLightIntensity(Light l) { return l._color.w; } -float getLightAmbientIntensity(Light l) { return l._direction.w; } - -float getLightSpotAngleCos(Light l) { - return l._spot.x; -} - -vec2 getLightSpotOutsideNormal2(Light l) { - return vec2(-l._spot.y, l._spot.x); -} - -float evalLightSpotAttenuation(Light l, float cosA) { - return pow(cosA, l._spot.w); -} - -float getLightRadius(Light l) { - return l._attenuation.x; -} - -float getLightSquareRadius(Light l) { - return getLightRadius(l) * getLightRadius(l); -} - -float getLightCutoffRadius(Light l) { - return l._attenuation.z; -} - -float getLightCutoffSquareRadius(Light l) { - return getLightCutoffRadius(l) * getLightCutoffRadius(l); -} - -float getLightShowContour(Light l) { - return l._control.w; -} - -vec4 getLightVolumeGeometry(Light l) { - return l._volumeGeometry; -} // Light is the light source its self, d is the light's distance calculated as length(unnormalized light vector). float evalLightAttenuation(Light l, float d) { - float radius = getLightRadius(l); + float radius = lightIrradiance_getFalloffRadius(l.irradiance); + float cutoff = lightVolume_getRadius(l.volume); float denom = d / radius + 1.0; float attenuation = 1.0 / (denom * denom); - - float cutoff = getLightCutoffRadius(l); - + + // "Fade" the edges of light sources to make things look a bit more attractive. // Note: this tends to look a bit odd at lower exponents. attenuation *= min(1, max(0, -(d - cutoff))); - + return attenuation; } -SphericalHarmonics getLightAmbientSphere(Light l) { + +float evalLightSpotAttenuation(Light l, float cosA) { + return pow(cosA, lightIrradiance_getFalloffSpot(l.irradiance)); +} + +bool light_isSpot(Light l) { return lightVolume_isSpot(l.volume); } + +vec3 getLightPosition(Light l) { return lightVolume_getPosition(l.volume); } +vec3 getLightDirection(Light l) { return lightVolume_getDirection(l.volume); } + + +vec3 getLightColor(Light l) { return lightIrradiance_getColor(l.irradiance); } +float getLightIntensity(Light l) { return lightIrradiance_getIntensity(l.irradiance); } +vec3 getLightIrradiance(Light l) { return lightIrradiance_getIrradiance(l.irradiance); } + + + + + + + +struct LightAmbient { + vec4 _ambient; + SphericalHarmonics _ambientSphere; +}; + +SphericalHarmonics getLightAmbientSphere(LightAmbient l) { return l._ambientSphere; } -bool getLightHasAmbientMap(Light l) { - return l._control.x > 0; + +float getLightAmbientIntensity(LightAmbient l) { return l._ambient.w; } + + +bool getLightHasAmbientMap(LightAmbient l) { + return l._ambient.x > 0; + // return l._control.x > 0; } -float getLightAmbientMapNumMips(Light l) { - return l._control.x; +float getLightAmbientMapNumMips(LightAmbient l) { + return l._ambient.x; } <@func declareLightBuffer(N)@> @@ -146,6 +91,7 @@ uniform lightBuffer { Light getLight(int index) { return lightArray[index]; } + <@else@> uniform lightBuffer { Light light; @@ -161,39 +107,32 @@ Light getLight() { -bool clipFragToLightVolumePoint(Light light, vec3 fragPos, out vec4 fragLightVecLen2) { - fragLightVecLen2.xyz = getLightPosition(light) - fragPos.xyz; - fragLightVecLen2.w = dot(fragLightVecLen2.xyz, fragLightVecLen2.xyz); - // Kill if too far from the light center - if (fragLightVecLen2.w > getLightCutoffSquareRadius(light)) { - return false; - } - return true; + +<@func declareLightAmbientBuffer(N)@> + +<@if N@> + +uniform lightAmbientBuffer { + LightAmbient lightAmbientArray[<$N$>]; +}; + +LightAmbient getLightAmbient(int index) { + return lightAmbientArray[index]; } -bool clipFragToLightVolumeSpot(Light light, vec3 fragPos, out vec4 fragLightVecLen2, out vec4 fragLightDirLen, out float cosSpotAngle) { - fragLightVecLen2.xyz = getLightPosition(light) - fragPos.xyz; - fragLightVecLen2.w = dot(fragLightVecLen2.xyz, fragLightVecLen2.xyz); +<@else@> +uniform lightAmbientBuffer { + LightAmbient lightAmbient; +}; - // Kill if too far from the light center - if (fragLightVecLen2.w > getLightCutoffSquareRadius(light)) { - return false; - } - - // Allright we re valid in the volume - fragLightDirLen.w = length(fragLightVecLen2.xyz); - fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; - - // Kill if not in the spot light (ah ah !) - cosSpotAngle = max(-dot(fragLightDirLen.xyz, getLightDirection(light)), 0.0); - if (cosSpotAngle < getLightSpotAngleCos(light)) { - return false; - } - - return true; +LightAmbient getLightAmbient() { + return lightAmbient; } +<@endif@> + +<@endfunc@> <@endif@> diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index cb5dd9dc48..76194965c1 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -15,6 +15,7 @@ <@include LightingModel.slh@> <$declareLightBuffer()$> +<$declareLightAmbientBuffer()$> <@include LightAmbient.slh@> <@include LightDirectional.slh@> @@ -29,7 +30,11 @@ // Get light Light light = getLight(); + LightAmbient lightAmbient = getLightAmbient(); + vec3 lightDirection = getLightDirection(light); + vec3 lightIrradiance = getLightIrradiance(light); + vec3 color = vec3(0.0); <@endfunc@> @@ -38,7 +43,7 @@ <@func declareEvalAmbientGlobalColor()@> vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float metallic, float roughness) { <$prepareGlobalLight()$> - color += albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(light); + color += albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(lightAmbient); return color; } <@endfunc@> @@ -63,7 +68,7 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness // Ambient vec3 ambientDiffuse; vec3 ambientSpecular; - evalLightingAmbient(ambientDiffuse, ambientSpecular, light, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance + evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance <@if supportScattering@> ,scattering, midNormalCurvature, lowNormalCurvature <@endif@> ); @@ -74,7 +79,7 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness // Directional vec3 directionalDiffuse; vec3 directionalSpecular; - evalLightingDirectional(directionalDiffuse, directionalSpecular, light, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation <@if supportScattering@> ,scattering, midNormalCurvature, lowNormalCurvature <@endif@> ); @@ -107,7 +112,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu // Ambient vec3 ambientDiffuse; vec3 ambientSpecular; - evalLightingAmbient(ambientDiffuse, ambientSpecular, light, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance + evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance <@if supportScattering@> ,scattering, midNormalCurvature, lowNormalCurvature <@endif@> @@ -119,7 +124,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu // Directional vec3 directionalDiffuse; vec3 directionalSpecular; - evalLightingDirectional(directionalDiffuse, directionalSpecular, light, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation <@if supportScattering@> ,scattering, midNormalCurvature, lowNormalCurvature <@endif@> @@ -135,6 +140,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu <@func declareEvalLightmappedColor()@> vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 albedo, vec3 lightmap) { Light light = getLight(); + LightAmbient ambient = getLightAmbient(); // Catch normals perpendicular to the projection plane, hence the magic number for the threshold // It should be just 0, but we have inaccuracy so we overshoot @@ -150,7 +156,7 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur vec3 diffuseLight = lightAttenuation * lightmap; // Ambient light is the lightmap when in shadow - vec3 ambientLight = (1 - lightAttenuation) * lightmap * getLightAmbientIntensity(light); + vec3 ambientLight = (1 - lightAttenuation) * lightmap * getLightAmbientIntensity(ambient); return isLightmapEnabled() * obscurance * albedo * (diffuseLight + ambientLight); } @@ -172,7 +178,7 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl // Ambient vec3 ambientDiffuse; vec3 ambientSpecular; - evalLightingAmbient(ambientDiffuse, ambientSpecular, light, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance); + evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance); color += ambientDiffuse; color += ambientSpecular / opacity; @@ -180,7 +186,7 @@ vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, fl // Directional vec3 directionalDiffuse; vec3 directionalSpecular; - evalLightingDirectional(directionalDiffuse, directionalSpecular, light, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); color += directionalDiffuse; color += directionalSpecular / opacity; diff --git a/libraries/render-utils/src/LightAmbient.slh b/libraries/render-utils/src/LightAmbient.slh index ec665e6deb..ecb8fa0ae5 100644 --- a/libraries/render-utils/src/LightAmbient.slh +++ b/libraries/render-utils/src/LightAmbient.slh @@ -30,16 +30,16 @@ vec3 fresnelSchlickAmbient(vec3 fresnelColor, vec3 lightDir, vec3 halfDir, float <$declareSkyboxMap()$> <@endif@> -vec3 evalAmbientSpecularIrradiance(Light light, vec3 fragEyeDir, vec3 fragNormal, float roughness, vec3 fresnel) { +vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, vec3 fragEyeDir, vec3 fragNormal, float roughness, vec3 fresnel) { vec3 direction = -reflect(fragEyeDir, fragNormal); vec3 ambientFresnel = fresnelSchlickAmbient(fresnel, fragEyeDir, fragNormal, 1 - roughness); vec3 specularLight; <@if supportIfAmbientMapElseAmbientSphere@> - if (getLightHasAmbientMap(light)) + if (getLightHasAmbientMap(ambient)) <@endif@> <@if supportAmbientMap@> { - float levels = getLightAmbientMapNumMips(light); + float levels = getLightAmbientMapNumMips(ambient); float lod = min(floor((roughness)* levels), levels); specularLight = evalSkyboxLight(direction, lod).xyz; } @@ -49,7 +49,7 @@ vec3 evalAmbientSpecularIrradiance(Light light, vec3 fragEyeDir, vec3 fragNormal <@endif@> <@if supportAmbientSphere@> { - specularLight = evalSphericalLight(getLightAmbientSphere(light), direction).xyz; + specularLight = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), direction).xyz; } <@endif@> @@ -67,7 +67,7 @@ float curvatureAO(in float k) { } <@endif@> -void evalLightingAmbient(out vec3 diffuse, out vec3 specular, Light light, vec3 eyeDir, vec3 normal, +void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambient, vec3 eyeDir, vec3 normal, float roughness, float metallic, vec3 fresnel, vec3 albedo, float obscurance <@if supportScattering@> , float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature @@ -76,10 +76,10 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, Light light, vec3 // Diffuse from ambient - diffuse = (1 - metallic) * evalSphericalLight(getLightAmbientSphere(light), normal).xyz; + diffuse = (1 - metallic) * sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), normal).xyz; // Specular highlight from ambient - specular = evalAmbientSpecularIrradiance(light, eyeDir, normal, roughness, fresnel) * obscurance * getLightAmbientIntensity(light); + specular = evalAmbientSpecularIrradiance(ambient, eyeDir, normal, roughness, fresnel) * obscurance * getLightAmbientIntensity(ambient); <@if supportScattering@> @@ -92,7 +92,7 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, Light light, vec3 if (scattering * isScatteringEnabled() > 0.0) { // Diffuse from ambient - diffuse = evalSphericalLight(getLightAmbientSphere(light), lowNormalCurvature.xyz).xyz; + diffuse = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), lowNormalCurvature.xyz).xyz; specular = vec3(0.0); } @@ -102,7 +102,7 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, Light light, vec3 obscurance = 1.0; } - float lightEnergy = obscurance * getLightAmbientIntensity(light); + float lightEnergy = obscurance * getLightAmbientIntensity(ambient); if (isAlbedoEnabled() > 0.0) { diffuse *= albedo; diff --git a/libraries/render-utils/src/LightDirectional.slh b/libraries/render-utils/src/LightDirectional.slh index 86eb130491..749709c600 100644 --- a/libraries/render-utils/src/LightDirectional.slh +++ b/libraries/render-utils/src/LightDirectional.slh @@ -11,7 +11,7 @@ <@func declareLightingDirectional(supportScattering)@> -void evalLightingDirectional(out vec3 diffuse, out vec3 specular, Light light, +void evalLightingDirectional(out vec3 diffuse, out vec3 specular, vec3 lightDir, vec3 lightIrradiance, vec3 eyeDir, vec3 normal, float roughness, float metallic, vec3 fresnel, vec3 albedo, float shadow <@if supportScattering@> @@ -20,9 +20,9 @@ void evalLightingDirectional(out vec3 diffuse, out vec3 specular, Light light, ) { // Attenuation - vec3 lightEnergy = shadow * getLightColor(light) * getLightIntensity(light); + vec3 lightEnergy = shadow * lightIrradiance; - evalFragShading(diffuse, specular, normal, -getLightDirection(light), eyeDir, metallic, fresnel, roughness, albedo + evalFragShading(diffuse, specular, normal, -lightDir, eyeDir, metallic, fresnel, roughness, albedo <@if supportScattering@> ,scattering, midNormalCurvature, lowNormalCurvature <@endif@> diff --git a/libraries/render-utils/src/LightPoint.slh b/libraries/render-utils/src/LightPoint.slh index 767a96fb51..b120df584a 100644 --- a/libraries/render-utils/src/LightPoint.slh +++ b/libraries/render-utils/src/LightPoint.slh @@ -25,7 +25,7 @@ void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light, // Eval attenuation float radialAttenuation = evalLightAttenuation(light, fragLightDistance); - vec3 lightEnergy = radialAttenuation * shadow * getLightColor(light) * getLightIntensity(light); + vec3 lightEnergy = radialAttenuation * shadow * getLightIrradiance(light); // Eval shading evalFragShading(diffuse, specular, normal, fragLightDir, fragEyeDir, metallic, fresnel, roughness, albedo @@ -39,7 +39,7 @@ void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light, if (isShowLightContour() > 0.0) { // Show edge - float edge = abs(2.0 * ((getLightCutoffRadius(light) - fragLightDistance) / (0.1)) - 1.0); + float edge = abs(2.0 * ((lightVolume_getRadius(light.volume) - fragLightDistance) / (0.1)) - 1.0); if (edge < 1) { float edgeCoord = exp2(-8.0*edge*edge); diffuse = vec3(edgeCoord * edgeCoord * getLightColor(light)); diff --git a/libraries/render-utils/src/LightSpot.slh b/libraries/render-utils/src/LightSpot.slh index 65a417110a..3a04c28bfb 100644 --- a/libraries/render-utils/src/LightSpot.slh +++ b/libraries/render-utils/src/LightSpot.slh @@ -26,7 +26,7 @@ void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light, // Eval attenuation float radialAttenuation = evalLightAttenuation(light, fragLightDistance); float angularAttenuation = evalLightSpotAttenuation(light, cosSpotAngle); - vec3 lightEnergy = angularAttenuation * radialAttenuation * shadow * getLightColor(light) * getLightIntensity(light); + vec3 lightEnergy = angularAttenuation * radialAttenuation * shadow *getLightIrradiance(light); // Eval shading evalFragShading(diffuse, specular, normal, fragLightDir, fragEyeDir, metallic, fresnel, roughness, albedo @@ -40,8 +40,8 @@ void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light, if (isShowLightContour() > 0.0) { // Show edges - float edgeDistR = (getLightCutoffRadius(light) - fragLightDistance); - float edgeDistS = dot(fragLightDistance * vec2(cosSpotAngle, sqrt(1.0 - cosSpotAngle * cosSpotAngle)), -getLightSpotOutsideNormal2(light)); + float edgeDistR = (lightVolume_getRadius(light.volume) - fragLightDistance); + float edgeDistS = dot(fragLightDistance * vec2(cosSpotAngle, sqrt(1.0 - cosSpotAngle * cosSpotAngle)), -lightVolume_getSpotOutsideNormal2(light.volume)); float edgeDist = min(edgeDistR, edgeDistS); float edge = abs(2.0 * (edgeDist / (0.1)) - 1.0); if (edge < 1) { diff --git a/libraries/render-utils/src/deferred_light_point.slv b/libraries/render-utils/src/deferred_light_point.slv index 6bdc6fe42f..f126ee9251 100644 --- a/libraries/render-utils/src/deferred_light_point.slv +++ b/libraries/render-utils/src/deferred_light_point.slv @@ -34,7 +34,7 @@ void main(void) { Light light = getLight(instanceID); vec4 sphereVertex = inPosition; vec3 lightOrigin = getLightPosition(light); - vec4 sphereParam = getLightVolumeGeometry(light); + vec4 sphereParam = vec4(1.0); // = getLightVolumeGeometry(light); sphereVertex.xyz *= sphereParam.w; diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index c120fa28b1..5edd889704 100755 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -31,7 +31,7 @@ void main(void) { int instanceID = lightIndex[gl_InstanceID]; Light light = getLight(instanceID); vec3 lightPos = getLightPosition(light); - vec4 coneParam = getLightVolumeGeometry(light); + vec4 coneParam = vec4(1.0); // = getLightVolumeGeometry(light); if(coneVertex.z >= 0.0) { // Evaluate the true position of the spot volume diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index eba65c39af..8cf817b127 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -94,7 +94,14 @@ void main(void) { vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - // int numLights = lightIndex[0]; + + /* int theLightIndex = clusterGrid_getClusterLightId(0, cluster); + if (theLightIndex == 65535) { + discard; + } + Light light = getLight(theLightIndex); + + int numLights = lightIndex[0];*/ for (int i = 0; i < numLights; i++) { // Need the light now int theLightIndex = clusterGrid_getClusterLightId(i, cluster); @@ -105,11 +112,11 @@ void main(void) { vec4 fragLightDirLen; float cosSpotAngle; if (isSpot) { - if (!clipFragToLightVolumeSpot(light, fragPos.xyz, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) { + if (!lightVolume_clipFragToLightVolumeSpot(light.volume, fragPos.xyz, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) { continue; } } else { - if (!clipFragToLightVolumePoint(light, fragPos.xyz, fragLightVecLen2)) { + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { continue; } } diff --git a/libraries/render-utils/src/overlay3D.slf b/libraries/render-utils/src/overlay3D.slf index 1a629dedf1..0cb3340845 100644 --- a/libraries/render-utils/src/overlay3D.slf +++ b/libraries/render-utils/src/overlay3D.slf @@ -14,6 +14,7 @@ <@include model/Light.slh@> <$declareLightBuffer()$> +<$declareLightAmbientBuffer()$> <@include LightingModel.slh@> @@ -27,6 +28,11 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 a // Need the light now Light light = getLight(); + vec3 lightDirection = getLightDirection(light); + vec3 lightIrradiance = getLightIrradiance(light); + + LightAmbient ambient = getLightAmbient(); + TransformCamera cam = getTransformCamera(); vec3 fragNormal; <$transformEyeToWorldDir(cam, normal, fragNormal)$> @@ -34,12 +40,12 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 a vec3 fragEyeDir; <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> - vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(light); + vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(ambient); // Directional vec3 directionalDiffuse; vec3 directionalSpecular; - evalLightingDirectional(directionalDiffuse, directionalSpecular, light, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); color += directionalDiffuse * isDiffuseEnabled() * isDirectionalEnabled(); color += directionalSpecular * isSpecularEnabled() * isDirectionalEnabled(); diff --git a/libraries/render-utils/src/overlay3D_translucent.slf b/libraries/render-utils/src/overlay3D_translucent.slf index f45aa897f9..9bdac2d21f 100644 --- a/libraries/render-utils/src/overlay3D_translucent.slf +++ b/libraries/render-utils/src/overlay3D_translucent.slf @@ -14,6 +14,7 @@ <@include model/Light.slh@> <$declareLightBuffer()$> +<$declareLightAmbientBuffer()$> <@include LightingModel.slh@> @@ -27,6 +28,11 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 a // Need the light now Light light = getLight(); + vec3 lightDirection = getLightDirection(light); + vec3 lightIrradiance = getLightIrradiance(light); + + LightAmbient ambient = getLightAmbient(); + TransformCamera cam = getTransformCamera(); vec3 fragNormal; <$transformEyeToWorldDir(cam, normal, fragNormal)$> @@ -34,12 +40,12 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 a vec3 fragEyeDir; <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> - vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(light); + vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(ambient); // Directional vec3 directionalDiffuse; vec3 directionalSpecular; - evalLightingDirectional(directionalDiffuse, directionalSpecular, light, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); + evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation); color += directionalDiffuse; color += directionalSpecular / opacity; diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index 239cbd5c91..e646db5069 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -58,7 +58,7 @@ void main(void) { // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space vec4 fragLightVecLen2; - if (!clipFragToLightVolumePoint(light, fragPos.xyz, fragLightVecLen2)) { + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { discard; } From bb5493106fbdba409645fbdf9a75fdbc242f79b8 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 28 Sep 2016 18:33:34 -0700 Subject: [PATCH 042/104] smaller struct descriptions --- .../src/model/LightIrradiance.shared.slh | 39 ++++++++++ .../model/src/model/LightVolume.shared.slh | 75 +++++++++++++++++++ .../src/model/SphericalHarmonics.shared.slh | 57 ++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 libraries/model/src/model/LightIrradiance.shared.slh create mode 100644 libraries/model/src/model/LightVolume.shared.slh create mode 100644 libraries/model/src/model/SphericalHarmonics.shared.slh diff --git a/libraries/model/src/model/LightIrradiance.shared.slh b/libraries/model/src/model/LightIrradiance.shared.slh new file mode 100644 index 0000000000..5068f71480 --- /dev/null +++ b/libraries/model/src/model/LightIrradiance.shared.slh @@ -0,0 +1,39 @@ +// glsl / C++ compatible source as interface for Light +#ifndef LightIrradiance_Shared_slh +#define LightIrradiance_Shared_slh + +// +// Created by Sam Gateau on 14/9/2016. +// Copyright 2014 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 +// + + +#define LightIrradianceConstRef LightIrradiance + +struct LightIrradiance { + vec3 color; + float intensity; + float falloffRadius; + float falloffSpot; + float spare1; + float spare2; +}; + + +vec3 lightIrradiance_getColor(LightIrradianceConstRef li) { return li.color; } +float lightIrradiance_getIntensity(LightIrradianceConstRef li) { return li.intensity; } +vec3 lightIrradiance_getIrradiance(LightIrradianceConstRef li) { return li.color * li.intensity; } +float lightIrradiance_getFalloffRadius(LightIrradianceConstRef li) { return li.falloffRadius; } +float lightIrradiance_getFalloffRadiusSquare(LightIrradianceConstRef li) { return li.falloffRadius * li.falloffRadius; } +float lightIrradiance_getFalloffSpot(LightIrradianceConstRef li) { return li.falloffSpot; } + + +#endif + + +// <@if 1@> +// Trigger Scribe include +// <@endif@> \ No newline at end of file diff --git a/libraries/model/src/model/LightVolume.shared.slh b/libraries/model/src/model/LightVolume.shared.slh new file mode 100644 index 0000000000..1ca32bd90e --- /dev/null +++ b/libraries/model/src/model/LightVolume.shared.slh @@ -0,0 +1,75 @@ +// glsl / C++ compatible source as interface for Light +#ifndef LightVolume_Shared_slh +#define LightVolume_Shared_slh + +// Light.shared.slh +// libraries/model/src/model +// +// Created by Sam Gateau on 14/9/2016. +// Copyright 2014 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 +// + + +#define LightVolumeConstRef LightVolume + +struct LightVolume { + vec3 position; + float radius; + vec3 direction; + float spotCos; +}; + +bool lightVolume_isPoint(LightVolumeConstRef lv) { return bool(lv.spotCos < 0.f); } +bool lightVolume_isSpot(LightVolumeConstRef lv) { return bool(lv.spotCos >= 0.f); } + +vec3 lightVolume_getPosition(LightVolumeConstRef lv) { return lv.position; } +float lightVolume_getRadius(LightVolumeConstRef lv) { return lv.radius; } +float lightVolume_getRadiusSquare(LightVolumeConstRef lv) { return lv.radius * lv.radius; } +vec3 lightVolume_getDirection(LightVolumeConstRef lv) { return lv.direction; } // direction is -Z axis + +float lightVolume_getSpotAngleCos(LightVolumeConstRef lv) { return lv.spotCos; } +vec2 lightVolume_getSpotOutsideNormal2(LightVolumeConstRef lv) { return vec2(-sqrt(1.0 - lv.spotCos * lv.spotCos), lv.spotCos); } + + +bool lightVolume_clipFragToLightVolumePoint(LightVolume lv, vec3 fragPos, vec4 fragLightVecLen2) { + fragLightVecLen2 = vec4(lightVolume_getPosition(lv) - fragPos.xyz, 1.0f); + fragLightVecLen2.w = dot(fragLightVecLen2.xyz, fragLightVecLen2.xyz); + + // Kill if too far from the light center + if (fragLightVecLen2.w > lightVolume_getRadiusSquare(lv)) { + return false; + } + return true; +} + +bool lightVolume_clipFragToLightVolumeSpot(LightVolume lv, vec3 fragPos, vec4 fragLightVecLen2, vec4 fragLightDirLen, float cosSpotAngle) { + fragLightVecLen2 = vec4(lightVolume_getPosition(lv) - fragPos.xyz, 1.0f); + fragLightVecLen2.w = dot(fragLightVecLen2.xyz, fragLightVecLen2.xyz); + + // Kill if too far from the light center + if (fragLightVecLen2.w > lightVolume_getRadiusSquare(lv)) { + return false; + } + + // Allright we re valid in the volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + + // Kill if not in the spot light (ah ah !) + cosSpotAngle = max(-dot(fragLightDirLen.xyz, lightVolume_getDirection(lv)), 0.0); + if (cosSpotAngle < lightVolume_getSpotAngleCos(lv)) { + return false; + } + + return true; +} + +#endif + + +// <@if 1@> +// Trigger Scribe include +// <@endif@> \ No newline at end of file diff --git a/libraries/model/src/model/SphericalHarmonics.shared.slh b/libraries/model/src/model/SphericalHarmonics.shared.slh new file mode 100644 index 0000000000..664c9e52db --- /dev/null +++ b/libraries/model/src/model/SphericalHarmonics.shared.slh @@ -0,0 +1,57 @@ +// glsl / C++ compatible source as interface for Light +#ifndef SphericalHarmonics_Shared_slh +#define SphericalHarmonics_Shared_slh + +// SphericalHarmonics.shared.slh +// libraries/model/src/model +// +// Created by Sam Gateau on 14/9/2016. +// Copyright 2014 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 +// + + +#define SphericalHarmonicsConstRef SphericalHarmonics + +struct SphericalHarmonics { + vec4 L00; + vec4 L1m1; + vec4 L10; + vec4 L11; + vec4 L2m2; + vec4 L2m1; + vec4 L20; + vec4 L21; + vec4 L22; +}; + +vec4 sphericalHarmonics_evalSphericalLight(SphericalHarmonicsConstRef sh, vec3 direction) { + + vec3 dir = direction.xyz; + + const float C1 = 0.429043; + const float C2 = 0.511664; + const float C3 = 0.743125; + const float C4 = 0.886227; + const float C5 = 0.247708; + + vec4 value = C1 * sh.L22 * (dir.x * dir.x - dir.y * dir.y) + + C3 * sh.L20 * dir.z * dir.z + + C4 * sh.L00 - C5 * sh.L20 + + 2.0 * C1 * (sh.L2m2 * dir.x * dir.y + + sh.L21 * dir.x * dir.z + + sh.L2m1 * dir.y * dir.z) + + 2.0 * C2 * (sh.L11 * dir.x + + sh.L1m1 * dir.y + + sh.L10 * dir.z); + return value; +} + +#endif + + +// <@if 1@> +// Trigger Scribe include +// <@endif@> End C++ compatible \ No newline at end of file From 2a0e67ee2a84e4cae2df5d6c4c0ffa1a40e8d8f2 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 29 Sep 2016 19:06:26 -0700 Subject: [PATCH 043/104] REvisiting the full lighting code to optimize the perf --- libraries/audio/src/AudioInjector.cpp | 2 +- libraries/model/src/model/Light.cpp | 67 ++++++----- libraries/model/src/model/Light.h | 107 +++++++++++------- libraries/model/src/model/Light.slh | 20 ---- .../src/model/LightIrradiance.shared.slh | 42 +++++-- .../model/src/model/LightVolume.shared.slh | 46 ++++---- .../src/DeferredLightingEffect.cpp | 4 +- .../render-utils/src/LightClusterGrid.slh | 6 +- libraries/render-utils/src/LightClusters.cpp | 4 +- libraries/render-utils/src/LightClusters.h | 2 +- libraries/render-utils/src/LightPoint.slh | 2 +- libraries/render-utils/src/LightSpot.slh | 5 +- libraries/render-utils/src/LightStage.cpp | 8 +- .../render-utils/src/SubsurfaceScattering.cpp | 2 +- .../render-utils/src/local_lights_shading.slf | 37 +++--- 15 files changed, 186 insertions(+), 168 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 43701a51d8..95cb3c9fb3 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -26,7 +26,7 @@ #include "SoundCache.h" #include "AudioSRC.h" -int audioInjectorPtrMetaTypeId = qRegisterMetaType(); +//int audioInjectorPtrMetaTypeId = qRegisterMetaType(); AbstractAudioInterface* AudioInjector::_localAudioInterface{ nullptr }; diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index c073e397dd..449054c9b2 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -13,22 +13,19 @@ using namespace model; Light::Light() { - // only if created from nothing shall we create the Buffer to store the properties - Schema schema; - _schemaBuffer = std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema); updateLightRadius(); } Light::Light(const Light& light) : _flags(light._flags), - _schemaBuffer(light._schemaBuffer), _transform(light._transform) { } Light& Light::operator= (const Light& light) { _flags = (light._flags); - _schemaBuffer = (light._schemaBuffer); + _lightSchemaBuffer = (light._lightSchemaBuffer); + _ambientSchemaBuffer = (light._ambientSchemaBuffer); _transform = (light._transform); return (*this); @@ -38,15 +35,22 @@ Light::~Light() { } void Light::setType(Type type) { - editSchema()._control.x = float(type); - updateLightRadius(); + if (_type != type) { + _type = type; + if (type != SPOT) { + _lightSchemaBuffer.edit().volume.spotCos = -1.f; + } else { + _lightSchemaBuffer.edit().volume.spotCos = _spotCos; + } + updateLightRadius(); + } updateVolumeGeometry(); } void Light::setPosition(const Vec3& position) { _transform.setTranslation(position); - editSchema()._position = Vec4(position, 1.f); + _lightSchemaBuffer.edit().volume.position = position; } void Light::setOrientation(const glm::quat& orientation) { @@ -55,39 +59,35 @@ void Light::setOrientation(const glm::quat& orientation) { } void Light::setDirection(const Vec3& direction) { - editSchema()._direction = glm::normalize(direction); + _lightSchemaBuffer.edit().volume.direction = (direction); } const Vec3& Light::getDirection() const { - return getSchema()._direction; + return _lightSchemaBuffer->volume.direction; } void Light::setColor(const Color& color) { - editSchema()._color = color; + _lightSchemaBuffer.edit().irradiance.color = color; updateLightRadius(); } void Light::setIntensity(float intensity) { - editSchema()._intensity = intensity; + _lightSchemaBuffer.edit().irradiance.intensity = intensity; updateLightRadius(); } -void Light::setAmbientIntensity(float intensity) { - editSchema()._ambientIntensity = intensity; -} - void Light::setFalloffRadius(float radius) { if (radius <= 0.0f) { radius = 0.1f; } - editSchema()._attenuation.x = radius; + _lightSchemaBuffer.edit().irradiance.falloffRadius = radius; updateLightRadius(); } void Light::setMaximumRadius(float radius) { if (radius <= 0.f) { radius = 1.0f; } - editSchema()._attenuation.y = radius; + _lightSchemaBuffer.edit().volume.radius = radius; updateLightRadius(); updateVolumeGeometry(); } @@ -106,7 +106,7 @@ void Light::updateLightRadius() { float cutoffRadius = getFalloffRadius() * ((glm::sqrt(intensity / MIN_CUTOFF_INTENSITY) - 1) - 1); // If it is less than max radius, store it to buffer to avoid extra shading - editSchema()._attenuation.z = std::min(getMaximumRadius(), cutoffRadius); + _lightSchemaBuffer.edit().irradiance.cutoffRadius = std::min(getMaximumRadius(), cutoffRadius); } #include @@ -119,12 +119,13 @@ void Light::setSpotAngle(float angle) { if (dangle > glm::half_pi()) { dangle = glm::half_pi(); } - auto cosAngle = cos(dangle); auto sinAngle = sin(dangle); - editSchema()._spot.x = (float) std::abs(cosAngle); - editSchema()._spot.y = (float) std::abs(sinAngle); - editSchema()._spot.z = (float) angle; + _spotCos = (float)std::abs(cosAngle); + + if (isSpot()) { + _lightSchemaBuffer.edit().volume.spotCos = _spotCos; + } updateVolumeGeometry(); } @@ -133,22 +134,20 @@ void Light::setSpotExponent(float exponent) { if (exponent <= 0.f) { exponent = 0.0f; } - editSchema()._spot.w = exponent; + _lightSchemaBuffer.edit().irradiance.falloffSpot = exponent; } -void Light::setShowContour(float show) { - if (show <= 0.f) { - show = 0.0f; - } - editSchema()._control.z = show; + +void Light::setAmbientIntensity(float intensity) { + _ambientSchemaBuffer.edit().intensity = intensity; } void Light::setAmbientSphere(const gpu::SphericalHarmonics& sphere) { - editSchema()._ambientSphere = sphere; + _ambientSchemaBuffer.edit().ambientSphere = sphere; } void Light::setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset) { - editSchema()._ambientSphere.assignPreset(preset); + _ambientSchemaBuffer.edit().ambientSphere.assignPreset(preset); } void Light::setAmbientMap(gpu::TexturePointer ambientMap) { @@ -161,17 +160,17 @@ void Light::setAmbientMap(gpu::TexturePointer ambientMap) { } void Light::setAmbientMapNumMips(uint16_t numMips) { - editSchema()._ambientMapNumMips = (float)numMips; + _ambientSchemaBuffer.edit().mapNumMips = (float)numMips; } void Light::updateVolumeGeometry() { // enlarge the scales slightly to account for tesselation - const float SCALE_EXPANSION = 0.05f; + /* const float SCALE_EXPANSION = 0.05f; glm::vec4 volumeGeometry(0.0f, 0.0f, 0.0f, getMaximumRadius() * (1.0f + SCALE_EXPANSION)); if (getType() == SPOT) { const float TANGENT_LENGTH_SCALE = 0.666f; volumeGeometry = glm::vec4(getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * getSpotAngle()), volumeGeometry.w); } - editSchema()._volumeGeometry = volumeGeometry; + editSchema()._volumeGeometry = volumeGeometry;*/ } diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index f1c68bb93a..893467866a 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -31,37 +31,38 @@ class Light { public: struct LightVolume { - vec3 position; - float radius; - vec3 direction; - float spotCos; + vec3 position { 0.f }; + float radius { 1.0f }; + vec3 direction { 0.f, 0.f, -1.f }; + float spotCos { -1.f }; - bool isPoint() { return bool(spotCos < 0.f); } - bool isSpot() { return bool(spotCos >= 0.f); } + bool isPoint() const { return bool(spotCos < 0.f); } + bool isSpot() const { return bool(spotCos >= 0.f); } - vec3 getPosition() { return position; } - float getRadius() { return radius; } - float getRadiusSquare() { return radius * radius; } - vec3 getDirection() { return direction; } + vec3 getPosition() const { return position; } + float getRadius() const { return radius; } + float getRadiusSquare() const { return radius * radius; } + vec3 getDirection() const { return direction; } - float getSpotAngleCos() { return spotCos; } + float getSpotAngleCos() const { return spotCos; } + vec2 getSpotAngleCosSin() const { return vec2(spotCos, sqrt(1.f - spotCos * spotCos)); } }; struct LightIrradiance { - vec3 color; - float intensity; - float falloffRadius; - float falloffSpot; + vec3 color { 1.f }; + float intensity { 1.f }; + float falloffRadius { 0.1f }; + float cutoffRadius { 0.1f }; + float falloffSpot { 1.f }; float spare1; - float spare2; - vec3 getColor() { return color; } - float getIntensity() { return intensity; } - vec3 getIrradiance() { return color * intensity; } - float getFalloffRadius() { return falloffRadius; } - float getFalloffRadiusSquare() { return falloffRadius * falloffRadius; } - float getFalloffSpot() { return falloffSpot; } + vec3 getColor() const { return color; } + float getIntensity() const { return intensity; } + vec3 getIrradiance() const { return color * intensity; } + float getFalloffRadius() const { return falloffRadius; } + float getCutoffRadius() const { return cutoffRadius; } + float getFalloffSpot() const { return falloffSpot; } }; @@ -93,7 +94,7 @@ public: virtual ~Light(); void setType(Type type); - Type getType() const { return Type((int) getSchema()._control.x); } + Type getType() const { return _type; } void setPosition(const Vec3& position); const Vec3& getPosition() const { return _transform.getTranslation(); } @@ -104,10 +105,10 @@ public: void setOrientation(const Quat& orientation); const glm::quat& getOrientation() const { return _transform.getRotation(); } - const Color& getColor() const { return getSchema()._color; } + const Color& getColor() const { return _lightSchemaBuffer->irradiance.color; } void setColor(const Color& color); - float getIntensity() const { return getSchema()._intensity; } + float getIntensity() const { return _lightSchemaBuffer->irradiance.intensity; } void setIntensity(float intensity); bool isRanged() const { return (getType() == POINT) || (getType() == SPOT ); } @@ -116,44 +117,58 @@ public: // expressed in meters. It is used only to calculate the falloff curve of the light. // Actual rendered lights will all have surface radii approaching 0. void setFalloffRadius(float radius); - float getFalloffRadius() const { return getSchema()._attenuation.x; } + float getFalloffRadius() const { return _lightSchemaBuffer->irradiance.falloffRadius; } // Maximum radius is the cutoff radius of the light energy, expressed in meters. // It is used to bound light entities, and *will not* affect the falloff curve of the light. // Setting it low will result in a noticeable cutoff. void setMaximumRadius(float radius); - float getMaximumRadius() const { return getSchema()._attenuation.y; } + float getMaximumRadius() const { return _lightSchemaBuffer->volume.radius; } // Spot properties bool isSpot() const { return getType() == SPOT; } void setSpotAngle(float angle); - float getSpotAngle() const { return getSchema()._spot.z; } - glm::vec2 getSpotAngleCosSin() const { return glm::vec2(getSchema()._spot.x, getSchema()._spot.y); } + float getSpotAngle() const { return acos(_lightSchemaBuffer->volume.getSpotAngleCos()); } + glm::vec2 getSpotAngleCosSin() const { return _lightSchemaBuffer->volume.getSpotAngleCosSin(); } void setSpotExponent(float exponent); - float getSpotExponent() const { return getSchema()._spot.w; } - - // For editing purpose, show the light volume contour. - // Set to non 0 to show it, the value is used as the intensity of the contour color - void setShowContour(float show); - float getShowContour() const { return getSchema()._control.z; } + float getSpotExponent() const { return _lightSchemaBuffer->irradiance.falloffSpot; } // If the light has an ambient (Indirect) component, then the Ambientintensity can be used to control its contribution to the lighting void setAmbientIntensity(float intensity); - float getAmbientIntensity() const { return getSchema()._ambientIntensity; } + float getAmbientIntensity() const { return _ambientSchemaBuffer->intensity; } // Spherical Harmonics storing the Ambient lighting approximation used for the Sun typed light void setAmbientSphere(const gpu::SphericalHarmonics& sphere); - const gpu::SphericalHarmonics& getAmbientSphere() const { return getSchema()._ambientSphere; } + const gpu::SphericalHarmonics& getAmbientSphere() const { return _ambientSchemaBuffer->ambientSphere; } void setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset); void setAmbientMap(gpu::TexturePointer ambientMap); gpu::TexturePointer getAmbientMap() const { return _ambientMap; } void setAmbientMapNumMips(uint16_t numMips); - uint16_t getAmbientMapNumMips() const { return (uint16_t) getSchema()._ambientMapNumMips; } + uint16_t getAmbientMapNumMips() const { return (uint16_t) _ambientSchemaBuffer->mapNumMips; } + + // LIght Schema + class LightSchema { + public: + LightVolume volume; + LightIrradiance irradiance; + }; + + class AmbientSchema { + public: + float intensity { 0.f }; + float mapNumMips { 0.f }; + float spare1; + float spare2; + gpu::SphericalHarmonics ambientSphere; + }; + + using LightSchemaBuffer = gpu::StructBuffer; + using AmbientSchemaBuffer = gpu::StructBuffer; // Schema to access the attribute values of the light - class Schema { + /* class Schema { public: Vec4 _position{0.0f, 0.0f, 0.0f, 1.0f}; Vec3 _direction{0.0f, 0.0f, -1.0f}; @@ -172,19 +187,23 @@ public: gpu::SphericalHarmonics _ambientSphere; }; - - const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } + */ + const LightSchemaBuffer& getLightSchemaBuffer() const { return _lightSchemaBuffer; } + const AmbientSchemaBuffer& getAmbientSchemaBuffer() const { return _ambientSchemaBuffer; } protected: Flags _flags{ 0 }; - UniformBufferView _schemaBuffer; + + LightSchemaBuffer _lightSchemaBuffer; + AmbientSchemaBuffer _ambientSchemaBuffer; + Transform _transform; gpu::TexturePointer _ambientMap; - const Schema& getSchema() const { return _schemaBuffer.get(); } - Schema& editSchema() { return _schemaBuffer.edit(); } + Type _type { SUN }; + float _spotCos { -1.0f }; // stored here to be able to reset the spot angle when turning the type spot on/off void updateLightRadius(); void updateVolumeGeometry(); diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 6e9f92e67f..78fa11416d 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -23,26 +23,6 @@ struct Light { LightIrradiance irradiance; }; -// Light is the light source its self, d is the light's distance calculated as length(unnormalized light vector). -float evalLightAttenuation(Light l, float d) { - float radius = lightIrradiance_getFalloffRadius(l.irradiance); - float cutoff = lightVolume_getRadius(l.volume); - float denom = d / radius + 1.0; - float attenuation = 1.0 / (denom * denom); - - - // "Fade" the edges of light sources to make things look a bit more attractive. - // Note: this tends to look a bit odd at lower exponents. - attenuation *= min(1, max(0, -(d - cutoff))); - - return attenuation; -} - - -float evalLightSpotAttenuation(Light l, float cosA) { - return pow(cosA, lightIrradiance_getFalloffSpot(l.irradiance)); -} - bool light_isSpot(Light l) { return lightVolume_isSpot(l.volume); } vec3 getLightPosition(Light l) { return lightVolume_getPosition(l.volume); } diff --git a/libraries/model/src/model/LightIrradiance.shared.slh b/libraries/model/src/model/LightIrradiance.shared.slh index 5068f71480..eaa1b33a88 100644 --- a/libraries/model/src/model/LightIrradiance.shared.slh +++ b/libraries/model/src/model/LightIrradiance.shared.slh @@ -14,21 +14,39 @@ #define LightIrradianceConstRef LightIrradiance struct LightIrradiance { - vec3 color; - float intensity; - float falloffRadius; - float falloffSpot; - float spare1; - float spare2; + vec4 colorIntensity; + // falloffRadius, cutoffRadius, falloffSpot, spare + vec4 attenuation; }; -vec3 lightIrradiance_getColor(LightIrradianceConstRef li) { return li.color; } -float lightIrradiance_getIntensity(LightIrradianceConstRef li) { return li.intensity; } -vec3 lightIrradiance_getIrradiance(LightIrradianceConstRef li) { return li.color * li.intensity; } -float lightIrradiance_getFalloffRadius(LightIrradianceConstRef li) { return li.falloffRadius; } -float lightIrradiance_getFalloffRadiusSquare(LightIrradianceConstRef li) { return li.falloffRadius * li.falloffRadius; } -float lightIrradiance_getFalloffSpot(LightIrradianceConstRef li) { return li.falloffSpot; } +vec3 lightIrradiance_getColor(LightIrradiance li) { return li.colorIntensity.xyz; } +float lightIrradiance_getIntensity(LightIrradiance li) { return li.colorIntensity.w; } +vec3 lightIrradiance_getIrradiance(LightIrradiance li) { return li.colorIntensity.xyz * li.colorIntensity.w; } +float lightIrradiance_getFalloffRadius(LightIrradiance li) { return li.attenuation.x; } +float lightIrradiance_getCutoffRadius(LightIrradiance li) { return li.attenuation.y; } +float lightIrradiance_getFalloffSpot(LightIrradiance li) { return li.attenuation.z; } + + +// Light is the light source its self, d is the light's distance calculated as length(unnormalized light vector). +float lightIrradiance_evalLightAttenuation(LightIrradiance li, float d) { + float radius = lightIrradiance_getFalloffRadius(li); + float cutoff = lightIrradiance_getCutoffRadius(li); + float denom = d / radius + 1.0; + float attenuation = 1.0 / (denom * denom); + + + // "Fade" the edges of light sources to make things look a bit more attractive. + // Note: this tends to look a bit odd at lower exponents. + attenuation *= min(1, max(0, -(d - cutoff))); + + return attenuation; +} + + +float lightIrradiance_evalLightSpotAttenuation(LightIrradiance li, float cosA) { + return pow(cosA, lightIrradiance_getFalloffSpot(li)); +} #endif diff --git a/libraries/model/src/model/LightVolume.shared.slh b/libraries/model/src/model/LightVolume.shared.slh index 1ca32bd90e..ac75308c18 100644 --- a/libraries/model/src/model/LightVolume.shared.slh +++ b/libraries/model/src/model/LightVolume.shared.slh @@ -16,37 +16,33 @@ #define LightVolumeConstRef LightVolume struct LightVolume { - vec3 position; - float radius; - vec3 direction; - float spotCos; + vec4 positionRadius; + vec4 directionSpotCos; }; -bool lightVolume_isPoint(LightVolumeConstRef lv) { return bool(lv.spotCos < 0.f); } -bool lightVolume_isSpot(LightVolumeConstRef lv) { return bool(lv.spotCos >= 0.f); } +bool lightVolume_isPoint(LightVolume lv) { return bool(lv.directionSpotCos.w < 0.f); } +bool lightVolume_isSpot(LightVolume lv) { return bool(lv.directionSpotCos.w >= 0.f); } -vec3 lightVolume_getPosition(LightVolumeConstRef lv) { return lv.position; } -float lightVolume_getRadius(LightVolumeConstRef lv) { return lv.radius; } -float lightVolume_getRadiusSquare(LightVolumeConstRef lv) { return lv.radius * lv.radius; } -vec3 lightVolume_getDirection(LightVolumeConstRef lv) { return lv.direction; } // direction is -Z axis +vec3 lightVolume_getPosition(LightVolume lv) { return lv.positionRadius.xyz; } +float lightVolume_getRadius(LightVolume lv) { return lv.positionRadius.w; } +float lightVolume_getRadiusSquare(LightVolume lv) { return lv.positionRadius.w * lv.positionRadius.w; } +vec3 lightVolume_getDirection(LightVolume lv) { return lv.directionSpotCos.xyz; } // direction is -Z axis -float lightVolume_getSpotAngleCos(LightVolumeConstRef lv) { return lv.spotCos; } -vec2 lightVolume_getSpotOutsideNormal2(LightVolumeConstRef lv) { return vec2(-sqrt(1.0 - lv.spotCos * lv.spotCos), lv.spotCos); } +float lightVolume_getSpotAngleCos(LightVolume lv) { return lv.directionSpotCos.w; } +vec2 lightVolume_getSpotOutsideNormal2(LightVolume lv) { return vec2(-sqrt(1.0 - lv.directionSpotCos.w * lv.directionSpotCos.w), lv.directionSpotCos.w); } -bool lightVolume_clipFragToLightVolumePoint(LightVolume lv, vec3 fragPos, vec4 fragLightVecLen2) { - fragLightVecLen2 = vec4(lightVolume_getPosition(lv) - fragPos.xyz, 1.0f); +bool lightVolume_clipFragToLightVolumePoint(LightVolume lv, vec3 fragPos, out vec4 fragLightVecLen2) { + fragLightVecLen2.xyz = lightVolume_getPosition(lv) - fragPos.xyz; fragLightVecLen2.w = dot(fragLightVecLen2.xyz, fragLightVecLen2.xyz); // Kill if too far from the light center - if (fragLightVecLen2.w > lightVolume_getRadiusSquare(lv)) { - return false; - } - return true; + return (fragLightVecLen2.w <= lightVolume_getRadiusSquare(lv)); } -bool lightVolume_clipFragToLightVolumeSpot(LightVolume lv, vec3 fragPos, vec4 fragLightVecLen2, vec4 fragLightDirLen, float cosSpotAngle) { - fragLightVecLen2 = vec4(lightVolume_getPosition(lv) - fragPos.xyz, 1.0f); + +bool lightVolume_clipFragToLightVolumeSpot(LightVolume lv, vec3 fragPos, out vec4 fragLightVecLen2, out vec4 fragLightDirLen, out float cosSpotAngle) { + fragLightVecLen2.xyz = lightVolume_getPosition(lv) - fragPos.xyz; fragLightVecLen2.w = dot(fragLightVecLen2.xyz, fragLightVecLen2.xyz); // Kill if too far from the light center @@ -67,6 +63,16 @@ bool lightVolume_clipFragToLightVolumeSpot(LightVolume lv, vec3 fragPos, vec4 fr return true; } +bool lightVolume_clipFragToLightVolumeSpotSide(LightVolume lv, vec4 fragLightVecLen2, out vec4 fragLightDirLen, out float cosSpotAngle) { + // Allright we re valid in the volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + + // Kill if not in the spot light (ah ah !) + cosSpotAngle = max(-dot(fragLightDirLen.xyz, lightVolume_getDirection(lv)), 0.0); + return (cosSpotAngle >= lightVolume_getSpotAngleCos(lv)); +} + #endif diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 59a75a5389..01c5a81732 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -187,7 +187,7 @@ void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBuff auto keyLight = _allocatedLights[_globalLights.front()]; if (lightBufferUnit >= 0) { - batch.setUniformBuffer(lightBufferUnit, keyLight->getSchemaBuffer()); + batch.setUniformBuffer(lightBufferUnit, keyLight->getLightSchemaBuffer()); } if (keyLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { @@ -727,8 +727,6 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, // Bind the global list of lights and the visible lights this frame batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, lightClusters->_lightStage->_lightArrayBuffer); - batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightIndexBufferUnit, lightClusters->_lightIndicesBuffer); - batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer); batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer); diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 7964d09142..3395f1be1a 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -64,9 +64,11 @@ ivec2 clusterGrid_getCluster(int index) { int clusterGrid_getClusterLightId(int index, ivec2 cluster) { int arrayElement = cluster.y + index; - int element = _clusterGridContent[arrayElement >> 1]; + int element = _clusterGridContent[arrayElement]; + return element; +// int element = _clusterGridContent[arrayElement >> 1]; - return (((arrayElement & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF; +// return (((arrayElement & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF; } <@endif@> diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 651ba4957d..cf79e30630 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -76,7 +76,7 @@ const glm::uvec4 LightClusters::MAX_GRID_DIMENSIONS { 32, 32, 31, 16384 }; LightClusters::LightClusters() : _lightIndicesBuffer(std::make_shared()), _clusterGridBuffer(std::make_shared(), gpu::Element::INDEX_INT32), - _clusterContentBuffer(std::make_shared(), gpu::Element::INDEX_UINT16) { + _clusterContentBuffer(std::make_shared(), gpu::Element::INDEX_INT32) { auto dims = _frustumGridBuffer.edit().dims; _frustumGridBuffer.edit().dims = ivec3(0); // make sure we go through the full reset of the dimensionts ion the setDImensions call setDimensions(dims, MAX_GRID_DIMENSIONS.w); @@ -109,7 +109,7 @@ void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { _clusterGridBuffer._size = _clusterGridBuffer._buffer->resize(_numClusters * sizeof(uint32_t)); } - auto configListBudget = std::min(MAX_GRID_DIMENSIONS.w, listBudget) * 2; + auto configListBudget = std::min(MAX_GRID_DIMENSIONS.w, listBudget); if (configListBudget != _clusterContentBuffer.getNumElements()) { _clusterContent.clear(); _clusterContent.resize(configListBudget, INVALID_LIGHT); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 02ea436718..7b50d8864a 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -94,7 +94,7 @@ public: const uint32_t EMPTY_CLUSTER { 0x0000FFFF }; const LightID INVALID_LIGHT { LightStage::INVALID_INDEX }; - using LightIndex = uint16_t; + using LightIndex = uint32_t; std::vector _clusterGrid; std::vector _clusterContent; diff --git a/libraries/render-utils/src/LightPoint.slh b/libraries/render-utils/src/LightPoint.slh index b120df584a..362aac5298 100644 --- a/libraries/render-utils/src/LightPoint.slh +++ b/libraries/render-utils/src/LightPoint.slh @@ -24,7 +24,7 @@ void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light, vec3 fragLightDir = fragLightVec / fragLightDistance; // Eval attenuation - float radialAttenuation = evalLightAttenuation(light, fragLightDistance); + float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance); vec3 lightEnergy = radialAttenuation * shadow * getLightIrradiance(light); // Eval shading diff --git a/libraries/render-utils/src/LightSpot.slh b/libraries/render-utils/src/LightSpot.slh index 3a04c28bfb..a3be944494 100644 --- a/libraries/render-utils/src/LightSpot.slh +++ b/libraries/render-utils/src/LightSpot.slh @@ -23,9 +23,10 @@ void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light, float fragLightDistance = fragLightDirLen.w; vec3 fragLightDir = fragLightDirLen.xyz; + // Eval attenuation - float radialAttenuation = evalLightAttenuation(light, fragLightDistance); - float angularAttenuation = evalLightSpotAttenuation(light, cosSpotAngle); + float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance); + float angularAttenuation = lightIrradiance_evalLightSpotAttenuation(light.irradiance, cosSpotAngle); vec3 lightEnergy = angularAttenuation * radialAttenuation * shadow *getLightIrradiance(light); // Eval shading diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 357e7f46f7..bedd22b360 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -134,22 +134,22 @@ LightStage::LightPointer LightStage::removeLight(Index index) { } void LightStage::updateLightArrayBuffer(Index lightId) { + auto lightSize = sizeof(model::Light::LightSchema); if (!_lightArrayBuffer) { _lightArrayBuffer = std::make_shared(); } assert(checkLightId(lightId)); - auto lightSize = sizeof(model::Light::Schema); - if (lightId > (Index) _lightArrayBuffer->getNumTypedElements()) { + if (lightId > (Index)_lightArrayBuffer->getNumTypedElements()) { _lightArrayBuffer->resize(lightSize * (lightId + 10)); } // lightArray is big enough so we can remap auto light = _lights._elements[lightId]; if (light) { - auto lightSchema = light->getSchemaBuffer().get(); - _lightArrayBuffer->setSubData(lightId, lightSchema); + const auto& lightSchema = light->getLightSchemaBuffer().get(); + _lightArrayBuffer->setSubData(lightId, lightSchema); } else { // this should not happen ? } diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index 7cfb717f12..1fea7d6ced 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -568,7 +568,7 @@ void DebugSubsurfaceScattering::run(const render::SceneContextPointer& sceneCont batch.setUniformBuffer(ScatteringTask_FrameTransformSlot, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(ScatteringTask_ParamSlot, scatteringResource->getParametersBuffer()); if (light) { - batch.setUniformBuffer(ScatteringTask_LightSlot, light->getSchemaBuffer()); + batch.setUniformBuffer(ScatteringTask_LightSlot, light->getLightSchemaBuffer()); } batch.setResourceTexture(ScatteringTask_ScatteringTableSlot, scatteringTable); batch.setResourceTexture(ScatteringTask_CurvatureMapSlot, curvatureFramebuffer->getRenderBuffer(0)); diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index 8cf817b127..3d85c0ccab 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -20,9 +20,6 @@ // Everything about light <@include model/Light.slh@> <$declareLightBuffer(128)$> -uniform lightIndexBuffer { - int lightIndex[128]; -}; <@include LightingModel.slh@> @@ -94,33 +91,31 @@ void main(void) { vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - - /* int theLightIndex = clusterGrid_getClusterLightId(0, cluster); - if (theLightIndex == 65535) { - discard; - } - Light light = getLight(theLightIndex); - - int numLights = lightIndex[0];*/ - for (int i = 0; i < numLights; i++) { + int numLightTouching = 0; + for (int i = 0; i < numLights && numLightTouching < 16; i++) { // Need the light now int theLightIndex = clusterGrid_getClusterLightId(i, cluster); Light light = getLight(theLightIndex); + bool isSpot = light_isSpot(light); // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space vec4 fragLightVecLen2; vec4 fragLightDirLen; float cosSpotAngle; - if (isSpot) { - if (!lightVolume_clipFragToLightVolumeSpot(light.volume, fragPos.xyz, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) { + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { + continue; + } + if (isSpot && !lightVolume_clipFragToLightVolumeSpotSide(light.volume, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) { continue; - } - } else { - if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { - continue; - } } + if (dot(frag.normal, normalize(fragLightVecLen2.xyz)) < 0.0) { + //_fragColor.rgb += vec3(0.0, 0.0, 1.0 / 16.0); + continue; + } + + numLightTouching++; + /* vec3 diffuse; vec3 specular; @@ -135,11 +130,11 @@ void main(void) { frag.metallic, frag.fresnel, frag.albedo, 1.0, frag.scattering, midNormalCurvature, lowNormalCurvature); } - _fragColor.rgb += diffuse; _fragColor.rgb += specular; + */ + _fragColor.rgb += vec3(1.0/16.0, 0.0, 0.0); } - // _fragColor.rgb += vec3(0.05, 0.0, 0.0); } From e143c05ef83e9e798129a5afa38df31d9e4d28c7 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 30 Sep 2016 02:41:21 -0700 Subject: [PATCH 044/104] Keep on investigating the shading cost per light --- .../model/src/model/LightVolume.shared.slh | 41 ++---- .../render-utils/src/LightClusterGrid.slh | 7 +- libraries/render-utils/src/LightClusters.cpp | 29 +++-- libraries/render-utils/src/LightPoint.slh | 8 +- libraries/render-utils/src/LightingModel.slh | 39 +++++- .../src/lightClusters_drawClusterContent.slv | 4 +- .../lightClusters_drawClusterFromDepth.slf | 4 +- .../src/lightClusters_drawGrid.slv | 4 +- .../render-utils/src/local_lights_shading.slf | 121 ++++++++++++++---- 9 files changed, 173 insertions(+), 84 deletions(-) diff --git a/libraries/model/src/model/LightVolume.shared.slh b/libraries/model/src/model/LightVolume.shared.slh index ac75308c18..a78667ed6c 100644 --- a/libraries/model/src/model/LightVolume.shared.slh +++ b/libraries/model/src/model/LightVolume.shared.slh @@ -40,39 +40,24 @@ bool lightVolume_clipFragToLightVolumePoint(LightVolume lv, vec3 fragPos, out ve return (fragLightVecLen2.w <= lightVolume_getRadiusSquare(lv)); } - -bool lightVolume_clipFragToLightVolumeSpot(LightVolume lv, vec3 fragPos, out vec4 fragLightVecLen2, out vec4 fragLightDirLen, out float cosSpotAngle) { - fragLightVecLen2.xyz = lightVolume_getPosition(lv) - fragPos.xyz; - fragLightVecLen2.w = dot(fragLightVecLen2.xyz, fragLightVecLen2.xyz); - - // Kill if too far from the light center - if (fragLightVecLen2.w > lightVolume_getRadiusSquare(lv)) { - return false; - } - - // Allright we re valid in the volume - fragLightDirLen.w = length(fragLightVecLen2.xyz); - fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; - - // Kill if not in the spot light (ah ah !) - cosSpotAngle = max(-dot(fragLightDirLen.xyz, lightVolume_getDirection(lv)), 0.0); - if (cosSpotAngle < lightVolume_getSpotAngleCos(lv)) { - return false; - } - - return true; -} - -bool lightVolume_clipFragToLightVolumeSpotSide(LightVolume lv, vec4 fragLightVecLen2, out vec4 fragLightDirLen, out float cosSpotAngle) { - // Allright we re valid in the volume - fragLightDirLen.w = length(fragLightVecLen2.xyz); - fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; - +bool lightVolume_clipFragToLightVolumeSpotSide(LightVolume lv, vec4 fragLightDirLen, out float cosSpotAngle) { // Kill if not in the spot light (ah ah !) cosSpotAngle = max(-dot(fragLightDirLen.xyz, lightVolume_getDirection(lv)), 0.0); return (cosSpotAngle >= lightVolume_getSpotAngleCos(lv)); } +bool lightVolume_clipFragToLightVolumeSpot(LightVolume lv, vec3 fragPos, out vec4 fragLightVecLen2, out vec4 fragLightDirLen, out float cosSpotAngle) { + if (!lightVolume_clipFragToLightVolumePoint(lv, fragPos, fragLightVecLen2)) { + return false; + } + + // Allright we re valid in the volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + + return lightVolume_clipFragToLightVolumeSpotSide(lv, fragLightDirLen, cosSpotAngle); +} + #endif diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 3395f1be1a..14595c91a0 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -55,11 +55,12 @@ uniform clusterContentBuffer { int _clusterGridContent[16384]; }; -ivec2 clusterGrid_getCluster(int index) { +ivec3 clusterGrid_getCluster(int index) { int clusterDesc = _clusterGridTable[index]; - int numLights = 0xFFFF & (clusterDesc >> 16); + int numPointLights = 0xFF & (clusterDesc >> 16); + int numSpotLights = 0xFF & (clusterDesc >> 24); int contentOffset = 0xFFFF & (clusterDesc); - return ivec2(numLights, contentOffset); + return ivec3(numPointLights, numSpotLights, contentOffset); } int clusterGrid_getClusterLightId(int index, ivec2 cluster) { diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index cf79e30630..870dccaeea 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -270,7 +270,8 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan void LightClusters::updateClusters() { // Clean up last info - std::vector< std::vector< LightIndex > > clusterGrid(_numClusters); + std::vector< std::vector< LightIndex > > clusterGridPoint(_numClusters); + std::vector< std::vector< LightIndex > > clusterGridSpot(_numClusters); _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); uint32_t maxNumIndices = (uint32_t) _clusterContent.size(); @@ -289,6 +290,7 @@ void LightClusters::updateClusters() { auto worldOri = light->getPosition(); auto radius = light->getMaximumRadius(); + bool isSpot = light->isSpot(); // Bring into frustum eye space auto eyeOri = theFrustumGrid.frustumGrid_worldToEye(glm::vec4(worldOri, 1.0f)); @@ -395,6 +397,7 @@ void LightClusters::updateClusters() { } // now voxelize + auto& clusterGrid = (isSpot ? clusterGridSpot : clusterGridPoint); numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); } @@ -405,9 +408,13 @@ void LightClusters::updateClusters() { checkBudget = true; } uint16_t indexOffset = 0; - for (int i = 0; i < clusterGrid.size(); i++) { - auto& cluster = clusterGrid[i]; - uint16_t numLights = ((uint16_t)cluster.size()); + for (int i = 0; i < clusterGridPoint.size(); i++) { + auto& clusterPoint = clusterGridPoint[i]; + auto& clusterSpot = clusterGridSpot[i]; + + uint8_t numLightsPoint = ((uint8_t)clusterPoint.size()); + uint8_t numLightsSpot = ((uint8_t)clusterSpot.size()); + uint16_t numLights = numLightsPoint + numLightsSpot; uint16_t offset = indexOffset; // Check for overflow @@ -417,14 +424,18 @@ void LightClusters::updateClusters() { } } - _clusterGrid[i] = (uint32_t)((numLights << 16) | offset); + // _clusterGrid[i] = (uint32_t)((numLights << 16) | offset); + _clusterGrid[i] = (uint32_t)((numLightsSpot << 24) | (numLightsPoint << 16) | offset); - if (numLights) { - memcpy(_clusterContent.data() + indexOffset, cluster.data(), numLights * sizeof(LightIndex)); + if (numLightsPoint) { + memcpy(_clusterContent.data() + indexOffset, clusterPoint.data(), numLightsPoint * sizeof(LightIndex)); + indexOffset += numLightsPoint; + } + if (numLightsSpot) { + memcpy(_clusterContent.data() + indexOffset, clusterSpot.data(), numLightsSpot * sizeof(LightIndex)); + indexOffset += numLightsSpot; } - - indexOffset += numLights; } // update the buffers diff --git a/libraries/render-utils/src/LightPoint.slh b/libraries/render-utils/src/LightPoint.slh index 362aac5298..5160396e8a 100644 --- a/libraries/render-utils/src/LightPoint.slh +++ b/libraries/render-utils/src/LightPoint.slh @@ -12,16 +12,16 @@ <@func declareLightingPoint(supportScattering)@> void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light, - vec3 fragLightVec, vec3 fragEyeDir, vec3 normal, float roughness, + vec4 fragLightDirLen, vec3 fragEyeDir, vec3 normal, float roughness, float metallic, vec3 fresnel, vec3 albedo, float shadow <@if supportScattering@> , float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature <@endif@> ) { - + // Allright we re valid in the volume - float fragLightDistance = length(fragLightVec); - vec3 fragLightDir = fragLightVec / fragLightDistance; + float fragLightDistance = fragLightDirLen.w; + vec3 fragLightDir = fragLightDirLen.xyz; // Eval attenuation float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance); diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index f36b2d8131..9d5f78a581 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -82,12 +82,6 @@ float fetchSpecularBeckmann(float ndoth, float roughness) { return pow(2.0 * texture(scatteringSpecularBeckmann, vec2(ndoth, roughness)).r, 10.0); } -float fresnelSchlickScalar(float fresnelColor, vec3 lightDir, vec3 halfDir) { - float base = 1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0); - float exponential = pow(base, 5.0); - return (exponential)+fresnelColor * (1.0 - exponential); -} - vec2 skinSpecular(vec3 N, vec3 L, vec3 V, float roughness, float intensity) { vec2 result = vec2(0.0, 1.0); float ndotl = dot(N, L); @@ -114,6 +108,11 @@ vec3 fresnelSchlickColor(vec3 fresnelColor, vec3 lightDir, vec3 halfDir) { return vec3(exponential) + fresnelColor * (1.0 - exponential); } +float fresnelSchlickScalar(float fresnelScalar, vec3 lightDir, vec3 halfDir) { + float base = 1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0); + float exponential = pow(base, 5.0); + return (exponential) + fresnelScalar * (1.0 - exponential); +} float specularDistribution(float roughness, vec3 normal, vec3 halfDir) { @@ -144,6 +143,21 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float m return vec4(specular, (1.0 - metallic) * diffuse * (1 - fresnelColor.x)); } + +// Frag Shading returns the diffuse amount as W and the specular rgb as xyz +vec4 evalPBRShadingDielectric(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float roughness) { + // Diffuse Lighting + float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0); + + // Specular Lighting + vec3 halfDir = normalize(fragEyeDir + fragLightDir); + float fresnelScalar = fresnelSchlickScalar(0.03, fragLightDir, halfDir); + float power = specularDistribution(roughness, fragNormal, halfDir); + float specular = power * fresnelScalar * diffuse; + + return vec4(vec3(specular), diffuse * (1 - fresnelScalar)); +} + <@endfunc@> @@ -196,5 +210,18 @@ void evalFragShading(out vec3 diffuse, out vec3 specular, } } +void evalFragShadingSimpler(out vec3 diffuse, out vec3 specular, + vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, + float metallic, vec3 fresnel, float roughness, vec3 albedo +/* + ,float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature +*/ +) { + vec4 shading = evalPBRShadingDielectric(fragNormal, fragLightDir, fragEyeDir, roughness); + // vec4 shading = evalPBRShading(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, roughness); + diffuse = vec3(shading.w); + diffuse *= albedo; + specular = shading.xyz; +} <@endif@> diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index 5bf6a0bf18..8b8bdd9c94 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -53,8 +53,8 @@ void main(void) { - ivec2 cluster = clusterGrid_getCluster(gl_InstanceID); - int numLights = cluster.x; + ivec3 cluster = clusterGrid_getCluster(gl_InstanceID); + int numLights = cluster.x + cluster.y; float numLightsScale = clamp(numLights * 0.1, 0.0, 1.0); diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index 1820d3113b..51d0faefa7 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -37,8 +37,8 @@ void main(void) { ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); - ivec2 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); - int numLights = cluster.x; + ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); + int numLights = cluster.x + cluster.y; float numLightsScale = clamp(numLights * 0.1, 0.01, 1.0); diff --git a/libraries/render-utils/src/lightClusters_drawGrid.slv b/libraries/render-utils/src/lightClusters_drawGrid.slv index 15fa8ac38a..a6590ada3f 100644 --- a/libraries/render-utils/src/lightClusters_drawGrid.slv +++ b/libraries/render-utils/src/lightClusters_drawGrid.slv @@ -54,8 +54,8 @@ void main(void) { vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]]; - ivec2 cluster = clusterGrid_getCluster(gl_InstanceID); - int numLights = cluster.x; + ivec3 cluster = clusterGrid_getCluster(gl_InstanceID); + int numLights = cluster.x + cluster.y; ivec3 clusterPos = frustumGrid_indexToCluster(gl_InstanceID); diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index 3d85c0ccab..57068c4052 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -58,11 +58,13 @@ void main(void) { ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); - ivec2 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); - int numLights = cluster.x; + ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); + int numLights = cluster.x + cluster.y; if (numLights <= 0) { discard; } + int lightClusterOffset = cluster.z; + ivec2 clusterAddress = ivec2(numLights, lightClusterOffset); ivec3 dims = frustumGrid.dims.xyz; if (clusterPos.x < 0 || clusterPos.x >= dims.x) { @@ -76,7 +78,6 @@ void main(void) { discard; } - int lightClusterOffset = cluster.y; @@ -92,48 +93,112 @@ void main(void) { vec3 fragEyeDir = normalize(fragEyeVector.xyz); int numLightTouching = 0; - for (int i = 0; i < numLights && numLightTouching < 16; i++) { + for (int i = 0; i < cluster.x; i++) { // Need the light now - int theLightIndex = clusterGrid_getClusterLightId(i, cluster); + int theLightIndex = clusterGrid_getClusterLightId(i, clusterAddress); Light light = getLight(theLightIndex); - bool isSpot = light_isSpot(light); // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space vec4 fragLightVecLen2; vec4 fragLightDirLen; - float cosSpotAngle; + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { continue; } - if (isSpot && !lightVolume_clipFragToLightVolumeSpotSide(light.volume, fragLightVecLen2, fragLightDirLen, cosSpotAngle)) { - continue; - } - if (dot(frag.normal, normalize(fragLightVecLen2.xyz)) < 0.0) { - //_fragColor.rgb += vec3(0.0, 0.0, 1.0 / 16.0); + // Allright we re in the light sphere volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + if (dot(frag.normal, fragLightDirLen.xyz) < 0.0) { continue; } numLightTouching++; - /* - vec3 diffuse; - vec3 specular; - if (isSpot) { - evalLightingSpot(diffuse, specular, light, - fragLightDirLen.xyzw, cosSpotAngle, fragEyeDir, frag.normal, frag.roughness, - frag.metallic, frag.fresnel, frag.albedo, 1.0, - frag.scattering, midNormalCurvature, lowNormalCurvature); - } else { - evalLightingPoint(diffuse, specular, light, - fragLightVecLen2.xyz, fragEyeDir, frag.normal, frag.roughness, - frag.metallic, frag.fresnel, frag.albedo, 1.0, - frag.scattering, midNormalCurvature, lowNormalCurvature); - } + vec3 diffuse = vec3(1.0); + vec3 specular = vec3(0.1); + + // Allright we re valid in the volume + float fragLightDistance = fragLightDirLen.w; + vec3 fragLightDir = fragLightDirLen.xyz; + + // Eval attenuation + float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance); + vec3 lightEnergy = radialAttenuation * getLightIrradiance(light); + + // Eval shading + evalFragShading(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo + ,frag.scattering, midNormalCurvature, lowNormalCurvature + ); + /* + evalLightingPoint(diffuse, specular, light, + fragLightDirLen.xyzw, fragEyeDir, frag.normal, frag.roughness, + frag.metallic, frag.fresnel, frag.albedo, 1.0, + frag.scattering, midNormalCurvature, lowNormalCurvature); + */ + diffuse *= lightEnergy * isDiffuseEnabled(); + specular *= lightEnergy * isSpecularEnabled(); + _fragColor.rgb += diffuse; _fragColor.rgb += specular; - */ - _fragColor.rgb += vec3(1.0/16.0, 0.0, 0.0); + } + + for (int i = cluster.x; i < numLights; i++) { + // Need the light now + int theLightIndex = clusterGrid_getClusterLightId(i, clusterAddress); + Light light = getLight(theLightIndex); + + // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space + vec4 fragLightVecLen2; + vec4 fragLightDirLen; + float cosSpotAngle; + + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { + continue; + } + + // Allright we re in the light sphere volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + if (dot(frag.normal, fragLightDirLen.xyz) < 0.0) { + continue; + } + + // Check spot + if (!lightVolume_clipFragToLightVolumeSpotSide(light.volume, fragLightDirLen, cosSpotAngle)) { + continue; + } + + numLightTouching++; + + vec3 diffuse = vec3(1.0); + vec3 specular = vec3(0.1); + + // Allright we re valid in the volume + float fragLightDistance = fragLightDirLen.w; + vec3 fragLightDir = fragLightDirLen.xyz; + + // Eval attenuation + float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance); + float angularAttenuation = lightIrradiance_evalLightSpotAttenuation(light.irradiance, cosSpotAngle); + vec3 lightEnergy = radialAttenuation * angularAttenuation * getLightIrradiance(light); + + // Eval shading + evalFragShading(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo + ,frag.scattering, midNormalCurvature, lowNormalCurvature + ); + /* evalLightingSpot(diffuse, specular, light, + fragLightDirLen.xyzw, cosSpotAngle, fragEyeDir, frag.normal, frag.roughness, + frag.metallic, frag.fresnel, frag.albedo, 1.0, + frag.scattering, midNormalCurvature, lowNormalCurvature); + */ + diffuse *= lightEnergy * isDiffuseEnabled(); + specular *= lightEnergy * isSpecularEnabled(); + + _fragColor.rgb += diffuse; + _fragColor.rgb += specular; + + // _fragColor.rgb += vec3(1.0/16.0, 0.0, 0.0); } } From 5b4829e7b6e1c905345a6ef2f7c5304833d2011e Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 30 Sep 2016 16:24:57 -0700 Subject: [PATCH 045/104] Brining back support for the ambinet lighting --- libraries/model/src/model/Light.h | 3 ++- libraries/render-utils/src/DeferredLightingEffect.cpp | 11 +++++++++-- libraries/render-utils/src/DeferredLightingEffect.h | 2 +- libraries/render-utils/src/LightingModel.slh | 8 ++++++-- libraries/render-utils/src/RenderPipelines.cpp | 1 + libraries/render/src/render/ShapePipeline.cpp | 4 +++- libraries/render/src/render/ShapePipeline.h | 2 ++ 7 files changed, 24 insertions(+), 7 deletions(-) diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 893467866a..b57b8c6095 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -111,7 +111,8 @@ public: float getIntensity() const { return _lightSchemaBuffer->irradiance.intensity; } void setIntensity(float intensity); - bool isRanged() const { return (getType() == POINT) || (getType() == SPOT ); } + bool isRanged() const { return (getType() == POINT) || (getType() == SPOT); } + bool hasAmbient() const { return (getType() == SUN); } // FalloffRradius is the physical radius of the light sphere through which energy shines, // expressed in meters. It is used only to calculate the falloff curve of the light. diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 01c5a81732..b1833764dd 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -45,6 +45,7 @@ struct LightLocations { int radius{ -1 }; int ambientSphere{ -1 }; int lightBufferUnit{ -1 }; + int ambientBufferUnit { -1 }; int lightIndexBufferUnit { -1 }; int texcoordFrameTransform{ -1 }; int deferredFrameTransformBuffer{ -1 }; @@ -72,6 +73,7 @@ enum DeferredShader_BufferSlot { SCATTERING_PARAMETERS_BUFFER_SLOT, LIGHTING_MODEL_BUFFER_SLOT = render::ShapePipeline::Slot::LIGHTING_MODEL, LIGHT_GPU_SLOT = render::ShapePipeline::Slot::LIGHT, + LIGHT_AMBIENT_SLOT, LIGHT_INDEX_GPU_SLOT, LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, @@ -182,13 +184,16 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu } } -void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int skyboxCubemapUnit) { +void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) { PerformanceTimer perfTimer("DLE->setupBatch()"); auto keyLight = _allocatedLights[_globalLights.front()]; if (lightBufferUnit >= 0) { batch.setUniformBuffer(lightBufferUnit, keyLight->getLightSchemaBuffer()); } + if (keyLight->hasAmbient() && (ambientBufferUnit >= 0)) { + batch.setUniformBuffer(ambientBufferUnit, keyLight->getAmbientSchemaBuffer()); + } if (keyLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { batch.setResourceTexture(skyboxCubemapUnit, keyLight->getAmbientMap()); @@ -221,6 +226,7 @@ static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* f slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), LIGHTING_MODEL_BUFFER_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("subsurfaceScatteringParametersBuffer"), SCATTERING_PARAMETERS_BUFFER_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("lightAmbientBuffer"), LIGHT_AMBIENT_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("lightIndexBuffer"), LIGHT_INDEX_GPU_SLOT)); @@ -236,6 +242,7 @@ static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* f locations->texcoordFrameTransform = program->getUniforms().findLocation("texcoordFrameTransform"); locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); + locations->ambientBufferUnit = program->getBuffers().findLocation("lightAmbientBuffer"); locations->lightIndexBufferUnit = program->getBuffers().findLocation("lightIndexBuffer"); locations->deferredFrameTransformBuffer = program->getBuffers().findLocation("deferredFrameTransformBuffer"); locations->subsurfaceScatteringParametersBuffer = program->getBuffers().findLocation("subsurfaceScatteringParametersBuffer"); @@ -640,7 +647,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c batch._glUniform4fv(locations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform)); { // Setup the global lighting - deferredLightingEffect->setupKeyLightBatch(batch, locations->lightBufferUnit, SKYBOX_MAP_UNIT); + deferredLightingEffect->setupKeyLightBatch(batch, locations->lightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT); } batch.draw(gpu::TRIANGLE_STRIP, 4); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 690d6ce5e0..1045cab30e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -56,7 +56,7 @@ public: float intensity = 0.5f, float falloffRadius = 0.01f, const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI); - void setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int skyboxCubemapUnit); + void setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit); // update global lighting void setGlobalLight(const model::LightPointer& light); diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index 9d5f78a581..5485224ab8 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -104,13 +104,17 @@ vec2 skinSpecular(vec3 N, vec3 L, vec3 V, float roughness, float intensity) { vec3 fresnelSchlickColor(vec3 fresnelColor, vec3 lightDir, vec3 halfDir) { float base = 1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0); - float exponential = pow(base, 5.0); + //float exponential = pow(base, 5.0); + float base2 = base * base; + float exponential = base * base2 * base2; return vec3(exponential) + fresnelColor * (1.0 - exponential); } float fresnelSchlickScalar(float fresnelScalar, vec3 lightDir, vec3 halfDir) { float base = 1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0); - float exponential = pow(base, 5.0); + //float exponential = pow(base, 5.0); + float base2 = base * base; + float exponential = base * base2 * base2; return (exponential) + fresnelScalar * (1.0 - exponential); } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index e50492fd64..1f4b7ca445 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -78,6 +78,7 @@ void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { if (pipeline.locations->lightBufferUnit >= 0) { DependencyManager::get()->setupKeyLightBatch(batch, pipeline.locations->lightBufferUnit, + pipeline.locations->lightAmbientBufferUnit, pipeline.locations->lightAmbientMapUnit); } } diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 3b613e0f96..4bab517e30 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -63,6 +63,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), Slot::MAP::OCCLUSION)); slotBindings.insert(gpu::Shader::Binding(std::string("scatteringMap"), Slot::MAP::SCATTERING)); 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("normalFittingMap"), Slot::NORMAL_FITTING)); @@ -85,8 +86,9 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); locations->texMapArrayBufferUnit = program->getBuffers().findLocation("texMapArrayBuffer"); locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); + locations->lightAmbientBufferUnit = program->getBuffers().findLocation("lightAmbientBuffer"); locations->lightAmbientMapUnit = program->getTextures().findLocation("skyboxMap"); - + ShapeKey key{filter._flags}; auto gpuPipeline = gpu::Pipeline::create(program, state); auto shapePipeline = std::make_shared(gpuPipeline, locations, batchSetter); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 5b60521068..e7a14d2f2b 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -201,6 +201,7 @@ public: TEXMAPARRAY, LIGHTING_MODEL, LIGHT, + LIGHT_AMBIENT_BUFFER, }; enum MAP { @@ -231,6 +232,7 @@ public: int materialBufferUnit; int texMapArrayBufferUnit; int lightBufferUnit; + int lightAmbientBufferUnit; int lightAmbientMapUnit; }; using LocationsPointer = std::shared_ptr; From 0475833e3bde695b7173bda204627e19d8a768c1 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 30 Sep 2016 19:08:00 -0700 Subject: [PATCH 046/104] Friday night state, down to ~3.5ms in hmd --- libraries/render-utils/src/LightClusters.cpp | 21 ++----- libraries/render-utils/src/LightClusters.h | 8 +-- libraries/render-utils/src/LightingModel.slh | 63 ++++++++++++++----- .../lightClusters_drawClusterFromDepth.slf | 2 +- .../render-utils/src/local_lights_shading.slf | 17 ++--- 5 files changed, 64 insertions(+), 47 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index e19439ba26..72f8c84c7e 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -183,7 +183,7 @@ float distanceToPlane(const glm::vec3& point, const glm::vec4& plane) { bool reduceSphereToPlane(const glm::vec4& sphere, const glm::vec4& plane, glm::vec4& reducedSphere) { float distance = distanceToPlane(glm::vec3(sphere), plane); - if (abs(distance) <= sphere.w) { + if (std::abs(distance) <= sphere.w) { reducedSphere = glm::vec4(sphere.x - distance * plane.x, sphere.y - distance * plane.y, sphere.z - distance * plane.z, sqrt(sphere.w * sphere.w - distance * distance)); return true; } @@ -242,7 +242,7 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan auto x = xMin; for (; (x < xMax); ++x) { - auto& plane = xPlanes[x + 1]; + const auto& plane = xPlanes[x + 1]; auto testDistance = distanceToPlane(spherePoint, plane) + ySphere.w; if (testDistance >= 0.0f) { break; @@ -250,7 +250,7 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan } auto xs = xMax; for (; (xs >= x); --xs) { - auto& plane = -xPlanes[xs]; + auto plane = -xPlanes[xs]; auto testDistance = distanceToPlane(spherePoint, plane) + ySphere.w; if (testDistance >= 0.0f) { break; @@ -313,27 +313,16 @@ void LightClusters::updateClusters() { continue; } - // Firt slice volume ? - /* if (zMin == -1) { - clusterGrid[0].emplace_back(lightId); - numClusterTouched++; - } */ - - // Stop there with this light if zmax is in near range - if (zMax == -1) { + // Before Range NEar just apss, range neatr == true near for now + if (zMin == -1 || zMax == -1) { continue; } - // is it a light whose origin is behind the near ? - bool behindLight = (eyeOri.z >= -theFrustumGrid.rangeNear); - // - float eyeOriLen2 = glm::length2(eyeOri); // CLamp the z range zMin = std::max(0, zMin); - // find 2D corners of the sphere in grid int xMin { 0 }; int xMax { theFrustumGrid.dims.x - 1 }; diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 7b50d8864a..5c52d44ff1 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -20,8 +20,8 @@ class FrustumGrid { public: float frustumNear { 0.1f }; - float rangeNear { 1.0f }; - float rangeFar { 100.0f }; + float rangeNear { 0.1f }; + float rangeFar { 200.0f }; float frustumFar { 10000.0f }; glm::ivec3 dims { 16, 12, 16 }; @@ -121,8 +121,8 @@ class LightClusteringPassConfig : public render::Job::Config { Q_PROPERTY(bool freeze MEMBER freeze NOTIFY dirty) public: LightClusteringPassConfig() : render::Job::Config(true){} - float rangeNear{ 1.0f }; - float rangeFar{ 512.0f }; + float rangeNear{ 0.1f }; + float rangeFar{ 200.0f }; int dimX { 16 }; int dimY { 16 }; diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index 5485224ab8..85abf06662 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -118,10 +118,19 @@ float fresnelSchlickScalar(float fresnelScalar, vec3 lightDir, vec3 halfDir) { return (exponential) + fresnelScalar * (1.0 - exponential); } - float specularDistribution(float roughness, vec3 normal, vec3 halfDir) { float ndoth = clamp(dot(halfDir, normal), 0.0, 1.0); - float gloss2 = pow(0.001 + roughness, 4); +// float gloss2 = pow(0.001 + roughness, 4); + float gloss2 = (0.001 + roughness); + gloss2 *= gloss2; // pow 2 + gloss2 *= gloss2; // pow 4 + float denom = (ndoth * ndoth*(gloss2 - 1) + 1); + float power = gloss2 / (3.14159 * denom * denom); + return power; +} +float specularDistributionGloss(float gloss2, vec3 normal, vec3 halfDir) { + float ndoth = clamp(dot(halfDir, normal), 0.0, 1.0); +// float gloss2 = pow(0.001 + roughness, 4); float denom = (ndoth * ndoth*(gloss2 - 1) + 1); float power = gloss2 / (3.14159 * denom * denom); return power; @@ -143,23 +152,50 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float m vec3 halfDir = normalize(fragEyeDir + fragLightDir); vec3 fresnelColor = fresnelSchlickColor(fresnel, fragLightDir, halfDir); float power = specularDistribution(roughness, fragNormal, halfDir); - vec3 specular = power * fresnelColor * diffuse; + vec3 specular = fresnelColor * power * diffuse; return vec4(specular, (1.0 - metallic) * diffuse * (1 - fresnelColor.x)); } // Frag Shading returns the diffuse amount as W and the specular rgb as xyz -vec4 evalPBRShadingDielectric(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float roughness) { +vec4 evalPBRShadingDielectric(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float roughness, float fresnel = 0.03) { // Diffuse Lighting float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0); // Specular Lighting vec3 halfDir = normalize(fragEyeDir + fragLightDir); - float fresnelScalar = fresnelSchlickScalar(0.03, fragLightDir, halfDir); + float fresnelScalar = fresnelSchlickScalar(fresnel, fragLightDir, halfDir); float power = specularDistribution(roughness, fragNormal, halfDir); - float specular = power * fresnelScalar * diffuse; + vec3 specular = vec3(fresnelScalar) * power * diffuse; - return vec4(vec3(specular), diffuse * (1 - fresnelScalar)); + return vec4(specular, diffuse * (1 - fresnelScalar)); +} + +vec4 evalPBRShadingMetallic(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float roughness, vec3 fresnel) { + // Diffuse Lighting + float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0); + + // Specular Lighting + vec3 halfDir = normalize(fragEyeDir + fragLightDir); + vec3 fresnelColor = fresnelSchlickColor(fresnel, fragLightDir, halfDir); + float power = specularDistribution(roughness, fragNormal, halfDir); + vec3 specular = fresnelColor * power * diffuse; + + return vec4(specular, 0.f); +} + +// Frag Shading returns the diffuse amount as W and the specular rgb as xyz +vec4 evalPBRShadingGloss(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float gloss2) { + // Diffuse Lighting + float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0); + + // Specular Lighting + vec3 halfDir = normalize(fragEyeDir + fragLightDir); + vec3 fresnelColor = fresnelSchlickColor(fresnel, fragLightDir, halfDir); + float power = specularDistributionGloss(gloss2, fragNormal, halfDir); + vec3 specular = fresnelColor * power * diffuse; + + return vec4(specular, (1.0 - metallic) * diffuse * (1 - fresnelColor.x)); } <@endfunc@> @@ -209,22 +245,19 @@ void evalFragShading(out vec3 diffuse, out vec3 specular, diffuse = vec3(shading.w); specular = shading.xyz; } - if (isAlbedoEnabled() > 0.0) { - diffuse *= albedo; - } + diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled()); } void evalFragShadingSimpler(out vec3 diffuse, out vec3 specular, vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float roughness, vec3 albedo -/* + ,float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature -*/ + ) { - vec4 shading = evalPBRShadingDielectric(fragNormal, fragLightDir, fragEyeDir, roughness); - // vec4 shading = evalPBRShading(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, roughness); + vec4 shading = evalPBRShadingGloss(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, roughness); diffuse = vec3(shading.w); - diffuse *= albedo; + diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled()); specular = shading.xyz; } diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index 51d0faefa7..ee2e6e0ccc 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -39,7 +39,7 @@ void main(void) { ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); int numLights = cluster.x + cluster.y; - float numLightsScale = clamp(numLights * 0.1, 0.01, 1.0); + float numLightsScale = clamp(numLights * 0.05, 0.01, 1.0); ivec3 dims = frustumGrid.dims.xyz; diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index 57068c4052..a4f9d6f24f 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -92,6 +92,10 @@ void main(void) { vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); + // COmpute the rougness into gloss2 once: + float fragGloss2 = pow(frag.roughness + 0.001, 2.0); + frag.roughness = fragGloss2; + int numLightTouching = 0; for (int i = 0; i < cluster.x; i++) { // Need the light now @@ -130,12 +134,7 @@ void main(void) { evalFragShading(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo ,frag.scattering, midNormalCurvature, lowNormalCurvature ); - /* - evalLightingPoint(diffuse, specular, light, - fragLightDirLen.xyzw, fragEyeDir, frag.normal, frag.roughness, - frag.metallic, frag.fresnel, frag.albedo, 1.0, - frag.scattering, midNormalCurvature, lowNormalCurvature); - */ + diffuse *= lightEnergy * isDiffuseEnabled(); specular *= lightEnergy * isSpecularEnabled(); @@ -187,11 +186,7 @@ void main(void) { evalFragShading(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo ,frag.scattering, midNormalCurvature, lowNormalCurvature ); - /* evalLightingSpot(diffuse, specular, light, - fragLightDirLen.xyzw, cosSpotAngle, fragEyeDir, frag.normal, frag.roughness, - frag.metallic, frag.fresnel, frag.albedo, 1.0, - frag.scattering, midNormalCurvature, lowNormalCurvature); - */ + diffuse *= lightEnergy * isDiffuseEnabled(); specular *= lightEnergy * isSpecularEnabled(); From 35f0d4b8a2e796f25809da004c80d9f6e3c881a5 Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 1 Oct 2016 15:35:59 -0700 Subject: [PATCH 047/104] cleaning for mac --- libraries/render-utils/src/LightClusterGrid.slh | 10 ++++++++-- libraries/render-utils/src/LightClusters.cpp | 5 ++++- libraries/render-utils/src/LightingModel.slh | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 14595c91a0..3eb3b53ccc 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -47,12 +47,18 @@ float projection_getFar(mat4 projection) { // end of hybrid include +<@if GLPROFILE == MAC_GL @> +#define GRID_NUM_ELEMENTS 4096 +<@else@> +#define GRID_NUM_ELEMENTS 16384 +<@endif@> + uniform clusterGridBuffer { - int _clusterGridTable[16384]; + int _clusterGridTable[GRID_NUM_ELEMENTS]; }; uniform clusterContentBuffer { - int _clusterGridContent[16384]; + int _clusterGridContent[GRID_NUM_ELEMENTS]; }; ivec3 clusterGrid_getCluster(int index) { diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 72f8c84c7e..2b2f3be9d5 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -69,8 +69,11 @@ void FrustumGrid::generateGridPlanes(Planes& xPlanes, Planes& yPlanes, Planes& z } #include "DeferredLightingEffect.h" - +#ifdef Q_OS_MAC +const glm::uvec4 LightClusters::MAX_GRID_DIMENSIONS { 8, 8, 8, 4096 }; +#else const glm::uvec4 LightClusters::MAX_GRID_DIMENSIONS { 32, 32, 31, 16384 }; +#endif LightClusters::LightClusters() : diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index 85abf06662..7303083405 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -158,7 +158,7 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float m } // Frag Shading returns the diffuse amount as W and the specular rgb as xyz -vec4 evalPBRShadingDielectric(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float roughness, float fresnel = 0.03) { +vec4 evalPBRShadingDielectric(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float roughness, float fresnel) { // Diffuse Lighting float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0); From 89717720f748304164822bafea207ea493bb7c40 Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 1 Oct 2016 16:12:45 -0700 Subject: [PATCH 048/104] CLeaning up code for Linux and Mac --- libraries/model/src/model/Light.cpp | 1 - .../src/LightClusterGrid_shared.slh | 24 +++++++++---------- libraries/render-utils/src/LightClusters.cpp | 8 +++---- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index 449054c9b2..59b57f274c 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -120,7 +120,6 @@ void Light::setSpotAngle(float angle) { dangle = glm::half_pi(); } auto cosAngle = cos(dangle); - auto sinAngle = sin(dangle); _spotCos = (float)std::abs(cosAngle); if (isSpot()) { diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index ec27b11a3f..37eddd087a 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -1,21 +1,21 @@ // glsl / C++ compatible source as interface for FrustrumGrid float frustumGrid_depthRampGridToVolume(float ngrid) { - if (ngrid < 0.0) + if (ngrid < 0.0f) return ngrid; // return ngrid; // return sqrt(ngrid); - return exp2(ngrid) - 1.0; + return exp2(ngrid) - 1.0f; } float frustumGrid_depthRampInverseVolumeToGrid(float nvolume) { - if (nvolume < 0.0) + if (nvolume < 0.0f) return nvolume; // return nvolume; // return nvolume * nvolume; - return log2(nvolume + 1.0); + return log2(nvolume + 1.0f); } vec3 frustumGrid_gridToVolume(vec3 pos, ivec3 dims) { - vec3 gridScale = vec3(1.0, 1.0, 1.0) / vec3(dims); + vec3 gridScale = vec3(1.0f) / vec3(dims); vec3 volumePos = pos * gridScale; volumePos.z = frustumGrid_depthRampGridToVolume(volumePos.z); return volumePos; @@ -33,9 +33,9 @@ vec3 frustumGrid_volumeToGrid(vec3 vpos, ivec3 dims) { vec4 frustumGrid_volumeToClip(vec3 vpos, float rangeNear, float rangeFar) { - vec3 ndcPos = vec3(-1.0 + 2.0 * vpos.x, -1.0 + 2.0 * vpos.y, vpos.z); + vec3 ndcPos = vec3(-1.0f + 2.0f * vpos.x, -1.0f + 2.0f * vpos.y, vpos.z); float depth = rangeNear * (1 - ndcPos.z) + rangeFar * (ndcPos.z); - vec4 clipPos = vec4(ndcPos.x * depth, ndcPos.y * depth, 1.0, depth); + vec4 clipPos = vec4(ndcPos.x * depth, ndcPos.y * depth, 1.0f, depth); return clipPos; } @@ -64,7 +64,7 @@ vec3 frustumGrid_eyeToVolume(vec3 epos, mat4 projection, float rangeNear, float -epos.z); vec4 ndcPos = clipPos / clipPos.w; - vec3 volumePos = vec3(0.5 * (ndcPos.x + 1.0), 0.5 * (ndcPos.y + 1.0), (clipPos.w - rangeNear) / (rangeFar - rangeNear)); + vec3 volumePos = vec3(0.5f * (ndcPos.x + 1.0f), 0.5f * (ndcPos.y + 1.0f), (clipPos.w - rangeNear) / (rangeFar - rangeNear)); return volumePos; } @@ -145,28 +145,28 @@ ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { } int frustumGrid_eyeToClusterDirH(vec3 eyeDir) { - if (eyeDir.z >= 0.0) { + if (eyeDir.z >= 0.0f) { return (eyeDir.x > 0 ? frustumGrid.dims.x : -1); } float eyeDepth = -eyeDir.z; float nclipDir = eyeDir.x / eyeDepth; float ndcDir = nclipDir * frustumGrid.eyeToGridProj[0][0] - frustumGrid.eyeToGridProj[2][0]; - float volumeDir = 0.5 * (ndcDir + 1.0); + float volumeDir = 0.5f * (ndcDir + 1.0f); float gridPos = volumeDir * float(frustumGrid.dims.x); return int(gridPos); } int frustumGrid_eyeToClusterDirV(vec3 eyeDir) { - if (eyeDir.z >= 0.0) { + if (eyeDir.z >= 0.0f) { return (eyeDir.y > 0 ? frustumGrid.dims.y : -1); } float eyeDepth = -eyeDir.z; float nclipDir = eyeDir.y / eyeDepth; float ndcDir = nclipDir * frustumGrid.eyeToGridProj[1][1] - frustumGrid.eyeToGridProj[2][1]; - float volumeDir = 0.5 * (ndcDir + 1.0); + float volumeDir = 0.5f * (ndcDir + 1.0f); float gridPos = volumeDir * float(frustumGrid.dims.y); return int(gridPos); diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 2b2f3be9d5..77e0d4d354 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -46,8 +46,8 @@ void FrustumGrid::generateGridPlanes(Planes& xPlanes, Planes& yPlanes, Planes& z yPlanes.resize(dims.y + 1); zPlanes.resize(dims.z + 1); - float centerY = float(dims.y) * 0.5; - float centerX = float(dims.x) * 0.5; + float centerY = float(dims.y) * 0.5f; + float centerX = float(dims.x) * 0.5f; for (int z = 0; z < (int) zPlanes.size(); z++) { ivec3 pos(0, 0, z); @@ -400,7 +400,7 @@ void LightClusters::updateClusters() { checkBudget = true; } uint16_t indexOffset = 0; - for (int i = 0; i < clusterGridPoint.size(); i++) { + for (int i = 0; i < (int) clusterGridPoint.size(); i++) { auto& clusterPoint = clusterGridPoint[i]; auto& clusterSpot = clusterGridSpot[i]; @@ -417,7 +417,7 @@ void LightClusters::updateClusters() { } // _clusterGrid[i] = (uint32_t)((numLights << 16) | offset); - _clusterGrid[i] = (uint32_t)((numLightsSpot << 24) | (numLightsPoint << 16) | offset); + _clusterGrid[i] = (uint32_t)((0xFF000000 & (numLightsSpot << 24)) | (0x00FF0000 & (numLightsPoint << 16)) | (0x0000FFFF & offset)); if (numLightsPoint) { From bdf2738f21bc48f61af473bf88e272edd1a3ee88 Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 1 Oct 2016 17:25:26 -0700 Subject: [PATCH 049/104] One more fix for linux build --- libraries/render-utils/src/LightClusterGrid_shared.slh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 37eddd087a..7308084b1e 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -1,14 +1,14 @@ // glsl / C++ compatible source as interface for FrustrumGrid float frustumGrid_depthRampGridToVolume(float ngrid) { - if (ngrid < 0.0f) - return ngrid; + //if (ngrid < 0.0f) + // return ngrid; // return ngrid; // return sqrt(ngrid); - return exp2(ngrid) - 1.0f; + return exp2(float(ngrid)) - 1.0f; } float frustumGrid_depthRampInverseVolumeToGrid(float nvolume) { - if (nvolume < 0.0f) - return nvolume; + //if (nvolume < 0.0f) + // return nvolume; // return nvolume; // return nvolume * nvolume; return log2(nvolume + 1.0f); From bd4268ee18d071b2a24adb5a99671d3e1873a2d3 Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 1 Oct 2016 17:59:37 -0700 Subject: [PATCH 050/104] Try to fix the exp2 float version for linux --- libraries/render-utils/src/LightClusterGrid_shared.slh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 7308084b1e..285b80c229 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -1,10 +1,16 @@ // glsl / C++ compatible source as interface for FrustrumGrid +#if defined(Q_OS_LINUX) +#define float_exp2 exp2f +#else +#define float_exp2 exp2 +#endif + float frustumGrid_depthRampGridToVolume(float ngrid) { //if (ngrid < 0.0f) // return ngrid; // return ngrid; // return sqrt(ngrid); - return exp2(float(ngrid)) - 1.0f; + return float_exp2(ngrid) - 1.0f; } float frustumGrid_depthRampInverseVolumeToGrid(float nvolume) { //if (nvolume < 0.0f) From 9a492b3a8889effeb40d62d47df1414ffc49be4a Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 2 Oct 2016 03:43:55 -0700 Subject: [PATCH 051/104] refining the voxelizatoion, tracking one bug where light flickers --- .../src/gpu/gl45/GL45BackendTexture.cpp | 2 +- .../src/LightClusterGrid_shared.slh | 8 ++--- libraries/render-utils/src/LightClusters.cpp | 31 ++++++++++++------- libraries/render-utils/src/LightingModel.slh | 26 +++++++++++++--- .../render-utils/src/local_lights_shading.slf | 23 ++++++++------ 5 files changed, 58 insertions(+), 32 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 3e6e53ffc3..061da3e397 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -513,7 +513,7 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { syncSampler(); size_t oldSize = _size; updateSize(); - Q_ASSERT(_size > oldSize); + // Q_ASSERT(_size > oldSize); // Re-insert into the texture-by-mips map if appropriate diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index 285b80c229..d5bde79056 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -6,16 +6,12 @@ #endif float frustumGrid_depthRampGridToVolume(float ngrid) { - //if (ngrid < 0.0f) - // return ngrid; - // return ngrid; + // return ngrid; // return sqrt(ngrid); return float_exp2(ngrid) - 1.0f; } float frustumGrid_depthRampInverseVolumeToGrid(float nvolume) { - //if (nvolume < 0.0f) - // return nvolume; - // return nvolume; + // return nvolume; // return nvolume * nvolume; return log2(nvolume + 1.0f); } diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 77e0d4d354..cbe5f17856 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -202,7 +202,7 @@ uint32_t scanLightVolumeBox(FrustumGrid& grid, const FrustumGrid::Planes planes[ for (auto z = zMin; (z <= zMax); z++) { for (auto y = yMin; (y <= yMax); y++) { for (auto x = xMin; (x <= xMax); x++) { - auto index = 1 + x + gridPosToOffset.y * y + gridPosToOffset.z * z; + auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * z; clusterGrid[index].emplace_back(lightId); numClustersTouched++; } @@ -220,12 +220,15 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan const auto& yPlanes = planes[1]; const auto& zPlanes = planes[2]; - int center_z = grid.frustumGrid_eyeDepthToClusterLayer(eyePosRadius.z); - int center_y = (yMax + yMin) >> 1; + // FInd the light origin cluster + auto centerCluster = grid.frustumGrid_eyeToClusterPos(glm::vec3(eyePosRadius)); + int center_z = centerCluster.z; + int center_y = centerCluster.y; + for (auto z = zMin; (z <= zMax); z++) { auto zSphere = eyePosRadius; if (z != center_z) { - auto& plane = (z < center_z) ? zPlanes[z + 1] : -zPlanes[z]; + auto plane = (z < center_z) ? zPlanes[z + 1] : -zPlanes[z]; if (!reduceSphereToPlane(zSphere, plane, zSphere)) { // pass this slice! continue; @@ -234,7 +237,7 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan for (auto y = yMin; (y <= yMax); y++) { auto ySphere = zSphere; if (y != center_y) { - auto& plane = (y < center_y) ? yPlanes[y + 1] : -yPlanes[y]; + auto plane = (y < center_y) ? yPlanes[y + 1] : -yPlanes[y]; if (!reduceSphereToPlane(ySphere, plane, ySphere)) { // pass this slice! continue; @@ -262,8 +265,12 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan for (; (x <= xs); x++) { auto index = grid.frustumGrid_clusterToIndex(ivec3(x, y, z)); - clusterGrid[index].emplace_back(lightId); - numClustersTouched++; + if (index < (int) clusterGrid.size()) { + clusterGrid[index].emplace_back(lightId); + numClustersTouched++; + } else { + qDebug() << "WARNING: LightClusters::scanLightVolumeSphere invalid index found ? numClusters = " << clusterGrid.size() << " index = " << index << " found from cluster xyz = " << x << " " << y << " " << z; + } } } } @@ -324,7 +331,7 @@ void LightClusters::updateClusters() { // CLamp the z range zMin = std::max(0, zMin); - + // zMax = std::min(zMax, theFrustumGrid.dims.z); // find 2D corners of the sphere in grid int xMin { 0 }; @@ -362,7 +369,7 @@ void LightClusters::updateClusters() { auto rc = theFrustumGrid.frustumGrid_eyeToClusterDirH(rightDir); xMin = std::max(xMin, lc); - xMax = std::max(0, std::min(rc, xMax)); + xMax = std::min(rc, xMax); } if ((eyeOriLen2V > radius2)) { @@ -385,12 +392,14 @@ void LightClusters::updateClusters() { auto tc = theFrustumGrid.frustumGrid_eyeToClusterDirV(topDir); yMin = std::max(yMin, bc); - yMax = std::max(yMin, std::min(tc, yMax)); + yMax =std::min(tc, yMax); } // now voxelize auto& clusterGrid = (isSpot ? clusterGridSpot : clusterGridPoint); - numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); + // numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); + numClusterTouched += scanLightVolumeBox(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); + } // Lights have been gathered now reexpress in terms of 2 sequential buffers diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index 7303083405..1f5a16afaa 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -241,21 +241,37 @@ void evalFragShading(out vec3 diffuse, out vec3 specular, diffuse *= specularBrdf.y; specular = vec3(specularBrdf.x); } else { - vec4 shading = evalPBRShading(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, roughness); + vec4 shading = evalPBRShadingGloss(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, roughness); diffuse = vec3(shading.w); specular = shading.xyz; } diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled()); } -void evalFragShadingSimpler(out vec3 diffuse, out vec3 specular, + +void evalFragShadingScattering(out vec3 diffuse, out vec3 specular, vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float roughness, vec3 albedo - ,float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature - ) { - vec4 shading = evalPBRShadingGloss(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, roughness); + vec3 brdf = evalSkinBRDF(fragLightDir, fragNormal, midNormalCurvature.xyz, lowNormalCurvature.xyz, lowNormalCurvature.w); + float NdotL = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0); + diffuse = mix(vec3(NdotL), brdf, scattering); + + // Specular Lighting + vec3 halfDir = normalize(fragEyeDir + fragLightDir); + vec2 specularBrdf = skinSpecular(fragNormal, fragLightDir, fragEyeDir, roughness, 1.0); + + diffuse *= specularBrdf.y; + specular = vec3(specularBrdf.x); + diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled()); +} + +void evalFragShadingGloss(out vec3 diffuse, out vec3 specular, + vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, + float metallic, vec3 fresnel, float gloss, vec3 albedo +) { + vec4 shading = evalPBRShadingGloss(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, gloss); diffuse = vec3(shading.w); diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled()); specular = shading.xyz; diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index a4f9d6f24f..128d128188 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -31,6 +31,7 @@ <@include LightClusterGrid.slh@> + in vec2 _texCoord0; out vec4 _fragColor; @@ -94,7 +95,7 @@ void main(void) { // COmpute the rougness into gloss2 once: float fragGloss2 = pow(frag.roughness + 0.001, 2.0); - frag.roughness = fragGloss2; + bool withScattering = (frag.scattering * isScatteringEnabled() > 0.0); int numLightTouching = 0; for (int i = 0; i < cluster.x; i++) { @@ -131,9 +132,12 @@ void main(void) { vec3 lightEnergy = radialAttenuation * getLightIrradiance(light); // Eval shading - evalFragShading(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo - ,frag.scattering, midNormalCurvature, lowNormalCurvature - ); + if (withScattering) { + evalFragShadingScattering(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo + ,frag.scattering, midNormalCurvature, lowNormalCurvature ); + } else { + evalFragShadingGloss(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, fragGloss2, frag.albedo); + } diffuse *= lightEnergy * isDiffuseEnabled(); specular *= lightEnergy * isSpecularEnabled(); @@ -183,17 +187,18 @@ void main(void) { vec3 lightEnergy = radialAttenuation * angularAttenuation * getLightIrradiance(light); // Eval shading - evalFragShading(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo - ,frag.scattering, midNormalCurvature, lowNormalCurvature - ); + if (withScattering) { + evalFragShadingScattering(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo + ,frag.scattering, midNormalCurvature, lowNormalCurvature ); + } else { + evalFragShadingGloss(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, fragGloss2, frag.albedo); + } diffuse *= lightEnergy * isDiffuseEnabled(); specular *= lightEnergy * isSpecularEnabled(); _fragColor.rgb += diffuse; _fragColor.rgb += specular; - - // _fragColor.rgb += vec3(1.0/16.0, 0.0, 0.0); } } From 6f2452815c04b6c265c42bd59ff25f27444b98f4 Mon Sep 17 00:00:00 2001 From: sam Date: Mon, 3 Oct 2016 00:08:30 -0700 Subject: [PATCH 052/104] pass the visibility of the enitity to the LightPaylkoad correctly, clean up the ambient shader --- libraries/audio/src/AudioInjector.cpp | 2 +- .../src/RenderableLightEntityItem.cpp | 3 ++ .../src/gpu/gl45/GL45BackendTexture.cpp | 3 -- libraries/model/src/model/Light.slh | 32 ++++------------- .../src/DeferredLightingEffect.cpp | 36 ++++++++++++++----- .../render-utils/src/DeferredLightingEffect.h | 1 + libraries/render-utils/src/LightAmbient.slh | 1 - libraries/render-utils/src/LightPayload.cpp | 13 +++++-- libraries/render-utils/src/LightPayload.h | 6 +++- 9 files changed, 54 insertions(+), 43 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 43bff3ccce..6f6534e2d2 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -26,7 +26,7 @@ #include "SoundCache.h" #include "AudioSRC.h" -//int audioInjectorPtrMetaTypeId = qRegisterMetaType(); +int audioInjectorPtrMetaTypeId = qRegisterMetaType(); AbstractAudioInterface* AudioInjector::_localAudioInterface{ nullptr }; diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 9f97b7f405..4ae2da295f 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -140,6 +140,9 @@ void RenderableLightEntityItem::updateLightFromEntity(render::PendingChanges& pe void RenderableLightEntityItem::updateRenderItemFromEntity(LightPayload* lightPayload) { auto entity = this; + + lightPayload->setVisible(entity->getVisible()); + auto light = lightPayload->editLight(); light->setPosition(entity->getPosition()); light->setOrientation(entity->getRotation()); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 061da3e397..821d4d14c9 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -511,10 +511,7 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { _minMip = newMinMip; // Re-sync the sampler to force access to the new mip level syncSampler(); - size_t oldSize = _size; updateSize(); - // Q_ASSERT(_size > oldSize); - // Re-insert into the texture-by-mips map if appropriate mipLevels = usedMipLevels(); diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 78fa11416d..d405848d43 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -11,13 +11,10 @@ <@if not MODEL_LIGHT_SLH@> <@def MODEL_LIGHT_SLH@> -<@include model/SphericalHarmonics.shared.slh@> <@include model/LightVolume.shared.slh@> <@include model/LightIrradiance.shared.slh@> // NOw lets define Light - - struct Light { LightVolume volume; LightIrradiance irradiance; @@ -28,38 +25,23 @@ bool light_isSpot(Light l) { return lightVolume_isSpot(l.volume); } vec3 getLightPosition(Light l) { return lightVolume_getPosition(l.volume); } vec3 getLightDirection(Light l) { return lightVolume_getDirection(l.volume); } - vec3 getLightColor(Light l) { return lightIrradiance_getColor(l.irradiance); } float getLightIntensity(Light l) { return lightIrradiance_getIntensity(l.irradiance); } vec3 getLightIrradiance(Light l) { return lightIrradiance_getIrradiance(l.irradiance); } - - - - - - +// AMbient lighting needs extra info provided from a different Buffer +<@include model/SphericalHarmonics.shared.slh@> +// Light Ambient struct LightAmbient { vec4 _ambient; SphericalHarmonics _ambientSphere; }; -SphericalHarmonics getLightAmbientSphere(LightAmbient l) { - return l._ambientSphere; -} +SphericalHarmonics getLightAmbientSphere(LightAmbient l) { return l._ambientSphere; } - -float getLightAmbientIntensity(LightAmbient l) { return l._ambient.w; } - - -bool getLightHasAmbientMap(LightAmbient l) { - return l._ambient.x > 0; - // return l._control.x > 0; -} - -float getLightAmbientMapNumMips(LightAmbient l) { - return l._ambient.x; -} +float getLightAmbientIntensity(LightAmbient l) { return l._ambient.x; } +bool getLightHasAmbientMap(LightAmbient l) { return l._ambient.y > 0; } +float getLightAmbientMapNumMips(LightAmbient l) { return l._ambient.y; } <@func declareLightBuffer(N)@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index b1833764dd..ace969563e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -43,7 +43,6 @@ using namespace render; struct LightLocations { int radius{ -1 }; - int ambientSphere{ -1 }; int lightBufferUnit{ -1 }; int ambientBufferUnit { -1 }; int lightIndexBufferUnit { -1 }; @@ -199,6 +198,22 @@ void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBuff batch.setResourceTexture(skyboxCubemapUnit, keyLight->getAmbientMap()); } } + +void DeferredLightingEffect::unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) { + auto keyLight = _allocatedLights[_globalLights.front()]; + + if (lightBufferUnit >= 0) { + batch.setUniformBuffer(lightBufferUnit, nullptr); + } + if (keyLight->hasAmbient() && (ambientBufferUnit >= 0)) { + batch.setUniformBuffer(ambientBufferUnit, nullptr); + } + + if (keyLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { + batch.setResourceTexture(skyboxCubemapUnit, nullptr); + } +} + static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* fragSource, LightLocationsPtr& locations) { auto VS = gpu::Shader::createVertex(std::string(vertSource)); auto PS = gpu::Shader::createPixel(std::string(fragSource)); @@ -237,7 +252,6 @@ static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* f gpu::Shader::makeProgram(*program, slotBindings); locations->radius = program->getUniforms().findLocation("radius"); - locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00"); locations->texcoordFrameTransform = program->getUniforms().findLocation("texcoordFrameTransform"); @@ -646,15 +660,14 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), args->_viewport); batch._glUniform4fv(locations->texcoordFrameTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform)); - { // Setup the global lighting - deferredLightingEffect->setupKeyLightBatch(batch, locations->lightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT); - } - + // Setup the global lighting + deferredLightingEffect->setupKeyLightBatch(batch, locations->lightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT); + batch.draw(gpu::TRIANGLE_STRIP, 4); - if (keyLight->getAmbientMap()) { - batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr); - } + deferredLightingEffect->unsetKeyLightBatch(batch, locations->lightBufferUnit, locations->ambientBufferUnit, SKYBOX_MAP_UNIT); + + batch.setResourceTexture(SHADOW_MAP_UNIT, nullptr); } } @@ -806,6 +819,11 @@ void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext, batch.setUniformBuffer(SCATTERING_PARAMETERS_BUFFER_SLOT, nullptr); // batch.setUniformBuffer(LIGHTING_MODEL_BUFFER_SLOT, nullptr); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); + + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, nullptr); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, nullptr); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, nullptr); + } auto deferredLightingEffect = DependencyManager::get(); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 1045cab30e..9462dbcc4e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -57,6 +57,7 @@ public: const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI); void setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit); + void unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit); // update global lighting void setGlobalLight(const model::LightPointer& light); diff --git a/libraries/render-utils/src/LightAmbient.slh b/libraries/render-utils/src/LightAmbient.slh index ecb8fa0ae5..98f043081e 100644 --- a/libraries/render-utils/src/LightAmbient.slh +++ b/libraries/render-utils/src/LightAmbient.slh @@ -74,7 +74,6 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie <@endif@> ) { - // Diffuse from ambient diffuse = (1 - metallic) * sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), normal).xyz; diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp index 8f7b893f6a..5f58677efe 100644 --- a/libraries/render-utils/src/LightPayload.cpp +++ b/libraries/render-utils/src/LightPayload.cpp @@ -16,7 +16,12 @@ namespace render { template <> const ItemKey payloadGetKey(const LightPayload::Pointer& payload) { - return ItemKey::Builder::light(); + ItemKey::Builder builder; + builder.withTypeLight(); + if (!payload || !payload->isVisible()) { + builder.withInvisible(); + } + return builder.build(); } template <> const Item::Bound payloadGetBound(const LightPayload::Pointer& payload) { @@ -63,7 +68,9 @@ void LightPayload::render(RenderArgs* args) { _needUpdate = false; } - // FInally, push the light visible in the frame - _stage->_currentFrame.pushLight(_index, _light->getType()); + if (isVisible()) { + // FInally, push the light visible in the frame + _stage->_currentFrame.pushLight(_index, _light->getType()); + } } diff --git a/libraries/render-utils/src/LightPayload.h b/libraries/render-utils/src/LightPayload.h index fba4ff15cb..6b5fe83f07 100644 --- a/libraries/render-utils/src/LightPayload.h +++ b/libraries/render-utils/src/LightPayload.h @@ -27,13 +27,17 @@ public: model::LightPointer editLight() { _needUpdate = true; return _light; } render::Item::Bound& editBound() { _needUpdate = true; return _bound; } - + + void setVisible(bool visible) { _isVisible = visible; } + bool isVisible() const { return _isVisible; } + protected: model::LightPointer _light; render::Item::Bound _bound; LightStagePointer _stage; LightStage::Index _index { LightStage::INVALID_INDEX }; bool _needUpdate { true }; + bool _isVisible{ true }; }; namespace render { From deab1db39a7a2cdc6bef174f7c2b954483695b28 Mon Sep 17 00:00:00 2001 From: sam Date: Mon, 3 Oct 2016 02:53:41 -0700 Subject: [PATCH 053/104] FIxed the flickering bug and make a better debuging view to control the overlap --- libraries/render-utils/src/LightClusters.cpp | 62 ++++++++++---- .../src/lightClusters_drawClusterContent.slf | 84 ++++++++++++++++++- .../render-utils/src/local_lights_shading.slf | 3 - 3 files changed, 126 insertions(+), 23 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index cbe5f17856..2eda0f95a2 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -27,6 +27,10 @@ enum LightClusterGridShader_MapSlot { DEFERRED_BUFFER_LINEAR_DEPTH_UNIT = 0, + DEFERRED_BUFFER_COLOR_UNIT, + DEFERRED_BUFFER_NORMAL_UNIT, + DEFERRED_BUFFER_EMISSIVE_UNIT, + DEFERRED_BUFFER_DEPTH_UNIT, }; enum LightClusterGridShader_BufferSlot { @@ -324,7 +328,7 @@ void LightClusters::updateClusters() { } // Before Range NEar just apss, range neatr == true near for now - if (zMin == -1 || zMax == -1) { + if ((zMin == -1) && (zMax == -1)) { continue; } @@ -397,8 +401,8 @@ void LightClusters::updateClusters() { // now voxelize auto& clusterGrid = (isSpot ? clusterGridSpot : clusterGridPoint); - // numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); - numClusterTouched += scanLightVolumeBox(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); + numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); + // numClusterTouched += scanLightVolumeBox(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); } @@ -539,6 +543,7 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterFromDepthPipeline() slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("linearZeyeMap"), DEFERRED_BUFFER_LINEAR_DEPTH_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), CAMERA_CORRECTION_BUFFER_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT)); @@ -546,9 +551,7 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterFromDepthPipeline() auto state = std::make_shared(); - - // state->setDepthTest(true, false, gpu::LESS_EQUAL); - + // Blend on transparent state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); @@ -560,23 +563,27 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterFromDepthPipeline() const gpu::PipelinePointer DebugLightClusters::getDrawClusterContentPipeline() { if (!_drawClusterContent) { - auto vs = gpu::Shader::createVertex(std::string(lightClusters_drawClusterContent_vert)); + // auto vs = gpu::Shader::createVertex(std::string(lightClusters_drawClusterContent_vert)); + auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); auto ps = gpu::Shader::createPixel(std::string(lightClusters_drawClusterContent_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("clusterGridBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("clusterContentBuffer"), LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("linearZeyeMap"), DEFERRED_BUFFER_LINEAR_DEPTH_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), CAMERA_CORRECTION_BUFFER_SLOT)); + slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); auto state = std::make_shared(); - - state->setDepthTest(true, false, gpu::LESS_EQUAL); - + // Blend on transparent state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); @@ -611,6 +618,14 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co // Then the actual ClusterGrid attributes batch.setModelTransform(Transform()); + + // Bind the G-Buffer surfaces +/* batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, deferredFramebuffer->getDeferredColorTexture()); + batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, deferredFramebuffer->getDeferredNormalTexture()); + batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, deferredFramebuffer->getDeferredSpecularTexture()); + batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, deferredFramebuffer->getPrimaryDepthTexture()); +*/ + batch.setUniformBuffer(LIGHT_GPU_SLOT, lightClusters->_lightStage->_lightArrayBuffer); batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer); batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer); batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer); @@ -626,9 +641,7 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co } batch.draw(gpu::TRIANGLE_STRIP, 4, 0); - - // Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target - + batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); } @@ -637,10 +650,16 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co // bind the one gpu::Pipeline we need batch.setPipeline(getDrawClusterContentPipeline()); + batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer()); - auto dims = lightClusters->_frustumGridBuffer->dims; - glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x); - batch.drawInstanced(summedDims.x, gpu::LINES, 24, 0); + if (linearDepthTarget) { + batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, linearDepthTarget->getLinearDepthTexture()); + } + + batch.draw(gpu::TRIANGLE_STRIP, 4, 0); + + batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); + batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); } if (doDrawGrid) { @@ -651,6 +670,17 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x); batch.drawInstanced(summedDims.x, gpu::LINES, 24, 0); } + + batch.setUniformBuffer(LIGHT_GPU_SLOT, nullptr); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, nullptr); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, nullptr); + batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, nullptr); + + batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, nullptr); + batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, nullptr); + batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, nullptr); + batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, nullptr); + args->_context->appendFrameBatch(batch); } \ No newline at end of file diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slf b/libraries/render-utils/src/lightClusters_drawClusterContent.slf index b31479554f..284e7cb9fe 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slf @@ -1,7 +1,7 @@ <@include gpu/Config.slh@> <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> -// lightClusters_drawClusterContent.slf +// lightClusters_drawClusterFro Depth.slf // // Created by Sam Gateau on 9/8/2016. // Copyright 2015 High Fidelity, Inc. @@ -10,10 +10,86 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -in vec4 varColor; -out vec4 outFragColor; +// Everything about deferred buffer +<@include DeferredBufferRead.slh@> + + +<@include model/Light.slh@> +<$declareLightBuffer(128)$> + +<@include LightClusterGrid.slh@> + +<@include gpu/Color.slh@> +<$declareColorWheel()$> + + +in vec2 varTexCoord0; +out vec4 _fragColor; void main(void) { - outFragColor = varColor; + + // Grab the fragment data from the uv + vec2 texCoord = varTexCoord0.st; + + vec4 fragEyePos = unpackDeferredPositionFromZeye(texCoord); + vec4 fragWorldPos = getViewInverse() * fragEyePos; + + // From frag world pos find the cluster + vec4 clusterEyePos = frustumGrid_worldToEye(fragWorldPos); + ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); + + + ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); + int numLights = cluster.x + cluster.y; + float numLightsScale = clamp(numLights * 0.05, 0.01, 1.0); + + ivec2 clusterAddress = ivec2(numLights, cluster.z); + + ivec3 dims = frustumGrid.dims.xyz; + dims.z +=1; + ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1); + + if (clusterPos.x < 0 || clusterPos.x >= dims.x) { + _fragColor = vec4(0.0); + return; + } + + if (clusterPos.y < 0 || clusterPos.y >= dims.y) { + _fragColor = vec4(0.0); + return; + } + if (clusterPos.z < 0 || clusterPos.z > dims.z) { + _fragColor = vec4(0.0); + return; + } + + int numLightTouching = 0; + for (int i = 0; i < numLights; i++) { + // Need the light now + int theLightIndex = clusterGrid_getClusterLightId(i, clusterAddress); + Light light = getLight(theLightIndex); + + // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space + vec4 fragLightVecLen2; + vec4 fragLightDirLen; + float cosSpotAngle; + + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragWorldPos.xyz, fragLightVecLen2)) { + continue; + } + // Allright we re in the light sphere volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + + // Check spot + if ((i >= cluster.x) && !lightVolume_clipFragToLightVolumeSpotSide(light.volume, fragLightDirLen, cosSpotAngle)) { + continue; + } + + numLightTouching++; + } + + _fragColor = vec4(colorWheel(numLightTouching/20.0f), (numLightTouching > 0 ? 0.5 + 0.5 * numLightsScale : 0.0)); } + diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index 128d128188..b8e70f439d 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -79,9 +79,6 @@ void main(void) { discard; } - - - vec4 midNormalCurvature; vec4 lowNormalCurvature; if (frag.mode == FRAG_MODE_SCATTERING) { From c72b3308211c143731f09ab17b34c7f55638e88b Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 3 Oct 2016 15:34:54 -0700 Subject: [PATCH 054/104] Simple change to the get cluster interface --- libraries/render-utils/src/LightClusterGrid.slh | 4 ++-- .../render-utils/src/lightClusters_drawClusterContent.slf | 4 ++-- libraries/render-utils/src/local_lights_shading.slf | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 3eb3b53ccc..efb38f621e 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -69,8 +69,8 @@ ivec3 clusterGrid_getCluster(int index) { return ivec3(numPointLights, numSpotLights, contentOffset); } -int clusterGrid_getClusterLightId(int index, ivec2 cluster) { - int arrayElement = cluster.y + index; +int clusterGrid_getClusterLightId(int index, int offset) { + int arrayElement = offset + index; int element = _clusterGridContent[arrayElement]; return element; // int element = _clusterGridContent[arrayElement >> 1]; diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slf b/libraries/render-utils/src/lightClusters_drawClusterContent.slf index 284e7cb9fe..3c9f7bad1c 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slf @@ -44,7 +44,7 @@ void main(void) { int numLights = cluster.x + cluster.y; float numLightsScale = clamp(numLights * 0.05, 0.01, 1.0); - ivec2 clusterAddress = ivec2(numLights, cluster.z); + int clusterOffset = cluster.z; ivec3 dims = frustumGrid.dims.xyz; dims.z +=1; @@ -67,7 +67,7 @@ void main(void) { int numLightTouching = 0; for (int i = 0; i < numLights; i++) { // Need the light now - int theLightIndex = clusterGrid_getClusterLightId(i, clusterAddress); + int theLightIndex = clusterGrid_getClusterLightId(i, clusterOffset); Light light = getLight(theLightIndex); // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index b8e70f439d..1522239e7f 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -65,7 +65,6 @@ void main(void) { discard; } int lightClusterOffset = cluster.z; - ivec2 clusterAddress = ivec2(numLights, lightClusterOffset); ivec3 dims = frustumGrid.dims.xyz; if (clusterPos.x < 0 || clusterPos.x >= dims.x) { @@ -97,7 +96,7 @@ void main(void) { int numLightTouching = 0; for (int i = 0; i < cluster.x; i++) { // Need the light now - int theLightIndex = clusterGrid_getClusterLightId(i, clusterAddress); + int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset); Light light = getLight(theLightIndex); // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space @@ -145,7 +144,7 @@ void main(void) { for (int i = cluster.x; i < numLights; i++) { // Need the light now - int theLightIndex = clusterGrid_getClusterLightId(i, clusterAddress); + int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset); Light light = getLight(theLightIndex); // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space From a378a6eccb8105227595ebc3a8ff7aa51840f810 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 3 Oct 2016 18:28:44 -0700 Subject: [PATCH 055/104] separate the rendering of the light outline from the main rendering and introduce a way to support both platform --- .../src/DeferredLightingEffect.cpp | 11 ++ .../render-utils/src/DeferredLightingEffect.h | 2 + .../render-utils/src/LightClusterGrid.slh | 19 ++- libraries/render-utils/src/LightPoint.slh | 21 +++ libraries/render-utils/src/LightSpot.slh | 22 +++ libraries/render-utils/src/LightingModel.h | 3 +- .../src/local_lights_drawOutline.slf | 153 ++++++++++++++++++ 7 files changed, 221 insertions(+), 10 deletions(-) create mode 100644 libraries/render-utils/src/local_lights_drawOutline.slf diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index ace969563e..084ec0e746 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -36,6 +36,7 @@ #include "directional_skybox_light_shadow_frag.h" #include "local_lights_shading_frag.h" +#include "local_lights_drawOutline_frag.h" #include "point_light_frag.h" #include "spot_light_frag.h" @@ -103,6 +104,7 @@ void DeferredLightingEffect::init() { _directionalSkyboxLightShadowLocations = std::make_shared(); _localLightLocations = std::make_shared(); + _localLightOutlineLocations = std::make_shared(); _pointLightLocations = std::make_shared(); _spotLightLocations = std::make_shared(); @@ -115,6 +117,7 @@ void DeferredLightingEffect::init() { loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations); + loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations); loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, false, _pointLightBack, _pointLightLocations); loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, true, _pointLightFront, _pointLightLocations); @@ -795,6 +798,14 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch._glUniform4fv(deferredLightingEffect->_localLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); batch.draw(gpu::TRIANGLE_STRIP, 4); + + // Draw outline as well ? + if (lightingModel->isShowLightContourEnabled()) { + batch.setPipeline(deferredLightingEffect->_localLightOutline); + batch._glUniform4fv(deferredLightingEffect->_localLightOutlineLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); + + batch.draw(gpu::TRIANGLE_STRIP, 4); + } } } } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 9462dbcc4e..d2b8dd42b2 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -90,6 +90,7 @@ private: gpu::PipelinePointer _directionalLightShadow; gpu::PipelinePointer _localLight; + gpu::PipelinePointer _localLightOutline; gpu::PipelinePointer _pointLightBack; gpu::PipelinePointer _pointLightFront; @@ -105,6 +106,7 @@ private: LightLocationsPtr _directionalLightShadowLocations; LightLocationsPtr _localLightLocations; + LightLocationsPtr _localLightOutlineLocations; LightLocationsPtr _pointLightLocations; LightLocationsPtr _spotLightLocations; diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index efb38f621e..80203ef49b 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -49,20 +49,24 @@ float projection_getFar(mat4 projection) { <@if GLPROFILE == MAC_GL @> #define GRID_NUM_ELEMENTS 4096 +#define GRID_INDEX_TYPE ivec4 +#define GRID_FETCH_BUFFER(i) i / 4][i % 4 <@else@> #define GRID_NUM_ELEMENTS 16384 +#define GRID_INDEX_TYPE int +#define GRID_FETCH_BUFFER(i) i <@endif@> uniform clusterGridBuffer { - int _clusterGridTable[GRID_NUM_ELEMENTS]; + GRID_INDEX_TYPE _clusterGridTable[GRID_NUM_ELEMENTS]; }; uniform clusterContentBuffer { - int _clusterGridContent[GRID_NUM_ELEMENTS]; + GRID_INDEX_TYPE _clusterGridContent[GRID_NUM_ELEMENTS]; }; ivec3 clusterGrid_getCluster(int index) { - int clusterDesc = _clusterGridTable[index]; + int clusterDesc = _clusterGridTable[GRID_FETCH_BUFFER(index)]; int numPointLights = 0xFF & (clusterDesc >> 16); int numSpotLights = 0xFF & (clusterDesc >> 24); int contentOffset = 0xFFFF & (clusterDesc); @@ -70,12 +74,11 @@ ivec3 clusterGrid_getCluster(int index) { } int clusterGrid_getClusterLightId(int index, int offset) { - int arrayElement = offset + index; - int element = _clusterGridContent[arrayElement]; + int elementIndex = offset + index; + int element = _clusterGridContent[GRID_FETCH_BUFFER(elementIndex)]; return element; -// int element = _clusterGridContent[arrayElement >> 1]; - -// return (((arrayElement & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF; + //int element = _clusterGridContent[GRID_FETCH_BUFFER(elementIndex)]; + // return (((elementIndex & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF; } <@endif@> diff --git a/libraries/render-utils/src/LightPoint.slh b/libraries/render-utils/src/LightPoint.slh index 5160396e8a..431731ec18 100644 --- a/libraries/render-utils/src/LightPoint.slh +++ b/libraries/render-utils/src/LightPoint.slh @@ -50,3 +50,24 @@ void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light, <@endfunc@> +<@func declareDrawPointOutline()@> + +bool evalLightPointEdge(out vec3 color, Light light, vec4 fragLightDirLen, vec3 fragEyeDir) { + // Allright we re valid in the volume + float fragLightDistance = fragLightDirLen.w; + vec3 fragLightDir = fragLightDirLen.xyz; + + // Show edges + float edge = abs(2.0 * ((lightVolume_getRadius(light.volume) - fragLightDistance) / (0.1)) - 1.0); + if (edge < 1) { + float edgeCoord = exp2(-8.0*edge*edge); + color = vec3(edgeCoord * edgeCoord * getLightColor(light)); + } + + return (edge < 1); +} + +<@endfunc@> + + + diff --git a/libraries/render-utils/src/LightSpot.slh b/libraries/render-utils/src/LightSpot.slh index a3be944494..6ce21f8823 100644 --- a/libraries/render-utils/src/LightSpot.slh +++ b/libraries/render-utils/src/LightSpot.slh @@ -54,4 +54,26 @@ void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light, <@endfunc@> +<@func declareDrawSpotOutline()@> + +bool evalLightSpotEdge(out vec3 color, Light light, vec4 fragLightDirLen, float cosSpotAngle, vec3 fragEyeDir) { + // Allright we re valid in the volume + float fragLightDistance = fragLightDirLen.w; + vec3 fragLightDir = fragLightDirLen.xyz; + + // Show edges + float edgeDistR = (lightVolume_getRadius(light.volume) - fragLightDistance); + float edgeDistS = dot(fragLightDistance * vec2(cosSpotAngle, sqrt(1.0 - cosSpotAngle * cosSpotAngle)), -lightVolume_getSpotOutsideNormal2(light.volume)); + float edgeDist = min(edgeDistR, edgeDistS); + float edge = abs(2.0 * (edgeDist / (0.1)) - 1.0); + if (edge < 1) { + float edgeCoord = exp2(-8.0*edge*edge); + color = vec3(edgeCoord * edgeCoord * getLightColor(light)); + } + + return (edge < 1); +} + +<@endfunc@> + diff --git a/libraries/render-utils/src/LightingModel.h b/libraries/render-utils/src/LightingModel.h index 5bb0e621a4..8f3ee9b7d6 100644 --- a/libraries/render-utils/src/LightingModel.h +++ b/libraries/render-utils/src/LightingModel.h @@ -143,8 +143,7 @@ public: bool enablePointLight{ true }; bool enableSpotLight{ true }; - // bool showLightContour { false }; // false by default - bool showLightContour { true }; // false by default + bool showLightContour { false }; // false by default signals: void dirty(); diff --git a/libraries/render-utils/src/local_lights_drawOutline.slf b/libraries/render-utils/src/local_lights_drawOutline.slf new file mode 100644 index 0000000000..3aa210a241 --- /dev/null +++ b/libraries/render-utils/src/local_lights_drawOutline.slf @@ -0,0 +1,153 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// local_lights_drawOutline.frag +// fragment shader +// +// Created by Sam Gateau on 9/6/2016. +// Copyright 2014 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 +// + +// Everything about deferred buffer +<@include DeferredBufferRead.slh@> + +<$declareDeferredCurvature()$> + +// Everything about light +<@include model/Light.slh@> +<$declareLightBuffer(128)$> +<@include LightingModel.slh@> + + +<@include LightPoint.slh@> +<$declareDrawPointOutline()$> +<@include LightSpot.slh@> +<$declareDrawSpotOutline()$> + +<@include LightClusterGrid.slh@> + + + +in vec2 _texCoord0; +out vec4 _fragColor; + +void main(void) { + + // Grab the fragment data from the uv + vec2 texCoord = _texCoord0.st; + + vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord); + DeferredFragment frag = unpackDeferredFragmentNoPosition(texCoord); + + if (frag.mode == FRAG_MODE_UNLIT) { + discard; + } + + frag.position = fragPosition; + + + // Frag pos in world + mat4 invViewMat = getViewInverse(); + vec4 fragPos = invViewMat * fragPosition; + + // From frag world pos find the cluster + vec4 clusterEyePos = frustumGrid_worldToEye(fragPos); + ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); + + ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); + int numLights = cluster.x + cluster.y; + if (numLights <= 0) { + discard; + } + int lightClusterOffset = cluster.z; + + ivec3 dims = frustumGrid.dims.xyz; + if (clusterPos.x < 0 || clusterPos.x >= dims.x) { + discard; + } + + if (clusterPos.y < 0 || clusterPos.y >= dims.y) { + discard; + } + if (clusterPos.z < 0 || clusterPos.z > dims.z) { + discard; + } + + // Frag to eye vec + vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); + vec3 fragEyeDir = normalize(fragEyeVector.xyz); + + int numLightTouching = 0; + for (int i = 0; i < cluster.x; i++) { + // Need the light now + int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset); + Light light = getLight(theLightIndex); + + // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space + vec4 fragLightVecLen2; + vec4 fragLightDirLen; + + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { + continue; + } + + // Allright we re in the light sphere volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + if (dot(frag.normal, fragLightDirLen.xyz) < 0.0) { + continue; + } + + numLightTouching++; + + // Allright we re valid in the volume + float fragLightDistance = fragLightDirLen.w; + vec3 fragLightDir = fragLightDirLen.xyz; + + vec3 color = vec3(0.0); + if (evalLightPointEdge(color, light, fragLightDirLen, fragEyeDir)) { + _fragColor.rgb += color; + } + } + + for (int i = cluster.x; i < numLights; i++) { + // Need the light now + int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset); + Light light = getLight(theLightIndex); + + // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space + vec4 fragLightVecLen2; + vec4 fragLightDirLen; + float cosSpotAngle; + + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { + continue; + } + + // Allright we re in the light sphere volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + if (dot(frag.normal, fragLightDirLen.xyz) < 0.0) { + continue; + } + + // Check spot + if (!lightVolume_clipFragToLightVolumeSpotSide(light.volume, fragLightDirLen, cosSpotAngle)) { + continue; + } + + numLightTouching++; + + vec3 color = vec3(0.0); + + if (evalLightSpotEdge(color, light, fragLightDirLen, cosSpotAngle, fragEyeDir)) { + _fragColor.rgb += color; + } + } + +} + From 6aa39ec95a840fa03e6b82cd2a100ec9da4cd7ec Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 4 Oct 2016 11:03:12 -0700 Subject: [PATCH 056/104] Polish the debugging of the light volumes --- libraries/gpu/src/gpu/Color.slh | 19 +++++++++ libraries/render-utils/src/LightClusters.cpp | 42 ++++++++++++------- .../src/lightClusters_drawClusterContent.slf | 2 +- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/libraries/gpu/src/gpu/Color.slh b/libraries/gpu/src/gpu/Color.slh index 4330b34b90..526cc3dd46 100644 --- a/libraries/gpu/src/gpu/Color.slh +++ b/libraries/gpu/src/gpu/Color.slh @@ -46,6 +46,25 @@ vec3 colorWheel(float normalizedHue) { return vec3(1.f, 0.f, 0.f); } } + +vec3 colorRamp(float normalizedHue) { + float v = normalizedHue * 5.f; + if (v < 0.f) { + return vec3(1.f, 0.f, 0.f); + } else if (v < 1.f) { + return vec3(1.f, v, 0.f); + } else if (v < 2.f) { + return vec3(1.f - (v - 1.f), 1.f, 0.f); + } else if (v < 3.f) { + return vec3(0.f, 1.f, (v - 2.f)); + } else if (v < 4.f) { + return vec3(0.f, 1.f - (v - 3.f), 1.f); + } else if (v < 5.f) { + return vec3((v - 4.f), 0.f, 1.f); + } else { + return vec3(1.f, 0.f, 1.f); + } +} <@endfunc@> <@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 2eda0f95a2..b7ab88f119 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -429,7 +429,6 @@ void LightClusters::updateClusters() { } } - // _clusterGrid[i] = (uint32_t)((numLights << 16) | offset); _clusterGrid[i] = (uint32_t)((0xFF000000 & (numLightsSpot << 24)) | (0x00FF0000 & (numLightsPoint << 16)) | (0x0000FFFF & offset)); @@ -595,16 +594,23 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterContentPipeline() { void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs) { + if (!(doDrawClusterFromDepth || doDrawContent || doDrawGrid)) { + return; + } + auto deferredTransform = inputs.get0(); auto deferredFramebuffer = inputs.get1(); auto lightingModel = inputs.get2(); auto linearDepthTarget = inputs.get3(); auto lightClusters = inputs.get4(); - + auto args = renderContext->args; - + gpu::Batch batch; + batch.enableStereo(false); + + // Assign the camera transform batch.setViewportTransform(args->_viewport); glm::mat4 projMat; @@ -661,26 +667,30 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr); batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr); } - + + + + gpu::Batch drawGridAndCleanBatch; + if (doDrawGrid) { // bind the one gpu::Pipeline we need - batch.setPipeline(getDrawClusterGridPipeline()); - + drawGridAndCleanBatch.setPipeline(getDrawClusterGridPipeline()); + auto dims = lightClusters->_frustumGridBuffer->dims; glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x); - batch.drawInstanced(summedDims.x, gpu::LINES, 24, 0); + drawGridAndCleanBatch.drawInstanced(summedDims.x, gpu::LINES, 24, 0); } - batch.setUniformBuffer(LIGHT_GPU_SLOT, nullptr); - batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, nullptr); - batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, nullptr); - batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, nullptr); + drawGridAndCleanBatch.setUniformBuffer(LIGHT_GPU_SLOT, nullptr); + drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, nullptr); + drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, nullptr); + drawGridAndCleanBatch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, nullptr); - batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, nullptr); - batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, nullptr); - batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, nullptr); - batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, nullptr); + drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, nullptr); + drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, nullptr); + drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, nullptr); + drawGridAndCleanBatch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, nullptr); args->_context->appendFrameBatch(batch); - + args->_context->appendFrameBatch(drawGridAndCleanBatch); } \ No newline at end of file diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slf b/libraries/render-utils/src/lightClusters_drawClusterContent.slf index 3c9f7bad1c..fe8d850e8a 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slf @@ -90,6 +90,6 @@ void main(void) { numLightTouching++; } - _fragColor = vec4(colorWheel(numLightTouching/20.0f), (numLightTouching > 0 ? 0.5 + 0.5 * numLightsScale : 0.0)); + _fragColor = vec4(colorRamp(1.0 - (numLightTouching / 12.0f)), (numLightTouching > 0 ? 0.5 + 0.5 * numLightsScale : 0.0)); } From 1c2a6722149ea66b50543041fe1488e2670d5fb8 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 4 Oct 2016 13:29:08 -0700 Subject: [PATCH 057/104] Adjust the grid size for mac --- libraries/render-utils/src/LightClusters.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index b7ab88f119..6d6ea005d5 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -74,7 +74,7 @@ void FrustumGrid::generateGridPlanes(Planes& xPlanes, Planes& yPlanes, Planes& z #include "DeferredLightingEffect.h" #ifdef Q_OS_MAC -const glm::uvec4 LightClusters::MAX_GRID_DIMENSIONS { 8, 8, 8, 4096 }; +const glm::uvec4 LightClusters::MAX_GRID_DIMENSIONS { 16, 16, 16, 16384 }; #else const glm::uvec4 LightClusters::MAX_GRID_DIMENSIONS { 32, 32, 31, 16384 }; #endif From 3e11eb41296cee3913348a77f9a01d4a7c2d14b5 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 4 Oct 2016 13:55:53 -0700 Subject: [PATCH 058/104] Try avoiding the basd update of the buffer for the grid content --- libraries/render-utils/src/LightClusters.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 6d6ea005d5..d3c7e40d48 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -444,7 +444,10 @@ void LightClusters::updateClusters() { // update the buffers _clusterGridBuffer._buffer->setData(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()); - _clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(LightIndex), (gpu::Byte*) _clusterContent.data()); + //_clusterGridBuffer._buffer->setSubData(0, _clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()); + _clusterContentBuffer._buffer->setData(indexOffset * sizeof(LightIndex), (gpu::Byte*) _clusterContent.data()); + + // _clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(LightIndex), (gpu::Byte*) _clusterContent.data()); } From 8c561eaa44b47dcdacc7461e94c3f4dcc082099d Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 4 Oct 2016 18:19:42 -0700 Subject: [PATCH 059/104] trying to whipe these buffer cleans but doesn;t seems to make a different in release, it is working clena in debug ... keep on looking --- .../render-utils/src/LightClusterGrid.slh | 1 - libraries/render-utils/src/LightClusters.cpp | 20 +++++++++++-------- .../render-utils/src/local_lights_shading.slf | 1 - 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 80203ef49b..24d4a8fbc8 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -46,7 +46,6 @@ float projection_getFar(mat4 projection) { // end of hybrid include - <@if GLPROFILE == MAC_GL @> #define GRID_NUM_ELEMENTS 4096 #define GRID_INDEX_TYPE ivec4 diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index d3c7e40d48..a29357f493 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -82,8 +82,8 @@ const glm::uvec4 LightClusters::MAX_GRID_DIMENSIONS { 32, 32, 31, 16384 }; LightClusters::LightClusters() : _lightIndicesBuffer(std::make_shared()), - _clusterGridBuffer(std::make_shared(), gpu::Element::INDEX_INT32), - _clusterContentBuffer(std::make_shared(), gpu::Element::INDEX_INT32) { + _clusterGridBuffer(/*std::make_shared(), */gpu::Element::INDEX_INT32), + _clusterContentBuffer(/*std::make_shared(), */gpu::Element::INDEX_INT32) { auto dims = _frustumGridBuffer.edit().dims; _frustumGridBuffer.edit().dims = ivec3(0); // make sure we go through the full reset of the dimensionts ion the setDImensions call setDimensions(dims, MAX_GRID_DIMENSIONS.w); @@ -113,14 +113,19 @@ void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { _numClusters = numClusters; _clusterGrid.clear(); _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); - _clusterGridBuffer._size = _clusterGridBuffer._buffer->resize(_numClusters * sizeof(uint32_t)); + // _clusterGridBuffer._size = _clusterGridBuffer._buffer->resize(_numClusters * sizeof(uint32_t)); + _clusterGridBuffer._size = (_numClusters * sizeof(uint32_t)); + _clusterGridBuffer._buffer = std::make_shared(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()/*, _clusterGridBuffer._size*/); } auto configListBudget = std::min(MAX_GRID_DIMENSIONS.w, listBudget); if (configListBudget != _clusterContentBuffer.getNumElements()) { _clusterContent.clear(); _clusterContent.resize(configListBudget, INVALID_LIGHT); - _clusterContentBuffer._size = _clusterContentBuffer._buffer->resize(configListBudget * sizeof(LightIndex)); + // _clusterContentBuffer._size = _clusterContentBuffer._buffer->resize(configListBudget * sizeof(LightIndex)); + _clusterContentBuffer._size = (configListBudget * sizeof(LightIndex)); + // _clusterContentBuffer._buffer->setData(_clusterContentBuffer._size, (gpu::Byte*) _clusterContent.data()); + _clusterContentBuffer._buffer = std::make_shared(_clusterContentBuffer._size, (gpu::Byte*) _clusterContent.data()/*, _clusterContentBuffer._size*/); } } @@ -287,8 +292,10 @@ void LightClusters::updateClusters() { std::vector< std::vector< LightIndex > > clusterGridPoint(_numClusters); std::vector< std::vector< LightIndex > > clusterGridSpot(_numClusters); + _clusterGrid.clear(); _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); uint32_t maxNumIndices = (uint32_t) _clusterContent.size(); + _clusterContent.clear(); _clusterContent.resize(maxNumIndices, INVALID_LIGHT); auto theFrustumGrid(_frustumGridBuffer.get()); @@ -444,10 +451,7 @@ void LightClusters::updateClusters() { // update the buffers _clusterGridBuffer._buffer->setData(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()); - //_clusterGridBuffer._buffer->setSubData(0, _clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()); - _clusterContentBuffer._buffer->setData(indexOffset * sizeof(LightIndex), (gpu::Byte*) _clusterContent.data()); - - // _clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(LightIndex), (gpu::Byte*) _clusterContent.data()); + _clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(LightIndex), (gpu::Byte*) _clusterContent.data()); } diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index 1522239e7f..c7d49de979 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -31,7 +31,6 @@ <@include LightClusterGrid.slh@> - in vec2 _texCoord0; out vec4 _fragColor; From ba88db1b14d3e3a72637304c5b65ff535f8d0a9c Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 5 Oct 2016 18:28:19 -0700 Subject: [PATCH 060/104] Tried many different things to narrow down the issue of the corrupted memory, it seems to be linked to the grid dimendsions somehow, i m now forcing to reassign the frustum grid dimension on the 10th iteration which seems to fix the issue.... --- libraries/gpu/src/gpu/Buffer.cpp | 3 ++- .../render-utils/src/LightClusterGrid.slh | 6 +++-- libraries/render-utils/src/LightClusters.cpp | 26 ++++++++++++++----- libraries/render-utils/src/LightClusters.h | 24 +++++++++++------ libraries/render-utils/src/LightStage.cpp | 2 +- .../render-utils/src/deferred_light_point.slv | 4 +-- .../render-utils/src/deferred_light_spot.slv | 4 +-- .../src/lightClusters_drawClusterContent.slf | 2 +- .../render-utils/src/local_lights_shading.slf | 2 +- libraries/render-utils/src/spot_light.slf | 4 +-- .../utilities/render/lightClustering.qml | 3 +++ 11 files changed, 53 insertions(+), 27 deletions(-) diff --git a/libraries/gpu/src/gpu/Buffer.cpp b/libraries/gpu/src/gpu/Buffer.cpp index f4cd9e41ba..fb60e0e737 100644 --- a/libraries/gpu/src/gpu/Buffer.cpp +++ b/libraries/gpu/src/gpu/Buffer.cpp @@ -42,7 +42,8 @@ Buffer::Size Buffer::getBufferGPUMemoryUsage() { } Buffer::Buffer(Size pageSize) : - _pages(pageSize) { + _pages(pageSize), + _renderPages(pageSize) { _bufferCPUCount++; } diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 24d4a8fbc8..3cd3bec473 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -74,10 +74,12 @@ ivec3 clusterGrid_getCluster(int index) { int clusterGrid_getClusterLightId(int index, int offset) { int elementIndex = offset + index; + /* int element = _clusterGridContent[GRID_FETCH_BUFFER(elementIndex)]; return element; - //int element = _clusterGridContent[GRID_FETCH_BUFFER(elementIndex)]; - // return (((elementIndex & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF; + */ + int element = _clusterGridContent[GRID_FETCH_BUFFER((elementIndex >> 1))]; + return (((elementIndex & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF; } <@endif@> diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index a29357f493..98615a72ff 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -101,9 +101,10 @@ void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { configDimensions.z = std::min(maxNumSlices, configDimensions.z); - + static int numFrames = 0; + numFrames++; auto& dims = _frustumGridBuffer->dims; - if ((dims.x != configDimensions.x) || (dims.y != configDimensions.y) || (dims.z != configDimensions.z)) { + if ((numFrames == 10) || (dims.x != configDimensions.x) || (dims.y != configDimensions.y) || (dims.z != configDimensions.z)) { _frustumGridBuffer.edit().dims = configDimensions; _frustumGridBuffer.edit().generateGridPlanes(_gridPlanes[0], _gridPlanes[1], _gridPlanes[2]); } @@ -115,17 +116,23 @@ void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); // _clusterGridBuffer._size = _clusterGridBuffer._buffer->resize(_numClusters * sizeof(uint32_t)); _clusterGridBuffer._size = (_numClusters * sizeof(uint32_t)); - _clusterGridBuffer._buffer = std::make_shared(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()/*, _clusterGridBuffer._size*/); + _clusterGridBuffer._buffer = std::make_shared(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data(), _clusterGridBuffer._size); } auto configListBudget = std::min(MAX_GRID_DIMENSIONS.w, listBudget); - if (configListBudget != _clusterContentBuffer.getNumElements()) { + + // SInce LightINdex is 2bytes, we can fit 2 in a uint32 + if (sizeof(LightIndex) == 2) { + configListBudget *= 2; + } + + if (configListBudget != _clusterContent.size()) { _clusterContent.clear(); _clusterContent.resize(configListBudget, INVALID_LIGHT); // _clusterContentBuffer._size = _clusterContentBuffer._buffer->resize(configListBudget * sizeof(LightIndex)); _clusterContentBuffer._size = (configListBudget * sizeof(LightIndex)); // _clusterContentBuffer._buffer->setData(_clusterContentBuffer._size, (gpu::Byte*) _clusterContent.data()); - _clusterContentBuffer._buffer = std::make_shared(_clusterContentBuffer._size, (gpu::Byte*) _clusterContent.data()/*, _clusterContentBuffer._size*/); + _clusterContentBuffer._buffer = std::make_shared(_clusterContentBuffer._size, (gpu::Byte*) _clusterContent.data(), _clusterContentBuffer._size); } } @@ -287,7 +294,7 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan return numClustersTouched; } -void LightClusters::updateClusters() { +uint32_t LightClusters::updateClusters() { // Clean up last info std::vector< std::vector< LightIndex > > clusterGridPoint(_numClusters); std::vector< std::vector< LightIndex > > clusterGridSpot(_numClusters); @@ -452,6 +459,8 @@ void LightClusters::updateClusters() { // update the buffers _clusterGridBuffer._buffer->setData(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()); _clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(LightIndex), (gpu::Byte*) _clusterContent.data()); + + return numClusterTouched; } @@ -492,9 +501,12 @@ void LightClusteringPass::run(const render::SceneContextPointer& sceneContext, c _lightClusters->updateLightStage(lightStage); _lightClusters->updateLightFrame(lightStage->_currentFrame, lightingModel->isPointLightEnabled(), lightingModel->isSpotLightEnabled()); - _lightClusters->updateClusters(); + auto numClusterdLights = _lightClusters->updateClusters(); output = _lightClusters; + + auto config = std::static_pointer_cast(renderContext->jobConfig); + config->setNumClusteredLights(numClusterdLights); } DebugLightClusters::DebugLightClusters() { diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 5c52d44ff1..e01d6c42f7 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -24,7 +24,8 @@ public: float rangeFar { 200.0f }; float frustumFar { 10000.0f }; - glm::ivec3 dims { 16, 12, 16 }; + // glm::ivec3 dims { 16, 16, 16 }; + glm::ivec3 dims { 16, 16, 16 }; float spare; glm::mat4 eyeToGridProj; @@ -74,7 +75,7 @@ public: void updateLightFrame(const LightStage::Frame& lightFrame, bool points = true, bool spots = true); - void updateClusters(); + uint32_t updateClusters(); ViewFrustum _frustum; @@ -94,15 +95,12 @@ public: const uint32_t EMPTY_CLUSTER { 0x0000FFFF }; const LightID INVALID_LIGHT { LightStage::INVALID_INDEX }; - using LightIndex = uint32_t; + using LightIndex = uint16_t; std::vector _clusterGrid; std::vector _clusterContent; gpu::BufferView _clusterGridBuffer; gpu::BufferView _clusterContentBuffer; - - - }; using LightClustersPointer = std::shared_ptr; @@ -119,17 +117,26 @@ class LightClusteringPassConfig : public render::Job::Config { Q_PROPERTY(int dimZ MEMBER dimZ NOTIFY dirty) Q_PROPERTY(bool freeze MEMBER freeze NOTIFY dirty) + + Q_PROPERTY(int numClusteredLights MEMBER numClusteredLights NOTIFY dirty) public: LightClusteringPassConfig() : render::Job::Config(true){} float rangeNear{ 0.1f }; float rangeFar{ 200.0f }; - + /* + int dimX { 16 }; + int dimY { 16 }; + int dimZ { 16 }; + */ int dimX { 16 }; int dimY { 16 }; int dimZ { 16 }; + bool freeze{ false }; + void setNumClusteredLights(int numLights) { numClusteredLights = numLights; emit dirty(); } + int numClusteredLights { 0 }; signals: void dirty(); @@ -175,7 +182,8 @@ public: bool doDrawGrid{ false }; bool doDrawClusterFromDepth { false }; - bool doDrawContent { false }; + // bool doDrawContent { false }; + bool doDrawContent { true }; signals: void dirty(); diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index bedd22b360..8c6e6d96a4 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -136,7 +136,7 @@ LightStage::LightPointer LightStage::removeLight(Index index) { void LightStage::updateLightArrayBuffer(Index lightId) { auto lightSize = sizeof(model::Light::LightSchema); if (!_lightArrayBuffer) { - _lightArrayBuffer = std::make_shared(); + _lightArrayBuffer = std::make_shared(lightSize); } assert(checkLightId(lightId)); diff --git a/libraries/render-utils/src/deferred_light_point.slv b/libraries/render-utils/src/deferred_light_point.slv index f126ee9251..88da7dd04c 100644 --- a/libraries/render-utils/src/deferred_light_point.slv +++ b/libraries/render-utils/src/deferred_light_point.slv @@ -20,10 +20,10 @@ <@include model/Light.slh@> -<$declareLightBuffer(120)$> +<$declareLightBuffer(256)$> uniform lightIndexBuffer { - int lightIndex[120]; + int lightIndex[256]; }; out vec4 _texCoord0; diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index 5edd889704..f9e81549dd 100755 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -19,10 +19,10 @@ <$declareStandardTransform()$> <@include model/Light.slh@> -<$declareLightBuffer(120)$> +<$declareLightBuffer(256)$> uniform lightIndexBuffer { - int lightIndex[120]; + int lightIndex[256]; }; out vec4 _texCoord0; diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slf b/libraries/render-utils/src/lightClusters_drawClusterContent.slf index fe8d850e8a..f4b9a82b64 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slf @@ -16,7 +16,7 @@ <@include model/Light.slh@> -<$declareLightBuffer(128)$> +<$declareLightBuffer(256)$> <@include LightClusterGrid.slh@> diff --git a/libraries/render-utils/src/local_lights_shading.slf b/libraries/render-utils/src/local_lights_shading.slf index c7d49de979..b144ce13c7 100644 --- a/libraries/render-utils/src/local_lights_shading.slf +++ b/libraries/render-utils/src/local_lights_shading.slf @@ -19,7 +19,7 @@ // Everything about light <@include model/Light.slh@> -<$declareLightBuffer(128)$> +<$declareLightBuffer(256)$> <@include LightingModel.slh@> diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 9d71832f15..4cacff86c4 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -19,9 +19,9 @@ // Everything about light <@include model/Light.slh@> -<$declareLightBuffer(32)$> +<$declareLightBuffer(256)$> uniform lightIndexBuffer { - int lightIndex[32]; + int lightIndex[256]; }; <@include LightingModel.slh@> diff --git a/scripts/developer/utilities/render/lightClustering.qml b/scripts/developer/utilities/render/lightClustering.qml index c772b9e88d..427a818239 100644 --- a/scripts/developer/utilities/render/lightClustering.qml +++ b/scripts/developer/utilities/render/lightClustering.qml @@ -106,6 +106,9 @@ Column { checked: Render.getConfig("DebugLightClusters")["doDrawContent"] onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawContent"] = checked } } + Label { + text: "Num Cluster Items = " + Render.getConfig("LightClustering")["numClusteredLights"].toFixed(0) + } } } From 765355e5d1956eefe1695c377794ba7b6f0c53d1 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 5 Oct 2016 18:30:03 -0700 Subject: [PATCH 061/104] Avoid the debug view by default --- libraries/render-utils/src/LightClusters.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index e01d6c42f7..5402339563 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -24,7 +24,6 @@ public: float rangeFar { 200.0f }; float frustumFar { 10000.0f }; - // glm::ivec3 dims { 16, 16, 16 }; glm::ivec3 dims { 16, 16, 16 }; float spare; @@ -123,11 +122,7 @@ public: LightClusteringPassConfig() : render::Job::Config(true){} float rangeNear{ 0.1f }; float rangeFar{ 200.0f }; - /* - int dimX { 16 }; - int dimY { 16 }; - int dimZ { 16 }; - */ + int dimX { 16 }; int dimY { 16 }; int dimZ { 16 }; @@ -182,9 +177,8 @@ public: bool doDrawGrid{ false }; bool doDrawClusterFromDepth { false }; - // bool doDrawContent { false }; - bool doDrawContent { true }; - + bool doDrawContent { false }; + signals: void dirty(); From 621d62cdf8bc89a5e8f8b3a646ec13deb07f1878 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 6 Oct 2016 09:53:12 -0700 Subject: [PATCH 062/104] Merge and fix the linux warning --- libraries/gpu/src/gpu/Buffer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/gpu/src/gpu/Buffer.cpp b/libraries/gpu/src/gpu/Buffer.cpp index fb60e0e737..018788365d 100644 --- a/libraries/gpu/src/gpu/Buffer.cpp +++ b/libraries/gpu/src/gpu/Buffer.cpp @@ -42,8 +42,8 @@ Buffer::Size Buffer::getBufferGPUMemoryUsage() { } Buffer::Buffer(Size pageSize) : - _pages(pageSize), - _renderPages(pageSize) { + _renderPages(pageSize), + _pages(pageSize) { _bufferCPUCount++; } From 4504877ba6f30e899892bd771d1dd614fae00abe Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 6 Oct 2016 15:14:08 -0700 Subject: [PATCH 063/104] Add a finer culling test to avoid faulty discards --- libraries/render-utils/src/LightClusters.cpp | 60 +++++++++++++++++--- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 98615a72ff..e51d8f2e4d 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -210,6 +210,23 @@ bool reduceSphereToPlane(const glm::vec4& sphere, const glm::vec4& plane, glm::v return false; } + +uint32_t scanLightVolumeBoxSlice(FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zSlice, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, + std::vector< std::vector>& clusterGrid) { + glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); + uint32_t numClustersTouched = 0; + + for (auto y = yMin; (y <= yMax); y++) { + for (auto x = xMin; (x <= xMax); x++) { + auto index = x + gridPosToOffset.y * y + gridPosToOffset.z * zSlice; + clusterGrid[index].emplace_back(lightId); + numClustersTouched++; + } + } + + return numClustersTouched; +} + uint32_t scanLightVolumeBox(FrustumGrid& grid, const FrustumGrid::Planes planes[3], int zMin, int zMax, int yMin, int yMax, int xMin, int xMax, LightClusters::LightID lightId, const glm::vec4& eyePosRadius, std::vector< std::vector>& clusterGrid) { glm::ivec3 gridPosToOffset(1, grid.dims.x, grid.dims.x * grid.dims.y); @@ -281,7 +298,7 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan for (; (x <= xs); x++) { auto index = grid.frustumGrid_clusterToIndex(ivec3(x, y, z)); - if (index < (int) clusterGrid.size()) { + if (index < (int)clusterGrid.size()) { clusterGrid[index].emplace_back(lightId); numClustersTouched++; } else { @@ -301,7 +318,7 @@ uint32_t LightClusters::updateClusters() { _clusterGrid.clear(); _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); - uint32_t maxNumIndices = (uint32_t) _clusterContent.size(); + uint32_t maxNumIndices = (uint32_t)_clusterContent.size(); _clusterContent.clear(); _clusterContent.resize(maxNumIndices, INVALID_LIGHT); @@ -329,8 +346,9 @@ uint32_t LightClusters::updateClusters() { continue; } float eyeZMin = eyeOri.z + radius; + bool beyondFar = false; if (eyeZMin < -theFrustumGrid.rangeFar) { - continue; + beyondFar = true; } // Get z slices @@ -349,7 +367,17 @@ uint32_t LightClusters::updateClusters() { // CLamp the z range zMin = std::max(0, zMin); - // zMax = std::min(zMax, theFrustumGrid.dims.z); + // zMax = std::min(zMax, theFrustumGrid.dims.z); + + auto xLeftDistance = radius - distanceToPlane(eyeOri, _gridPlanes[0][0]); + auto xRightDistance = radius + distanceToPlane(eyeOri, _gridPlanes[0].back()); + + auto yBottomDistance = radius - distanceToPlane(eyeOri, _gridPlanes[1][0]); + auto yTopDistance = radius + distanceToPlane(eyeOri, _gridPlanes[1].back()); + + if ((xLeftDistance < 0.f) || (xRightDistance < 0.f) || (yBottomDistance < 0.f) || (yTopDistance < 0.f)) { + continue; + } // find 2D corners of the sphere in grid int xMin { 0 }; @@ -384,10 +412,16 @@ uint32_t LightClusters::updateClusters() { glm::vec3 rightDir(eyeOriDirH.x * eyeToTangentCircleCosH - eyeOriDirH.z * eyeToTangentCircleSinH, 0.0f, eyeOriDirH.x * eyeToTangentCircleSinH + eyeOriDirH.z * eyeToTangentCircleCosH); auto lc = theFrustumGrid.frustumGrid_eyeToClusterDirH(leftDir); + if (lc > xMax) { + lc = xMin; + } auto rc = theFrustumGrid.frustumGrid_eyeToClusterDirH(rightDir); - + if (rc < 0) { + rc = xMax; + } xMin = std::max(xMin, lc); xMax = std::min(rc, xMax); + assert(xMin <= xMax); } if ((eyeOriLen2V > radius2)) { @@ -408,16 +442,24 @@ uint32_t LightClusters::updateClusters() { auto bc = theFrustumGrid.frustumGrid_eyeToClusterDirV(bottomDir); auto tc = theFrustumGrid.frustumGrid_eyeToClusterDirV(topDir); - + if (bc > yMax) { + bc = yMin; + } + if (tc < 0) { + tc = yMax; + } yMin = std::max(yMin, bc); yMax =std::min(tc, yMax); + assert(yMin <= yMax); } // now voxelize auto& clusterGrid = (isSpot ? clusterGridSpot : clusterGridPoint); - numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); - // numClusterTouched += scanLightVolumeBox(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); - + if (beyondFar) { + numClusterTouched += scanLightVolumeBoxSlice(theFrustumGrid, _gridPlanes, zMin, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); + } else { + numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); + } } // Lights have been gathered now reexpress in terms of 2 sequential buffers From ac54533433891c7c661596ff1ff9e9e3498081f7 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 6 Oct 2016 18:15:32 -0700 Subject: [PATCH 064/104] Adding more counters to understand the cullign bug --- libraries/render-utils/src/LightClusters.cpp | 17 +++++++---- libraries/render-utils/src/LightClusters.h | 9 +++++- .../utilities/render/lightClustering.qml | 28 ++++++++++++++----- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index e51d8f2e4d..dd7897b23e 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -311,7 +311,7 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan return numClustersTouched; } -uint32_t LightClusters::updateClusters() { +glm::ivec3 LightClusters::updateClusters() { // Clean up last info std::vector< std::vector< LightIndex > > clusterGridPoint(_numClusters); std::vector< std::vector< LightIndex > > clusterGridSpot(_numClusters); @@ -327,11 +327,14 @@ uint32_t LightClusters::updateClusters() { glm::ivec3 gridPosToOffset(1, theFrustumGrid.dims.x, theFrustumGrid.dims.x * theFrustumGrid.dims.y); uint32_t numClusterTouched = 0; + uint32_t numLightsIn = _visibleLightIndices[0]; + uint32_t numClusteredLights = 0; for (size_t lightNum = 1; lightNum < _visibleLightIndices.size(); ++lightNum) { auto lightId = _visibleLightIndices[lightNum]; auto light = _lightStage->getLight(lightId); - if (!light) + if (!light) { continue; + } auto worldOri = light->getPosition(); auto radius = light->getMaximumRadius(); @@ -460,6 +463,8 @@ uint32_t LightClusters::updateClusters() { } else { numClusterTouched += scanLightVolumeSphere(theFrustumGrid, _gridPlanes, zMin, zMax, yMin, yMax, xMin, xMax, lightId, glm::vec4(glm::vec3(eyeOri), radius), clusterGrid); } + + numClusteredLights++; } // Lights have been gathered now reexpress in terms of 2 sequential buffers @@ -502,7 +507,7 @@ uint32_t LightClusters::updateClusters() { _clusterGridBuffer._buffer->setData(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data()); _clusterContentBuffer._buffer->setSubData(0, indexOffset * sizeof(LightIndex), (gpu::Byte*) _clusterContent.data()); - return numClusterTouched; + return glm::ivec3(numLightsIn, numClusteredLights, numClusterTouched); } @@ -543,12 +548,14 @@ void LightClusteringPass::run(const render::SceneContextPointer& sceneContext, c _lightClusters->updateLightStage(lightStage); _lightClusters->updateLightFrame(lightStage->_currentFrame, lightingModel->isPointLightEnabled(), lightingModel->isSpotLightEnabled()); - auto numClusterdLights = _lightClusters->updateClusters(); + auto clusteringStats = _lightClusters->updateClusters(); output = _lightClusters; auto config = std::static_pointer_cast(renderContext->jobConfig); - config->setNumClusteredLights(numClusterdLights); + config->setNumInputLights(clusteringStats.x); + config->setNumClusteredLights(clusteringStats.y); + config->setNumClusteredLightReferences(clusteringStats.z); } DebugLightClusters::DebugLightClusters() { diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 5402339563..bb2bf47295 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -74,7 +74,7 @@ public: void updateLightFrame(const LightStage::Frame& lightFrame, bool points = true, bool spots = true); - uint32_t updateClusters(); + glm::ivec3 updateClusters(); ViewFrustum _frustum; @@ -117,6 +117,8 @@ class LightClusteringPassConfig : public render::Job::Config { Q_PROPERTY(bool freeze MEMBER freeze NOTIFY dirty) + Q_PROPERTY(int numClusteredLightReferences MEMBER numClusteredLightReferences NOTIFY dirty) + Q_PROPERTY(int numInputLights MEMBER numInputLights NOTIFY dirty) Q_PROPERTY(int numClusteredLights MEMBER numClusteredLights NOTIFY dirty) public: LightClusteringPassConfig() : render::Job::Config(true){} @@ -130,6 +132,11 @@ public: bool freeze{ false }; + void setNumClusteredLightReferences(int numRefs) { numClusteredLightReferences = numRefs; emit dirty(); } + int numClusteredLightReferences { 0 }; + + void setNumInputLights(int numLights) { numInputLights = numLights; emit dirty(); } + int numInputLights { 0 }; void setNumClusteredLights(int numLights) { numClusteredLights = numLights; emit dirty(); } int numClusteredLights { 0 }; signals: diff --git a/scripts/developer/utilities/render/lightClustering.qml b/scripts/developer/utilities/render/lightClustering.qml index 427a818239..a9ca05dff8 100644 --- a/scripts/developer/utilities/render/lightClustering.qml +++ b/scripts/developer/utilities/render/lightClustering.qml @@ -33,14 +33,28 @@ Column { label: "time", scale: 1, color: "#FFFFFF" + } + ] + } + + PlotPerf { + title: "Lights" + height: 50 + object: Render.getConfig("LightClustering") + valueUnit: "" + valueScale: 1 + valueNumDigits: "0" + plots: [ + { + object: Render.getConfig("LightClustering"), + prop: "numClusteredLights", + label: "visible", + color: "#D959FE" }, { - object: Render.getConfig("DrawLight"), - prop: "numDrawn", - unit: "", - scale: 0.01, - numDigits: 0, - label: "Lights", + object: Render.getConfig("LightClustering"), + prop: "numInputLights", + label: "input", color: "#FED959" } ] @@ -107,7 +121,7 @@ Column { onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawContent"] = checked } } Label { - text: "Num Cluster Items = " + Render.getConfig("LightClustering")["numClusteredLights"].toFixed(0) + text: "Num Cluster Items = " + Render.getConfig("LightClustering")["numClusteredLightReferences"].toFixed(0) } } From 567adf651a9c747c676a422783515b26b62bedb9 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 7 Oct 2016 05:02:04 -0700 Subject: [PATCH 065/104] FOund 2 bugs causing the empty clusters. now back to working --- .../src/DeferredLightingEffect.cpp | 1 + libraries/render-utils/src/LightClusters.cpp | 13 +++++---- libraries/render-utils/src/LightClusters.h | 19 ++++++++---- libraries/render-utils/src/LightStage.cpp | 10 +++++++ libraries/render-utils/src/LightStage.h | 5 ++++ .../render/src/render/IndexedContainer.h | 10 +++++-- .../utilities/render/lightClustering.qml | 29 +++++++++++++++++++ 7 files changed, 74 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 084ec0e746..0524466412 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -139,6 +139,7 @@ void DeferredLightingEffect::init() { // Add the global light to the light stage (for later shadow rendering) _globalLights.push_back(_lightStage->addLight(lp)); + _lightStage->addShadow(_globalLights[0]); } diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index dd7897b23e..7cfd609f1e 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -174,9 +174,7 @@ void LightClusters::updateLightFrame(const LightStage::Frame& lightFrame, bool p auto& srcPointLights = lightFrame._pointLights; auto& srcSpotLights = lightFrame._spotLights; int numPointLights = (int)srcPointLights.size(); - // int offsetPointLights = 0; int numSpotLights = (int)srcSpotLights.size(); - // int offsetSpotLights = numPointLights; _visibleLightIndices.resize(numPointLights + numSpotLights + 1); @@ -367,10 +365,8 @@ glm::ivec3 LightClusters::updateClusters() { continue; } - // CLamp the z range zMin = std::max(0, zMin); - // zMax = std::min(zMax, theFrustumGrid.dims.z); auto xLeftDistance = radius - distanceToPlane(eyeOri, _gridPlanes[0][0]); auto xRightDistance = radius + distanceToPlane(eyeOri, _gridPlanes[0].back()); @@ -389,8 +385,9 @@ glm::ivec3 LightClusters::updateClusters() { int yMax { theFrustumGrid.dims.y - 1 }; float radius2 = radius * radius; - auto eyeOriH = eyeOri; - auto eyeOriV = eyeOri; + + auto eyeOriH = glm::vec3(eyeOri); + auto eyeOriV = glm::vec3(eyeOri); eyeOriH.y = 0.0f; eyeOriV.x = 0.0f; @@ -490,6 +487,7 @@ glm::ivec3 LightClusters::updateClusters() { } } + // Encode the cluster grid: [ ContentOffset - 16bits, Num Point LIghts - 8bits, Num Spot Lights - 8bits] _clusterGrid[i] = (uint32_t)((0xFF000000 & (numLightsSpot << 24)) | (0x00FF0000 & (numLightsPoint << 16)) | (0x0000FFFF & offset)); @@ -553,6 +551,9 @@ void LightClusteringPass::run(const render::SceneContextPointer& sceneContext, c output = _lightClusters; auto config = std::static_pointer_cast(renderContext->jobConfig); + config->numSceneLights = lightStage->getNumLights(); + config->numFreeSceneLights = lightStage->getNumFreeLights(); + config->numAllocatedSceneLights = lightStage->getNumAllocatedLights(); config->setNumInputLights(clusteringStats.x); config->setNumClusteredLights(clusteringStats.y); config->setNumClusteredLightReferences(clusteringStats.z); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index bb2bf47295..57acc74121 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -120,6 +120,11 @@ class LightClusteringPassConfig : public render::Job::Config { Q_PROPERTY(int numClusteredLightReferences MEMBER numClusteredLightReferences NOTIFY dirty) Q_PROPERTY(int numInputLights MEMBER numInputLights NOTIFY dirty) Q_PROPERTY(int numClusteredLights MEMBER numClusteredLights NOTIFY dirty) + + Q_PROPERTY(int numSceneLights MEMBER numSceneLights NOTIFY dirty) + Q_PROPERTY(int numFreeSceneLights MEMBER numFreeSceneLights NOTIFY dirty) + Q_PROPERTY(int numAllocatedSceneLights MEMBER numAllocatedSceneLights NOTIFY dirty) + public: LightClusteringPassConfig() : render::Job::Config(true){} float rangeNear{ 0.1f }; @@ -131,14 +136,18 @@ public: bool freeze{ false }; - - void setNumClusteredLightReferences(int numRefs) { numClusteredLightReferences = numRefs; emit dirty(); } - int numClusteredLightReferences { 0 }; - void setNumInputLights(int numLights) { numInputLights = numLights; emit dirty(); } + int numClusteredLightReferences { 0 }; int numInputLights { 0 }; - void setNumClusteredLights(int numLights) { numClusteredLights = numLights; emit dirty(); } int numClusteredLights { 0 }; + + void setNumClusteredLightReferences(int numRefs) { numClusteredLightReferences = numRefs; emit dirty(); } + void setNumInputLights(int numLights) { numInputLights = numLights; emit dirty(); } + void setNumClusteredLights(int numLights) { numClusteredLights = numLights; emit dirty(); } + + int numSceneLights { 0 }; + int numFreeSceneLights { 0 }; + int numAllocatedSceneLights { 0 }; signals: void dirty(); diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 8c6e6d96a4..66a9797d3c 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -123,6 +123,16 @@ LightStage::Index LightStage::addLight(const LightPointer& light) { } } +LightStage::Index LightStage::addShadow(Index lightIndex) { + auto light = getLight(lightIndex); + Index shadowId = INVALID_INDEX; + if (light) { + shadowId = _shadows.newElement(std::make_shared(light)); + _descs[lightIndex].shadowId = shadowId; + } + return shadowId; +} + LightStage::LightPointer LightStage::removeLight(Index index) { LightPointer removed = _lights.freeElement(index); diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 34575596dd..c2293ac099 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -80,11 +80,16 @@ public: Index findLight(const LightPointer& light) const; Index addLight(const LightPointer& light); + + Index addShadow(Index lightIndex); + LightPointer removeLight(Index index); bool checkLightId(Index index) const { return _lights.checkIndex(index); } Index getNumLights() const { return _lights.getNumElements(); } + Index getNumFreeLights() const { return _lights.getNumFreeIndices(); } + Index getNumAllocatedLights() const { return _lights.getNumAllocatedIndices(); } LightPointer getLight(Index lightId) const { return _lights.get(lightId); diff --git a/libraries/render/src/render/IndexedContainer.h b/libraries/render/src/render/IndexedContainer.h index 6250d4f4f1..bb1a9b72b7 100644 --- a/libraries/render/src/render/IndexedContainer.h +++ b/libraries/render/src/render/IndexedContainer.h @@ -31,6 +31,8 @@ namespace indexed_container { bool checkIndex(Index index) const { return ((index >= 0) && (index < _nextNewIndex)); } Index getNumIndices() const { return _nextNewIndex - (Index) _freeIndices.size(); } + Index getNumFreeIndices() const { return (Index) _freeIndices.size(); } + Index getNumAllocatedIndices() const { return _nextNewIndex; } Index allocateIndex() { if (_freeIndices.empty()) { @@ -74,12 +76,14 @@ namespace indexed_container { bool checkIndex(Index index) const { return _allocator.checkIndex(index); }; Index getNumElements() const { return _allocator.getNumIndices(); } + Index getNumFreeIndices() const { return _allocator.getNumFreeIndices(); } + Index getNumAllocatedIndices() const { return _allocator.getNumAllocatedIndices(); } Index newElement(const Element& e) { Index index = _allocator.allocateIndex(); if (index != INVALID_INDEX) { if (index < (Index) _elements.size()) { - _elements.emplace(_elements.begin() + index, e); + _elements[index] = e; } else { assert(index == _elements.size()); _elements.emplace_back(e); @@ -113,12 +117,14 @@ namespace indexed_container { bool checkIndex(Index index) const { return _allocator.checkIndex(index); }; Index getNumElements() const { return _allocator.getNumIndices(); } + Index getNumFreeIndices() const { return _allocator.getNumFreeIndices(); } + Index getNumAllocatedIndices() const { return _allocator.getNumAllocatedIndices(); } Index newElement(const ElementPtr& e) { Index index = _allocator.allocateIndex(); if (index != INVALID_INDEX) { if (index < (Index) _elements.size()) { - _elements.emplace(_elements.begin() + index, e); + _elements[index] = e; } else { assert(index == (Index) _elements.size()); _elements.emplace_back(e); diff --git a/scripts/developer/utilities/render/lightClustering.qml b/scripts/developer/utilities/render/lightClustering.qml index a9ca05dff8..4db7aa8c39 100644 --- a/scripts/developer/utilities/render/lightClustering.qml +++ b/scripts/developer/utilities/render/lightClustering.qml @@ -60,6 +60,35 @@ Column { ] } + PlotPerf { + title: "Scene Lights" + height: 80 + object: Render.getConfig("LightClustering") + valueUnit: "" + valueScale: 1 + valueNumDigits: "0" + plots: [ + { + object: Render.getConfig("LightClustering"), + prop: "numSceneLights", + label: "current", + color: "#00B4EF" + }, + { + object: Render.getConfig("LightClustering"), + prop: "numFreeSceneLights", + label: "free", + color: "#1AC567" + }, + { + object: Render.getConfig("LightClustering"), + prop: "numAllocatedSceneLights", + label: "allocated", + color: "#9495FF" + } + ] + } + ConfigSlider { label: qsTr("Range Near [m]") integral: false From 8a44140e6bc4a8b334a0ef31e78641b46ba7ac9a Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 7 Oct 2016 16:04:19 -0700 Subject: [PATCH 066/104] cleaning up the comments from review and trying something to adress the issue that showed up on i5 --- .../src/RenderableLightEntityItem.cpp | 24 ------ libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/LightEntityItem.h | 2 +- .../gpu-gl/src/gpu/gl/GLBackendQuery.cpp | 5 +- libraries/model/src/model/Light.cpp | 15 ---- libraries/model/src/model/Light.h | 28 +------ .../render-utils/src/LightClusterGrid.slh | 2 +- libraries/render-utils/src/LightClusters.cpp | 74 ++++++++++++------- libraries/render-utils/src/LightClusters.h | 12 ++- libraries/render-utils/src/LightPayload.cpp | 7 ++ 10 files changed, 69 insertions(+), 102 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 4ae2da295f..2e55901bbd 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -89,30 +89,6 @@ void RenderableLightEntityItem::notifyChanged() { scene->enqueuePendingChanges(pendingChanges); } -/* -void RenderableLightEntityItem::render(RenderArgs* args) { - PerformanceTimer perfTimer("RenderableLightEntityItem::render"); - assert(getType() == EntityTypes::Light); - checkFading(); - - - glm::vec3 position = getPosition(); - glm::vec3 dimensions = getDimensions(); - glm::quat rotation = getRotation(); - float largestDiameter = glm::compMax(dimensions); - - - // DependencyManager::get()->addLight(_light); - -#ifdef WANT_DEBUG - Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - batch.setModelTransform(getTransformToCenter()); - DependencyManager::get()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f)); -#endif -}; -*/ - bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e01e5e087c..7e06a59f06 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -90,7 +90,7 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; /// returns true if something changed - // THis function calls setSubClass properties and detects if any property changes value. + // This function calls setSubClass properties and detects if any property changes value. // If something changed then the "somethingChangedNotification" calls happens virtual bool setProperties(const EntityItemProperties& properties); diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index cb23c2357f..b9f02eead8 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -109,7 +109,7 @@ protected: float _cutoff { DEFAULT_CUTOFF }; // Dirty flag turn true when either light properties is changing values. - // THis gets back to false in the somethingChangedNotification() call + // This gets back to false in the somethingChangedNotification() call // Which is called after a setProperties() or a readEntitySubClassFromBUfferCall on the entity. bool _lightPropertiesChanged { false }; diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp index 5fd1c4c6a3..c53e650aee 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendQuery.cpp @@ -27,7 +27,6 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) { if (glquery) { PROFILE_RANGE_BEGIN(glquery->_profileRangeId, query->getName().c_str(), 0xFFFF7F00); - //glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime); glquery->_batchElapsedTime = usecTimestampNow() * 1000; if (timeElapsed) { glBeginQuery(GL_TIME_ELAPSED, glquery->_endqo); @@ -47,10 +46,8 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) { } else { glQueryCounter(glquery->_endqo, GL_TIMESTAMP); } - GLint64 now; - //glGetInteger64v(GL_TIMESTAMP, &now); - now = usecTimestampNow() * 1000; + GLint64 now = usecTimestampNow() * 1000; glquery->_batchElapsedTime = now - glquery->_batchElapsedTime; PROFILE_RANGE_END(glquery->_profileRangeId); diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index 59b57f274c..4ac0573cf6 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -44,7 +44,6 @@ void Light::setType(Type type) { } updateLightRadius(); } - updateVolumeGeometry(); } @@ -89,7 +88,6 @@ void Light::setMaximumRadius(float radius) { } _lightSchemaBuffer.edit().volume.radius = radius; updateLightRadius(); - updateVolumeGeometry(); } void Light::updateLightRadius() { @@ -125,8 +123,6 @@ void Light::setSpotAngle(float angle) { if (isSpot()) { _lightSchemaBuffer.edit().volume.spotCos = _spotCos; } - - updateVolumeGeometry(); } void Light::setSpotExponent(float exponent) { @@ -162,14 +158,3 @@ void Light::setAmbientMapNumMips(uint16_t numMips) { _ambientSchemaBuffer.edit().mapNumMips = (float)numMips; } -void Light::updateVolumeGeometry() { - // enlarge the scales slightly to account for tesselation - /* const float SCALE_EXPANSION = 0.05f; - glm::vec4 volumeGeometry(0.0f, 0.0f, 0.0f, getMaximumRadius() * (1.0f + SCALE_EXPANSION)); - - if (getType() == SPOT) { - const float TANGENT_LENGTH_SCALE = 0.666f; - volumeGeometry = glm::vec4(getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * getSpotAngle()), volumeGeometry.w); - } - editSchema()._volumeGeometry = volumeGeometry;*/ -} diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index b57b8c6095..947474bbfd 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -149,7 +149,7 @@ public: void setAmbientMapNumMips(uint16_t numMips); uint16_t getAmbientMapNumMips() const { return (uint16_t) _ambientSchemaBuffer->mapNumMips; } - // LIght Schema + // Light Schema class LightSchema { public: LightVolume volume; @@ -158,8 +158,8 @@ public: class AmbientSchema { public: - float intensity { 0.f }; - float mapNumMips { 0.f }; + float intensity { 0.0f }; + float mapNumMips { 0.0f }; float spare1; float spare2; gpu::SphericalHarmonics ambientSphere; @@ -168,27 +168,6 @@ public: using LightSchemaBuffer = gpu::StructBuffer; using AmbientSchemaBuffer = gpu::StructBuffer; - // Schema to access the attribute values of the light - /* class Schema { - public: - Vec4 _position{0.0f, 0.0f, 0.0f, 1.0f}; - Vec3 _direction{0.0f, 0.0f, -1.0f}; - float _ambientIntensity{0.0f}; - Color _color{1.0f}; - float _intensity{1.0f}; - Vec4 _attenuation{0.1f, 1.0f, 0.0f, 0.0f}; - Vec4 _spot{0.0f, 0.0f, 0.0f, 0.0f}; - //Vec4 _shadow{0.0f}; - - - float _ambientMapNumMips{ 0.0f }; - Vec3 _control{ 0.0f, 0.0f, 0.0f }; - - Vec4 _volumeGeometry { 1.f }; - - gpu::SphericalHarmonics _ambientSphere; - }; - */ const LightSchemaBuffer& getLightSchemaBuffer() const { return _lightSchemaBuffer; } const AmbientSchemaBuffer& getAmbientSchemaBuffer() const { return _ambientSchemaBuffer; } @@ -207,7 +186,6 @@ protected: float _spotCos { -1.0f }; // stored here to be able to reset the spot angle when turning the type spot on/off void updateLightRadius(); - void updateVolumeGeometry(); }; typedef std::shared_ptr< Light > LightPointer; diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 3cd3bec473..f4ec35a75c 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -1,5 +1,5 @@ ()), _clusterGridBuffer(/*std::make_shared(), */gpu::Element::INDEX_INT32), _clusterContentBuffer(/*std::make_shared(), */gpu::Element::INDEX_INT32) { - auto dims = _frustumGridBuffer.edit().dims; - _frustumGridBuffer.edit().dims = ivec3(0); // make sure we go through the full reset of the dimensionts ion the setDImensions call - setDimensions(dims, MAX_GRID_DIMENSIONS.w); } void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { ivec3 configDimensions; auto gridBudget = MAX_GRID_DIMENSIONS.w; - configDimensions.x = std::min(MAX_GRID_DIMENSIONS.x, gridDims.x); - configDimensions.y = std::min(MAX_GRID_DIMENSIONS.y, gridDims.y); - configDimensions.z = std::min(MAX_GRID_DIMENSIONS.z, gridDims.z); + configDimensions.x = std::max(1, (int) std::min(MAX_GRID_DIMENSIONS.x, gridDims.x)); + configDimensions.y = std::max(1, (int) std::min(MAX_GRID_DIMENSIONS.y, gridDims.y)); + configDimensions.z = std::max(1, (int) std::min(MAX_GRID_DIMENSIONS.z, gridDims.z)); auto sliceCost = configDimensions.x * configDimensions.y; auto maxNumSlices = (int)(gridBudget / sliceCost) - 1; configDimensions.z = std::min(maxNumSlices, configDimensions.z); - static int numFrames = 0; - numFrames++; - auto& dims = _frustumGridBuffer->dims; - if ((numFrames == 10) || (dims.x != configDimensions.x) || (dims.y != configDimensions.y) || (dims.z != configDimensions.z)) { - _frustumGridBuffer.edit().dims = configDimensions; - _frustumGridBuffer.edit().generateGridPlanes(_gridPlanes[0], _gridPlanes[1], _gridPlanes[2]); - } - - auto numClusters = _frustumGridBuffer.edit().frustumGrid_numClusters(); - if (numClusters != _numClusters) { - _numClusters = numClusters; - _clusterGrid.clear(); - _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); - // _clusterGridBuffer._size = _clusterGridBuffer._buffer->resize(_numClusters * sizeof(uint32_t)); - _clusterGridBuffer._size = (_numClusters * sizeof(uint32_t)); - _clusterGridBuffer._buffer = std::make_shared(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data(), _clusterGridBuffer._size); + // Grab the frustumGridBuffer and force it updated + const auto& constFrustumGrid = _frustumGridBuffer.get(); + const auto& dims = constFrustumGrid.dims; + if ((dims.x != configDimensions.x) || (dims.y != configDimensions.y) || (dims.z != configDimensions.z)) { + auto& theFrustumGrid = _frustumGridBuffer.edit(); + theFrustumGrid.dims = configDimensions; + theFrustumGrid.generateGridPlanes(_gridPlanes[0], _gridPlanes[1], _gridPlanes[2]); + _clusterResourcesInvalid = true; } auto configListBudget = std::min(MAX_GRID_DIMENSIONS.w, listBudget); + if (_clusterContentBudget != configListBudget) { + _clusterContentBudget = configListBudget; + _clusterResourcesInvalid = true; + } +} - // SInce LightINdex is 2bytes, we can fit 2 in a uint32 +uint32_t LightClusters::getNumClusters() const { + auto theFrustumGrid = _frustumGridBuffer.get(); + return theFrustumGrid.frustumGrid_numClusters(); +} + + void LightClusters::updateClusterResource() { + if (!_clusterResourcesInvalid) { + return; + } + _clusterResourcesInvalid = false; + auto numClusters = getNumClusters(); + if (numClusters != _clusterGrid.size()) { + _clusterGrid.clear(); + _clusterGrid.resize(numClusters, EMPTY_CLUSTER); + _clusterGridBuffer._size = (numClusters * sizeof(uint32_t)); + _clusterGridBuffer._buffer = std::make_shared(_clusterGridBuffer._size, (gpu::Byte*) _clusterGrid.data(), _clusterGridBuffer._size); + } + + // Since LightIndex is 2bytes, we can fit 2 in a uint32 + auto configListBudget = _clusterContentBudget; if (sizeof(LightIndex) == 2) { configListBudget *= 2; } @@ -129,9 +142,7 @@ void LightClusters::setDimensions(glm::uvec3 gridDims, uint32_t listBudget) { if (configListBudget != _clusterContent.size()) { _clusterContent.clear(); _clusterContent.resize(configListBudget, INVALID_LIGHT); - // _clusterContentBuffer._size = _clusterContentBuffer._buffer->resize(configListBudget * sizeof(LightIndex)); _clusterContentBuffer._size = (configListBudget * sizeof(LightIndex)); - // _clusterContentBuffer._buffer->setData(_clusterContentBuffer._size, (gpu::Byte*) _clusterContent.data()); _clusterContentBuffer._buffer = std::make_shared(_clusterContentBuffer._size, (gpu::Byte*) _clusterContent.data(), _clusterContentBuffer._size); } } @@ -310,16 +321,23 @@ uint32_t scanLightVolumeSphere(FrustumGrid& grid, const FrustumGrid::Planes plan } glm::ivec3 LightClusters::updateClusters() { + // Make sure resource are in good shape + updateClusterResource(); + // Clean up last info - std::vector< std::vector< LightIndex > > clusterGridPoint(_numClusters); - std::vector< std::vector< LightIndex > > clusterGridSpot(_numClusters); + uint32_t numClusters = (uint32_t)_clusterGrid.size(); + + std::vector< std::vector< LightIndex > > clusterGridPoint(numClusters); + std::vector< std::vector< LightIndex > > clusterGridSpot(numClusters); _clusterGrid.clear(); - _clusterGrid.resize(_numClusters, EMPTY_CLUSTER); + _clusterGrid.resize(numClusters, EMPTY_CLUSTER); + uint32_t maxNumIndices = (uint32_t)_clusterContent.size(); _clusterContent.clear(); _clusterContent.resize(maxNumIndices, INVALID_LIGHT); + auto theFrustumGrid(_frustumGridBuffer.get()); glm::ivec3 gridPosToOffset(1, theFrustumGrid.dims.x, theFrustumGrid.dims.x * theFrustumGrid.dims.y); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 57acc74121..450047b0ab 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -24,7 +24,7 @@ public: float rangeFar { 200.0f }; float frustumFar { 10000.0f }; - glm::ivec3 dims { 16, 16, 16 }; + glm::ivec3 dims { 1, 1, 1 }; float spare; glm::mat4 eyeToGridProj; @@ -68,6 +68,8 @@ public: void setDimensions(glm::uvec3 gridDims, uint32_t listBudget = MAX_GRID_DIMENSIONS.w); void setRangeNearFar(float rangeNear, float rangeFar); + uint32_t getNumClusters() const; + void updateFrustum(const ViewFrustum& frustum); void updateLightStage(const LightStagePointer& lightStage); @@ -76,8 +78,10 @@ public: glm::ivec3 updateClusters(); + ViewFrustum _frustum; + LightStagePointer _lightStage; @@ -89,8 +93,6 @@ public: LightStage::LightIndices _visibleLightIndices; gpu::BufferView _lightIndicesBuffer; - int32_t _numClusters { 0 }; - const uint32_t EMPTY_CLUSTER { 0x0000FFFF }; const LightID INVALID_LIGHT { LightStage::INVALID_INDEX }; @@ -100,6 +102,10 @@ public: std::vector _clusterContent; gpu::BufferView _clusterGridBuffer; gpu::BufferView _clusterContentBuffer; + int32_t _clusterContentBudget { 0 }; + + bool _clusterResourcesInvalid { true }; + void updateClusterResource(); }; using LightClustersPointer = std::shared_ptr; diff --git a/libraries/render-utils/src/LightPayload.cpp b/libraries/render-utils/src/LightPayload.cpp index 5f58677efe..a670c9f620 100644 --- a/libraries/render-utils/src/LightPayload.cpp +++ b/libraries/render-utils/src/LightPayload.cpp @@ -71,6 +71,13 @@ void LightPayload::render(RenderArgs* args) { if (isVisible()) { // FInally, push the light visible in the frame _stage->_currentFrame.pushLight(_index, _light->getType()); + +#ifdef WANT_DEBUG + Q_ASSERT(args->_batch); + gpu::Batch& batch = *args->_batch; + batch.setModelTransform(getTransformToCenter()); + DependencyManager::get()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f)); +#endif } } From 429a7cf58ae23cd21fd285c1053d81273dbc9104 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 7 Oct 2016 16:12:36 -0700 Subject: [PATCH 067/104] adjust grid dimension to 14 x 14 x 14 conservatively to keep the generation fast --- libraries/render-utils/src/LightClusters.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 450047b0ab..13e5e19895 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -136,9 +136,9 @@ public: float rangeNear{ 0.1f }; float rangeFar{ 200.0f }; - int dimX { 16 }; - int dimY { 16 }; - int dimZ { 16 }; + int dimX { 14 }; + int dimY { 14 }; + int dimZ { 14 }; bool freeze{ false }; From 8476939ba9a6049af27a97f0e18b1efbc78309f5 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 7 Oct 2016 16:44:51 -0700 Subject: [PATCH 068/104] Avoiding warnings maybe --- libraries/render-utils/src/LightClusters.cpp | 4 ++-- libraries/render-utils/src/LightClusters.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index c96b56a457..c2559f847b 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -126,7 +126,7 @@ uint32_t LightClusters::getNumClusters() const { } _clusterResourcesInvalid = false; auto numClusters = getNumClusters(); - if (numClusters != _clusterGrid.size()) { + if (numClusters != (uint32_t) _clusterGrid.size()) { _clusterGrid.clear(); _clusterGrid.resize(numClusters, EMPTY_CLUSTER); _clusterGridBuffer._size = (numClusters * sizeof(uint32_t)); @@ -139,7 +139,7 @@ uint32_t LightClusters::getNumClusters() const { configListBudget *= 2; } - if (configListBudget != _clusterContent.size()) { + if (configListBudget != (uint32_t) _clusterContent.size()) { _clusterContent.clear(); _clusterContent.resize(configListBudget, INVALID_LIGHT); _clusterContentBuffer._size = (configListBudget * sizeof(LightIndex)); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 13e5e19895..9514066561 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -102,7 +102,7 @@ public: std::vector _clusterContent; gpu::BufferView _clusterGridBuffer; gpu::BufferView _clusterContentBuffer; - int32_t _clusterContentBudget { 0 }; + uint32_t _clusterContentBudget { 0 }; bool _clusterResourcesInvalid { true }; void updateClusterResource(); From 297907688c898e61ac6ea63d268671d96406bc7a Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 10 Oct 2016 12:43:33 -0700 Subject: [PATCH 069/104] Fixing reveiw comments --- libraries/gpu/src/gpu/Query.h | 4 ++-- libraries/model/src/model/LightIrradiance.shared.slh | 3 +-- libraries/render-utils/src/LightClusters.h | 10 ++++------ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h index 26553d67b3..e053fdd507 100644 --- a/libraries/gpu/src/gpu/Query.h +++ b/libraries/gpu/src/gpu/Query.h @@ -42,7 +42,7 @@ namespace gpu { protected: Handler _returnHandler; - std::string _name; + const std::string _name; uint64_t _queryResult { 0 }; uint64_t _usecBatchElapsedTime { 0 }; }; @@ -67,7 +67,7 @@ namespace gpu { static const int QUERY_QUEUE_SIZE { 4 }; - std::string _name; + const std::string _name; gpu::Queries _timerQueries; int _headIndex = -1; int _tailIndex = -1; diff --git a/libraries/model/src/model/LightIrradiance.shared.slh b/libraries/model/src/model/LightIrradiance.shared.slh index eaa1b33a88..4a2ee40c9d 100644 --- a/libraries/model/src/model/LightIrradiance.shared.slh +++ b/libraries/model/src/model/LightIrradiance.shared.slh @@ -32,10 +32,9 @@ float lightIrradiance_getFalloffSpot(LightIrradiance li) { return li.attenuation float lightIrradiance_evalLightAttenuation(LightIrradiance li, float d) { float radius = lightIrradiance_getFalloffRadius(li); float cutoff = lightIrradiance_getCutoffRadius(li); - float denom = d / radius + 1.0; + float denom = (d / radius) + 1.0; float attenuation = 1.0 / (denom * denom); - // "Fade" the edges of light sources to make things look a bit more attractive. // Note: this tends to look a bit odd at lower exponents. attenuation *= min(1, max(0, -(d - cutoff))); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 9514066561..955e780b23 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -11,11 +11,13 @@ #ifndef hifi_render_utils_LightClusters_h #define hifi_render_utils_LightClusters_h +#include #include #include #include "LightStage.h" - -#include +#include "DeferredFrameTransform.h" +#include "LightingModel.h" +#include "SurfaceGeometryPass.h" class FrustumGrid { public: @@ -160,10 +162,6 @@ signals: protected: }; -#include "DeferredFrameTransform.h" -#include "LightingModel.h" -#include "SurfaceGeometryPass.h" - class LightClusteringPass { public: using Inputs = render::VaryingSet3; From 77062ac1b37e5ac4e29b321f145a24e4f9bbdea9 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 11 Oct 2016 17:13:08 -0700 Subject: [PATCH 070/104] Cleaning up a missing constructor and adjusting the stride for the StrucBuffer by default + merging with upstream --- libraries/gpu/src/gpu/Buffer.h | 8 ++++---- libraries/render-utils/src/LightClusters.cpp | 11 +++++++++++ libraries/render-utils/src/LightClusters.h | 3 +++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h index 2079c60605..6b9306ebac 100644 --- a/libraries/gpu/src/gpu/Buffer.h +++ b/libraries/gpu/src/gpu/Buffer.h @@ -384,12 +384,12 @@ public: template class StructBuffer : public gpu::BufferView { public: - static BufferPointer makeBuffer() { - T t; - return std::make_shared(sizeof(T), (const gpu::Byte*) &t); + template static BufferPointer makeBuffer() { + U t; + return std::make_shared(sizeof(U), (const gpu::Byte*) &t, sizeof(U)); } ~StructBuffer() {}; - StructBuffer() : gpu::BufferView(makeBuffer()) {} + StructBuffer() : gpu::BufferView(makeBuffer()) {} T& edit() { diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index c2559f847b..f569351c55 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -44,6 +44,17 @@ enum LightClusterGridShader_BufferSlot { LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, }; +FrustumGrid::FrustumGrid(const FrustumGrid& source) : + frustumNear(source.frustumNear), + rangeNear(source.rangeNear), + rangeFar(source.rangeFar), + frustumFar(source.frustumFar), + dims(source.dims), + spare(source.spare), + eyeToGridProj(source.eyeToGridProj), + worldToEyeMat(source.worldToEyeMat), + eyeToWorldMat(source.eyeToWorldMat) +{} void FrustumGrid::generateGridPlanes(Planes& xPlanes, Planes& yPlanes, Planes& zPlanes) { xPlanes.resize(dims.x + 1); diff --git a/libraries/render-utils/src/LightClusters.h b/libraries/render-utils/src/LightClusters.h index 955e780b23..d27a6e1d92 100644 --- a/libraries/render-utils/src/LightClusters.h +++ b/libraries/render-utils/src/LightClusters.h @@ -33,6 +33,9 @@ public: glm::mat4 worldToEyeMat; glm::mat4 eyeToWorldMat; + FrustumGrid() = default; + FrustumGrid(const FrustumGrid& source); + void updateFrustum(const ViewFrustum& frustum) { frustumNear = frustum.getNearClip(); frustumFar = frustum.getFarClip(); From 7956c7b10b7a6c22245341e30248717dbc81821d Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 12 Oct 2016 09:57:06 -0700 Subject: [PATCH 071/104] Fixing a mistake introduced in previous commit in a shader --- libraries/render-utils/src/DeferredGlobalLight.slh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 9ccee8c43f..57ca33eaca 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -156,7 +156,7 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur vec3 diffuseLight = lightAttenuation * lightmap; // Ambient light is the lightmap when in shadow - vec3 ambientLight = (1.0 - lightAttenuation) * lightmap * getLightAmbientIntensity(light); + vec3 ambientLight = (1.0 - lightAttenuation) * lightmap * getLightAmbientIntensity(ambient); return isLightmapEnabled() * obscurance * albedo * (diffuseLight + ambientLight); } From af438ae31bb62bad94df122076457c526a7a2637 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 7 Nov 2016 17:56:54 -0800 Subject: [PATCH 072/104] Fix the buid --- libraries/gpu/src/gpu/Context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 4344cd4d2c..108ed07916 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -36,7 +36,7 @@ void Context::beginFrame(const glm::mat4& renderPose) { _currentFrame->pose = renderPose; if (!_frameRangeTimer) { - _frameRangeTimer = std::make_shared(); + _frameRangeTimer = std::make_shared("gpu::Context::Frame"); } } From 1d3fc1b64797d4f7e57a93537c9c6dcbd531f8aa Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 10 Nov 2016 17:57:11 -0800 Subject: [PATCH 073/104] Fix a bad conversion to integer for negative values of the GRid COordinates --- libraries/render-utils/src/LightClusterGrid_shared.slh | 3 ++- .../render-utils/src/lightClusters_drawClusterContent.slf | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/LightClusterGrid_shared.slh b/libraries/render-utils/src/LightClusterGrid_shared.slh index d5bde79056..ed0ed8d04d 100644 --- a/libraries/render-utils/src/LightClusterGrid_shared.slh +++ b/libraries/render-utils/src/LightClusterGrid_shared.slh @@ -136,6 +136,7 @@ ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { vec3 volumePos = frustumGrid_eyeToVolume(eyePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar); + vec3 gridPos = frustumGrid_volumeToGrid(volumePos, frustumGrid.dims); if (gridPos.z >= frustumGrid.dims.z) { @@ -143,7 +144,7 @@ ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) { } - return ivec3(gridPos); + return ivec3(floor(gridPos)); } int frustumGrid_eyeToClusterDirH(vec3 eyeDir) { diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slf b/libraries/render-utils/src/lightClusters_drawClusterContent.slf index f4b9a82b64..447f8bd634 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slf @@ -38,9 +38,9 @@ void main(void) { // From frag world pos find the cluster vec4 clusterEyePos = frustumGrid_worldToEye(fragWorldPos); ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); + int clusterIndex = frustumGrid_clusterToIndex(clusterPos); - - ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); + ivec3 cluster = clusterGrid_getCluster(clusterIndex); int numLights = cluster.x + cluster.y; float numLightsScale = clamp(numLights * 0.05, 0.01, 1.0); From 94902106e63acc1eda20354a9a42d439499b8afe Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Sun, 13 Nov 2016 12:17:12 -0800 Subject: [PATCH 074/104] use for loop for kick and mute overlay cleanup --- scripts/system/mod.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/system/mod.js b/scripts/system/mod.js index f94be98406..7e5cc5d2a5 100644 --- a/scripts/system/mod.js +++ b/scripts/system/mod.js @@ -137,10 +137,10 @@ function updateOverlays() { isFacingAvatar: true, drawInFront: true }); - + modOverlays[avatarID]=[newKickOverlay]; - - if (Users.canKick) { + + if (Users.canKick) { var newMuteOverlay = Overlays.addOverlay("image3d", { url: muteOverlayURL(), position: muteOverlayPosition, @@ -166,11 +166,11 @@ AvatarList.avatarRemovedEvent.connect(function(avatarID){ if (isShowingOverlays) { // we are currently showing overlays and an avatar just went away - // first remove the rendered overlay - for (var overlay in modOverlays[avatarID]) { - Overlays.deleteOverlay(overlay); + // first remove the rendered overlays + for (var j = 0; j < modOverlays[avatarID].length; ++j) { + Overlays.deleteOverlay(modOverlays[avatarID][j]); } - + // delete the saved ID of the overlay from our mod overlays object delete modOverlays[avatarID]; } @@ -193,7 +193,7 @@ function handleSelectedOverlay(clickedOverlay) { Users.ignore(avatarID); } // cleanup of the overlay is handled by the connection to avatarRemovedEvent - + } else if (muteOverlay && clickedOverlay.overlayID == muteOverlay) { Users.mute(avatarID); } From 9f2b6dc40b82f2797b6cfc20d8ac08c4f99403f9 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 16 Nov 2016 12:53:57 -0800 Subject: [PATCH 075/104] location cleanup --- interface/resources/qml/AddressBarDialog.qml | 4 ++-- libraries/networking/src/AddressManager.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 941099b7cc..38250b8be7 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -370,7 +370,7 @@ Window { if (place.action === 'snapshot') { return true; } - return (place.place_name !== AddressManager.hostname); // Not our entry, but do show other entry points to current domain. + return (place.place_name !== AddressManager.placename); // Not our entry, but do show other entry points to current domain. // could also require right protocolVersion } function getUserStoryPage(pageNumber, cb) { // cb(error) after all pages of domain data have been added to model @@ -436,7 +436,7 @@ Window { notice.text = AddressManager.isConnected ? "Your location:" : "Not Connected"; notice.color = AddressManager.isConnected ? hifiStyleConstants.colors.baseGrayHighlight : hifiStyleConstants.colors.redHighlight; // Display hostname, which includes ip address, localhost, and other non-placenames. - location.text = (AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''); + location.text = (AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''); } } diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index f979002f7a..0c46f9688b 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -35,7 +35,7 @@ class AddressManager : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY Q_PROPERTY(bool isConnected READ isConnected) - Q_PROPERTY(QUrl href READ currentAddress) + Q_PROPERTY(QUrl href READ currentShareableAddress) Q_PROPERTY(QString protocol READ getProtocol) Q_PROPERTY(QString hostname READ getHost) Q_PROPERTY(QString pathname READ currentPath) @@ -67,7 +67,7 @@ public: QString currentFacingPath() const; const QUuid& getRootPlaceID() const { return _rootPlaceID; } - const QString& getPlaceName() const { return _placeName; } + const QString& getPlaceName() const { return _shareablePlaceName.isEmpty() ? _placeName : _shareablePlaceName; } const QString& getHost() const { return _host; } From f1806eb64917687924aceed7165f42b5500a32ac Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 18 Nov 2016 17:05:14 -0800 Subject: [PATCH 076/104] server protocols --- interface/resources/qml/AddressBarDialog.qml | 3 +++ libraries/networking/src/AddressManager.cpp | 4 ++++ libraries/networking/src/AddressManager.h | 2 ++ scripts/system/snapshot.js | 22 +++++++++++++++++++- 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 38250b8be7..172245876a 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -375,7 +375,10 @@ Window { } function getUserStoryPage(pageNumber, cb) { // cb(error) after all pages of domain data have been added to model var options = [ + 'now=' + new Date().toISOString(), 'include_actions=snapshot,concurrency', + 'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'), + 'require_online=true', 'protocol=' + encodeURIComponent(AddressManager.protocolVersion()), 'page=' + pageNumber ]; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 4089fd4966..05210012ba 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -750,6 +750,10 @@ void AddressManager::copyPath() { QApplication::clipboard()->setText(currentPath()); } +QString AddressManager::getDomainId() const { + return DependencyManager::get()->getDomainHandler().getUUID().toString(); +} + void AddressManager::handleShareableNameAPIResponse(QNetworkReply& requestReply) { // make sure that this response is for the domain we're currently connected to auto domainID = DependencyManager::get()->getDomainHandler().getUUID(); diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 0c46f9688b..366fc5dfab 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -40,6 +40,7 @@ class AddressManager : public QObject, public Dependency { Q_PROPERTY(QString hostname READ getHost) Q_PROPERTY(QString pathname READ currentPath) Q_PROPERTY(QString placename READ getPlaceName) + Q_PROPERTY(QString domainId READ getDomainId) public: Q_INVOKABLE QString protocolVersion(); using PositionGetter = std::function; @@ -68,6 +69,7 @@ public: const QUuid& getRootPlaceID() const { return _rootPlaceID; } const QString& getPlaceName() const { return _shareablePlaceName.isEmpty() ? _placeName : _shareablePlaceName; } + QString getDomainId() const; const QString& getHost() const { return _host; } diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 5eebadd02f..daee40d576 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -124,6 +124,26 @@ function onClicked() { }, SNAPSHOT_DELAY); } +function isDomainOpen(id) { + var request = new XMLHttpRequest(); + var options = [ + 'now=' + new Date().toISOString(), + 'include_actions=concurrency', + 'domain_id=' + id.slice(1, -1), + 'restriction=open,hifi' // If we're sharing, we're logged in + // If we're here, protocol matches, and it is online + ]; + var url = "https://metaverse.highfidelity.com/api/v1/user_stories?" + options.join('&'); + request.open("GET", url, false); + request.send(); + if (request.status != 200) { + return false; + } + var response = JSON.parse(request.response); // Not parsed for us. + return (response.status === 'success') && + response.total_entries; +} + function resetButtons(path, notify) { // show overlays if they were on if (resetOverlays) { @@ -143,7 +163,7 @@ function resetButtons(path, notify) { confirmShare([ { localPath: path }, { - canShare: !!location.placename, + canShare: !!isDomainOpen(location.domainId), openFeedAfterShare: shouldOpenFeedAfterShare() } ]); From 14857a085a4fb15ae43c3c54a76c10be64bb97d3 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 19 Nov 2016 15:05:53 -0800 Subject: [PATCH 077/104] personal space feature --- assignment-client/src/AvatarAudioTimer.cpp | 1 - assignment-client/src/audio/AudioMixer.cpp | 35 ++- assignment-client/src/audio/AudioMixer.h | 1 + .../src/audio/AudioMixerClientData.cpp | 4 - .../src/audio/AudioMixerClientData.h | 1 + assignment-client/src/avatars/AvatarMixer.cpp | 19 ++ assignment-client/src/avatars/AvatarMixer.h | 1 + .../src/avatars/AvatarMixerClientData.cpp | 13 + .../src/avatars/AvatarMixerClientData.h | 8 + interface/src/ui/PreferencesDialog.cpp | 14 +- libraries/networking/src/Node.cpp | 10 + libraries/networking/src/Node.h | 7 + libraries/networking/src/NodeList.cpp | 22 +- libraries/networking/src/NodeList.h | 13 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- .../src/UsersScriptingInterface.cpp | 24 ++ .../src/UsersScriptingInterface.h | 66 +++++ scripts/defaultScripts.js | 3 +- scripts/system/assets/images/tools/bubble.svg | 275 ++++++++++++++++++ scripts/system/bubble.js | 58 ++++ 20 files changed, 557 insertions(+), 21 deletions(-) create mode 100644 scripts/system/assets/images/tools/bubble.svg create mode 100644 scripts/system/bubble.js diff --git a/assignment-client/src/AvatarAudioTimer.cpp b/assignment-client/src/AvatarAudioTimer.cpp index 77dd61043e..d031b9d9f6 100644 --- a/assignment-client/src/AvatarAudioTimer.cpp +++ b/assignment-client/src/AvatarAudioTimer.cpp @@ -15,7 +15,6 @@ // this should send a signal every 10ms, with pretty good precision. Hardcoding // to 10ms since that's what you'd want for audio. void AvatarAudioTimer::start() { - qDebug() << __FUNCTION__; auto startTime = usecTimestampNow(); quint64 frameCounter = 0; const int TARGET_INTERVAL_USEC = 10000; // 10ms diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index ffd7cc703b..3dba1ce1c2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -95,7 +95,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket"); packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::NodeMuteRequest, this, "handleNodeMuteRequestPacket"); - + packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); } @@ -393,16 +393,26 @@ bool AudioMixer::prepareMixForListeningNode(Node* node) { && !node->isIgnoringNodeWithID(otherNode->getUUID()) && !otherNode->isIgnoringNodeWithID(node->getUUID())) { AudioMixerClientData* otherNodeClientData = (AudioMixerClientData*) otherNode->getLinkedData(); - // enumerate the ARBs attached to the otherNode and add all that should be added to mix - auto streamsCopy = otherNodeClientData->getAudioStreams(); + // check to see if we're ignoring in radius + bool insideIgnoreRadius = false; + if (node->isIgnoreRadiusEnabled() || otherNode->isIgnoreRadiusEnabled()) { + AudioMixerClientData* otherData = reinterpret_cast(otherNode->getLinkedData()); + AudioMixerClientData* nodeData = reinterpret_cast(node->getLinkedData()); + float ignoreRadius = glm::min(node->getIgnoreRadius(), otherNode->getIgnoreRadius()); + if (glm::distance(nodeData->getPosition(), otherData->getPosition()) < ignoreRadius) { + insideIgnoreRadius = true; + } + } - for (auto& streamPair : streamsCopy) { - - auto otherNodeStream = streamPair.second; - - if (*otherNode != *node || otherNodeStream->shouldLoopbackForNode()) { - addStreamToMixForListeningNodeWithStream(*listenerNodeData, *otherNodeStream, otherNode->getUUID(), - *nodeAudioStream); + if (!insideIgnoreRadius) { + // enumerate the ARBs attached to the otherNode and add all that should be added to mix + auto streamsCopy = otherNodeClientData->getAudioStreams(); + for (auto& streamPair : streamsCopy) { + auto otherNodeStream = streamPair.second; + if (*otherNode != *node || otherNodeStream->shouldLoopbackForNode()) { + addStreamToMixForListeningNodeWithStream(*listenerNodeData, *otherNodeStream, otherNode->getUUID(), + *nodeAudioStream); + } } } } @@ -634,11 +644,14 @@ void AudioMixer::handleKillAvatarPacket(QSharedPointer packet, } } - void AudioMixer::handleNodeIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode) { sendingNode->parseIgnoreRequestMessage(packet); } +void AudioMixer::handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode) { + sendingNode->parseIgnoreRadiusRequestMessage(packet); +} + void AudioMixer::removeHRTFsForFinishedInjector(const QUuid& streamID) { auto injectorClientData = qobject_cast(sender()); if (injectorClientData) { diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 91eafadd9d..9bf337fe60 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -48,6 +48,7 @@ private slots: void handleNegotiateAudioFormat(QSharedPointer message, SharedNodePointer sendingNode); void handleNodeKilled(SharedNodePointer killedNode); void handleNodeIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleKillAvatarPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleNodeMuteRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 5b8c4aa105..70d6a67b5b 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -365,10 +365,6 @@ QJsonObject AudioMixerClientData::getAudioStreamStats() { } void AudioMixerClientData::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) { - qDebug() << __FUNCTION__ << - "sendingNode:" << *node << - "currentCodec:" << currentCodec << - "receivedCodec:" << recievedCodec; sendSelectAudioFormat(node, currentCodec); } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index c74461a444..a8b6b6606d 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -89,6 +89,7 @@ public: bool shouldMuteClient() { return _shouldMuteClient; } void setShouldMuteClient(bool shouldMuteClient) { _shouldMuteClient = shouldMuteClient; } + glm::vec3 getPosition() { return getAvatarAudioStream() ? getAvatarAudioStream()->getPosition() : glm::vec3(0); } signals: void injectorStreamFinished(const QUuid& streamIdentifier); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 2c9fadc7b1..63cda4a4ff 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -46,6 +46,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket"); packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket"); + packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &AvatarMixer::handlePacketVersionMismatch); @@ -237,6 +238,20 @@ void AvatarMixer::broadcastAvatarData() { || otherNode->isIgnoringNodeWithID(node->getUUID())) { return false; } else { + AvatarMixerClientData* otherData = reinterpret_cast(otherNode->getLinkedData()); + AvatarMixerClientData* nodeData = reinterpret_cast(node->getLinkedData()); + // check to see if we're ignoring in radius + if (node->isIgnoreRadiusEnabled() || otherNode->isIgnoreRadiusEnabled()) { + float ignoreRadius = glm::min(node->getIgnoreRadius(), otherNode->getIgnoreRadius()); + if (glm::distance(nodeData->getPosition(), otherData->getPosition()) < ignoreRadius) { + nodeData->ignoreOther(node, otherNode); + otherData->ignoreOther(otherNode, node); + return false; + } + } + // not close enough to ignore + nodeData->removeFromRadiusIgnoringSet(otherNode->getUUID()); + otherData->removeFromRadiusIgnoringSet(node->getUUID()); return true; } }, @@ -442,6 +457,10 @@ void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer senderNode->parseIgnoreRequestMessage(message); } +void AvatarMixer::handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode) { + sendingNode->parseIgnoreRadiusRequestMessage(packet); +} + void AvatarMixer::sendStatsPacket() { QJsonObject statsObject; statsObject["average_listeners_last_second"] = (float) _sumListeners / (float) _numStatFrames; diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 6e1d722145..f537cc9244 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -38,6 +38,7 @@ private slots: void handleAvatarIdentityPacket(QSharedPointer message, SharedNodePointer senderNode); void handleKillAvatarPacket(QSharedPointer message); void handleNodeIgnoreRequestPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void domainSettingsRequestComplete(); void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 4b7a696d58..60d03f8930 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -11,6 +11,9 @@ #include +#include +#include + #include "AvatarMixerClientData.h" int AvatarMixerClientData::parseData(ReceivedMessage& message) { @@ -39,6 +42,16 @@ uint16_t AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& node } } +void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointer other) { + if (!isRadiusIgnoring(other->getUUID())) { + addToRadiusIgnoringSet(other->getUUID()); + auto killPacket = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID); + killPacket->write(other->getUUID().toRfc4122()); + DependencyManager::get()->sendUnreliablePacket(*killPacket, *self); + _hasReceivedFirstPacketsFrom.erase(other->getUUID()); + } +} + void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const { jsonObject["display_name"] = _avatar->getDisplayName(); jsonObject["full_rate_distance"] = _fullRateDistance; diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 4a816291f4..96bc275a13 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -79,6 +79,13 @@ public: { return _avgOtherAvatarDataRate.getAverageSampleValuePerSecond() / (float) BYTES_PER_KILOBIT; } void loadJSONStats(QJsonObject& jsonObject) const; + + glm::vec3 getPosition() { return _avatar ? _avatar->getPosition() : glm::vec3(0); } + bool isRadiusIgnoring(const QUuid& other) { return _radiusIgnoredOthers.find(other) != _radiusIgnoredOthers.end(); } + void addToRadiusIgnoringSet(const QUuid& other) { _radiusIgnoredOthers.insert(other); } + void removeFromRadiusIgnoringSet(const QUuid& other) { _radiusIgnoredOthers.erase(other); } + void ignoreOther(SharedNodePointer self, SharedNodePointer other); + private: AvatarSharedPointer _avatar { new AvatarData() }; @@ -99,6 +106,7 @@ private: int _numOutOfOrderSends = 0; SimpleMovingAverage _avgOtherAvatarDataRate; + std::unordered_set _radiusIgnoredOthers; }; #endif // hifi_AvatarMixerClientData_h diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 35af1067d8..dea1c49346 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -32,7 +32,7 @@ void setupPreferences() { auto preferences = DependencyManager::get(); - + auto nodeList = DependencyManager::get(); auto myAvatar = DependencyManager::get()->getMyAvatar(); static const QString AVATAR_BASICS { "Avatar Basics" }; { @@ -68,6 +68,18 @@ void setupPreferences() { auto setter = [=](bool value) { myAvatar->setClearOverlayWhenMoving(value); }; preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Clear overlays when moving", getter, setter)); } + { + auto getter = [=]()->float { return nodeList->getIgnoreRadius(); }; + auto setter = [=](float value) { + nodeList->ignoreNodesInRadius(value, nodeList->getIgnoreRadiusEnabled()); + }; + auto preference = new SpinnerPreference(AVATAR_BASICS, "Personal space bubble radius (default is 1m)", getter, setter); + preference->setMin(0.01f); + preference->setMax(99.9f); + preference->setDecimals(2); + preference->setStep(0.25); + preferences->addPreference(preference); + } // UI { diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 406498b025..36e7cc961b 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -64,6 +64,7 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, { // Update socket's object name setType(_type); + _ignoreRadiusEnabled = false; } void Node::setType(char type) { @@ -101,6 +102,15 @@ void Node::addIgnoredNode(const QUuid& otherNodeID) { } } +void Node::parseIgnoreRadiusRequestMessage(QSharedPointer message) { + bool enabled; + float radius; + message->readPrimitive(&enabled); + message->readPrimitive(&radius); + _ignoreRadiusEnabled = enabled; + _ignoreRadius = radius; +} + QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._type; out << node._uuid; diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 18088c6cea..ab8cdb3a41 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -74,10 +74,14 @@ public: void parseIgnoreRequestMessage(QSharedPointer message); void addIgnoredNode(const QUuid& otherNodeID); bool isIgnoringNodeWithID(const QUuid& nodeID) const { return _ignoredNodeIDSet.find(nodeID) != _ignoredNodeIDSet.cend(); } + void parseIgnoreRadiusRequestMessage(QSharedPointer message); friend QDataStream& operator<<(QDataStream& out, const Node& node); friend QDataStream& operator>>(QDataStream& in, Node& node); + bool isIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled; } + float getIgnoreRadius() { return _ignoreRadiusEnabled ? _ignoreRadius.load() : std::numeric_limits::max(); } + private: // privatize copy and assignment operator to disallow Node copying Node(const Node &otherNode); @@ -94,6 +98,9 @@ private: MovingPercentile _clockSkewMovingPercentile; NodePermissions _permissions; tbb::concurrent_unordered_set _ignoredNodeIDSet; + + std::atomic_bool _ignoreRadiusEnabled; + std::atomic _ignoreRadius { 0.0f }; }; Q_DECLARE_METATYPE(Node*) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 361070b306..86b9bc1794 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -750,9 +750,26 @@ bool NodeList::sockAddrBelongsToDomainOrNode(const HifiSockAddr& sockAddr) { return _domainHandler.getSockAddr() == sockAddr || LimitedNodeList::sockAddrBelongsToNode(sockAddr); } +void NodeList::ignoreNodesInRadius(float radiusToIgnore, bool enabled) { + _ignoreRadiusEnabled.set(enabled); + _ignoreRadius.set(radiusToIgnore); + + eachMatchingNode([](const SharedNodePointer& node)->bool { + return (node->getType() == NodeType::AudioMixer || node->getType() == NodeType::AvatarMixer); + }, [this](const SharedNodePointer& destinationNode) { + sendIgnoreRadiusStateToNode(destinationNode); + }); +} + +void NodeList::sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode) { + auto ignorePacket = NLPacket::create(PacketType::RadiusIgnoreRequest, sizeof(bool) + sizeof(float), true); + ignorePacket->writePrimitive(_ignoreRadiusEnabled.get()); + ignorePacket->writePrimitive(_ignoreRadius.get()); + sendPacket(std::move(ignorePacket), *destinationNode); +} + void NodeList::ignoreNodeBySessionID(const QUuid& nodeID) { // enumerate the nodes to send a reliable ignore packet to each that can leverage it - if (!nodeID.isNull() && _sessionUUID != nodeID) { eachMatchingNode([&nodeID](const SharedNodePointer& node)->bool { if (node->getType() == NodeType::AudioMixer || node->getType() == NodeType::AvatarMixer) { @@ -811,6 +828,9 @@ void NodeList::maybeSendIgnoreSetToNode(SharedNodePointer newNode) { // send this NLPacketList to the new node sendPacketList(std::move(ignorePacketList), *newNode); } + + // also send them the current ignore radius state. + sendIgnoreRadiusStateToNode(newNode); } } diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 4c06a13469..f30283f3c2 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -30,6 +30,7 @@ #include #include +#include #include "DomainHandler.h" #include "LimitedNodeList.h" @@ -70,6 +71,12 @@ public: void setIsShuttingDown(bool isShuttingDown) { _isShuttingDown = isShuttingDown; } + void ignoreNodesInRadius(float radiusToIgnore, bool enabled = true); + float getIgnoreRadius() const { return _ignoreRadius.get(); } + bool getIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled.get(); } + void toggleIgnoreRadius() { ignoreNodesInRadius(getIgnoreRadius(), !getIgnoreRadiusEnabled()); } + void enableIgnoreRadius() { ignoreNodesInRadius(getIgnoreRadius(), true); } + void disableIgnoreRadius() { ignoreNodesInRadius(getIgnoreRadius(), false); } void ignoreNodeBySessionID(const QUuid& nodeID); bool isIgnoringNode(const QUuid& nodeID) const; @@ -101,7 +108,7 @@ signals: void limitOfSilentDomainCheckInsReached(); void receivedDomainServerList(); void ignoredNode(const QUuid& nodeID); - + private slots: void stopKeepalivePingTimer(); void sendPendingDSPathQuery(); @@ -146,6 +153,10 @@ private: mutable QReadWriteLock _ignoredSetLock; tbb::concurrent_unordered_set _ignoredNodeIDs; + void sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode); + Setting::Handle _ignoreRadiusEnabled { "IgnoreRadiusEnabled", false }; + Setting::Handle _ignoreRadius { "IgnoreRadius", 1.0f }; + #if (PR_BUILD || DEV_BUILD) bool _shouldSendNewerVersion { false }; #endif diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 8d63b972cc..2b17aa7d57 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -100,7 +100,8 @@ public: MoreEntityShapes, NodeKickRequest, NodeMuteRequest, - LAST_PACKET_TYPE = NodeMuteRequest + RadiusIgnoreRequest, + LAST_PACKET_TYPE = RadiusIgnoreRequest }; }; diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index 702368c2b3..c809617995 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -38,3 +38,27 @@ bool UsersScriptingInterface::getCanKick() { // ask the NodeList to return our ability to kick return DependencyManager::get()->getThisNodeCanKick(); } + +void UsersScriptingInterface::toggleIgnoreRadius() { + DependencyManager::get()->toggleIgnoreRadius(); +} + +void UsersScriptingInterface::enableIgnoreRadius() { + DependencyManager::get()->enableIgnoreRadius(); +} + +void UsersScriptingInterface::disableIgnoreRadius() { + DependencyManager::get()->disableIgnoreRadius(); +} + +void UsersScriptingInterface::setIgnoreRadius(float radius, bool enabled) { + DependencyManager::get()->ignoreNodesInRadius(radius, enabled); +} + + float UsersScriptingInterface::getIgnoreRadius() { + return DependencyManager::get()->getIgnoreRadius(); +} + +bool UsersScriptingInterface::getIgnoreRadiusEnabled() { + return DependencyManager::get()->getIgnoreRadiusEnabled(); +} diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 3c98d0a393..07398558e5 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -16,6 +16,9 @@ #include +/**jsdoc +* @namespace Users +*/ class UsersScriptingInterface : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -26,12 +29,75 @@ public: UsersScriptingInterface(); public slots: + + /**jsdoc + * Ignore another user. + * @function Users.ignore + * @param {nodeID} nodeID The node or session ID of the user you want to ignore. + */ void ignore(const QUuid& nodeID); + + /**jsdoc + * Kick another user. + * @function Users.kick + * @param {nodeID} nodeID The node or session ID of the user you want to kick. + */ void kick(const QUuid& nodeID); + + /**jsdoc + * Mute another user. + * @function Users.mute + * @param {nodeID} nodeID The node or session ID of the user you want to mute. + */ void mute(const QUuid& nodeID); + /**jsdoc + * Returns `true` if the DomainServer will allow this Node/Avatar to make kick + * @function Users.getCanKick + * @return {bool} `true` if the client can kick other users, `false` if not. + */ bool getCanKick(); + /**jsdoc + * Toggle the state of the ignore in radius feature + * @function Users.toggleIgnoreRadius + */ + void toggleIgnoreRadius(); + + /**jsdoc + * Enables the ignore radius feature. + * @function Users.enableIgnoreRadius + */ + void enableIgnoreRadius(); + + /**jsdoc + * Disables the ignore radius feature. + * @function Users.disableIgnoreRadius + */ + void disableIgnoreRadius(); + + /**jsdoc + * sets the parameters for the ignore radius feature. + * @function Users.setIgnoreRadius + * @param {number} radius The radius for the auto ignore in radius feature + * @param {bool} [enabled=true] Whether the ignore in radius feature should be enabled + */ + void setIgnoreRadius(float radius, bool enabled = true); + + /**jsdoc + * Returns the effective radius of the ingore radius feature if it is enabled. + * @function Users.getIgnoreRadius + * @return {number} radius of the ignore feature + */ + float getIgnoreRadius(); + + /**jsdoc + * Returns `true` if the ignore in radius feature is enabled + * @function Users.getIgnoreRadiusEnabled + * @return {bool} `true` if the ignore in radius feature is enabled, `false` if not. + */ + bool getIgnoreRadiusEnabled(); + signals: void canKickChanged(bool canKick); }; diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 4376960ea5..90a77b508d 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -33,7 +33,8 @@ var DEFAULT_SCRIPTS = [ "system/dialTone.js", "system/firstPersonHMD.js", "system/snapshot.js", - "system/help.js" + "system/help.js", + "system/bubble.js" ]; // add a menu item for debugging diff --git a/scripts/system/assets/images/tools/bubble.svg b/scripts/system/assets/images/tools/bubble.svg new file mode 100644 index 0000000000..064b7734a9 --- /dev/null +++ b/scripts/system/assets/images/tools/bubble.svg @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/system/bubble.js b/scripts/system/bubble.js new file mode 100644 index 0000000000..ba317ecdca --- /dev/null +++ b/scripts/system/bubble.js @@ -0,0 +1,58 @@ +"use strict"; + +// +// bubble.js +// scripts/system/ +// +// Created by Brad Hefta-Gaub on 11/18/2016 +// Copyright 2016 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 +// +/* global Toolbars, Script, Users, Overlays, AvatarList, Controller, Camera, getControllerWorldLocation */ + + +(function() { // BEGIN LOCAL_SCOPE + +// grab the toolbar +var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); + +var ASSETS_PATH = Script.resolvePath("assets"); +var TOOLS_PATH = Script.resolvePath("assets/images/tools/"); + +function buttonImageURL() { + return TOOLS_PATH + 'bubble.svg'; +} + +var bubbleActive = Users.getIgnoreRadiusEnabled(); + +// setup the mod button and add it to the toolbar +var button = toolbar.addButton({ + objectName: 'bubble', + imageURL: buttonImageURL(), + visible: true, + buttonState: bubbleActive ? 0 : 1, + defaultState: bubbleActive ? 0 : 1, + hoverState: bubbleActive ? 2 : 3, + alpha: 0.9 +}); + + +// handle clicks on the toolbar button +function buttonClicked(){ + Users.toggleIgnoreRadius(); + bubbleActive = Users.getIgnoreRadiusEnabled(); + button.writeProperty('buttonState', bubbleActive ? 0 : 1); + button.writeProperty('defaultState', bubbleActive ? 0 : 1); + button.writeProperty('hoverState', bubbleActive ? 2 : 3); +} + +button.clicked.connect(buttonClicked); + +// cleanup the toolbar button and overlays when script is stopped +Script.scriptEnding.connect(function() { + toolbar.removeButton('bubble'); +}); + +}()); // END LOCAL_SCOPE From 8e1f03db430ab5c97affffc45d04210d46a899ef Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 21 Nov 2016 11:34:49 -0800 Subject: [PATCH 078/104] Add AC Audio searcher for tutorial --- tutorial/ACAudioSearchAndInject_tutorial.js | 283 ++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 tutorial/ACAudioSearchAndInject_tutorial.js diff --git a/tutorial/ACAudioSearchAndInject_tutorial.js b/tutorial/ACAudioSearchAndInject_tutorial.js new file mode 100644 index 0000000000..70e936bb1c --- /dev/null +++ b/tutorial/ACAudioSearchAndInject_tutorial.js @@ -0,0 +1,283 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true*/ +/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ +// +// ACAudioSearchAndInject.js +// audio +// +// Created by Eric Levin and Howard Stearns 2/1/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. +// Inject as many as practical into the audio mixer. +// See acAudioSearchAndCompatibilityEntitySpawner.js. +// +// This implementation takes some precautions to scale well: +// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. +// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only +// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). +// This implementation tries to use all the available injectors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +var MSEC_PER_SEC = 1000; +var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. +var old_sound_data_key = "soundKey"; // For backwards compatibility. +var QUERY_RADIUS = 50; // meters +var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. +var EXPIRATION_TIME = 5 * MSEC_PER_SEC; // ms. Remove sounds that have been out of range for this time. +var RECHECK_TIME = 10 * MSEC_PER_SEC; // ms. Check for new userData properties this often when not currently playing. +// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) +var UPDATES_PER_STATS_LOG = RECHECK_TIME / UPDATE_TIME; // (It's nice to smooth out the results by straddling a recheck.) + +var DEFAULT_SOUND_DATA = { + volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. + loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. + playbackGap: MSEC_PER_SEC, // in ms + playbackGapRange: 0 // in ms +}; + +//var isACScript = this.EntityViewer !== undefined; +var isACScript = true; + +Script.include("http://hifi-content.s3.amazonaws.com/ryan/development/utils_ryan.js"); +if (isACScript) { + Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. + Avatar.skeletonModelURL = "http://hifi-content.s3.amazonaws.com/ozan/dev/avatars/invisible_avatar/invisible_avatar.fst"; +} +function ignore() {} +function debug() { // Display the arguments not just [Object object]. + //print.apply(null, [].map.call(arguments, JSON.stringify)); +} + +if (isACScript) { + EntityViewer.setCenterRadius(QUERY_RADIUS); +} + +// ENTITY DATA CACHE +// +var entityCache = {}; // A dictionary of unexpired EntityData objects. +var entityInvalidUserDataCache = {}; // A cache containing the entity IDs that have + // previously been identified as containing non-JSON userData. + // We use a dictionary here so id lookups are constant time. +var examinationCount = 0; +function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. + // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. + var that = this; + that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data + // State Transitions: + // no data => no data | sound data | expired + // expired => stop => remove + // sound data => downloading + // downloading => downloading | waiting + // waiting => playing | waiting (if too many already playing) + // playing => update position etc | no data + that.stop = function stop() { + if (!that.sound) { + return; + } + print("stopping sound", entityIdentifier, that.url); + delete that.sound; + delete that.url; + if (!that.injector) { + return; + } + that.injector.stop(); + delete that.injector; + }; + this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { + if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE + that.stop(); // Alternatively, we could fade out and then stop... + delete entityCache[entityIdentifier]; + return; + } + var properties, soundData; // Latest data, pulled from local octree. + // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. + // Most entity updates are fast and only a very few do getEntityProperties. + function ensureSoundData() { // We only getEntityProperities when we need to. + if (properties) { + return; + } + properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); + examinationCount++; // Collect statistics on how many getEntityProperties we do. + debug("updating", that, properties); + try { + var userData = properties.userData && JSON.parse(properties.userData); + soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. + that.lastUserDataUpdate = now; // But do update these ... + that.url = soundData && soundData.url; + that.playAfter = that.url && now; + } catch (err) { + if (!(entityIdentifier in entityInvalidUserDataCache)) { + print(err, properties.userData); + entityInvalidUserDataCache[entityIdentifier] = true; + } + } + } + // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. + if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA + ensureSoundData(); + } + if (!that.url) { // NO DATA => NO DATA + return that.stop(); + } + if (!that.sound) { // SOUND DATA => DOWNLOADING + that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. + } + if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING + return; + } + if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING + return; + } + ensureSoundData(); // We'll try to play/setOptions and will need position, so we might as well get soundData, too. + if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) + return that.stop(); + } + var options = { + position: properties.position, + loop: soundData.loop || DEFAULT_SOUND_DATA.loop, + volume: soundData.volume || DEFAULT_SOUND_DATA.volume + }; + function repeat() { + return !options.loop && (soundData.playbackGap >= 0); + } + function randomizedNextPlay() { // time of next play or recheck, randomized to distribute the work + var range = soundData.playbackGapRange || DEFAULT_SOUND_DATA.playbackGapRange, + base = repeat() ? ((that.sound.duration * MSEC_PER_SEC) + (soundData.playbackGap || DEFAULT_SOUND_DATA.playbackGap)) : RECHECK_TIME; + return now + base + randFloat(-Math.min(base, range), range); + } + if (that.injector && soundData.playing === false) { + that.injector.stop(); + that.injector = null; + } + if (!that.injector) { + if (soundData.playing === false) { // WAITING => PLAYING | WAITING + return; + } + debug("starting", that, options); + that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. + if (that.injector) { + print("started", entityIdentifier, that.url); + } else { // Don't hammer ensureSoundData or injector manager. + that.playAfter = randomizedNextPlay(); + } + return; + } + that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC + if (!that.injector.playing) { // Subtle: a looping sound will not check playbackGap. + if (repeat()) { // WAITING => PLAYING + // Setup next play just once, now. Changes won't be looked at while we wait. + that.playAfter = randomizedNextPlay(); + // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. + that.injector.restart(); + } else { // PLAYING => NO DATA + that.playAfter = Infinity; // was one-shot and we're finished + } + } + }; +} +function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { + ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. + var entitySound = entityCache[entityIdentifier]; + if (!entitySound) { + entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); + } + entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. +} +var nUpdates = UPDATES_PER_STATS_LOG, lastStats = Date.now(); +function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. + var now = Date.now(), + expirationCutoff = now - EXPIRATION_TIME, + userDataRecheckCutoff = now - RECHECK_TIME; + Object.keys(entityCache).forEach(function (entityIdentifier) { + entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); + }); + if (nUpdates-- <= 0) { // Report statistics. + // For example, with: + // injector-limit = 40 (in C++ code) + // N_SOUNDS = 1000 (from userData in, e.g., acAudioSearchCompatibleEntitySpawner.js) + // replay-period = 3 + 20 = 23 (seconds, ditto) + // stats-period = UPDATES_PER_STATS_LOG * UPDATE_TIME / MSEC_PER_SEC = 10 seconds + // The log should show between each stats report: + // "start" lines ~= injector-limit * P(finish) = injector-limit * stats-period/replay-period = 17 ? + // total attempts at starting ("start" lines + "could not thread" lines) ~= N_SOUNDS = 1000 ? + // entities > N_SOUNDS * (1+ N_SILENT_ENTITIES_PER_SOUND) = 11000 + whatever was in the scene before running spawner + // sounds = N_SOUNDS = 1000 + // getEntityPropertiesPerUpdate ~= playing + failed-starts/UPDATES_PER_STATS_LOG + other-rechecks-each-update + // = injector-limit + (total attempts - "start" lines)/UPDATES_PER_STATS__LOG + // + (entities - playing - failed-starts/UPDATES_PER_STATS_LOG) * P(recheck-in-update) + // where failed-starts/UPDATES_PER_STATS_LOG = (1000-17)/100 = 10 + // = 40 + 10 + (11000 - 40 - 10)*UPDATE_TIME/RECHECK_TIME + // = 40 + 10 + 10950*0.01 = 159 (mostly proportional to enties/RECHECK_TIME) + // millisecondsPerUpdate ~= UPDATE_TIME = 100 (+ some timer machinery time) + // this assignment client activity monitor < 100% cpu + var stats = { + entities: 0, + sounds: 0, + playing: 0, + getEntityPropertiesPerUpdate: examinationCount / UPDATES_PER_STATS_LOG, + millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG + }; + nUpdates = UPDATES_PER_STATS_LOG; + lastStats = now; + examinationCount = 0; + Object.keys(entityCache).forEach(function (entityIdentifier) { + var datum = entityCache[entityIdentifier]; + stats.entities++; + if (datum.url) { + stats.sounds++; + if (datum.injector && datum.injector.playing) { + stats.playing++; + } + } + }); + print(JSON.stringify(stats)); + } +} + +// Update the set of which EntityData we know about. +// +function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. + // This does at most: + // one queryOctree request of the entity server, and + // one findEntities geometry query of our own octree, and + // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. + // The idea is that this is a nice bounded piece of work that should not be done too frequently. + // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. + var avatar = AvatarList.getAvatar(avatarIdentifier), avatarPosition = avatar && avatar.position; + if (!avatarPosition) { // No longer here. + return; + } + var timestamp = Date.now(); + if (isACScript) { + EntityViewer.setPosition(avatarPosition); + EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. + } + var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); + debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); + entities.forEach(function (entityIdentifier) { + internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); + }); +} + +// Slowly update the set of data we have to work with. +// +var workQueue = []; +function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates + workQueue = AvatarList.getAvatarIdentifiers().map(function (avatarIdentifier) { + return function () { + updateEntiesForAvatar(avatarIdentifier); + }; + }); +} +Script.setInterval(function () { + // There might be thousands of EntityData known to us, but only a few will require any work to update. + updateAllEntityData(); // i.e., this better be pretty fast. + // Each interval, we do no more than one updateEntitiesforAvatar. + if (!workQueue.length) { + workQueue = [updateWorkQueueForAvatarsPresent]; + } + workQueue.pop()(); // There's always one +}, UPDATE_TIME); From 728f8aa2388fb50147d10c4e3ea4b4fb895dd615 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 21 Nov 2016 11:56:32 -0800 Subject: [PATCH 079/104] Reduce logspam, change some debug output to warning --- .../gpu-gl/src/gpu/gl/GLBackendOutput.cpp | 6 ++-- libraries/gpu-gl/src/gpu/gl/GLFramebuffer.cpp | 10 +++---- libraries/gpu-gl/src/gpu/gl/GLShader.cpp | 2 +- libraries/gpu-gl/src/gpu/gl/GLShared.cpp | 16 +++++----- libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp | 30 +++++++++---------- .../src/gpu/gl45/GL45BackendTexture.cpp | 18 ++--------- 6 files changed, 34 insertions(+), 48 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp index 2eadd4976a..1e6691538b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp @@ -141,19 +141,19 @@ void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, co auto readFBO = getFramebufferID(srcFramebuffer); if (srcFramebuffer && readFBO) { if ((srcFramebuffer->getWidth() < (region.x + region.z)) || (srcFramebuffer->getHeight() < (region.y + region.w))) { - qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : srcFramebuffer is too small to provide the region queried"; + qCWarning(gpugllogging) << "GLBackend::downloadFramebuffer : srcFramebuffer is too small to provide the region queried"; return; } } if ((destImage.width() < region.z) || (destImage.height() < region.w)) { - qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : destImage is too small to receive the region of the framebuffer"; + qCWarning(gpugllogging) << "GLBackend::downloadFramebuffer : destImage is too small to receive the region of the framebuffer"; return; } GLenum format = GL_BGRA; if (destImage.format() != QImage::Format_ARGB32) { - qCDebug(gpugllogging) << "GLBackend::downloadFramebuffer : destImage format must be FORMAT_ARGB32 to receive the region of the framebuffer"; + qCWarning(gpugllogging) << "GLBackend::downloadFramebuffer : destImage format must be FORMAT_ARGB32 to receive the region of the framebuffer"; return; } diff --git a/libraries/gpu-gl/src/gpu/gl/GLFramebuffer.cpp b/libraries/gpu-gl/src/gpu/gl/GLFramebuffer.cpp index 0ff00697ca..85cf069062 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLFramebuffer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLFramebuffer.cpp @@ -29,19 +29,19 @@ bool GLFramebuffer::checkStatus(GLenum target) const { result = true; break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT."; + qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT."; break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT."; + qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT."; break; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER."; + qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER."; break; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER."; + qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER."; break; case GL_FRAMEBUFFER_UNSUPPORTED: - qCDebug(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED."; + qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED."; break; } return result; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp index 23439a640a..5020ad38a4 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp @@ -119,7 +119,7 @@ GLShader* compileBackendProgram(GLBackend& backend, const Shader& program) { if (object) { shaderGLObjects.push_back(object->_shaderObjects[version].glshader); } else { - qCDebug(gpugllogging) << "GLShader::compileBackendProgram - One of the shaders of the program is not compiled?"; + qCWarning(gpugllogging) << "GLShader::compileBackendProgram - One of the shaders of the program is not compiled?"; return nullptr; } } diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp index 943cb3c7b5..76457206e2 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp @@ -26,25 +26,25 @@ bool checkGLError(const char* name) { } else { switch (error) { case GL_INVALID_ENUM: - qCDebug(gpugllogging) << "GLBackend::" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag."; + qCWarning(gpugllogging) << "GLBackend::" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag."; break; case GL_INVALID_VALUE: - qCDebug(gpugllogging) << "GLBackend" << name << ": A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag"; + qCWarning(gpugllogging) << "GLBackend" << name << ": A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag"; break; case GL_INVALID_OPERATION: - qCDebug(gpugllogging) << "GLBackend" << name << ": The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag.."; + qCWarning(gpugllogging) << "GLBackend" << name << ": The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag.."; break; case GL_INVALID_FRAMEBUFFER_OPERATION: - qCDebug(gpugllogging) << "GLBackend" << name << ": The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag."; + qCWarning(gpugllogging) << "GLBackend" << name << ": The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag."; break; case GL_OUT_OF_MEMORY: - qCDebug(gpugllogging) << "GLBackend" << name << ": There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded."; + qCWarning(gpugllogging) << "GLBackend" << name << ": There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded."; break; case GL_STACK_UNDERFLOW: - qCDebug(gpugllogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to underflow."; + qCWarning(gpugllogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to underflow."; break; case GL_STACK_OVERFLOW: - qCDebug(gpugllogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to overflow."; + qCWarning(gpugllogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to overflow."; break; } return true; @@ -751,7 +751,7 @@ void makeProgramBindings(ShaderObject& shaderObject) { GLint linked = 0; glGetProgramiv(glprogram, GL_LINK_STATUS, &linked); if (!linked) { - qCDebug(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?"; + qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?"; } // now assign the ubo binding, then DON't relink! diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp index 39c3bd2f67..bd945cbaaa 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp @@ -120,7 +120,7 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; } @@ -132,7 +132,7 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { result = GL_RG8; break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; @@ -155,7 +155,7 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { result = GL_COMPRESSED_SRGB; break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; @@ -241,13 +241,13 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { */ default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; } default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } return result; } @@ -280,7 +280,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.internalFormat = GL_DEPTH24_STENCIL8; break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; } @@ -295,7 +295,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.internalFormat = GL_RG8; break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; @@ -318,7 +318,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.internalFormat = GL_COMPRESSED_SRGB; break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; @@ -381,13 +381,13 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E */ default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; } default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } return texel; } else { @@ -523,7 +523,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.internalFormat = GL_DEPTH24_STENCIL8; break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; @@ -539,7 +539,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.internalFormat = GL_RG8; break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; @@ -566,7 +566,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.internalFormat = GL_COMPRESSED_SRGB; break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; } @@ -648,13 +648,13 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA; break; default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } break; } default: - qCDebug(gpugllogging) << "Unknown combination of texel format"; + qCWarning(gpugllogging) << "Unknown combination of texel format"; } return texel; } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 0516bc6be0..fba2c138dc 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -61,7 +61,6 @@ static std::vector getPageDimensionsForFormat(const TextureTypeFormat& ty for (GLint i = 0; i < count; ++i) { result[i] = uvec3(x[i], y[i], z[i]); } - qCDebug(gpugl45logging) << "Got " << count << " page sizes"; } { @@ -91,7 +90,6 @@ SparseInfo::SparseInfo(GL45Texture& texture) void SparseInfo::maybeMakeSparse() { // Don't enable sparse for objects with explicitly managed mip levels if (!texture._gpuObject.isAutogenerateMips()) { - qCDebug(gpugl45logging) << "Don't enable sparse texture for explicitly generated mipmaps on texture " << texture._source.c_str(); return; } @@ -285,11 +283,6 @@ GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& } GL45Texture::~GL45Texture() { - // // External textures cycle very quickly, so don't spam the log with messages about them. - // if (!_gpuObject.getUsage().isExternal()) { - // qCDebug(gpugl45logging) << "Destroying texture " << _id << " from source " << _source.c_str(); - // } - // Remove this texture from the candidate list of derezzable textures if (_transferrable) { auto mipLevels = usedMipLevels(); @@ -350,9 +343,6 @@ void GL45Texture::withPreservedTexture(std::function f) const { } void GL45Texture::generateMips() const { - if (_transferrable) { - qCDebug(gpugl45logging) << "Generating mipmaps for " << _source.c_str(); - } glGenerateTextureMipmap(_id); (void)CHECK_GL_ERROR(); } @@ -628,19 +618,16 @@ void GL45Backend::derezTextures() const { Lock lock(texturesByMipCountsMutex); if (texturesByMipCounts.empty()) { - qCDebug(gpugl45logging) << "No available textures to derez"; + // No available textures to derez return; } auto mipLevel = texturesByMipCounts.rbegin()->first; if (mipLevel <= 1) { - qCDebug(gpugl45logging) << "Max mip levels " << mipLevel; + // No mips available to remove return; } - qCDebug(gpugl45logging) << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); - qCDebug(gpugl45logging) << "Used texture memory " << (Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage()); - GL45Texture* targetTexture = nullptr; { auto& textures = texturesByMipCounts[mipLevel]; @@ -649,5 +636,4 @@ void GL45Backend::derezTextures() const { } lock.unlock(); targetTexture->derez(); - qCDebug(gpugl45logging) << "New Used texture memory " << (Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage()); } From 066a5181421b1c91d8211b6210f99eaf337ae0ec Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 21 Nov 2016 13:07:38 -0800 Subject: [PATCH 080/104] expose metaverse url to javascript and use it rather than hardcoding --- libraries/networking/src/AddressManager.cpp | 5 +++++ libraries/networking/src/AddressManager.h | 2 ++ scripts/system/snapshot.js | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 05210012ba..240c722872 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -24,6 +24,7 @@ #include "AddressManager.h" #include "NodeList.h" +#include "NetworkingConstants.h" #include "NetworkLogging.h" #include "UserActivityLogger.h" #include "udt/PacketHeaders.h" @@ -754,6 +755,10 @@ QString AddressManager::getDomainId() const { return DependencyManager::get()->getDomainHandler().getUUID().toString(); } +const QUrl AddressManager::getMetaverseServerUrl() const { + return NetworkingConstants::METAVERSE_SERVER_URL; +} + void AddressManager::handleShareableNameAPIResponse(QNetworkReply& requestReply) { // make sure that this response is for the domain we're currently connected to auto domainID = DependencyManager::get()->getDomainHandler().getUUID(); diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 366fc5dfab..c7d283ad02 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -41,6 +41,7 @@ class AddressManager : public QObject, public Dependency { Q_PROPERTY(QString pathname READ currentPath) Q_PROPERTY(QString placename READ getPlaceName) Q_PROPERTY(QString domainId READ getDomainId) + Q_PROPERTY(QUrl metaverseServerUrl READ getMetaverseServerUrl) public: Q_INVOKABLE QString protocolVersion(); using PositionGetter = std::function; @@ -70,6 +71,7 @@ public: const QUuid& getRootPlaceID() const { return _rootPlaceID; } const QString& getPlaceName() const { return _shareablePlaceName.isEmpty() ? _placeName : _shareablePlaceName; } QString getDomainId() const; + const QUrl getMetaverseServerUrl() const; const QString& getHost() const { return _host; } diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 6b8e2b32aa..f6ae6d153d 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -133,7 +133,7 @@ function isDomainOpen(id) { 'restriction=open,hifi' // If we're sharing, we're logged in // If we're here, protocol matches, and it is online ]; - var url = "https://metaverse.highfidelity.com/api/v1/user_stories?" + options.join('&'); + var url = location.metaverseServerUrl + "/api/v1/user_stories?" + options.join('&'); request.open("GET", url, false); request.send(); if (request.status != 200) { From 2beed7e70b66ded39acc8107741f2cd4d8ccfcd6 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 21 Nov 2016 16:22:02 -0800 Subject: [PATCH 081/104] proper include_actions for 'places' tab. --- interface/resources/qml/AddressBarDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index a616b05394..db6b87220d 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -438,7 +438,7 @@ Window { function getUserStoryPage(pageNumber, cb) { // cb(error) after all pages of domain data have been added to model var options = [ 'now=' + new Date().toISOString(), - 'include_actions=snapshot,concurrency', + 'include_actions=' + selectedTab.includeActions, 'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'), 'require_online=true', 'protocol=' + encodeURIComponent(AddressManager.protocolVersion()), From 81786bf8197c4ae587c16bd17aa3cf47852957e5 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 21 Nov 2016 16:46:10 -0800 Subject: [PATCH 082/104] animate suggestions when available --- interface/resources/qml/AddressBarDialog.qml | 2 ++ interface/resources/qml/hifi/Card.qml | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index bfb5295512..aab912a201 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -112,6 +112,7 @@ Window { placeName: model.place_name; hifiUrl: model.place_name + model.path; thumbnail: model.thumbnail_url; + imageUrl: model.image_url; action: model.action; timestamp: model.created_at; onlineUsers: model.online_users; @@ -395,6 +396,7 @@ Window { created_at: data.created_at || "", action: data.action || "", thumbnail_url: resolveUrl(thumbnail_url), + image_url: resolveUrl(data.details.image_url), metaverseId: (data.id || "").toString(), // Some are strings from server while others are numbers. Model objects require uniformity. diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index 9e9b1dff51..876be740cd 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -25,6 +25,7 @@ Rectangle { property string timestamp: ""; property string hifiUrl: ""; property string thumbnail: defaultThumbnail; + property string imageUrl: ""; property var goFunction: null; property string storyId: ""; @@ -67,13 +68,21 @@ Rectangle { return 'about a minute ago'; } + property bool hasGif: imageUrl.indexOf('.gif') === (imageUrl.length - 4); + AnimatedImage { + id: animation; + // Always visible, to drive loading, but initially covered up by lobby during load. + source: hasGif ? imageUrl : ""; + fillMode: lobby.fillMode; + anchors.fill: lobby; + } Image { id: lobby; + visible: !hasGif || (animation.status !== Image.Ready); width: parent.width - (isConcurrency ? 0 : (2 * smallMargin)); height: parent.height - messageHeight - (isConcurrency ? 0 : smallMargin); source: thumbnail || defaultThumbnail; fillMode: Image.PreserveAspectCrop; - // source gets filled in later anchors { horizontalCenter: parent.horizontalCenter; top: parent.top; From d69d77d0eed12bc939e667bca0677a12de9d58ae Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 21 Nov 2016 21:36:17 -0800 Subject: [PATCH 083/104] Refactor the audio device format detection. Only use the native format when Qt can correctly determine it. --- libraries/audio-client/src/AudioClient.cpp | 63 +++++++++++++--------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index a05d550fd8..84c64398d3 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -375,41 +375,53 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { return (mode == QAudio::AudioInput) ? QAudioDeviceInfo::defaultInputDevice() : QAudioDeviceInfo::defaultOutputDevice(); } +// attempt to use the native sample rate and channel count +bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, + QAudioFormat& audioFormat) { + + audioFormat = audioDevice.preferredFormat(); + + audioFormat.setCodec("audio/pcm"); + audioFormat.setSampleSize(16); + audioFormat.setSampleType(QAudioFormat::SignedInt); + audioFormat.setByteOrder(QAudioFormat::LittleEndian); + + if (!audioDevice.isFormatSupported(audioFormat)) { + qCDebug(audioclient) << "WARNING: The native format is" << audioFormat << "but isFormatSupported() failed."; + return false; + } + // converting to/from this rate must produce an integral number of samples + if (audioFormat.sampleRate() * AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL % AudioConstants::SAMPLE_RATE != 0) { + qCDebug(audioclient) << "WARNING: The native sample rate [" << audioFormat.sampleRate() << "] is not supported."; + return false; + } + return true; +} + bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, const QAudioFormat& desiredAudioFormat, QAudioFormat& adjustedAudioFormat) { qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat; - adjustedAudioFormat = desiredAudioFormat; +#if defined(Q_OS_ANDROID) || defined(Q_OS_OSX) + // As of Qt5.6, Android returns the native OpenSLES sample rate when possible, else 48000 + // Mac OSX returns the preferred CoreAudio format + if (nativeFormatForAudioDevice(audioDevice, adjustedAudioFormat)) { + return true; + } +#endif #if defined(Q_OS_WIN) - - // On Windows, using WASAPI shared mode, the sample rate and channel count must - // exactly match the internal mix format. Any other format will fail to open. - - adjustedAudioFormat = audioDevice.preferredFormat(); // returns mixFormat - - adjustedAudioFormat.setCodec("audio/pcm"); - adjustedAudioFormat.setSampleSize(16); - adjustedAudioFormat.setSampleType(QAudioFormat::SignedInt); - adjustedAudioFormat.setByteOrder(QAudioFormat::LittleEndian); - - if (!audioDevice.isFormatSupported(adjustedAudioFormat)) { - qCDebug(audioclient) << "WARNING: The mix format is" << adjustedAudioFormat << "but isFormatSupported() failed."; - return false; + if (IsWindows8OrGreater()) { + // On Windows using WASAPI shared-mode, returns the internal mix format + if (nativeFormatForAudioDevice(audioDevice, adjustedAudioFormat)) { + return true; + } } - // converting to/from this rate must produce an integral number of samples - if (adjustedAudioFormat.sampleRate() * AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL % AudioConstants::SAMPLE_RATE != 0) { - qCDebug(audioclient) << "WARNING: The current sample rate [" << adjustedAudioFormat.sampleRate() << "] is not supported."; - return false; - } - return true; +#endif -#elif defined(Q_OS_ANDROID) - // FIXME: query the native sample rate of the device? - adjustedAudioFormat.setSampleRate(48000); -#else + adjustedAudioFormat = desiredAudioFormat; // // Attempt the device sample rate in decreasing order of preference. @@ -433,7 +445,6 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, } else if (audioDevice.supportedSampleRates().contains(176400)) { adjustedAudioFormat.setSampleRate(176400); } -#endif if (adjustedAudioFormat != desiredAudioFormat) { // return the nearest in case it needs 2 channels From dfc0b7beac31630329f56ff9e0260ed76cf64ce2 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 22 Nov 2016 10:15:49 -0800 Subject: [PATCH 084/104] adressed reveiw comments --- .../src/RenderableLightEntityItem.cpp | 16 ++--- .../src/RenderableLightEntityItem.h | 2 +- libraries/entities/src/EntityItem.h | 3 +- .../src/DeferredLightingEffect.cpp | 65 ------------------- 4 files changed, 11 insertions(+), 75 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 2e55901bbd..a7fcbf53ae 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -31,7 +31,7 @@ bool RenderableLightEntityItem::addToScene(EntityItemPointer self, std::shared_p _myItem = scene->allocateID(); auto renderItem = std::make_shared(); - updateRenderItemFromEntity(renderItem.get()); + updateRenderItemFromEntity((*renderItem)); auto renderPayload = std::make_shared(renderItem); @@ -109,24 +109,24 @@ void RenderableLightEntityItem::updateLightFromEntity(render::PendingChanges& pe } - pendingChanges.updateItem(_myItem, [this](LightPayload& data) { - this->updateRenderItemFromEntity(&data); + pendingChanges.updateItem(_myItem, [&](LightPayload& data) { + updateRenderItemFromEntity(data); }); } -void RenderableLightEntityItem::updateRenderItemFromEntity(LightPayload* lightPayload) { +void RenderableLightEntityItem::updateRenderItemFromEntity(LightPayload& lightPayload) { auto entity = this; - lightPayload->setVisible(entity->getVisible()); + lightPayload.setVisible(entity->getVisible()); - auto light = lightPayload->editLight(); + auto light = lightPayload.editLight(); light->setPosition(entity->getPosition()); light->setOrientation(entity->getRotation()); bool success; - lightPayload->editBound() = entity->getAABox(success); + lightPayload.editBound() = entity->getAABox(success); if (!success) { - lightPayload->editBound() = render::Item::Bound(); + lightPayload.editBound() = render::Item::Bound(); } glm::vec3 dimensions = entity->getDimensions(); diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index d37fa30318..36ba0d6311 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -49,7 +49,7 @@ private: // Dirty flag turn true when either setSubClassProperties or readEntitySubclassDataFromBuffer is changing a value - void updateRenderItemFromEntity(LightPayload* lightPayload); + void updateRenderItemFromEntity(LightPayload& lightPayload); }; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index fffdd2e0ff..8100d02e1c 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -95,7 +95,8 @@ public: virtual bool setProperties(const EntityItemProperties& properties); // Set properties for sub class so they can add their own properties - // it does nothing in the root eclass + // it does nothing in the root class + // This function is called by setProperties which then can detects if any property changes value in the SubClass (see aboe comment on setProperties) virtual bool setSubClassProperties(const EntityItemProperties& properties) { return false; } // Update properties with empty parent id and globalized/absolute values (applying offset), and apply (non-empty) log template to args id, name-or-type, parent id. diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index c365ab6a9f..872aac974e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -719,36 +719,9 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), viewport); - // batch.setProjectionTransform(projMat); - // batch.setViewTransform(viewTransform, true); - // gather lights - /* auto& srcPointLights = deferredLightingEffect->_pointLights; - auto& srcSpotLights = deferredLightingEffect->_spotLights; - int numPointLights = (int) srcPointLights.size(); - int offsetPointLights = 0; - int numSpotLights = (int) srcSpotLights.size(); - int offsetSpotLights = numPointLights; - - - std::vector lightIndices(numPointLights + numSpotLights + 1); - lightIndices[0] = 0; - - if (points && !srcPointLights.empty()) { - memcpy(lightIndices.data() + (lightIndices[0] + 1), srcPointLights.data(), srcPointLights.size() * sizeof(int)); - lightIndices[0] += (int)srcPointLights.size(); - } - if (spots && !srcSpotLights.empty()) { - memcpy(lightIndices.data() + (lightIndices[0] + 1), srcSpotLights.data(), srcSpotLights.size() * sizeof(int)); - lightIndices[0] += (int)srcSpotLights.size(); - }*/ - //auto lightClusters = deferredLightingEffect->_lightClusters; auto& lightIndices = lightClusters->_visibleLightIndices; if (!lightIndices.empty() && lightIndices[0] > 0) { - // _localLightsBuffer._buffer->setData(lightIndices.size() * sizeof(int), (const gpu::Byte*) lightIndices.data()); - // _localLightsBuffer._size = lightIndices.size() * sizeof(int); - - // Bind the global list of lights and the visible lights this frame batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, lightClusters->_lightStage->_lightArrayBuffer); @@ -756,44 +729,6 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer); batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer); - - // before we get to the real lighting, let s try to cull down the number of pixels - if (false) {/* - if (numPointLights > 0) { - auto mesh = deferredLightingEffect->getPointLightMesh(); - batch.setIndexBuffer(mesh->getIndexBuffer()); - batch.setInputBuffer(0, mesh->getVertexBuffer()); - batch.setInputFormat(mesh->getVertexFormat()); - auto& pointPart = mesh->getPartBuffer().get(0); - - // Point light pipeline - batch.setPipeline(deferredLightingEffect->_pointLightBack); - - batch.drawIndexedInstanced(numPointLights, model::Mesh::topologyToPrimitive(pointPart._topology), pointPart._numIndices, pointPart._startIndex, offsetPointLights); - - batch.setPipeline(deferredLightingEffect->_pointLightFront); - - batch.drawIndexedInstanced(numPointLights, model::Mesh::topologyToPrimitive(pointPart._topology), pointPart._numIndices, pointPart._startIndex, offsetPointLights); - } - - if (numSpotLights > 0) { - auto mesh = deferredLightingEffect->getSpotLightMesh(); - batch.setIndexBuffer(mesh->getIndexBuffer()); - batch.setInputBuffer(0, mesh->getVertexBuffer()); - batch.setInputFormat(mesh->getVertexFormat()); - auto& conePart = mesh->getPartBuffer().get(0); - - // Spot light pipeline - batch.setPipeline(deferredLightingEffect->_spotLightBack); - - batch.drawIndexedInstanced(numSpotLights, model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex, offsetSpotLights); - - batch.setPipeline(deferredLightingEffect->_spotLightFront); - - batch.drawIndexedInstanced(numSpotLights, model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex, offsetSpotLights); - }*/ - } - // Local light pipeline batch.setPipeline(deferredLightingEffect->_localLight); batch._glUniform4fv(deferredLightingEffect->_localLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); From 5188de924f3418b757f4350f66c4077f0ab3df95 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 22 Nov 2016 11:09:43 -0800 Subject: [PATCH 085/104] allow for SnapshotReview dialog to be up during a change of href for all media capture --- interface/src/Application.cpp | 6 +++--- interface/src/Application.h | 2 +- .../src/scripting/WindowScriptingInterface.cpp | 4 ++-- interface/src/scripting/WindowScriptingInterface.h | 2 +- interface/src/ui/Snapshot.cpp | 14 +++++++++----- interface/src/ui/Snapshot.h | 2 +- scripts/system/snapshot.js | 10 +++++++--- 7 files changed, 24 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 82007c4f06..a072615c03 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5450,10 +5450,10 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa } }); } -void Application::shareSnapshot(const QString& path) { - postLambdaEvent([path] { +void Application::shareSnapshot(const QString& path, const QUrl& href) { + postLambdaEvent([path, href] { // not much to do here, everything is done in snapshot code... - Snapshot::uploadSnapshot(path); + Snapshot::uploadSnapshot(path, href); }); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 8f8b42d66a..5ab94465cc 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -267,7 +267,7 @@ public: float getAverageSimsPerSecond() const { return _simCounter.rate(); } void takeSnapshot(bool notify, bool includeAnimated = false, float aspectRatio = 0.0f); - void shareSnapshot(const QString& filename); + void shareSnapshot(const QString& filename, const QUrl& href = QUrl("")); model::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; } gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; } diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 0cb574c1f6..765c9a8499 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -203,8 +203,8 @@ void WindowScriptingInterface::takeSnapshot(bool notify, bool includeAnimated, f qApp->takeSnapshot(notify, includeAnimated, aspectRatio); } -void WindowScriptingInterface::shareSnapshot(const QString& path) { - qApp->shareSnapshot(path); +void WindowScriptingInterface::shareSnapshot(const QString& path, const QUrl& href) { + qApp->shareSnapshot(path, href); } bool WindowScriptingInterface::isPhysicsEnabled() { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 7246dc0927..2e552d44d1 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -53,7 +53,7 @@ public slots: void showAssetServer(const QString& upload = ""); void copyToClipboard(const QString& text); void takeSnapshot(bool notify = true, bool includeAnimated = false, float aspectRatio = 0.0f); - void shareSnapshot(const QString& path); + void shareSnapshot(const QString& path, const QUrl& href = QUrl("")); bool isPhysicsEnabled(); signals: diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index 5df0d4575b..45e2680032 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -151,13 +151,17 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary) { return imageTempFile; } -void Snapshot::uploadSnapshot(const QString& filename) { +void Snapshot::uploadSnapshot(const QString& filename, const QUrl& href) { const QString SNAPSHOT_UPLOAD_URL = "/api/v1/snapshots"; - // Alternatively to parseSnapshotData, we could pass the inWorldLocation through the call chain. This way is less disruptive to existing code. - SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(filename); - SnapshotUploader* uploader = new SnapshotUploader(snapshotData->getURL(), filename); - delete snapshotData; + SnapshotUploader* uploader; + if (href.isEmpty()) { + SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(filename); + uploader = new SnapshotUploader(snapshotData->getURL(), filename); + delete snapshotData; + } else { + uploader = new SnapshotUploader(href, filename); + } QFile* file = new QFile(filename); Q_ASSERT(file->exists()); diff --git a/interface/src/ui/Snapshot.h b/interface/src/ui/Snapshot.h index 2daed0e860..14e1bc2e9f 100644 --- a/interface/src/ui/Snapshot.h +++ b/interface/src/ui/Snapshot.h @@ -39,7 +39,7 @@ public: static SnapshotMetaData* parseSnapshotData(QString snapshotPath); static Setting::Handle snapshotsLocation; - static void uploadSnapshot(const QString& filename); + static void uploadSnapshot(const QString& filename, const QUrl& href = QUrl("")); private: static QFile* savedFileForSnapshot(QImage & image, bool isTemporary); }; diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index f6ae6d153d..18015a479d 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -71,7 +71,7 @@ function confirmShare(data) { if (submessage.share) { print('sharing', submessage.localPath); outstanding++; - Window.shareSnapshot(submessage.localPath); + Window.shareSnapshot(submessage.localPath, submessage.href); } else { print('not sharing', submessage.localPath); } @@ -159,10 +159,14 @@ function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) { button.writeProperty("hoverState", 3); Window.snapshotTaken.disconnect(resetButtons); + // A Snapshot Review dialog might be left open indefinitely after taking the picture, + // during which time the user may have moved. So stash that info in the dialog so that + // it records the correct href. (We can also stash in .jpegs, but not .gifs.) + var href = location.href; // last element in data array tells dialog whether we can share or not confirmShare([ - { localPath: pathAnimatedSnapshot }, - { localPath: pathStillSnapshot }, + { localPath: pathAnimatedSnapshot, href: href }, + { localPath: pathStillSnapshot, href: href }, { canShare: !!isDomainOpen(location.domainId), openFeedAfterShare: shouldOpenFeedAfterShare() From d764eebc79370e1ac17e50a73ea5611b7791f25b Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 22 Nov 2016 12:10:56 -0800 Subject: [PATCH 086/104] removing dead code --- libraries/render-utils/src/LightClusters.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 829d84e883..d3a384f1df 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -726,13 +726,7 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co // Then the actual ClusterGrid attributes batch.setModelTransform(Transform()); - - // Bind the G-Buffer surfaces -/* batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, deferredFramebuffer->getDeferredColorTexture()); - batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, deferredFramebuffer->getDeferredNormalTexture()); - batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, deferredFramebuffer->getDeferredSpecularTexture()); - batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, deferredFramebuffer->getPrimaryDepthTexture()); -*/ + // Bind the Light CLuster data strucutre batch.setUniformBuffer(LIGHT_GPU_SLOT, lightClusters->_lightStage->_lightArrayBuffer); batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer); batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer); From 3d0b557af6e866c8b3d02424ba9d236b2edd8cf0 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 22 Nov 2016 13:01:02 -0800 Subject: [PATCH 087/104] Fix the bad binding for polyline --- .../src/RenderablePolyLineEntityItem.cpp | 15 +++++++++------ .../src/RenderablePolyLineEntityItem.h | 4 +++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index dc2545b956..286efb5fb8 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -46,7 +46,8 @@ _numVertices(0) gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline; gpu::Stream::FormatPointer RenderablePolyLineEntityItem::_format; -int32_t RenderablePolyLineEntityItem::PAINTSTROKE_GPU_SLOT; +const int32_t RenderablePolyLineEntityItem::PAINTSTROKE_TEXTURE_SLOT; +const int32_t RenderablePolyLineEntityItem::PAINTSTROKE_UNIFORM_SLOT; void RenderablePolyLineEntityItem::createPipeline() { static const int NORMAL_OFFSET = 12; @@ -62,8 +63,8 @@ void RenderablePolyLineEntityItem::createPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; - PAINTSTROKE_GPU_SLOT = 0; - slotBindings.insert(gpu::Shader::Binding(std::string("paintStrokeTextureBinding"), PAINTSTROKE_GPU_SLOT)); + 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()); @@ -193,14 +194,14 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) { Transform transform = Transform(); transform.setTranslation(getPosition()); transform.setRotation(getRotation()); - batch.setUniformBuffer(0, _uniformBuffer); + batch.setUniformBuffer(PAINTSTROKE_UNIFORM_SLOT, _uniformBuffer); batch.setModelTransform(transform); batch.setPipeline(_pipeline); if (_texture->isLoaded()) { - batch.setResourceTexture(PAINTSTROKE_GPU_SLOT, _texture->getGPUTexture()); + batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, _texture->getGPUTexture()); } else { - batch.setResourceTexture(PAINTSTROKE_GPU_SLOT, args->_whiteTexture); + batch.setResourceTexture(PAINTSTROKE_TEXTURE_SLOT, args->_whiteTexture); } batch.setInputFormat(_format); @@ -208,6 +209,8 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) { if (_isFading) { batch._glColor4f(1.0f, 1.0f, 1.0f, Interpolate::calculateFadeRatio(_fadeStartTime)); + } else { + batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } batch.draw(gpu::TRIANGLE_STRIP, _numVertices, 0); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 75b2bcd58a..44b29bdec1 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -40,7 +40,9 @@ public: static gpu::PipelinePointer _pipeline; static gpu::Stream::FormatPointer _format; - static int32_t PAINTSTROKE_GPU_SLOT; + + static const int32_t PAINTSTROKE_TEXTURE_SLOT { 0 }; + static const int32_t PAINTSTROKE_UNIFORM_SLOT { 0 }; protected: void updateGeometry(); From 2c9046742eed14296600c60d661e1413f6e3ae05 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 22 Nov 2016 16:02:01 -0800 Subject: [PATCH 088/104] allow movement during .gif recording --- scripts/system/snapshot.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 18015a479d..439cae22f8 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -14,6 +14,7 @@ var SNAPSHOT_DELAY = 500; // 500ms var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); var resetOverlays; var reticleVisible; +var clearOverlayWhenMoving; var button = toolBar.addButton({ objectName: "snapshot", imageURL: Script.resolvePath("assets/images/tools/snap.svg"), @@ -100,8 +101,13 @@ function snapshotShared(errorMessage) { } function onClicked() { + // Raising the desktop for the share dialog at end will interact badly with clearOverlayWhenMoving. + // Turn it off now, before we start futzing with things (and possibly moving). + clearOverlayWhenMoving = MyAvatar.getClearOverlayWhenMoving(); // Do not use Settings. MyAvatar keeps a separate copy. + MyAvatar.setClearOverlayWhenMoving(false); + // update button states - resetOverlays = Menu.isOptionChecked("Overlays"); + resetOverlays = Menu.isOptionChecked("Overlays"); // For completness. Certainly true if the button is visible to be clicke. reticleVisible = Reticle.visible; Reticle.visible = false; Window.snapshotTaken.connect(resetButtons); @@ -109,7 +115,7 @@ function onClicked() { button.writeProperty("buttonState", 0); button.writeProperty("defaultState", 0); button.writeProperty("hoverState", 2); - + // hide overlays if they are on if (resetOverlays) { Menu.setIsOptionChecked("Overlays", false); @@ -145,10 +151,6 @@ function isDomainOpen(id) { } function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) { - // show overlays if they were on - if (resetOverlays) { - Menu.setIsOptionChecked("Overlays", true); - } // show hud toolBar.writeProperty("visible", true); Reticle.visible = reticleVisible; @@ -158,6 +160,10 @@ function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) { button.writeProperty("defaultState", 1); button.writeProperty("hoverState", 3); Window.snapshotTaken.disconnect(resetButtons); + // show overlays if they were on + if (resetOverlays) { + Menu.setIsOptionChecked("Overlays", true); + } // A Snapshot Review dialog might be left open indefinitely after taking the picture, // during which time the user may have moved. So stash that info in the dialog so that @@ -172,7 +178,10 @@ function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) { openFeedAfterShare: shouldOpenFeedAfterShare() } ]); - } + if (clearOverlayWhenMoving) { + MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog + } +} button.clicked.connect(onClicked); Window.snapshotShared.connect(snapshotShared); From 414371d1fc5b3b53e3742b14a5181f9c9807b55c Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 22 Nov 2016 16:13:08 -0800 Subject: [PATCH 089/104] record starting href/domainId, not ending --- scripts/system/snapshot.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 439cae22f8..f78b7ec985 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -99,13 +99,18 @@ function snapshotShared(errorMessage) { showFeedWindow(); } } - +var href, domainId; function onClicked() { // Raising the desktop for the share dialog at end will interact badly with clearOverlayWhenMoving. // Turn it off now, before we start futzing with things (and possibly moving). clearOverlayWhenMoving = MyAvatar.getClearOverlayWhenMoving(); // Do not use Settings. MyAvatar keeps a separate copy. MyAvatar.setClearOverlayWhenMoving(false); + // We will record snapshots based on the starting location. That could change, e.g., when recording a .gif. + // Even the domainId could change (e.g., if the user falls into a teleporter while recording). + href = location.href; + domainId = location.domainId; + // update button states resetOverlays = Menu.isOptionChecked("Overlays"); // For completness. Certainly true if the button is visible to be clicke. reticleVisible = Reticle.visible; @@ -168,13 +173,12 @@ function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) { // A Snapshot Review dialog might be left open indefinitely after taking the picture, // during which time the user may have moved. So stash that info in the dialog so that // it records the correct href. (We can also stash in .jpegs, but not .gifs.) - var href = location.href; // last element in data array tells dialog whether we can share or not confirmShare([ { localPath: pathAnimatedSnapshot, href: href }, { localPath: pathStillSnapshot, href: href }, { - canShare: !!isDomainOpen(location.domainId), + canShare: !!isDomainOpen(domainId), openFeedAfterShare: shouldOpenFeedAfterShare() } ]); From b24c81e334c8ea5801ef2eeb0462fe4ef2c554fc Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 21 Nov 2016 21:36:17 -0800 Subject: [PATCH 090/104] Refactor the audio device format detection. Only use the native format when Qt can correctly determine it. --- libraries/audio-client/src/AudioClient.cpp | 63 +++++++++++++--------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index a05d550fd8..84c64398d3 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -375,41 +375,53 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { return (mode == QAudio::AudioInput) ? QAudioDeviceInfo::defaultInputDevice() : QAudioDeviceInfo::defaultOutputDevice(); } +// attempt to use the native sample rate and channel count +bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, + QAudioFormat& audioFormat) { + + audioFormat = audioDevice.preferredFormat(); + + audioFormat.setCodec("audio/pcm"); + audioFormat.setSampleSize(16); + audioFormat.setSampleType(QAudioFormat::SignedInt); + audioFormat.setByteOrder(QAudioFormat::LittleEndian); + + if (!audioDevice.isFormatSupported(audioFormat)) { + qCDebug(audioclient) << "WARNING: The native format is" << audioFormat << "but isFormatSupported() failed."; + return false; + } + // converting to/from this rate must produce an integral number of samples + if (audioFormat.sampleRate() * AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL % AudioConstants::SAMPLE_RATE != 0) { + qCDebug(audioclient) << "WARNING: The native sample rate [" << audioFormat.sampleRate() << "] is not supported."; + return false; + } + return true; +} + bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, const QAudioFormat& desiredAudioFormat, QAudioFormat& adjustedAudioFormat) { qCDebug(audioclient) << "The desired format for audio I/O is" << desiredAudioFormat; - adjustedAudioFormat = desiredAudioFormat; +#if defined(Q_OS_ANDROID) || defined(Q_OS_OSX) + // As of Qt5.6, Android returns the native OpenSLES sample rate when possible, else 48000 + // Mac OSX returns the preferred CoreAudio format + if (nativeFormatForAudioDevice(audioDevice, adjustedAudioFormat)) { + return true; + } +#endif #if defined(Q_OS_WIN) - - // On Windows, using WASAPI shared mode, the sample rate and channel count must - // exactly match the internal mix format. Any other format will fail to open. - - adjustedAudioFormat = audioDevice.preferredFormat(); // returns mixFormat - - adjustedAudioFormat.setCodec("audio/pcm"); - adjustedAudioFormat.setSampleSize(16); - adjustedAudioFormat.setSampleType(QAudioFormat::SignedInt); - adjustedAudioFormat.setByteOrder(QAudioFormat::LittleEndian); - - if (!audioDevice.isFormatSupported(adjustedAudioFormat)) { - qCDebug(audioclient) << "WARNING: The mix format is" << adjustedAudioFormat << "but isFormatSupported() failed."; - return false; + if (IsWindows8OrGreater()) { + // On Windows using WASAPI shared-mode, returns the internal mix format + if (nativeFormatForAudioDevice(audioDevice, adjustedAudioFormat)) { + return true; + } } - // converting to/from this rate must produce an integral number of samples - if (adjustedAudioFormat.sampleRate() * AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL % AudioConstants::SAMPLE_RATE != 0) { - qCDebug(audioclient) << "WARNING: The current sample rate [" << adjustedAudioFormat.sampleRate() << "] is not supported."; - return false; - } - return true; +#endif -#elif defined(Q_OS_ANDROID) - // FIXME: query the native sample rate of the device? - adjustedAudioFormat.setSampleRate(48000); -#else + adjustedAudioFormat = desiredAudioFormat; // // Attempt the device sample rate in decreasing order of preference. @@ -433,7 +445,6 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, } else if (audioDevice.supportedSampleRates().contains(176400)) { adjustedAudioFormat.setSampleRate(176400); } -#endif if (adjustedAudioFormat != desiredAudioFormat) { // return the nearest in case it needs 2 channels From 9b0ce556e79fac4f4281e7c20ceff4cee87f532a Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 23 Nov 2016 10:10:00 -0800 Subject: [PATCH 091/104] Added preferences for the Perception Neuron plugin. By default this plugin is disabled. The server address and port number are also configurable. --- .../hifi/dialogs/GeneralPreferencesDialog.qml | 2 +- plugins/hifiNeuron/src/NeuronPlugin.cpp | 119 ++++++++++++++---- plugins/hifiNeuron/src/NeuronPlugin.h | 4 +- 3 files changed, 99 insertions(+), 26 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml index 9e46d86ecd..fec836626f 100644 --- a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml @@ -17,7 +17,7 @@ PreferencesDialog { id: root objectName: "GeneralPreferencesDialog" title: "General Settings" - showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers"] + showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron"] property var settings: Settings { category: root.objectName property alias x: root.x diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index aec8bf072a..93e7da028f 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include Q_DECLARE_LOGGING_CATEGORY(inputplugins) Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") @@ -30,6 +32,10 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") const char* NeuronPlugin::NAME = "Neuron"; const char* NeuronPlugin::NEURON_ID_STRING = "Perception Neuron"; +const bool DEFAULT_ENABLED = false; +const QString DEFAULT_SERVER_ADDRESS = "localhost"; +const int DEFAULT_SERVER_PORT = 7001; + // indices of joints of the Neuron standard skeleton. // This is 'almost' the same as the High Fidelity standard skeleton. // It is missing a thumb joint. @@ -356,6 +362,39 @@ static void SocketStatusChangedCallback(void* context, SOCKET_REF sender, Socket // NeuronPlugin // +void NeuronPlugin::init() { + loadSettings(); + + auto preferences = DependencyManager::get(); + static const QString NEURON_PLUGIN { "Perception Neuron" }; + { + auto getter = [this]()->QString { return _serverAddress; }; + auto setter = [this](const QString& value) { _serverAddress = value; saveSettings(); }; + auto preference = new EditPreference(NEURON_PLUGIN, "Server Address", getter, setter); + preference->setPlaceholderText(""); + preferences->addPreference(preference); + } + { + static const int MIN_PORT_NUMBER { 0 }; + static const int MAX_PORT_NUMBER { 65535 }; + + auto getter = [this]()->float { return (float)_serverPort; }; + auto setter = [this](float value) { _serverPort = (int)value; saveSettings(); }; + auto preference = new SpinnerPreference(NEURON_PLUGIN, "Server Port", getter, setter); + + preference->setMin(MIN_PORT_NUMBER); + preference->setMax(MAX_PORT_NUMBER); + preference->setStep(1); + preferences->addPreference(preference); + } + { + auto getter = [this]()->bool { return _enabled; }; + auto setter = [this](bool value) { _enabled = value; saveSettings(); }; + auto preference = new CheckPreference(NEURON_PLUGIN, "Enabled", getter, setter); + preferences->addPreference(preference); + } +} + bool NeuronPlugin::isSupported() const { // Because it's a client/server network architecture, we can't tell // if the neuron is actually connected until we connect to the server. @@ -365,32 +404,37 @@ bool NeuronPlugin::isSupported() const { bool NeuronPlugin::activate() { InputPlugin::activate(); - // register with userInputMapper - auto userInputMapper = DependencyManager::get(); - userInputMapper->registerDevice(_inputDevice); + loadSettings(); - // register c-style callbacks - BRRegisterFrameDataCallback((void*)this, FrameDataReceivedCallback); - BRRegisterCommandDataCallback((void*)this, CommandDataReceivedCallback); - BRRegisterSocketStatusCallback((void*)this, SocketStatusChangedCallback); + if (_enabled) { - // TODO: Pull these from prefs dialog? - // localhost is fine for now. - _serverAddress = "localhost"; - _serverPort = 7001; // default port for TCP Axis Neuron server. + // register with userInputMapper + auto userInputMapper = DependencyManager::get(); + userInputMapper->registerDevice(_inputDevice); - _socketRef = BRConnectTo((char*)_serverAddress.c_str(), _serverPort); - if (!_socketRef) { - // error - qCCritical(inputplugins) << "NeuronPlugin: error connecting to " << _serverAddress.c_str() << ":" << _serverPort << ", error = " << BRGetLastErrorMessage(); - return false; + // register c-style callbacks + BRRegisterFrameDataCallback((void*)this, FrameDataReceivedCallback); + BRRegisterCommandDataCallback((void*)this, CommandDataReceivedCallback); + BRRegisterSocketStatusCallback((void*)this, SocketStatusChangedCallback); + + // convert _serverAddress into a c-string. + QByteArray serverAddressByteArray = _serverAddress.toUtf8(); + char* cstr = serverAddressByteArray.data(); + + _socketRef = BRConnectTo(cstr, _serverPort); + if (!_socketRef) { + qCWarning(inputplugins) << "NeuronPlugin: error connecting to " << _serverAddress << ":" << _serverPort << ", error = " << BRGetLastErrorMessage(); + return false; + } else { + qCDebug(inputplugins) << "NeuronPlugin: success connecting to " << _serverAddress << ":" << _serverPort; + + emit deviceConnected(getName()); + + BRRegisterAutoSyncParmeter(_socketRef, Cmd_CombinationMode); + return true; + } } else { - qCDebug(inputplugins) << "NeuronPlugin: success connecting to " << _serverAddress.c_str() << ":" << _serverPort; - - emit deviceConnected(getName()); - - BRRegisterAutoSyncParmeter(_socketRef, Cmd_CombinationMode); - return true; + return false; } } @@ -407,6 +451,7 @@ void NeuronPlugin::deactivate() { } InputPlugin::deactivate(); + saveSettings(); } void NeuronPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { @@ -426,11 +471,36 @@ void NeuronPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrat } void NeuronPlugin::saveSettings() const { - InputPlugin::saveSettings(); + Settings settings; + QString idString = getID(); + settings.beginGroup(idString); + { + settings.setValue(QString("enabled"), _enabled); + settings.setValue(QString("serverAddress"), _serverAddress); + settings.setValue(QString("serverPort"), _serverPort); + } + settings.endGroup(); } void NeuronPlugin::loadSettings() { - InputPlugin::loadSettings(); + Settings settings; + QString idString = getID(); + settings.beginGroup(idString); + { + // enabled + _enabled = settings.value("enabled", QVariant(DEFAULT_ENABLED)).toBool(); + + // serverAddress + _serverAddress = settings.value("serverAddress", QVariant(DEFAULT_SERVER_ADDRESS)).toString(); + + // serverPort + bool canConvertPortToInt = false; + int port = settings.value("serverPort", QVariant(DEFAULT_SERVER_PORT)).toInt(&canConvertPortToInt); + if (canConvertPortToInt) { + _serverPort = port; + } + } + settings.endGroup(); } // @@ -478,3 +548,4 @@ void NeuronPlugin::InputDevice::update(float deltaTime, const controller::InputC _poseStateMap[controller::RIGHT_HAND_THUMB1] = controller::Pose(rightHandThumb1DefaultAbsTranslation, glm::quat(), glm::vec3(), glm::vec3()); _poseStateMap[controller::LEFT_HAND_THUMB1] = controller::Pose(leftHandThumb1DefaultAbsTranslation, glm::quat(), glm::vec3(), glm::vec3()); } + diff --git a/plugins/hifiNeuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h index 36dcf93c23..43b27d14dd 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -28,6 +28,7 @@ public: bool isHandController() const override { return false; } // Plugin functions + virtual void init() override; virtual bool isSupported() const override; virtual const QString getName() const override { return NAME; } const QString getID() const override { return NEURON_ID_STRING; } @@ -68,7 +69,8 @@ protected: static const char* NAME; static const char* NEURON_ID_STRING; - std::string _serverAddress; + bool _enabled; + QString _serverAddress; int _serverPort; void* _socketRef; From cbf514a738e0116d39b7d83e703af9dc7a5d9420 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 23 Nov 2016 10:11:28 -0800 Subject: [PATCH 092/104] PreferenceDialogs now preserve the sort order of their showCategories. Specifically, this was to fix the issue with the Neuron plugin preferences being the top section in the General Preferences dialog, now it is the last. --- .../qml/dialogs/PreferencesDialog.qml | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index ac9aad0e4a..e16f3aa12d 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -55,22 +55,20 @@ ScrollingWindow { Component.onCompleted: { var categories = Preferences.categories; - var categoryMap; var i; - if (showCategories && showCategories.length) { - categoryMap = {}; - for (i = 0; i < showCategories.length; ++i) { - categoryMap[showCategories[i]] = true; - } + + // build a map of valid categories. + var categoryMap = {}; + for (i = 0; i < categories.length; i++) { + categoryMap[categories[i]] = true; } - for (i = 0; i < categories.length; ++i) { - var category = categories[i]; - if (categoryMap && !categoryMap[category]) { - continue; + // create a section for each valid category in showCategories + // NOTE: the sort order of items in the showCategories array is the same order in the dialog. + for (i = 0; i < showCategories.length; i++) { + if (categoryMap[showCategories[i]]) { + sections.push(sectionBuilder.createObject(prefControls, {name: showCategories[i]})); } - - sections.push(sectionBuilder.createObject(prefControls, { name: category })); } if (sections.length) { From 8b9efb461e5711b706bc7fb6772890462869a57d Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 23 Nov 2016 10:22:24 -0800 Subject: [PATCH 093/104] bubble state --- libraries/networking/src/NodeList.cpp | 6 +++++ libraries/networking/src/NodeList.h | 5 ++-- .../src/UsersScriptingInterface.cpp | 1 + .../src/UsersScriptingInterface.h | 1 + scripts/system/bubble.js | 26 ++++++++----------- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 86b9bc1794..d960fb6db9 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -886,3 +886,9 @@ void NodeList::muteNodeBySessionID(const QUuid& nodeID) { } } + +void NodeList::toggleIgnoreRadius() { + bool isIgnored = !getIgnoreRadiusEnabled(); + ignoreNodesInRadius(getIgnoreRadius(), isIgnored); + emit ignoreRadiusEnabledChanged(isIgnored); +} \ No newline at end of file diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index f30283f3c2..c453dbb766 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -74,7 +74,7 @@ public: void ignoreNodesInRadius(float radiusToIgnore, bool enabled = true); float getIgnoreRadius() const { return _ignoreRadius.get(); } bool getIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled.get(); } - void toggleIgnoreRadius() { ignoreNodesInRadius(getIgnoreRadius(), !getIgnoreRadiusEnabled()); } + void toggleIgnoreRadius(); void enableIgnoreRadius() { ignoreNodesInRadius(getIgnoreRadius(), true); } void disableIgnoreRadius() { ignoreNodesInRadius(getIgnoreRadius(), false); } void ignoreNodeBySessionID(const QUuid& nodeID); @@ -108,6 +108,7 @@ signals: void limitOfSilentDomainCheckInsReached(); void receivedDomainServerList(); void ignoredNode(const QUuid& nodeID); + void ignoreRadiusEnabledChanged(bool isIgnored); private slots: void stopKeepalivePingTimer(); @@ -154,7 +155,7 @@ private: tbb::concurrent_unordered_set _ignoredNodeIDs; void sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode); - Setting::Handle _ignoreRadiusEnabled { "IgnoreRadiusEnabled", false }; + Setting::Handle _ignoreRadiusEnabled { "IgnoreRadiusEnabled", true }; Setting::Handle _ignoreRadius { "IgnoreRadius", 1.0f }; #if (PR_BUILD || DEV_BUILD) diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index c809617995..368b7f3985 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -17,6 +17,7 @@ UsersScriptingInterface::UsersScriptingInterface() { // emit a signal when kick permissions have changed auto nodeList = DependencyManager::get(); connect(nodeList.data(), &LimitedNodeList::canKickChanged, this, &UsersScriptingInterface::canKickChanged); + connect(nodeList.data(), &NodeList::ignoreRadiusEnabledChanged, this, &UsersScriptingInterface::ignoreRadiusEnabledChanged); } void UsersScriptingInterface::ignore(const QUuid& nodeID) { diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 07398558e5..c621fd9284 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -100,6 +100,7 @@ public slots: signals: void canKickChanged(bool canKick); + void ignoreRadiusEnabledChanged(bool isEnabled); }; diff --git a/scripts/system/bubble.js b/scripts/system/bubble.js index ba317ecdca..408f3acffa 100644 --- a/scripts/system/bubble.js +++ b/scripts/system/bubble.js @@ -25,34 +25,30 @@ function buttonImageURL() { return TOOLS_PATH + 'bubble.svg'; } -var bubbleActive = Users.getIgnoreRadiusEnabled(); +function onBubbleToggled() { + var bubbleActive = Users.getIgnoreRadiusEnabled(); + button.writeProperty('buttonState', bubbleActive ? 0 : 1); + button.writeProperty('defaultState', bubbleActive ? 0 : 1); + button.writeProperty('hoverState', bubbleActive ? 2 : 3); +} // setup the mod button and add it to the toolbar var button = toolbar.addButton({ objectName: 'bubble', imageURL: buttonImageURL(), visible: true, - buttonState: bubbleActive ? 0 : 1, - defaultState: bubbleActive ? 0 : 1, - hoverState: bubbleActive ? 2 : 3, alpha: 0.9 }); +onBubbleToggled(); - -// handle clicks on the toolbar button -function buttonClicked(){ - Users.toggleIgnoreRadius(); - bubbleActive = Users.getIgnoreRadiusEnabled(); - button.writeProperty('buttonState', bubbleActive ? 0 : 1); - button.writeProperty('defaultState', bubbleActive ? 0 : 1); - button.writeProperty('hoverState', bubbleActive ? 2 : 3); -} - -button.clicked.connect(buttonClicked); +button.clicked.connect(Users.toggleIgnoreRadius); +Users.ignoreRadiusEnabledChanged.connect(onBubbleToggled); // cleanup the toolbar button and overlays when script is stopped Script.scriptEnding.connect(function() { toolbar.removeButton('bubble'); + button.clicked.disconnect(Users.toggleIgnoreRadius); + Users.ignoreRadiusEnabledChanged.disconnect(onBubbleToggled); }); }()); // END LOCAL_SCOPE From f2118614da629bd7fa98cad7702ef846758418c0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 23 Nov 2016 10:30:52 -0800 Subject: [PATCH 094/104] Fix camera in render perf test --- tests/render-perf/src/Camera.hpp | 27 ++++++++++++++------------- tests/render-perf/src/main.cpp | 5 +++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/render-perf/src/Camera.hpp b/tests/render-perf/src/Camera.hpp index 6e1d95bfe1..a3b33ceb14 100644 --- a/tests/render-perf/src/Camera.hpp +++ b/tests/render-perf/src/Camera.hpp @@ -13,11 +13,11 @@ protected: } public: - glm::quat getOrientation() const { - return glm::angleAxis(yawPitch.x, Vectors::UP) * glm::angleAxis(yawPitch.y, Vectors::RIGHT); + const glm::quat& getOrientation() const { + return orientation; } - vec2 yawPitch { 0 }; + glm::quat orientation; glm::vec3 position; float rotationSpeed { 1.0f }; float movementSpeed { 1.0f }; @@ -77,24 +77,25 @@ public: }; void rotate(const float delta) { - yawPitch.x += delta; + orientation = glm::angleAxis(delta, Vectors::UP) * orientation; updateViewMatrix(); } void rotate(const glm::vec2& delta) { - yawPitch += delta; + + // create orientation vectors + auto lookat = orientation * Vectors::UNIT_NEG_Z; + auto forward = glm::normalize(vec3(lookat.x, 0, lookat.z)); + auto side = glm::cross(Vectors::UP, forward); + + // rotate camera with quaternions created from axis and angle + orientation = glm::angleAxis(delta.x, Vectors::UP) * orientation; + orientation = glm::angleAxis(-delta.y, side) * orientation; updateViewMatrix(); } void setRotation(const glm::quat& rotation) { - glm::vec3 f = rotation * Vectors::UNIT_NEG_Z; - f.y = 0; - f = glm::normalize(f); - yawPitch.x = angleBetween(Vectors::UNIT_NEG_Z, f); - f = rotation * Vectors::UNIT_NEG_Z; - f.x = 0; - f = glm::normalize(f); - yawPitch.y = angleBetween(Vectors::UNIT_NEG_Z, f); + orientation = rotation; updateViewMatrix(); } diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index b152c4b4bf..3be1a92af1 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -946,7 +946,7 @@ private: orientationRegex.cap(3).toFloat(), orientationRegex.cap(4).toFloat()); if (!glm::any(glm::isnan(v))) { - _camera.setRotation(glm::normalize(glm::quat(v.w, v.x, v.y, v.z))); + _camera.setRotation(glm::quat(v.w, v.x, v.y, v.z)); } } } @@ -1008,6 +1008,7 @@ private: arg(v.x).arg(v.y).arg(v.z). arg(q.x).arg(q.y).arg(q.z).arg(q.w); _settings.setValue(LAST_LOCATION_KEY, viewpoint); + _camera.setRotation(q); } void restorePosition() { @@ -1019,7 +1020,7 @@ private: } void resetPosition() { - _camera.yawPitch = vec3(0); + _camera.setRotation(quat()); _camera.setPosition(vec3()); } From 4e0c6e5d0f793c31cb242b4099e5da073bac5e20 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 23 Nov 2016 11:00:31 -0800 Subject: [PATCH 095/104] handle empty snapshot text data more broadly (and at the same time, don't lie from parseSnapshotData). --- interface/src/ui/Snapshot.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index 45e2680032..06aa90386b 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -63,8 +63,6 @@ SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) { // parsing URL url = QUrl(shot.text(URL), QUrl::ParsingMode::StrictMode); - } else if (snapshotPath.right(3) == "gif") { - url = QUrl(DependencyManager::get()->currentShareableAddress()); } else { return NULL; } @@ -154,14 +152,16 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary) { void Snapshot::uploadSnapshot(const QString& filename, const QUrl& href) { const QString SNAPSHOT_UPLOAD_URL = "/api/v1/snapshots"; - SnapshotUploader* uploader; - if (href.isEmpty()) { + QUrl url = href; + if (url.isEmpty()) { SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(filename); - uploader = new SnapshotUploader(snapshotData->getURL(), filename); + url = snapshotData->getURL(); delete snapshotData; - } else { - uploader = new SnapshotUploader(href, filename); } + if (url.isEmpty()) { + url = QUrl(DependencyManager::get()->currentShareableAddress()); + } + SnapshotUploader* uploader = new SnapshotUploader(url, filename); QFile* file = new QFile(filename); Q_ASSERT(file->exists()); From b37feb20deb15c0c01ef8f281ee7d7742078bc9e Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 23 Nov 2016 11:23:06 -0800 Subject: [PATCH 096/104] signal from ignoreNodesInRadius --- libraries/networking/src/NodeList.cpp | 10 ++++------ libraries/networking/src/NodeList.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index d960fb6db9..dfb65a70ec 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -751,6 +751,7 @@ bool NodeList::sockAddrBelongsToDomainOrNode(const HifiSockAddr& sockAddr) { } void NodeList::ignoreNodesInRadius(float radiusToIgnore, bool enabled) { + bool isEnabledChange = _ignoreRadiusEnabled.get() != enabled; _ignoreRadiusEnabled.set(enabled); _ignoreRadius.set(radiusToIgnore); @@ -759,6 +760,9 @@ void NodeList::ignoreNodesInRadius(float radiusToIgnore, bool enabled) { }, [this](const SharedNodePointer& destinationNode) { sendIgnoreRadiusStateToNode(destinationNode); }); + if (isEnabledChange) { + emit ignoreRadiusEnabledChanged(enabled); + } } void NodeList::sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode) { @@ -886,9 +890,3 @@ void NodeList::muteNodeBySessionID(const QUuid& nodeID) { } } - -void NodeList::toggleIgnoreRadius() { - bool isIgnored = !getIgnoreRadiusEnabled(); - ignoreNodesInRadius(getIgnoreRadius(), isIgnored); - emit ignoreRadiusEnabledChanged(isIgnored); -} \ No newline at end of file diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index c453dbb766..3bf44bbdf4 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -74,7 +74,7 @@ public: void ignoreNodesInRadius(float radiusToIgnore, bool enabled = true); float getIgnoreRadius() const { return _ignoreRadius.get(); } bool getIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled.get(); } - void toggleIgnoreRadius(); + void toggleIgnoreRadius() { ignoreNodesInRadius(getIgnoreRadius(), !getIgnoreRadiusEnabled()); } void enableIgnoreRadius() { ignoreNodesInRadius(getIgnoreRadius(), true); } void disableIgnoreRadius() { ignoreNodesInRadius(getIgnoreRadius(), false); } void ignoreNodeBySessionID(const QUuid& nodeID); From bf0f56c138e2577c0e6cd3ba50197e9e14a4d64d Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 23 Nov 2016 15:27:24 -0800 Subject: [PATCH 097/104] null guard --- interface/src/ui/Snapshot.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index 06aa90386b..f75190530c 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -155,7 +155,9 @@ void Snapshot::uploadSnapshot(const QString& filename, const QUrl& href) { QUrl url = href; if (url.isEmpty()) { SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(filename); - url = snapshotData->getURL(); + if (snapshotData) { + url = snapshotData->getURL(); + } delete snapshotData; } if (url.isEmpty()) { From 1974ded0505f89f6df712156d43391142b29a1e5 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 23 Nov 2016 16:37:06 -0800 Subject: [PATCH 098/104] Potentially address the crash when no vertex format is specified --- .../gpu-gl/src/gpu/gl45/GL45BackendInput.cpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp index 25f8c83074..01bd2d7bce 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp @@ -81,24 +81,23 @@ void GL45Backend::updateInput() { glVertexBindingDivisor(bufferChannelNum, frequency); #endif } - - - // Manage Activation what was and what is expected now - // This should only disable VertexAttribs since the one in use have been disabled above - for (GLuint i = 0; i < (GLuint)newActivation.size(); i++) { - bool newState = newActivation[i]; - if (newState != _input._attributeActivation[i]) { - if (newState) { - glEnableVertexAttribArray(i); - } else { - glDisableVertexAttribArray(i); - } - _input._attributeActivation.flip(i); - } - } - (void)CHECK_GL_ERROR(); } + // Manage Activation what was and what is expected now + // This should only disable VertexAttribs since the one needed by the vertex format (if it exists) have been enabled above + for (GLuint i = 0; i < (GLuint)newActivation.size(); i++) { + bool newState = newActivation[i]; + if (newState != _input._attributeActivation[i]) { + if (newState) { + glEnableVertexAttribArray(i); + } else { + glDisableVertexAttribArray(i); + } + _input._attributeActivation.flip(i); + } + } + (void)CHECK_GL_ERROR(); + _input._invalidFormat = false; _stats._ISNumFormatChanges++; } From 4be1922df5a89656f382e60ec5879e270ccbbf8f Mon Sep 17 00:00:00 2001 From: Ryan Jones Date: Mon, 28 Nov 2016 14:47:15 -0800 Subject: [PATCH 099/104] add bind polyfill --- scripts/system/libraries/utils.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index b7de9b012c..6a3f20717e 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -6,6 +6,34 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +if (!Function.prototype.bind) { + Function.prototype.bind = function(oThis) { + if (typeof this !== 'function') { + // closest thing possible to the ECMAScript 5 + // internal IsCallable function + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function() {}, + fBound = function() { + return fToBind.apply(this instanceof fNOP + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + if (this.prototype) { + // Function.prototype doesn't have a prototype property + fNOP.prototype = this.prototype; + } + fBound.prototype = new fNOP(); + + return fBound; + }; +} + vec3toStr = function(v, digits) { if (!digits) { digits = 3; } return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits)+ " }"; From 68e86da023fbc48880e123c930874c253bbb8abf Mon Sep 17 00:00:00 2001 From: Ryan Jones Date: Mon, 28 Nov 2016 17:10:59 -0800 Subject: [PATCH 100/104] adjust indentation and implement editorconfig at root of repo --- .editorconfig | 6 ++++++ scripts/developer/libraries/utils.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..70dee8a217 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,6 @@ +root = true + +# 4-space indentation +[*] +indent_style = space +indent_size = 4 \ No newline at end of file diff --git a/scripts/developer/libraries/utils.js b/scripts/developer/libraries/utils.js index f39f4d7913..64f3b2c9e0 100644 --- a/scripts/developer/libraries/utils.js +++ b/scripts/developer/libraries/utils.js @@ -6,6 +6,34 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +if (!Function.prototype.bind) { + Function.prototype.bind = function(oThis) { + if (typeof this !== 'function') { + // closest thing possible to the ECMAScript 5 + // internal IsCallable function + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function() {}, + fBound = function() { + return fToBind.apply(this instanceof fNOP + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + if (this.prototype) { + // Function.prototype doesn't have a prototype property + fNOP.prototype = this.prototype; + } + fBound.prototype = new fNOP(); + + return fBound; + }; +} + vec3toStr = function(v, digits) { if (!digits) { digits = 3; } return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits)+ " }"; From 3961dbcf55f48be8c8b303e38ad57de7c3817d53 Mon Sep 17 00:00:00 2001 From: Ryan Jones Date: Mon, 28 Nov 2016 17:18:31 -0800 Subject: [PATCH 101/104] revert changes to dev utils, apply changes to system utils --- scripts/developer/libraries/utils.js | 28 ---------------------------- scripts/system/libraries/utils.js | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 39 deletions(-) diff --git a/scripts/developer/libraries/utils.js b/scripts/developer/libraries/utils.js index 64f3b2c9e0..f39f4d7913 100644 --- a/scripts/developer/libraries/utils.js +++ b/scripts/developer/libraries/utils.js @@ -6,34 +6,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -if (!Function.prototype.bind) { - Function.prototype.bind = function(oThis) { - if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function() {}, - fBound = function() { - return fToBind.apply(this instanceof fNOP - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - if (this.prototype) { - // Function.prototype doesn't have a prototype property - fNOP.prototype = this.prototype; - } - fBound.prototype = new fNOP(); - - return fBound; - }; -} - vec3toStr = function(v, digits) { if (!digits) { digits = 3; } return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits)+ " }"; diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index 6a3f20717e..3d03f51e78 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -7,31 +7,31 @@ // if (!Function.prototype.bind) { - Function.prototype.bind = function(oThis) { +Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + // closest thing possible to the ECMAScript 5 + // internal IsCallable function + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { - return fToBind.apply(this instanceof fNOP - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); + return fToBind.apply(this instanceof fNOP + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); }; if (this.prototype) { - // Function.prototype doesn't have a prototype property - fNOP.prototype = this.prototype; + // Function.prototype doesn't have a prototype property + fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; - }; + }; } vec3toStr = function(v, digits) { From a59df5b04d84630f794774e0300e200dab701fb1 Mon Sep 17 00:00:00 2001 From: Ryan Jones Date: Mon, 28 Nov 2016 17:19:43 -0800 Subject: [PATCH 102/104] one last indentation fix --- scripts/system/libraries/utils.js | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index 3d03f51e78..9bd29d663a 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -7,30 +7,30 @@ // if (!Function.prototype.bind) { -Function.prototype.bind = function(oThis) { - if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); - } + Function.prototype.bind = function(oThis) { + if (typeof this !== 'function') { + // closest thing possible to the ECMAScript 5 + // internal IsCallable function + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + } - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function() {}, - fBound = function() { - return fToBind.apply(this instanceof fNOP - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function() {}, + fBound = function() { + return fToBind.apply(this instanceof fNOP + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; - if (this.prototype) { - // Function.prototype doesn't have a prototype property - fNOP.prototype = this.prototype; - } - fBound.prototype = new fNOP(); + if (this.prototype) { + // Function.prototype doesn't have a prototype property + fNOP.prototype = this.prototype; + } + fBound.prototype = new fNOP(); - return fBound; + return fBound; }; } From 251b070db314c5c7e13fd389f69bf78eb2adc55c Mon Sep 17 00:00:00 2001 From: Ryan Jones Date: Tue, 29 Nov 2016 11:50:11 -0800 Subject: [PATCH 103/104] add unit test --- scripts/developer/tests/bindUnitTest.js | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 scripts/developer/tests/bindUnitTest.js diff --git a/scripts/developer/tests/bindUnitTest.js b/scripts/developer/tests/bindUnitTest.js new file mode 100644 index 0000000000..38c2fb350f --- /dev/null +++ b/scripts/developer/tests/bindUnitTest.js @@ -0,0 +1,31 @@ +Script.include('../libraries/jasmine/jasmine.js'); +Script.include('../libraries/jasmine/hifi-boot.js'); +Script.include('../../system/libraries/utils.js'); + +describe('Bind', function() { + it('functions should have bind available', function() { + var foo = 'bar'; + + function callAnotherFn(anotherFn) { + return anotherFn(); + } + + function TestConstructor() { + this.foo = foo; + } + + TestConstructor.prototype.doSomething = function() { + return callAnotherFn(function() { + return this.foo; + }.bind(this)); + } + + var instance = new TestConstructor(); + + expect(typeof(instance.doSomething.bind) !== 'undefined'); + expect(instance.doSomething()).toEqual(foo); + }); +}); + +jasmine.getEnv().execute(); +Script.stop(); \ No newline at end of file From 01ae2b945248ac11f6c5f02cb2769d5fd645b2be Mon Sep 17 00:00:00 2001 From: Ryan Jones Date: Tue, 29 Nov 2016 11:56:11 -0800 Subject: [PATCH 104/104] add errant semicolon --- scripts/developer/tests/bindUnitTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/developer/tests/bindUnitTest.js b/scripts/developer/tests/bindUnitTest.js index 38c2fb350f..95fd497916 100644 --- a/scripts/developer/tests/bindUnitTest.js +++ b/scripts/developer/tests/bindUnitTest.js @@ -18,7 +18,7 @@ describe('Bind', function() { return callAnotherFn(function() { return this.foo; }.bind(this)); - } + }; var instance = new TestConstructor();