Spherical Harmonics Lighting代码实现(续)



上一篇文章我们已经可以求出由SH基函数组成特定复合函数的因子,现在我们就来实现三维空间的SHL,光源来自HDR图像。

该算法使用上一篇文章的SH因子计算过程、HDR图像导入过程,同时也使用了光线/物体相交过程。

这里新引进几个结构体。

SHRay-使用两个SHVector3d表示射线的起点和方向。

SHRGBColor-表示RGB颜色值,每个分量都是double精度的浮点数。

SHCoeff-为每一个颜色通道容纳SH因子。

SHMaterial-包含物体表面属性:ambient,diffuse,specular,specular power,最后一个分量作为物体的uid。

SHMaterialLookup-一个查找表。因为3DS文件使用名字表示材质,而不是一个uid。这个结构体有两个成员:一个string代表材质名称,一个整数表示和SHMaterial结构体中uid相对应的uid。这个uid作为材质数组的索引。

SHFace3d-容纳场景中给定三角形的特征。成员有:附着在三角形上的材质uid,一个代表法线的向量,含有三个索引的数组(这三个索引分别指向三个顶点),常数(用来搞笑检测交点),两个主轴索引(在求交点过程中三角形投影平面的主轴)。

SHMesh3d-场景中物体的特征,成员有:顶点个数,三角面片个数,两个向量代表包围盒的范围(用来加速求交),三角形数组,顶点数组,每个顶点的法线数组,每一个转移方程的SH因子(不考虑自阴影、自阴影、全局光照)。

SHCamera3d-包含摄像机的属性,成员有:位置(SHVector3d),目标向量(SHVector3d),视野范围(FOV)。

SHScene3d-包含3D场景中的一切东西:摄像机的数目,光源数目,材质数目,物体数目,三角面片总数,场景物体数组,默认材质,材质查找表,背景色,摄像机数组,光源数组。

QQ截图20120531201731

 

1、SH Diffuse Unshadowed Light

201205291620328425

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
point:要计算SH因子的当前顶点
normal:当前顶点的法线
color:当前顶点的颜色
sphericalSamples:在所有SH计算中都要使用的样本
result:结果因子
numSamples:样本数
numCoeffs:因子数
*/
 
void   SHProjectDiffuseUnshadowedVertex(SHVector3d point,SHVector3d normal,SHRGBColor color,SHSample* sphericalSamples,SHRGBColor* result, int   numSamples, int   numCoeffs)
{
      //反射率
      SHRGBColor albedo;
  
      //dot product and scale coefficient
      double   H,value;
      
     //weighting factor
     double   dWeight=4.0*PI;
     double   factor=dWeight/numSamples;
 
     //indexes
     int   i,n;
 
     //loop through all the spherical samples
     for (i=0;i<numSamples;++i)
     {
          //the transfer function is the cosine item
          VecDot(sphericalSamples[i].vec,normal,H);
 
          //calculate the albedo
          RGBScale(color,ONE_OVER_PI,albedo);
   
          //calculate only if cosine positive
          if (H>0.0)
          {
             //calculate the coefficient
             for (n=0;n<numCoeffs;++n)
             {
                  value=H*sphericalSamples[i].coeff[n];
                  result[n].r+=albedo.r*value;
                  result[n].g+=albedo.g*value;
                  result[n].b+=albedo.b*value;
             }
          }
     }
     //scale the SH coefficient
     for (i=0;i<numCoeffs;++i)
     {
          result[i].r*=factor;
          result[i].g*=factor;
          result[i].b*=factor;
     }
}

以上代码是求给定点转移方程的SH投影(即求系数),是预处理的一步。


2、SH Diffuse Shadowed Light

201205291620347670

转移方程包含可见项,需要检测和场景中所有其他三角面片的相交情况,需要使用光线追踪的算法。对于一个给定的顶点,我们不去检测它和场景中所有物体的所有三角面片的相交情况,而是我们首先检测它和每个物体包围盒的相交情况,如果相交,则继续检测它和该物体所有三角面片的相交情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
aScene:被照亮的场景
meshIndex:当前顶点属于的mesh
faceIndex:当前顶点属于的三角面片
*/
void   SHProjectDiffuseShadowedVertex(SHScene3d* aScene, int   meshIndex, int   faceIndex,SHVector3d point,SHVector3d normal,SHRGBColor color,SHSample* sphericalSamples,SHRGBColor* result, int   numSample, int   numCoeffs)
{
    //反射率
    SHRGBColor albedo;
    
    //dot product and scale coefficient
    double   H,value;   
 
    //weighting factor
    double   dWeight=4.0*PI;
    double   factor=dWeight/numSamples;
    
    //indexes
    int   i,n;
 
    //ray used for the visibility term
    SHRay ray;
    
    //origin of the ray is the current vertex
    VecCopy(point,ray.origin);
 
    //loop through all the spherical samples
    for (i=0;i<numSamples;++i)
    {
        VecDot(sphericalSamples[i].vec,normal,H);
        
        RGBScale(color,ONE_OVER_PI,albedo);
 
        if (H>0.0)
        {
             //the direction is the spherical sample direction
             VecCopy(sphericalSamples[i].vec,ray.direction);
    
             //determine the visibility for shadowing
             if (!intersectScene(&ray,aScene,faceIndex,meshIndex))
             {
                 for (n=0;n<numCoeffs;++n)
                 {
                     value=H*sphericalSamples[i].coeff[n];
                     result[n]+=albedo*value;
                 }
             }
        }
    }
    for (n=0;n<numCoeffs;++n)
       result[n]*=factor;  
}
 
int   intersectScene(SHRay* ray,SHScene3d* aScene, int   faceIndex, int   meshIndex)
{
    //the current mesh
    SHMesh3d* mesh;
    
    //indexes
    int   i,j;
 
    //go through each object of the model
    for (i=0;i<aScene->numMeshes;++i)
    {
        //assign current mesh
        mesh=&aScene->meshes[i];
     
       //check if ray intersects the mesh's bounding box
       if (!boxIntersect(ray,mesh->min,mesh->max))
          continue ;
    
       //go through all of the faces of the object
       for (j=0;j<mesh->numFaces;++j)
       {
           //skip triangles from which the ray orginated
           if (i==meshIndex && j==faceIndex)
              continue ;
  
           //test intersection,returns if intersection
           if (triangleIntersect(&mesh->faces[j],mesh->points[mesh->faces[j].pointIndex[0]],mesh->points[mesh->faces[j].pointIndex[1]],
mesh->points[mesh->faces[j].pointIndex[2]].ray))
           return   1; 
       }
    }
    
    //returns 0 if no intersection found
    return   0;
}

下面的程序实时计算每一个顶点的最终颜色值,用到SH基函数的性质2

201205291620188340

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SHRGBColor SHLighting(SHRGBColor* light,SHRGBColor* vertexSH,
int   numCoeffs, double   dScale)
{
     . //the color returned
      SHRGBColor result;
 
     //index
     int   i;
 
     //initialize the color
     result.r=result.g=result.b=0.0;
 
     //perform the dot product of the SH coefficients
     for (i=0;i<numCoeffs;++i)
     {
         result+=light[i]*vertexSH[i]*dScale;
     }
     
     return   result;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值