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

/*

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

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

/*

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

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;

}

你可能感兴趣的:(ARM)