From afb1ebf42e6094ecd79862edee4b457bdf51b1ad Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 26 Jul 2016 23:19:41 -0700 Subject: [PATCH 01/71] Revolutionizing ao --- .../src/AmbientOcclusionEffect.cpp | 207 ++++++++++++------ .../render-utils/src/AmbientOcclusionEffect.h | 51 ++++- .../render-utils/src/DebugDeferredBuffer.cpp | 17 +- .../render-utils/src/DebugDeferredBuffer.h | 3 +- .../src/DeferredLightingEffect.cpp | 11 +- .../render-utils/src/DeferredLightingEffect.h | 5 +- .../render-utils/src/FramebufferCache.cpp | 70 ------ libraries/render-utils/src/FramebufferCache.h | 17 -- .../render-utils/src/RenderDeferredTask.cpp | 7 +- .../render-utils/src/SurfaceGeometryPass.cpp | 2 +- libraries/render-utils/src/ssao.slh | 3 + .../render-utils/src/ssao_makeOcclusion.slf | 18 +- 12 files changed, 221 insertions(+), 190 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 4b283731d2..929f4896b3 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -33,6 +33,91 @@ #include "ssao_makeHorizontalBlur_frag.h" #include "ssao_makeVerticalBlur_frag.h" + +AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { +} + +void AmbientOcclusionFramebuffer::updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer) { + //If the depth buffer or size changed, we need to delete our FBOs + bool reset = false; + if ((_linearDepthTexture != linearDepthBuffer)) { + _linearDepthTexture = linearDepthBuffer; + reset = true; + } + if (_linearDepthTexture) { + auto newFrameSize = glm::ivec2(_linearDepthTexture->getDimensions()); + if (_frameSize != newFrameSize) { + _frameSize = newFrameSize; + reset = true; + } + } + + if (reset) { + clear(); + } +} + +void AmbientOcclusionFramebuffer::clear() { + _occlusionFramebuffer.reset(); + _occlusionTexture.reset(); + _occlusionBlurredFramebuffer.reset(); + _occlusionBlurredTexture.reset(); +} + +gpu::TexturePointer AmbientOcclusionFramebuffer::getLinearDepthTexture() { + return _linearDepthTexture; +} + +void AmbientOcclusionFramebuffer::allocate() { + + auto width = _frameSize.x; + auto height = _frameSize.y; + + _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); + _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); + + _occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); + _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); +} + +gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionFramebuffer() { + if (!_occlusionFramebuffer) { + allocate(); + } + return _occlusionFramebuffer; +} + +gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionTexture() { + if (!_occlusionTexture) { + allocate(); + } + return _occlusionTexture; +} + +gpu::FramebufferPointer AmbientOcclusionFramebuffer::getOcclusionBlurredFramebuffer() { + if (!_occlusionBlurredFramebuffer) { + allocate(); + } + return _occlusionBlurredFramebuffer; +} + +gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionBlurredTexture() { + if (!_occlusionBlurredTexture) { + allocate(); + } + return _occlusionBlurredTexture; +} + +void AmbientOcclusionFramebuffer::setResolutionLevel(int resolutionLevel) { + if (resolutionLevel != getResolutionLevel()) { + clear(); + _resolutionLevel = resolutionLevel; + } +} + + class GaussianDistribution { public: @@ -90,8 +175,7 @@ public: const int AmbientOcclusionEffect_FrameTransformSlot = 0; const int AmbientOcclusionEffect_ParamsSlot = 1; -const int AmbientOcclusionEffect_DepthMapSlot = 0; -const int AmbientOcclusionEffect_PyramidMapSlot = 0; +const int AmbientOcclusionEffect_LinearDepthMapSlot = 0; const int AmbientOcclusionEffect_OcclusionMapSlot = 0; AmbientOcclusionEffect::AmbientOcclusionEffect() { @@ -147,13 +231,22 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.y = 1.0f / config.numSamples; } + if (!_framebuffer) { + _framebuffer = std::make_shared(); + } + + _framebuffer->setResolutionLevel(config.resolutionLevel); + if (config.resolutionLevel != getResolutionLevel()) { + _parametersBuffer.edit().resolutionInfo.w = config.resolutionLevel; + } + const auto& resolutionLevel = config.resolutionLevel; if (resolutionLevel != getResolutionLevel()) { auto& current = _parametersBuffer.edit().resolutionInfo; current.x = (float)resolutionLevel; // Communicate the change to the Framebuffer cache - DependencyManager::get()->setAmbientOcclusionResolutionLevel(resolutionLevel); + // DependencyManager::get()->setAmbientOcclusionResolutionLevel(resolutionLevel); } if (config.blurRadius != getBlurRadius()) { @@ -177,32 +270,6 @@ void AmbientOcclusionEffect::configure(const Config& config) { } } -const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() { - if (!_pyramidPipeline) { - auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(ssao_makePyramid_frag)); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), AmbientOcclusionEffect_DepthMapSlot)); - gpu::Shader::makeProgram(*program, slotBindings); - - - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - - // Stencil test the pyramid passe 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->setColorWriteMask(true, false, false, false); - - // Good to go add the brand new pipeline - _pyramidPipeline = gpu::Pipeline::create(program, state); - } - return _pyramidPipeline; -} - const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { if (!_occlusionPipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); @@ -212,7 +279,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); - slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_PyramidMapSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_LinearDepthMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -282,8 +349,7 @@ void AmbientOcclusionEffect::updateGaussianDistribution() { GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, getBlurRadius(), getBlurDeviation()); } -void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { -#ifdef FIX_THE_FRAMEBUFFER_CACHE +void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); @@ -294,18 +360,39 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext return; } - auto framebufferCache = DependencyManager::get(); - auto depthBuffer = framebufferCache->getPrimaryDepthTexture(); - auto normalBuffer = framebufferCache->getDeferredNormalTexture(); - auto pyramidFBO = framebufferCache->getDepthPyramidFramebuffer(); - auto occlusionFBO = framebufferCache->getOcclusionFramebuffer(); - auto occlusionBlurredFBO = framebufferCache->getOcclusionBlurredFramebuffer(); + const auto frameTransform = inputs.get0(); + const auto deferredFramebuffer = inputs.get1(); + const auto linearDepthFramebuffer = inputs.get2(); + + auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); + auto normalTexture = deferredFramebuffer->getDeferredNormalTexture(); + auto sourceViewport = args->_viewport; + auto occlusionViewport = sourceViewport; - QSize framebufferSize = framebufferCache->getFrameBufferSize(); - float sMin = args->_viewport.x / (float)framebufferSize.width(); - float sWidth = args->_viewport.z / (float)framebufferSize.width(); - float tMin = args->_viewport.y / (float)framebufferSize.height(); - float tHeight = args->_viewport.w / (float)framebufferSize.height(); + if (!_framebuffer) { + _framebuffer = std::make_shared(); + } + + if (_framebuffer->getResolutionLevel() > 0) { + linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); + normalTexture = linearDepthFramebuffer->getHalfNormalTexture(); + occlusionViewport = occlusionViewport >> _framebuffer->getResolutionLevel(); + } + + _framebuffer->updateLinearDepth(linearDepthTexture); + + + auto occlusionFBO = _framebuffer->getOcclusionFramebuffer(); + auto occlusionBlurredFBO = _framebuffer->getOcclusionBlurredFramebuffer(); + + outputs = _framebuffer; + + auto framebufferSize = _framebuffer->getSourceFrameSize(); + + float sMin = args->_viewport.x / (float)framebufferSize.x; + float sWidth = args->_viewport.z / (float)framebufferSize.x; + float tMin = args->_viewport.y / (float)framebufferSize.y; + float tHeight = args->_viewport.w / (float)framebufferSize.y; auto resolutionLevel = getResolutionLevel(); @@ -341,7 +428,6 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext } - auto pyramidPipeline = getPyramidPipeline(); auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); auto lastVBlurPipeline = getVBlurPipeline(); @@ -351,7 +437,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext _gpuTimer.begin(batch); - batch.setViewportTransform(args->_viewport); + batch.setViewportTransform(occlusionViewport); batch.setProjectionTransform(glm::mat4()); batch.setViewTransform(Transform()); @@ -363,32 +449,18 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, _frameTransformBuffer); batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, _parametersBuffer); - - // Pyramid pass - batch.setFramebuffer(pyramidFBO); - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(args->getViewFrustum().getFarClip(), 0.0f, 0.0f, 0.0f)); - batch.setPipeline(pyramidPipeline); - batch.setResourceTexture(AmbientOcclusionEffect_DepthMapSlot, depthBuffer); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - // Make pyramid mips - batch.generateTextureMips(pyramidFBO->getRenderBuffer(0)); - - // Adjust Viewport for rendering resolution - if (resolutionLevel > 0) { - glm::ivec4 viewport(args->_viewport.x, args->_viewport.y, args->_viewport.z >> resolutionLevel, args->_viewport.w >> resolutionLevel); - batch.setViewportTransform(viewport); - } - + + // batch.generateTextureMips(linearDepthTexture); + // Occlusion pass batch.setFramebuffer(occlusionFBO); batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); batch.setPipeline(occlusionPipeline); - batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0)); + batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, linearDepthTexture); batch.draw(gpu::TRIANGLE_STRIP, 4); - if (getBlurRadius() > 0) { + /* if (getBlurRadius() > 0) { // Blur 1st pass batch.setFramebuffer(occlusionBlurredFBO); batch.setPipeline(firstHBlurPipeline); @@ -400,12 +472,15 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.setPipeline(lastVBlurPipeline); batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionBlurredFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); - } + }*/ + + + batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, nullptr); + batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, nullptr); _gpuTimer.end(batch); }); // Update the timer std::static_pointer_cast(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage(); -#endif } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 717c9dc4fc..8c458a5879 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -16,6 +16,47 @@ #include "render/DrawTask.h" +#include "DeferredFrameTransform.h" +#include "DeferredFramebuffer.h" +#include "SurfaceGeometryPass.h" + +class AmbientOcclusionFramebuffer { +public: + AmbientOcclusionFramebuffer(); + + gpu::FramebufferPointer getOcclusionFramebuffer(); + gpu::TexturePointer getOcclusionTexture(); + + gpu::FramebufferPointer getOcclusionBlurredFramebuffer(); + gpu::TexturePointer getOcclusionBlurredTexture(); + + // Update the source framebuffer size which will drive the allocation of all the other resources. + void updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); + gpu::TexturePointer getLinearDepthTexture(); + const glm::ivec2& getSourceFrameSize() const { return _frameSize; } + + void setResolutionLevel(int level); + int getResolutionLevel() const { return _resolutionLevel; } + +protected: + void clear(); + void allocate(); + + gpu::TexturePointer _linearDepthTexture; + + gpu::FramebufferPointer _occlusionFramebuffer; + gpu::TexturePointer _occlusionTexture; + + gpu::FramebufferPointer _occlusionBlurredFramebuffer; + gpu::TexturePointer _occlusionBlurredTexture; + + + glm::ivec2 _frameSize; + int _resolutionLevel{ 0 }; +}; + +using AmbientOcclusionFramebufferPointer = std::shared_ptr; + class AmbientOcclusionEffectConfig : public render::Job::Config::Persistent { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty) @@ -67,13 +108,15 @@ signals: class AmbientOcclusionEffect { public: + using Inputs = render::VaryingSet3; + using Outputs = AmbientOcclusionFramebufferPointer; using Config = AmbientOcclusionEffectConfig; - using JobModel = render::Job::Model; + using JobModel = render::Job::ModelIO; AmbientOcclusionEffect(); void configure(const Config& config); - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); float getRadius() const { return _parametersBuffer.get().radiusInfo.x; } float getObscuranceLevel() const { return _parametersBuffer.get().radiusInfo.w; } @@ -131,16 +174,16 @@ private: }; gpu::BufferView _parametersBuffer; - const gpu::PipelinePointer& getPyramidPipeline(); const gpu::PipelinePointer& getOcclusionPipeline(); const gpu::PipelinePointer& getHBlurPipeline(); // first const gpu::PipelinePointer& getVBlurPipeline(); // second - gpu::PipelinePointer _pyramidPipeline; gpu::PipelinePointer _occlusionPipeline; gpu::PipelinePointer _hBlurPipeline; gpu::PipelinePointer _vBlurPipeline; + AmbientOcclusionFramebufferPointer _framebuffer; + gpu::RangeTimer _gpuTimer; }; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 8118df5435..ed4eba972f 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -202,14 +202,14 @@ static const std::string DEFAULT_DEBUG_SCATTERING_SHADER{ static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{ "vec4 getFragmentColor() {" - " return vec4(vec3(texture(obscuranceMap, uv).x), 1.0);" + " return vec4(vec3(texture(obscuranceMap, uv).xyz), 1.0);" // When drawing color " return vec4(vec3(texture(occlusionMap, uv).xyz), 1.0);" - // when drawing normal " return vec4(normalize(texture(occlusionMap, uv).xyz * 2.0 - vec3(1.0)), 1.0);" + // when drawing normal" return vec4(normalize(texture(occlusionMap, uv).xyz * 2.0 - vec3(1.0)), 1.0);" " }" }; static const std::string DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER{ "vec4 getFragmentColor() {" - " return vec4(vec3(texture(occlusionBlurredMap, uv).x), 1.0);" + " return vec4(vec3(texture(occlusionBlurredMap, uv).xyz), 1.0);" " }" }; @@ -379,6 +379,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren auto& deferredFramebuffer = inputs.get0(); auto& linearDepthTarget = inputs.get1(); auto& surfaceGeometryFramebuffer = inputs.get2(); + auto& ambientOcclusionFramebuffer = inputs.get3(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); @@ -414,13 +415,9 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setResourceTexture(Curvature, surfaceGeometryFramebuffer->getCurvatureTexture()); batch.setResourceTexture(DiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture()); - if (DependencyManager::get()->isAmbientOcclusionEnabled()) { - batch.setResourceTexture(AmbientOcclusion, framebufferCache->getOcclusionTexture()); - } else { - // need to assign the white texture if ao is off - batch.setResourceTexture(AmbientOcclusion, textureCache->getWhiteTexture()); - } - batch.setResourceTexture(AmbientOcclusionBlurred, framebufferCache->getOcclusionBlurredTexture()); + + 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); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index d6005de349..da78ac081a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -17,6 +17,7 @@ #include #include "DeferredFramebuffer.h" #include "SurfaceGeometryPass.h" +#include "AmbientOcclusionEffect.h" class DebugDeferredBufferConfig : public render::Job::Config { Q_OBJECT @@ -36,7 +37,7 @@ signals: class DebugDeferredBuffer { public: - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet4; using Config = DebugDeferredBufferConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 6f202f6200..9038b8bada 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -400,7 +400,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c const DeferredFramebufferPointer& deferredFramebuffer, const LightingModelPointer& lightingModel, const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer, - const gpu::FramebufferPointer& lowCurvatureNormalFramebuffer, + const AmbientOcclusionFramebufferPointer& ambientOcclusionFramebuffer, const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource) { auto args = renderContext->args; @@ -431,7 +431,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c // FIXME: Different render modes should have different tasks if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && deferredLightingEffect->isAmbientOcclusionEnabled()) { - batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, framebufferCache->getOcclusionTexture()); + batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, ambientOcclusionFramebuffer->getOcclusionTexture()); } else { // need to assign the white texture if ao is off batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, textureCache->getWhiteTexture()); @@ -446,9 +446,6 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c // Subsurface scattering specific if (surfaceGeometryFramebuffer) { batch.setResourceTexture(DEFERRED_BUFFER_CURVATURE_UNIT, surfaceGeometryFramebuffer->getCurvatureTexture()); - } - if (lowCurvatureNormalFramebuffer) { - // batch.setResourceTexture(DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, lowCurvatureNormalFramebuffer->getRenderBuffer(0)); batch.setResourceTexture(DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, surfaceGeometryFramebuffer->getLowCurvatureTexture()); } if (subsurfaceScatteringResource) { @@ -693,7 +690,7 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo auto deferredFramebuffer = inputs.get1(); auto lightingModel = inputs.get2(); auto surfaceGeometryFramebuffer = inputs.get3(); - auto lowCurvatureNormalFramebuffer = inputs.get4(); + auto ssaoFramebuffer = inputs.get4(); auto subsurfaceScatteringResource = inputs.get5(); auto args = renderContext->args; @@ -701,7 +698,7 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo _gpuTimer.begin(batch); }); - setupJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, lowCurvatureNormalFramebuffer, subsurfaceScatteringResource); + setupJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, ssaoFramebuffer, subsurfaceScatteringResource); lightsJob.run(sceneContext, renderContext, deferredTransform, deferredFramebuffer, lightingModel); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index b309299be9..466c58c36e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -30,6 +30,7 @@ #include "LightStage.h" #include "SurfaceGeometryPass.h" #include "SubsurfaceScattering.h" +#include "AmbientOcclusionEffect.h" class RenderArgs; struct LightLocations; @@ -138,7 +139,7 @@ public: const DeferredFramebufferPointer& deferredFramebuffer, const LightingModelPointer& lightingModel, const SurfaceGeometryFramebufferPointer& surfaceGeometryFramebuffer, - const gpu::FramebufferPointer& lowCurvatureNormalFramebuffer, + const AmbientOcclusionFramebufferPointer& ambientOcclusionFramebuffer, const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource); }; @@ -178,7 +179,7 @@ signals: class RenderDeferred { public: - using Inputs = render::VaryingSet6 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer, gpu::FramebufferPointer, SubsurfaceScatteringResourcePointer>; + using Inputs = render::VaryingSet6 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer, SubsurfaceScatteringResourcePointer>; using Config = RenderDeferredConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 5375de273a..ff0fb8db50 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -35,10 +35,6 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { _frameBufferSize = frameBufferSize; _selfieFramebuffer.reset(); _cachedFramebuffers.clear(); - _occlusionFramebuffer.reset(); - _occlusionTexture.reset(); - _occlusionBlurredFramebuffer.reset(); - _occlusionBlurredTexture.reset(); } } @@ -54,35 +50,6 @@ void FramebufferCache::createPrimaryFramebuffer() { _selfieFramebuffer->setRenderBuffer(0, tex); auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); - - - - resizeAmbientOcclusionBuffers(); -} - - -void FramebufferCache::resizeAmbientOcclusionBuffers() { - _occlusionFramebuffer.reset(); - _occlusionTexture.reset(); - _occlusionBlurredFramebuffer.reset(); - _occlusionBlurredTexture.reset(); - - - auto width = _frameBufferSize.width() >> _AOResolutionLevel; - auto height = _frameBufferSize.height() >> _AOResolutionLevel; - auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGB); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); - // auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format - - _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); - _occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture); - // _occlusionFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); - - _occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); - _occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture); - // _occlusionBlurredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); } @@ -107,40 +74,3 @@ gpu::FramebufferPointer FramebufferCache::getSelfieFramebuffer() { } return _selfieFramebuffer; } - -void FramebufferCache::setAmbientOcclusionResolutionLevel(int level) { - const int MAX_AO_RESOLUTION_LEVEL = 4; - level = std::max(0, std::min(level, MAX_AO_RESOLUTION_LEVEL)); - if (level != _AOResolutionLevel) { - _AOResolutionLevel = level; - resizeAmbientOcclusionBuffers(); - } -} - -gpu::FramebufferPointer FramebufferCache::getOcclusionFramebuffer() { - if (!_occlusionFramebuffer) { - resizeAmbientOcclusionBuffers(); - } - return _occlusionFramebuffer; -} - -gpu::TexturePointer FramebufferCache::getOcclusionTexture() { - if (!_occlusionTexture) { - resizeAmbientOcclusionBuffers(); - } - return _occlusionTexture; -} - -gpu::FramebufferPointer FramebufferCache::getOcclusionBlurredFramebuffer() { - if (!_occlusionBlurredFramebuffer) { - resizeAmbientOcclusionBuffers(); - } - return _occlusionBlurredFramebuffer; -} - -gpu::TexturePointer FramebufferCache::getOcclusionBlurredTexture() { - if (!_occlusionBlurredTexture) { - resizeAmbientOcclusionBuffers(); - } - return _occlusionBlurredTexture; -} \ No newline at end of file diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index d3d26c35b0..2f521d7677 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -30,12 +30,6 @@ public: void setFrameBufferSize(QSize frameBufferSize); const QSize& getFrameBufferSize() const { return _frameBufferSize; } - void setAmbientOcclusionResolutionLevel(int level); - gpu::FramebufferPointer getOcclusionFramebuffer(); - gpu::TexturePointer getOcclusionTexture(); - gpu::FramebufferPointer getOcclusionBlurredFramebuffer(); - gpu::TexturePointer getOcclusionBlurredTexture(); - /// Returns the framebuffer object used to render selfie maps; gpu::FramebufferPointer getSelfieFramebuffer(); @@ -56,18 +50,7 @@ private: gpu::FramebufferPointer _selfieFramebuffer; - gpu::FramebufferPointer _occlusionFramebuffer; - gpu::TexturePointer _occlusionTexture; - - gpu::FramebufferPointer _occlusionBlurredFramebuffer; - gpu::TexturePointer _occlusionBlurredTexture; - QSize _frameBufferSize{ 100, 100 }; - int _AOResolutionLevel = 1; // AO perform at half res - - // Resize/reallocate the buffers used for AO - // the size of the AO buffers is scaled by the AOResolutionScale; - void resizeAmbientOcclusionBuffers(); }; #endif // hifi_FramebufferCache_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index bb7adf3f80..afff4bac72 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -141,13 +141,14 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { const auto scatteringResource = addJob("Scattering"); // AO job - addJob("AmbientOcclusion"); + const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying(); + const auto ambientOcclusionFramebuffer = addJob("AmbientOcclusion", ambientOcclusionInputs); // 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, lowCurvatureNormalFramebuffer, scatteringResource).hasVarying(); + surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying(); // DeferredBuffer is complete, now let's shade it into the LightingBuffer addJob("RenderDeferred", deferredLightingInputs); @@ -178,7 +179,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { addJob("DebugScattering", deferredLightingInputs); // Debugging Deferred buffer job - const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, lowCurvatureNormalFramebuffer)); + const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); addJob("DebugDeferredBuffer", debugFramebuffers); // Scene Octree Debuging job diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index fd778d30be..6dc1cb2f9b 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -193,7 +193,7 @@ void LinearDepthPass::run(const render::SceneContextPointer& sceneContext, const batch.setResourceTexture(DepthLinearPass_NormalMapSlot, normalTexture); batch.setPipeline(downsamplePipeline); batch.draw(gpu::TRIANGLE_STRIP, 4); - + _gpuTimer.end(batch); }); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 5fcd224e9d..21e9a5a297 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -76,6 +76,9 @@ bool isStereo() { float getStereoSideWidth() { return float(int(frameTransform._stereoInfo.y) >> getResolutionLevel()); } +float getStereoSideHeight() { + return float(int(frameTransform._pixelInfo.w) >> getResolutionLevel()); +} ivec3 getStereoSideInfo(int xPos) { int sideWidth = int(getStereoSideWidth()); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 01e44d0bb9..7512d6568c 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -21,7 +21,7 @@ const int MAX_MIP_LEVEL = 5; uniform sampler2D pyramidMap; float getZEye(ivec2 pixel) { - return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; + return -texelFetch(pyramidMap, pixel, 0/*getResolutionLevel()*/).x; } vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { @@ -112,7 +112,7 @@ void main(void) { // From now on, ssC is the pixel pos in the side ssC.x -= side.y; - vec2 fragPos = (vec2(ssC) + 0.5) / getStereoSideWidth(); + vec2 fragPos = (vec2(ssC) + 0.5) / vec2(getStereoSideWidth(), getStereoSideHeight()); // The position and normal of the pixel fragment in Eye space vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos); @@ -146,16 +146,16 @@ void main(void) { outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); - + // vec3 v = normalize(Q - Cp); + //outFragColor = vec4((v + vec3(1.0))* 0.5, 1.0); + // outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); } From beb42332ef8b0a102854b689b9015228acadb97f Mon Sep 17 00:00:00 2001 From: samcake Date: Sun, 31 Jul 2016 16:05:25 -0700 Subject: [PATCH 02/71] save the current state of adding debug and evolving the ao job --- .../src/AmbientOcclusionEffect.cpp | 227 ++++++++++++------ .../render-utils/src/AmbientOcclusionEffect.h | 131 +++++++--- .../render-utils/src/DeferredTransform.slh | 3 + .../render-utils/src/RenderDeferredTask.cpp | 7 +- libraries/render-utils/src/ssao.slh | 62 +---- .../render-utils/src/ssao_debugOcclusion.slf | 162 +++++++++++++ .../render-utils/src/ssao_makeOcclusion.slf | 17 +- .../utilities/render/ambientOcclusionPass.qml | 50 ++++ .../render/debugAmbientOcclusionPass.js | 19 ++ 9 files changed, 506 insertions(+), 172 deletions(-) create mode 100644 libraries/render-utils/src/ssao_debugOcclusion.slf create mode 100644 scripts/developer/utilities/render/ambientOcclusionPass.qml create mode 100644 scripts/developer/utilities/render/debugAmbientOcclusionPass.js diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 929f4896b3..0d339c71ed 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -30,6 +30,7 @@ #include "ssao_makePyramid_frag.h" #include "ssao_makeOcclusion_frag.h" +#include "ssao_debugOcclusion_frag.h" #include "ssao_makeHorizontalBlur_frag.h" #include "ssao_makeVerticalBlur_frag.h" @@ -179,10 +180,6 @@ const int AmbientOcclusionEffect_LinearDepthMapSlot = 0; const int AmbientOcclusionEffect_OcclusionMapSlot = 0; AmbientOcclusionEffect::AmbientOcclusionEffect() { - FrameTransform frameTransform; - _frameTransformBuffer = gpu::BufferView(std::make_shared(sizeof(FrameTransform), (const gpu::Byte*) &frameTransform)); - Parameters parameters; - _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Parameters), (const gpu::Byte*) ¶meters)); } void AmbientOcclusionEffect::configure(const Config& config) { @@ -192,41 +189,41 @@ void AmbientOcclusionEffect::configure(const Config& config) { const double RADIUS_POWER = 6.0; const auto& radius = config.radius; - if (radius != getRadius()) { - auto& current = _parametersBuffer.edit().radiusInfo; + if (radius != _parametersBuffer->getRadius()) { + auto& current = _parametersBuffer->radiusInfo; current.x = radius; current.y = radius * radius; current.z = (float)(1.0 / pow((double)radius, RADIUS_POWER)); } - if (config.obscuranceLevel != getObscuranceLevel()) { - auto& current = _parametersBuffer.edit().radiusInfo; + if (config.obscuranceLevel != _parametersBuffer->getObscuranceLevel()) { + auto& current = _parametersBuffer->radiusInfo; current.w = config.obscuranceLevel; } - if (config.falloffBias != getFalloffBias()) { - auto& current = _parametersBuffer.edit().ditheringInfo; + if (config.falloffBias != _parametersBuffer->getFalloffBias()) { + auto& current = _parametersBuffer->ditheringInfo; current.z = config.falloffBias; } - if (config.edgeSharpness != getEdgeSharpness()) { - auto& current = _parametersBuffer.edit().blurInfo; + if (config.edgeSharpness != _parametersBuffer->getEdgeSharpness()) { + auto& current = _parametersBuffer->blurInfo; current.x = config.edgeSharpness; } - if (config.blurDeviation != getBlurDeviation()) { - auto& current = _parametersBuffer.edit().blurInfo; + if (config.blurDeviation != _parametersBuffer->getBlurDeviation()) { + auto& current = _parametersBuffer->blurInfo; current.z = config.blurDeviation; shouldUpdateGaussian = true; } - if (config.numSpiralTurns != getNumSpiralTurns()) { - auto& current = _parametersBuffer.edit().sampleInfo; + if (config.numSpiralTurns != _parametersBuffer->getNumSpiralTurns()) { + auto& current = _parametersBuffer->sampleInfo; current.z = config.numSpiralTurns; } - if (config.numSamples != getNumSamples()) { - auto& current = _parametersBuffer.edit().sampleInfo; + if (config.numSamples != _parametersBuffer->getNumSamples()) { + auto& current = _parametersBuffer->sampleInfo; current.x = config.numSamples; current.y = 1.0f / config.numSamples; } @@ -235,33 +232,36 @@ void AmbientOcclusionEffect::configure(const Config& config) { _framebuffer = std::make_shared(); } + if (config.perspectiveScale != _parametersBuffer->getPerspectiveScale()) { + _parametersBuffer->resolutionInfo.z = config.perspectiveScale; + } _framebuffer->setResolutionLevel(config.resolutionLevel); - if (config.resolutionLevel != getResolutionLevel()) { - _parametersBuffer.edit().resolutionInfo.w = config.resolutionLevel; + if (config.resolutionLevel != _parametersBuffer->getResolutionLevel()) { + _parametersBuffer->resolutionInfo.w = config.resolutionLevel; } const auto& resolutionLevel = config.resolutionLevel; - if (resolutionLevel != getResolutionLevel()) { - auto& current = _parametersBuffer.edit().resolutionInfo; + if (resolutionLevel != _parametersBuffer->getResolutionLevel()) { + auto& current = _parametersBuffer->resolutionInfo; current.x = (float)resolutionLevel; // Communicate the change to the Framebuffer cache // DependencyManager::get()->setAmbientOcclusionResolutionLevel(resolutionLevel); } - if (config.blurRadius != getBlurRadius()) { - auto& current = _parametersBuffer.edit().blurInfo; + if (config.blurRadius != _parametersBuffer->getBlurRadius()) { + auto& current = _parametersBuffer->blurInfo; current.y = (float)config.blurRadius; shouldUpdateGaussian = true; } - if (config.ditheringEnabled != isDitheringEnabled()) { - auto& current = _parametersBuffer.edit().ditheringInfo; + if (config.ditheringEnabled != _parametersBuffer->isDitheringEnabled()) { + auto& current = _parametersBuffer->ditheringInfo; current.x = (float)config.ditheringEnabled; } - if (config.borderingEnabled != isBorderingEnabled()) { - auto& current = _parametersBuffer.edit().ditheringInfo; + if (config.borderingEnabled != _parametersBuffer->isBorderingEnabled()) { + auto& current = _parametersBuffer->ditheringInfo; current.w = (float)config.borderingEnabled; } @@ -277,7 +277,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_LinearDepthMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); @@ -339,14 +339,9 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { return _vBlurPipeline; } - -void AmbientOcclusionEffect::setDepthInfo(float nearZ, float farZ) { - _frameTransformBuffer.edit().depthInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f); -} - void AmbientOcclusionEffect::updateGaussianDistribution() { - auto coefs = _parametersBuffer.edit()._gaussianCoefs; - GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, getBlurRadius(), getBlurDeviation()); + auto coefs = _parametersBuffer->_gaussianCoefs; + GaussianDistribution::evalSampling(coefs, Parameters::GAUSSIAN_COEFS_LENGTH, _parametersBuffer->getBlurRadius(), _parametersBuffer->getBlurDeviation()); } void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { @@ -356,9 +351,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext RenderArgs* args = renderContext->args; // FIXME: Different render modes should have different tasks - if (args->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) { - return; - } +// if (args->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) { +// return; +// } const auto frameTransform = inputs.get0(); const auto deferredFramebuffer = inputs.get1(); @@ -385,7 +380,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext auto occlusionFBO = _framebuffer->getOcclusionFramebuffer(); auto occlusionBlurredFBO = _framebuffer->getOcclusionBlurredFramebuffer(); - outputs = _framebuffer; + outputs.edit0() = _framebuffer; + outputs.edit1() = _parametersBuffer; auto framebufferSize = _framebuffer->getSourceFrameSize(); @@ -394,39 +390,13 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext float tMin = args->_viewport.y / (float)framebufferSize.y; float tHeight = args->_viewport.w / (float)framebufferSize.y; - auto resolutionLevel = getResolutionLevel(); + auto resolutionLevel = _parametersBuffer->getResolutionLevel(); - // Update the depth info with near and far (same for stereo) - setDepthInfo(args->getViewFrustum().getNearClip(), args->getViewFrustum().getFarClip()); - _frameTransformBuffer.edit().pixelInfo = args->_viewport; //_parametersBuffer.edit()._ditheringInfo.y += 0.25f; // Running in stero ? bool isStereo = args->_context->isStereo(); - if (!isStereo) { - // Eval the mono projection - mat4 monoProjMat; - args->getViewFrustum().evalProjectionMatrix(monoProjMat); - _frameTransformBuffer.edit().projection[0] = monoProjMat; - _frameTransformBuffer.edit().stereoInfo = glm::vec4(0.0f, (float)args->_viewport.z, 0.0f, 0.0f); - - } else { - - mat4 projMats[2]; - mat4 eyeViews[2]; - args->_context->getStereoProjections(projMats); - args->_context->getStereoViews(eyeViews); - - for (int i = 0; i < 2; i++) { - // Compose the mono Eye space to Stereo clip space Projection Matrix - auto sideViewMat = projMats[i] * eyeViews[i]; - _frameTransformBuffer.edit().projection[i] = sideViewMat; - } - - _frameTransformBuffer.edit().stereoInfo = glm::vec4(1.0f, (float)(args->_viewport.z >> 1), 0.0f, 1.0f); - - } auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); @@ -446,11 +416,12 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext model.setScale(glm::vec3(sWidth, tHeight, 1.0f)); batch.setModelTransform(model); - batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, _frameTransformBuffer); + batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, _parametersBuffer); - - // batch.generateTextureMips(linearDepthTexture); + + // We need this with the mips levels + batch.generateTextureMips(linearDepthTexture); // Occlusion pass batch.setFramebuffer(occlusionFBO); @@ -460,7 +431,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.draw(gpu::TRIANGLE_STRIP, 4); - /* if (getBlurRadius() > 0) { + if (_parametersBuffer->getBlurRadius() > 0) { // Blur 1st pass batch.setFramebuffer(occlusionBlurredFBO); batch.setPipeline(firstHBlurPipeline); @@ -472,7 +443,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext batch.setPipeline(lastVBlurPipeline); batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionBlurredFBO->getRenderBuffer(0)); batch.draw(gpu::TRIANGLE_STRIP, 4); - }*/ + } batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, nullptr); @@ -484,3 +455,115 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // Update the timer std::static_pointer_cast(renderContext->jobConfig)->gpuTime = _gpuTimer.getAverage(); } + + + +DebugAmbientOcclusion::DebugAmbientOcclusion() { +} + +void DebugAmbientOcclusion::configure(const Config& config) { + + _showCursorPixel = config.showCursorPixel; + + auto cursorPos = glm::vec2(_parametersBuffer->pixelInfo); + if (cursorPos != config.debugCursorTexcoord) { + _parametersBuffer->pixelInfo = glm::vec4(config.debugCursorTexcoord, 0.0f, 0.0f); + } +} + +const gpu::PipelinePointer& DebugAmbientOcclusion::getDebugPipeline() { + if (!_debugPipeline) { + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto ps = gpu::Shader::createPixel(std::string(ssao_debugOcclusion_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_LinearDepthMapSlot)); + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setColorWriteMask(true, true, true, false); + + // Good to go add the brand new pipeline + _debugPipeline = gpu::Pipeline::create(program, state); + } + return _debugPipeline; +} + +void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + + RenderArgs* args = renderContext->args; + + // FIXME: Different render modes should have different tasks +// if (args->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) { +// return; +// } + + const auto frameTransform = inputs.get0(); + const auto deferredFramebuffer = inputs.get1(); + const auto linearDepthFramebuffer = inputs.get2(); + const auto ambientOcclusionUniforms = inputs.get3(); + + auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); + auto normalTexture = deferredFramebuffer->getDeferredNormalTexture(); + auto sourceViewport = args->_viewport; + auto occlusionViewport = sourceViewport; + + auto resolutionLevel = ambientOcclusionUniforms->getResolutionLevel(); + + if (resolutionLevel > 0) { + linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); + normalTexture = linearDepthFramebuffer->getHalfNormalTexture(); + occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel(); + } + + + auto framebufferSize = glm::ivec2(linearDepthTexture->getDimensions()); + + float sMin = args->_viewport.x / (float)framebufferSize.x; + float sWidth = args->_viewport.z / (float)framebufferSize.x; + float tMin = args->_viewport.y / (float)framebufferSize.y; + float tHeight = args->_viewport.w / (float)framebufferSize.y; + + + // Running in stero ? + bool isStereo = args->_context->isStereo(); + + auto debugPipeline = getDebugPipeline(); + + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + batch.enableStereo(false); + + batch.setViewportTransform(sourceViewport); + batch.setProjectionTransform(glm::mat4()); + batch.setViewTransform(Transform()); + + Transform model; + model.setTranslation(glm::vec3(sMin, tMin, 0.0f)); + model.setScale(glm::vec3(sWidth, tHeight, 1.0f)); + batch.setModelTransform(model); + + batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, frameTransform->getFrameTransformBuffer()); + batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, ambientOcclusionUniforms); + + + // We need this with the mips levels + batch.generateTextureMips(linearDepthTexture); + + batch.setPipeline(debugPipeline); + batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, linearDepthTexture); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + + batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, nullptr); + batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, nullptr); + + }); + +} + \ No newline at end of file diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 8c458a5879..ffc2c4d3e3 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -63,6 +63,7 @@ class AmbientOcclusionEffectConfig : public render::Job::Config::Persistent { Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty) Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty) Q_PROPERTY(float radius MEMBER radius WRITE setRadius) + Q_PROPERTY(float perspectiveScale MEMBER perspectiveScale WRITE setPerspectiveScale) Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel) Q_PROPERTY(float falloffBias MEMBER falloffBias WRITE setFalloffBias) Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness) @@ -79,6 +80,7 @@ public: const int MAX_BLUR_RADIUS = 6; void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); } + void setPerspectiveScale(float scale) { perspectiveScale = scale; emit dirty(); } void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); } void setFalloffBias(float bias) { falloffBias = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); } void setEdgeSharpness(float sharpness) { edgeSharpness = std::max(0.0f, (float)sharpness); emit dirty(); } @@ -90,14 +92,15 @@ public: double getGpuTime() { return gpuTime; } float radius{ 0.5f }; + float perspectiveScale{ 1.0f }; float obscuranceLevel{ 0.5f }; // intensify or dim down the obscurance effect float falloffBias{ 0.01f }; float edgeSharpness{ 1.0f }; float blurDeviation{ 2.5f }; float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions int numSamples{ 11 }; - int resolutionLevel{ 1 }; - int blurRadius{ 4 }; // 0 means no blurring + int resolutionLevel{ 0 }; + int blurRadius{ 0 }; // 0 means no blurring bool ditheringEnabled{ true }; // randomize the distribution of rays per pixel, should always be true bool borderingEnabled{ true }; // avoid evaluating information from non existing pixels out of the frame, should always be true double gpuTime{ 0.0 }; @@ -106,10 +109,25 @@ signals: void dirty(); }; + +namespace gpu { +template class UniformBuffer : public gpu::BufferView { + public: + ~UniformBuffer() {}; + UniformBuffer() : gpu::BufferView(std::make_shared(sizeof(T), (const gpu::Byte*) &T())) {} + + const T* operator ->() const { return &get(); } + T* operator ->() { return &edit(); } + +}; + + +} + class AmbientOcclusionEffect { public: using Inputs = render::VaryingSet3; - using Outputs = AmbientOcclusionFramebufferPointer; + using Outputs = render::VaryingSet2; using Config = AmbientOcclusionEffectConfig; using JobModel = render::Job::ModelIO; @@ -118,46 +136,12 @@ public: void configure(const Config& config); void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); - float getRadius() const { return _parametersBuffer.get().radiusInfo.x; } - float getObscuranceLevel() const { return _parametersBuffer.get().radiusInfo.w; } - float getFalloffBias() const { return (float)_parametersBuffer.get().ditheringInfo.z; } - float getEdgeSharpness() const { return (float)_parametersBuffer.get().blurInfo.x; } - float getBlurDeviation() const { return _parametersBuffer.get().blurInfo.z; } - float getNumSpiralTurns() const { return _parametersBuffer.get().sampleInfo.z; } - int getNumSamples() const { return (int)_parametersBuffer.get().sampleInfo.x; } - int getResolutionLevel() const { return _parametersBuffer.get().resolutionInfo.x; } - int getBlurRadius() const { return (int)_parametersBuffer.get().blurInfo.y; } - bool isDitheringEnabled() const { return _parametersBuffer.get().ditheringInfo.x; } - bool isBorderingEnabled() const { return _parametersBuffer.get().ditheringInfo.w; } - -private: - void updateGaussianDistribution(); - void setDepthInfo(float nearZ, float farZ); - - typedef gpu::BufferView UniformBufferView; - // Class describing the uniform buffer with the transform info common to the AO shaders - // It s changing every frame - class FrameTransform { - public: - // Pixel info is { viemport width height and stereo on off} - glm::vec4 pixelInfo; - // Depth info is { n.f, f - n, -f} - glm::vec4 depthInfo; - // Stereo info - glm::vec4 stereoInfo { 0.0 }; - // Mono proj matrix or Left and Right proj matrix going from Mono Eye space to side clip space - glm::mat4 projection[2]; - - FrameTransform() {} - }; - gpu::BufferView _frameTransformBuffer; - // Class describing the uniform buffer with all the parameters common to the AO shaders class Parameters { public: // Resolution info - glm::vec4 resolutionInfo { -1.0f, 0.0f, 0.0f, 0.0f }; + glm::vec4 resolutionInfo { -1.0f, 0.0f, 1.0f, 0.0f }; // radius info is { R, R^2, 1 / R^6, ObscuranceScale} glm::vec4 radiusInfo{ 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f }; // Dithering info @@ -169,10 +153,28 @@ private: // gaussian distribution coefficients first is the sampling radius (max is 6) const static int GAUSSIAN_COEFS_LENGTH = 8; float _gaussianCoefs[GAUSSIAN_COEFS_LENGTH]; - + Parameters() {} + + int getResolutionLevel() const { return resolutionInfo.x; } + float getRadius() const { return radiusInfo.x; } + float getPerspectiveScale() const { return resolutionInfo.z; } + float getObscuranceLevel() const { return radiusInfo.w; } + float getFalloffBias() const { return (float)ditheringInfo.z; } + float getEdgeSharpness() const { return (float)blurInfo.x; } + float getBlurDeviation() const { return blurInfo.z; } + float getNumSpiralTurns() const { return sampleInfo.z; } + int getNumSamples() const { return (int)sampleInfo.x; } + int getBlurRadius() const { return (int)blurInfo.y; } + bool isDitheringEnabled() const { return ditheringInfo.x; } + bool isBorderingEnabled() const { return ditheringInfo.w; } }; - gpu::BufferView _parametersBuffer; + using ParametersBuffer = gpu::UniformBuffer; + +private: + void updateGaussianDistribution(); + + ParametersBuffer _parametersBuffer; const gpu::PipelinePointer& getOcclusionPipeline(); const gpu::PipelinePointer& getHBlurPipeline(); // first @@ -185,6 +187,55 @@ private: AmbientOcclusionFramebufferPointer _framebuffer; gpu::RangeTimer _gpuTimer; + + friend class DebugAmbientOcclusion; +}; + + +class DebugAmbientOcclusionConfig : public render::Job::Config { + Q_OBJECT + + Q_PROPERTY(bool showCursorPixel MEMBER showCursorPixel NOTIFY dirty) + Q_PROPERTY(glm::vec2 debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) +public: + DebugAmbientOcclusionConfig() : render::Job::Config(true) {} + + bool showCursorPixel{ false }; + glm::vec2 debugCursorTexcoord{ 0.5, 0.5 }; + +signals: + void dirty(); +}; + + +class DebugAmbientOcclusion { +public: + using Inputs = render::VaryingSet4; + using Config = DebugAmbientOcclusionConfig; + using JobModel = render::Job::ModelI; + + DebugAmbientOcclusion(); + + void configure(const Config& config); + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs); + +private: + + // Class describing the uniform buffer with all the parameters common to the debug AO shaders + class Parameters { + public: + // Pixel info + glm::vec4 pixelInfo { 0.0f, 0.0f, 0.0f, 0.0f }; + + Parameters() {} + }; + gpu::UniformBuffer _parametersBuffer; + + const gpu::PipelinePointer& getDebugPipeline(); + + gpu::PipelinePointer _debugPipeline; + + bool _showCursorPixel{ false }; }; #endif // hifi_AmbientOcclusionEffect_h diff --git a/libraries/render-utils/src/DeferredTransform.slh b/libraries/render-utils/src/DeferredTransform.slh index b3881c4c71..ec8cdac8c1 100644 --- a/libraries/render-utils/src/DeferredTransform.slh +++ b/libraries/render-utils/src/DeferredTransform.slh @@ -81,6 +81,9 @@ bool isStereo() { float getStereoSideWidth(int resolutionLevel) { return float(int(frameTransform._stereoInfo.y) >> resolutionLevel); } +float getStereoSideHeight(int resolutionLevel) { + return float(int(frameTransform._pixelInfo.w) >> resolutionLevel); +} ivec4 getStereoSideInfo(int xPos, int resolutionLevel) { int sideWidth = int(getStereoSideWidth(resolutionLevel)); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index afff4bac72..0a4f5a9b8e 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -142,7 +142,9 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { // AO job const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying(); - const auto ambientOcclusionFramebuffer = addJob("AmbientOcclusion", ambientOcclusionInputs); + const auto ambientOcclusionOutputs = addJob("AmbientOcclusion", ambientOcclusionInputs); + 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); @@ -178,6 +180,9 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { { addJob("DebugScattering", deferredLightingInputs); + const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying(); + addJob("DebugAmbientOcclusion", debugAmbientOcclusionInputs); + // Debugging Deferred buffer job const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); addJob("DebugDeferredBuffer", debugFramebuffers); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 21e9a5a297..01be0e463a 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -30,13 +30,8 @@ vec2 unpackOcclusionDepth(vec3 raw) { <@endfunc@> <@func declareAmbientOcclusion()@> - -struct AmbientOcclusionFrameTransform { - vec4 _pixelInfo; - vec4 _depthInfo; - vec4 _stereoInfo; - mat4 _projection[2]; -}; +<@include DeferredTransform.slh@> +<$declareDeferredFrameTransform()$> struct AmbientOcclusionParams { vec4 _resolutionInfo; @@ -47,55 +42,20 @@ struct AmbientOcclusionParams { float _gaussianCoefs[8]; }; -uniform ambientOcclusionFrameTransformBuffer { - AmbientOcclusionFrameTransform frameTransform; -}; uniform ambientOcclusionParamsBuffer { AmbientOcclusionParams params; }; +float getPerspectiveScale() { + + return (params._resolutionInfo.z); +} int getResolutionLevel() { + return int(params._resolutionInfo.x); } -vec2 getWidthHeight() { - return vec2(ivec2(frameTransform._pixelInfo.zw) >> getResolutionLevel()); -} -float getProjScale() { - return getWidthHeight().y * frameTransform._projection[0][1][1] * 0.5; -} -mat4 getProjection(int side) { - return frameTransform._projection[side]; -} - -bool isStereo() { - return frameTransform._stereoInfo.x > 0.0f; -} - -float getStereoSideWidth() { - return float(int(frameTransform._stereoInfo.y) >> getResolutionLevel()); -} -float getStereoSideHeight() { - return float(int(frameTransform._pixelInfo.w) >> getResolutionLevel()); -} - -ivec3 getStereoSideInfo(int xPos) { - int sideWidth = int(getStereoSideWidth()); - return ivec3(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth); -} - - -float evalZeyeFromZdb(float depth) { - return frameTransform._depthInfo.x / (depth * frameTransform._depthInfo.y + frameTransform._depthInfo.z); -} - -vec3 evalEyeNormal(vec3 C) { - //return normalize(cross(dFdy(C), dFdx(C))); - return normalize(cross(dFdx(C), dFdy(C))); -} - - float getRadius() { return params._radiusInfo.x; } @@ -191,7 +151,7 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 ssC, float key) { ivec2 tapOffset = <$axis$> * (r * RADIUS_SCALE); ivec2 ssP = (ssC + tapOffset); - if ((ssP.x < side.y || ssP.x >= side.z + side.y) || (ssP.y < 0 || ssP.y >= int(getWidthHeight().y))) { + if ((ssP.x < side.y || ssP.x >= side.z + side.y) || (ssP.y < 0 || ssP.y >= int(getWidthHeight(getResolutionLevel()).y))) { return vec2(0.0); } vec2 tapOZ = fetchOcclusionDepth(ssC + tapOffset); @@ -209,7 +169,7 @@ vec3 getBlurredOcclusion(vec2 coord) { ivec2 ssC = ivec2(coord); // Stereo side info - ivec3 side = getStereoSideInfo(ssC.x); + ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel()); vec3 rawSample; vec2 occlusionDepth = fetchOcclusionDepthRaw(ssC, rawSample); @@ -223,11 +183,11 @@ vec3 getBlurredOcclusion(vec2 coord) { int blurRadius = getBlurRadius(); // negative side first for (int r = -blurRadius; r <= -1; ++r) { - weightedSums += evalTapWeightedValue(side, r, ssC, key); + weightedSums += evalTapWeightedValue(side.xyz, r, ssC, key); } // then positive side for (int r = 1; r <= blurRadius; ++r) { - weightedSums += evalTapWeightedValue(side, r, ssC, key); + weightedSums += evalTapWeightedValue(side.xyz, r, ssC, key); } // Final normalization diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf new file mode 100644 index 0000000000..7bad1420bf --- /dev/null +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -0,0 +1,162 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gateau on 1/1/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 ssao.slh@> +<$declareAmbientOcclusion()$> +<$declarePackOcclusionDepth()$> + + +const int LOG_MAX_OFFSET = 3; +const int MAX_MIP_LEVEL = 5; + +// the depth pyramid texture +uniform sampler2D pyramidMap; + +float getZEye(ivec2 pixel) { + return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; +} +/* +vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { + // compute the view space position using the depth + // basically manually pick the proj matrix components to do the inverse + float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][0] - frameTransform._projection[side][3][0]) / frameTransform._projection[side][0][0]; + float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][1] - frameTransform._projection[side][3][1]) / frameTransform._projection[side][1][1]; + return vec3(Xe, Ye, Zeye); +} +*/ +out vec4 outFragColor; + +uniform sampler2D normalMap; + +float getAngleDithering(in ivec2 pixelPos) { + // Hash function used in the AlchemyAO paper + return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); +} + +const float TWO_PI = 6.28; + +vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ + // Radius relative to ssR + float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); + float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle; + + ssR = alpha; + return vec2(cos(angle), sin(angle)); +} + +vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) { + // Derivation: + // mipLevel = floor(log(ssR / MAX_OFFSET)); + int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); + + ivec2 ssOffset = ivec2(ssR * unitOffset); + ivec2 ssP = ssOffset + ssC; + if (bool(isBorderingEnabled())) { + ssP.x = ((ssP.x < 0 || ssP.x >= side.z) ? ssC.x - ssOffset.x : ssP.x); + ssP.y = ((ssP.y < 0 || ssP.y >= int(getWidthHeight(getResolutionLevel()).y)) ? ssC.y - ssOffset.y : ssP.y); + } + + ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); + + vec3 P; + + // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. + // Manually clamp to the texture size because texelFetch bypasses the texture unit + ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, getResolutionLevel() + mipLevel) - ivec2(1)); + P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r; + + // Offset to pixel center + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / float(side.z); + P = evalEyePositionFromZeye(side.x, P.z, tapUV); + return P; +} + +float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { + // Offset on the unit disk, spun for this pixel + float ssR; + vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); + ssR *= ssDiskRadius; + + + + // The occluding point in camera space + vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR); + + vec3 v = Q - C; + float vv = dot(v, v); + float vn = dot(v, n_C); + + // Fall off function as recommended in SAO paper + const float epsilon = 0.01; + float f = max(getRadius2() - vv, 0.0); + return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0); +} + +void main(void) { + // Pixel being shaded + ivec2 ssC = ivec2(gl_FragCoord.xy); + + // Fetch the z under the pixel (stereo or not) + float Zeye = getZEye(ssC); + + // Stereo side info + ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel()); + + // From now on, ssC is the pixel pos in the side + ssC.x -= side.y; + vec2 fragPos = (vec2(ssC) + vec2(0.5)) / vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel())); + + // The position and normal of the pixel fragment in Eye space + vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos); + vec3 Cn = evalEyeNormal(Cp); + + // Choose the screen-space sample radius + // proportional to the projected area of the sphere + float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Cp.z ) * getPerspectiveScale(); + + // Let's make noise + float randomPatternRotationAngle = getAngleDithering(ssC); + + // Accumulate the Obscurance for each samples + float sum = 0.0; + for (int i = 0; i < getNumSamples(); ++i) { + sum += sampleAO(side.xyz, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); + } + + float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); + + + + outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); + + // KEEP IT for Debugging + // Debug Normal: outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); + // Debug Radius outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); + // Debug MaxMiplevel outFragColor = vec4(1.0 - vec3(float(clamp(findMSB(int(ssDiskRadius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL))/ float(MAX_MIP_LEVEL)), 1.0); + // Debug OffsetPosition + // float ssR; + // vec2 unitOffset = tapLocation(int(getNumSamples() - 1), 0, ssR); + // vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR * ssDiskRadius); + //outFragColor = vec4(vec3(Q.x / 10.0, Q.y / 2.0, -Q.z/ 3.0), 1.0); + // vec3 v = normalize(Q - Cp); + //outFragColor = vec4((v + vec3(1.0))* 0.5, 1.0); + // outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); + //outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); +} diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 7512d6568c..7bad1420bf 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -21,9 +21,9 @@ const int MAX_MIP_LEVEL = 5; uniform sampler2D pyramidMap; float getZEye(ivec2 pixel) { - return -texelFetch(pyramidMap, pixel, 0/*getResolutionLevel()*/).x; + return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; } - +/* vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { // compute the view space position using the depth // basically manually pick the proj matrix components to do the inverse @@ -31,7 +31,7 @@ vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][1] - frameTransform._projection[side][3][1]) / frameTransform._projection[side][1][1]; return vec3(Xe, Ye, Zeye); } - +*/ out vec4 outFragColor; uniform sampler2D normalMap; @@ -61,7 +61,7 @@ vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) { ivec2 ssP = ssOffset + ssC; if (bool(isBorderingEnabled())) { ssP.x = ((ssP.x < 0 || ssP.x >= side.z) ? ssC.x - ssOffset.x : ssP.x); - ssP.y = ((ssP.y < 0 || ssP.y >= int(getWidthHeight().y)) ? ssC.y - ssOffset.y : ssP.y); + ssP.y = ((ssP.y < 0 || ssP.y >= int(getWidthHeight(getResolutionLevel()).y)) ? ssC.y - ssOffset.y : ssP.y); } ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); @@ -108,11 +108,11 @@ void main(void) { float Zeye = getZEye(ssC); // Stereo side info - ivec3 side = getStereoSideInfo(ssC.x); + ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel()); // From now on, ssC is the pixel pos in the side ssC.x -= side.y; - vec2 fragPos = (vec2(ssC) + 0.5) / vec2(getStereoSideWidth(), getStereoSideHeight()); + vec2 fragPos = (vec2(ssC) + vec2(0.5)) / vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel())); // The position and normal of the pixel fragment in Eye space vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos); @@ -120,7 +120,7 @@ void main(void) { // Choose the screen-space sample radius // proportional to the projected area of the sphere - float ssDiskRadius = -getProjScale() * getRadius() / Cp.z; + float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Cp.z ) * getPerspectiveScale(); // Let's make noise float randomPatternRotationAngle = getAngleDithering(ssC); @@ -128,7 +128,7 @@ void main(void) { // Accumulate the Obscurance for each samples float sum = 0.0; for (int i = 0; i < getNumSamples(); ++i) { - sum += sampleAO(side, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); + sum += sampleAO(side.xyz, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); } float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); @@ -158,4 +158,5 @@ void main(void) { // vec3 v = normalize(Q - Cp); //outFragColor = vec4((v + vec3(1.0))* 0.5, 1.0); // outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); + //outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); } diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml new file mode 100644 index 0000000000..ae4ec7770b --- /dev/null +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -0,0 +1,50 @@ +// +// surfaceGeometryPass.qml +// +// Created by Sam Gateau on 6/6/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: surfaceGeometry + spacing: 10 + + Column{ + Repeater { + model: [ + "Radius:radius:2.0:false", + "Level:obscuranceLevel:1.0:false", + "Scale:perspectiveScale:2.0:false", + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: (modelData.split(":")[3] == 'true') + config: Render.getConfig("AmbientOcclusion") + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: 0.0 + } + } + Repeater { + model: [ + "resolutionLevel:resolutionLevel", + "ditheringEnabled:ditheringEnabled", + "borderingEnabled:borderingEnabled", + ] + CheckBox { + text: qsTr(modelData.split(":")[0]) + checked: Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]] + onCheckedChanged: { Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]] = checked } + } + } + } + } +} diff --git a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js new file mode 100644 index 0000000000..fbd1e10099 --- /dev/null +++ b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js @@ -0,0 +1,19 @@ +// +// debugSurfaceGeometryPass.js +// +// Created by Sam Gateau on 6/6/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 +// + +// Set up the qml ui +var qml = Script.resolvePath('ambientOcclusionPass.qml'); +var window = new OverlayWindow({ + title: 'Ambient Occlusion Pass', + source: qml, + width: 400, height: 170, +}); +window.setPosition(Window.innerWidth - 420, 50 + 550 + 50); +window.closed.connect(function() { Script.stop(); }); From 4ec971b449259be9d71ef010bcb08ea0a353105c Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 1 Aug 2016 23:17:32 -0700 Subject: [PATCH 03/71] MOre debugging --- .../src/AmbientOcclusionEffect.cpp | 2 + .../render-utils/src/ssao_debugOcclusion.slf | 51 +++++++++++++++---- .../render/debugAmbientOcclusionPass.js | 19 +++++++ 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 0d339c71ed..71222ee671 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -480,6 +480,7 @@ const gpu::PipelinePointer& DebugAmbientOcclusion::getDebugPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("debugAmbientOcclusionBuffer"), 2)); slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_LinearDepthMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); @@ -550,6 +551,7 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, ambientOcclusionUniforms); + batch.setUniformBuffer(2, _parametersBuffer); // We need this with the mips levels diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 7bad1420bf..0c40042ba2 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -13,7 +13,17 @@ <$declareAmbientOcclusion()$> <$declarePackOcclusionDepth()$> +struct DebugParams{ + vec4 pixelInfo; +}; +uniform debugAmbientOcclusionBuffer { + DebugParams debugParams; +}; + +vec2 getDebugCursorTexcoord(){ + return debugParams.pixelInfo.xy; +} const int LOG_MAX_OFFSET = 3; const int MAX_MIP_LEVEL = 5; @@ -23,15 +33,7 @@ uniform sampler2D pyramidMap; float getZEye(ivec2 pixel) { return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; } -/* -vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { - // compute the view space position using the depth - // basically manually pick the proj matrix components to do the inverse - float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][0] - frameTransform._projection[side][3][0]) / frameTransform._projection[side][0][0]; - float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][1] - frameTransform._projection[side][3][1]) / frameTransform._projection[side][1][1]; - return vec3(Xe, Ye, Zeye); -} -*/ + out vec4 outFragColor; uniform sampler2D normalMap; @@ -52,6 +54,13 @@ vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ return vec2(cos(angle), sin(angle)); } +vec3 getTapLocation(int sampleNumber, float spinAngle, float outerRadius) { + // Radius relative to ssR + float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); + float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle; + return vec2(cos(angle), sin(angle), alpha * outerRadius); +} + vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) { // Derivation: // mipLevel = floor(log(ssR / MAX_OFFSET)); @@ -79,6 +88,7 @@ vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) { return P; } + float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { // Offset on the unit disk, spun for this pixel float ssR; @@ -100,9 +110,13 @@ float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssD return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0); } + void main(void) { + // Pixel Debugged + vec2 cursorUV = getDebugCursorTexcoord(); + ivec2 ssC = ivec2(cursorUV * vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel()))); // Pixel being shaded - ivec2 ssC = ivec2(gl_FragCoord.xy); + //ivec2 ssC = ivec2(gl_FragCoord.xy); // Fetch the z under the pixel (stereo or not) float Zeye = getZEye(ssC); @@ -122,15 +136,32 @@ void main(void) { // proportional to the projected area of the sphere float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Cp.z ) * getPerspectiveScale(); + vec2 fragToCursor = cursorUV * vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel())) - gl_FragCoord.xy; + if (dot(fragToCursor,fragToCursor) > ssDiskRadius * ssDiskRadius) { + discard; + } + // Let's make noise float randomPatternRotationAngle = getAngleDithering(ssC); // Accumulate the Obscurance for each samples float sum = 0.0; + float keepTapRadius = 2.0; + bool keep = (dot(fragToCursor,fragToCursor) < keepTapRadius); for (int i = 0; i < getNumSamples(); ++i) { + vec3 tap = getTapLocation(i, randomPatternRotationAngle, outerRadius); + + vec2 fragToTap = vec2(ssC) + tap.xy * tap.z - gl_FragCoord.xy; + if (dot(fragToTap,fragToTap) < keepTapRadius) { + keep = true; + } sum += sampleAO(side.xyz, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); } + if (!keep) { + discard; + } + float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); Date: Wed, 3 Aug 2016 15:45:22 -0700 Subject: [PATCH 04/71] fixing ao --- .../src/AmbientOcclusionEffect.cpp | 2 +- .../render-utils/src/AmbientOcclusionEffect.h | 2 +- .../render-utils/src/DeferredTransform.slh | 4 + .../render-utils/src/RenderDeferredTask.cpp | 8 +- libraries/render-utils/src/ssao.slh | 109 ++++++++++++++++++ .../render-utils/src/ssao_debugOcclusion.slf | 100 ++++------------ .../render-utils/src/ssao_makeOcclusion.slf | 59 +++------- .../utilities/render/ambientOcclusionPass.qml | 4 +- 8 files changed, 159 insertions(+), 129 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 71222ee671..97132a0fc7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -487,7 +487,7 @@ const gpu::PipelinePointer& DebugAmbientOcclusion::getDebugPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setColorWriteMask(true, true, true, false); - + 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 _debugPipeline = gpu::Pipeline::create(program, state); } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index ffc2c4d3e3..5a0e7da587 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -100,7 +100,7 @@ public: float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions int numSamples{ 11 }; int resolutionLevel{ 0 }; - int blurRadius{ 0 }; // 0 means no blurring + int blurRadius{ 3 }; // 0 means no blurring bool ditheringEnabled{ true }; // randomize the distribution of rays per pixel, should always be true bool borderingEnabled{ true }; // avoid evaluating information from non existing pixels out of the frame, should always be true double gpuTime{ 0.0 }; diff --git a/libraries/render-utils/src/DeferredTransform.slh b/libraries/render-utils/src/DeferredTransform.slh index ec8cdac8c1..44f1073702 100644 --- a/libraries/render-utils/src/DeferredTransform.slh +++ b/libraries/render-utils/src/DeferredTransform.slh @@ -85,6 +85,10 @@ float getStereoSideHeight(int resolutionLevel) { return float(int(frameTransform._pixelInfo.w) >> resolutionLevel); } +vec2 getSideImageSize(int resolutionLevel) { + return vec2(float(int(frameTransform._stereoInfo.y) >> resolutionLevel), float(int(frameTransform._pixelInfo.w) >> resolutionLevel)); +} + ivec4 getStereoSideInfo(int xPos, int resolutionLevel) { int sideWidth = int(getStereoSideWidth(resolutionLevel)); return ivec4(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth, isStereo()); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index bfb61b9dfb..7ea81eb706 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -178,14 +178,16 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { // Debugging stages { + // Debugging Deferred buffer job + const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); + addJob("DebugDeferredBuffer", debugFramebuffers); + addJob("DebugScattering", deferredLightingInputs); const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying(); addJob("DebugAmbientOcclusion", debugAmbientOcclusionInputs); - // Debugging Deferred buffer job - const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); - addJob("DebugDeferredBuffer", debugFramebuffers); + // Scene Octree Debuging job { diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 01be0e463a..3a3203e2e3 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -126,6 +126,115 @@ float getBlurCoef(int c) { <@endfunc@> +<@func declareSamplingDisk()@> + +float evalDiskRadius(float Zeye, vec2 imageSize) { + // Choose the screen-space sample radius + // proportional to the projected area of the sphere + float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Zeye ) * getPerspectiveScale(); + + // clamp the disk to fit in the image otherwise too many unknown + ssDiskRadius = min(ssDiskRadius, imageSize.y * 0.5); + + return ssDiskRadius; +} + +const float TWO_PI = 6.28; + +vec3 getUnitTapLocation(int sampleNumber, float spinAngle){ + // Radius relative to ssR + float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); + float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle; + return vec3(cos(angle), sin(angle), alpha); +} + +vec3 getTapLocation(int sampleNumber, float spinAngle, float outerRadius) { + vec3 tap = getUnitTapLocation(sampleNumber, spinAngle); + tap.xy *= tap.z; + tap *= outerRadius; + return tap; +} + +vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 imageSize) { + vec3 tap = getTapLocation(sampleNumber, spinAngle, outerRadius); + vec2 tapPos = pixelPos + tap.xy; + + if (!(isBorderingEnabled() > 0.0)) { + return tap; + } + bool redoTap = false; + + if ((tapPos.x < 0.5)) { + tapPos.x = -tapPos.x; + redoTap = true; + } else if ((tapPos.x > imageSize.x - 0.5)) { + tapPos.x -= (imageSize.x - tapPos.x); + redoTap = true; + } + + if ((tapPos.y < 0.5)) { + tapPos.y = -tapPos.y; + redoTap = true; + } else if ((tapPos.y > imageSize.y - 0.5)) { + tapPos.y -= (imageSize.y - tapPos.y); + redoTap = true; + } + + if (redoTap) { + tap.xy = tapPos - pixelPos; + tap.z = length(tap.xy); + } +/* + if ((tapPos.x < 0.0) || (tapPos.x >= imageSize.x)) { + // tapPos.x = pixelPos.x - tapVec.x; + tap.x = -tap.x; + } + if ((tapPos.y < 0.0) || (tapPos.y >= imageSize.y)) { + // tapPos.y = pixelPos.y - tapVec.y; + tap.y = -tap.y; + }*/ + + return tap; +} + +<@endfunc@> + + +<@func declareFetchDepthPyramidMap()@> + +const int LOG_MAX_OFFSET = 3; +const int MAX_MIP_LEVEL = 5; + +// the depth pyramid texture +uniform sampler2D pyramidMap; + +float getZEye(ivec2 pixel) { + return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; +} + +vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { + // Derivation: + // mipLevel = floor(log(ssR / MAX_OFFSET)); + int mipLevel = clamp(findMSB(int(tap.z)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); + + ivec2 ssP = ivec2(tap.xy) + ssC; + ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); + + vec3 P; + + // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. + // Manually clamp to the texture size because texelFetch bypasses the texture unit + ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, getResolutionLevel() + mipLevel) - ivec2(1)); + P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r; + + // Offset to pixel center + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; + P = evalEyePositionFromZeye(side.x, P.z, tapUV); + return P; +} + +<@endfunc@> + <@func declareBlurPass(axis)@> <$declarePackOcclusionDepth()$> diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 0c40042ba2..7e6a792c3b 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -11,6 +11,9 @@ <@include ssao.slh@> <$declareAmbientOcclusion()$> +<$declareFetchDepthPyramidMap()$> +<$declareSamplingDisk()$> + <$declarePackOcclusionDepth()$> struct DebugParams{ @@ -24,15 +27,6 @@ uniform debugAmbientOcclusionBuffer { vec2 getDebugCursorTexcoord(){ return debugParams.pixelInfo.xy; } -const int LOG_MAX_OFFSET = 3; -const int MAX_MIP_LEVEL = 5; - -// the depth pyramid texture -uniform sampler2D pyramidMap; - -float getZEye(ivec2 pixel) { - return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; -} out vec4 outFragColor; @@ -43,63 +37,7 @@ float getAngleDithering(in ivec2 pixelPos) { return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); } -const float TWO_PI = 6.28; - -vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ - // Radius relative to ssR - float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); - float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle; - - ssR = alpha; - return vec2(cos(angle), sin(angle)); -} - -vec3 getTapLocation(int sampleNumber, float spinAngle, float outerRadius) { - // Radius relative to ssR - float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); - float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle; - return vec2(cos(angle), sin(angle), alpha * outerRadius); -} - -vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) { - // Derivation: - // mipLevel = floor(log(ssR / MAX_OFFSET)); - int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - - ivec2 ssOffset = ivec2(ssR * unitOffset); - ivec2 ssP = ssOffset + ssC; - if (bool(isBorderingEnabled())) { - ssP.x = ((ssP.x < 0 || ssP.x >= side.z) ? ssC.x - ssOffset.x : ssP.x); - ssP.y = ((ssP.y < 0 || ssP.y >= int(getWidthHeight(getResolutionLevel()).y)) ? ssC.y - ssOffset.y : ssP.y); - } - - ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); - - vec3 P; - - // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. - // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, getResolutionLevel() + mipLevel) - ivec2(1)); - P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r; - - // Offset to pixel center - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / float(side.z); - P = evalEyePositionFromZeye(side.x, P.z, tapUV); - return P; -} - - -float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { - // Offset on the unit disk, spun for this pixel - float ssR; - vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); - ssR *= ssDiskRadius; - - - - // The occluding point in camera space - vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR); - +float evalAO(in vec3 C, in vec3 n_C, vec3 Q) { vec3 v = Q - C; float vv = dot(v, v); float vn = dot(v, n_C); @@ -114,7 +52,9 @@ float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssD void main(void) { // Pixel Debugged vec2 cursorUV = getDebugCursorTexcoord(); - ivec2 ssC = ivec2(cursorUV * vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel()))); + vec2 imageSize = getSideImageSize(getResolutionLevel()); + vec2 cursorPixelPos = cursorUV * imageSize; + ivec2 ssC = ivec2(cursorPixelPos); // Pixel being shaded //ivec2 ssC = ivec2(gl_FragCoord.xy); @@ -126,17 +66,16 @@ void main(void) { // From now on, ssC is the pixel pos in the side ssC.x -= side.y; - vec2 fragPos = (vec2(ssC) + vec2(0.5)) / vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel())); + vec2 fragPos = (vec2(ssC) + vec2(0.5)) / imageSize; // The position and normal of the pixel fragment in Eye space vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos); vec3 Cn = evalEyeNormal(Cp); // Choose the screen-space sample radius - // proportional to the projected area of the sphere - float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Cp.z ) * getPerspectiveScale(); + float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); - vec2 fragToCursor = cursorUV * vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel())) - gl_FragCoord.xy; + vec2 fragToCursor = cursorPixelPos - gl_FragCoord.xy; if (dot(fragToCursor,fragToCursor) > ssDiskRadius * ssDiskRadius) { discard; } @@ -149,18 +88,18 @@ void main(void) { float keepTapRadius = 2.0; bool keep = (dot(fragToCursor,fragToCursor) < keepTapRadius); for (int i = 0; i < getNumSamples(); ++i) { - vec3 tap = getTapLocation(i, randomPatternRotationAngle, outerRadius); - - vec2 fragToTap = vec2(ssC) + tap.xy * tap.z - gl_FragCoord.xy; + vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize); + // The occluding point in camera space + vec2 fragToTap = vec2(ssC) + tap.xy - gl_FragCoord.xy; if (dot(fragToTap,fragToTap) < keepTapRadius) { keep = true; } - sum += sampleAO(side.xyz, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); + + vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize); + + sum += evalAO(Cp, Cn, Q); } - if (!keep) { - discard; - } float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); @@ -190,4 +129,9 @@ void main(void) { //outFragColor = vec4((v + vec3(1.0))* 0.5, 1.0); // outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); //outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); + + + if (!keep) { + outFragColor = vec4(0.1); + } } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 7bad1420bf..739dc1ddcb 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -11,27 +11,12 @@ <@include ssao.slh@> <$declareAmbientOcclusion()$> +<$declareFetchDepthPyramidMap()$> +<$declareSamplingDisk()$> + <$declarePackOcclusionDepth()$> -const int LOG_MAX_OFFSET = 3; -const int MAX_MIP_LEVEL = 5; - -// the depth pyramid texture -uniform sampler2D pyramidMap; - -float getZEye(ivec2 pixel) { - return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; -} -/* -vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { - // compute the view space position using the depth - // basically manually pick the proj matrix components to do the inverse - float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][0] - frameTransform._projection[side][3][0]) / frameTransform._projection[side][0][0]; - float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][1] - frameTransform._projection[side][3][1]) / frameTransform._projection[side][1][1]; - return vec3(Xe, Ye, Zeye); -} -*/ out vec4 outFragColor; uniform sampler2D normalMap; @@ -40,18 +25,7 @@ float getAngleDithering(in ivec2 pixelPos) { // Hash function used in the AlchemyAO paper return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); } - -const float TWO_PI = 6.28; - -vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){ - // Radius relative to ssR - float alpha = float(sampleNumber + 0.5) * getInvNumSamples(); - float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle; - - ssR = alpha; - return vec2(cos(angle), sin(angle)); -} - +/* vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) { // Derivation: // mipLevel = floor(log(ssR / MAX_OFFSET)); @@ -77,19 +51,9 @@ vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) { vec2 tapUV = (vec2(ssP) + vec2(0.5)) / float(side.z); P = evalEyePositionFromZeye(side.x, P.z, tapUV); return P; -} - -float sampleAO(in ivec3 side, in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) { - // Offset on the unit disk, spun for this pixel - float ssR; - vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR); - ssR *= ssDiskRadius; - - - - // The occluding point in camera space - vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR); +}*/ +float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) { vec3 v = Q - C; float vv = dot(v, v); float vn = dot(v, n_C); @@ -104,6 +68,8 @@ void main(void) { // Pixel being shaded ivec2 ssC = ivec2(gl_FragCoord.xy); + vec2 imageSize = getSideImageSize(getResolutionLevel()); + // Fetch the z under the pixel (stereo or not) float Zeye = getZEye(ssC); @@ -119,8 +85,7 @@ void main(void) { vec3 Cn = evalEyeNormal(Cp); // Choose the screen-space sample radius - // proportional to the projected area of the sphere - float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Cp.z ) * getPerspectiveScale(); + float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); // Let's make noise float randomPatternRotationAngle = getAngleDithering(ssC); @@ -128,7 +93,11 @@ void main(void) { // Accumulate the Obscurance for each samples float sum = 0.0; for (int i = 0; i < getNumSamples(); ++i) { - sum += sampleAO(side.xyz, ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle); + vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize); + + vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize); + + sum += evalAO(Cp, Cn, Q); } float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index ae4ec7770b..527c8d8cd0 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -22,7 +22,9 @@ Column { model: [ "Radius:radius:2.0:false", "Level:obscuranceLevel:1.0:false", - "Scale:perspectiveScale:2.0:false", + "Num Taps:numSamples:32:true", + "Taps Spiral:numSpiralTurns:10.0:false", + "Blur Radius:blurRadius:10.0:false", ] ConfigSlider { label: qsTr(modelData.split(":")[0]) From 92c0fa2e7aa7f4d88c00a0a01b0405c7df920c74 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 5 Aug 2016 09:26:48 -0700 Subject: [PATCH 05/71] Testiung more variations --- .../src/AmbientOcclusionEffect.cpp | 10 +++ .../render-utils/src/AmbientOcclusionEffect.h | 9 ++- .../render-utils/src/SurfaceGeometryPass.cpp | 2 +- libraries/render-utils/src/ssao.slh | 74 ++++++++++++++----- .../render-utils/src/ssao_debugOcclusion.slf | 26 +++++-- .../render-utils/src/ssao_makeOcclusion.slf | 34 +-------- .../utilities/render/ambientOcclusionPass.qml | 21 ++++++ .../render/debugAmbientOcclusionPass.js | 2 +- 8 files changed, 113 insertions(+), 65 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 97132a0fc7..9bdabbfb04 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -228,6 +228,11 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.y = 1.0f / config.numSamples; } + if (config.fetchMipsEnabled != _parametersBuffer->isFetchMipsEnabled()) { + auto& current = _parametersBuffer->sampleInfo; + current.w = (float)config.fetchMipsEnabled; + } + if (!_framebuffer) { _framebuffer = std::make_shared(); } @@ -510,6 +515,11 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const auto linearDepthFramebuffer = inputs.get2(); const auto ambientOcclusionUniforms = inputs.get3(); + // Skip if AO is not started yet + if (!ambientOcclusionUniforms._buffer) { + return; + } + auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto normalTexture = deferredFramebuffer->getDeferredNormalTexture(); auto sourceViewport = args->_viewport; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 5a0e7da587..7c2c465ba3 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -62,8 +62,8 @@ class AmbientOcclusionEffectConfig : public render::Job::Config::Persistent { Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty) Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty) Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty) + Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty) Q_PROPERTY(float radius MEMBER radius WRITE setRadius) - Q_PROPERTY(float perspectiveScale MEMBER perspectiveScale WRITE setPerspectiveScale) Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel) Q_PROPERTY(float falloffBias MEMBER falloffBias WRITE setFalloffBias) Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness) @@ -80,7 +80,6 @@ public: const int MAX_BLUR_RADIUS = 6; void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); } - void setPerspectiveScale(float scale) { perspectiveScale = scale; emit dirty(); } void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); } void setFalloffBias(float bias) { falloffBias = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); } void setEdgeSharpness(float sharpness) { edgeSharpness = std::max(0.0f, (float)sharpness); emit dirty(); } @@ -101,8 +100,9 @@ public: int numSamples{ 11 }; int resolutionLevel{ 0 }; int blurRadius{ 3 }; // 0 means no blurring - bool ditheringEnabled{ true }; // randomize the distribution of rays per pixel, should always be true + 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 }; signals: @@ -163,8 +163,11 @@ public: float getFalloffBias() const { return (float)ditheringInfo.z; } float getEdgeSharpness() const { return (float)blurInfo.x; } float getBlurDeviation() const { return blurInfo.z; } + float getNumSpiralTurns() const { return sampleInfo.z; } int getNumSamples() const { return (int)sampleInfo.x; } + bool isFetchMipsEnabled() const { return sampleInfo.w; } + int getBlurRadius() const { return (int)blurInfo.y; } bool isDitheringEnabled() const { return ditheringInfo.x; } bool isBorderingEnabled() const { return ditheringInfo.w; } diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 6dc1cb2f9b..683fe69ff0 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -71,7 +71,7 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: _linearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - // _linearDepthTexture->autoGenerateMips(1); + _linearDepthTexture->autoGenerateMips(1); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 3a3203e2e3..7efcd861c7 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -93,6 +93,10 @@ float getNumSpiralTurns() { return params._sampleInfo.z; } +int doFetchMips() { + return int(params._sampleInfo.w); +} + float getBlurEdgeSharpness() { return params._blurInfo.x; } @@ -128,6 +132,19 @@ float getBlurCoef(int c) { <@func declareSamplingDisk()@> +float getAngleDitheringWorldPos(in vec3 pixelWorldPos) { + vec3 worldPosFract = fract(pixelWorldPos * 0.2); + + ivec3 pixelPos = ivec3(worldPosFract * 256); + + return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); +} + +float getAngleDithering(in ivec2 pixelPos) { + // Hash function used in the AlchemyAO paper + return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); +} + float evalDiskRadius(float Zeye, vec2 imageSize) { // Choose the screen-space sample radius // proportional to the projected area of the sphere @@ -179,20 +196,28 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, tapPos.y -= (imageSize.y - tapPos.y); redoTap = true; } - +/* + if ((tapPos.x < 0.5)) { + tapPos.x = 0.5; + redoTap = true; + } else if ((tapPos.x > imageSize.x - 0.5)) { + tapPos.x = imageSize.x - 0.5; + redoTap = true; + } + + if ((tapPos.y < 0.5)) { + tapPos.y = 0.5; + redoTap = true; + } else if ((tapPos.y > imageSize.y - 0.5)) { + tapPos.y = imageSize.y - 0.5; + redoTap = true; + } +*/ + if (redoTap) { tap.xy = tapPos - pixelPos; tap.z = length(tap.xy); } -/* - if ((tapPos.x < 0.0) || (tapPos.x >= imageSize.x)) { - // tapPos.x = pixelPos.x - tapVec.x; - tap.x = -tap.x; - } - if ((tapPos.y < 0.0) || (tapPos.y >= imageSize.y)) { - // tapPos.y = pixelPos.y - tapVec.y; - tap.y = -tap.y; - }*/ return tap; } @@ -202,8 +227,6 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, <@func declareFetchDepthPyramidMap()@> -const int LOG_MAX_OFFSET = 3; -const int MAX_MIP_LEVEL = 5; // the depth pyramid texture uniform sampler2D pyramidMap; @@ -212,23 +235,34 @@ float getZEye(ivec2 pixel) { return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; } -vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { - // Derivation: +const int LOG_MAX_OFFSET = 3; +const int MAX_MIP_LEVEL = 5; +int evalMipFromRadius(float radius) { // mipLevel = floor(log(ssR / MAX_OFFSET)); - int mipLevel = clamp(findMSB(int(tap.z)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); + return doFetchMips() * clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); +} + +vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { + int mipLevel = evalMipFromRadius(tap.z); ivec2 ssP = ivec2(tap.xy) + ssC; ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); - vec3 P; - // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, getResolutionLevel() + mipLevel) - ivec2(1)); - P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r; + // ivec2 mipSize = textureSize(pyramidMap, mipLevel); + // ivec2 mipSize = max(ivec2(imageSize) >> mipLevel, ivec2(1)); + + // ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), mipSize - ivec2(1)); + + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; + // vec2 tapUV = (vec2(mipP) + vec2(0.5)) / vec2(mipSize); + + vec3 P; + // P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; + P.z = -textureLod(pyramidMap, tapUV, float(mipLevel)).r; // Offset to pixel center - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; P = evalEyePositionFromZeye(side.x, P.z, tapUV); return P; } diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 7e6a792c3b..ecb1d112b9 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -16,6 +16,9 @@ <$declarePackOcclusionDepth()$> +<@include gpu/color.slh@> +<$declareColorWheel()$> + struct DebugParams{ vec4 pixelInfo; }; @@ -32,10 +35,6 @@ out vec4 outFragColor; uniform sampler2D normalMap; -float getAngleDithering(in ivec2 pixelPos) { - // Hash function used in the AlchemyAO paper - return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); -} float evalAO(in vec3 C, in vec3 n_C, vec3 Q) { vec3 v = Q - C; @@ -81,18 +80,23 @@ void main(void) { } // Let's make noise - float randomPatternRotationAngle = getAngleDithering(ssC); + // float randomPatternRotationAngle = getAngleDithering(ssC); + float randomPatternRotationAngle = getAngleDitheringWorldPos(Cp); + // Accumulate the Obscurance for each samples float sum = 0.0; - float keepTapRadius = 2.0; - bool keep = (dot(fragToCursor,fragToCursor) < keepTapRadius); + float keepTapRadius = 1.0; + int keepedMip = -1; + bool keep = false; + for (int i = 0; i < getNumSamples(); ++i) { vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize); // The occluding point in camera space vec2 fragToTap = vec2(ssC) + tap.xy - gl_FragCoord.xy; if (dot(fragToTap,fragToTap) < keepTapRadius) { keep = true; + keepedMip = evalMipFromRadius(tap.z); } vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize); @@ -130,8 +134,14 @@ void main(void) { // outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); //outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); - + if ((dot(fragToCursor,fragToCursor) < (4.0 * keepTapRadius * keepTapRadius) )) { + outFragColor = vec4(vec3(A), 1.0); + return; + } + if (!keep) { outFragColor = vec4(0.1); + } else { + outFragColor.rgb = colorWheel(float(keepedMip)/float(MAX_MIP_LEVEL)); } } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 739dc1ddcb..19a6244a07 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -21,37 +21,6 @@ out vec4 outFragColor; uniform sampler2D normalMap; -float getAngleDithering(in ivec2 pixelPos) { - // Hash function used in the AlchemyAO paper - return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); -} -/* -vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec2 unitOffset, float ssR) { - // Derivation: - // mipLevel = floor(log(ssR / MAX_OFFSET)); - int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); - - ivec2 ssOffset = ivec2(ssR * unitOffset); - ivec2 ssP = ssOffset + ssC; - if (bool(isBorderingEnabled())) { - ssP.x = ((ssP.x < 0 || ssP.x >= side.z) ? ssC.x - ssOffset.x : ssP.x); - ssP.y = ((ssP.y < 0 || ssP.y >= int(getWidthHeight(getResolutionLevel()).y)) ? ssC.y - ssOffset.y : ssP.y); - } - - ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); - - vec3 P; - - // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. - // Manually clamp to the texture size because texelFetch bypasses the texture unit - ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), textureSize(pyramidMap, getResolutionLevel() + mipLevel) - ivec2(1)); - P.z = -texelFetch(pyramidMap, mipP, getResolutionLevel() + mipLevel).r; - - // Offset to pixel center - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / float(side.z); - P = evalEyePositionFromZeye(side.x, P.z, tapUV); - return P; -}*/ float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) { vec3 v = Q - C; @@ -88,7 +57,8 @@ void main(void) { float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); // Let's make noise - float randomPatternRotationAngle = getAngleDithering(ssC); + // float randomPatternRotationAngle = getAngleDithering(ssC); + float randomPatternRotationAngle = getAngleDitheringWorldPos(Cp); // Accumulate the Obscurance for each samples float sum = 0.0; diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 527c8d8cd0..c4d86e544e 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -10,6 +10,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "configSlider" +import "../lib/plotperf" Column { spacing: 8 @@ -35,11 +36,15 @@ Column { min: 0.0 } } + } + + Column { Repeater { model: [ "resolutionLevel:resolutionLevel", "ditheringEnabled:ditheringEnabled", "borderingEnabled:borderingEnabled", + "fetchMipsEnabled:fetchMipsEnabled", ] CheckBox { text: qsTr(modelData.split(":")[0]) @@ -48,5 +53,21 @@ Column { } } } + + PlotPerf { + title: "Timing" + height: 50 + object: Render.getConfig("AmbientOcclusion") + valueUnit: "ms" + valueScale: 1 + valueNumDigits: "4" + plots: [ + { + prop: "gpuTime", + label: "gpu", + color: "#FFFFFF" + } + ] + } } } diff --git a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js index 680db81607..60fb8bf918 100644 --- a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js +++ b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js @@ -13,7 +13,7 @@ var qml = Script.resolvePath('ambientOcclusionPass.qml'); var window = new OverlayWindow({ title: 'Ambient Occlusion Pass', source: qml, - width: 400, height: 170, + width: 400, height: 200, }); window.setPosition(Window.innerWidth - 420, 50 + 550 + 50); window.closed.connect(function() { Script.stop(); }); From e92e69d963f4102073dc7b268eaa3755f536c78a Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 6 Aug 2016 11:54:54 -0700 Subject: [PATCH 06/71] More changes --- .../src/AmbientOcclusionEffect.cpp | 55 +++++-------------- .../render-utils/src/AmbientOcclusionEffect.h | 8 +-- .../render-utils/src/SurfaceGeometryPass.cpp | 3 +- libraries/render-utils/src/ssao.slh | 27 +++++++-- .../render-utils/src/ssao_debugOcclusion.slf | 41 ++++++-------- .../render-utils/src/ssao_makeOcclusion.slf | 47 ++++------------ .../utilities/render/ambientOcclusionPass.qml | 1 + .../utilities/render/deferredLighting.qml | 1 + 8 files changed, 68 insertions(+), 115 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 9bdabbfb04..3899c1deb5 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -111,13 +111,6 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getOcclusionBlurredTexture() { return _occlusionBlurredTexture; } -void AmbientOcclusionFramebuffer::setResolutionLevel(int resolutionLevel) { - if (resolutionLevel != getResolutionLevel()) { - clear(); - _resolutionLevel = resolutionLevel; - } -} - class GaussianDistribution { public: @@ -240,20 +233,11 @@ void AmbientOcclusionEffect::configure(const Config& config) { if (config.perspectiveScale != _parametersBuffer->getPerspectiveScale()) { _parametersBuffer->resolutionInfo.z = config.perspectiveScale; } - _framebuffer->setResolutionLevel(config.resolutionLevel); if (config.resolutionLevel != _parametersBuffer->getResolutionLevel()) { - _parametersBuffer->resolutionInfo.w = config.resolutionLevel; + auto& current = _parametersBuffer->resolutionInfo; + current.x = (float) config.resolutionLevel; } - const auto& resolutionLevel = config.resolutionLevel; - if (resolutionLevel != _parametersBuffer->getResolutionLevel()) { - auto& current = _parametersBuffer->resolutionInfo; - current.x = (float)resolutionLevel; - - // Communicate the change to the Framebuffer cache - // DependencyManager::get()->setAmbientOcclusionResolutionLevel(resolutionLevel); - } - if (config.blurRadius != _parametersBuffer->getBlurRadius()) { auto& current = _parametersBuffer->blurInfo; current.y = (float)config.blurRadius; @@ -355,17 +339,11 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext RenderArgs* args = renderContext->args; - // FIXME: Different render modes should have different tasks -// if (args->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) { -// return; -// } - const auto frameTransform = inputs.get0(); const auto deferredFramebuffer = inputs.get1(); const auto linearDepthFramebuffer = inputs.get2(); auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); - auto normalTexture = deferredFramebuffer->getDeferredNormalTexture(); auto sourceViewport = args->_viewport; auto occlusionViewport = sourceViewport; @@ -373,10 +351,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext _framebuffer = std::make_shared(); } - if (_framebuffer->getResolutionLevel() > 0) { + if (_parametersBuffer->getResolutionLevel() > 0) { linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); - normalTexture = linearDepthFramebuffer->getHalfNormalTexture(); - occlusionViewport = occlusionViewport >> _framebuffer->getResolutionLevel(); + occlusionViewport = occlusionViewport >> _parametersBuffer->getResolutionLevel(); } _framebuffer->updateLinearDepth(linearDepthTexture); @@ -390,10 +367,10 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext auto framebufferSize = _framebuffer->getSourceFrameSize(); - float sMin = args->_viewport.x / (float)framebufferSize.x; - float sWidth = args->_viewport.z / (float)framebufferSize.x; - float tMin = args->_viewport.y / (float)framebufferSize.y; - float tHeight = args->_viewport.w / (float)framebufferSize.y; + float sMin = occlusionViewport.x / (float)framebufferSize.x; + float sWidth = occlusionViewport.z / (float)framebufferSize.x; + float tMin = occlusionViewport.y / (float)framebufferSize.y; + float tHeight = occlusionViewport.w / (float)framebufferSize.y; auto resolutionLevel = _parametersBuffer->getResolutionLevel(); @@ -536,10 +513,10 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, auto framebufferSize = glm::ivec2(linearDepthTexture->getDimensions()); - float sMin = args->_viewport.x / (float)framebufferSize.x; - float sWidth = args->_viewport.z / (float)framebufferSize.x; - float tMin = args->_viewport.y / (float)framebufferSize.y; - float tHeight = args->_viewport.w / (float)framebufferSize.y; + float sMin = occlusionViewport.x / (float)framebufferSize.x; + float sWidth = occlusionViewport.z / (float)framebufferSize.x; + float tMin = occlusionViewport.y / (float)framebufferSize.y; + float tHeight = occlusionViewport.w / (float)framebufferSize.y; // Running in stero ? @@ -562,19 +539,13 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, batch.setUniformBuffer(AmbientOcclusionEffect_FrameTransformSlot, frameTransform->getFrameTransformBuffer()); batch.setUniformBuffer(AmbientOcclusionEffect_ParamsSlot, ambientOcclusionUniforms); batch.setUniformBuffer(2, _parametersBuffer); - - - // We need this with the mips levels - batch.generateTextureMips(linearDepthTexture); batch.setPipeline(debugPipeline); batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, linearDepthTexture); batch.draw(gpu::TRIANGLE_STRIP, 4); - batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, nullptr); - batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, nullptr); - + batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, nullptr); }); } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 7c2c465ba3..dd0031bee7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -34,10 +34,7 @@ public: void updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer); gpu::TexturePointer getLinearDepthTexture(); const glm::ivec2& getSourceFrameSize() const { return _frameSize; } - - void setResolutionLevel(int level); - int getResolutionLevel() const { return _resolutionLevel; } - + protected: void clear(); void allocate(); @@ -52,7 +49,6 @@ protected: glm::ivec2 _frameSize; - int _resolutionLevel{ 0 }; }; using AmbientOcclusionFramebufferPointer = std::shared_ptr; @@ -98,7 +94,7 @@ public: float blurDeviation{ 2.5f }; float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions int numSamples{ 11 }; - int resolutionLevel{ 0 }; + int resolutionLevel{ 1 }; int blurRadius{ 3 }; // 0 means no blurring 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 diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 683fe69ff0..0f009990de 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -71,7 +71,7 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: _linearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _linearDepthTexture->autoGenerateMips(1); + _linearDepthTexture->autoGenerateMips(5); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); @@ -79,6 +79,7 @@ void LinearDepthFramebuffer::allocate() { // For Downsampling: _halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); + _halfLinearDepthTexture->autoGenerateMips(-1); _halfNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 7efcd861c7..ae3b70095e 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -133,11 +133,11 @@ float getBlurCoef(int c) { <@func declareSamplingDisk()@> float getAngleDitheringWorldPos(in vec3 pixelWorldPos) { - vec3 worldPosFract = fract(pixelWorldPos * 0.2); + vec3 worldPosFract = fract(pixelWorldPos * 0.4); ivec3 pixelPos = ivec3(worldPosFract * 256); - return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); + return isDitheringEnabled() * ((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10 + getFrameDithering(); } float getAngleDithering(in ivec2 pixelPos) { @@ -217,7 +217,8 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, if (redoTap) { tap.xy = tapPos - pixelPos; tap.z = length(tap.xy); - } + tap.z = 0; + } return tap; } @@ -231,8 +232,8 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, // the depth pyramid texture uniform sampler2D pyramidMap; -float getZEye(ivec2 pixel) { - return -texelFetch(pyramidMap, pixel, getResolutionLevel()).x; +float getZEye(ivec2 pixel, int level) { + return -texelFetch(pyramidMap, pixel, level).x; } const int LOG_MAX_OFFSET = 3; @@ -269,6 +270,22 @@ vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { <@endfunc@> + +<@func declareEvalObscurance()@> + +float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) { + vec3 v = Q - C; + float vv = dot(v, v); + float vn = dot(v, n_C); + + // Fall off function as recommended in SAO paper + const float epsilon = 0.01; + float f = max(getRadius2() - vv, 0.0); + return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0); +} + +<@endfunc@> + <@func declareBlurPass(axis)@> <$declarePackOcclusionDepth()$> diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index ecb1d112b9..5db1626ab8 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -13,6 +13,7 @@ <$declareAmbientOcclusion()$> <$declareFetchDepthPyramidMap()$> <$declareSamplingDisk()$> +<$declareEvalObscurance()$> <$declarePackOcclusionDepth()$> @@ -33,32 +34,23 @@ vec2 getDebugCursorTexcoord(){ out vec4 outFragColor; -uniform sampler2D normalMap; - - -float evalAO(in vec3 C, in vec3 n_C, vec3 Q) { - vec3 v = Q - C; - float vv = dot(v, v); - float vn = dot(v, n_C); - - // Fall off function as recommended in SAO paper - const float epsilon = 0.01; - float f = max(getRadius2() - vv, 0.0); - return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0); -} - - void main(void) { + vec2 imageSize = getSideImageSize(getResolutionLevel()); + + // In debug adjust the correct frag pixel based on base resolution + vec2 fragCoord = gl_FragCoord.xy; + if (getResolutionLevel() > 0) { + fragCoord /= float (1 << getResolutionLevel()); + } + // Pixel Debugged vec2 cursorUV = getDebugCursorTexcoord(); - vec2 imageSize = getSideImageSize(getResolutionLevel()); vec2 cursorPixelPos = cursorUV * imageSize; - ivec2 ssC = ivec2(cursorPixelPos); - // Pixel being shaded - //ivec2 ssC = ivec2(gl_FragCoord.xy); + ivec2 ssC = ivec2(cursorPixelPos); + // Fetch the z under the pixel (stereo or not) - float Zeye = getZEye(ssC); + float Zeye = getZEye(ssC, 0); // Stereo side info ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel()); @@ -74,7 +66,7 @@ void main(void) { // Choose the screen-space sample radius float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); - vec2 fragToCursor = cursorPixelPos - gl_FragCoord.xy; + vec2 fragToCursor = cursorPixelPos - fragCoord.xy; if (dot(fragToCursor,fragToCursor) > ssDiskRadius * ssDiskRadius) { discard; } @@ -93,7 +85,7 @@ void main(void) { for (int i = 0; i < getNumSamples(); ++i) { vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize); // The occluding point in camera space - vec2 fragToTap = vec2(ssC) + tap.xy - gl_FragCoord.xy; + vec2 fragToTap = vec2(ssC) + tap.xy - fragCoord.xy; if (dot(fragToTap,fragToTap) < keepTapRadius) { keep = true; keepedMip = evalMipFromRadius(tap.z); @@ -101,7 +93,7 @@ void main(void) { vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize); - sum += evalAO(Cp, Cn, Q); + sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q); } @@ -134,7 +126,8 @@ void main(void) { // outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); //outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); - if ((dot(fragToCursor,fragToCursor) < (4.0 * keepTapRadius * keepTapRadius) )) { + if ((dot(fragToCursor,fragToCursor) < (100.0 * keepTapRadius * keepTapRadius) )) { + // outFragColor = vec4(vec3(A), 1.0); outFragColor = vec4(vec3(A), 1.0); return; } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 19a6244a07..7af1feb477 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -13,41 +13,28 @@ <$declareAmbientOcclusion()$> <$declareFetchDepthPyramidMap()$> <$declareSamplingDisk()$> +<$declareEvalObscurance()$> <$declarePackOcclusionDepth()$> - out vec4 outFragColor; -uniform sampler2D normalMap; - - -float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) { - vec3 v = Q - C; - float vv = dot(v, v); - float vn = dot(v, n_C); - - // Fall off function as recommended in SAO paper - const float epsilon = 0.01; - float f = max(getRadius2() - vv, 0.0); - return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0); -} - void main(void) { - // Pixel being shaded - ivec2 ssC = ivec2(gl_FragCoord.xy); - vec2 imageSize = getSideImageSize(getResolutionLevel()); + // Pixel being shaded + vec2 fragCoord = gl_FragCoord.xy; + ivec2 ssC = ivec2(fragCoord.xy); + // Fetch the z under the pixel (stereo or not) - float Zeye = getZEye(ssC); + float Zeye = getZEye(ssC, 0); // Stereo side info ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel()); // From now on, ssC is the pixel pos in the side ssC.x -= side.y; - vec2 fragPos = (vec2(ssC) + vec2(0.5)) / vec2(getStereoSideWidth(getResolutionLevel()), getStereoSideHeight(getResolutionLevel())); + vec2 fragPos = (vec2(ssC) + vec2(0.5)) / imageSize; // The position and normal of the pixel fragment in Eye space vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos); @@ -57,7 +44,7 @@ void main(void) { float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); // Let's make noise - // float randomPatternRotationAngle = getAngleDithering(ssC); + //float randomPatternRotationAngle = getAngleDithering(ssC); float randomPatternRotationAngle = getAngleDitheringWorldPos(Cp); // Accumulate the Obscurance for each samples @@ -65,9 +52,9 @@ void main(void) { for (int i = 0; i < getNumSamples(); ++i) { vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize); - vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize); + vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize); - sum += evalAO(Cp, Cn, Q); + sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q); } float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); @@ -84,18 +71,4 @@ void main(void) { !> outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); - - // KEEP IT for Debugging - // Debug Normal: outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); - // Debug Radius outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); - // Debug MaxMiplevel outFragColor = vec4(1.0 - vec3(float(clamp(findMSB(int(ssDiskRadius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL))/ float(MAX_MIP_LEVEL)), 1.0); - // Debug OffsetPosition - // float ssR; - // vec2 unitOffset = tapLocation(int(getNumSamples() - 1), 0, ssR); - // vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR * ssDiskRadius); - //outFragColor = vec4(vec3(Q.x / 10.0, Q.y / 2.0, -Q.z/ 3.0), 1.0); - // vec3 v = normalize(Q - Cp); - //outFragColor = vec4((v + vec3(1.0))* 0.5, 1.0); - // outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); - //outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); } diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index c4d86e544e..b6d54676e3 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -25,6 +25,7 @@ Column { "Level:obscuranceLevel:1.0:false", "Num Taps:numSamples:32:true", "Taps Spiral:numSpiralTurns:10.0:false", + "Falloff Bias:falloffBias:0.2:false", "Blur Radius:blurRadius:10.0:false", ] ConfigSlider { diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 635d8b1471..4901be8e03 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -24,6 +24,7 @@ Column { "Emissive:LightingModel:enableEmissive", "Lightmap:LightingModel:enableLightmap", "Background:LightingModel:enableBackground", + "ssao:AmbientOcclusion:enabled", ] CheckBox { text: modelData.split(":")[0] From d1105b8102b48748eff21322ae647a8fc66c251a Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 7 Aug 2016 18:10:03 -0700 Subject: [PATCH 07/71] Still trying --- .../src/AmbientOcclusionEffect.cpp | 24 +++++++++---------- .../render-utils/src/DebugDeferredBuffer.cpp | 18 ++++++++++++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 3899c1deb5..f11ec8f3f7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -339,9 +339,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext RenderArgs* args = renderContext->args; - const auto frameTransform = inputs.get0(); - const auto deferredFramebuffer = inputs.get1(); - const auto linearDepthFramebuffer = inputs.get2(); + const auto& frameTransform = inputs.get0(); + const auto& deferredFramebuffer = inputs.get1(); + const auto& linearDepthFramebuffer = inputs.get2(); auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto sourceViewport = args->_viewport; @@ -403,13 +403,13 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // We need this with the mips levels - batch.generateTextureMips(linearDepthTexture); + batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); // Occlusion pass batch.setFramebuffer(occlusionFBO); batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); batch.setPipeline(occlusionPipeline); - batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, linearDepthTexture); + batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, _framebuffer->getLinearDepthTexture()); batch.draw(gpu::TRIANGLE_STRIP, 4); @@ -487,10 +487,10 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, // return; // } - const auto frameTransform = inputs.get0(); - const auto deferredFramebuffer = inputs.get1(); - const auto linearDepthFramebuffer = inputs.get2(); - const auto ambientOcclusionUniforms = inputs.get3(); + const auto& frameTransform = inputs.get0(); + const auto& deferredFramebuffer = inputs.get1(); + const auto& linearDepthFramebuffer = inputs.get2(); + const auto& ambientOcclusionUniforms = inputs.get3(); // Skip if AO is not started yet if (!ambientOcclusionUniforms._buffer) { @@ -498,16 +498,14 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, } auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); - auto normalTexture = deferredFramebuffer->getDeferredNormalTexture(); auto sourceViewport = args->_viewport; auto occlusionViewport = sourceViewport; auto resolutionLevel = ambientOcclusionUniforms->getResolutionLevel(); if (resolutionLevel > 0) { - linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); - normalTexture = linearDepthFramebuffer->getHalfNormalTexture(); - occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel(); + linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); + occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel(); } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index ed4eba972f..86f97d57a6 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -423,5 +423,23 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren 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(Curvature, nullptr); + batch.setResourceTexture(DiffusedCurvature, nullptr); + + batch.setResourceTexture(AmbientOcclusion, nullptr); + batch.setResourceTexture(AmbientOcclusionBlurred, nullptr); + }); } From e6c74b29c7a3913c0ba0f59d738f0fa8b2811d35 Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 7 Aug 2016 19:48:23 -0700 Subject: [PATCH 08/71] WTF... --- .../src/AmbientOcclusionEffect.cpp | 6 ++- .../render-utils/src/DebugDeferredBuffer.cpp | 38 +++++++++++------- .../render-utils/src/RenderDeferredTask.cpp | 6 +-- .../render-utils/src/SurfaceGeometryPass.cpp | 5 ++- .../utilities/render/ambientOcclusionPass.qml | 39 ++++++++++++------- 5 files changed, 61 insertions(+), 33 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index f11ec8f3f7..39a9d99458 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -403,7 +403,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // We need this with the mips levels - batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); + // batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); // Occlusion pass batch.setFramebuffer(occlusionFBO); @@ -480,6 +480,10 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); + if (!_showCursorPixel) { + return; + } + RenderArgs* args = renderContext->args; // FIXME: Different render modes should have different tasks diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 86f97d57a6..c45ab8c0e2 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -403,22 +403,30 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setPipeline(getPipeline(_mode, first)); - 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()); - batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getDepthStencilBuffer()); - batch.setResourceTexture(LinearDepth, linearDepthTarget->getLinearDepthTexture()); - batch.setResourceTexture(HalfLinearDepth, linearDepthTarget->getHalfLinearDepthTexture()); - batch.setResourceTexture(HalfNormal, linearDepthTarget->getHalfNormalTexture()); - - batch.setResourceTexture(Curvature, surfaceGeometryFramebuffer->getCurvatureTexture()); - batch.setResourceTexture(DiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture()); - - batch.setResourceTexture(AmbientOcclusion, ambientOcclusionFramebuffer->getOcclusionTexture()); - batch.setResourceTexture(AmbientOcclusionBlurred, ambientOcclusionFramebuffer->getOcclusionBlurredTexture()); + 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 (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); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 7ea81eb706..7be78890e9 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -124,9 +124,9 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).hasVarying(); const auto linearDepthPassOutputs = addJob("LinearDepth", linearDepthPassInputs); const auto linearDepthTarget = linearDepthPassOutputs.getN(0); - const auto linearDepthTexture = linearDepthPassOutputs.getN(2); - const auto halfLinearDepthTexture = linearDepthPassOutputs.getN(3); - const auto halfNormalTexture = linearDepthPassOutputs.getN(4); + // const auto linearDepthTexture = linearDepthPassOutputs.getN(2); + // const auto halfLinearDepthTexture = linearDepthPassOutputs.getN(3); + // const auto halfNormalTexture = linearDepthPassOutputs.getN(4); // Curvature pass diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 0f009990de..46158e30b3 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -61,6 +61,9 @@ void LinearDepthFramebuffer::updatePrimaryDepth(const gpu::TexturePointer& depth void LinearDepthFramebuffer::clear() { _linearDepthFramebuffer.reset(); _linearDepthTexture.reset(); + _downsampleFramebuffer.reset(); + _halfLinearDepthTexture.reset(); + _halfNormalTexture.reset(); } void LinearDepthFramebuffer::allocate() { @@ -79,7 +82,7 @@ void LinearDepthFramebuffer::allocate() { // For Downsampling: _halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _halfLinearDepthTexture->autoGenerateMips(-1); + _halfLinearDepthTexture->autoGenerateMips(5); _halfNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index b6d54676e3..89883ab399 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -38,21 +38,34 @@ Column { } } } - - Column { - Repeater { - model: [ - "resolutionLevel:resolutionLevel", - "ditheringEnabled:ditheringEnabled", - "borderingEnabled:borderingEnabled", - "fetchMipsEnabled:fetchMipsEnabled", - ] - CheckBox { - text: qsTr(modelData.split(":")[0]) - checked: Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]] - onCheckedChanged: { Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]] = checked } + Row{ + Column { + Repeater { + model: [ + "resolutionLevel:resolutionLevel", + "ditheringEnabled:ditheringEnabled", + "borderingEnabled:borderingEnabled", + "fetchMipsEnabled:fetchMipsEnabled" + ] + CheckBox { + text: qsTr(modelData.split(":")[0]) + checked: Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]] + onCheckedChanged: { Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]] = checked } + } } } + Column { + Repeater { + model: [ + "debugEnabled:showCursorPixel" + ] + CheckBox { + text: qsTr(modelData.split(":")[0]) + checked: Render.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]] + onCheckedChanged: { Render.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]] = checked } + } + } + } } PlotPerf { From db8bf78dd186fac8fe0077a274dab83cc10f42b9 Mon Sep 17 00:00:00 2001 From: sam Date: Mon, 8 Aug 2016 02:28:25 -0700 Subject: [PATCH 09/71] Good state --- .../src/AmbientOcclusionEffect.cpp | 4 +- .../render-utils/src/AmbientOcclusionEffect.h | 4 +- .../render-utils/src/RenderDeferredTask.cpp | 17 +++----- .../render-utils/src/SurfaceGeometryPass.cpp | 2 +- libraries/render-utils/src/ssao.slh | 43 +++++++++++++------ .../render-utils/src/ssao_debugOcclusion.slf | 12 ++++-- .../render-utils/src/ssao_makeOcclusion.slf | 9 ++-- .../utilities/render/ambientOcclusionPass.qml | 4 +- .../render/debugAmbientOcclusionPass.js | 2 +- 9 files changed, 57 insertions(+), 40 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 39a9d99458..b17db5796d 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -375,7 +375,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext auto resolutionLevel = _parametersBuffer->getResolutionLevel(); - //_parametersBuffer.edit()._ditheringInfo.y += 0.25f; + _parametersBuffer->ditheringInfo.y += 0.25f; // Running in stero ? bool isStereo = args->_context->isStereo(); @@ -403,7 +403,7 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // We need this with the mips levels - // batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); + batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); // Occlusion pass batch.setFramebuffer(occlusionFBO); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index dd0031bee7..5ec0060d84 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -94,8 +94,8 @@ public: float blurDeviation{ 2.5f }; float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions int numSamples{ 11 }; - int resolutionLevel{ 1 }; - int blurRadius{ 3 }; // 0 means no blurring + int resolutionLevel{ 0 }; + int blurRadius{ 4 }; // 0 means no blurring 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 diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 7be78890e9..cedc2ef45e 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -124,10 +124,6 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).hasVarying(); const auto linearDepthPassOutputs = addJob("LinearDepth", linearDepthPassInputs); const auto linearDepthTarget = linearDepthPassOutputs.getN(0); - // const auto linearDepthTexture = linearDepthPassOutputs.getN(2); - // const auto halfLinearDepthTexture = linearDepthPassOutputs.getN(3); - // const auto halfNormalTexture = linearDepthPassOutputs.getN(4); - // Curvature pass const auto surfaceGeometryPassInputs = SurfaceGeometryPass::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying(); @@ -150,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); @@ -178,17 +174,16 @@ 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); const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying(); addJob("DebugAmbientOcclusion", debugAmbientOcclusionInputs); - // Scene Octree Debuging job { addJob("DrawSceneOctree", spatialSelection); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 46158e30b3..0ee4e6af4a 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -74,7 +74,7 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: _linearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _linearDepthTexture->autoGenerateMips(5); + // _linearDepthTexture->autoGenerateMips(5); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index ae3b70095e..fe4b77577f 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -133,7 +133,7 @@ float getBlurCoef(int c) { <@func declareSamplingDisk()@> float getAngleDitheringWorldPos(in vec3 pixelWorldPos) { - vec3 worldPosFract = fract(pixelWorldPos * 0.4); + vec3 worldPosFract = fract(pixelWorldPos * 1.0); ivec3 pixelPos = ivec3(worldPosFract * 256); @@ -240,34 +240,49 @@ const int LOG_MAX_OFFSET = 3; const int MAX_MIP_LEVEL = 5; int evalMipFromRadius(float radius) { // mipLevel = floor(log(ssR / MAX_OFFSET)); - return doFetchMips() * clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); + return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL); } -vec3 getOffsetPosition(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { - int mipLevel = evalMipFromRadius(tap.z); + +vec3 fetchTapUnfiltered(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { + ivec2 ssP = ivec2(tap.xy) + ssC; + ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); + + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; + + vec3 P; + P.xy = tapUV; + P.z = -texture(pyramidMap, tapUV).x; + + return P; +} + +vec3 fetchTap(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { + int mipLevel = evalMipFromRadius(tap.z * doFetchMips()); ivec2 ssP = ivec2(tap.xy) + ssC; ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map. // Manually clamp to the texture size because texelFetch bypasses the texture unit - // ivec2 mipSize = textureSize(pyramidMap, mipLevel); - // ivec2 mipSize = max(ivec2(imageSize) >> mipLevel, ivec2(1)); + // ivec2 mipSize = textureSize(pyramidMap, mipLevel); + ivec2 mipSize = max(ivec2(imageSize) >> mipLevel, ivec2(1)); - // ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), mipSize - ivec2(1)); + ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), mipSize - ivec2(1)); - vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; - // vec2 tapUV = (vec2(mipP) + vec2(0.5)) / vec2(mipSize); + // vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; + vec2 tapUV = (vec2(mipP) + vec2(0.5)) / vec2(mipSize); vec3 P; - // P.z = -texelFetch(pyramidMap, mipP, mipLevel).r; - P.z = -textureLod(pyramidMap, tapUV, float(mipLevel)).r; + P.xy = tapUV; + P.z = -texelFetch(pyramidMap, mipP, mipLevel).x; + // P.z = -textureLod(pyramidMap, tapUV, float(mipLevel)).x; - // Offset to pixel center - P = evalEyePositionFromZeye(side.x, P.z, tapUV); - return P; + return P; } + + <@endfunc@> diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 5db1626ab8..077b7e68b9 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -72,8 +72,9 @@ void main(void) { } // Let's make noise - // float randomPatternRotationAngle = getAngleDithering(ssC); - float randomPatternRotationAngle = getAngleDitheringWorldPos(Cp); + //float randomPatternRotationAngle = getAngleDithering(ssC); + vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; + float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp); // Accumulate the Obscurance for each samples @@ -84,14 +85,17 @@ void main(void) { for (int i = 0; i < getNumSamples(); ++i) { vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize); + // The occluding point in camera space vec2 fragToTap = vec2(ssC) + tap.xy - fragCoord.xy; if (dot(fragToTap,fragToTap) < keepTapRadius) { keep = true; - keepedMip = evalMipFromRadius(tap.z); + keepedMip = evalMipFromRadius(tap.z * doFetchMips()); } - vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize); + vec3 tapUVZ = fetchTap(side.xyz, ssC, tap, imageSize); + + vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q); } diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 7af1feb477..4e90160d23 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -44,15 +44,18 @@ void main(void) { float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); // Let's make noise - //float randomPatternRotationAngle = getAngleDithering(ssC); - float randomPatternRotationAngle = getAngleDitheringWorldPos(Cp); + // float randomPatternRotationAngle = getAngleDithering(ssC); + vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; + float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp); // Accumulate the Obscurance for each samples float sum = 0.0; for (int i = 0; i < getNumSamples(); ++i) { vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize); - vec3 Q = getOffsetPosition(side.xyz, ssC, tap, imageSize); + vec3 tapUVZ = fetchTap(side.xyz, ssC, tap, imageSize); + + vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q); } diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 89883ab399..402aba015b 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -44,8 +44,8 @@ Column { model: [ "resolutionLevel:resolutionLevel", "ditheringEnabled:ditheringEnabled", - "borderingEnabled:borderingEnabled", - "fetchMipsEnabled:fetchMipsEnabled" + "fetchMipsEnabled:fetchMipsEnabled", + "borderingEnabled:borderingEnabled" ] CheckBox { text: qsTr(modelData.split(":")[0]) diff --git a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js index 60fb8bf918..c57fdf0526 100644 --- a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js +++ b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js @@ -13,7 +13,7 @@ var qml = Script.resolvePath('ambientOcclusionPass.qml'); var window = new OverlayWindow({ title: 'Ambient Occlusion Pass', source: qml, - width: 400, height: 200, + width: 400, height: 250, }); window.setPosition(Window.innerWidth - 420, 50 + 550 + 50); window.closed.connect(function() { Script.stop(); }); From 4d3dce449f7cb36a3f49f90af749a41aeed59a1d Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 8 Aug 2016 17:28:04 -0700 Subject: [PATCH 10/71] Better maybe --- .../src/AmbientOcclusionEffect.cpp | 48 +++++++++---------- .../render-utils/src/AmbientOcclusionEffect.h | 4 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index b17db5796d..21605292ca 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -234,8 +234,8 @@ void AmbientOcclusionEffect::configure(const Config& config) { _parametersBuffer->resolutionInfo.z = config.perspectiveScale; } if (config.resolutionLevel != _parametersBuffer->getResolutionLevel()) { - auto& current = _parametersBuffer->resolutionInfo; - current.x = (float) config.resolutionLevel; + auto& current = _parametersBuffer->resolutionInfo; + current.x = (float) config.resolutionLevel; } if (config.blurRadius != _parametersBuffer->getBlurRadius()) { @@ -351,9 +351,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext _framebuffer = std::make_shared(); } - if (_parametersBuffer->getResolutionLevel() > 0) { + if (_parametersBuffer->getResolutionLevel() > 0) { linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); - occlusionViewport = occlusionViewport >> _parametersBuffer->getResolutionLevel(); + occlusionViewport = occlusionViewport >> _parametersBuffer->getResolutionLevel(); } _framebuffer->updateLinearDepth(linearDepthTexture); @@ -367,15 +367,15 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext auto framebufferSize = _framebuffer->getSourceFrameSize(); - float sMin = occlusionViewport.x / (float)framebufferSize.x; - float sWidth = occlusionViewport.z / (float)framebufferSize.x; - float tMin = occlusionViewport.y / (float)framebufferSize.y; - float tHeight = occlusionViewport.w / (float)framebufferSize.y; + float sMin = occlusionViewport.x / (float)framebufferSize.x; + float sWidth = occlusionViewport.z / (float)framebufferSize.x; + float tMin = occlusionViewport.y / (float)framebufferSize.y; + float tHeight = occlusionViewport.w / (float)framebufferSize.y; auto resolutionLevel = _parametersBuffer->getResolutionLevel(); - _parametersBuffer->ditheringInfo.y += 0.25f; + //_parametersBuffer->ditheringInfo.y += 0.25f; // Running in stero ? bool isStereo = args->_context->isStereo(); @@ -403,13 +403,13 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext // We need this with the mips levels - batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); + batch.generateTextureMips(_framebuffer->getLinearDepthTexture()); // Occlusion pass batch.setFramebuffer(occlusionFBO); batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(1.0f)); batch.setPipeline(occlusionPipeline); - batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, _framebuffer->getLinearDepthTexture()); + batch.setResourceTexture(AmbientOcclusionEffect_LinearDepthMapSlot, _framebuffer->getLinearDepthTexture()); batch.draw(gpu::TRIANGLE_STRIP, 4); @@ -480,9 +480,9 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); - if (!_showCursorPixel) { - return; - } + if (!_showCursorPixel) { + return; + } RenderArgs* args = renderContext->args; @@ -496,10 +496,10 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const auto& linearDepthFramebuffer = inputs.get2(); const auto& ambientOcclusionUniforms = inputs.get3(); - // Skip if AO is not started yet - if (!ambientOcclusionUniforms._buffer) { - return; - } + // Skip if AO is not started yet + if (!ambientOcclusionUniforms._buffer) { + return; + } auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); auto sourceViewport = args->_viewport; @@ -508,17 +508,17 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, auto resolutionLevel = ambientOcclusionUniforms->getResolutionLevel(); if (resolutionLevel > 0) { - linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); - occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel(); + linearDepthTexture = linearDepthFramebuffer->getHalfLinearDepthTexture(); + occlusionViewport = occlusionViewport >> ambientOcclusionUniforms->getResolutionLevel(); } auto framebufferSize = glm::ivec2(linearDepthTexture->getDimensions()); - float sMin = occlusionViewport.x / (float)framebufferSize.x; - float sWidth = occlusionViewport.z / (float)framebufferSize.x; - float tMin = occlusionViewport.y / (float)framebufferSize.y; - float tHeight = occlusionViewport.w / (float)framebufferSize.y; + float sMin = occlusionViewport.x / (float)framebufferSize.x; + float sWidth = occlusionViewport.z / (float)framebufferSize.x; + float tMin = occlusionViewport.y / (float)framebufferSize.y; + float tHeight = occlusionViewport.w / (float)framebufferSize.y; // Running in stero ? diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 5ec0060d84..5fdea81979 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -93,8 +93,8 @@ public: float edgeSharpness{ 1.0f }; float blurDeviation{ 2.5f }; float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions - int numSamples{ 11 }; - int resolutionLevel{ 0 }; + int numSamples{ 9 }; + int resolutionLevel{ 1 }; int blurRadius{ 4 }; // 0 means no blurring 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 From b90e0cfd898dc1315b8c76c15acd82a251975a3c Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 12 Aug 2016 19:18:05 -0700 Subject: [PATCH 11/71] Fixing the stereo issue --- libraries/render-utils/src/ssao.slh | 24 +++++++------ .../render-utils/src/ssao_debugOcclusion.slf | 36 ++++++------------- .../render-utils/src/ssao_makeOcclusion.slf | 19 +++++++--- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index fe4b77577f..c9b27bc2c8 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -218,7 +218,7 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, tap.xy = tapPos - pixelPos; tap.z = length(tap.xy); tap.z = 0; - } + } return tap; } @@ -244,20 +244,23 @@ int evalMipFromRadius(float radius) { } -vec3 fetchTapUnfiltered(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { +vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { ivec2 ssP = ivec2(tap.xy) + ssC; ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y); + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; + vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y); + vec3 P; - P.xy = tapUV; - P.z = -texture(pyramidMap, tapUV).x; + P.xy = tapUV; + P.z = -texture(pyramidMap, fetchUV).x; return P; } -vec3 fetchTap(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { +vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { int mipLevel = evalMipFromRadius(tap.z * doFetchMips()); ivec2 ssP = ivec2(tap.xy) + ssC; @@ -270,13 +273,14 @@ vec3 fetchTap(ivec3 side, ivec2 ssC, vec3 tap, vec2 imageSize) { ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), mipSize - ivec2(1)); - // vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; - vec2 tapUV = (vec2(mipP) + vec2(0.5)) / vec2(mipSize); + vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; + vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y); + // vec2 tapUV = (vec2(mipP) + vec2(0.5)) / vec2(mipSize); vec3 P; - P.xy = tapUV; - P.z = -texelFetch(pyramidMap, mipP, mipLevel).x; - // P.z = -textureLod(pyramidMap, tapUV, float(mipLevel)).x; + P.xy = tapUV; + // P.z = -texelFetch(pyramidMap, mipP, mipLevel).x; + P.z = -textureLod(pyramidMap, fetchUV, float(mipLevel)).x; return P; } diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 077b7e68b9..50c66c62e3 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -36,13 +36,13 @@ out vec4 outFragColor; void main(void) { vec2 imageSize = getSideImageSize(getResolutionLevel()); - - // In debug adjust the correct frag pixel based on base resolution - vec2 fragCoord = gl_FragCoord.xy; - if (getResolutionLevel() > 0) { - fragCoord /= float (1 << getResolutionLevel()); - } - + + // In debug adjust the correct frag pixel based on base resolution + vec2 fragCoord = gl_FragCoord.xy; + if (getResolutionLevel() > 0) { + fragCoord /= float (1 << getResolutionLevel()); + } + // Pixel Debugged vec2 cursorUV = getDebugCursorTexcoord(); vec2 cursorPixelPos = cursorUV * imageSize; @@ -73,7 +73,7 @@ void main(void) { // Let's make noise //float randomPatternRotationAngle = getAngleDithering(ssC); - vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; + vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp); @@ -93,9 +93,9 @@ void main(void) { keepedMip = evalMipFromRadius(tap.z * doFetchMips()); } - vec3 tapUVZ = fetchTap(side.xyz, ssC, tap, imageSize); - - vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); + vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize); + + vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q); } @@ -116,20 +116,6 @@ void main(void) { outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); - // KEEP IT for Debugging - // Debug Normal: outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); - // Debug Radius outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); - // Debug MaxMiplevel outFragColor = vec4(1.0 - vec3(float(clamp(findMSB(int(ssDiskRadius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL))/ float(MAX_MIP_LEVEL)), 1.0); - // Debug OffsetPosition - // float ssR; - // vec2 unitOffset = tapLocation(int(getNumSamples() - 1), 0, ssR); - // vec3 Q = getOffsetPosition(side, ssC, unitOffset, ssR * ssDiskRadius); - //outFragColor = vec4(vec3(Q.x / 10.0, Q.y / 2.0, -Q.z/ 3.0), 1.0); - // vec3 v = normalize(Q - Cp); - //outFragColor = vec4((v + vec3(1.0))* 0.5, 1.0); - // outFragColor = vec4((Cn + vec3(1.0))* 0.5, 1.0); - //outFragColor = vec4(vec3(ssDiskRadius / 100.0), 1.0); - if ((dot(fragToCursor,fragToCursor) < (100.0 * keepTapRadius * keepTapRadius) )) { // outFragColor = vec4(vec3(A), 1.0); outFragColor = vec4(vec3(A), 1.0); diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 4e90160d23..91d94294af 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -23,7 +23,7 @@ void main(void) { vec2 imageSize = getSideImageSize(getResolutionLevel()); // Pixel being shaded - vec2 fragCoord = gl_FragCoord.xy; + vec2 fragCoord = gl_FragCoord.xy; ivec2 ssC = ivec2(fragCoord.xy); // Fetch the z under the pixel (stereo or not) @@ -44,8 +44,8 @@ void main(void) { float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); // Let's make noise - // float randomPatternRotationAngle = getAngleDithering(ssC); - vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; + //float randomPatternRotationAngle = getAngleDithering(ssC); + vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp); // Accumulate the Obscurance for each samples @@ -53,9 +53,9 @@ void main(void) { for (int i = 0; i < getNumSamples(); ++i) { vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize); - vec3 tapUVZ = fetchTap(side.xyz, ssC, tap, imageSize); + vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize); - vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); + vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q); } @@ -74,4 +74,13 @@ void main(void) { !> outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); + + /* { + vec3 tap = getTapLocationClamped(2, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize); + vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize); + vec2 fetchUV = vec2(tapUVZ.x + side.w * 0.5 * (side.x - tapUVZ.x), tapUVZ.y); + vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy); + outFragColor = vec4(fetchUV, 0.0, 1.0); + }*/ + } From 6a076bcee4316d40bb7bec8c652c2abc4cff1145 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 19 Aug 2016 11:09:12 -0700 Subject: [PATCH 12/71] PRoviding a fix for the macOS build --- libraries/gpu/src/gpu/Buffer.h | 8 ++++---- .../render-utils/src/AmbientOcclusionEffect.cpp | 17 +---------------- .../render-utils/src/AmbientOcclusionEffect.h | 9 ++++++--- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h index 8160f648fc..9fc0108e35 100644 --- a/libraries/gpu/src/gpu/Buffer.h +++ b/libraries/gpu/src/gpu/Buffer.h @@ -180,10 +180,10 @@ public: using Index = int; BufferPointer _buffer; - Size _offset; - Size _size; - Element _element; - uint16 _stride; + Size _offset { 0 }; + Size _size { 0 }; + Element _element { DEFAULT_ELEMENT }; + uint16 _stride { 0 }; BufferView(const BufferView& view) = default; BufferView& operator=(const BufferView& view) = default; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 3470e4b8ff..5f3c3ca76a 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -340,7 +340,6 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext RenderArgs* args = renderContext->args; const auto& frameTransform = inputs.get0(); - const auto& deferredFramebuffer = inputs.get1(); const auto& linearDepthFramebuffer = inputs.get2(); auto linearDepthTexture = linearDepthFramebuffer->getLinearDepthTexture(); @@ -372,13 +371,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext float tMin = occlusionViewport.y / (float)framebufferSize.y; float tHeight = occlusionViewport.w / (float)framebufferSize.y; - auto resolutionLevel = _parametersBuffer->getResolutionLevel(); - //_parametersBuffer->ditheringInfo.y += 0.25f; - // Running in stero ? - bool isStereo = args->_context->isStereo(); auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); @@ -486,13 +481,7 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, RenderArgs* args = renderContext->args; - // FIXME: Different render modes should have different tasks -// if (args->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) { -// return; -// } - const auto& frameTransform = inputs.get0(); - const auto& deferredFramebuffer = inputs.get1(); const auto& linearDepthFramebuffer = inputs.get2(); const auto& ambientOcclusionUniforms = inputs.get3(); @@ -519,11 +508,7 @@ void DebugAmbientOcclusion::run(const render::SceneContextPointer& sceneContext, float sWidth = occlusionViewport.z / (float)framebufferSize.x; float tMin = occlusionViewport.y / (float)framebufferSize.y; float tHeight = occlusionViewport.w / (float)framebufferSize.y; - - - // Running in stero ? - bool isStereo = args->_context->isStereo(); - + auto debugPipeline = getDebugPipeline(); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 5fdea81979..0c393709d5 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -109,15 +109,18 @@ signals: 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(std::make_shared(sizeof(T), (const gpu::Byte*) &T())) {} + UniformBuffer() : gpu::BufferView(makeBuffer()) {} const T* operator ->() const { return &get(); } T* operator ->() { return &edit(); } }; - - } class AmbientOcclusionEffect { From 9cdd07921373719fb3e6d6ce6b989e3b2fe9f4d3 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 19 Aug 2016 18:22:14 -0700 Subject: [PATCH 13/71] And again --- libraries/render-utils/src/AmbientOcclusionEffect.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 0c393709d5..12771e931e 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -118,7 +118,9 @@ template class UniformBuffer : public gpu::BufferView { UniformBuffer() : gpu::BufferView(makeBuffer()) {} const T* operator ->() const { return &get(); } - T* operator ->() { return &edit(); } + T* operator ->() { + return &edit(0); + } }; } From 4097fcb0f67d1f0e7016179fc45101aa1a6c08cd Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 21 Aug 2016 00:27:43 -0700 Subject: [PATCH 14/71] fixing the blurring issue --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 5 +++++ libraries/render-utils/src/AmbientOcclusionEffect.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 5f3c3ca76a..613bc22c84 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -169,6 +169,7 @@ public: const int AmbientOcclusionEffect_FrameTransformSlot = 0; const int AmbientOcclusionEffect_ParamsSlot = 1; +const int AmbientOcclusionEffect_CameraCorrectionSlot = 2; const int AmbientOcclusionEffect_LinearDepthMapSlot = 0; const int AmbientOcclusionEffect_OcclusionMapSlot = 0; @@ -268,6 +269,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), AmbientOcclusionEffect_CameraCorrectionSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("pyramidMap"), AmbientOcclusionEffect_LinearDepthMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); @@ -290,6 +293,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), AmbientOcclusionEffect_CameraCorrectionSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot)); gpu::Shader::makeProgram(*program, slotBindings); @@ -312,6 +316,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionFrameTransformBuffer"), AmbientOcclusionEffect_FrameTransformSlot)); + slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), AmbientOcclusionEffect_CameraCorrectionSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot)); slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot)); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 12771e931e..7f3ff3f64f 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -93,7 +93,7 @@ public: float edgeSharpness{ 1.0f }; float blurDeviation{ 2.5f }; float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions - int numSamples{ 9 }; + int numSamples{ 16 }; int resolutionLevel{ 1 }; int blurRadius{ 4 }; // 0 means no blurring bool ditheringEnabled{ true }; // randomize the distribution of taps per pixel, should always be true From 1e84f9dc90d0169adf8d15b45aff9da4fd0a476d Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 21 Aug 2016 23:37:24 -0700 Subject: [PATCH 15/71] back to noise seeded in image space --- libraries/render-utils/src/ssao_makeOcclusion.slf | 10 +++++----- .../utilities/render/ambientOcclusionPass.qml | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/ssao_makeOcclusion.slf b/libraries/render-utils/src/ssao_makeOcclusion.slf index 91d94294af..4c808342c5 100644 --- a/libraries/render-utils/src/ssao_makeOcclusion.slf +++ b/libraries/render-utils/src/ssao_makeOcclusion.slf @@ -44,9 +44,9 @@ void main(void) { float ssDiskRadius = evalDiskRadius(Cp.z, imageSize); // Let's make noise - //float randomPatternRotationAngle = getAngleDithering(ssC); - vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; - float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp); + float randomPatternRotationAngle = getAngleDithering(ssC); + //vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz; + //float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp); // Accumulate the Obscurance for each samples float sum = 0.0; @@ -62,7 +62,7 @@ void main(void) { float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples()); - + outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0); diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 402aba015b..a461c06a19 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -26,6 +26,7 @@ Column { "Num Taps:numSamples:32:true", "Taps Spiral:numSpiralTurns:10.0:false", "Falloff Bias:falloffBias:0.2:false", + "Edge Sharpness:edgeSharpness:1.0:false", "Blur Radius:blurRadius:10.0:false", ] ConfigSlider { From e1f7dfc4e14836ce7d596b1ccf0fc617e4f5ab9e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 22 Aug 2016 10:34:56 -0700 Subject: [PATCH 16/71] Raised max iterations for IK to 16 from 4 * IK now returns early if solution is "good enough" * IK now has nsight markers for profiling --- libraries/animation/CMakeLists.txt | 2 + .../animation/src/AnimInverseKinematics.cpp | 153 +++++++++++------- 2 files changed, 97 insertions(+), 58 deletions(-) diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index dd2fdaaabc..cc2f3858a3 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -1,3 +1,5 @@ set(TARGET_NAME animation) setup_hifi_library(Network Script) link_hifi_libraries(shared model fbx) + +target_nsight() diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 6ab4aa2127..b516e56750 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "ElbowConstraint.h" #include "SwingTwistConstraint.h" @@ -144,9 +145,12 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector MAX_ERROR_TOLERANCE && numLoops < MAX_IK_LOOPS) { ++numLoops; // solve all targets @@ -173,6 +177,19 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector maxError) { + maxError = error; + HACK_MAX_ERROR_JOINT = targets[i].getIndex(); + } + } + } } // finally set the relative rotation of each tip to agree with absolute target rotation @@ -285,8 +302,8 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f; if (angle > MIN_ADJUSTMENT_ANGLE) { // reduce angle by a fraction (for stability) - const float fraction = 0.5f; - angle *= fraction; + const float FRACTION = 0.5f; + angle *= FRACTION; deltaRotation = glm::angleAxis(angle, axis); // The swing will re-orient the tip but there will tend to be be a non-zero delta between the tip's @@ -308,7 +325,7 @@ int AnimInverseKinematics::solveTargetWithCCD(const IKTarget& target, AnimPoseVe glm::vec3 axis = glm::normalize(deltaRotation * leverArm); swingTwistDecomposition(missingRotation, axis, swingPart, twistPart); float dotSign = copysignf(1.0f, twistPart.w); - deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * twistPart, fraction)) * deltaRotation; + deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * twistPart, FRACTION)) * deltaRotation; } } } @@ -369,6 +386,7 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar //virtual const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) { + const float MAX_OVERLAY_DT = 1.0f / 30.0f; // what to clamp delta-time to in AnimInverseKinematics::overlay if (dt > MAX_OVERLAY_DT) { dt = MAX_OVERLAY_DT; @@ -377,6 +395,9 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars if (_relativePoses.size() != underPoses.size()) { loadPoses(underPoses); } else { + + PROFILE_RANGE_EX("ik/relax", 0xffff00ff, 0); + // relax toward underPoses // HACK: this relaxation needs to be constant per-frame rather than per-realtime // in order to prevent IK "flutter" for bad FPS. The bad news is that the good parts @@ -410,9 +431,13 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars } if (!_relativePoses.empty()) { + // build a list of targets from _targetVarVec std::vector targets; - computeTargets(animVars, targets, underPoses); + { + PROFILE_RANGE_EX("ik/computeTargets", 0xffff00ff, 0); + computeTargets(animVars, targets, underPoses); + } if (targets.empty()) { // no IK targets but still need to enforce constraints @@ -425,64 +450,76 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars ++constraintItr; } } else { - // shift hips according to the _hipsOffset from the previous frame - float offsetLength = glm::length(_hipsOffset); - const float MIN_HIPS_OFFSET_LENGTH = 0.03f; - if (offsetLength > MIN_HIPS_OFFSET_LENGTH && _hipsIndex >= 0) { - // but only if offset is long enough - float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength); - if (_hipsParentIndex == -1) { - // the hips are the root so _hipsOffset is in the correct frame - _relativePoses[_hipsIndex].trans = underPoses[_hipsIndex].trans + scaleFactor * _hipsOffset; - } else { - // the hips are NOT the root so we need to transform _hipsOffset into hips local-frame - glm::quat hipsFrameRotation = _relativePoses[_hipsParentIndex].rot; - int index = _skeleton->getParentIndex(_hipsParentIndex); - while (index != -1) { - hipsFrameRotation *= _relativePoses[index].rot; - index = _skeleton->getParentIndex(index); + + { + PROFILE_RANGE_EX("ik/shiftHips", 0xffff00ff, 0); + + // shift hips according to the _hipsOffset from the previous frame + float offsetLength = glm::length(_hipsOffset); + const float MIN_HIPS_OFFSET_LENGTH = 0.03f; + if (offsetLength > MIN_HIPS_OFFSET_LENGTH && _hipsIndex >= 0) { + // but only if offset is long enough + float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength); + if (_hipsParentIndex == -1) { + // the hips are the root so _hipsOffset is in the correct frame + _relativePoses[_hipsIndex].trans = underPoses[_hipsIndex].trans + scaleFactor * _hipsOffset; + } else { + // the hips are NOT the root so we need to transform _hipsOffset into hips local-frame + glm::quat hipsFrameRotation = _relativePoses[_hipsParentIndex].rot; + int index = _skeleton->getParentIndex(_hipsParentIndex); + while (index != -1) { + hipsFrameRotation *= _relativePoses[index].rot; + index = _skeleton->getParentIndex(index); + } + _relativePoses[_hipsIndex].trans = underPoses[_hipsIndex].trans + + glm::inverse(glm::normalize(hipsFrameRotation)) * (scaleFactor * _hipsOffset); } - _relativePoses[_hipsIndex].trans = underPoses[_hipsIndex].trans - + glm::inverse(glm::normalize(hipsFrameRotation)) * (scaleFactor * _hipsOffset); } } - solveWithCyclicCoordinateDescent(targets); - - // measure new _hipsOffset for next frame - // by looking for discrepancies between where a targeted endEffector is - // and where it wants to be (after IK solutions are done) - glm::vec3 newHipsOffset = Vectors::ZERO; - for (auto& target: targets) { - int targetIndex = target.getIndex(); - if (targetIndex == _headIndex && _headIndex != -1) { - // special handling for headTarget - if (target.getType() == IKTarget::Type::RotationOnly) { - // we want to shift the hips to bring the underPose closer - // to where the head happens to be (overpose) - glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans; - glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; - const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; - newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under); - } else if (target.getType() == IKTarget::Type::HmdHead) { - // we want to shift the hips to bring the head to its designated position - glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; - _hipsOffset += target.getTranslation() - actual; - // and ignore all other targets - newHipsOffset = _hipsOffset; - break; - } - } else if (target.getType() == IKTarget::Type::RotationAndPosition) { - glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans; - glm::vec3 targetPosition = target.getTranslation(); - newHipsOffset += targetPosition - actualPosition; - } + { + PROFILE_RANGE_EX("ik/ccd", 0xffff00ff, 0); + solveWithCyclicCoordinateDescent(targets); } - // smooth transitions by relaxing _hipsOffset toward the new value - const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f; - float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f; - _hipsOffset += (newHipsOffset - _hipsOffset) * tau; + { + PROFILE_RANGE_EX("ik/measureHipsOffset", 0xffff00ff, 0); + + // measure new _hipsOffset for next frame + // by looking for discrepancies between where a targeted endEffector is + // and where it wants to be (after IK solutions are done) + glm::vec3 newHipsOffset = Vectors::ZERO; + for (auto& target: targets) { + int targetIndex = target.getIndex(); + if (targetIndex == _headIndex && _headIndex != -1) { + // special handling for headTarget + if (target.getType() == IKTarget::Type::RotationOnly) { + // we want to shift the hips to bring the underPose closer + // to where the head happens to be (overpose) + glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans; + glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; + const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; + newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under); + } else if (target.getType() == IKTarget::Type::HmdHead) { + // we want to shift the hips to bring the head to its designated position + glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; + _hipsOffset += target.getTranslation() - actual; + // and ignore all other targets + newHipsOffset = _hipsOffset; + break; + } + } else if (target.getType() == IKTarget::Type::RotationAndPosition) { + glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans; + glm::vec3 targetPosition = target.getTranslation(); + newHipsOffset += targetPosition - actualPosition; + } + } + + // smooth transitions by relaxing _hipsOffset toward the new value + const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f; + float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f; + _hipsOffset += (newHipsOffset - _hipsOffset) * tau; + } } } return _relativePoses; From 4da712fbdf9daaf609a51de0f72a8709ee32116f Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 22 Aug 2016 10:36:43 -0700 Subject: [PATCH 17/71] Fixing bad include not respecting filename case (for linux) --- libraries/render-utils/src/ssao_debugOcclusion.slf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index 50c66c62e3..6af457db67 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -17,7 +17,7 @@ <$declarePackOcclusionDepth()$> -<@include gpu/color.slh@> +<@include gpu/Color.slh@> <$declareColorWheel()$> struct DebugParams{ From 1e95e067c029cb26b8e6de76163788e1cbd81fc9 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 24 Aug 2016 15:46:55 -0700 Subject: [PATCH 18/71] warning fixes for llvm/gcc --- libraries/animation/src/AnimInverseKinematics.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index b516e56750..7985251002 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -146,7 +146,6 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector maxError) { maxError = error; - HACK_MAX_ERROR_JOINT = targets[i].getIndex(); } } } From e086792eac89af80dd7a48131b1cf1117fb785ca Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Jul 2016 17:09:33 -0700 Subject: [PATCH 19/71] enforce coding standards --- libraries/physics/src/ShapeManager.cpp | 4 ++-- libraries/physics/src/ShapeManager.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 4fa660239c..35046adcfd 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -30,13 +30,13 @@ ShapeManager::~ShapeManager() { btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { if (info.getType() == SHAPE_TYPE_NONE) { - return NULL; + return nullptr; } const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube if (4.0f * glm::length2(info.getHalfExtents()) < MIN_SHAPE_DIAGONAL_SQUARED) { // tiny shapes are not supported // qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal; - return NULL; + return nullptr; } DoubleHashKey key = info.getHash(); diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index 0c411f5f62..cdb2b78789 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -43,11 +43,12 @@ public: private: bool releaseShapeByKey(const DoubleHashKey& key); - struct ShapeReference { + class ShapeReference { + public: int refCount; btCollisionShape* shape; DoubleHashKey key; - ShapeReference() : refCount(0), shape(NULL) {} + ShapeReference() : refCount(0), shape(nullptr) {} }; btHashMap _shapeMap; From af1be8ccd4e6a1a309d9ceb613f037eba3d24657 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Jul 2016 17:26:17 -0700 Subject: [PATCH 20/71] remove whitespace --- libraries/shared/src/DoubleHashKey.cpp | 6 +++--- libraries/shared/src/DoubleHashKey.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/DoubleHashKey.cpp b/libraries/shared/src/DoubleHashKey.cpp index 794604d21b..ded2f073eb 100644 --- a/libraries/shared/src/DoubleHashKey.cpp +++ b/libraries/shared/src/DoubleHashKey.cpp @@ -12,7 +12,7 @@ #include "DoubleHashKey.h" const uint32_t NUM_PRIMES = 64; -const uint32_t PRIMES[] = { +const uint32_t PRIMES[] = { 4194301U, 4194287U, 4194277U, 4194271U, 4194247U, 4194217U, 4194199U, 4194191U, 4194187U, 4194181U, 4194173U, 4194167U, 4194143U, 4194137U, 4194131U, 4194107U, 4194103U, 4194023U, 4194011U, 4194007U, 4193977U, 4193971U, 4193963U, 4193957U, @@ -27,8 +27,8 @@ uint32_t DoubleHashKey::hashFunction(uint32_t value, uint32_t primeIndex) { uint32_t hash = PRIMES[primeIndex % NUM_PRIMES] * (value + 1U); hash += ~(hash << 15); hash ^= (hash >> 10); - hash += (hash << 3); - hash ^= (hash >> 6); + hash += (hash << 3); + hash ^= (hash >> 6); hash += ~(hash << 11); return hash ^ (hash >> 16); } diff --git a/libraries/shared/src/DoubleHashKey.h b/libraries/shared/src/DoubleHashKey.h index 3b08bf7c1a..ca92a7197f 100644 --- a/libraries/shared/src/DoubleHashKey.h +++ b/libraries/shared/src/DoubleHashKey.h @@ -22,9 +22,9 @@ public: DoubleHashKey() : _hash(0), _hash2(0) { } - DoubleHashKey(uint32_t value, uint32_t primeIndex = 0) : - _hash(hashFunction(value, primeIndex)), - _hash2(hashFunction2(value)) { + DoubleHashKey(uint32_t value, uint32_t primeIndex = 0) : + _hash(hashFunction(value, primeIndex)), + _hash2(hashFunction2(value)) { } void clear() { _hash = 0; _hash2 = 0; } From 9f26836b436d5d31428650216be7ae43abce0e41 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Jul 2016 14:03:53 -0700 Subject: [PATCH 21/71] added basic CollisionGeometryCache container --- .../physics/src/CollisionGeometryCache.cpp | 79 +++++++++++++++++++ .../physics/src/CollisionGeometryCache.h | 62 +++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 libraries/physics/src/CollisionGeometryCache.cpp create mode 100644 libraries/physics/src/CollisionGeometryCache.h diff --git a/libraries/physics/src/CollisionGeometryCache.cpp b/libraries/physics/src/CollisionGeometryCache.cpp new file mode 100644 index 0000000000..b474d44c32 --- /dev/null +++ b/libraries/physics/src/CollisionGeometryCache.cpp @@ -0,0 +1,79 @@ +// +// CollisionGeometryCache.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2016.07.13 +// 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 +//#include + +//#include "ShapeFactory.h" +#include "CollisionGeometryCache.h" + +int foo = 0; + +GeometryPointer createGeometryFromShape(CollisionGeometryCache::Key key) { + return std::make_shared(++foo); +} + +CollisionGeometryCache::CollisionGeometryCache() { +} + +CollisionGeometryCache::~CollisionGeometryCache() { + _geometryMap.clear(); + _pendingGarbage.clear(); +} + +GeometryPointer CollisionGeometryCache::getGeometry(CollisionGeometryCache::Key key) { + if (!key) { + return GeometryPointer(); + } + GeometryPointer geometry = 0; + + CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) { + // make geometry and add it to map + geometry = createGeometryFromShape(key); + if (geometry) { + _geometryMap.insert(std::make_pair(key, geometry)); + } + } + return geometry; +} + +bool CollisionGeometryCache::releaseGeometry(CollisionGeometryCache::Key key) { + if (!key) { + return false; + } + CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) { + assert((*itr).second.use_count() != 1); + if ((*itr).second.use_count() == 2) { + // we hold all of the references inside the cache so we'll try to delete later + _pendingGarbage.push_back(key); + } + return true; + } + return false; +} + +void CollisionGeometryCache::collectGarbage() { + int numShapes = _pendingGarbage.size(); + for (int i = 0; i < numShapes; ++i) { + CollisionGeometryCache::Key key = _pendingGarbage[i]; + CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) { + if ((*itr).second.use_count() == 1) { + // we hold the only reference + _geometryMap.erase(itr); + } + } + } + _pendingGarbage.clear(); +} + diff --git a/libraries/physics/src/CollisionGeometryCache.h b/libraries/physics/src/CollisionGeometryCache.h new file mode 100644 index 0000000000..f6a7a6f3e8 --- /dev/null +++ b/libraries/physics/src/CollisionGeometryCache.h @@ -0,0 +1,62 @@ +// +// CollisionGeometryCache.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2016.07.13 +// 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_CollisionGeometryCache +#define hifi_CollisionGeometryCache + +#include +#include +#include +//#include +//#include + +class btCollisionShape; + +// BEGIN TEST HACK +using GeometryPointer = std::shared_ptr; +// END TEST HACK + +namespace std { + template <> + struct hash { + std::size_t operator()(btCollisionShape* key) const { + return (hash()((void*)key)); + } + }; +} + +class CollisionGeometryCache { +public: + using Key = btCollisionShape const *; + + CollisionGeometryCache(); + ~CollisionGeometryCache(); + + /// \return pointer to geometry + GeometryPointer getGeometry(Key key); + + /// \return true if geometry was found and released + bool releaseGeometry(Key key); + + /// delete geometries that have zero references + void collectGarbage(); + + // validation methods + uint32_t getNumGeometries() const { return (uint32_t)_geometryMap.size(); } + bool hasGeometry(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } + +private: + using CollisionGeometryMap = std::unordered_map; + CollisionGeometryMap _geometryMap; + std::vector _pendingGarbage; +}; + +#endif // hifi_CollisionGeometryCache From 8d3f592e68b6c435531c0038dd55351467ab378c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Jul 2016 15:17:50 -0700 Subject: [PATCH 22/71] rename class to be more correct --- ...Cache.cpp => CollisionRenderMeshCache.cpp} | 30 +++++++++---------- ...etryCache.h => CollisionRenderMeshCache.h} | 28 ++++++++--------- 2 files changed, 28 insertions(+), 30 deletions(-) rename libraries/physics/src/{CollisionGeometryCache.cpp => CollisionRenderMeshCache.cpp} (62%) rename libraries/physics/src/{CollisionGeometryCache.h => CollisionRenderMeshCache.h} (60%) diff --git a/libraries/physics/src/CollisionGeometryCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp similarity index 62% rename from libraries/physics/src/CollisionGeometryCache.cpp rename to libraries/physics/src/CollisionRenderMeshCache.cpp index b474d44c32..14d02951a1 100644 --- a/libraries/physics/src/CollisionGeometryCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -1,5 +1,5 @@ // -// CollisionGeometryCache.cpp +// CollisionRenderMeshCache.cpp // libraries/physcis/src // // Created by Andrew Meadows 2016.07.13 @@ -13,32 +13,32 @@ //#include //#include "ShapeFactory.h" -#include "CollisionGeometryCache.h" +#include "CollisionRenderMeshCache.h" int foo = 0; -GeometryPointer createGeometryFromShape(CollisionGeometryCache::Key key) { +MeshPointer createMeshFromShape(CollisionRenderMeshCache::Key key) { return std::make_shared(++foo); } -CollisionGeometryCache::CollisionGeometryCache() { +CollisionRenderMeshCache::CollisionRenderMeshCache() { } -CollisionGeometryCache::~CollisionGeometryCache() { +CollisionRenderMeshCache::~CollisionRenderMeshCache() { _geometryMap.clear(); _pendingGarbage.clear(); } -GeometryPointer CollisionGeometryCache::getGeometry(CollisionGeometryCache::Key key) { +MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::Key key) { if (!key) { - return GeometryPointer(); + return MeshPointer(); } - GeometryPointer geometry = 0; + MeshPointer geometry = 0; - CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + CollisionMeshMap::const_iterator itr = _geometryMap.find(key); if (itr != _geometryMap.end()) { // make geometry and add it to map - geometry = createGeometryFromShape(key); + geometry = createMeshFromShape(key); if (geometry) { _geometryMap.insert(std::make_pair(key, geometry)); } @@ -46,11 +46,11 @@ GeometryPointer CollisionGeometryCache::getGeometry(CollisionGeometryCache::Key return geometry; } -bool CollisionGeometryCache::releaseGeometry(CollisionGeometryCache::Key key) { +bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { if (!key) { return false; } - CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + CollisionMeshMap::const_iterator itr = _geometryMap.find(key); if (itr != _geometryMap.end()) { assert((*itr).second.use_count() != 1); if ((*itr).second.use_count() == 2) { @@ -62,11 +62,11 @@ bool CollisionGeometryCache::releaseGeometry(CollisionGeometryCache::Key key) { return false; } -void CollisionGeometryCache::collectGarbage() { +void CollisionRenderMeshCache::collectGarbage() { int numShapes = _pendingGarbage.size(); for (int i = 0; i < numShapes; ++i) { - CollisionGeometryCache::Key key = _pendingGarbage[i]; - CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + CollisionRenderMeshCache::Key key = _pendingGarbage[i]; + CollisionMeshMap::const_iterator itr = _geometryMap.find(key); if (itr != _geometryMap.end()) { if ((*itr).second.use_count() == 1) { // we hold the only reference diff --git a/libraries/physics/src/CollisionGeometryCache.h b/libraries/physics/src/CollisionRenderMeshCache.h similarity index 60% rename from libraries/physics/src/CollisionGeometryCache.h rename to libraries/physics/src/CollisionRenderMeshCache.h index f6a7a6f3e8..3b39ef80f8 100644 --- a/libraries/physics/src/CollisionGeometryCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -1,5 +1,5 @@ // -// CollisionGeometryCache.h +// CollisionRenderMeshCache.h // libraries/physcis/src // // Created by Andrew Meadows 2016.07.13 @@ -9,19 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_CollisionGeometryCache -#define hifi_CollisionGeometryCache +#ifndef hifi_CollisionRenderMeshCache_h +#define hifi_CollisionRenderMeshCache_h #include #include #include -//#include -//#include class btCollisionShape; // BEGIN TEST HACK -using GeometryPointer = std::shared_ptr; +using MeshPointer = std::shared_ptr; // END TEST HACK namespace std { @@ -33,30 +31,30 @@ namespace std { }; } -class CollisionGeometryCache { +class CollisionRenderMeshCache { public: using Key = btCollisionShape const *; - CollisionGeometryCache(); - ~CollisionGeometryCache(); + CollisionRenderMeshCache(); + ~CollisionRenderMeshCache(); /// \return pointer to geometry - GeometryPointer getGeometry(Key key); + MeshPointer getMesh(Key key); /// \return true if geometry was found and released - bool releaseGeometry(Key key); + bool releaseMesh(Key key); /// delete geometries that have zero references void collectGarbage(); // validation methods uint32_t getNumGeometries() const { return (uint32_t)_geometryMap.size(); } - bool hasGeometry(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } + bool hasMesh(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } private: - using CollisionGeometryMap = std::unordered_map; - CollisionGeometryMap _geometryMap; + using CollisionMeshMap = std::unordered_map; + CollisionMeshMap _geometryMap; std::vector _pendingGarbage; }; -#endif // hifi_CollisionGeometryCache +#endif // hifi_CollisionRenderMeshCache_h From d59c997e64b994b2b32d928d2c8be36e06ceffc7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Jul 2016 16:32:22 -0700 Subject: [PATCH 23/71] remove stubbery, make physics lib depend on model --- libraries/model/src/model/Geometry.h | 2 +- libraries/physics/CMakeLists.txt | 2 +- .../physics/src/CollisionRenderMeshCache.cpp | 47 ++++++++++++------- .../physics/src/CollisionRenderMeshCache.h | 10 ++-- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/libraries/model/src/model/Geometry.h b/libraries/model/src/model/Geometry.h index a3e95c68c0..4256f0be03 100755 --- a/libraries/model/src/model/Geometry.h +++ b/libraries/model/src/model/Geometry.h @@ -130,7 +130,7 @@ protected: void evalVertexStream(); }; -typedef std::shared_ptr< Mesh > MeshPointer; +using MeshPointer = std::shared_ptr< Mesh >; class Geometry { diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index b734c9ac2e..7733c019e0 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME physics) setup_hifi_library() -link_hifi_libraries(shared fbx entities) +link_hifi_libraries(shared fbx entities model) target_bullet() diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 14d02951a1..e563c05e90 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -9,16 +9,31 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "CollisionRenderMeshCache.h" + #include //#include //#include "ShapeFactory.h" -#include "CollisionRenderMeshCache.h" +#include -int foo = 0; -MeshPointer createMeshFromShape(CollisionRenderMeshCache::Key key) { - return std::make_shared(++foo); +model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { + if (!shape) { + return std::make_shared(); + } + int32_t shapeType = shape->getShapeType(); + if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { + const btCompoundShape* compoundShape = static_cast(shape); + int32_t numSubShapes = compoundShape->getNumChildShapes(); + for (int i = 0; i < numSubShapes; ++i) { + const btCollisionShape* childShape = compoundShape->getChildShape(i); + std::cout << "adebug " << i << " " << (void*)(childShape) << std::endl; // adebug + } + } else if (shape->isConvex()) { + std::cout << "adebug " << (void*)(shape)<< std::endl; // adebug + } + return std::make_shared(); } CollisionRenderMeshCache::CollisionRenderMeshCache() { @@ -29,21 +44,19 @@ CollisionRenderMeshCache::~CollisionRenderMeshCache() { _pendingGarbage.clear(); } -MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::Key key) { - if (!key) { - return MeshPointer(); - } - MeshPointer geometry = 0; - - CollisionMeshMap::const_iterator itr = _geometryMap.find(key); - if (itr != _geometryMap.end()) { - // make geometry and add it to map - geometry = createMeshFromShape(key); - if (geometry) { - _geometryMap.insert(std::make_pair(key, geometry)); +model::MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::Key key) { + model::MeshPointer mesh; + if (key) { + CollisionMeshMap::const_iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) { + // make mesh and add it to map + mesh = createMeshFromShape(key); + if (mesh) { + _geometryMap.insert(std::make_pair(key, mesh)); + } } } - return geometry; + return mesh; } bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index 3b39ef80f8..03083048d8 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -16,11 +16,9 @@ #include #include -class btCollisionShape; +#include -// BEGIN TEST HACK -using MeshPointer = std::shared_ptr; -// END TEST HACK +class btCollisionShape; namespace std { template <> @@ -39,7 +37,7 @@ public: ~CollisionRenderMeshCache(); /// \return pointer to geometry - MeshPointer getMesh(Key key); + model::MeshPointer getMesh(Key key); /// \return true if geometry was found and released bool releaseMesh(Key key); @@ -52,7 +50,7 @@ public: bool hasMesh(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } private: - using CollisionMeshMap = std::unordered_map; + using CollisionMeshMap = std::unordered_map; CollisionMeshMap _geometryMap; std::vector _pendingGarbage; }; From d0295f3876204e00bd3677c53e82497636e68e20 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 11:43:23 -0700 Subject: [PATCH 24/71] remove cruft include --- libraries/physics/src/ShapeFactory.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 67072d46d4..8576a9caee 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -10,7 +10,6 @@ // #include -#include #include // for MILLIMETERS_PER_METER From 1e95e489cba359b80dd4566bf579a419b323ba13 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 11:43:33 -0700 Subject: [PATCH 25/71] make mesh around btConvexShape, copy to model::Mesh --- .../physics/src/CollisionRenderMeshCache.cpp | 59 +++++++++++++++++-- .../physics/src/CollisionRenderMeshCache.h | 2 +- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index e563c05e90..c7ce892e52 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -12,28 +12,77 @@ #include "CollisionRenderMeshCache.h" #include -//#include -//#include "ShapeFactory.h" #include +#include +#include // for MAX_HULL_POINTS + +float verts[3 * MAX_HULL_POINTS]; + +void copyHullToMesh(const btShapeHull& hull, model::MeshPointer mesh) { + if ((bool)mesh) { + const uint32_t* hullIndices = hull.getIndexPointer(); + int32_t numIndices = hull.numIndices(); + assert(numIndices <= 6 * MAX_HULL_POINTS); + + { // new part + model::Mesh::Part part; + part._startIndex = mesh->getIndexBuffer().getNumElements(); + part._numIndices = (model::Index)numIndices; + part._baseVertex = mesh->getVertexBuffer().getNumElements(); + + gpu::BufferView::Size numBytes = sizeof(model::Mesh::Part); + const gpu::Byte* data = reinterpret_cast(&part); + mesh->getPartBuffer()._buffer->append(numBytes, data); + } + + { // new vertices + const btVector3* hullVertices = hull.getVertexPointer(); + int32_t numVertices = hull.numVertices(); + assert(numVertices <= MAX_HULL_POINTS); + for (int32_t i = 0; i < numVertices; ++i) { + float* data = verts + 3 * i; + data[0] = hullVertices[i].getX(); + data[1] = hullVertices[i].getY(); + data[2] = hullVertices[i].getZ(); + } + + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numVertices); + const gpu::Byte* data = reinterpret_cast(verts); + mesh->getVertexBuffer()._buffer->append(numBytes, data); + } + + { // new indices + gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(uint32_t) * hull.numIndices()); + const gpu::Byte* data = reinterpret_cast(hullIndices); + mesh->getIndexBuffer()._buffer->append(numBytes, data); + } + } +} model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { if (!shape) { return std::make_shared(); } + model::MeshPointer mesh = std::make_shared(); int32_t shapeType = shape->getShapeType(); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { + const btScalar MARGIN = 0.0f; const btCompoundShape* compoundShape = static_cast(shape); int32_t numSubShapes = compoundShape->getNumChildShapes(); for (int i = 0; i < numSubShapes; ++i) { const btCollisionShape* childShape = compoundShape->getChildShape(i); - std::cout << "adebug " << i << " " << (void*)(childShape) << std::endl; // adebug + if (childShape->isConvex()) { + const btConvexShape* convexShape = static_cast(childShape); + btShapeHull shapeHull(convexShape); + shapeHull.buildHull(MARGIN); + copyHullToMesh(shapeHull, mesh); + } } } else if (shape->isConvex()) { - std::cout << "adebug " << (void*)(shape)<< std::endl; // adebug } - return std::make_shared(); + return mesh; } CollisionRenderMeshCache::CollisionRenderMeshCache() { diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index 03083048d8..05da3750c3 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -31,7 +31,7 @@ namespace std { class CollisionRenderMeshCache { public: - using Key = btCollisionShape const *; + using Key = const btCollisionShape*; CollisionRenderMeshCache(); ~CollisionRenderMeshCache(); From 06d40afeacbaacb13de1e0b2e924481d9282b00f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 13:30:57 -0700 Subject: [PATCH 26/71] don't forget to use the transform of child shapes --- .../physics/src/CollisionRenderMeshCache.cpp | 102 +++++++++--------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index c7ce892e52..6cf2f91ce2 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -20,67 +20,71 @@ float verts[3 * MAX_HULL_POINTS]; -void copyHullToMesh(const btShapeHull& hull, model::MeshPointer mesh) { - if ((bool)mesh) { - const uint32_t* hullIndices = hull.getIndexPointer(); - int32_t numIndices = hull.numIndices(); - assert(numIndices <= 6 * MAX_HULL_POINTS); +void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, model::MeshPointer mesh) { + assert((bool)mesh); + assert(shape); - { // new part - model::Mesh::Part part; - part._startIndex = mesh->getIndexBuffer().getNumElements(); - part._numIndices = (model::Index)numIndices; - part._baseVertex = mesh->getVertexBuffer().getNumElements(); + btShapeHull hull(shape); + const btScalar MARGIN = 0.0f; + hull.buildHull(MARGIN); - gpu::BufferView::Size numBytes = sizeof(model::Mesh::Part); - const gpu::Byte* data = reinterpret_cast(&part); - mesh->getPartBuffer()._buffer->append(numBytes, data); + const uint32_t* hullIndices = hull.getIndexPointer(); + int32_t numIndices = hull.numIndices(); + assert(numIndices <= 6 * MAX_HULL_POINTS); + + { // new part + model::Mesh::Part part; + part._startIndex = mesh->getIndexBuffer().getNumElements(); + part._numIndices = (model::Index)numIndices; + part._baseVertex = mesh->getVertexBuffer().getNumElements(); + + gpu::BufferView::Size numBytes = sizeof(model::Mesh::Part); + const gpu::Byte* data = reinterpret_cast(&part); + mesh->getPartBuffer()._buffer->append(numBytes, data); + } + + { // new vertices + const btVector3* hullVertices = hull.getVertexPointer(); + int32_t numVertices = hull.numVertices(); + assert(numVertices <= MAX_HULL_POINTS); + for (int32_t i = 0; i < numVertices; ++i) { + btVector3 transformedPoint = transform * hullVertices[i]; + memcpy(transformedPoint.m_floats, verts + 3 * i, 3 * sizeof(float)); + //data[0] = transformedPoint.getX(); + //data[1] = transformedPoint.getY(); + //data[2] = transformedPoint.getZ(); } - { // new vertices - const btVector3* hullVertices = hull.getVertexPointer(); - int32_t numVertices = hull.numVertices(); - assert(numVertices <= MAX_HULL_POINTS); - for (int32_t i = 0; i < numVertices; ++i) { - float* data = verts + 3 * i; - data[0] = hullVertices[i].getX(); - data[1] = hullVertices[i].getY(); - data[2] = hullVertices[i].getZ(); - } + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numVertices); + const gpu::Byte* data = reinterpret_cast(verts); + mesh->getVertexBuffer()._buffer->append(numBytes, data); + } - gpu::BufferView::Size numBytes = sizeof(float) * (3 * numVertices); - const gpu::Byte* data = reinterpret_cast(verts); - mesh->getVertexBuffer()._buffer->append(numBytes, data); - } - - { // new indices - gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(uint32_t) * hull.numIndices()); - const gpu::Byte* data = reinterpret_cast(hullIndices); - mesh->getIndexBuffer()._buffer->append(numBytes, data); - } + { // new indices + gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(uint32_t) * hull.numIndices()); + const gpu::Byte* data = reinterpret_cast(hullIndices); + mesh->getIndexBuffer()._buffer->append(numBytes, data); } } model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { - if (!shape) { - return std::make_shared(); - } model::MeshPointer mesh = std::make_shared(); - int32_t shapeType = shape->getShapeType(); - if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { - const btScalar MARGIN = 0.0f; - const btCompoundShape* compoundShape = static_cast(shape); - int32_t numSubShapes = compoundShape->getNumChildShapes(); - for (int i = 0; i < numSubShapes; ++i) { - const btCollisionShape* childShape = compoundShape->getChildShape(i); - if (childShape->isConvex()) { - const btConvexShape* convexShape = static_cast(childShape); - btShapeHull shapeHull(convexShape); - shapeHull.buildHull(MARGIN); - copyHullToMesh(shapeHull, mesh); + if (shape) { + int32_t shapeType = shape->getShapeType(); + if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { + const btCompoundShape* compoundShape = static_cast(shape); + int32_t numSubShapes = compoundShape->getNumChildShapes(); + for (int i = 0; i < numSubShapes; ++i) { + const btCollisionShape* childShape = compoundShape->getChildShape(i); + if (childShape->isConvex()) { + const btConvexShape* convexShape = static_cast(childShape); + copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, mesh); + } } + } else if (shape->isConvex()) { + const btConvexShape* convexShape = static_cast(shape); + copyShapeToMesh(btTransform(), convexShape, mesh); } - } else if (shape->isConvex()) { } return mesh; } From b79af55e16f56f9b5e20a3e73e7fb6e4d87b5379 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 13:35:03 -0700 Subject: [PATCH 27/71] fix ref accounting for garbage collection --- libraries/physics/src/CollisionRenderMeshCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 6cf2f91ce2..3714d9d464 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -119,7 +119,7 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { CollisionMeshMap::const_iterator itr = _geometryMap.find(key); if (itr != _geometryMap.end()) { assert((*itr).second.use_count() != 1); - if ((*itr).second.use_count() == 2) { + if ((*itr).second.use_count() == 1) { // we hold all of the references inside the cache so we'll try to delete later _pendingGarbage.push_back(key); } From e473edff4adc4b1458b6cab964ddd7c09d3af467 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 14:04:26 -0700 Subject: [PATCH 28/71] fix shapeManagerTests --- tests/physics/src/ShapeManagerTests.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index c8805132fa..24d4a5ab35 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "ShapeManagerTests.h" @@ -197,6 +198,7 @@ void ShapeManagerTests::addCompoundShape() { ShapeInfo::PointCollection pointCollection; int numHulls = 5; glm::vec3 offsetNormal(1.0f, 0.0f, 0.0f); + Extents extents; for (int i = 0; i < numHulls; ++i) { glm::vec3 offset = (float)(i - numHulls/2) * offsetNormal; ShapeInfo::PointList pointList; @@ -204,13 +206,16 @@ void ShapeManagerTests::addCompoundShape() { for (int j = 0; j < numHullPoints; ++j) { glm::vec3 point = radius * tetrahedron[j] + offset; pointList.push_back(point); + extents.addPoint(point); } pointCollection.push_back(pointList); } // create the ShapeInfo ShapeInfo info; - info.setPointCollection(hulls); + glm::vec3 halfExtents = 0.5f * (extents.maximum - extents.minimum); + info.setParams(SHAPE_TYPE_COMPOUND, halfExtents); + info.setPointCollection(pointCollection); // create the shape ShapeManager shapeManager; From c1216cbcaf98fedfda93be43576fcb24a5cf87f8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 15:05:47 -0700 Subject: [PATCH 29/71] stubbery for CollisionRenderMeshCacheTests --- tests/physics/CMakeLists.txt | 2 +- .../src/CollisionRenderMeshCacheTests.cpp | 41 +++++++++++++++++++ .../src/CollisionRenderMeshCacheTests.h | 24 +++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/physics/src/CollisionRenderMeshCacheTests.cpp create mode 100644 tests/physics/src/CollisionRenderMeshCacheTests.h diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index cc3df5ea8e..755886ebbf 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -2,7 +2,7 @@ # Declare dependencies macro (SETUP_TESTCASE_DEPENDENCIES) target_bullet() - link_hifi_libraries(shared physics) + link_hifi_libraries(shared physics gpu model) package_libraries_for_deployment() endmacro () diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.cpp b/tests/physics/src/CollisionRenderMeshCacheTests.cpp new file mode 100644 index 0000000000..58b45f6400 --- /dev/null +++ b/tests/physics/src/CollisionRenderMeshCacheTests.cpp @@ -0,0 +1,41 @@ +// +// CollisionRenderMeshCacheTests.cpp +// tests/physics/src +// +// Created by Andrew Meadows on 2014.10.30 +// 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 +// + +#include +#include +#include + +#include "CollisionRenderMeshCacheTests.h" + +QTEST_MAIN(CollisionRenderMeshCacheTests) + + +void CollisionRenderMeshCacheTests::test001() { + CollisionRenderMeshCache cache; + + // create a compound shape + int32_t numSubShapes = 3; + + + // get the mesh + + // get the mesh again + + // forget the mesh once + + // collect garbage + + // forget the mesh a second time + + // collect garbage + +} + diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.h b/tests/physics/src/CollisionRenderMeshCacheTests.h new file mode 100644 index 0000000000..d927bf8cab --- /dev/null +++ b/tests/physics/src/CollisionRenderMeshCacheTests.h @@ -0,0 +1,24 @@ +// +// CollisionRenderMeshCacheTests.h +// tests/physics/src +// +// Created by Andrew Meadows on 2014.10.30 +// 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 +// + +#ifndef hifi_CollisionRenderMeshCacheTests_h +#define hifi_CollisionRenderMeshCacheTests_h + +#include + +class CollisionRenderMeshCacheTests : public QObject { + Q_OBJECT + +private slots: + void test001(); +}; + +#endif // hifi_CollisionRenderMeshCacheTests_h From 0d84e6ece5c8d99ef0f8572991edcb389e9df31b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 18:03:25 -0700 Subject: [PATCH 30/71] first CollisionRenderMeshCache unit test --- .../src/CollisionRenderMeshCacheTests.cpp | 242 +++++++++++++++++- tests/physics/src/MeshUtil.cpp | 45 ++++ tests/physics/src/MeshUtil.h | 61 +++++ 3 files changed, 343 insertions(+), 5 deletions(-) create mode 100644 tests/physics/src/MeshUtil.cpp create mode 100644 tests/physics/src/MeshUtil.h diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.cpp b/tests/physics/src/CollisionRenderMeshCacheTests.cpp index 58b45f6400..b4ed49b605 100644 --- a/tests/physics/src/CollisionRenderMeshCacheTests.cpp +++ b/tests/physics/src/CollisionRenderMeshCacheTests.cpp @@ -9,20 +9,123 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include - #include "CollisionRenderMeshCacheTests.h" +#include +#include + +#include +#include + +#include +#include // for MAX_HULL_POINTS + +#include "MeshUtil.cpp" + + QTEST_MAIN(CollisionRenderMeshCacheTests) +btVector3 directions[] = { + btVector3(1.0f, 1.0f, 1.0f), + btVector3(1.0f, 1.0f, -1.0f), + btVector3(1.0f, -1.0f, 1.0f), + btVector3(1.0f, -1.0f, -1.0f), + btVector3(-1.0f, 1.0f, 1.0f), + btVector3(-1.0f, 1.0f, -1.0f), + btVector3(-1.0f, -1.0f, 1.0f), + btVector3(-1.0f, -1.0f, -1.0f) +}; +void computeCubePoints(const btVector3& center, btScalar radius, uint32_t numPoints, + btAlignedObjectArray& points) { + points.reserve(points.size() + 8); + for (uint32_t i = 0; i < 8; ++i) { + points.push_back(center + radius * directions[i]); + } +} + +float randomFloat() { + return (float)rand() / (float)RAND_MAX; +} + +btBoxShape* createRandomCubeShape() { + //const btScalar MAX_RADIUS = 3.0; + //const btScalar MIN_RADIUS = 0.5; + //btScalar radius = randomFloat() * (MAX_RADIUS - MIN_RADIUS) + MIN_RADIUS; + btScalar radius = 0.5f; + btVector3 halfExtents(radius, radius, radius); + + btBoxShape* shape = new btBoxShape(halfExtents); + return shape; +} + +void CollisionRenderMeshCacheTests::test001() { + // make a box shape + btBoxShape* box = createRandomCubeShape(); + + // wrap it with a ShapeHull + btShapeHull hull(box); + //const btScalar MARGIN = 0.01f; + const btScalar MARGIN = 0.00f; + hull.buildHull(MARGIN); + + // verify the vertex count is capped + uint32_t numVertices = (uint32_t)hull.numVertices(); + QVERIFY(numVertices <= MAX_HULL_POINTS); + + // verify the mesh is inside the radius + btVector3 halfExtents = box->getHalfExtentsWithMargin(); + btScalar acceptableRadiusError = 0.01f; + btScalar maxRadius = halfExtents.length() + acceptableRadiusError; + const btVector3* meshVertices = hull.getVertexPointer(); + for (uint32_t i = 0; i < numVertices; ++i) { + btVector3 vertex = meshVertices[i]; + QVERIFY(vertex.length() <= maxRadius); + } + + // verify the index count is capped + uint32_t numIndices = (uint32_t)hull.numIndices(); + QVERIFY(numIndices < 6 * MAX_HULL_POINTS); + + // verify the index count is a multiple of 3 + QVERIFY(numIndices % 3 == 0); + + // verify the mesh is closed + const uint32_t* meshIndices = hull.getIndexPointer(); + bool isClosed = MeshUtil::isClosedManifold(meshIndices, numIndices); + QVERIFY(isClosed); + + // verify the triangle normals are outward using right-hand-rule + const uint32_t INDICES_PER_TRIANGLE = 3; + for (uint32_t i = 0; i < numIndices; i += INDICES_PER_TRIANGLE) { + btVector3 A = meshVertices[meshIndices[i]]; + btVector3 B = meshVertices[meshIndices[i+1]]; + btVector3 C = meshVertices[meshIndices[i+2]]; + + btVector3 face = (B - A).cross(C - B); + btVector3 center = (A + B + C) / 3.0f; + QVERIFY(face.dot(center) > 0.0f); + } + + delete box; +} + +#ifdef FOO void CollisionRenderMeshCacheTests::test001() { CollisionRenderMeshCache cache; // create a compound shape - int32_t numSubShapes = 3; + btScalar radiusA = 1.0f; + btScalar radiusB = 1.5f; + btScalar radiusC = 2.75f; + + btVector3 centerA(radiusA, 0.0f, 0.0f); + btVector3 centerB(0.0f, radiusB, 0.0f); + btVector3 centerC(0.0f, 0.0f, radiusC); + + btCompoundShape compoundShape = new btCompoundShape(); + for (uint32_t i = 0; i < numSubShapes; ++i) { + } // get the mesh @@ -38,4 +141,133 @@ void CollisionRenderMeshCacheTests::test001() { // collect garbage } +#endif // FOO +/* +void CollisionRenderMeshCacheTests::addManyShapes() { + ShapeManager shapeManager; + + QVector shapes; + + int numSizes = 100; + float startSize = 1.0f; + float endSize = 99.0f; + float deltaSize = (endSize - startSize) / (float)numSizes; + ShapeInfo info; + for (int i = 0; i < numSizes; ++i) { + // make a sphere + float s = startSize + (float)i * deltaSize; + glm::vec3 scale(s, 1.23f + s, s - 0.573f); + info.setBox(0.5f * scale); + btCollisionShape* shape = shapeManager.getShape(info); + shapes.push_back(shape); + QCOMPARE(shape != nullptr, true); + + // make a box + float radius = 0.5f * s; + info.setSphere(radius); + shape = shapeManager.getShape(info); + shapes.push_back(shape); + QCOMPARE(shape != nullptr, true); + } + + // verify shape count + int numShapes = shapeManager.getNumShapes(); + QCOMPARE(numShapes, 2 * numSizes); + + // release each shape by pointer + for (int i = 0; i < numShapes; ++i) { + btCollisionShape* shape = shapes[i]; + bool success = shapeManager.releaseShape(shape); + QCOMPARE(success, true); + } + + // verify zero references + for (int i = 0; i < numShapes; ++i) { + btCollisionShape* shape = shapes[i]; + int numReferences = shapeManager.getNumReferences(shape); + QCOMPARE(numReferences, 0); + } +} + +void CollisionRenderMeshCacheTests::addBoxShape() { + ShapeInfo info; + glm::vec3 halfExtents(1.23f, 4.56f, 7.89f); + info.setBox(halfExtents); + + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + + ShapeInfo otherInfo = info; + btCollisionShape* otherShape = shapeManager.getShape(otherInfo); + QCOMPARE(shape, otherShape); +} + +void CollisionRenderMeshCacheTests::addSphereShape() { + ShapeInfo info; + float radius = 1.23f; + info.setSphere(radius); + + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + + ShapeInfo otherInfo = info; + btCollisionShape* otherShape = shapeManager.getShape(otherInfo); + QCOMPARE(shape, otherShape); +} + +void CollisionRenderMeshCacheTests::addCompoundShape() { + // initialize some points for generating tetrahedral convex hulls + QVector tetrahedron; + tetrahedron.push_back(glm::vec3(1.0f, 1.0f, 1.0f)); + tetrahedron.push_back(glm::vec3(1.0f, -1.0f, -1.0f)); + tetrahedron.push_back(glm::vec3(-1.0f, 1.0f, -1.0f)); + tetrahedron.push_back(glm::vec3(-1.0f, -1.0f, 1.0f)); + int numHullPoints = tetrahedron.size(); + + // compute the points of the hulls + ShapeInfo::PointCollection pointCollection; + int numHulls = 5; + glm::vec3 offsetNormal(1.0f, 0.0f, 0.0f); + for (int i = 0; i < numHulls; ++i) { + glm::vec3 offset = (float)(i - numHulls/2) * offsetNormal; + ShapeInfo::PointList pointList; + float radius = (float)(i + 1); + for (int j = 0; j < numHullPoints; ++j) { + glm::vec3 point = radius * tetrahedron[j] + offset; + pointList.push_back(point); + } + pointCollection.push_back(pointList); + } + + // create the ShapeInfo + ShapeInfo info; + info.setPointCollection(hulls); + + // create the shape + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + QVERIFY(shape != nullptr); + + // verify the shape is correct type + QCOMPARE(shape->getShapeType(), (int)COMPOUND_SHAPE_PROXYTYPE); + + // verify the shape has correct number of children + btCompoundShape* compoundShape = static_cast(shape); + QCOMPARE(compoundShape->getNumChildShapes(), numHulls); + + // verify manager has only one shape + QCOMPARE(shapeManager.getNumShapes(), 1); + QCOMPARE(shapeManager.getNumReferences(info), 1); + + // release the shape + shapeManager.releaseShape(shape); + QCOMPARE(shapeManager.getNumShapes(), 1); + QCOMPARE(shapeManager.getNumReferences(info), 0); + + // collect garbage + shapeManager.collectGarbage(); + QCOMPARE(shapeManager.getNumShapes(), 0); + QCOMPARE(shapeManager.getNumReferences(info), 0); +} +*/ diff --git a/tests/physics/src/MeshUtil.cpp b/tests/physics/src/MeshUtil.cpp new file mode 100644 index 0000000000..d3eb815948 --- /dev/null +++ b/tests/physics/src/MeshUtil.cpp @@ -0,0 +1,45 @@ +// +// MeshUtil.cpp +// tests/physics/src +// +// Created by Andrew Meadows 2016.07.14 +// 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 "MeshUtil.h" + +#include + +// returns false if any edge has only one adjacent triangle +bool MeshUtil::isClosedManifold(const uint32_t* meshIndices, uint32_t numIndices) { + using EdgeList = std::unordered_map; + EdgeList edges; + + // count the triangles for each edge + const uint32_t TRIANGLE_STRIDE = 3; + for (uint32_t i = 0; i < numIndices; i += TRIANGLE_STRIDE) { + MeshUtil::TriangleEdge edge; + // the triangles indices are stored in sequential order + for (uint32_t j = 0; j < 3; ++j) { + edge.setIndices(meshIndices[i + j], meshIndices[i + ((j + 1) % 3)]); + + EdgeList::iterator edgeEntry = edges.find(edge); + if (edgeEntry == edges.end()) { + edges.insert(std::pair(edge, 1)); + } else { + edgeEntry->second += 1; + } + } + } + // scan for outside edge + for (auto& edgeEntry : edges) { + if (edgeEntry.second == 1) { + return false; + } + } + return true; +} + diff --git a/tests/physics/src/MeshUtil.h b/tests/physics/src/MeshUtil.h new file mode 100644 index 0000000000..82d33d631b --- /dev/null +++ b/tests/physics/src/MeshUtil.h @@ -0,0 +1,61 @@ +// +// MeshUtil.h +// tests/physics/src +// +// Created by Andrew Meadows 2016.07.14 +// 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_MeshUtil_h +#define hifi_MeshUtil_h + +#include + +namespace MeshUtil { + +class TriangleEdge { +public: + TriangleEdge() {} + TriangleEdge(uint32_t A, uint32_t B) { + setIndices(A, B); + } + void setIndices(uint32_t A, uint32_t B) { + if (A < B) { + _indexA = A; + _indexB = B; + } else { + _indexA = B; + _indexB = A; + } + } + bool operator==(const TriangleEdge& other) const { + return _indexA == other._indexA && _indexB == other._indexB; + } + + uint32_t getIndexA() const { return _indexA; } + uint32_t getIndexB() const { return _indexB; } +private: + uint32_t _indexA { (uint32_t)(-1) }; + uint32_t _indexB { (uint32_t)(-1) }; +}; + +bool isClosedManifold(const uint32_t* meshIndices, uint32_t numIndices); + +} // MeshUtil namespace + +namespace std { + template <> + struct hash { + std::size_t operator()(const MeshUtil::TriangleEdge& edge) const { + // use Cantor's pairing function to generate a hash of ZxZ --> Z + uint32_t ab = edge.getIndexA() + edge.getIndexB(); + return hash()((ab * (ab + 1)) / 2 + edge.getIndexB()); + } + }; +} + + +#endif // hifi_MeshUtil_h From cbacb02010d139add3bf88ce99cd51aa581191e7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jul 2016 11:28:11 -0700 Subject: [PATCH 31/71] more unit tests for CollisionRenderMeshCache --- .../physics/src/CollisionRenderMeshCache.cpp | 41 ++- .../physics/src/CollisionRenderMeshCache.h | 10 +- .../src/CollisionRenderMeshCacheTests.cpp | 342 +++++++++--------- .../src/CollisionRenderMeshCacheTests.h | 4 +- 4 files changed, 208 insertions(+), 189 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 3714d9d464..14386c6f48 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -68,9 +68,19 @@ void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, m } model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { - model::MeshPointer mesh = std::make_shared(); - if (shape) { - int32_t shapeType = shape->getShapeType(); + model::MeshPointer mesh; + if (!shape) { + return mesh; + } + + int32_t shapeType = shape->getShapeType(); + if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE || shape->isConvex()) { + // create the mesh and allocate buffers for it + mesh = std::make_shared(); + mesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getVertexBuffer()._element)); + mesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getIndexBuffer()._element)); + mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getPartBuffer()._element)); + if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); int32_t numSubShapes = compoundShape->getNumChildShapes(); @@ -81,7 +91,8 @@ model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, mesh); } } - } else if (shape->isConvex()) { + } else { + // shape is convex const btConvexShape* convexShape = static_cast(shape); copyShapeToMesh(btTransform(), convexShape, mesh); } @@ -93,20 +104,22 @@ CollisionRenderMeshCache::CollisionRenderMeshCache() { } CollisionRenderMeshCache::~CollisionRenderMeshCache() { - _geometryMap.clear(); + _meshMap.clear(); _pendingGarbage.clear(); } model::MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::Key key) { model::MeshPointer mesh; if (key) { - CollisionMeshMap::const_iterator itr = _geometryMap.find(key); - if (itr != _geometryMap.end()) { + CollisionMeshMap::const_iterator itr = _meshMap.find(key); + if (itr == _meshMap.end()) { // make mesh and add it to map mesh = createMeshFromShape(key); if (mesh) { - _geometryMap.insert(std::make_pair(key, mesh)); + _meshMap.insert(std::make_pair(key, mesh)); } + } else { + mesh = itr->second; } } return mesh; @@ -116,12 +129,12 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { if (!key) { return false; } - CollisionMeshMap::const_iterator itr = _geometryMap.find(key); - if (itr != _geometryMap.end()) { + CollisionMeshMap::const_iterator itr = _meshMap.find(key); + if (itr != _meshMap.end()) { assert((*itr).second.use_count() != 1); + _pendingGarbage.push_back(key); if ((*itr).second.use_count() == 1) { // we hold all of the references inside the cache so we'll try to delete later - _pendingGarbage.push_back(key); } return true; } @@ -132,11 +145,11 @@ void CollisionRenderMeshCache::collectGarbage() { int numShapes = _pendingGarbage.size(); for (int i = 0; i < numShapes; ++i) { CollisionRenderMeshCache::Key key = _pendingGarbage[i]; - CollisionMeshMap::const_iterator itr = _geometryMap.find(key); - if (itr != _geometryMap.end()) { + CollisionMeshMap::const_iterator itr = _meshMap.find(key); + if (itr != _meshMap.end()) { if ((*itr).second.use_count() == 1) { // we hold the only reference - _geometryMap.erase(itr); + _meshMap.erase(itr); } } } diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index 05da3750c3..ad3c86562b 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -23,8 +23,8 @@ class btCollisionShape; namespace std { template <> struct hash { - std::size_t operator()(btCollisionShape* key) const { - return (hash()((void*)key)); + std::size_t operator()(btCollisionShape* shape) const { + return (hash()((void*)shape)); } }; } @@ -46,12 +46,12 @@ public: void collectGarbage(); // validation methods - uint32_t getNumGeometries() const { return (uint32_t)_geometryMap.size(); } - bool hasMesh(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } + uint32_t getNumMeshes() const { return (uint32_t)_meshMap.size(); } + bool hasMesh(Key key) const { return _meshMap.find(key) == _meshMap.end(); } private: using CollisionMeshMap = std::unordered_map; - CollisionMeshMap _geometryMap; + CollisionMeshMap _meshMap; std::vector _pendingGarbage; }; diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.cpp b/tests/physics/src/CollisionRenderMeshCacheTests.cpp index b4ed49b605..085c9a2fe3 100644 --- a/tests/physics/src/CollisionRenderMeshCacheTests.cpp +++ b/tests/physics/src/CollisionRenderMeshCacheTests.cpp @@ -25,48 +25,53 @@ QTEST_MAIN(CollisionRenderMeshCacheTests) -btVector3 directions[] = { - btVector3(1.0f, 1.0f, 1.0f), - btVector3(1.0f, 1.0f, -1.0f), - btVector3(1.0f, -1.0f, 1.0f), - btVector3(1.0f, -1.0f, -1.0f), - btVector3(-1.0f, 1.0f, 1.0f), - btVector3(-1.0f, 1.0f, -1.0f), - btVector3(-1.0f, -1.0f, 1.0f), - btVector3(-1.0f, -1.0f, -1.0f) +const float INV_SQRT_THREE = 0.577350269f; + +const uint32_t numSphereDirections = 6 + 8; +btVector3 sphereDirections[] = { + btVector3(1.0f, 0.0f, 0.0f), + btVector3(-1.0f, 0.0f, 0.0f), + btVector3(0.0f, 1.0f, 0.0f), + btVector3(0.0f, -1.0f, 0.0f), + btVector3(0.0f, 0.0f, 1.0f), + btVector3(0.0f, 0.0f, -1.0f), + btVector3(INV_SQRT_THREE, INV_SQRT_THREE, INV_SQRT_THREE), + btVector3(INV_SQRT_THREE, INV_SQRT_THREE, -INV_SQRT_THREE), + btVector3(INV_SQRT_THREE, -INV_SQRT_THREE, INV_SQRT_THREE), + btVector3(INV_SQRT_THREE, -INV_SQRT_THREE, -INV_SQRT_THREE), + btVector3(-INV_SQRT_THREE, INV_SQRT_THREE, INV_SQRT_THREE), + btVector3(-INV_SQRT_THREE, INV_SQRT_THREE, -INV_SQRT_THREE), + btVector3(-INV_SQRT_THREE, -INV_SQRT_THREE, INV_SQRT_THREE), + btVector3(-INV_SQRT_THREE, -INV_SQRT_THREE, -INV_SQRT_THREE) }; -void computeCubePoints(const btVector3& center, btScalar radius, uint32_t numPoints, - btAlignedObjectArray& points) { - points.reserve(points.size() + 8); - for (uint32_t i = 0; i < 8; ++i) { - points.push_back(center + radius * directions[i]); - } -} - float randomFloat() { - return (float)rand() / (float)RAND_MAX; + return 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f; } -btBoxShape* createRandomCubeShape() { - //const btScalar MAX_RADIUS = 3.0; - //const btScalar MIN_RADIUS = 0.5; - //btScalar radius = randomFloat() * (MAX_RADIUS - MIN_RADIUS) + MIN_RADIUS; - btScalar radius = 0.5f; - btVector3 halfExtents(radius, radius, radius); - - btBoxShape* shape = new btBoxShape(halfExtents); +btBoxShape* createBoxShape(const btVector3& extent) { + btBoxShape* shape = new btBoxShape(0.5f * extent); return shape; } -void CollisionRenderMeshCacheTests::test001() { +btConvexHullShape* createConvexHull(float radius) { + btConvexHullShape* hull = new btConvexHullShape(); + for (uint32_t i = 0; i < numSphereDirections; ++i) { + btVector3 point = radius * sphereDirections[i]; + hull->addPoint(point, false); + } + hull->recalcLocalAabb(); + return hull; +} + +void CollisionRenderMeshCacheTests::testShapeHullManifold() { // make a box shape - btBoxShape* box = createRandomCubeShape(); + btVector3 extent(1.0f, 2.0f, 3.0f); + btBoxShape* box = createBoxShape(extent); // wrap it with a ShapeHull btShapeHull hull(box); - //const btScalar MARGIN = 0.01f; - const btScalar MARGIN = 0.00f; + const float MARGIN = 0.0f; hull.buildHull(MARGIN); // verify the vertex count is capped @@ -75,8 +80,8 @@ void CollisionRenderMeshCacheTests::test001() { // verify the mesh is inside the radius btVector3 halfExtents = box->getHalfExtentsWithMargin(); - btScalar acceptableRadiusError = 0.01f; - btScalar maxRadius = halfExtents.length() + acceptableRadiusError; + float ACCEPTABLE_EXTENTS_ERROR = 0.01f; + float maxRadius = halfExtents.length() + ACCEPTABLE_EXTENTS_ERROR; const btVector3* meshVertices = hull.getVertexPointer(); for (uint32_t i = 0; i < numVertices; ++i) { btVector3 vertex = meshVertices[i]; @@ -107,167 +112,166 @@ void CollisionRenderMeshCacheTests::test001() { QVERIFY(face.dot(center) > 0.0f); } + // delete unmanaged memory delete box; } -#ifdef FOO -void CollisionRenderMeshCacheTests::test001() { - CollisionRenderMeshCache cache; +void CollisionRenderMeshCacheTests::testCompoundShape() { + uint32_t numSubShapes = 3; - // create a compound shape - btScalar radiusA = 1.0f; - btScalar radiusB = 1.5f; - btScalar radiusC = 2.75f; + btVector3 centers[] = { + btVector3(1.0f, 0.0f, 0.0f), + btVector3(0.0f, -2.0f, 0.0f), + btVector3(0.0f, 0.0f, 3.0f), + }; - btVector3 centerA(radiusA, 0.0f, 0.0f); - btVector3 centerB(0.0f, radiusB, 0.0f); - btVector3 centerC(0.0f, 0.0f, radiusC); + float radii[] = { 3.0f, 2.0f, 1.0f }; - btCompoundShape compoundShape = new btCompoundShape(); + btCompoundShape* compoundShape = new btCompoundShape(); for (uint32_t i = 0; i < numSubShapes; ++i) { + btTransform transform; + transform.setOrigin(centers[i]); + btConvexHullShape* hull = createConvexHull(radii[i]); + compoundShape->addChildShape(transform, hull); } + // create the cache + CollisionRenderMeshCache cache; + QVERIFY(cache.getNumMeshes() == 0); - // get the mesh + // get the mesh once + model::MeshPointer mesh = cache.getMesh(compoundShape); + QVERIFY((bool)mesh); + QVERIFY(cache.getNumMeshes() == 1); // get the mesh again + model::MeshPointer mesh2 = cache.getMesh(compoundShape); + QVERIFY(mesh2 == mesh); + QVERIFY(cache.getNumMeshes() == 1); // forget the mesh once + cache.releaseMesh(compoundShape); + mesh.reset(); + QVERIFY(cache.getNumMeshes() == 1); - // collect garbage + // collect garbage (should still cache mesh) + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 1); - // forget the mesh a second time + // forget the mesh a second time (should still cache mesh) + cache.releaseMesh(compoundShape); + mesh2.reset(); + QVERIFY(cache.getNumMeshes() == 1); - // collect garbage + // collect garbage (should no longer cache mesh) + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 0); + // delete unmanaged memory + for (int i = 0; i < compoundShape->getNumChildShapes(); ++i) { + delete compoundShape->getChildShape(i); + } + delete compoundShape; } -#endif // FOO -/* -void CollisionRenderMeshCacheTests::addManyShapes() { - ShapeManager shapeManager; - - QVector shapes; - - int numSizes = 100; - float startSize = 1.0f; - float endSize = 99.0f; - float deltaSize = (endSize - startSize) / (float)numSizes; - ShapeInfo info; - for (int i = 0; i < numSizes; ++i) { - // make a sphere - float s = startSize + (float)i * deltaSize; - glm::vec3 scale(s, 1.23f + s, s - 0.573f); - info.setBox(0.5f * scale); - btCollisionShape* shape = shapeManager.getShape(info); - shapes.push_back(shape); - QCOMPARE(shape != nullptr, true); - - // make a box - float radius = 0.5f * s; - info.setSphere(radius); - shape = shapeManager.getShape(info); - shapes.push_back(shape); - QCOMPARE(shape != nullptr, true); +void CollisionRenderMeshCacheTests::testMultipleShapes() { + // shapeA is compound of hulls + uint32_t numSubShapes = 3; + btVector3 centers[] = { + btVector3(1.0f, 0.0f, 0.0f), + btVector3(0.0f, -2.0f, 0.0f), + btVector3(0.0f, 0.0f, 3.0f), + }; + float radii[] = { 3.0f, 2.0f, 1.0f }; + btCompoundShape* shapeA = new btCompoundShape(); + for (uint32_t i = 0; i < numSubShapes; ++i) { + btTransform transform; + transform.setOrigin(centers[i]); + btConvexHullShape* hull = createConvexHull(radii[i]); + shapeA->addChildShape(transform, hull); } - // verify shape count - int numShapes = shapeManager.getNumShapes(); - QCOMPARE(numShapes, 2 * numSizes); - - // release each shape by pointer - for (int i = 0; i < numShapes; ++i) { - btCollisionShape* shape = shapes[i]; - bool success = shapeManager.releaseShape(shape); - QCOMPARE(success, true); + // shapeB is compound of boxes + btVector3 extents[] = { + btVector3(1.0f, 2.0f, 3.0f), + btVector3(2.0f, 3.0f, 1.0f), + btVector3(3.0f, 1.0f, 2.0f), + }; + btCompoundShape* shapeB = new btCompoundShape(); + for (uint32_t i = 0; i < numSubShapes; ++i) { + btTransform transform; + transform.setOrigin(centers[i]); + btBoxShape* box = createBoxShape(extents[i]); + shapeB->addChildShape(transform, box); } - // verify zero references - for (int i = 0; i < numShapes; ++i) { - btCollisionShape* shape = shapes[i]; - int numReferences = shapeManager.getNumReferences(shape); - QCOMPARE(numReferences, 0); + // shapeC is just a box + btVector3 extentC(7.0f, 3.0f, 5.0f); + btBoxShape* shapeC = createBoxShape(extentC); + + // create the cache + CollisionRenderMeshCache cache; + QVERIFY(cache.getNumMeshes() == 0); + + // get the meshes + model::MeshPointer meshA = cache.getMesh(shapeA); + model::MeshPointer meshB = cache.getMesh(shapeB); + model::MeshPointer meshC = cache.getMesh(shapeC); + QVERIFY((bool)meshA); + QVERIFY((bool)meshB); + QVERIFY((bool)meshC); + QVERIFY(cache.getNumMeshes() == 3); + + // get the meshes again + model::MeshPointer meshA2 = cache.getMesh(shapeA); + model::MeshPointer meshB2 = cache.getMesh(shapeB); + model::MeshPointer meshC2 = cache.getMesh(shapeC); + QVERIFY(meshA == meshA2); + QVERIFY(meshB == meshB2); + QVERIFY(meshC == meshC2); + QVERIFY(cache.getNumMeshes() == 3); + + // forget the meshes once + cache.releaseMesh(shapeA); + cache.releaseMesh(shapeB); + cache.releaseMesh(shapeC); + meshA2.reset(); + meshB2.reset(); + meshC2.reset(); + QVERIFY(cache.getNumMeshes() == 3); + + // collect garbage (should still cache mesh) + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 3); + + // forget again, one mesh at a time... + // shapeA... + cache.releaseMesh(shapeA); + meshA.reset(); + QVERIFY(cache.getNumMeshes() == 3); + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 2); + // shapeB... + cache.releaseMesh(shapeB); + meshB.reset(); + QVERIFY(cache.getNumMeshes() == 2); + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 1); + // shapeC... + cache.releaseMesh(shapeC); + meshC.reset(); + QVERIFY(cache.getNumMeshes() == 1); + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 0); + + // delete unmanaged memory + for (int i = 0; i < shapeA->getNumChildShapes(); ++i) { + delete shapeA->getChildShape(i); } -} - -void CollisionRenderMeshCacheTests::addBoxShape() { - ShapeInfo info; - glm::vec3 halfExtents(1.23f, 4.56f, 7.89f); - info.setBox(halfExtents); - - ShapeManager shapeManager; - btCollisionShape* shape = shapeManager.getShape(info); - - ShapeInfo otherInfo = info; - btCollisionShape* otherShape = shapeManager.getShape(otherInfo); - QCOMPARE(shape, otherShape); -} - -void CollisionRenderMeshCacheTests::addSphereShape() { - ShapeInfo info; - float radius = 1.23f; - info.setSphere(radius); - - ShapeManager shapeManager; - btCollisionShape* shape = shapeManager.getShape(info); - - ShapeInfo otherInfo = info; - btCollisionShape* otherShape = shapeManager.getShape(otherInfo); - QCOMPARE(shape, otherShape); -} - -void CollisionRenderMeshCacheTests::addCompoundShape() { - // initialize some points for generating tetrahedral convex hulls - QVector tetrahedron; - tetrahedron.push_back(glm::vec3(1.0f, 1.0f, 1.0f)); - tetrahedron.push_back(glm::vec3(1.0f, -1.0f, -1.0f)); - tetrahedron.push_back(glm::vec3(-1.0f, 1.0f, -1.0f)); - tetrahedron.push_back(glm::vec3(-1.0f, -1.0f, 1.0f)); - int numHullPoints = tetrahedron.size(); - - // compute the points of the hulls - ShapeInfo::PointCollection pointCollection; - int numHulls = 5; - glm::vec3 offsetNormal(1.0f, 0.0f, 0.0f); - for (int i = 0; i < numHulls; ++i) { - glm::vec3 offset = (float)(i - numHulls/2) * offsetNormal; - ShapeInfo::PointList pointList; - float radius = (float)(i + 1); - for (int j = 0; j < numHullPoints; ++j) { - glm::vec3 point = radius * tetrahedron[j] + offset; - pointList.push_back(point); - } - pointCollection.push_back(pointList); + delete shapeA; + for (int i = 0; i < shapeB->getNumChildShapes(); ++i) { + delete shapeB->getChildShape(i); } - - // create the ShapeInfo - ShapeInfo info; - info.setPointCollection(hulls); - - // create the shape - ShapeManager shapeManager; - btCollisionShape* shape = shapeManager.getShape(info); - QVERIFY(shape != nullptr); - - // verify the shape is correct type - QCOMPARE(shape->getShapeType(), (int)COMPOUND_SHAPE_PROXYTYPE); - - // verify the shape has correct number of children - btCompoundShape* compoundShape = static_cast(shape); - QCOMPARE(compoundShape->getNumChildShapes(), numHulls); - - // verify manager has only one shape - QCOMPARE(shapeManager.getNumShapes(), 1); - QCOMPARE(shapeManager.getNumReferences(info), 1); - - // release the shape - shapeManager.releaseShape(shape); - QCOMPARE(shapeManager.getNumShapes(), 1); - QCOMPARE(shapeManager.getNumReferences(info), 0); - - // collect garbage - shapeManager.collectGarbage(); - QCOMPARE(shapeManager.getNumShapes(), 0); - QCOMPARE(shapeManager.getNumReferences(info), 0); + delete shapeB; + delete shapeC; } -*/ diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.h b/tests/physics/src/CollisionRenderMeshCacheTests.h index d927bf8cab..640314a2a0 100644 --- a/tests/physics/src/CollisionRenderMeshCacheTests.h +++ b/tests/physics/src/CollisionRenderMeshCacheTests.h @@ -18,7 +18,9 @@ class CollisionRenderMeshCacheTests : public QObject { Q_OBJECT private slots: - void test001(); + void testShapeHullManifold(); + void testCompoundShape(); + void testMultipleShapes(); }; #endif // hifi_CollisionRenderMeshCacheTests_h From 1ed76ae44215b3fa1ad85ee2bb554e02d6195ff0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jul 2016 14:11:40 -0700 Subject: [PATCH 32/71] added virtual ObjectMotionState::setShape() --- libraries/physics/src/ObjectMotionState.cpp | 37 +++++++++++---------- libraries/physics/src/ObjectMotionState.h | 3 +- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index f915121718..64b1e9c527 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -64,16 +64,17 @@ ShapeManager* ObjectMotionState::getShapeManager() { ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : _motionType(MOTION_TYPE_STATIC), - _shape(shape), + _shape(nullptr), _body(nullptr), _mass(0.0f), _lastKinematicStep(worldSimulationStep) { + setShape(shape); } ObjectMotionState::~ObjectMotionState() { assert(!_body); - releaseShape(); + setShape(nullptr); _type = MOTIONSTATE_TYPE_INVALID; } @@ -114,13 +115,6 @@ glm::vec3 ObjectMotionState::getBodyAngularVelocity() const { return bulletToGLM(_body->getAngularVelocity()); } -void ObjectMotionState::releaseShape() { - if (_shape) { - shapeManager->releaseShape(_shape); - _shape = nullptr; - } -} - void ObjectMotionState::setMotionType(PhysicsMotionType motionType) { _motionType = motionType; } @@ -165,6 +159,15 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } +void ObjectMotionState::setShape(btCollisionShape* shape) { + if (_shape != shape) { + if (_shape) { + getShapeManager()->releaseShape(_shape); + } + _shape = shape; + } +} + void ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); @@ -265,15 +268,15 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* return true; } } - getShapeManager()->releaseShape(_shape); - if (_shape != newShape) { - _shape = newShape; - _body->setCollisionShape(_shape); - - updateCCDConfiguration(); - } else { - // huh... the shape didn't actually change, so we clear the DIRTY_SHAPE flag + if (_shape == newShape) { + // the shape didn't actually change, so we clear the DIRTY_SHAPE flag flags &= ~Simulation::DIRTY_SHAPE; + // and clear the reference we just created + getShapeManager()->releaseShape(_shape); + } else { + _body->setCollisionShape(newShape); + setShape(newShape); + updateCCDConfiguration(); } } if (flags & EASY_DIRTY_PHYSICS_FLAGS) { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index c0c10c6f71..ca9b80a3b3 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -113,8 +113,6 @@ public: btCollisionShape* getShape() const { return _shape; } btRigidBody* getRigidBody() const { return _body; } - void releaseShape(); - virtual bool isMoving() const = 0; // These pure virtual methods must be implemented for each MotionState type @@ -157,6 +155,7 @@ protected: void updateCCDConfiguration(); void setRigidBody(btRigidBody* body); + virtual void setShape(btCollisionShape* shape); MotionStateType _type = MOTIONSTATE_TYPE_INVALID; // type of MotionState PhysicsMotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC From b2dfa49a6ffe600bb3af355259c0ea2ab6eccb10 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jul 2016 15:24:57 -0700 Subject: [PATCH 33/71] stubbery for alerting entity that shape changed --- .../entities-renderer/src/RenderableModelEntityItem.h | 2 ++ libraries/entities/src/EntityItem.h | 7 +++++++ libraries/physics/src/EntityMotionState.cpp | 8 ++++++++ libraries/physics/src/EntityMotionState.h | 7 ++++--- libraries/physics/src/ObjectMotionState.h | 2 +- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index a3d9e4db98..22469cf0ef 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -61,6 +61,8 @@ public: virtual bool isReadyToComputeShape() override; virtual void computeShapeInfo(ShapeInfo& info) override; + void setCollisionShape(const btCollisionShape* shape) override {} + virtual bool contains(const glm::vec3& point) const override; virtual bool shouldBePhysical() const override; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 9fe83b53cb..1ad1d938a7 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -44,6 +44,7 @@ class EntityTreeElementExtraEncodeData; class EntityActionInterface; class EntityItemProperties; class EntityTree; +class btCollisionShape; typedef std::shared_ptr EntityTreePointer; typedef std::shared_ptr EntityActionPointer; typedef std::shared_ptr EntityTreeElementPointer; @@ -324,6 +325,12 @@ public: /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } + virtual void setCollisionShape(const btCollisionShape* shape) {} + + // these are only needed because the names don't match + virtual const glm::quat getRotation() const { return getOrientation(); } + virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } + // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags virtual void updateRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 08d207fa72..4b6823dd8a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -271,6 +271,14 @@ btCollisionShape* EntityMotionState::computeNewShape() { return getShapeManager()->getShape(shapeInfo); } +void EntityMotionState::setShape(btCollisionShape* shape) { + bool shapeChanged = (_shape != shape); + ObjectMotionState::setShape(shape); + if (shapeChanged) { + _entity->setCollisionShape(_shape); + } +} + bool EntityMotionState::isCandidateForOwnership() const { assert(_body); assert(_entity); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 8f1532bf8f..2c39da9164 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -88,9 +88,10 @@ protected: bool entityTreeIsLocked() const; #endif - virtual bool isReadyToComputeShape() const override; - virtual btCollisionShape* computeNewShape() override; - virtual void setMotionType(PhysicsMotionType motionType); + bool isReadyToComputeShape() const override; + btCollisionShape* computeNewShape() override; + void setShape(btCollisionShape* shape) override; + void setMotionType(PhysicsMotionType motionType) override; // In the glorious future (when entities lib depends on physics lib) the EntityMotionState will be // properly "owned" by the EntityItem and will be deleted by it in the dtor. In pursuit of that diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index ca9b80a3b3..ccaef17fd1 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -151,7 +151,7 @@ public: protected: virtual bool isReadyToComputeShape() const = 0; virtual btCollisionShape* computeNewShape() = 0; - void setMotionType(PhysicsMotionType motionType); + virtual void setMotionType(PhysicsMotionType motionType); void updateCCDConfiguration(); void setRigidBody(btRigidBody* body); From 499150bbed02387aa881002116ea137440bc960a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jul 2016 15:56:52 -0700 Subject: [PATCH 34/71] finish hook alert for new entity collision shape --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++++ libraries/entities-renderer/src/RenderableModelEntityItem.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ac447417aa..2ff5e236fc 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -917,6 +917,10 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } +void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) { + // TODO: generate collision mesh and update _model +} + bool RenderableModelEntityItem::contains(const glm::vec3& point) const { if (EntityItem::contains(point) && _model && _model->isCollisionLoaded()) { return _model->getCollisionFBXGeometry().convexHullContains(worldToEntity(point)); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 22469cf0ef..412cb6f296 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -61,7 +61,7 @@ public: virtual bool isReadyToComputeShape() override; virtual void computeShapeInfo(ShapeInfo& info) override; - void setCollisionShape(const btCollisionShape* shape) override {} + void setCollisionShape(const btCollisionShape* shape) override; virtual bool contains(const glm::vec3& point) const override; From 726928c14c061d958b96362d73e88efda367ccdf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Jul 2016 09:38:54 -0700 Subject: [PATCH 35/71] creae collision Geometry from mesh --- libraries/entities-renderer/CMakeLists.txt | 2 +- .../src/RenderableModelEntityItem.cpp | 17 ++++++++++++- .../src/RenderableModelEntityItem.h | 1 + .../src/model-networking/ModelCache.h | 7 +++--- .../physics/src/CollisionRenderMeshCache.cpp | 24 ++++++++++++------- .../physics/src/CollisionRenderMeshCache.h | 4 +++- libraries/render-utils/src/Model.cpp | 22 +++++++++++++++++ libraries/render-utils/src/Model.h | 3 ++- 8 files changed, 64 insertions(+), 16 deletions(-) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 0063f4a701..9218b94fe1 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME entities-renderer) AUTOSCRIBE_SHADER_LIB(gpu model procedural render render-utils) setup_hifi_library(Widgets Network Script) -link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils) +link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils physics) target_bullet() diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 2ff5e236fc..cdf94017ff 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -917,8 +918,22 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } +static CollisionRenderMeshCache collisionMeshCache; + void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) { - // TODO: generate collision mesh and update _model + const void* key = static_cast(shape); + if (_collisionMeshKey != key) { + if (_collisionMeshKey) { + // releasing the shape is not strictly necessary, but + // we do it as hint to the cache's garbage collection system + collisionMeshCache.releaseMesh(_collisionMeshKey); + } + _collisionMeshKey = key; + model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); + if (_model) { + _model->setCollisionMesh(mesh); + } + } } bool RenderableModelEntityItem::contains(const glm::vec3& point) const { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 412cb6f296..1f44260f65 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -119,6 +119,7 @@ private: bool getAnimationFrame(); bool _needsJointSimulation { false }; + const void* _collisionMeshKey { nullptr }; }; #endif // hifi_RenderableModelEntityItem_h diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 5c1aafdd45..fa93d3c899 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -111,13 +111,12 @@ public: QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); } -signals: - void finished(bool success); - -private: void startWatching(); void stopWatching(); +signals: + void finished(bool success); + private slots: void resourceFinished(bool success); void resourceRefreshed(); diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 14386c6f48..22f0b986ab 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -67,12 +67,16 @@ void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, m } } -model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { +model::MeshPointer createMeshFromShape(const void* pointer) { model::MeshPointer mesh; - if (!shape) { + if (!pointer) { return mesh; } + // pointer must actually be a const btCollisionShape*, but it only + // needs to be valid here when its render mesh is created. + const btCollisionShape* shape = static_cast(pointer); + int32_t shapeType = shape->getShapeType(); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE || shape->isConvex()) { // create the mesh and allocate buffers for it @@ -84,7 +88,7 @@ model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); int32_t numSubShapes = compoundShape->getNumChildShapes(); - for (int i = 0; i < numSubShapes; ++i) { + for (int32_t i = 0; i < numSubShapes; ++i) { const btCollisionShape* childShape = compoundShape->getChildShape(i); if (childShape->isConvex()) { const btConvexShape* convexShape = static_cast(childShape); @@ -122,6 +126,10 @@ model::MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::K mesh = itr->second; } } + const uint32_t MAX_NUM_PENDING_GARBAGE = 20; + if (_pendingGarbage.size() > MAX_NUM_PENDING_GARBAGE) { + collectGarbage(); + } return mesh; } @@ -131,19 +139,19 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { } CollisionMeshMap::const_iterator itr = _meshMap.find(key); if (itr != _meshMap.end()) { + // we hold at least one reference, and the outer scope also holds at least one + // so we assert that the reference count is not 1 assert((*itr).second.use_count() != 1); + _pendingGarbage.push_back(key); - if ((*itr).second.use_count() == 1) { - // we hold all of the references inside the cache so we'll try to delete later - } return true; } return false; } void CollisionRenderMeshCache::collectGarbage() { - int numShapes = _pendingGarbage.size(); - for (int i = 0; i < numShapes; ++i) { + uint32_t numShapes = _pendingGarbage.size(); + for (int32_t i = 0; i < numShapes; ++i) { CollisionRenderMeshCache::Key key = _pendingGarbage[i]; CollisionMeshMap::const_iterator itr = _meshMap.find(key); if (itr != _meshMap.end()) { diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index ad3c86562b..0c789f3da9 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -18,6 +18,7 @@ #include +/* class btCollisionShape; namespace std { @@ -28,10 +29,11 @@ namespace std { } }; } +*/ class CollisionRenderMeshCache { public: - using Key = const btCollisionShape*; + using Key = const void*; // must actually be a const btCollisionShape* CollisionRenderMeshCache(); ~CollisionRenderMeshCache(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index a6e1bb53f4..35e40403cf 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1336,6 +1336,28 @@ bool Model::initWhenReady(render::ScenePointer scene) { return false; } +class CollisionRenderGeometry : public Geometry { +public: + CollisionRenderGeometry(model::MeshPointer mesh) { + _fbxGeometry = std::make_shared(); + std::shared_ptr meshes = std::make_shared(); + meshes->push_back(mesh); + _meshes = meshes; + _meshParts = std::shared_ptr(); + } +}; + +void Model::setCollisionMesh(model::MeshPointer mesh) { + _collisionWatcher.stopWatching(); + _collisionGeometry = std::make_shared(mesh); + + if (_showCollisionHull) { + // TODO: need to trigger: + // (a) reconstruction of RenderItems + // (b) and reinsertion into scene if we are showing collision geometry + } +} + ModelBlender::ModelBlender() : _pendingBlenders(0) { } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 15c8e0326a..d6580b8413 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -249,6 +249,7 @@ public slots: signals: void setURLFinished(bool success); void setCollisionModelURLFinished(bool success); + void setCollisionMesh(model::MeshPointer mesh); protected: @@ -282,7 +283,7 @@ protected: bool getJointPosition(int jointIndex, glm::vec3& position) const; Geometry::Pointer _renderGeometry; // only ever set by its watcher - Geometry::Pointer _collisionGeometry; // only ever set by its watcher + Geometry::Pointer _collisionGeometry; GeometryResourceWatcher _renderWatcher; GeometryResourceWatcher _collisionWatcher; From d8fa0d1dd1f0c4b5ff6ef817941f1b7e241b8965 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Jul 2016 09:43:59 -0700 Subject: [PATCH 36/71] segregateMeshGroups() --> createRenderItems() --- libraries/render-utils/src/Model.cpp | 8 ++++---- libraries/render-utils/src/Model.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 35e40403cf..afb5cbcfb6 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -575,7 +575,7 @@ void Model::renderSetup(RenderArgs* args) { } if (!_meshGroupsKnown && isLoaded()) { - segregateMeshGroups(); + createRenderItems(); } } @@ -600,7 +600,7 @@ bool Model::addToScene(std::shared_ptr scene, bool showCollisionHull) { if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) { _showCollisionHull = showCollisionHull; - segregateMeshGroups(); + createRenderItems(); } bool somethingAdded = false; @@ -1236,7 +1236,7 @@ AABox Model::getRenderableMeshBound() const { } } -void Model::segregateMeshGroups() { +void Model::createRenderItems() { Geometry::Pointer geometry; bool showingCollisionHull = false; if (_showCollisionHull && _collisionGeometry) { @@ -1303,7 +1303,7 @@ void Model::segregateMeshGroups() { bool Model::initWhenReady(render::ScenePointer scene) { if (isActive() && isRenderable() && !_meshGroupsKnown && isLoaded()) { - segregateMeshGroups(); + createRenderItems(); render::PendingChanges pendingChanges; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index d6580b8413..55a55a3d27 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -377,7 +377,7 @@ protected: void recalculateMeshBoxes(bool pickAgainstTriangles = false); - void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes + void createRenderItems(); // used to calculate our list of translucent vs opaque meshes static model::MaterialPointer _collisionHullMaterial; bool _meshGroupsKnown; From 6b0ae654ba3aa143960cad2cbcfbd57caf6a54a0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 21 Jul 2016 17:11:04 -0700 Subject: [PATCH 37/71] cleanup logic around creating RenderItems --- .../src/RenderableModelEntityItem.cpp | 47 ++-- .../src/RenderableModelEntityItem.h | 2 - .../src/RenderableZoneEntityItem.cpp | 2 +- .../render-utils/src/MeshPartPayload.cpp | 5 +- libraries/render-utils/src/Model.cpp | 236 +++++++++++------- libraries/render-utils/src/Model.h | 24 +- 6 files changed, 195 insertions(+), 121 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index cdf94017ff..6e5d1c7959 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -177,6 +177,24 @@ void RenderableModelEntityItem::doInitialModelSimulation() { _needsInitialSimulation = false; } +// TODO: we need a solution for changes to the postion/rotation/etc of a model... +// this current code path only addresses that in this setup case... not the changing/moving case +bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) { + if (!_model && renderArgs) { + // TODO: this getModel() appears to be about 3% of model render time. We should optimize + PerformanceTimer perfTimer("getModel"); + EntityTreeRenderer* renderer = static_cast(renderArgs->_renderer); + getModel(renderer); + } + if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoaded()) { + // make sure to simulate so everything gets set up correctly for rendering + doInitialModelSimulation(); + _model->renderSetup(renderArgs); + } + bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(); + return ready; +} + class RenderableModelEntityItemMeta { public: RenderableModelEntityItemMeta(EntityItemPointer entity) : entity(entity){ } @@ -215,21 +233,21 @@ namespace render { bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { _myMetaItem = scene->allocateID(); - + auto renderData = std::make_shared(self); auto renderPayload = std::make_shared(renderData); - + pendingChanges.resetItem(_myMetaItem, renderPayload); - + if (_model) { render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); - - // note: we don't care if the model fails to add items, we always added our meta item and therefore we return - // true so that the system knows our meta item is in the scene! - _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); + + // note: we don't mind if the model fails to add, we'll retry (in render()) until it succeeds + _model->addToScene(scene, pendingChanges, statusGetters); } + // we've successfully added _myMetaItem so we always return true return true; } @@ -416,19 +434,20 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // Remap textures for the next frame to avoid flicker remapTextures(); - // check to see if when we added our models to the scene they were ready, if they were not ready, then - // fix them up in the scene - bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0 - && getShapeType() == SHAPE_TYPE_COMPOUND; - if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) { - _showCollisionHull = shouldShowCollisionHull; + // update whether the model should be showing collision mesh + // (this may flag for fixupInScene) + bool shouldShowCollisionHull = getShapeType() != SHAPE_TYPE_STATIC_MESH && + (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; + _model->setShowCollisionMesh(shouldShowCollisionHull); + + if (_model->needsFixupInScene()) { render::PendingChanges pendingChanges; _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); - _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); + _model->addToScene(scene, pendingChanges, statusGetters); scene->enqueuePendingChanges(pendingChanges); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 1f44260f65..16cd9c8bc5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -114,8 +114,6 @@ private: render::ItemID _myMetaItem{ render::Item::INVALID_ITEM_ID }; - bool _showCollisionHull = false; - bool getAnimationFrame(); bool _needsJointSimulation { false }; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index ef47a777c2..9aa52f5ad3 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -122,7 +122,7 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); - _model->addToScene(scene, pendingChanges, false); + _model->addToScene(scene, pendingChanges); scene->enqueuePendingChanges(pendingChanges); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 1c8c89d6db..8913a62d9d 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -414,8 +414,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown // to false to rebuild out mesh groups. if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) { - _model->_meshGroupsKnown = false; // regenerate these lists next time around. - _model->_readyWhenAdded = false; // in case any of our users are using scenes + _model->_needsFixupInScene = true; // trigger remove/add cycle _model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid return ShapeKey::Builder::invalid(); } @@ -533,7 +532,7 @@ void ModelMeshPartPayload::startFade() { void ModelMeshPartPayload::render(RenderArgs* args) const { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - if (!_model->_readyWhenAdded || !_model->_isVisible) { + if (!_model->addedToScene() || !_model->isVisible()) { return; // bail asap } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index afb5cbcfb6..075e550dd5 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -100,7 +100,6 @@ Model::Model(RigPointer rig, QObject* parent) : _calculatedMeshPartBoxesValid(false), _calculatedMeshBoxesValid(false), _calculatedMeshTrianglesValid(false), - _meshGroupsKnown(false), _isWireframe(false), _rig(rig) { @@ -121,19 +120,33 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; +void Model::setShowCollisionMesh(bool value) { + if (_showCollisionHull != value) { + _showCollisionHull = value; + _needsFixupInScene = true; + } +} + bool Model::needsFixupInScene() const { - if (readyToAddToScene()) { - if (_needsUpdateTextures && _renderGeometry->areTexturesLoaded()) { - _needsUpdateTextures = false; + if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { + if (_showCollisionHull && _collisionGeometry) { return true; } - if (!_readyWhenAdded) { + if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { + if (_needsUpdateTextures) { + if (!_renderGeometry->areTexturesLoaded()) { + return false; + } + _needsUpdateTextures = false; + } return true; } } return false; } +// TODO?: should we combine translation and rotation into single method to avoid double-work? +// (figure out where we call these) void Model::setTranslation(const glm::vec3& translation) { _translation = translation; updateRenderItems(); @@ -172,6 +185,9 @@ void Model::setOffset(const glm::vec3& offset) { } void Model::updateRenderItems() { + if (!_addedToScene) { + return; + } _needsUpdateClusterMatrices = true; _renderItemsNeedUpdate = false; @@ -574,8 +590,8 @@ void Model::renderSetup(RenderArgs* args) { } } - if (!_meshGroupsKnown && isLoaded()) { - createRenderItems(); + if (!_addedToScene && isLoaded()) { + createRenderItemSet(); } } @@ -596,43 +612,46 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, - render::Item::Status::Getters& statusGetters, - bool showCollisionHull) { - if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) { - _showCollisionHull = showCollisionHull; - createRenderItems(); + render::Item::Status::Getters& statusGetters) { + bool readyToRender = (_showCollisionHull && _collisionGeometry) || isLoaded(); + if (!_addedToScene && readyToRender) { + createRenderItemSet(); } bool somethingAdded = false; - - if (_modelMeshRenderItems.empty()) { - foreach (auto renderItem, _modelMeshRenderItemsSet) { - auto item = scene->allocateID(); - auto renderPayload = std::make_shared(renderItem); - if (statusGetters.size()) { - renderPayload->addStatusGetters(statusGetters); + if (_showCollisionHull && _collisionGeometry) { + if (_collisionRenderItems.empty()) { + foreach (auto renderItem, _collisionRenderItemsSet) { + auto item = scene->allocateID(); + auto renderPayload = std::make_shared(renderItem); + if (statusGetters.size()) { + renderPayload->addStatusGetters(statusGetters); + } + pendingChanges.resetItem(item, renderPayload); + _collisionRenderItems.insert(item, renderPayload); } - pendingChanges.resetItem(item, renderPayload); - _modelMeshRenderItems.insert(item, renderPayload); - somethingAdded = true; + somethingAdded = !_collisionRenderItems.empty(); } - } - if (_collisionRenderItems.empty()) { - foreach (auto renderItem, _collisionRenderItemsSet) { - auto item = scene->allocateID(); - auto renderPayload = std::make_shared(renderItem); - if (statusGetters.size()) { - renderPayload->addStatusGetters(statusGetters); + } else { + if (_modelMeshRenderItems.empty()) { + foreach (auto renderItem, _modelMeshRenderItemsSet) { + auto item = scene->allocateID(); + auto renderPayload = std::make_shared(renderItem); + if (statusGetters.size()) { + renderPayload->addStatusGetters(statusGetters); + } + pendingChanges.resetItem(item, renderPayload); + _modelMeshRenderItems.insert(item, renderPayload); } - pendingChanges.resetItem(item, renderPayload); - _collisionRenderItems.insert(item, renderPayload); - somethingAdded = true; + somethingAdded = !_modelMeshRenderItems.empty(); } } - updateRenderItems(); - - _readyWhenAdded = readyToAddToScene(); + if (somethingAdded) { + _addedToScene = true; + updateRenderItems(); + _needsFixupInScene = false; + } return somethingAdded; } @@ -643,13 +662,13 @@ void Model::removeFromScene(std::shared_ptr scene, render::Pendin } _modelMeshRenderItems.clear(); _modelMeshRenderItemsSet.clear(); + foreach (auto item, _collisionRenderItems.keys()) { pendingChanges.removeItem(item); } _collisionRenderItems.clear(); _collisionRenderItemsSet.clear(); - _meshGroupsKnown = false; - _readyWhenAdded = false; + _addedToScene = false; } void Model::renderDebugMeshBoxes(gpu::Batch& batch) { @@ -804,6 +823,7 @@ int Model::getLastFreeJointIndex(int jointIndex) const { void Model::setTextures(const QVariantMap& textures) { if (isLoaded()) { _needsUpdateTextures = true; + _needsFixupInScene = true; _renderGeometry->setTextures(textures); } } @@ -825,8 +845,8 @@ void Model::setURL(const QUrl& url) { _needsReload = true; _needsUpdateTextures = true; - _meshGroupsKnown = false; _visualGeometryRequestFailed = false; + _needsFixupInScene = true; invalidCalculatedMeshBoxes(); deleteGeometry(); @@ -1236,21 +1256,21 @@ AABox Model::getRenderableMeshBound() const { } } -void Model::createRenderItems() { - Geometry::Pointer geometry; - bool showingCollisionHull = false; +void Model::createRenderItemSet() { if (_showCollisionHull && _collisionGeometry) { - if (isCollisionLoaded()) { - geometry = _collisionGeometry; - showingCollisionHull = true; - } else { - return; + if (_collisionRenderItemsSet.empty()) { + createCollisionRenderItemSet(); } } else { - assert(isLoaded()); - geometry = _renderGeometry; + if (_modelMeshRenderItemsSet.empty()) { + createVisibleRenderItemSet(); + } } - const auto& meshes = geometry->getMeshes(); +}; + +void Model::createVisibleRenderItemSet() { + assert(isLoaded()); + const auto& meshes = _renderGeometry->getMeshes(); // all of our mesh vectors must match in size if ((int)meshes.size() != _meshStates.size()) { @@ -1259,13 +1279,9 @@ void Model::createRenderItems() { } // We should not have any existing renderItems if we enter this section of code - Q_ASSERT(_modelMeshRenderItems.isEmpty()); Q_ASSERT(_modelMeshRenderItemsSet.isEmpty()); - Q_ASSERT(_collisionRenderItems.isEmpty()); - Q_ASSERT(_collisionRenderItemsSet.isEmpty()); _modelMeshRenderItemsSet.clear(); - _collisionRenderItemsSet.clear(); Transform transform; transform.setTranslation(_translation); @@ -1280,60 +1296,98 @@ void Model::createRenderItems() { uint32_t numMeshes = (uint32_t)meshes.size(); for (uint32_t i = 0; i < numMeshes; i++) { const auto& mesh = meshes.at(i); - if (mesh) { + if (!mesh) { + continue; + } - // Create the render payloads - int numParts = (int)mesh->getNumParts(); - for (int partIndex = 0; partIndex < numParts; partIndex++) { - if (showingCollisionHull) { - if (_collisionHullMaterials.empty()) { - initCollisionHullMaterials(); - } - _collisionRenderItemsSet << std::make_shared(mesh, partIndex, _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS], transform, offset); - } else { - _modelMeshRenderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); - } - - shapeID++; - } + // Create the render payloads + int numParts = (int)mesh->getNumParts(); + for (int partIndex = 0; partIndex < numParts; partIndex++) { + _modelMeshRenderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); + shapeID++; } } - _meshGroupsKnown = true; +} + +void Model::createCollisionRenderItemSet() { + assert((bool)_collisionGeometry); + if (_collisionHullMaterials.empty()) { + initCollisionHullMaterials(); + } + + const auto& meshes = _collisionGeometry->getMeshes(); + + // We should not have any existing renderItems if we enter this section of code + Q_ASSERT(_collisionRenderItemsSet.isEmpty()); + + Transform transform; + transform.setTranslation(_translation); + transform.setRotation(_rotation); + + Transform offset; + offset.setScale(_scale); + offset.postTranslate(_offset); + + // Run through all of the meshes, and place them into their segregated, but unsorted buckets + uint32_t numMeshes = (uint32_t)meshes.size(); + for (uint32_t i = 0; i < numMeshes; i++) { + const auto& mesh = meshes.at(i); + if (!mesh) { + continue; + } + + // Create the render payloads + int numParts = (int)mesh->getNumParts(); + for (int partIndex = 0; partIndex < numParts; partIndex++) { + model::MaterialPointer& material = _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; + _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material, transform, offset); + } + } +} + +bool Model::isRenderable() const { + return !_meshStates.isEmpty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } bool Model::initWhenReady(render::ScenePointer scene) { - if (isActive() && isRenderable() && !_meshGroupsKnown && isLoaded()) { - createRenderItems(); + // NOTE: this only called by SkeletonModel + if (_addedToScene || !isRenderable()) { + return false; + } - render::PendingChanges pendingChanges; + createRenderItemSet(); - Transform transform; - transform.setTranslation(_translation); - transform.setRotation(_rotation); + render::PendingChanges pendingChanges; - Transform offset; - offset.setScale(_scale); - offset.postTranslate(_offset); - - foreach (auto renderItem, _modelMeshRenderItemsSet) { - auto item = scene->allocateID(); - auto renderPayload = std::make_shared(renderItem); - _modelMeshRenderItems.insert(item, renderPayload); - pendingChanges.resetItem(item, renderPayload); - } + bool addedPendingChanges = false; + if (_showCollisionHull && _collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); _collisionRenderItems.insert(item, renderPayload); pendingChanges.resetItem(item, renderPayload); } - scene->enqueuePendingChanges(pendingChanges); - updateRenderItems(); - - _readyWhenAdded = true; - return true; + addedPendingChanges = !_collisionRenderItems.empty(); + } else { + foreach (auto renderItem, _modelMeshRenderItemsSet) { + auto item = scene->allocateID(); + auto renderPayload = std::make_shared(renderItem); + _modelMeshRenderItems.insert(item, renderPayload); + pendingChanges.resetItem(item, renderPayload); + } + addedPendingChanges = !_modelMeshRenderItems.empty(); } - return false; + _addedToScene = addedPendingChanges; + if (addedPendingChanges) { + scene->enqueuePendingChanges(pendingChanges); + // NOTE: updateRender items enqueues identical pendingChanges (using a lambda) + // so it looks like we're doing double work here, but I don't want to remove the call + // for fear there is some sideeffect we'll miss. -- Andrew 2016.07.21 + // TODO: figure out if we really need this call to updateRenderItems() or not. + updateRenderItems(); + } + + return true; } class CollisionRenderGeometry : public Geometry { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 55a55a3d27..b30b0b0d76 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -81,24 +81,25 @@ public: // new Scene/Engine rendering support void setVisibleInScene(bool newValue, std::shared_ptr scene); bool needsFixupInScene() const; + + void setShowCollisionMesh(bool value); + bool readyToAddToScene(RenderArgs* renderArgs = nullptr) const { return !_needsReload && isRenderable() && isActive(); } bool needsReload() const { return _needsReload; } bool initWhenReady(render::ScenePointer scene); bool addToScene(std::shared_ptr scene, - render::PendingChanges& pendingChanges, - bool showCollisionHull = false) { + render::PendingChanges& pendingChanges) { auto getters = render::Item::Status::Getters(0); - return addToScene(scene, pendingChanges, getters, showCollisionHull); + return addToScene(scene, pendingChanges, getters); } bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, - render::Item::Status::Getters& statusGetters, - bool showCollisionHull = false); + render::Item::Status::Getters& statusGetters); void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); void renderSetup(RenderArgs* args); - bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _renderGeometry->getMeshes().empty()); } + bool isRenderable() const; bool isVisible() const { return _isVisible; } @@ -239,6 +240,7 @@ public: // returns 'true' if needs fullUpdate after geometry change bool updateGeometry(); + void setCollisionMesh(model::MeshPointer mesh); void setLoadingPriority(float priority) { _loadingPriority = priority; } @@ -249,9 +251,9 @@ public slots: signals: void setURLFinished(bool success); void setCollisionModelURLFinished(bool success); - void setCollisionMesh(model::MeshPointer mesh); protected: + bool addedToScene() const { return _addedToScene; } void setPupilDilation(float dilation) { _pupilDilation = dilation; } float getPupilDilation() const { return _pupilDilation; } @@ -377,10 +379,11 @@ protected: void recalculateMeshBoxes(bool pickAgainstTriangles = false); - void createRenderItems(); // used to calculate our list of translucent vs opaque meshes + void createRenderItemSet(); + void createVisibleRenderItemSet(); + void createCollisionRenderItemSet(); static model::MaterialPointer _collisionHullMaterial; - bool _meshGroupsKnown; bool _isWireframe; @@ -397,7 +400,8 @@ protected: QSet> _modelMeshRenderItemsSet; QMap _modelMeshRenderItems; - bool _readyWhenAdded { false }; + bool _addedToScene { false }; // has been added to scene + bool _needsFixupInScene { true }; // needs to be removed/re-added to scene bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; bool _showCollisionHull { false }; From 25fb7aacad3e9e49674ae8686c27aa20a48375fb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 07:53:11 -0700 Subject: [PATCH 38/71] ShapeManager hands out const shape pointers --- interface/src/avatar/AvatarManager.cpp | 2 +- interface/src/avatar/AvatarMotionState.cpp | 4 ++-- interface/src/avatar/AvatarMotionState.h | 4 ++-- libraries/physics/src/PhysicalEntitySimulation.cpp | 2 +- libraries/physics/src/PhysicsEngine.cpp | 6 +++--- libraries/physics/src/ShapeFactory.cpp | 14 +++++++++----- libraries/physics/src/ShapeFactory.h | 4 ++-- libraries/physics/src/ShapeManager.cpp | 4 ++-- libraries/physics/src/ShapeManager.h | 4 ++-- 9 files changed, 24 insertions(+), 20 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index bd76d2bd81..441130bd83 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -367,7 +367,7 @@ void AvatarManager::addAvatarToSimulation(Avatar* avatar) { ShapeInfo shapeInfo; avatar->computeShapeInfo(shapeInfo); - btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); + btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); if (shape) { // we don't add to the simulation now, we put it on a list to be added later AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 9cc3095ae2..335245670b 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -17,7 +17,7 @@ #include "AvatarMotionState.h" #include "BulletUtil.h" -AvatarMotionState::AvatarMotionState(Avatar* avatar, btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { +AvatarMotionState::AvatarMotionState(Avatar* avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { assert(_avatar); _type = MOTIONSTATE_TYPE_AVATAR; if (_shape) { @@ -47,7 +47,7 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const { } // virtual and protected -btCollisionShape* AvatarMotionState::computeNewShape() { +const btCollisionShape* AvatarMotionState::computeNewShape() { ShapeInfo shapeInfo; _avatar->computeShapeInfo(shapeInfo); return getShapeManager()->getShape(shapeInfo); diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 04aa5ea57c..66824d6e37 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -20,7 +20,7 @@ class Avatar; class AvatarMotionState : public ObjectMotionState { public: - AvatarMotionState(Avatar* avatar, btCollisionShape* shape); + AvatarMotionState(Avatar* avatar, const btCollisionShape* shape); virtual PhysicsMotionType getMotionType() const override { return _motionType; } @@ -72,7 +72,7 @@ protected: ~AvatarMotionState(); virtual bool isReadyToComputeShape() const override { return true; } - virtual btCollisionShape* computeNewShape() override; + virtual const btCollisionShape* computeNewShape() override; // The AvatarMotionState keeps a RAW backpointer to its Avatar because all AvatarMotionState // instances are "owned" by their corresponding Avatar instance and are deleted in the Avatar dtor. diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 9714059e7c..be420604b3 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -225,7 +225,7 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re << "at" << entity->getPosition() << " will be reduced"; } } - btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); + btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); if (shape) { EntityMotionState* motionState = new EntityMotionState(shape, entity); entity->setPhysicsInfo(static_cast(motionState)); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index aa6c1b4e40..1c6d5d535e 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -76,7 +76,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { switch(motionType) { case MOTION_TYPE_KINEMATIC: { if (!body) { - btCollisionShape* shape = motionState->getShape(); + btCollisionShape* shape = const_cast(motionState->getShape()); assert(shape); body = new btRigidBody(mass, motionState, shape, inertia); motionState->setRigidBody(body); @@ -93,7 +93,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { } case MOTION_TYPE_DYNAMIC: { mass = motionState->getMass(); - btCollisionShape* shape = motionState->getShape(); + btCollisionShape* shape = const_cast(motionState->getShape()); assert(shape); shape->calculateLocalInertia(mass, inertia); if (!body) { @@ -120,7 +120,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { default: { if (!body) { assert(motionState->getShape()); - body = new btRigidBody(mass, motionState, motionState->getShape(), inertia); + body = new btRigidBody(mass, motionState, const_cast(motionState->getShape()), inertia); motionState->setRigidBody(body); } else { body->setMassProps(mass, inertia); diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 8576a9caee..f11b0f95dc 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -247,7 +247,7 @@ void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) { delete dataArray; } -btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { +const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; int type = info.getType(); switch(type) { @@ -359,10 +359,14 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { return shape; } -void ShapeFactory::deleteShape(btCollisionShape* shape) { +void ShapeFactory::deleteShape(const btCollisionShape* shape) { assert(shape); - if (shape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) { - btCompoundShape* compoundShape = static_cast(shape); + // ShapeFactory is responsible for deleting all shapes, even the const ones that are stored + // in the ShapeManager, so we must cast to non-const here when deleting. + // so we cast to non-const here when deleting memory. + btCollisionShape* nonConstShape = const_cast(shape); + if (nonConstShape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) { + btCompoundShape* compoundShape = static_cast(nonConstShape); const int numChildShapes = compoundShape->getNumChildShapes(); for (int i = 0; i < numChildShapes; i ++) { btCollisionShape* childShape = compoundShape->getChildShape(i); @@ -374,7 +378,7 @@ void ShapeFactory::deleteShape(btCollisionShape* shape) { } } } - delete shape; + delete nonConstShape; } // the dataArray must be created before we create the StaticMeshShape diff --git a/libraries/physics/src/ShapeFactory.h b/libraries/physics/src/ShapeFactory.h index 6202612eb9..a1022104dd 100644 --- a/libraries/physics/src/ShapeFactory.h +++ b/libraries/physics/src/ShapeFactory.h @@ -20,8 +20,8 @@ // translates between ShapeInfo and btShape namespace ShapeFactory { - btCollisionShape* createShapeFromInfo(const ShapeInfo& info); - void deleteShape(btCollisionShape* shape); + const btCollisionShape* createShapeFromInfo(const ShapeInfo& info); + void deleteShape(const btCollisionShape* shape); //btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info); //void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray); diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 35046adcfd..b61fb0037b 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -28,7 +28,7 @@ ShapeManager::~ShapeManager() { _shapeMap.clear(); } -btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { +const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { if (info.getType() == SHAPE_TYPE_NONE) { return nullptr; } @@ -45,7 +45,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { shapeRef->refCount++; return shapeRef->shape; } - btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); + const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); if (shape) { ShapeReference newRef; newRef.refCount = 1; diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index cdb2b78789..261c06ddb9 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -26,7 +26,7 @@ public: ~ShapeManager(); /// \return pointer to shape - btCollisionShape* getShape(const ShapeInfo& info); + const btCollisionShape* getShape(const ShapeInfo& info); /// \return true if shape was found and released bool releaseShape(const btCollisionShape* shape); @@ -46,7 +46,7 @@ private: class ShapeReference { public: int refCount; - btCollisionShape* shape; + const btCollisionShape* shape; DoubleHashKey key; ShapeReference() : refCount(0), shape(nullptr) {} }; From daff897fc4bd16e0a7b71a77b6fda6355aafbf4d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 07:54:31 -0700 Subject: [PATCH 39/71] const shapes, and use *MotionState::setShape() --- libraries/physics/src/EntityMotionState.cpp | 14 ++++++++------ libraries/physics/src/EntityMotionState.h | 4 ++-- libraries/physics/src/ObjectMotionState.cpp | 12 ++++++------ libraries/physics/src/ObjectMotionState.h | 10 +++++----- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 4b6823dd8a..b70927d501 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -46,7 +46,7 @@ bool entityTreeIsLocked() { EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) : - ObjectMotionState(shape), + ObjectMotionState(nullptr), _entityPtr(entity), _entity(entity.get()), _serverPosition(0.0f), @@ -71,6 +71,9 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer assert(_entity); assert(entityTreeIsLocked()); setMass(_entity->computeMass()); + // we need the side-effects of EntityMotionState::setShape() so we call it explicitly here + // rather than pass the legit shape pointer to the ObjectMotionState ctor above. + setShape(shape); } EntityMotionState::~EntityMotionState() { @@ -264,17 +267,16 @@ bool EntityMotionState::isReadyToComputeShape() const { } // virtual and protected -btCollisionShape* EntityMotionState::computeNewShape() { +const btCollisionShape* EntityMotionState::computeNewShape() { ShapeInfo shapeInfo; assert(entityTreeIsLocked()); _entity->computeShapeInfo(shapeInfo); return getShapeManager()->getShape(shapeInfo); } -void EntityMotionState::setShape(btCollisionShape* shape) { - bool shapeChanged = (_shape != shape); - ObjectMotionState::setShape(shape); - if (shapeChanged) { +void EntityMotionState::setShape(const btCollisionShape* shape) { + if (_shape != shape) { + ObjectMotionState::setShape(shape); _entity->setCollisionShape(_shape); } } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 2c39da9164..194d82805f 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -89,8 +89,8 @@ protected: #endif bool isReadyToComputeShape() const override; - btCollisionShape* computeNewShape() override; - void setShape(btCollisionShape* shape) override; + const btCollisionShape* computeNewShape() override; + void setShape(const btCollisionShape* shape) override; void setMotionType(PhysicsMotionType motionType) override; // In the glorious future (when entities lib depends on physics lib) the EntityMotionState will be diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 64b1e9c527..38f079c1d4 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -62,14 +62,13 @@ ShapeManager* ObjectMotionState::getShapeManager() { return shapeManager; } -ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : +ObjectMotionState::ObjectMotionState(const btCollisionShape* shape) : _motionType(MOTION_TYPE_STATIC), - _shape(nullptr), + _shape(shape), _body(nullptr), _mass(0.0f), _lastKinematicStep(worldSimulationStep) { - setShape(shape); } ObjectMotionState::~ObjectMotionState() { @@ -154,12 +153,13 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { _body = body; if (_body) { _body->setUserPointer(this); + assert(_body->getCollisionShape() == _shape); } updateCCDConfiguration(); } } -void ObjectMotionState::setShape(btCollisionShape* shape) { +void ObjectMotionState::setShape(const btCollisionShape* shape) { if (_shape != shape) { if (_shape) { getShapeManager()->releaseShape(_shape); @@ -254,7 +254,7 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* if (!isReadyToComputeShape()) { return false; } - btCollisionShape* newShape = computeNewShape(); + const btCollisionShape* newShape = computeNewShape(); if (!newShape) { qCDebug(physics) << "Warning: failed to generate new shape!"; // failed to generate new shape! --> keep old shape and remove shape-change flag @@ -274,7 +274,7 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* // and clear the reference we just created getShapeManager()->releaseShape(_shape); } else { - _body->setCollisionShape(newShape); + _body->setCollisionShape(const_cast(newShape)); setShape(newShape); updateCCDConfiguration(); } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index ccaef17fd1..a7894998a8 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -78,7 +78,7 @@ public: static void setShapeManager(ShapeManager* manager); static ShapeManager* getShapeManager(); - ObjectMotionState(btCollisionShape* shape); + ObjectMotionState(const btCollisionShape* shape); ~ObjectMotionState(); virtual void handleEasyChanges(uint32_t& flags); @@ -110,7 +110,7 @@ public: virtual PhysicsMotionType computePhysicsMotionType() const = 0; - btCollisionShape* getShape() const { return _shape; } + const btCollisionShape* getShape() const { return _shape; } btRigidBody* getRigidBody() const { return _body; } virtual bool isMoving() const = 0; @@ -150,17 +150,17 @@ public: protected: virtual bool isReadyToComputeShape() const = 0; - virtual btCollisionShape* computeNewShape() = 0; + virtual const btCollisionShape* computeNewShape() = 0; virtual void setMotionType(PhysicsMotionType motionType); void updateCCDConfiguration(); void setRigidBody(btRigidBody* body); - virtual void setShape(btCollisionShape* shape); + virtual void setShape(const btCollisionShape* shape); MotionStateType _type = MOTIONSTATE_TYPE_INVALID; // type of MotionState PhysicsMotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC - btCollisionShape* _shape; + const btCollisionShape* _shape; btRigidBody* _body; float _mass; From 26f5d3cfaa382dcf075ba7f8f503e7b2305bbcb3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 07:55:34 -0700 Subject: [PATCH 40/71] fix render geometry for collision shapes --- .../physics/src/CollisionRenderMeshCache.cpp | 84 ++++++++++++------- libraries/render-utils/src/Model.cpp | 23 +++-- 2 files changed, 67 insertions(+), 40 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 22f0b986ab..ef2f9013ef 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -18,53 +18,69 @@ #include // for MAX_HULL_POINTS -float verts[3 * MAX_HULL_POINTS]; +const int32_t MAX_HULL_INDICES = 6 * MAX_HULL_POINTS; +float tempVertexBuffer[3 * MAX_HULL_POINTS]; +model::Index tempIndexBuffer[MAX_HULL_INDICES]; -void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, model::MeshPointer mesh) { - assert((bool)mesh); +//void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, model::MeshPointer mesh) { +void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, + gpu::BufferView& vertices, gpu::BufferView& indices, gpu::BufferView& parts) { assert(shape); btShapeHull hull(shape); const btScalar MARGIN = 0.0f; hull.buildHull(MARGIN); - const uint32_t* hullIndices = hull.getIndexPointer(); - int32_t numIndices = hull.numIndices(); - assert(numIndices <= 6 * MAX_HULL_POINTS); + int32_t numHullIndices = hull.numIndices(); + assert(numHullIndices <= MAX_HULL_INDICES); + + int32_t numHullVertices = hull.numVertices(); + assert(numHullVertices <= MAX_HULL_POINTS); { // new part model::Mesh::Part part; - part._startIndex = mesh->getIndexBuffer().getNumElements(); - part._numIndices = (model::Index)numIndices; - part._baseVertex = mesh->getVertexBuffer().getNumElements(); + part._startIndex = indices.getNumElements(); + part._numIndices = (model::Index)numHullIndices; + // FIXME: the render code cannot handle the case where part._baseVertex != 0 + //part._baseVertex = vertices.getNumElements(); // DOES NOT WORK + part._baseVertex = 0; gpu::BufferView::Size numBytes = sizeof(model::Mesh::Part); const gpu::Byte* data = reinterpret_cast(&part); - mesh->getPartBuffer()._buffer->append(numBytes, data); + parts._buffer->append(numBytes, data); + parts._size = parts._buffer->getSize(); } + model::Index indexOffset = vertices.getNumElements(); { // new vertices const btVector3* hullVertices = hull.getVertexPointer(); - int32_t numVertices = hull.numVertices(); - assert(numVertices <= MAX_HULL_POINTS); - for (int32_t i = 0; i < numVertices; ++i) { + assert(numHullVertices <= MAX_HULL_POINTS); + for (int32_t i = 0; i < numHullVertices; ++i) { btVector3 transformedPoint = transform * hullVertices[i]; - memcpy(transformedPoint.m_floats, verts + 3 * i, 3 * sizeof(float)); - //data[0] = transformedPoint.getX(); - //data[1] = transformedPoint.getY(); - //data[2] = transformedPoint.getZ(); + memcpy(tempVertexBuffer + 3 * i, transformedPoint.m_floats, 3 * sizeof(float)); } - gpu::BufferView::Size numBytes = sizeof(float) * (3 * numVertices); - const gpu::Byte* data = reinterpret_cast(verts); - mesh->getVertexBuffer()._buffer->append(numBytes, data); + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices); + const gpu::Byte* data = reinterpret_cast(tempVertexBuffer); + vertices._buffer->append(numBytes, data); + vertices._size = vertices._buffer->getSize(); } { // new indices - gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(uint32_t) * hull.numIndices()); - const gpu::Byte* data = reinterpret_cast(hullIndices); - mesh->getIndexBuffer()._buffer->append(numBytes, data); + const uint32_t* hullIndices = hull.getIndexPointer(); + // FIXME: the render code cannot handle the case where part._baseVertex != 0 + // so we must add an offset to each index + for (int32_t i = 0; i < numHullIndices; ++i) { + tempIndexBuffer[i] = hullIndices[i] + indexOffset; + } + const gpu::Byte* data = reinterpret_cast(tempIndexBuffer); + gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(model::Index) * numHullIndices); + indices._buffer->append(numBytes, data); + indices._size = indices._buffer->getSize(); } + + gpu::BufferView::Iterator partItr = parts.cbegin(); + gpu::Size numParts = parts.getNumElements(); } model::MeshPointer createMeshFromShape(const void* pointer) { @@ -73,17 +89,18 @@ model::MeshPointer createMeshFromShape(const void* pointer) { return mesh; } - // pointer must actually be a const btCollisionShape*, but it only - // needs to be valid here when its render mesh is created. + // pointer must be a const btCollisionShape* (cast to void*), but it only + // needs to be valid here when its render mesh is created, after this call + // the cache doesn't care what happens to the shape behind the pointer const btCollisionShape* shape = static_cast(pointer); int32_t shapeType = shape->getShapeType(); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE || shape->isConvex()) { // create the mesh and allocate buffers for it mesh = std::make_shared(); - mesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getVertexBuffer()._element)); - mesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getIndexBuffer()._element)); - mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getPartBuffer()._element)); + gpu::BufferView vertices(new gpu::Buffer(), mesh->getVertexBuffer()._element); + gpu::BufferView indices(new gpu::Buffer(), mesh->getIndexBuffer()._element); + gpu::BufferView parts(new gpu::Buffer(), mesh->getPartBuffer()._element); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); @@ -92,14 +109,19 @@ model::MeshPointer createMeshFromShape(const void* pointer) { const btCollisionShape* childShape = compoundShape->getChildShape(i); if (childShape->isConvex()) { const btConvexShape* convexShape = static_cast(childShape); - copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, mesh); + copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, vertices, indices, parts); } } } else { // shape is convex const btConvexShape* convexShape = static_cast(shape); - copyShapeToMesh(btTransform(), convexShape, mesh); + btTransform transform; + transform.setIdentity(); + copyShapeToMesh(transform, convexShape, vertices, indices, parts); } + mesh->setVertexBuffer(vertices); + mesh->setIndexBuffer(indices); + mesh->setPartBuffer(parts); } return mesh; } @@ -151,7 +173,7 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { void CollisionRenderMeshCache::collectGarbage() { uint32_t numShapes = _pendingGarbage.size(); - for (int32_t i = 0; i < numShapes; ++i) { + for (uint32_t i = 0; i < numShapes; ++i) { CollisionRenderMeshCache::Key key = _pendingGarbage[i]; CollisionMeshMap::const_iterator itr = _meshMap.find(key); if (itr != _meshMap.end()) { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 075e550dd5..bbb0294e21 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -219,10 +219,6 @@ void Model::updateRenderItems() { modelMeshOffset.postTranslate(self->_offset); } - // only apply offset only, collision mesh does not share the same unit scale as the FBX file's mesh. - Transform collisionMeshOffset; - collisionMeshOffset.postTranslate(self->_offset); - uint32_t deleteGeometryCounter = self->_deleteGeometryCounter; render::PendingChanges pendingChanges; @@ -243,6 +239,11 @@ void Model::updateRenderItems() { }); } + // collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset + Transform collisionMeshOffset; + // adebug FIXME: recover correct behavior for collisionURL shapes + //collisionMeshOffset.postTranslate(self->_offset); + collisionMeshOffset.setIdentity(); foreach (auto itemID, self->_collisionRenderItems.keys()) { pendingChanges.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { // update the model transform for this render item. @@ -1321,12 +1322,16 @@ void Model::createCollisionRenderItemSet() { Q_ASSERT(_collisionRenderItemsSet.isEmpty()); Transform transform; - transform.setTranslation(_translation); - transform.setRotation(_rotation); + transform.setIdentity(); + // adebug FIXME: recover correct behavior for collisionURL + //transform.setTranslation(_translation); + //transform.setRotation(_rotation); Transform offset; - offset.setScale(_scale); - offset.postTranslate(_offset); + // adebug FIXME: recover correct behavior for collisionURL + offset.setIdentity(); + //offset.setScale(_scale); + //offset.postTranslate(_offset); // Run through all of the meshes, and place them into their segregated, but unsorted buckets uint32_t numMeshes = (uint32_t)meshes.size(); @@ -1339,7 +1344,7 @@ void Model::createCollisionRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - model::MaterialPointer& material = _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; + model::MaterialPointer& material = _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material, transform, offset); } } From 3b772d2fe6ff000ddee1c760ec503647c1b0d70e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 17:06:40 -0700 Subject: [PATCH 41/71] fallback to SIMPLE_COMPOUND when can't do COMPOUND --- libraries/entities/src/ModelEntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 8e925b2f79..b098247524 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -282,8 +282,8 @@ ShapeType ModelEntityItem::computeTrueShapeType() const { type = SHAPE_TYPE_COMPOUND; } if (type == SHAPE_TYPE_COMPOUND && !hasCompoundShapeURL()) { - // no compoundURL set --> fall back to NONE - type = SHAPE_TYPE_NONE; + // no compoundURL set --> fall back to SIMPLE_COMPOUND + type = SHAPE_TYPE_SIMPLE_COMPOUND; } return type; } From 481d6990a3b188f53d36236e7aeaefb0e9c367ee Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 17:07:16 -0700 Subject: [PATCH 42/71] trigger collision shape render mesh creation --- libraries/render-utils/src/Model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index bbb0294e21..546631232e 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1411,6 +1411,7 @@ void Model::setCollisionMesh(model::MeshPointer mesh) { _collisionGeometry = std::make_shared(mesh); if (_showCollisionHull) { + _needsFixupInScene = true; // TODO: need to trigger: // (a) reconstruction of RenderItems // (b) and reinsertion into scene if we are showing collision geometry From 1f84ef3053317ba5e1ba0259ffe31f7574f8599e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 17:07:43 -0700 Subject: [PATCH 43/71] compute normals for collision mesh geometry --- .../physics/src/CollisionRenderMeshCache.cpp | 91 ++++++++++++------- 1 file changed, 60 insertions(+), 31 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index ef2f9013ef..8b27bbae24 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -19,17 +19,19 @@ #include // for MAX_HULL_POINTS const int32_t MAX_HULL_INDICES = 6 * MAX_HULL_POINTS; -float tempVertexBuffer[3 * MAX_HULL_POINTS]; +const int32_t MAX_HULL_NORMALS = MAX_HULL_INDICES; +float tempVertices[MAX_HULL_NORMALS]; model::Index tempIndexBuffer[MAX_HULL_INDICES]; -//void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, model::MeshPointer mesh) { -void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, - gpu::BufferView& vertices, gpu::BufferView& indices, gpu::BufferView& parts) { +bool copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, + gpu::BufferView& vertices, gpu::BufferView& indices, gpu::BufferView& parts, + gpu::BufferView& normals) { assert(shape); btShapeHull hull(shape); - const btScalar MARGIN = 0.0f; - hull.buildHull(MARGIN); + if (!hull.buildHull(shape->getMargin())) { + return false; + } int32_t numHullIndices = hull.numIndices(); assert(numHullIndices <= MAX_HULL_INDICES); @@ -51,20 +53,8 @@ void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, parts._size = parts._buffer->getSize(); } + const int32_t SIZE_OF_VEC3 = 3 * sizeof(float); model::Index indexOffset = vertices.getNumElements(); - { // new vertices - const btVector3* hullVertices = hull.getVertexPointer(); - assert(numHullVertices <= MAX_HULL_POINTS); - for (int32_t i = 0; i < numHullVertices; ++i) { - btVector3 transformedPoint = transform * hullVertices[i]; - memcpy(tempVertexBuffer + 3 * i, transformedPoint.m_floats, 3 * sizeof(float)); - } - - gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices); - const gpu::Byte* data = reinterpret_cast(tempVertexBuffer); - vertices._buffer->append(numBytes, data); - vertices._size = vertices._buffer->getSize(); - } { // new indices const uint32_t* hullIndices = hull.getIndexPointer(); @@ -78,9 +68,37 @@ void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, indices._buffer->append(numBytes, data); indices._size = indices._buffer->getSize(); } + { // new vertices + const btVector3* hullVertices = hull.getVertexPointer(); + assert(numHullVertices <= MAX_HULL_POINTS); + for (int32_t i = 0; i < numHullVertices; ++i) { + btVector3 transformedPoint = transform * hullVertices[i]; + memcpy(tempVertices + 3 * i, transformedPoint.m_floats, SIZE_OF_VEC3); + } + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices); + const gpu::Byte* data = reinterpret_cast(tempVertices); + vertices._buffer->append(numBytes, data); + vertices._size = vertices._buffer->getSize(); + } + { // new normals + // compute average point + btVector3 avgVertex(0.0f, 0.0f, 0.0f); + const btVector3* hullVertices = hull.getVertexPointer(); + for (int i = 0; i < numHullVertices; ++i) { + avgVertex += hullVertices[i]; + } + avgVertex = transform * (avgVertex * (1.0f / (float)numHullVertices)); - gpu::BufferView::Iterator partItr = parts.cbegin(); - gpu::Size numParts = parts.getNumElements(); + for (int i = 0; i < numHullVertices; ++i) { + btVector3 norm = (transform * hullVertices[i] - avgVertex).normalize(); + memcpy(tempVertices + 3 * i, norm.m_floats, SIZE_OF_VEC3); + } + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices); + const gpu::Byte* data = reinterpret_cast(tempVertices); + normals._buffer->append(numBytes, data); + normals._size = vertices._buffer->getSize(); + } + return true; } model::MeshPointer createMeshFromShape(const void* pointer) { @@ -96,12 +114,13 @@ model::MeshPointer createMeshFromShape(const void* pointer) { int32_t shapeType = shape->getShapeType(); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE || shape->isConvex()) { - // create the mesh and allocate buffers for it - mesh = std::make_shared(); - gpu::BufferView vertices(new gpu::Buffer(), mesh->getVertexBuffer()._element); - gpu::BufferView indices(new gpu::Buffer(), mesh->getIndexBuffer()._element); - gpu::BufferView parts(new gpu::Buffer(), mesh->getPartBuffer()._element); + // allocate buffers for it + gpu::BufferView vertices(new gpu::Buffer(), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + gpu::BufferView indices(new gpu::Buffer(), gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::INDEX)); + gpu::BufferView parts(new gpu::Buffer(), gpu::Element(gpu::VEC4, gpu::UINT32, gpu::PART)); + gpu::BufferView normals(new gpu::Buffer(), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + int32_t numSuccesses = 0; if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); int32_t numSubShapes = compoundShape->getNumChildShapes(); @@ -109,7 +128,9 @@ model::MeshPointer createMeshFromShape(const void* pointer) { const btCollisionShape* childShape = compoundShape->getChildShape(i); if (childShape->isConvex()) { const btConvexShape* convexShape = static_cast(childShape); - copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, vertices, indices, parts); + if (copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, vertices, indices, parts, normals)) { + numSuccesses++; + } } } } else { @@ -117,11 +138,19 @@ model::MeshPointer createMeshFromShape(const void* pointer) { const btConvexShape* convexShape = static_cast(shape); btTransform transform; transform.setIdentity(); - copyShapeToMesh(transform, convexShape, vertices, indices, parts); + if (copyShapeToMesh(transform, convexShape, vertices, indices, parts, normals)) { + numSuccesses++; + } + } + if (numSuccesses > 0) { + mesh = std::make_shared(); + mesh->setVertexBuffer(vertices); + mesh->setIndexBuffer(indices); + mesh->setPartBuffer(parts); + mesh->addAttribute(gpu::Stream::NORMAL, normals); + } else { + // TODO: log failure message here } - mesh->setVertexBuffer(vertices); - mesh->setIndexBuffer(indices); - mesh->setPartBuffer(parts); } return mesh; } From 329c5432ed67a116316c818b3f486d4c464ad9cf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 17:28:02 -0700 Subject: [PATCH 44/71] _showCollisionHull --> _showCollisionGeometry --- libraries/render-utils/src/Model.cpp | 30 ++++++++++++++-------------- libraries/render-utils/src/Model.h | 3 +-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 546631232e..4e4edb0202 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -37,9 +37,9 @@ float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; #define HTTP_INVALID_COM "http://invalid.com" const int NUM_COLLISION_HULL_COLORS = 24; -std::vector _collisionHullMaterials; +std::vector _collisionMaterials; -void initCollisionHullMaterials() { +void initCollisionMaterials() { // generates bright colors in red, green, blue, yellow, magenta, and cyan spectrums // (no browns, greys, or dark shades) float component[NUM_COLLISION_HULL_COLORS] = { @@ -50,7 +50,7 @@ void initCollisionHullMaterials() { 1.0f, 1.0f, 1.0f, 1.0f, 0.8f, 0.6f, 0.4f, 0.2f }; - _collisionHullMaterials.reserve(NUM_COLLISION_HULL_COLORS); + _collisionMaterials.reserve(NUM_COLLISION_HULL_COLORS); // each component gets the same cuve // but offset by a multiple of one third the full width @@ -72,7 +72,7 @@ void initCollisionHullMaterials() { material->setAlbedo(glm::vec3(red, green, blue)); material->setMetallic(0.02f); material->setRoughness(0.5f); - _collisionHullMaterials.push_back(material); + _collisionMaterials.push_back(material); } } } @@ -121,15 +121,15 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; void Model::setShowCollisionMesh(bool value) { - if (_showCollisionHull != value) { - _showCollisionHull = value; + if (_showCollisionGeometry != value) { + _showCollisionGeometry = value; _needsFixupInScene = true; } } bool Model::needsFixupInScene() const { if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { - if (_showCollisionHull && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { return true; } if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { @@ -614,13 +614,13 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) { - bool readyToRender = (_showCollisionHull && _collisionGeometry) || isLoaded(); + bool readyToRender = (_showCollisionGeometry && _collisionGeometry) || isLoaded(); if (!_addedToScene && readyToRender) { createRenderItemSet(); } bool somethingAdded = false; - if (_showCollisionHull && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { if (_collisionRenderItems.empty()) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); @@ -1258,7 +1258,7 @@ AABox Model::getRenderableMeshBound() const { } void Model::createRenderItemSet() { - if (_showCollisionHull && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { if (_collisionRenderItemsSet.empty()) { createCollisionRenderItemSet(); } @@ -1312,8 +1312,8 @@ void Model::createVisibleRenderItemSet() { void Model::createCollisionRenderItemSet() { assert((bool)_collisionGeometry); - if (_collisionHullMaterials.empty()) { - initCollisionHullMaterials(); + if (_collisionMaterials.empty()) { + initCollisionMaterials(); } const auto& meshes = _collisionGeometry->getMeshes(); @@ -1344,7 +1344,7 @@ void Model::createCollisionRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - model::MaterialPointer& material = _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; + model::MaterialPointer& material = _collisionMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material, transform, offset); } } @@ -1365,7 +1365,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { render::PendingChanges pendingChanges; bool addedPendingChanges = false; - if (_showCollisionHull && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); @@ -1410,7 +1410,7 @@ void Model::setCollisionMesh(model::MeshPointer mesh) { _collisionWatcher.stopWatching(); _collisionGeometry = std::make_shared(mesh); - if (_showCollisionHull) { + if (_showCollisionGeometry) { _needsFixupInScene = true; // TODO: need to trigger: // (a) reconstruction of RenderItems diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index b30b0b0d76..9a0f2e6713 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -382,7 +382,6 @@ protected: void createRenderItemSet(); void createVisibleRenderItemSet(); void createCollisionRenderItemSet(); - static model::MaterialPointer _collisionHullMaterial; bool _isWireframe; @@ -404,7 +403,7 @@ protected: bool _needsFixupInScene { true }; // needs to be removed/re-added to scene bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; - bool _showCollisionHull { false }; + bool _showCollisionGeometry { false }; mutable bool _needsUpdateTextures { true }; friend class ModelMeshPartPayload; From 191b7f0f39e3b5c92a060b650d82b4aed89b3e76 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 27 Jul 2016 13:52:50 -0700 Subject: [PATCH 45/71] variable namechange: Hull --> Mesh --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 6e5d1c7959..b80a003e8e 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -436,9 +436,9 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // update whether the model should be showing collision mesh // (this may flag for fixupInScene) - bool shouldShowCollisionHull = getShapeType() != SHAPE_TYPE_STATIC_MESH && + bool shouldShowCollisionMesh = getShapeType() != SHAPE_TYPE_STATIC_MESH && (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; - _model->setShowCollisionMesh(shouldShowCollisionHull); + _model->setShowCollisionMesh(shouldShowCollisionMesh); if (_model->needsFixupInScene()) { render::PendingChanges pendingChanges; From fe4198530f83030cb20bfbed76be698173944005 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 27 Jul 2016 13:52:55 -0700 Subject: [PATCH 46/71] don't render raw compound collision geometry --- .../render-utils/src/MeshPartPayload.cpp | 4 +- libraries/render-utils/src/MeshPartPayload.h | 2 +- libraries/render-utils/src/Model.cpp | 46 ++++++++----------- libraries/render-utils/src/Model.h | 1 + 4 files changed, 22 insertions(+), 31 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 8913a62d9d..42dd41c739 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -46,11 +46,9 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr } } -MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) { - +MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material) { updateMeshPart(mesh, partIndex); updateMaterial(material); - updateTransform(transform, offsetTransform); } void MeshPartPayload::updateMeshPart(const std::shared_ptr& drawMesh, int partIndex) { diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 29478b3b4e..a934863846 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -26,7 +26,7 @@ class Model; class MeshPartPayload { public: MeshPartPayload() {} - MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform); + MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material); typedef render::Payload Payload; typedef Payload::DataPointer Pointer; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 4e4edb0202..ce8ebfb00a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -121,15 +121,17 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; void Model::setShowCollisionMesh(bool value) { - if (_showCollisionGeometry != value) { - _showCollisionGeometry = value; - _needsFixupInScene = true; + if (_readyToShowCollisionGeometry) { + if (_showCollisionGeometry != value) { + _showCollisionGeometry = value; + _needsFixupInScene = true; + } } } bool Model::needsFixupInScene() const { if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { - if (_showCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { return true; } if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { @@ -241,8 +243,6 @@ void Model::updateRenderItems() { // collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset Transform collisionMeshOffset; - // adebug FIXME: recover correct behavior for collisionURL shapes - //collisionMeshOffset.postTranslate(self->_offset); collisionMeshOffset.setIdentity(); foreach (auto itemID, self->_collisionRenderItems.keys()) { pendingChanges.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { @@ -614,13 +614,13 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) { - bool readyToRender = (_showCollisionGeometry && _collisionGeometry) || isLoaded(); + bool readyToRender = (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) || isLoaded(); if (!_addedToScene && readyToRender) { createRenderItemSet(); } bool somethingAdded = false; - if (_showCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { if (_collisionRenderItems.empty()) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); @@ -1258,7 +1258,7 @@ AABox Model::getRenderableMeshBound() const { } void Model::createRenderItemSet() { - if (_showCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { if (_collisionRenderItemsSet.empty()) { createCollisionRenderItemSet(); } @@ -1321,18 +1321,6 @@ void Model::createCollisionRenderItemSet() { // We should not have any existing renderItems if we enter this section of code Q_ASSERT(_collisionRenderItemsSet.isEmpty()); - Transform transform; - transform.setIdentity(); - // adebug FIXME: recover correct behavior for collisionURL - //transform.setTranslation(_translation); - //transform.setRotation(_rotation); - - Transform offset; - // adebug FIXME: recover correct behavior for collisionURL - offset.setIdentity(); - //offset.setScale(_scale); - //offset.postTranslate(_offset); - // Run through all of the meshes, and place them into their segregated, but unsorted buckets uint32_t numMeshes = (uint32_t)meshes.size(); for (uint32_t i = 0; i < numMeshes; i++) { @@ -1345,7 +1333,7 @@ void Model::createCollisionRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { model::MaterialPointer& material = _collisionMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; - _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material, transform, offset); + _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material); } } } @@ -1365,7 +1353,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { render::PendingChanges pendingChanges; bool addedPendingChanges = false; - if (_showCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); @@ -1387,7 +1375,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { scene->enqueuePendingChanges(pendingChanges); // NOTE: updateRender items enqueues identical pendingChanges (using a lambda) // so it looks like we're doing double work here, but I don't want to remove the call - // for fear there is some sideeffect we'll miss. -- Andrew 2016.07.21 + // for fear there is some side effect we'll miss. -- Andrew 2016.07.21 // TODO: figure out if we really need this call to updateRenderItems() or not. updateRenderItems(); } @@ -1410,11 +1398,15 @@ void Model::setCollisionMesh(model::MeshPointer mesh) { _collisionWatcher.stopWatching(); _collisionGeometry = std::make_shared(mesh); + // HACK: we don't want to show the _collisionGeometry until we're ready (e.g. it has been created) + // hence we track whether it has been created using _readyToShowCollisionGeoemtry, because there + // is an ambiguous case where _collisionGeometry is valid (from CompoundURL) but has not yet been + // properly computed (zeroed offset transform) using the CollisionRenderMeshCache. + // + // TODO: At the moment we create the collision mesh for every model that has a collision shape + // as soon as we know the shape, but we SHOULD only ever create the render mesh when we need it. if (_showCollisionGeometry) { _needsFixupInScene = true; - // TODO: need to trigger: - // (a) reconstruction of RenderItems - // (b) and reinsertion into scene if we are showing collision geometry } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 9a0f2e6713..3fc681261a 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -404,6 +404,7 @@ protected: bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; bool _showCollisionGeometry { false }; + bool _readyToShowCollisionGeometry { false }; mutable bool _needsUpdateTextures { true }; friend class ModelMeshPartPayload; From ef597265d76bcc1f3a0e7e0ba7a75b7816f1800e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 07:30:27 -0700 Subject: [PATCH 47/71] remove unimplemented declaration --- libraries/networking/src/ResourceCache.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index a2a5b4cbbe..eba84dddd4 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -226,8 +226,6 @@ private: void resetResourceCounters(); void removeResource(const QUrl& url, qint64 size = 0); - void getResourceAsynchronously(const QUrl& url); - static int _requestLimit; static int _requestsActive; From b0a0293e6e0a19b0efa911c96a23ea9065f20208 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 07:31:32 -0700 Subject: [PATCH 48/71] move compoundResource out of Model class --- .../src/EntityTreeRenderer.cpp | 18 -------- .../src/EntityTreeRenderer.h | 1 - .../src/RenderableModelEntityItem.cpp | 46 +++++++++++++------ .../src/RenderableModelEntityItem.h | 2 + libraries/entities/src/EntityTree.h | 1 - libraries/render-utils/src/Model.cpp | 43 ++++------------- libraries/render-utils/src/Model.h | 9 ---- 7 files changed, 42 insertions(+), 78 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 39031acaa1..209a27739b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -499,22 +499,6 @@ ModelPointer EntityTreeRenderer::getModelForEntityItem(EntityItemPointer entityI return result; } -const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemPointer entityItem) { - const FBXGeometry* result = NULL; - - if (entityItem->getType() == EntityTypes::Model) { - std::shared_ptr modelEntityItem = - std::dynamic_pointer_cast(entityItem); - if (modelEntityItem->hasCompoundShapeURL()) { - ModelPointer model = modelEntityItem->getModel(this); - if (model && model->isCollisionLoaded()) { - result = &model->getCollisionFBXGeometry(); - } - } - } - return result; -} - void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) { std::static_pointer_cast(_tree)->processEraseMessage(message, sourceNode); } @@ -536,7 +520,6 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString model->setLoadingPriority(loadingPriority); model->init(); model->setURL(QUrl(url)); - model->setCollisionModelURL(QUrl(collisionUrl)); return model; } @@ -553,7 +536,6 @@ ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& } model->setURL(QUrl(newUrl)); - model->setCollisionModelURL(QUrl(collisionUrl)); return model; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 5d634fa6ca..5664f33041 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -65,7 +65,6 @@ public: virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) override; virtual ModelPointer getModelForEntityItem(EntityItemPointer entityItem) override; - virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem) override; /// clears the tree virtual void clear() override; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index b80a003e8e..84646d7607 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -494,7 +494,7 @@ ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL(), renderer->getEntityLoadingPriority(*this)); _needsInitialSimulation = true; // If we need to change URLs, update it *after rendering* (to avoid access violations) - } else if ((QUrl(getModelURL()) != _model->getURL() || QUrl(getCompoundShapeURL()) != _model->getCollisionURL())) { + } else if (QUrl(getModelURL()) != _model->getURL()) { QMetaObject::invokeMethod(_myRenderer, "updateModel", Qt::QueuedConnection, Q_ARG(ModelPointer, _model), Q_ARG(const QString&, getModelURL()), @@ -566,6 +566,18 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori face, surfaceNormal, extraInfo, precisionPicking); } +void RenderableModelEntityItem::setShapeType(ShapeType type) { + ModelEntityItem::setShapeType(type); + if (_shapeType == SHAPE_TYPE_COMPOUND) { + if (!_compoundShapeResource && !_compoundShapeURL.isEmpty()) { + _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL()); + } + } else if (_compoundShapeResource && !_compoundShapeURL.isEmpty()) { + // the compoundURL has been set but the shapeType does not agree + _compoundShapeResource.reset(); + } +} + void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { auto currentCompoundShapeURL = getCompoundShapeURL(); ModelEntityItem::setCompoundShapeURL(url); @@ -575,6 +587,9 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { if (tree) { QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); } + if (_shapeType == SHAPE_TYPE_COMPOUND) { + _compoundShapeResource = DependencyManager::get()->getGeometryResource(url); + } } } @@ -582,7 +597,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { ShapeType type = getShapeType(); if (type == SHAPE_TYPE_COMPOUND) { - if (!_model || _model->getCollisionURL().isEmpty()) { + if (!_model || _compoundShapeURL.isEmpty()) { EntityTreePointer tree = getTree(); if (tree) { QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); @@ -595,15 +610,18 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { return false; } - if (_model->isLoaded() && _model->isCollisionLoaded()) { - // we have both URLs AND both geometries AND they are both fully loaded. - if (_needsInitialSimulation) { - // the _model's offset will be wrong until _needsInitialSimulation is false - PerformanceTimer perfTimer("_model->simulate"); - doInitialModelSimulation(); + if (_model->isLoaded()) { + if (_compoundShapeResource && _compoundShapeResource->isLoaded()) { + // we have both URLs AND both geometries AND they are both fully loaded. + if (_needsInitialSimulation) { + // the _model's offset will be wrong until _needsInitialSimulation is false + PerformanceTimer perfTimer("_model->simulate"); + doInitialModelSimulation(); + } + return true; + } else if (!_compoundShapeURL.isEmpty()) { + _compoundShapeResource = DependencyManager::get()->getGeometryResource(_compoundShapeURL); } - - return true; } // the model is still being downloaded. @@ -625,8 +643,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { // should never fall in here when collision model not fully loaded // hence we assert that all geometries exist and are loaded - assert(_model && _model->isLoaded() && _model->isCollisionLoaded()); - const FBXGeometry& collisionGeometry = _model->getCollisionFBXGeometry(); + assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded()); + const FBXGeometry& collisionGeometry = _compoundShapeResource->getFBXGeometry(); ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); pointCollection.clear(); @@ -956,8 +974,8 @@ void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) } bool RenderableModelEntityItem::contains(const glm::vec3& point) const { - if (EntityItem::contains(point) && _model && _model->isCollisionLoaded()) { - return _model->getCollisionFBXGeometry().convexHullContains(worldToEntity(point)); + if (EntityItem::contains(point) && _model && _compoundShapeResource && _compoundShapeResource->isLoaded()) { + return _compoundShapeResource->getFBXGeometry().convexHullContains(worldToEntity(point)); } return false; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 16cd9c8bc5..09468dfae0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -56,6 +56,7 @@ public: virtual bool needsToCallUpdate() const override; virtual void update(const quint64& now) override; + virtual void setShapeType(ShapeType type) override; virtual void setCompoundShapeURL(const QString& url) override; virtual bool isReadyToComputeShape() override; @@ -100,6 +101,7 @@ private: QVariantMap parseTexturesToMap(QString textures); void remapTextures(); + GeometryResource::Pointer _compoundShapeResource; ModelPointer _model = nullptr; bool _needsInitialSimulation = true; bool _needsModelReload = true; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 15daf3bf3c..7dc999aac2 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -40,7 +40,6 @@ class EntityItemFBXService { public: virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) = 0; virtual ModelPointer getModelForEntityItem(EntityItemPointer entityItem) = 0; - virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem) = 0; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ce8ebfb00a..d1269f769a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -82,7 +82,6 @@ Model::Model(RigPointer rig, QObject* parent) : _renderGeometry(), _collisionGeometry(), _renderWatcher(_renderGeometry), - _collisionWatcher(_collisionGeometry), _translation(0.0f), _rotation(), _scale(1.0f, 1.0f, 1.0f), @@ -111,7 +110,6 @@ Model::Model(RigPointer rig, QObject* parent) : setSnapModelToRegistrationPoint(true, glm::vec3(0.5f)); connect(&_renderWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished); - connect(&_collisionWatcher, &GeometryResourceWatcher::finished, this, &Model::loadCollisionModelURLFinished); } Model::~Model() { @@ -121,17 +119,15 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; void Model::setShowCollisionMesh(bool value) { - if (_readyToShowCollisionGeometry) { - if (_showCollisionGeometry != value) { - _showCollisionGeometry = value; - _needsFixupInScene = true; - } + if (_showCollisionGeometry != value) { + _showCollisionGeometry = value; + _needsFixupInScene = true; } } bool Model::needsFixupInScene() const { if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { - if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { return true; } if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { @@ -614,13 +610,13 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) { - bool readyToRender = (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) || isLoaded(); + bool readyToRender = (_showCollisionGeometry && _collisionGeometry) || isLoaded(); if (!_addedToScene && readyToRender) { createRenderItemSet(); } bool somethingAdded = false; - if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { if (_collisionRenderItems.empty()) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); @@ -864,23 +860,6 @@ void Model::loadURLFinished(bool success) { emit setURLFinished(success); } -void Model::setCollisionModelURL(const QUrl& url) { - if (_collisionUrl == url && _collisionWatcher.getURL() == url) { - return; - } - _collisionUrl = url; - _collisionGeometryRequestFailed = false; - _collisionWatcher.setResource(DependencyManager::get()->getGeometryResource(url)); -} - -void Model::loadCollisionModelURLFinished(bool success) { - if (!success) { - _collisionGeometryRequestFailed = true; - } - - emit setCollisionModelURLFinished(success); -} - bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { return _rig->getJointPositionInWorldFrame(jointIndex, position, _translation, _rotation); } @@ -1258,7 +1237,7 @@ AABox Model::getRenderableMeshBound() const { } void Model::createRenderItemSet() { - if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { if (_collisionRenderItemsSet.empty()) { createCollisionRenderItemSet(); } @@ -1353,7 +1332,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { render::PendingChanges pendingChanges; bool addedPendingChanges = false; - if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); @@ -1395,14 +1374,8 @@ public: }; void Model::setCollisionMesh(model::MeshPointer mesh) { - _collisionWatcher.stopWatching(); _collisionGeometry = std::make_shared(mesh); - // HACK: we don't want to show the _collisionGeometry until we're ready (e.g. it has been created) - // hence we track whether it has been created using _readyToShowCollisionGeoemtry, because there - // is an ambiguous case where _collisionGeometry is valid (from CompoundURL) but has not yet been - // properly computed (zeroed offset transform) using the CollisionRenderMeshCache. - // // TODO: At the moment we create the collision mesh for every model that has a collision shape // as soon as we know the shape, but we SHOULD only ever create the render mesh when we need it. if (_showCollisionGeometry) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 3fc681261a..edb8f0b6ae 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -115,7 +115,6 @@ public: const QVector& vertices, const QVector& normals); bool isLoaded() const { return (bool)_renderGeometry; } - bool isCollisionLoaded() const { return (bool)_collisionGeometry; } void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } bool isWireframe() const { return _isWireframe; } @@ -142,13 +141,9 @@ public: /// Provided as a convenience, will crash if !isLoaded() // And so that getGeometry() isn't chained everywhere const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return _renderGeometry->getFBXGeometry(); } - /// Provided as a convenience, will crash if !isCollisionLoaded() - const FBXGeometry& getCollisionFBXGeometry() const { assert(isCollisionLoaded()); return _collisionGeometry->getFBXGeometry(); } // Set the model to use for collisions. // Should only be called from the model's rendering thread to avoid access violations of changed geometry. - Q_INVOKABLE void setCollisionModelURL(const QUrl& url); - const QUrl& getCollisionURL() const { return _collisionUrl; } bool isActive() const { return isLoaded(); } @@ -246,7 +241,6 @@ public: public slots: void loadURLFinished(bool success); - void loadCollisionModelURLFinished(bool success); signals: void setURLFinished(bool success); @@ -288,7 +282,6 @@ protected: Geometry::Pointer _collisionGeometry; GeometryResourceWatcher _renderWatcher; - GeometryResourceWatcher _collisionWatcher; glm::vec3 _translation; glm::quat _rotation; @@ -356,7 +349,6 @@ protected: QVector _blendshapeCoefficients; QUrl _url; - QUrl _collisionUrl; bool _isVisible; gpu::Buffers _blendedVertexBuffers; @@ -404,7 +396,6 @@ protected: bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; bool _showCollisionGeometry { false }; - bool _readyToShowCollisionGeometry { false }; mutable bool _needsUpdateTextures { true }; friend class ModelMeshPartPayload; From eb65be5478af994c813b3c3a34a130218d07e9d7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 07:37:54 -0700 Subject: [PATCH 49/71] remove cruft argument from allocateModel() --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 5 ++--- libraries/entities-renderer/src/EntityTreeRenderer.h | 2 +- .../entities-renderer/src/RenderableModelEntityItem.cpp | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 209a27739b..25352255fa 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -503,15 +503,14 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha std::static_pointer_cast(_tree)->processEraseMessage(message, sourceNode); } -ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl, float loadingPriority) { +ModelPointer EntityTreeRenderer::allocateModel(const QString& url, loadingPriority) { ModelPointer model = nullptr; // Only create and delete models on the thread that owns the EntityTreeRenderer if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ModelPointer, model), - Q_ARG(const QString&, url), - Q_ARG(const QString&, collisionUrl)); + Q_ARG(const QString&, url)); return model; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 5664f33041..7ca11ccdbb 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -73,7 +73,7 @@ public: void reloadEntityScripts(); /// if a renderable entity item needs a model, we will allocate it for them - Q_INVOKABLE ModelPointer allocateModel(const QString& url, const QString& collisionUrl, float loadingPriority = 0.0f); + Q_INVOKABLE ModelPointer allocateModel(const QString& url, float loadingPriority = 0.0f); /// if a renderable entity item needs to update the URL of a model, we will handle that for the entity Q_INVOKABLE ModelPointer updateModel(ModelPointer original, const QString& newUrl, const QString& collisionUrl); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 84646d7607..93ad4e17d5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -491,14 +491,13 @@ ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { if (!getModelURL().isEmpty()) { // If we don't have a model, allocate one *immediately* if (!_model) { - _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL(), renderer->getEntityLoadingPriority(*this)); + _model = _myRenderer->allocateModel(getModelURL(), renderer->getEntityLoadingPriority(*this)); _needsInitialSimulation = true; // If we need to change URLs, update it *after rendering* (to avoid access violations) } else if (QUrl(getModelURL()) != _model->getURL()) { QMetaObject::invokeMethod(_myRenderer, "updateModel", Qt::QueuedConnection, Q_ARG(ModelPointer, _model), - Q_ARG(const QString&, getModelURL()), - Q_ARG(const QString&, getCompoundShapeURL())); + Q_ARG(const QString&, getModelURL())); _needsInitialSimulation = true; } // Else we can just return the _model From 68dd66daec3e855344e07ceacb0e54a7ce9c02e4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 09:33:25 -0700 Subject: [PATCH 50/71] create collision render geometry only when needed --- .../src/RenderableModelEntityItem.cpp | 38 +++++++++++------ .../src/RenderableModelEntityItem.h | 1 + libraries/render-utils/src/Model.cpp | 42 +++++-------------- libraries/render-utils/src/Model.h | 3 -- 4 files changed, 37 insertions(+), 47 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 93ad4e17d5..2d03f76ae6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -29,6 +29,9 @@ #include "RenderableModelEntityItem.h" #include "RenderableEntityItem.h" +static CollisionRenderMeshCache collisionMeshCache; + + EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity{ new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()) }; entity->setProperties(properties); @@ -434,11 +437,28 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // Remap textures for the next frame to avoid flicker remapTextures(); - // update whether the model should be showing collision mesh - // (this may flag for fixupInScene) - bool shouldShowCollisionMesh = getShapeType() != SHAPE_TYPE_STATIC_MESH && + // update whether the model should be showing collision mesh (this may flag for fixupInScene) + ShapeType type = getShapeType(); + bool shouldShowCollisionGeometry = type != SHAPE_TYPE_STATIC_MESH && + type != SHAPE_TYPE_NONE && (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; - _model->setShowCollisionMesh(shouldShowCollisionMesh); + if (shouldShowCollisionGeometry != _showCollisionGeometry) { + _showCollisionGeometry = shouldShowCollisionGeometry; + if (_showCollisionGeometry) { + // NOTE: it is OK if _collisionMeshKey is nullptr + model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); + // NOTE: the model will render the collisionGeometry if it has one + _model->setCollisionMesh(mesh); + } else { + // release mesh + if (_collisionMeshKey) { + collisionMeshCache.releaseMesh(_collisionMeshKey); + } + // clear model's collision geometry + model::MeshPointer mesh = nullptr; + _model->setCollisionMesh(mesh); + } + } if (_model->needsFixupInScene()) { render::PendingChanges pendingChanges; @@ -954,21 +974,15 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } -static CollisionRenderMeshCache collisionMeshCache; - void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) { const void* key = static_cast(shape); if (_collisionMeshKey != key) { if (_collisionMeshKey) { - // releasing the shape is not strictly necessary, but - // we do it as hint to the cache's garbage collection system collisionMeshCache.releaseMesh(_collisionMeshKey); } _collisionMeshKey = key; - model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); - if (_model) { - _model->setCollisionMesh(mesh); - } + // toggle _showCollisionGeometry forces re-evaluation later + _showCollisionGeometry = !_showCollisionGeometry; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 09468dfae0..3c2333e679 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -119,6 +119,7 @@ private: bool getAnimationFrame(); bool _needsJointSimulation { false }; + bool _showCollisionGeometry { false }; const void* _collisionMeshKey { nullptr }; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d1269f769a..ca0994b837 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -118,29 +118,8 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; -void Model::setShowCollisionMesh(bool value) { - if (_showCollisionGeometry != value) { - _showCollisionGeometry = value; - _needsFixupInScene = true; - } -} - bool Model::needsFixupInScene() const { - if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { - if (_showCollisionGeometry && _collisionGeometry) { - return true; - } - if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { - if (_needsUpdateTextures) { - if (!_renderGeometry->areTexturesLoaded()) { - return false; - } - _needsUpdateTextures = false; - } - return true; - } - } - return false; + return (_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded(); } // TODO?: should we combine translation and rotation into single method to avoid double-work? @@ -610,13 +589,13 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) { - bool readyToRender = (_showCollisionGeometry && _collisionGeometry) || isLoaded(); + bool readyToRender = _collisionGeometry || isLoaded(); if (!_addedToScene && readyToRender) { createRenderItemSet(); } bool somethingAdded = false; - if (_showCollisionGeometry && _collisionGeometry) { + if (_collisionGeometry) { if (_collisionRenderItems.empty()) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); @@ -1237,7 +1216,7 @@ AABox Model::getRenderableMeshBound() const { } void Model::createRenderItemSet() { - if (_showCollisionGeometry && _collisionGeometry) { + if (_collisionGeometry) { if (_collisionRenderItemsSet.empty()) { createCollisionRenderItemSet(); } @@ -1332,7 +1311,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { render::PendingChanges pendingChanges; bool addedPendingChanges = false; - if (_showCollisionGeometry && _collisionGeometry) { + if (_collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); @@ -1374,13 +1353,12 @@ public: }; void Model::setCollisionMesh(model::MeshPointer mesh) { - _collisionGeometry = std::make_shared(mesh); - - // TODO: At the moment we create the collision mesh for every model that has a collision shape - // as soon as we know the shape, but we SHOULD only ever create the render mesh when we need it. - if (_showCollisionGeometry) { - _needsFixupInScene = true; + if (mesh) { + _collisionGeometry = std::make_shared(mesh); + } else { + _collisionGeometry.reset(); } + _needsFixupInScene = true; } ModelBlender::ModelBlender() : diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index edb8f0b6ae..08a3a2fc54 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -82,8 +82,6 @@ public: void setVisibleInScene(bool newValue, std::shared_ptr scene); bool needsFixupInScene() const; - void setShowCollisionMesh(bool value); - bool readyToAddToScene(RenderArgs* renderArgs = nullptr) const { return !_needsReload && isRenderable() && isActive(); } @@ -395,7 +393,6 @@ protected: bool _needsFixupInScene { true }; // needs to be removed/re-added to scene bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; - bool _showCollisionGeometry { false }; mutable bool _needsUpdateTextures { true }; friend class ModelMeshPartPayload; From 83426fd5a8c0c4804e584fbff2bd24d7800c9baf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 10:30:28 -0700 Subject: [PATCH 51/71] handle transitions to/from STATIC_MESH when rendering collision geometry --- .../src/RenderableModelEntityItem.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 2d03f76ae6..d47c9afab6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -438,13 +438,11 @@ void RenderableModelEntityItem::render(RenderArgs* args) { remapTextures(); // update whether the model should be showing collision mesh (this may flag for fixupInScene) - ShapeType type = getShapeType(); - bool shouldShowCollisionGeometry = type != SHAPE_TYPE_STATIC_MESH && - type != SHAPE_TYPE_NONE && - (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; - if (shouldShowCollisionGeometry != _showCollisionGeometry) { - _showCollisionGeometry = shouldShowCollisionGeometry; - if (_showCollisionGeometry) { + bool showingCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS); + if (showingCollisionGeometry != _showCollisionGeometry) { + ShapeType type = getShapeType(); + _showCollisionGeometry = showingCollisionGeometry; + if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) { // NOTE: it is OK if _collisionMeshKey is nullptr model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); // NOTE: the model will render the collisionGeometry if it has one From 269b7ae7c163644b6b2549b69b0ecfb3d751f9d8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 11:44:54 -0700 Subject: [PATCH 52/71] remove commented out cruft --- libraries/physics/src/CollisionRenderMeshCache.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index 0c789f3da9..910b43996e 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -18,18 +18,6 @@ #include -/* -class btCollisionShape; - -namespace std { - template <> - struct hash { - std::size_t operator()(btCollisionShape* shape) const { - return (hash()((void*)shape)); - } - }; -} -*/ class CollisionRenderMeshCache { public: From 48c73acae0616e674558da5a9871dd960bfd3e28 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 11:46:02 -0700 Subject: [PATCH 53/71] restore privacy of GeometryResourceWatcher methods --- libraries/model-networking/src/model-networking/ModelCache.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index fa93d3c899..bcca846625 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -111,6 +111,7 @@ public: QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); } +private: void startWatching(); void stopWatching(); From e5547122599d5f06d4d93c3e8d1012903c763e9e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 12:07:13 -0700 Subject: [PATCH 54/71] remove entities-renderer dependency on physics lib --- libraries/entities-renderer/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 9218b94fe1..0063f4a701 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME entities-renderer) AUTOSCRIBE_SHADER_LIB(gpu model procedural render render-utils) setup_hifi_library(Widgets Network Script) -link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils physics) +link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils) target_bullet() From d801b3521c66671833b810fa2f42e9a9b0ec5794 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 14:18:39 -0700 Subject: [PATCH 55/71] fix warnings on windows --- libraries/physics/src/CollisionRenderMeshCache.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 8b27bbae24..bd6b761f4e 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -41,7 +41,7 @@ bool copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, { // new part model::Mesh::Part part; - part._startIndex = indices.getNumElements(); + part._startIndex = (model::Index)indices.getNumElements(); part._numIndices = (model::Index)numHullIndices; // FIXME: the render code cannot handle the case where part._baseVertex != 0 //part._baseVertex = vertices.getNumElements(); // DOES NOT WORK @@ -54,7 +54,7 @@ bool copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, } const int32_t SIZE_OF_VEC3 = 3 * sizeof(float); - model::Index indexOffset = vertices.getNumElements(); + model::Index indexOffset = (model::Index)vertices.getNumElements(); { // new indices const uint32_t* hullIndices = hull.getIndexPointer(); @@ -201,7 +201,7 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { } void CollisionRenderMeshCache::collectGarbage() { - uint32_t numShapes = _pendingGarbage.size(); + uint32_t numShapes = (uint32_t)_pendingGarbage.size(); for (uint32_t i = 0; i < numShapes; ++i) { CollisionRenderMeshCache::Key key = _pendingGarbage[i]; CollisionMeshMap::const_iterator itr = _meshMap.find(key); From 2f16aca114194575d734fbd983a8bbb5da9fca01 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Aug 2016 09:57:53 -0700 Subject: [PATCH 56/71] remove cruft and fix typo in rebase --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 ++ libraries/render-utils/src/Model.h | 3 --- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 25352255fa..bc045a99d7 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -503,7 +503,7 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha std::static_pointer_cast(_tree)->processEraseMessage(message, sourceNode); } -ModelPointer EntityTreeRenderer::allocateModel(const QString& url, loadingPriority) { +ModelPointer EntityTreeRenderer::allocateModel(const QString& url, float loadingPriority) { ModelPointer model = nullptr; // Only create and delete models on the thread that owns the EntityTreeRenderer diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index d47c9afab6..3ba48b931d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -180,6 +180,7 @@ void RenderableModelEntityItem::doInitialModelSimulation() { _needsInitialSimulation = false; } +/* // TODO: we need a solution for changes to the postion/rotation/etc of a model... // this current code path only addresses that in this setup case... not the changing/moving case bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) { @@ -197,6 +198,7 @@ bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) { bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(); return ready; } +*/ class RenderableModelEntityItemMeta { public: diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 08a3a2fc54..ff702d1ec5 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -82,9 +82,6 @@ public: void setVisibleInScene(bool newValue, std::shared_ptr scene); bool needsFixupInScene() const; - bool readyToAddToScene(RenderArgs* renderArgs = nullptr) const { - return !_needsReload && isRenderable() && isActive(); - } bool needsReload() const { return _needsReload; } bool initWhenReady(render::ScenePointer scene); bool addToScene(std::shared_ptr scene, From e4317adcf19f24737f282d4fa88e4c25ea8ed3c4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Aug 2016 09:58:39 -0700 Subject: [PATCH 57/71] remove cruft --- .../src/RenderableModelEntityItem.cpp | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 3ba48b931d..970969f1c9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -180,26 +180,6 @@ void RenderableModelEntityItem::doInitialModelSimulation() { _needsInitialSimulation = false; } -/* -// TODO: we need a solution for changes to the postion/rotation/etc of a model... -// this current code path only addresses that in this setup case... not the changing/moving case -bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) { - if (!_model && renderArgs) { - // TODO: this getModel() appears to be about 3% of model render time. We should optimize - PerformanceTimer perfTimer("getModel"); - EntityTreeRenderer* renderer = static_cast(renderArgs->_renderer); - getModel(renderer); - } - if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoaded()) { - // make sure to simulate so everything gets set up correctly for rendering - doInitialModelSimulation(); - _model->renderSetup(renderArgs); - } - bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(); - return ready; -} -*/ - class RenderableModelEntityItemMeta { public: RenderableModelEntityItemMeta(EntityItemPointer entity) : entity(entity){ } From acaa77b75a3ea064575fde92e48d19892d390cd9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 22 Aug 2016 09:06:13 -0700 Subject: [PATCH 58/71] remove cruft from debug efforts --- libraries/entities/src/EntityItem.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 1ad1d938a7..e572bf4de8 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -327,10 +327,6 @@ public: virtual void setCollisionShape(const btCollisionShape* shape) {} - // these are only needed because the names don't match - virtual const glm::quat getRotation() const { return getOrientation(); } - virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } - // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags virtual void updateRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); From 19cd4648adfd8216cc30f71e42a295a407bede03 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 24 Aug 2016 11:21:47 -0700 Subject: [PATCH 59/71] scale collision render mesh correctly --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/physics/src/CollisionRenderMeshCache.cpp | 4 ---- libraries/render-utils/src/Model.cpp | 9 +++++++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 29cbfd79e6..68636415f8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2213,4 +2213,4 @@ void EntityItem::globalizeProperties(EntityItemProperties& properties, const QSt } QUuid empty; properties.setParentID(empty); -} \ No newline at end of file +} diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index bd6b761f4e..517e25e1c4 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -190,10 +190,6 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { } CollisionMeshMap::const_iterator itr = _meshMap.find(key); if (itr != _meshMap.end()) { - // we hold at least one reference, and the outer scope also holds at least one - // so we assert that the reference count is not 1 - assert((*itr).second.use_count() != 1); - _pendingGarbage.push_back(key); return true; } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ca0994b837..6f435b2c8d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -166,6 +166,11 @@ void Model::updateRenderItems() { return; } + glm::vec3 scale = getScale(); + if (_collisionGeometry) { + // _collisionGeometry is already scaled + scale = glm::vec3(1.0f); + } _needsUpdateClusterMatrices = true; _renderItemsNeedUpdate = false; @@ -173,7 +178,7 @@ void Model::updateRenderItems() { // the application will ensure only the last lambda is actually invoked. void* key = (void*)this; std::weak_ptr weakSelf = shared_from_this(); - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() { // do nothing, if the model has already been destroyed. auto self = weakSelf.lock(); @@ -184,7 +189,7 @@ void Model::updateRenderItems() { render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); Transform modelTransform; - modelTransform.setScale(self->_scale); + modelTransform.setScale(scale); modelTransform.setTranslation(self->_translation); modelTransform.setRotation(self->_rotation); From 502146b1718df33b43ca9505d41185073c6dc194 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 24 Aug 2016 17:50:13 -0700 Subject: [PATCH 60/71] distribute reg offset to compound children --- libraries/physics/src/ShapeFactory.cpp | 28 ++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index f11b0f95dc..a67e0053da 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -346,14 +346,26 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) } if (shape) { if (glm::length2(info.getOffset()) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET) { - // this shape has an offset, which we support by wrapping the true shape - // in a btCompoundShape with a local transform - auto compound = new btCompoundShape(); - btTransform trans; - trans.setIdentity(); - trans.setOrigin(glmToBullet(info.getOffset())); - compound->addChildShape(trans, shape); - shape = compound; + // we need to apply an offset + btTransform offset; + offset.setIdentity(); + offset.setOrigin(glmToBullet(info.getOffset())); + + if (shape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) { + // this shape is already compound + // walk through the child shapes and adjust their transforms + btCompoundShape* compound = static_cast(shape); + int32_t numSubShapes = compound->getNumChildShapes(); + for (int32_t i = 0; i < numSubShapes; ++i) { + compound->updateChildTransform(i, offset * compound->getChildTransform(i), false); + } + compound->recalculateLocalAabb(); + } else { + // wrap this shape in a compound + auto compound = new btCompoundShape(); + compound->addChildShape(offset, shape); + shape = compound; + } } } return shape; From b95cb566cd377a6ff968ede4852c3bd9b5eda5f6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 24 Aug 2016 17:51:33 -0700 Subject: [PATCH 61/71] fix collision mesh for non-trivial registration --- .../src/RenderableModelEntityItem.cpp | 34 ++++++++++--------- .../src/RenderableModelEntityItem.h | 2 +- libraries/render-utils/src/Model.cpp | 9 ++++- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 970969f1c9..fc3245f322 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -631,7 +631,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { return true; } -void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { +void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { const uint32_t TRIANGLE_STRIDE = 3; const uint32_t QUAD_STRIDE = 4; @@ -645,7 +645,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded()); const FBXGeometry& collisionGeometry = _compoundShapeResource->getFBXGeometry(); - ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); + ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection(); pointCollection.clear(); uint32_t i = 0; @@ -721,15 +721,14 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 scaleToFit = dimensions / _model->getFBXGeometry().getUnscaledMeshExtents().size(); // multiply each point by scale before handing the point-set off to the physics engine. // also determine the extents of the collision model. + glm::vec3 registrationOffset = dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()); for (int32_t i = 0; i < pointCollection.size(); i++) { for (int32_t j = 0; j < pointCollection[i].size(); j++) { - // compensate for registration - pointCollection[i][j] += _model->getOffset(); - // scale so the collision points match the model points - pointCollection[i][j] *= scaleToFit; + // back compensate for registration so we can apply that offset to the shapeInfo later + pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + _model->getOffset()) - registrationOffset; } } - info.setParams(type, dimensions, _compoundShapeURL); + shapeInfo.setParams(type, dimensions, _compoundShapeURL); } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) { // should never fall in here when model not fully loaded assert(_model && _model->isLoaded()); @@ -742,29 +741,31 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { const FBXGeometry& fbxGeometry = _model->getFBXGeometry(); int numFbxMeshes = fbxGeometry.meshes.size(); int totalNumVertices = 0; + glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT)); for (int i = 0; i < numFbxMeshes; i++) { const FBXMesh& mesh = fbxGeometry.meshes.at(i); if (mesh.clusters.size() > 0) { const FBXCluster& cluster = mesh.clusters.at(0); auto jointMatrix = _model->getRig()->getJointTransform(cluster.jointIndex); - localTransforms.push_back(jointMatrix * cluster.inverseBindMatrix); + // we backtranslate by the registration offset so we can apply that offset to the shapeInfo later + localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix); } else { glm::mat4 identity; - localTransforms.push_back(identity); + localTransforms.push_back(invRegistraionOffset); } totalNumVertices += mesh.vertices.size(); } const int32_t MAX_VERTICES_PER_STATIC_MESH = 1e6; if (totalNumVertices > MAX_VERTICES_PER_STATIC_MESH) { qWarning() << "model" << getModelURL() << "has too many vertices" << totalNumVertices << "and will collide as a box."; - info.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions); + shapeInfo.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions); return; } auto& meshes = _model->getGeometry()->getMeshes(); int32_t numMeshes = (int32_t)(meshes.size()); - ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); + ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection(); pointCollection.clear(); if (type == SHAPE_TYPE_SIMPLE_COMPOUND) { pointCollection.resize(numMeshes); @@ -772,7 +773,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { pointCollection.resize(1); } - ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices(); + ShapeInfo::TriangleIndices& triangleIndices = shapeInfo.getTriangleIndices(); triangleIndices.clear(); Extents extents; @@ -946,12 +947,13 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } - info.setParams(type, 0.5f * dimensions, _modelURL); + shapeInfo.setParams(type, 0.5f * dimensions, _modelURL); } else { - ModelEntityItem::computeShapeInfo(info); - info.setParams(type, 0.5f * dimensions); - adjustShapeInfoByRegistration(info); + ModelEntityItem::computeShapeInfo(shapeInfo); + shapeInfo.setParams(type, 0.5f * dimensions); } + // finally apply the registration offset to the shapeInfo + adjustShapeInfoByRegistration(shapeInfo); } void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 3c2333e679..e785e61d22 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -60,7 +60,7 @@ public: virtual void setCompoundShapeURL(const QString& url) override; virtual bool isReadyToComputeShape() override; - virtual void computeShapeInfo(ShapeInfo& info) override; + virtual void computeShapeInfo(ShapeInfo& shapeInfo) override; void setCollisionShape(const btCollisionShape* shape) override; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 6f435b2c8d..3a7308c277 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1284,6 +1284,11 @@ void Model::createCollisionRenderItemSet() { // We should not have any existing renderItems if we enter this section of code Q_ASSERT(_collisionRenderItemsSet.isEmpty()); + Transform identity; + identity.setIdentity(); + Transform offset; + offset.postTranslate(_offset); + // Run through all of the meshes, and place them into their segregated, but unsorted buckets uint32_t numMeshes = (uint32_t)meshes.size(); for (uint32_t i = 0; i < numMeshes; i++) { @@ -1296,7 +1301,9 @@ void Model::createCollisionRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { model::MaterialPointer& material = _collisionMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; - _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material); + auto payload = std::make_shared(mesh, partIndex, material); + payload->updateTransform(identity, offset); + _collisionRenderItemsSet << payload; } } } From c337cc92e5ebc8ef805ae3d5152c80cf0325feae Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Aug 2016 08:51:53 -0700 Subject: [PATCH 62/71] remove crufty comment --- libraries/render-utils/src/Model.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index ff702d1ec5..7a193b1d47 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -137,9 +137,6 @@ public: // And so that getGeometry() isn't chained everywhere const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return _renderGeometry->getFBXGeometry(); } - // Set the model to use for collisions. - // Should only be called from the model's rendering thread to avoid access violations of changed geometry. - bool isActive() const { return isLoaded(); } bool didVisualGeometryRequestFail() const { return _visualGeometryRequestFailed; } @@ -176,6 +173,7 @@ public: bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; + /// \param jointIndex index of joint in model structure /// \param rotation[out] rotation of joint in model-frame /// \return true if joint exists From d7bb5559877b21f7bfe6df3254a7e30012273a6b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Aug 2016 08:53:08 -0700 Subject: [PATCH 63/71] make menu wording more correct --- interface/src/Menu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d47b6842a5..ee00644746 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -137,7 +137,7 @@ namespace MenuOption { const QString Overlays = "Overlays"; const QString PackageModel = "Package Model..."; const QString Pair = "Pair"; - const QString PhysicsShowHulls = "Draw Collision Hulls"; + const QString PhysicsShowHulls = "Draw Collision Shapes"; const QString PhysicsShowOwned = "Highlight Simulation Ownership"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString Preferences = "General..."; From 13a12a2a13279f45dd20659380786966ca19f56f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 11 Aug 2016 18:07:29 -0700 Subject: [PATCH 64/71] Script.include() default scripts not Script.load() --- scripts/defaultScripts.js | 90 ++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 5aa3c6945b..c7ea18d883 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -8,25 +8,75 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +var DEFAULT_SCRIPTS = [ + "system/progress.js", + "system/away.js", + "system/users.js", + "system/mute.js", + "system/goto.js", + "system/hmd.js", + "system/marketplaces/marketplace.js", + "system/edit.js", + "system/mod.js", + "system/selectAudioDevice.js", + "system/notifications.js", + "system/controllers/handControllerGrab.js", + "system/controllers/handControllerPointer.js", + "system/controllers/squeezeHands.js", + "system/controllers/grab.js", + "system/controllers/teleport.js", + "system/controllers/toggleAdvancedMovementForHandControllers.js, + "system/dialTone.js", + "system/firstPersonHMD.js", + "system/snapshot.js" +]; -Script.load("system/progress.js"); -Script.load("system/away.js"); -Script.load("system/users.js"); -Script.load("system/mute.js"); -Script.load("system/goto.js"); -Script.load("system/hmd.js"); -Script.load("system/marketplaces/marketplace.js"); -Script.load("system/edit.js"); -Script.load("system/mod.js"); -Script.load("system/selectAudioDevice.js"); -Script.load("system/notifications.js"); -Script.load("system/controllers/handControllerGrab.js"); -Script.load("system/controllers/handControllerPointer.js"); -Script.load("system/controllers/squeezeHands.js"); -Script.load("system/controllers/grab.js"); -Script.load("system/controllers/teleport.js"); -Script.load("system/controllers/toggleAdvancedMovementForHandControllers.js") -Script.load("system/dialTone.js"); -Script.load("system/firstPersonHMD.js"); -Script.load("system/snapshot.js"); +// add a menu item for debugging +var MENU_CATEGORY = "Developer" +var MENU_ITEM = "Debug defaultScripts.js"; +var debuggingDefaultScripts = false; +if (Menu.menuExists(MENU_CATEGORY) && !Menu.menuItemExists(MENU_CATEGORY, MENU_ITEM)) { + Menu.addMenuItem({ + menuName: MENU_CATEGORY, + menuItemName: MENU_ITEM, + isCheckable: true, + isChecked: false, + grouping: "Advanced" + }); +} + +// start all scripts +if (Menu.isOptionChecked(MENU_ITEM)) { + // we're debugging individual default scripts + // so we load each into its own ScriptEngine instance + debuggingDefaultScripts = true; + for (var i in DEFAULT_SCRIPTS) { + Script.load(DEFAULT_SCRIPTS[i]); + } +} else { + // include all default scripts into this ScriptEngine + for (var i in DEFAULT_SCRIPTS) { + Script.include(DEFAULT_SCRIPTS[i]); + } +} + +function stopLoadedScripts() { + if (debuggingDefaultScripts) { + // remove debug script loads + var runningScripts = ScriptDiscoveryService.getRunning(); + for (var i in runningScripts) { + var scriptName = runningScripts[i].name; + for (var j in DEFAULT_SCRIPTS) { + if (DEFAULT_SCRIPTS[j].slice(-scriptName.length) == scriptName) { + ScriptDiscoveryService.stopScript(runningScripts[i].url); + } + } + } + if (!Menu.isOptionChecked(MENU_ITEM)) { + Menu.removeMenuItem(MENU_CATEGORY, MENU_ITEM); + } + } +} + +Script.scriptEnding.connect(stopLoadedScripts); From 3690b38c65b2cb870a67c0854fa98b3276e9032f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 22 Aug 2016 14:47:50 -0700 Subject: [PATCH 65/71] fix warnings found by eslint in defaultScripts.js --- scripts/defaultScripts.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index c7ea18d883..444816dfd7 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -32,7 +32,7 @@ var DEFAULT_SCRIPTS = [ ]; // add a menu item for debugging -var MENU_CATEGORY = "Developer" +var MENU_CATEGORY = "Developer"; var MENU_ITEM = "Debug defaultScripts.js"; var debuggingDefaultScripts = false; @@ -56,8 +56,8 @@ if (Menu.isOptionChecked(MENU_ITEM)) { } } else { // include all default scripts into this ScriptEngine - for (var i in DEFAULT_SCRIPTS) { - Script.include(DEFAULT_SCRIPTS[i]); + for (var j in DEFAULT_SCRIPTS) { + Script.include(DEFAULT_SCRIPTS[j]); } } @@ -68,7 +68,7 @@ function stopLoadedScripts() { for (var i in runningScripts) { var scriptName = runningScripts[i].name; for (var j in DEFAULT_SCRIPTS) { - if (DEFAULT_SCRIPTS[j].slice(-scriptName.length) == scriptName) { + if (DEFAULT_SCRIPTS[j].slice(-scriptName.length) === scriptName) { ScriptDiscoveryService.stopScript(runningScripts[i].url); } } From 6f6a7bcc44452f24a920ca50e0682f5e60125754 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 23 Aug 2016 12:34:32 -0700 Subject: [PATCH 66/71] wrap default scripts with local scope --- scripts/defaultScripts.js | 3 +++ scripts/system/away.js | 23 ++++++++++------ scripts/system/controllers/grab.js | 17 +++++++----- .../system/controllers/handControllerGrab.js | 10 +++---- .../controllers/handControllerPointer.js | 8 +++--- scripts/system/controllers/squeezeHands.js | 6 +++++ scripts/system/controllers/teleport.js | 9 +++++-- ...oggleAdvancedMovementForHandControllers.js | 16 ++++++++---- scripts/system/dialTone.js | 8 ++++-- scripts/system/edit.js | 11 ++++---- scripts/system/firstPersonHMD.js | 6 +++++ scripts/system/goto.js | 6 +++++ scripts/system/hmd.js | 11 +++++--- scripts/system/marketplaces/clara.js | 6 +++++ scripts/system/mod.js | 12 ++++++--- scripts/system/mute.js | 9 +++++-- scripts/system/notifications.js | 18 ++++++++----- scripts/system/progress.js | 7 +++-- scripts/system/selectAudioDevice.js | 26 ++++++++++++------- scripts/system/users.js | 6 +++++ 20 files changed, 156 insertions(+), 62 deletions(-) diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 444816dfd7..dc0f1217c6 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -1,3 +1,6 @@ +"use strict"; +/* jslint vars: true, plusplus: true */ + // // defaultScripts.js // examples diff --git a/scripts/system/away.js b/scripts/system/away.js index 290cda0d64..716fe1340e 100644 --- a/scripts/system/away.js +++ b/scripts/system/away.js @@ -1,8 +1,8 @@ "use strict"; -/*jslint vars: true, plusplus: true*/ -/*global HMD, AudioDevice, MyAvatar, Controller, Script, Overlays, print*/ + // // away.js +// // examples // // Created by Howard Stearns 11/3/15 @@ -13,9 +13,11 @@ // // Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key. // See MAIN CONTROL, below, for what "paused" actually does. + +(function() { // BEGIN LOCAL_SCOPE + var OVERLAY_WIDTH = 1920; var OVERLAY_HEIGHT = 1080; -var OVERLAY_RATIO = OVERLAY_WIDTH / OVERLAY_HEIGHT; var OVERLAY_DATA = { width: OVERLAY_WIDTH, height: OVERLAY_HEIGHT, @@ -51,7 +53,11 @@ var AWAY_INTRO = { var _animation = AnimationCache.prefetch(AWAY_INTRO.url); function playAwayAnimation() { - MyAvatar.overrideAnimation(AWAY_INTRO.url, AWAY_INTRO.playbackRate, AWAY_INTRO.loopFlag, AWAY_INTRO.startFrame, AWAY_INTRO.endFrame); + MyAvatar.overrideAnimation(AWAY_INTRO.url, + AWAY_INTRO.playbackRate, + AWAY_INTRO.loopFlag, + AWAY_INTRO.startFrame, + AWAY_INTRO.endFrame); } function stopAwayAnimation() { @@ -74,8 +80,6 @@ function moveCloserToCamera(positionAtHUD) { } function showOverlay() { - var properties = {visible: true}; - if (HMD.active) { // make sure desktop version is hidden Overlays.editOverlay(overlay, { visible: false }); @@ -252,8 +256,9 @@ function maybeGoAway() { } } - // If the mouse has gone from captured, to non-captured state, then it likely means the person is still in the HMD, but - // tabbed away from the application (meaning they don't have mouse control) and they likely want to go into an away state + // If the mouse has gone from captured, to non-captured state, then it likely means the person is still in the HMD, + // but tabbed away from the application (meaning they don't have mouse control) and they likely want to go into + // an away state if (Reticle.mouseCaptured !== wasMouseCaptured) { wasMouseCaptured = !wasMouseCaptured; if (!wasMouseCaptured) { @@ -298,3 +303,5 @@ Script.scriptEnding.connect(function () { Controller.mousePressEvent.disconnect(goActive); Controller.keyPressEvent.disconnect(maybeGoActive); }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index ef39e95880..dc57fe4451 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -1,3 +1,5 @@ +"use strict"; + // grab.js // examples // @@ -9,7 +11,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/*global print, Mouse, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ + +(function() { // BEGIN LOCAL_SCOPE Script.include("../libraries/utils.js"); // objects that appear smaller than this can't be grabbed @@ -344,7 +347,6 @@ Grabber.prototype.pressEvent = function(event) { mouse.startDrag(event); - var now = Date.now(); this.lastHeartBeat = 0; var clickedEntity = pickResults.entityID; @@ -385,7 +387,7 @@ Grabber.prototype.pressEvent = function(event) { beacon.updatePosition(this.startPosition); - if(!entityIsGrabbedByOther(this.entityID)){ + if (!entityIsGrabbedByOther(this.entityID)) { this.moveEvent(event); } @@ -452,7 +454,7 @@ Grabber.prototype.moveEvent = function(event) { // see if something added/restored gravity var entityProperties = Entities.getEntityProperties(this.entityID); - if (Vec3.length(entityProperties.gravity) != 0) { + if (Vec3.length(entityProperties.gravity) !== 0.0) { this.originalGravity = entityProperties.gravity; } this.currentPosition = entityProperties.position; @@ -500,7 +502,8 @@ Grabber.prototype.moveEvent = function(event) { }; } else { var cameraPosition = Camera.getPosition(); - newPointOnPlane = mouseIntersectionWithPlane(this.pointOnPlane, this.planeNormal, mouse.current, this.maxDistance); + newPointOnPlane = mouseIntersectionWithPlane( + this.pointOnPlane, this.planeNormal, mouse.current, this.maxDistance); var relativePosition = Vec3.subtract(newPointOnPlane, cameraPosition); var distance = Vec3.length(relativePosition); if (distance > this.maxDistance) { @@ -625,7 +628,7 @@ function editEvent(channel, message, sender, localOnly) { return; } try { - data = JSON.parse(message); + var data = JSON.parse(message); if ("enabled" in data) { enabled = !data["enabled"]; } @@ -640,3 +643,5 @@ Controller.keyPressEvent.connect(keyPressEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent); Messages.subscribe("edit-events"); Messages.messageReceived.connect(editEvent); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index ac1c844cc9..32e0b047de 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1,4 +1,5 @@ "use strict"; + // handControllerGrab.js // // Created by Eric Levin on 9/2/15 @@ -10,7 +11,8 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global setEntityCustomData, getEntityCustomData, vec3toStr, flatten, Xform */ + +(function() { // BEGIN LOCAL_SCOPE Script.include("/~/system/libraries/utils.js"); Script.include("/~/system/libraries/Xform.js"); @@ -26,8 +28,6 @@ var WANT_DEBUG_SEARCH_NAME = null; // these tune time-averaging and "on" value for analog trigger // -var SPARK_MODEL_SCALE_FACTOR = 0.75; - var TRIGGER_SMOOTH_RATIO = 0.1; // Time averaging of trigger - 0.0 disables smoothing var TRIGGER_OFF_VALUE = 0.1; var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab @@ -88,7 +88,6 @@ var COLORS_GRAB_DISTANCE_HOLD = { }; -var LINE_LENGTH = 500; var PICK_MAX_DISTANCE = 500; // max length of pick-ray // @@ -129,7 +128,6 @@ var ZERO_VEC = { var NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; // these control how long an abandoned pointer line or action will hang around -var LIFETIME = 10; var ACTION_TTL = 15; // seconds var ACTION_TTL_REFRESH = 5; var PICKS_PER_SECOND_PER_HAND = 60; @@ -2643,3 +2641,5 @@ function cleanup() { Script.scriptEnding.connect(cleanup); Script.update.connect(update); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index 5888b53a27..6b62674be5 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -1,6 +1,4 @@ "use strict"; -/*jslint vars: true, plusplus: true*/ -/*globals Script, Overlays, Controller, Reticle, HMD, Camera, Entities, MyAvatar, Settings, Menu, ScriptDiscoveryService, Window, Vec3, Quat, print*/ // // handControllerPointer.js @@ -13,6 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + // Control the "mouse" using hand controller. (HMD and desktop.) // First-person only. // Starts right handed, but switches to whichever is free: Whichever hand was NOT most recently squeezed. @@ -440,7 +440,7 @@ function clearSystemLaser() { HMD.disableHandLasers(BOTH_HUD_LASERS); systemLaserOn = false; weMovedReticle = true; - Reticle.position = { x: -1, y: -1 }; + Reticle.position = { x: -1, y: -1 }; } function setColoredLaser() { // answer trigger state if lasers supported, else falsey. var color = (activeTrigger.state === 'full') ? LASER_TRIGGER_COLOR_XYZW : LASER_SEARCH_COLOR_XYZW; @@ -508,3 +508,5 @@ Script.scriptEnding.connect(function () { Script.clearInterval(settingsChecker); OffscreenFlags.navigationFocusDisabled = false; }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/controllers/squeezeHands.js b/scripts/system/controllers/squeezeHands.js index f549f911c9..f06529f2b2 100644 --- a/scripts/system/controllers/squeezeHands.js +++ b/scripts/system/controllers/squeezeHands.js @@ -1,3 +1,5 @@ +"use strict"; + // // controllers/squeezeHands.js // @@ -10,6 +12,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + var lastLeftTrigger = 0; var lastRightTrigger = 0; var leftHandOverlayAlpha = 0; @@ -82,3 +86,5 @@ function shutdown() { Script.scriptEnding.connect(shutdown); init(); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index 0aa5820b0f..f3e94d23de 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -1,3 +1,5 @@ +"use strict"; + // Created by james b. pollack @imgntn on 7/2/2016 // Copyright 2016 High Fidelity, Inc. // @@ -6,6 +8,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +(function() { // BEGIN LOCAL_SCOPE + var inTeleportMode = false; var SMOOTH_ARRIVAL_SPACING = 33; @@ -594,7 +598,6 @@ function getAvatarFootOffset() { } }) - var myPosition = MyAvatar.position; var offset = upperLeg + lowerLeg + foot + toe + toeTop; offset = offset / 100; return offset; @@ -737,4 +740,6 @@ var handleHandMessages = function(channel, message, sender) { } Messages.subscribe('Hifi-Teleport-Disabler'); -Messages.messageReceived.connect(handleHandMessages); \ No newline at end of file +Messages.messageReceived.connect(handleHandMessages); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js index 3a75482770..f5ab42cf53 100644 --- a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js +++ b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js @@ -1,14 +1,18 @@ +"use strict"; + // Created by james b. pollack @imgntn on 8/18/2016 // Copyright 2016 High Fidelity, Inc. // -//advanced movements settings are in individual controller json files -//what we do is check the status of the 'advance movement' checkbox when you enter HMD mode -//if 'advanced movement' is checked...we give you the defaults that are in the json. -//if 'advanced movement' is not checked... we override the advanced controls with basic ones. +// advanced movements settings are in individual controller json files +// what we do is check the status of the 'advance movement' checkbox when you enter HMD mode +// if 'advanced movement' is checked...we give you the defaults that are in the json. +// if 'advanced movement' is not checked... we override the advanced controls with basic ones. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +(function() { // BEGIN LOCAL_SCOPE + var mappingName, basicMapping, isChecked; var TURN_RATE = 1000; @@ -138,4 +142,6 @@ HMD.displayModeChanged.connect(function(isHMDMode) { } } -}); \ No newline at end of file +}); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/dialTone.js b/scripts/system/dialTone.js index 64ef62d61a..02624645d5 100644 --- a/scripts/system/dialTone.js +++ b/scripts/system/dialTone.js @@ -1,3 +1,5 @@ +"use strict"; + // // dialTone.js // examples @@ -10,9 +12,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + // setup the local sound we're going to use - - var connectSound = SoundCache.getSound(Script.resolvePath("assets/sounds/hello.wav")); var disconnectSound = SoundCache.getSound(Script.resolvePath("assets/sounds/goodbye.wav")); var micMutedSound = SoundCache.getSound(Script.resolvePath("assets/sounds/goodbye.wav")); @@ -36,3 +38,5 @@ AudioDevice.muteToggled.connect(function () { Audio.playSound(micMutedSound, soundOptions); } }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/edit.js b/scripts/system/edit.js index d34d4acffc..bcf31726bc 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -1,3 +1,5 @@ +"use strict"; + // newEditEntities.js // examples // @@ -11,13 +13,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var EDIT_TOGGLE_BUTTON = "com.highfidelity.interface.system.editButton"; var SYSTEM_TOOLBAR = "com.highfidelity.interface.toolbar.system"; var EDIT_TOOLBAR = "com.highfidelity.interface.toolbar.edit"; -/* globals SelectionDisplay, SelectionManager, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Toolbars, - progressDialog, tooltip, ParticleExplorerTool */ Script.include([ "libraries/stringHelpers.js", "libraries/dataViewHelpers.js", @@ -94,7 +96,6 @@ var SHOULD_SHOW_PROPERTY_MENU = false; var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain."; var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain."; -var mode = 0; var isActive = false; var IMPORTING_SVO_OVERLAY_WIDTH = 144; @@ -502,8 +503,6 @@ var orientation; var intersection; -var SCALE_FACTOR = 200.0; - function rayPlaneIntersection(pickRay, point, normal) { // // // This version of the test returns the intersection of a line with a plane @@ -1726,3 +1725,5 @@ entityListTool.webView.webEventReceived.connect(function (data) { } } }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/firstPersonHMD.js b/scripts/system/firstPersonHMD.js index 082c6304be..5fdee1b7b5 100644 --- a/scripts/system/firstPersonHMD.js +++ b/scripts/system/firstPersonHMD.js @@ -1,3 +1,5 @@ +"use strict"; + // // firstPersonHMD.js // system @@ -9,9 +11,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + // Automatically enter first person mode when entering HMD mode HMD.displayModeChanged.connect(function(isHMDMode) { if (isHMDMode) { Camera.setModeString("first person"); } }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/goto.js b/scripts/system/goto.js index 2ed98c689b..9116142293 100644 --- a/scripts/system/goto.js +++ b/scripts/system/goto.js @@ -1,3 +1,5 @@ +"use strict"; + // // goto.js // scripts/system/ @@ -9,6 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); @@ -38,3 +42,5 @@ Script.scriptEnding.connect(function () { button.clicked.disconnect(onClicked); DialogsManager.addressBarShown.disconnect(onAddressBarShown); }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/hmd.js b/scripts/system/hmd.js index ac1918b001..84ff6b3c89 100644 --- a/scripts/system/hmd.js +++ b/scripts/system/hmd.js @@ -1,3 +1,5 @@ +"use strict"; + // // hmd.js // scripts/system/ @@ -9,6 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + var headset; // The preferred headset. Default to the first one found in the following list. var displayMenuName = "Display"; var desktopMenuItemName = "Desktop"; @@ -36,13 +40,13 @@ if (headset) { visible: true, hoverState: 2, defaultState: 0, - alpha: 0.9, + alpha: 0.9 }); onHmdChanged(HMD.active); - + button.clicked.connect(onClicked); HMD.displayModeChanged.connect(onHmdChanged); - + Script.scriptEnding.connect(function () { toolBar.removeButton("hmdToggle"); button.clicked.disconnect(onClicked); @@ -50,3 +54,4 @@ if (headset) { }); } +}()); // END LOCAL_SCOPE diff --git a/scripts/system/marketplaces/clara.js b/scripts/system/marketplaces/clara.js index 7b48f49135..67c2d5503c 100644 --- a/scripts/system/marketplaces/clara.js +++ b/scripts/system/marketplaces/clara.js @@ -1,3 +1,5 @@ +"use strict"; + // // clara.js // @@ -9,6 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + var toolIconUrl = Script.resolvePath("../assets/images/tools/"); var qml = Script.resolvePath("../../../resources/qml/MarketplaceComboBox.qml") @@ -77,3 +81,5 @@ Script.scriptEnding.connect(function () { browseExamplesButton.clicked.disconnect(onClick); marketplaceWindow.visibleChanged.disconnect(onExamplesWindowVisibilityChanged); }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/mod.js b/scripts/system/mod.js index 43afb94c9d..e69c2ce2f6 100644 --- a/scripts/system/mod.js +++ b/scripts/system/mod.js @@ -1,3 +1,5 @@ +"use strict"; + // // mod.js // scripts/system/ @@ -9,6 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + // grab the toolbar var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); @@ -39,7 +43,7 @@ function removeOverlays() { // enumerate the overlays and remove them var modOverlayKeys = Object.keys(modOverlays); - for (i = 0; i < modOverlayKeys.length; ++i) { + for (var i = 0; i < modOverlayKeys.length; ++i) { var avatarID = modOverlayKeys[i]; Overlays.deleteOverlay(modOverlays[avatarID]); } @@ -72,7 +76,7 @@ function updateOverlays() { var identifiers = AvatarList.getAvatarIdentifiers(); - for (i = 0; i < identifiers.length; ++i) { + for (var i = 0; i < identifiers.length; ++i) { var avatarID = identifiers[i]; if (avatarID === null) { @@ -138,7 +142,7 @@ function handleSelectedOverlay(clickedOverlay) { // see this is one of our mod overlays var modOverlayKeys = Object.keys(modOverlays) - for (i = 0; i < modOverlayKeys.length; ++i) { + for (var i = 0; i < modOverlayKeys.length; ++i) { var avatarID = modOverlayKeys[i]; var modOverlay = modOverlays[avatarID]; @@ -214,3 +218,5 @@ Script.scriptEnding.connect(function() { removeOverlays(); triggerMapping.disable(); }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/mute.js b/scripts/system/mute.js index 4ea8aee546..722ed65b3d 100644 --- a/scripts/system/mute.js +++ b/scripts/system/mute.js @@ -1,3 +1,5 @@ +"use strict"; + // // goto.js // scripts/system/ @@ -9,8 +11,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); +(function() { // BEGIN LOCAL_SCOPE +var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); var button = toolBar.addButton({ objectName: "mute", @@ -33,7 +36,7 @@ function onMuteToggled() { } onMuteToggled(); function onClicked(){ - var menuItem = "Mute Microphone"; + var menuItem = "Mute Microphone"; Menu.setIsOptionChecked(menuItem, !Menu.isOptionChecked(menuItem)); } button.clicked.connect(onClicked); @@ -44,3 +47,5 @@ Script.scriptEnding.connect(function () { button.clicked.disconnect(onClicked); AudioDevice.muteToggled.disconnect(onMuteToggled); }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 34f9814d8a..673b48961d 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -1,3 +1,5 @@ +"use strict"; + // // notifications.js // Version 0.801 @@ -56,6 +58,8 @@ // } // } +(function() { // BEGIN LOCAL_SCOPE + Script.include("./libraries/soundArray.js"); var width = 340.0; //width of notification overlay @@ -105,7 +109,7 @@ var NotificationType = { return NotificationType.UNKNOWN; } var preMenuItemName = menuItemName.substr(0, menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length); - for (type in this.properties) { + for (var type in this.properties) { if (this.properties[type].text === preMenuItemName) { return parseInt(type) + 1; } @@ -120,7 +124,7 @@ var NotificationType = { var randomSounds = new SoundArray({ localOnly: true }, true); var numberOfSounds = 2; for (var i = 1; i <= numberOfSounds; i++) { - + randomSounds.addSound(Script.resolvePath("assets/sounds/notification-general"+ i + ".raw")); } @@ -230,9 +234,9 @@ function calculate3DOverlayPositions(noticeWidth, noticeHeight, y) { }; } -// Pushes data to each array and sets up data for 2nd dimension array +// Pushes data to each array and sets up data for 2nd dimension array // to handle auxiliary data not carried by the overlay class -// specifically notification "heights", "times" of creation, and . +// specifically notification "heights", "times" of creation, and . function notify(notice, button, height, imageProperties, image) { var notificationText, noticeWidth, @@ -584,7 +588,7 @@ function setup() { isChecked: Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING) }); Menu.addSeparator(MENU_NAME, "Play sounds for:"); - for (type in NotificationType.properties) { + for (var type in NotificationType.properties) { checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + (parseInt(type) + 1)); checked = checked === '' ? true : checked; Menu.addMenuItem({ @@ -620,7 +624,7 @@ LODManager.LODDecreased.connect(function() { var warningText = "\n" + "Due to the complexity of the content, the \n" + "level of detail has been decreased. " - + "You can now see: \n" + + "You can now see: \n" + LODManager.getLODFeedbackText(); if (lodTextID == false) { @@ -641,3 +645,5 @@ Window.domainConnectionRefused.connect(onDomainConnectionRefused); Window.snapshotTaken.connect(onSnapshotTaken); setup(); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/progress.js b/scripts/system/progress.js index 7c1c475e99..2b1efa94af 100644 --- a/scripts/system/progress.js +++ b/scripts/system/progress.js @@ -1,3 +1,5 @@ +"use strict"; + // // progress.js // examples @@ -11,7 +13,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -(function() { +(function() { // BEGIN LOCAL_SCOPE function debug() { return; @@ -283,4 +285,5 @@ GlobalServices.updateDownloadInfo(); Script.setInterval(update, 1000/60); Script.scriptEnding.connect(tearDown); -}()); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/selectAudioDevice.js b/scripts/system/selectAudioDevice.js index 663f96b59c..a44295fd3c 100644 --- a/scripts/system/selectAudioDevice.js +++ b/scripts/system/selectAudioDevice.js @@ -1,3 +1,5 @@ +"use strict"; + // // audioDeviceExample.js // examples @@ -11,6 +13,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + if (typeof String.prototype.startsWith != 'function') { String.prototype.startsWith = function (str){ return this.slice(0, str.length) == str; @@ -62,11 +66,11 @@ function setupAudioMenus() { for(var i = 0; i < outputDevices.length; i++) { var thisDeviceSelected = (outputDevices[i] == selectedOutputDevice); var menuItem = "Use " + outputDevices[i] + " for Output"; - Menu.addMenuItem({ - menuName: "Audio > Devices", - menuItemName: menuItem, - isCheckable: true, - isChecked: thisDeviceSelected + Menu.addMenuItem({ + menuName: "Audio > Devices", + menuItemName: menuItem, + isCheckable: true, + isChecked: thisDeviceSelected }); if (thisDeviceSelected) { selectedOutputMenu = menuItem; @@ -86,11 +90,11 @@ function setupAudioMenus() { for(var i = 0; i < inputDevices.length; i++) { var thisDeviceSelected = (inputDevices[i] == selectedInputDevice); var menuItem = "Use " + inputDevices[i] + " for Input"; - Menu.addMenuItem({ - menuName: "Audio > Devices", - menuItemName: menuItem, - isCheckable: true, - isChecked: thisDeviceSelected + Menu.addMenuItem({ + menuName: "Audio > Devices", + menuItemName: menuItem, + isCheckable: true, + isChecked: thisDeviceSelected }); if (thisDeviceSelected) { selectedInputMenu = menuItem; @@ -212,3 +216,5 @@ Script.scriptEnding.connect(function () { Menu.menuItemEvent.disconnect(menuItemEvent); Script.update.disconnect(checkHMDAudio); }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/users.js b/scripts/system/users.js index 853067b90b..a56656a074 100644 --- a/scripts/system/users.js +++ b/scripts/system/users.js @@ -1,3 +1,5 @@ +"use strict"; + // // users.js // examples @@ -9,6 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + var PopUpMenu = function (properties) { var value = properties.value, promptOverlay, @@ -1189,3 +1193,5 @@ var usersWindow = (function () { setUp(); Script.scriptEnding.connect(tearDown); }()); + +}()); // END LOCAL_SCOPE From fefe5e30ec4b3e431c7a61f299594562266e20ec Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 23 Aug 2016 12:54:09 -0700 Subject: [PATCH 67/71] don't use globals and remove double definitions --- scripts/system/controllers/grab.js | 21 ++++----------------- scripts/system/progress.js | 2 +- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index dc57fe4451..05303aa0a7 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -15,8 +15,7 @@ (function() { // BEGIN LOCAL_SCOPE Script.include("../libraries/utils.js"); -// objects that appear smaller than this can't be grabbed -var MAX_SOLID_ANGLE = 0.01; +var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed var ZERO_VEC3 = { x: 0, @@ -42,18 +41,6 @@ var DEFAULT_GRABBABLE_DATA = { }; -var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed -var ZERO_VEC3 = { - x: 0, - y: 0, - z: 0 -}; -var IDENTITY_QUAT = { - x: 0, - y: 0, - z: 0, - w: 0 -}; var ACTION_TTL = 10; // seconds var enabled = true; @@ -124,7 +111,7 @@ function mouseIntersectionWithPlane(pointOnPlane, planeNormal, event, maxDistanc } // Mouse class stores mouse click and drag info -Mouse = function() { +function Mouse() { this.current = { x: 0, y: 0 @@ -194,7 +181,7 @@ var mouse = new Mouse(); // Beacon class stores info for drawing a line at object's target position -Beacon = function() { +function Beacon() { this.height = 0.10; this.overlayID = Overlays.addOverlay("line3d", { color: { @@ -246,7 +233,7 @@ var beacon = new Beacon(); // Grabber class stores and computes info for grab behavior -Grabber = function() { +function Grabber() { this.isGrabbing = false; this.entityID = null; this.actionID = null; diff --git a/scripts/system/progress.js b/scripts/system/progress.js index 2b1efa94af..d7f6713c69 100644 --- a/scripts/system/progress.js +++ b/scripts/system/progress.js @@ -245,7 +245,7 @@ } function updateProgressBarLocation() { - viewport = Controller.getViewportDimensions(); + var viewport = Controller.getViewportDimensions(); windowWidth = viewport.x; windowHeight = viewport.y; From a0911d2b9dc2fd2ada4b215e78a29447b0070a0e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Aug 2016 09:04:06 -0700 Subject: [PATCH 68/71] add local scope wrappers to new default scripts --- scripts/system/marketplaces/marketplace.js | 4 ++++ scripts/system/snapshot.js | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/scripts/system/marketplaces/marketplace.js b/scripts/system/marketplaces/marketplace.js index 2bd6033e62..349c3f70e1 100644 --- a/scripts/system/marketplaces/marketplace.js +++ b/scripts/system/marketplaces/marketplace.js @@ -8,6 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +(function() { // BEGIN LOCAL_SCOPE + /* global WebTablet */ Script.include("../libraries/WebTablet.js"); @@ -100,3 +102,5 @@ Script.scriptEnding.connect(function () { browseExamplesButton.clicked.disconnect(onClick); marketplaceWindow.visibleChanged.disconnect(onMarketplaceWindowVisibilityChanged); }); + +}()); // END LOCAL_SCOPE diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 2f3b8862c2..c9876af039 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -7,6 +7,9 @@ // Distributed under the Apache License, Version 2.0 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +(function() { // BEGIN LOCAL_SCOPE + var SNAPSHOT_DELAY = 500; // 500ms var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); var resetOverlays; @@ -152,3 +155,5 @@ Script.scriptEnding.connect(function () { button.clicked.disconnect(onClicked); Window.snapshotShared.disconnect(snapshotShared); }); + +}()); // END LOCAL_SCOPE From da387a958a3f58b5e1a6c185da2ea1620c058f02 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Aug 2016 10:26:05 -0700 Subject: [PATCH 69/71] fix typo --- scripts/defaultScripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index dc0f1217c6..98825c594d 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -28,7 +28,7 @@ var DEFAULT_SCRIPTS = [ "system/controllers/squeezeHands.js", "system/controllers/grab.js", "system/controllers/teleport.js", - "system/controllers/toggleAdvancedMovementForHandControllers.js, + "system/controllers/toggleAdvancedMovementForHandControllers.js", "system/dialTone.js", "system/firstPersonHMD.js", "system/snapshot.js" From e82f6a90afa8b8ddb82a5a80dc86c79aa40ce72c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 25 Aug 2016 11:04:23 -0700 Subject: [PATCH 70/71] Improved web entity rendering * fading now works properly * web browsers are now fully opaque. --- interface/src/ui/overlays/Web3DOverlay.cpp | 7 ++- .../src/RenderableWebEntityItem.cpp | 16 +++++- .../src/RenderableWebEntityItem.h | 2 + libraries/render-utils/src/GeometryCache.cpp | 53 +++++++++++++++---- libraries/render-utils/src/GeometryCache.h | 16 +++--- .../src/simple_opaque_web_browser.slf | 30 +++++++++++ ...slf => simple_transparent_web_browser.slf} | 24 +++------ 7 files changed, 112 insertions(+), 36 deletions(-) create mode 100644 libraries/render-utils/src/simple_opaque_web_browser.slf rename libraries/render-utils/src/{simple_srgb_textured_unlit_no_tex_alpha.slf => simple_transparent_web_browser.slf} (58%) diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 618785ca66..46fc2dfc36 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -28,6 +28,7 @@ static const float DPI = 30.47f; static const float INCHES_TO_METERS = 1.0f / 39.3701f; +static float OPAQUE_ALPHA_THRESHOLD = 0.99f; QString const Web3DOverlay::TYPE = "web3d"; @@ -106,7 +107,11 @@ void Web3DOverlay::render(RenderArgs* args) { batch.setModelTransform(transform); auto geometryCache = DependencyManager::get(); - geometryCache->bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(batch); + if (color.a < OPAQUE_ALPHA_THRESHOLD) { + geometryCache->bindTransparentWebBrowserProgram(batch); + } else { + geometryCache->bindOpaqueWebBrowserProgram(batch); + } geometryCache->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color); batch.setResourceTexture(0, args->_whiteTexture); // restore default white color after me } diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 9221fec140..4a42df561e 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -35,6 +35,7 @@ static const uint32_t MAX_CONCURRENT_WEB_VIEWS = 100; static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND; static int MAX_WINDOW_SIZE = 4096; +static float OPAQUE_ALPHA_THRESHOLD = 0.99f; EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity{ new RenderableWebEntityItem(entityID) }; @@ -144,7 +145,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) { glm::vec2 windowSize = getWindowSize(); // The offscreen surface is idempotent for resizes (bails early - // if it's a no-op), so it's safe to just call resize every frame + // if it's a no-op), so it's safe to just call resize every frame // without worrying about excessive overhead. _webSurface->resize(QSize(windowSize.x, windowSize.y)); @@ -164,9 +165,14 @@ void RenderableWebEntityItem::render(RenderArgs* args) { } float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; + batch._glColor4f(1.0f, 1.0f, 1.0f, fadeRatio); - DependencyManager::get()->bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(batch); + if (fadeRatio < OPAQUE_ALPHA_THRESHOLD) { + DependencyManager::get()->bindTransparentWebBrowserProgram(batch); + } else { + DependencyManager::get()->bindOpaqueWebBrowserProgram(batch); + } DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio)); } @@ -291,3 +297,9 @@ void RenderableWebEntityItem::update(const quint64& now) { destroyWebSurface(); } } + + +bool RenderableWebEntityItem::isTransparent() { + float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; + return fadeRatio < OPAQUE_ALPHA_THRESHOLD; +} diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 7bfd40864b..03234ce690 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -44,6 +44,8 @@ public: SIMPLE_RENDERABLE(); + virtual bool isTransparent() override; + private: bool buildWebSurface(EntityTreeRenderer* renderer); void destroyWebSurface(); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 01cec78eae..a3a9303156 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -35,7 +35,8 @@ #include "simple_vert.h" #include "simple_textured_frag.h" #include "simple_textured_unlit_frag.h" -#include "simple_srgb_textured_unlit_no_tex_alpha_frag.h" +#include "simple_opaque_web_browser_frag.h" +#include "simple_transparent_web_browser_frag.h" #include "glowLine_vert.h" #include "glowLine_geom.h" #include "glowLine_frag.h" @@ -1763,25 +1764,55 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { return a.getRaw() == b.getRaw(); } -void GeometryCache::bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(gpu::Batch& batch) { - batch.setPipeline(getSimpleSRGBTexturedUnlitNoTexAlphaPipeline()); +void GeometryCache::bindOpaqueWebBrowserProgram(gpu::Batch& batch) { + batch.setPipeline(getOpaqueWebBrowserProgram()); // Set a default normal map batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, - DependencyManager::get()->getNormalFittingTexture()); + DependencyManager::get()->getNormalFittingTexture()); } -gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoTexAlphaPipeline() { - // Compile the shaders, once +gpu::PipelinePointer GeometryCache::getOpaqueWebBrowserProgram() { static std::once_flag once; std::call_once(once, [&]() { auto VS = gpu::Shader::createVertex(std::string(simple_vert)); - auto PS = gpu::Shader::createPixel(std::string(simple_srgb_textured_unlit_no_tex_alpha_frag)); + auto PS = gpu::Shader::createPixel(std::string(simple_opaque_web_browser_frag)); - _simpleSRGBTexturedUnlitNoTexAlphaShader = gpu::Shader::createProgram(VS, PS); + _simpleOpaqueWebBrowserShader = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING)); - gpu::Shader::makeProgram(*_simpleSRGBTexturedUnlitNoTexAlphaShader, slotBindings); + gpu::Shader::makeProgram(*_simpleOpaqueWebBrowserShader, slotBindings); + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_NONE); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + _simpleOpaqueWebBrowserPipeline = gpu::Pipeline::create(_simpleOpaqueWebBrowserShader, state); + }); + + return _simpleOpaqueWebBrowserPipeline; +} + +void GeometryCache::bindTransparentWebBrowserProgram(gpu::Batch& batch) { + batch.setPipeline(getTransparentWebBrowserProgram()); + // Set a default normal map + batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, + DependencyManager::get()->getNormalFittingTexture()); +} + +gpu::PipelinePointer GeometryCache::getTransparentWebBrowserProgram() { + static std::once_flag once; + std::call_once(once, [&]() { + auto VS = gpu::Shader::createVertex(std::string(simple_vert)); + auto PS = gpu::Shader::createPixel(std::string(simple_transparent_web_browser_frag)); + + _simpleTransparentWebBrowserShader = gpu::Shader::createProgram(VS, PS); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING)); + gpu::Shader::makeProgram(*_simpleTransparentWebBrowserShader, slotBindings); auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_NONE); state->setDepthTest(true, true, gpu::LESS_EQUAL); @@ -1789,10 +1820,10 @@ gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoTexAlphaPipeline gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _simpleSRGBTexturedUnlitNoTexAlphaPipeline = gpu::Pipeline::create(_simpleSRGBTexturedUnlitNoTexAlphaShader, state); + _simpleTransparentWebBrowserPipeline = gpu::Pipeline::create(_simpleTransparentWebBrowserShader, state); }); - return _simpleSRGBTexturedUnlitNoTexAlphaPipeline; + return _simpleTransparentWebBrowserPipeline; } void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool transparent, bool culled, bool unlit, bool depthBiased) { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 9099daf7c0..244683759d 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -149,8 +149,7 @@ public: int allocateID() { return _nextID++; } static const int UNKNOWN_ID; - - + // Bind the pipeline and get the state to render static geometry void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool transparent = false, bool culled = true, bool unlit = false, bool depthBias = false); @@ -158,8 +157,11 @@ public: gpu::PipelinePointer getSimplePipeline(bool textured = false, bool transparent = false, bool culled = true, bool unlit = false, bool depthBias = false); - void bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(gpu::Batch& batch); - gpu::PipelinePointer getSimpleSRGBTexturedUnlitNoTexAlphaPipeline(); + void bindOpaqueWebBrowserProgram(gpu::Batch& batch); + gpu::PipelinePointer getOpaqueWebBrowserProgram(); + + void bindTransparentWebBrowserProgram(gpu::Batch& batch); + gpu::PipelinePointer getTransparentWebBrowserProgram(); render::ShapePipelinePointer getOpaqueShapePipeline() { return GeometryCache::_simpleOpaquePipeline; } render::ShapePipelinePointer getTransparentShapePipeline() { return GeometryCache::_simpleTransparentPipeline; } @@ -423,9 +425,11 @@ private: gpu::PipelinePointer _glowLinePipeline; QHash _simplePrograms; - gpu::ShaderPointer _simpleSRGBTexturedUnlitNoTexAlphaShader; - gpu::PipelinePointer _simpleSRGBTexturedUnlitNoTexAlphaPipeline; + gpu::ShaderPointer _simpleOpaqueWebBrowserShader; + gpu::PipelinePointer _simpleOpaqueWebBrowserPipeline; + gpu::ShaderPointer _simpleTransparentWebBrowserShader; + gpu::PipelinePointer _simpleTransparentWebBrowserPipeline; }; #endif // hifi_GeometryCache_h diff --git a/libraries/render-utils/src/simple_opaque_web_browser.slf b/libraries/render-utils/src/simple_opaque_web_browser.slf new file mode 100644 index 0000000000..2921d6aea0 --- /dev/null +++ b/libraries/render-utils/src/simple_opaque_web_browser.slf @@ -0,0 +1,30 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple_opaque_web_browser.frag +// fragment shader +// +// Created by Anthony Thibault on 7/25/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 gpu/Color.slh@> +<@include DeferredBufferWrite.slh@> + +// the albedo texture +uniform sampler2D originalTexture; + +// the interpolated normal +in vec3 _normal; +in vec4 _color; +in vec2 _texCoord0; + +void main(void) { + vec4 texel = texture(originalTexture, _texCoord0.st); + texel = colorToLinearRGBA(texel); + packDeferredFragmentUnlit(normalize(_normal), 1.0, _color.rgb * texel.rgb); +} diff --git a/libraries/render-utils/src/simple_srgb_textured_unlit_no_tex_alpha.slf b/libraries/render-utils/src/simple_transparent_web_browser.slf similarity index 58% rename from libraries/render-utils/src/simple_srgb_textured_unlit_no_tex_alpha.slf rename to libraries/render-utils/src/simple_transparent_web_browser.slf index 38b7e1002c..b7606985e6 100644 --- a/libraries/render-utils/src/simple_srgb_textured_unlit_no_tex_alpha.slf +++ b/libraries/render-utils/src/simple_transparent_web_browser.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// simple_srgb_texture_unlit_no_tex_alpha.frag +// simple_transparent_web_browser.frag // fragment shader // // Created by Anthony Thibault on 7/25/16. @@ -26,19 +26,11 @@ in vec2 _texCoord0; void main(void) { vec4 texel = texture(originalTexture, _texCoord0.st); texel = colorToLinearRGBA(texel); - - const float ALPHA_THRESHOLD = 0.999; - if (_color.a < ALPHA_THRESHOLD) { - packDeferredFragmentTranslucent( - normalize(_normal), - _color.a, - _color.rgb * texel.rgb, - DEFAULT_FRESNEL, - DEFAULT_ROUGHNESS); - } else { - packDeferredFragmentUnlit( - normalize(_normal), - 1.0, - _color.rgb * texel.rgb); - } + packDeferredFragmentTranslucent( + normalize(_normal), + _color.a, + _color.rgb * texel.rgb, + DEFAULT_FRESNEL, + DEFAULT_ROUGHNESS); } + From 8cc65ea9653244dbbaae7bcbb66ff099a0cb2ab0 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 25 Aug 2016 16:31:42 -0700 Subject: [PATCH 71/71] Adrressing review issues --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 3 --- libraries/render-utils/src/AmbientOcclusionEffect.h | 2 +- libraries/render-utils/src/SurfaceGeometryPass.cpp | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 613bc22c84..86223e9877 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -377,9 +377,6 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext float tHeight = occlusionViewport.w / (float)framebufferSize.y; - //_parametersBuffer->ditheringInfo.y += 0.25f; - - auto occlusionPipeline = getOcclusionPipeline(); auto firstHBlurPipeline = getHBlurPipeline(); auto lastVBlurPipeline = getVBlurPipeline(); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 7f3ff3f64f..8bb4600d3c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -205,7 +205,7 @@ public: DebugAmbientOcclusionConfig() : render::Job::Config(true) {} bool showCursorPixel{ false }; - glm::vec2 debugCursorTexcoord{ 0.5, 0.5 }; + glm::vec2 debugCursorTexcoord{ 0.5f, 0.5f }; signals: void dirty(); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index cc8d04e929..7a5a34c756 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -74,7 +74,6 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: _linearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - // _linearDepthTexture->autoGenerateMips(5); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); @@ -82,7 +81,7 @@ void LinearDepthFramebuffer::allocate() { // For Downsampling: _halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _halfLinearDepthTexture->autoGenerateMips(5); + _halfLinearDepthTexture->autoGenerateMips(5); _halfNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));