1、Per-Vertex SH Data Generation with D3DX
D3DX函数产生的数据是SH系数的集合,可以跨平台使用。
对于Per-Vertex SH coefficient,使用D3DXSHPRTSimulation
HRESULT WINAPI D3DXSHPRTSimulation(UINT Order, LPD3DXMESH *ppMeshArray,D3DXSHMATERIAL **ppMaterials, UINT NumRays,UINT NumBounces,BOOL EnableSubSurfaceScattering, FLOAT LengthScale,BOOL EnableSpectral,LPD3DBUFFER *ppResultBuffer, LPD3DXSHPRTSIMCB pProgressCallback);
上面的函数为preconputed radiance transfer(PRT)生成SH系数。该函数是一个离线函数,不能在实时调用。
现在得到了SH系数的集合,但是系数的个数可能很多,比如一个order=5(即带宽l=5)的模拟,每个顶点需要5^2=25个颜色值,即75个系数。
DX使用的压缩方法称为Clustered Principal Component Analysis(CPCA)。
如上图,每一个箭头代表一组SH系数。实际上,一组SH系数可以看成一个多维数组。
如果观察模型中多个顶点的SH系数,可以讲多组SH系数组成集群。例如,平面中相邻的顶点会有相似的系数组。
上图是将不同的SH系数组划分到集群。
我们要首先找出每一个集群中SH系数组的平均值,如下图:
接下来,找出n组SH系数来代表这个集群(必须是最能代表这个集群的SH系数组),被找出来的n个SH系数组被称为PCA。下图展示了n=2的情况:
最后,每一个顶点的SH系数组都可以由这n个系数组线性插值得到,如下图:
上上一篇我们说到,计算每个顶点的最终颜色值可以通过转移方程的SH系数和光线的SH系数求点积得到,这里,因为我们用另一种方式表示转移方程的SH系数,所以最终颜色值的计算方法也可以换一种方式,公式如下:
M代表集群的平均值,B代表若干个挑选出来的值,w代表每一个值的权重。
这样,这种方法让你可以用n个权重值来表示没一个顶点的SH系数组,每个顶点只需要存储集群的索引和一系列的权重值。
HRESULT WINAPI D3DXSHPRTCompress(UINT Order, LPD3DXBUFFER pSHCoefficients, D3DXCOMPRESSQUALITYTYPE Quality, UINT NumClusters,UINT NumPCAVectors, LPD3DXBUFFER *ppResults);
最终的buffer存储了每一个集群的n个SH系数组,同时还包含每一个顶点的权重值。
现在我们还需要将光线投影到SH基上,得到光照的SH系数。D3DX提供了一系列的函数帮助处理平行光、球形光、锥形光、半球形光。
void D3DXSHEvalConeLight(); void D3DXSHEvalDirectionalLight();
最后,进行点乘步骤。
除了一系列的基本光源类型,D3DX还提供了从立方贴图中生成SH光照的API。立方贴图支持反射和折射效果,但是这些效果高光度太大而且diffuse不平滑。现在可以通过将立方贴图投影到SH基上来生成平滑的diffuse环境效果。
void D3DXSHProjectCubeMap();
SH lighting能很好的支持diffuse light,然而,怎么往既有效果中加入specular元素?
低带宽的SH方案适合diffuse lighting,因为它将光线的低频部分编码进去,而高光需要物体反射光线的高频部分给摄像机。