diff --git a/interface/resources/images/normalFittingScale.dds b/interface/resources/images/normalFittingScale.dds new file mode 100644 index 0000000000..8207ee0981 Binary files /dev/null and b/interface/resources/images/normalFittingScale.dds differ diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index 91447cbf8b..9a3dda7076 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -21,6 +21,23 @@ uniform float glowIntensity; // the alpha threshold uniform float alphaThreshold; +uniform sampler2D normalFittingMap; + +vec3 bestFitNormal(vec3 normal) { + vec3 absNorm = abs(normal); + float maxNAbs = max(absNorm.z, max(absNorm.x, absNorm.y)); + + vec2 texcoord = (absNorm.z < maxNAbs ? + (absNorm.y < maxNAbs ? absNorm.yz : absNorm.xz) : + absNorm.xy); + texcoord = (texcoord.x < texcoord.y ? texcoord.yx : texcoord.xy); + texcoord.y /= texcoord.x; + vec3 cN = normal / maxNAbs; + float fittingScale = texture2D(normalFittingMap, texcoord).a; + cN *= fittingScale; + return (cN * 0.5 + 0.5); +} + float evalOpaqueFinalAlpha(float alpha, float mapAlpha) { return mix(alpha * glowIntensity, 1.0 - alpha * glowIntensity, step(mapAlpha, alphaThreshold)); } @@ -33,7 +50,7 @@ void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, discard; } _fragColor0 = vec4(diffuse.rgb, alpha); - _fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); + _fragColor1 = vec4(bestFitNormal(normal), 1.0); _fragColor2 = vec4(specular, shininess / 128.0); } @@ -44,7 +61,7 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 s _fragColor0 = vec4(diffuse.rgb, alpha); //_fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); - _fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5); + _fragColor1 = vec4(bestFitNormal(normal), 0.5); _fragColor2 = vec4(emissive, shininess / 128.0); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index aaaa3b6d6a..08ab6e0cf6 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -86,6 +86,7 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { _emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive)); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); gpu::Shader::makeProgram(*_simpleShader, slotBindings); gpu::Shader::makeProgram(*_emissiveShader, slotBindings); @@ -151,6 +152,8 @@ void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, // If it is not textured, bind white texture and keep using textured pipeline batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture()); } + + batch.setResourceTexture(NORMAL_FITTING_MAP_SLOT, DependencyManager::get<TextureCache>()->getNormalFittingTexture()); } void DeferredLightingEffect::renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color) { diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index ba4fbd6d69..62497851d7 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -30,7 +30,8 @@ class DeferredLightingEffect : public Dependency { SINGLETON_DEPENDENCY public: - + static const int NORMAL_FITTING_MAP_SLOT = 10; + void init(AbstractViewStateInterface* viewState); /// Sets up the state necessary to render static untextured geometry with the simple program. diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index cf0fb67d8c..43579892a7 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -105,6 +105,8 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3)); slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), 4)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); gpu::Shader::makeProgram(*program, slotBindings); @@ -180,6 +182,8 @@ void Model::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, Model: locations.emissiveParams = program->getUniforms().findLocation("emissiveParams"); locations.glowIntensity = program->getUniforms().findLocation("glowIntensity"); + locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); + locations.specularTextureUnit = program->getTextures().findLocation("specularMap"); locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); @@ -1864,6 +1868,10 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f const float DEFAULT_GLOW_INTENSITY = 1.0f; // FIXME - glow is removed batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY); } + + if ((locations->normalFittingMapUnit > -1)) { + batch.setResourceTexture(locations->normalFittingMapUnit, DependencyManager::get<TextureCache>()->getNormalFittingTexture()); + } } bool Model::initWhenReady(render::ScenePointer scene) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 09504c7501..9fdb2f3691 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -350,6 +350,7 @@ private: int emissiveTextureUnit; int emissiveParams; int glowIntensity; + int normalFittingMapUnit; int materialBufferUnit; int clusterMatrices; int clusterIndices; diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index d6a9bf5b36..deeec58f49 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -21,6 +21,7 @@ #include <QRunnable> #include <QThreadPool> #include <qimagereader.h> +#include "PathUtils.h" #include <gpu/Batch.h> @@ -129,6 +130,14 @@ const gpu::TexturePointer& TextureCache::getBlackTexture() { return _blackTexture; } + +const gpu::TexturePointer& TextureCache::getNormalFittingTexture() { + if (!_normalFittingTexture) { + _normalFittingTexture = getImageTexture(PathUtils::resourcesPath() + "images/normalFittingScale.dds"); + } + return _normalFittingTexture; +} + /// Extra data for creating textures. class TextureExtra { public: @@ -170,6 +179,7 @@ gpu::TexturePointer TextureCache::getImageTexture(const QString& path) { return texture; } + QSharedPointer<Resource> TextureCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) { const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra); diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index 8f60382e9b..eeb17f07b9 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -54,6 +54,9 @@ public: /// Returns the a black texture (useful for a default). const gpu::TexturePointer& getBlackTexture(); + // Returns a map used to compress the normals through a fitting scale algorithm + const gpu::TexturePointer& getNormalFittingTexture(); + /// Returns a texture version of an image file static gpu::TexturePointer getImageTexture(const QString& path); @@ -76,6 +79,7 @@ private: gpu::TexturePointer _grayTexture; gpu::TexturePointer _blueTexture; gpu::TexturePointer _blackTexture; + gpu::TexturePointer _normalFittingTexture; QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures; };