Example #1
0
CubeSurface CubeSurface::irradianceFilter(int size, EdgeFixup fixupMethod) const
{
    m->allocateTexelTable();

    // Transform this cube to spherical harmonic basis
    Sh2 sh;

    // For each texel of the input cube.
    const uint edgeLength = m->edgeLength;
    for (uint f = 0; f < 6; f++) {
        for (uint y = 0; y < edgeLength; y++) {
            for (uint x = 0; x < edgeLength; x++) {

                Vector3 dir = m->texelTable->direction(f, x, y);
                float solidAngle = m->texelTable->solidAngle(f, x, y);

                Sh2 shDir;
                shDir.eval(dir);

                sh.addScaled(sh, solidAngle);
            }
        }
    }


    // Evaluate spherical harmonic for each output texel.
    CubeSurface output;
    output.m->allocate(size);




    // @@ TODO
    return CubeSurface();
}
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;
}