Introducing the Normal fitting algorithm for better normal in the deferred buffer

This commit is contained in:
Sam Gateau 2015-08-05 17:17:00 -07:00
parent a4f105f6c3
commit 95682e6270
8 changed files with 47 additions and 3 deletions

Binary file not shown.

View file

@ -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);
}

View file

@ -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) {

View file

@ -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.

View file

@ -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) {

View file

@ -350,6 +350,7 @@ private:
int emissiveTextureUnit;
int emissiveParams;
int glowIntensity;
int normalFittingMapUnit;
int materialBufferUnit;
int clusterMatrices;
int clusterIndices;

View file

@ -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);

View file

@ -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;
};