From 1dca62f752067786afe90c5ea779c6bc32005f6d Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 1 Jun 2016 17:51:53 -0700 Subject: [PATCH] Introducing a new technique for normal packing and fixing a bug on the normal buffer format --- .../src/RenderableProceduralItemShader.h | 49 +++++++++----- libraries/render-utils/src/DeferredBuffer.slh | 66 +++++++++++++++++++ .../render-utils/src/DeferredBufferRead.slh | 2 +- .../render-utils/src/DeferredBufferWrite.slh | 24 +------ .../render-utils/src/FramebufferCache.cpp | 5 +- 5 files changed, 107 insertions(+), 39 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableProceduralItemShader.h b/libraries/entities-renderer/src/RenderableProceduralItemShader.h index 1afd3bc608..4762f619bf 100644 --- a/libraries/entities-renderer/src/RenderableProceduralItemShader.h +++ b/libraries/entities-renderer/src/RenderableProceduralItemShader.h @@ -25,24 +25,43 @@ layout(location = 2) out vec4 _fragColor2; // 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 signNotZero(vec2 v) { + return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0); +} - 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 = texture(normalFittingMap, texcoord).a; - cN *= fittingScale; - return (cN * 0.5 + 0.5); +vec2 float32x3_to_oct(in vec3 v) { + vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z))); + return ((v.z <= 0.0) ? ((1.0 - abs(p.yx)) * signNotZero(p)) : p); } +vec3 oct_to_float32x3(in vec2 e) { + vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); + if (v.z < 0) { + v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy); + } + return normalize(v); +} + +vec3 snorm12x2_to_unorm8x3(vec2 f) { + vec2 u = vec2(round(clamp(f, -1.0, 1.0) * 2047.0 + 2047.0)); + float t = floor(u.y / 256.0); + + return floor(vec3( + u.x / 16.0, + fract(u.x / 16.0) * 256.0 + t, + u.y - t * 256.0 + )) / 255.0; +} + +vec2 unorm8x3_to_snorm12x2(vec3 u) { + u *= 255.0; + u.y *= (1.0 / 16.0); + vec2 s = vec2( u.x * 16.0 + floor(u.y), + fract(u.y) * (16.0 * 256.0) + u.z); + return clamp(s * (1.0 / 2047.0) - 1.0, vec2(-1.0), vec2(1.0)); +} float mod289(float x) { return x - floor(x * (1.0 / 289.0)) * 289.0; @@ -322,7 +341,7 @@ void main(void) { } vec4 diffuse = vec4(_color.rgb, alpha); - vec4 normal = vec4(normalize(bestFitNormal(_normal)), 0.5); + vec4 normal = vec4(packNormal(normalize(_normal)), 0.5); _fragColor0 = diffuse; _fragColor1 = normal; @@ -355,7 +374,7 @@ void main(void) { float emissiveAmount = getProceduralColors(diffuse, specular, shininess); _fragColor0 = vec4(diffuse.rgb, 1.0); - _fragColor1 = vec4(bestFitNormal(normalize(_normal.xyz)), 1.0 - (emissiveAmount / 2.0)); + _fragColor1 = vec4(packNormal(normalize(_normal.xyz)), 1.0 - (emissiveAmount / 2.0)); _fragColor2 = vec4(specular, shininess / 128.0); } )SCRIBE"; diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index aed89b30d0..b9c65a3bff 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -51,4 +51,70 @@ float packUnlit() { return FRAG_PACK_UNLIT; } + +vec2 signNotZero(vec2 v) { + return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0); +} + +vec2 float32x3_to_oct(in vec3 v) { + vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z))); + return ((v.z <= 0.0) ? ((1.0 - abs(p.yx)) * signNotZero(p)) : p); +} + + +vec3 oct_to_float32x3(in vec2 e) { + vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); + if (v.z < 0) { + v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy); + } + return normalize(v); +} + +vec3 snorm12x2_to_unorm8x3(vec2 f) { + vec2 u = vec2(round(clamp(f, -1.0, 1.0) * 2047.0 + 2047.0)); + float t = floor(u.y / 256.0); + + return floor(vec3( + u.x / 16.0, + fract(u.x / 16.0) * 256.0 + t, + u.y - t * 256.0 + )) / 255.0; +} + +vec2 unorm8x3_to_snorm12x2(vec3 u) { + u *= 255.0; + u.y *= (1.0 / 16.0); + vec2 s = vec2( u.x * 16.0 + floor(u.y), + fract(u.y) * (16.0 * 256.0) + u.z); + return clamp(s * (1.0 / 2047.0) - 1.0, vec2(-1.0), vec2(1.0)); +} + +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 = texture(normalFittingMap, texcoord).a; + cN *= fittingScale; + + return (cN * 0.5 + 0.5); +} + +vec3 packNormal(in vec3 n) { + return snorm12x2_to_unorm8x3(float32x3_to_oct(n)); +} + +vec3 unpackNormal(in vec3 p) { + return oct_to_float32x3(unorm8x3_to_snorm12x2(p)); +} + + <@endif@> diff --git a/libraries/render-utils/src/DeferredBufferRead.slh b/libraries/render-utils/src/DeferredBufferRead.slh index 569063955d..7714859f5a 100644 --- a/libraries/render-utils/src/DeferredBufferRead.slh +++ b/libraries/render-utils/src/DeferredBufferRead.slh @@ -100,7 +100,7 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) { frag.obscurance = texture(obscuranceMap, texcoord).x; // Unpack the normal from the map - frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0)); + frag.normal = unpackNormal(frag.normalVal.xyz); frag.roughness = frag.normalVal.a; // Diffuse color and unpack the mode and the metallicness diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index 2be38fbea3..e869f32dc6 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -17,24 +17,6 @@ layout(location = 0) out vec4 _fragColor0; layout(location = 1) out vec4 _fragColor1; layout(location = 2) out vec4 _fragColor2; -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 = texture(normalFittingMap, texcoord).a; - cN *= fittingScale; - return (cN * 0.5 + 0.5); -} - // the alpha threshold const float alphaThreshold = 0.5; @@ -55,7 +37,7 @@ void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness discard; } _fragColor0 = vec4(albedo, packShadedMetallic(metallic)); - _fragColor1 = vec4(bestFitNormal(normal), clamp(roughness, 0.0, 1.0)); + _fragColor1 = vec4(packNormal(normal), clamp(roughness, 0.0, 1.0)); _fragColor2 = vec4(emissive, occlusion); } @@ -65,7 +47,7 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, float r discard; } _fragColor0 = vec4(albedo, packLightmappedMetallic(metallic)); - _fragColor1 = vec4(bestFitNormal(normal), clamp(roughness, 0.0, 1.0)); + _fragColor1 = vec4(packNormal(normal), clamp(roughness, 0.0, 1.0)); _fragColor2 = vec4(emissive, 1.0); } @@ -74,7 +56,7 @@ void packDeferredFragmentUnlit(vec3 normal, float alpha, vec3 color) { discard; } _fragColor0 = vec4(color, packUnlit()); - _fragColor1 = vec4(bestFitNormal(normal), 1.0); + _fragColor1 = vec4(packNormal(normal), 1.0); //_fragColor2 = vec4(vec3(0.0), 1.0); // If unlit, do not worry about the emissive color target } diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 3223ee5535..2d322b1726 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -59,8 +59,8 @@ void FramebufferCache::createPrimaryFramebuffer() { _deferredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _deferredFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create()); - // auto colorFormat = gpu::Element::COLOR_RGBA_32; auto colorFormat = gpu::Element::COLOR_SRGBA_32; + auto linearFormat = gpu::Element::COLOR_RGBA_32; auto width = _frameBufferSize.width(); auto height = _frameBufferSize.height(); @@ -70,7 +70,8 @@ void FramebufferCache::createPrimaryFramebuffer() { _primaryFramebuffer->setRenderBuffer(0, _primaryColorTexture); _deferredColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _deferredNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + + _deferredNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(linearFormat, width, height, defaultSampler)); _deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture);