nvidia-texture-tools/src/nvimage/NormalMipmap.cpp
castano babb7e8df7 - weighted cuda compressor.
- faster and better BC3n compressor
- add normal map flag to DDS files that store normal maps.
- stop using RXGB fourcc code.
- move tools to tools/
- add temptative config dialog for UI based tool. 
- add experimental normal map mipmap generation.
- start adding support for input dds files in nvcompress.
- many other small fixes and cleanup.
2007-05-17 00:11:38 +00:00

99 lines
2.0 KiB
C++

// This code is in the public domain -- castanyo@yahoo.es
#include <nvcore/Ptr.h>
#include <nvmath/Montecarlo.h>
#include <nvmath/SphericalHarmonic.h>
#include <nvimage/NormalMipmap.h>
#include <nvimage/FloatImage.h>
using namespace nv;
FloatImage * nv::createNormalMipmapMap(const FloatImage * img)
{
nvDebugCheck(img != NULL);
uint w = img->width();
uint h = img->height();
uint hw = w / 2;
uint hh = h / 2;
FloatImage dotImg;
dotImg.allocate(1, w, h);
FloatImage shImg;
shImg.allocate(9, hw, hh);
SampleDistribution distribution(256);
const uint sampleCount = distribution.sampleCount();
for (uint d = 0; d < sampleCount; d++)
{
const float * xChannel = img->channel(0);
const float * yChannel = img->channel(1);
const float * zChannel = img->channel(2);
Vector3 dir = distribution.sampleDir(d);
Sh2 basis;
basis.eval(dir);
for(uint i = 0; i < w*h; i++)
{
Vector3 normal(xChannel[i], yChannel[i], zChannel[i]);
normal = normalizeSafe(normal, Vector3(zero), 0.0f);
dotImg.setPixel(dot(dir, normal), d);
}
// @@ It would be nice to have a fastDownSample that took an existing image as an argument, to avoid allocations.
AutoPtr<FloatImage> dotMip(dotImg.fastDownSample());
for(uint p = 0; p < hw*hh; p++)
{
float f = dotMip->pixel(p);
// Project irradiance to sh basis and accumulate.
for (uint i = 0; i < 9; i++)
{
float & sum = shImg.channel(i)[p];
sum += f * basis.elemAt(i);
}
}
}
FloatImage * normalMipmap = new FloatImage;
normalMipmap->allocate(4, hw, hh);
// Precompute the clamped cosine radiance transfer.
Sh2 prt;
prt.cosineTransfer();
// Allocate outside the loop.
Sh2 sh;
for(uint p = 0; p < hw*hh; p++)
{
for (uint i = 0; i < 9; i++)
{
sh.elemAt(i) = shImg.channel(i)[p];
}
// Convolve sh irradiance by radiance transfer.
sh *= prt;
// Now sh(0) is the ambient occlusion.
// and sh(1) is the normal direction.
// Should we use SVD to fit only the normals to the SH?
}
return normalMipmap;
}