DirectX 11 SDK文档(七)

来源:互联网 发布:威士忌用什么杯子 知乎 编辑:程序博客网 时间:2024/04/27 08:49

总结

      在前面的教程中,这个世界看起来令人厌烦,因为所有的对象以同一种方式显示。在这个教程将介绍简单的光照概念,并介绍如何去应用它。这个技术是方向光。

光照

      在这个教程中,将介绍最基础的光照类型是方向光。方向光不论对象跟光源的距离,都受到统一的关照。当光照到一个表面时,光照的发射计算这个表面和光线的夹角大小。当光线直接照射到表面时,表面会将所有的光反射回去,显示最高的强度。然而,随着表面与光线的角度增长,反射的光照强度会慢慢暗下来。

      为了算出光线照射到表面的反射强度,光线的方向和表面的向量将被用来计算。这是表面的向量将被定义为垂直于表面的向量。这个计算只要把两个向量做一个简单的点乘就可以了,这个计算将返回光线在表面向量的投影的值。如果夹角比较大,那么投影就会比较小。那么这给我们一个正确的功能来调节扩散的光线。

      在这个教程中所使用的光源是一种近似的方向光。光线的向量决定了光线的方向。既然说是近似,不论一个对象在哪里,光线的方向都是一样的。就比如太阳的光线。对于任何对象,受到的太阳的光照都是一样的。除此之外,照射在各个对象上将会有不同的光照强度。

      还有其他一些光:点光,辐射光,和聚光。

初始化光照

      在这个教程中,有两个光源。一个放在立方体的前面向立方体照射,另一个以立方体为中心绕轨道移动。注意,轨道上的立方体用来表示光源的位置。

      既然光照由渲染器计算,一些变量必须声明并绑定。在这个例子中,我们只需要光源的方向向量和它的颜色。第一个光源是灰色,第二个是红色。代码如下:

      // Setup our lighting parameters
      XMFLOAT4 vLightDirs[2] = {
           XMFLOAT4( -0.577f, 0.577f, -0.577f, 1.0f ),
           XMFLOAT4( 0.0f, 0.0f, -1.0f, 1.0f ),
      };
      XMFLOAT4 vLightColors[2] = {
          XMFLOAT4( 0.5f, 0.5f, 0.5f, 1.0f ),
          XMFLOAT4( 0.5f, 0.0f, 0.0f, 1.0f )
      };

      轨道中旋转的光源与上个教程中的立方体类似。用一个旋转矩阵来改变光源的方向,让这个光源总是向中心照射。注意,XMVector3Transform()函数用于计算向量和矩阵相乘。在前面的教程中,我们只是把多个变换矩阵进行相乘,得到世界变换矩阵,然后传给渲染器进行变换。然而,由于在这个例子中简单的缘故。实际上我们只对灯光做了世界变换。

      // Rotate the second light around the origin
      XMMATRIX mRotate = XMMatrixRotationY( -2.0f * t );
      XMVECTOR vLightDir = XMLoadFloat4( &vLightDirs[1] );
      vLightDir = XMVector3Transform( vLightDir, mRotate );
      XMStoreFloat4( &vLightDirs[1], vLightDir );

      像矩阵一样,把灯光的方向向量和颜色传给渲染器。相关的变量将会被设置,参数也会传进来。

      //
      // Update matrix variables and lighting variables
      //
      ConstantBuffer cb1;
      cb1.mWorld = XMMatrixTranspose( g_World );
      cb1.mView = XMMatrixTranspose( g_View );
      cb1.mProjection = XMMatrixTranspose( g_Projection );
      cb1.vLightDir[0] = vLightDirs[0];
      cb1.vLightDir[1] = vLightDirs[1];
      cb1.vLightColor[0] = vLightColors[0];
      cb1.vLightColor[1] = vLightColors[1];
      cb1.vOutputColor = XMFLOAT4(0, 0, 0, 0);
      g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb1, 0, 0 );

在像素渲染器中显然灯光

      一旦我们准备好数据,并且渲染器准备好要读入的数据。我们就可以计算出方向光作用在每个像素的结果。之前我们使用的是点乘的方法。

      一旦我们将向量与光线进行点乘,然后我们就可以把结果乘以颜色和光线算出光线作用的最后结果。这些值将通过saturate函数,这个函数将颜色值控制在[0,1]。结果就是两个光光照的效果叠加在一起,算出最后的颜色。

      我们没有把表面的材质考虑进去,所以最后的计算结果就是光的颜色。

      //
      // Pixel Shader
      //
      float4 PS( PS_INPUT input) : SV_Target{
             float4 finalColor = 0;
       
             //do NdotL lighting for 2 lights
             for(int i=0; i<2; i++){
                    finalColor += saturate( dot( (float3)vLightDir[i],input.Norm) * vLightColor[i] );
             }
             return finalColor;
      }
      经过像素渲染器的运算,像素的颜色受灯光调节。并且你可以看到每个灯光作用在表面的效果。必须注意的是,我们现在看到的像素显示都是平面的,因为像素在同一个平面上,并且有相同的法向量。对于计算机来讲,漫反射是一个非常简单的光照模型。你可以使用更复杂的模型来实现更丰富,更真实的效果。

原创粉丝点击