Fixed GGC radiance filtering.

This commit is contained in:
Branimir Karadžić
2018-07-17 14:43:31 -07:00
parent ef8639ca40
commit 8f382eb408

View File

@@ -356,6 +356,7 @@ namespace bimg
// Reference:
// - https://web.archive.org/web/20180614195754/http://www.mpia.de/~mathar/public/mathar20051002.pdf
// - https://web.archive.org/web/20180614195725/http://www.rorydriscoll.com/2012/01/15/cubemap-texel-solid-angle/
//
const float x0 = _u - _invFaceSize;
const float x1 = _u + _invFaceSize;
const float y0 = _v - _invFaceSize;
@@ -665,7 +666,7 @@ namespace bimg
{
Sampler(const ImageContainer& _image, uint16_t _side, float _lod, float (*func)(float) )
{
const float lod = bx::clamp(_lod, 0.0f, 1.0f) * (_image.m_numMips - 1);
const float lod = bx::clamp(_lod, 0.0f, float(_image.m_numMips - 1) );
imageGetRawData(
_image
, _side
@@ -761,7 +762,7 @@ namespace bimg
_rgba[3] = bx::lerp(rgbaA[3], rgbaB[3], fl);
}
void importanceSampleGgx(float* _result, float _u, float _v, float _roughness, const float* _normal)
void importanceSampleGgx(float* _result, float _u, float _v, float _roughness, const float* _normal, const float* _tangentX, const float* _tangentY)
{
const float aa = bx::square(_roughness);
const float phi = bx::kPi2 * _u;
@@ -775,21 +776,9 @@ namespace bimg
cosTheta,
};
float up[3] = { 0.0f, 0.0f, 0.0f };
up[bx::abs(_normal[2]) < 0.999f ? 2 : 0] = 1.0f;
float right[3];
bx::vec3Cross(right, up, _normal);
float tangentX[3];
bx::vec3Norm(tangentX, right);
float tangentY[3];
bx::vec3Cross(tangentY, _normal, tangentX);
_result[0] = tangentX[0] * hh[0] + tangentY[0] * hh[1] + _normal[0] * hh[2];
_result[1] = tangentX[1] * hh[0] + tangentY[1] * hh[1] + _normal[1] * hh[2];
_result[2] = tangentX[2] * hh[0] + tangentY[2] * hh[1] + _normal[2] * hh[2];
_result[0] = _tangentX[0] * hh[0] + _tangentY[0] * hh[1] + _normal[0] * hh[2];
_result[1] = _tangentX[1] * hh[0] + _tangentY[1] * hh[1] + _normal[1] * hh[2];
_result[2] = _tangentX[2] * hh[0] + _tangentY[2] * hh[1] + _normal[2] * hh[2];
}
float normalDistributionGgx(float _ndoth, float _roughness)
@@ -814,25 +803,35 @@ namespace bimg
const uint32_t bpp = getBitsPerPixel(_image.m_format);
constexpr int32_t kNumSamples = 64;
constexpr int32_t kNumSamples = 512;
const uint32_t pitch = mip.m_width*bpp/8;
const float widthMinusOne = float(mip.m_width-1);
const float mipBias = 0.5f*bx::log2(bx::square(float(mip.m_width) )/float(kNumSamples) );
const float mipBias = 0.5f*bx::log2(bx::square(float(_image.m_width) )/float(kNumSamples) );
UnpackFn unpack = getUnpack(_image.m_format);
float color[3] = { 0.0f, 0.0f, 0.0f };
float totalWeight = 0.0f;
bx::RngMwc mwc;
// Golden Ratio Sequences for Low-Discrepancy Sampling
// https://web.archive.org/web/20180717194847/https://www.graphics.rwth-aachen.de/publication/2/jgt.pdf
//
// kGoldenSection = (0.5f*bx::sqrt(5.0f) + 0.5f) - 1.0f = 0.61803398875f
//
const float kGoldenSection = 0.61803398875f;
float offset = kGoldenSection;
float tangentX[3];
float tangentY[3];
bx::vec3TangentFrame(_dir, tangentX, tangentY);
for (uint32_t ii = 0; ii < kNumSamples; ++ii)
{
const float uu = ii/float(kNumSamples);
const float vv = bx::frnd(&mwc);
offset += kGoldenSection;
const float vv = ii/float(kNumSamples);
float hh[3];
importanceSampleGgx(hh, uu, vv, _roughness, _dir);
importanceSampleGgx(hh, offset, vv, _roughness, _dir, tangentX, tangentY);
const float ddoth2 = 2.0f * bx::vec3Dot(_dir, hh);
@@ -845,30 +844,49 @@ namespace bimg
if (ndotl > 0.0f)
{
const float ndoth = ndotl;
const float vdoth = ndotl;
const float ndoth = bx::clamp(bx::vec3Dot(_dir, hh), 0.0f, 1.0f);
const float vdoth = ndoth;
// Chapter 20. GPU-Based Importance Sampling
// http://archive.today/2018.07.14-004914/https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch20.html
//
const float pdf = normalDistributionGgx(ndoth, _roughness) * ndoth / (4.0f * vdoth);
const float lod = bx::max(0.0f, mipBias - 0.5f*bx::log2(pdf) );
const float lod = bx::max(0.0f, mipBias - 0.5f*bx::log2(pdf));
float rgba[4];
sampleCubeMap(rgba, _image, ll, lod);
color[0] += rgba[0] * ndotl;
color[1] += rgba[1] * ndotl;
color[2] += rgba[2] * ndotl;
// Optimized Reversible Tonemapper for Resolve
// https://web.archive.org/web/20180717182019/https://gpuopen.com/optimized-reversible-tonemapper-for-resolve/
// "a single sample with a large HDR value can over-power all other samples"
// "instead accept a bias in the resolve and reduce the weighting of samples
// as a function of how bright they are"
// Include ndotl here to "fold the weighting into the tonemap operation"
//
const float tm = ndotl / (bx::max(rgba[0], rgba[1], rgba[2]) + 1.0f);
color[0] += rgba[0] * tm;
color[1] += rgba[1] * tm;
color[2] += rgba[2] * tm;
totalWeight += ndotl;
}
}
if (0.0f < totalWeight)
{
// Optimized Reversible Tonemapper for Resovle
// https://web.archive.org/web/20180717182019/https://gpuopen.com/optimized-reversible-tonemapper-for-resolve/
// Average, then reverse the tonemapper
//
const float invWeight = 1.0f/totalWeight;
_result[0] = color[0] * invWeight;
_result[1] = color[1] * invWeight;
_result[2] = color[2] * invWeight;
color[0] = color[0] * invWeight;
color[1] = color[1] * invWeight;
color[2] = color[2] * invWeight;
const float invTm = 1.0f / (1.0f - bx::max(0.00001f, bx::max(color[0], color[1], color[2])));
_result[0] = color[0] * invTm;
_result[1] = color[1] * invTm;
_result[2] = color[2] * invTm;
}
else
{
@@ -1069,11 +1087,12 @@ namespace bimg
return bx::max(0.0f, 1.0f - _mip/(_mipCount-1.0000001f) );
}
float applyLightningModel(float _specularPower, LightingModel::Enum _lightingModel)
float applyLightingModel(float _specularPower, LightingModel::Enum _lightingModel)
{
// Reference:
// - https://web.archive.org/web/20180622232018/https://seblagarde.wordpress.com/2012/06/10/amd-cubemapgen-for-physically-based-rendering/
// - https://web.archive.org/web/20180622232041/https://seblagarde.wordpress.com/2012/03/29/relationship-between-phong-and-blinn-lighting-model/
//
switch (_lightingModel)
{
case LightingModel::PhongBrdf: return _specularPower + 1.0f;
@@ -1143,7 +1162,7 @@ namespace bimg
const float glossiness = glossinessFor(lod, float(numMips) );
const float roughness = 1.0f-glossiness;
const float specularPowerRef = bx::pow(2.0f, glossiness*glossScale + glossBias);
const float specularPower = applyLightningModel(specularPowerRef, _lightingModel);
const float specularPower = applyLightingModel(specularPowerRef, _lightingModel);
const float filterAngle = bx::clamp(cosinePowerFilterAngle(specularPower), minAngle, maxAngle);
const float cosAngle = bx::max(0.0f, bx::cos(filterAngle) );
const float texelSize = 1.0f/float(dstWidth);