LTC-PolygonLighting

来源:互联网 发布:王坚 阿里云 编辑:程序博客网 时间:2024/06/06 12:58

由于多边形在球面上的分部积分比较复杂,再考虑到各种物理因素,材质的粗糙度,各向异性,偏角等等,为了解决这些个问题,出现了一种新的球面分布,它包含各种球面,并且可以对任意多边形分析并积分。



根据上图我们可以知道,原覆盖区域进行一个3x3矩阵M的变换可以得到我们想要的任意形状,所以线性变换余弦近似于物理上的BRDF。

下图是和物理上的BRDF和LTC的一个比较:



矩阵M可以存储到纹理,然后根据视角和粗糙度进行查找。


由于线性时不变特性,对LTC覆盖的多边形积分等价于原夹角余弦分布多边形的逆线性(进行M的逆)变换:这就是封闭多边形变换的辐照度(外形)。



上面的说完了,我们进入正题。

整体步骤如下:

1.根据roughness和viewAngle去索引M的逆矩阵的贴图

2.对原的多边形进行M逆矩阵的变换

3.裁剪

4.进行边的积分,求辐照度


我们先说球面上多边形灯的辐照度,公式如下:



现在来解释这个公式:

先看图

其中,v1,v2......代表球心到多边形光源的角的向量与球面的交点,球心这个点即是,被渲染的点。


再看下图:



我们可以知道,公式中的,acos(pi,pj)其实就是每两个向量之间的夹角的弧度值,也就是对应扇形弧的长度,然后我们可以计算出扇形的面积。而公式后半部分的相邻两个向量的叉积与这个点的法向量的点积可以得出,扇面与半球切面的夹角的余弦值,两者的乘积即是扇面在切面上的面积,然后把所有边的面积相加,就是在切面上的面积(也就是辐射通量)。所以这个点的入射辐照度就是求出的结果再除以PI。PI是球切面的面积。

裁剪是针对对变形光源在受到遮挡后的情况,主要改变的相当于传入的多边形顶点的个数。

修正后的核心代码如下:

float IntegrateEdge(float3 v1, float3 v2) {float cosTheta = dot(v1, v2);float theta = acos(cosTheta);float res = cross(v1, v2).z * ((theta > 0.001) ? theta / sin(theta) : 1.0);return res;}void ClipQuadToHorizon(inout float3 L[5], out int n) {// detect clipping configint config = 0;if (L[0].z > 0.0) config += 1;if (L[1].z > 0.0) config += 2;if (L[2].z > 0.0) config += 4;if (L[3].z > 0.0) config += 8;// clipn = 0;if (config == 0) {// clip all}else if (config == 1) { // V1 clip V2 V3 V4n = 3;L[1] = -L[1].z * L[0] + L[0].z * L[1];L[2] = -L[3].z * L[0] + L[0].z * L[3];}else if (config == 2) { // V2 clip V1 V3 V4n = 3;L[0] = -L[0].z * L[1] + L[1].z * L[0];L[2] = -L[2].z * L[1] + L[1].z * L[2];}else if (config == 3) { // V1 V2 clip V3 V4n = 4;L[2] = -L[2].z * L[1] + L[1].z * L[2];L[3] = -L[3].z * L[0] + L[0].z * L[3];}else if (config == 4) { // V3 clip V1 V2 V4n = 3;L[0] = -L[3].z * L[2] + L[2].z * L[3];L[1] = -L[1].z * L[2] + L[2].z * L[1];}else if (config == 5) { // V1 V3 clip V2 V4) impossiblen = 0;}else if (config == 6) { // V2 V3 clip V1 V4n = 4;L[0] = -L[0].z * L[1] + L[1].z * L[0];L[3] = -L[3].z * L[2] + L[2].z * L[3];}else if (config == 7) { // V1 V2 V3 clip V4n = 5;L[4] = -L[3].z * L[0] + L[0].z * L[3];L[3] = -L[3].z * L[2] + L[2].z * L[3];}else if (config == 8) { // V4 clip V1 V2 V3n = 3;L[0] = -L[0].z * L[3] + L[3].z * L[0];L[1] = -L[2].z * L[3] + L[3].z * L[2];L[2] = L[3];}else if (config == 9) { // V1 V4 clip V2 V3n = 4;L[1] = -L[1].z * L[0] + L[0].z * L[1];L[2] = -L[2].z * L[3] + L[3].z * L[2];}else if (config == 10) { // V2 V4 clip V1 V3) impossiblen = 0;}else if (config == 11) { // V1 V2 V4 clip V3n = 5;L[4] = L[3];L[3] = -L[2].z * L[3] + L[3].z * L[2];L[2] = -L[2].z * L[1] + L[1].z * L[2];}else if (config == 12) { // V3 V4 clip V1 V2n = 4;L[1] = -L[1].z * L[2] + L[2].z * L[1];L[0] = -L[0].z * L[3] + L[3].z * L[0];}else if (config == 13) { // V1 V3 V4 clip V2n = 5;L[4] = L[3];L[3] = L[2];L[2] = -L[1].z * L[2] + L[2].z * L[1];L[1] = -L[1].z * L[0] + L[0].z * L[1];}else if (config == 14) { // V2 V3 V4 clip V1n = 5;L[4] = -L[0].z * L[3] + L[3].z * L[0];L[0] = -L[0].z * L[1] + L[1].z * L[0];}else if (config == 15) { // V1 V2 V3 V4n = 4;}if (n == 3)L[3] = L[0];if (n == 4)L[4] = L[0];}float3 LTC_Evaluate(float3 N, float3 V, float3 P, float3x3 Minv, float3 points[4]) {// construct orthonormal basis around Nfloat3 T1, T2;T1 = normalize(V - N*(dot(V, N)));T2 = normalize(cross(N, T1));Minv = mul(Minv,float3x3(T1, T2, N));float3 L[5];L[0] = mul(Minv,points[0] - P);L[1] = mul(Minv,points[1] - P);L[2] = mul(Minv,points[2] - P);L[3] = mul(Minv,points[3] - P);L[4] = L[3];int n;ClipQuadToHorizon(L, n);if (n == 0)return float3(0, 0, 0);L[0] = normalize(L[0]);L[1] = normalize(L[1]);L[2] = normalize(L[2]);L[3] = normalize(L[3]);L[4] = normalize(L[4]);// integratefloat sum = 0.0;sum += IntegrateEdge(L[0], L[1]);sum += IntegrateEdge(L[1], L[2]);sum += IntegrateEdge(L[2], L[3]);if (n >= 4)sum += IntegrateEdge(L[3], L[4]);if (n >= 5)sum += IntegrateEdge(L[4], L[0]);sum = max(sum, 0.0);//sum = abs(sum);return float3(sum,sum,sum);}

最后效果图如下:









参考:


https://eheitzresearch.wordpress.com/415-2/




原创粉丝点击