这篇文章中,我们将实现在 HLSL 下的漫反射光照绘制。漫反射的原理我们在 OpenGL 学习笔记中已经详细提及,这里就省下篇幅了。
首先我们修改之前的立方体代码来给漫反射光照做准备。我们将绘制一个缓慢转动的立方体模型并为他贴图,然后我们需要一个光源,使用一个比较小的白色立方体代替。
重新定义顶点数据结构:
1 | struct Vertex |
之后,我们更改立方体的顶点(由于法线的原因,导致我们会将顶点的个数扩展到24个),并且更新索引:
1 | Vertex vertices[] = { |
这是我们绘制立方体的时候使用的新的数据(具体绘制过程有兴趣的可以去看源码),由于我们需要绘制光源,所以需要简单的光源立方体使用的着色器程序,如下:
1 | // lightVertexShader.hlsl |
现在,进行绘制,同时使用 XMMatrixRotation
方法使其旋转:
1 | cubeWorld = cubeWorld * XMMatrixRotationX(0.0001f) * XMMatrixRotationY(0.0001f) * XMMatrixRotationZ(0.0001f); |
现在你应该看到的是一个旋转的立方体和一个在立方体上方的光源,如下:
接下来就是 HLSL 中的代码了。首先修改顶点着色器的数据结构:
1 | struct vertexInputType { |
同时在对顶点着色器中变换坐标的同时也变换法线坐标:
1 | pixelInputType main( vertexInputType input ){ |
有了法线之后,我们可以在像素着色器中根据法线与光照方向的夹角 cos 值来计算颜色了。首先我们使用硬编码写好光源位置和环境光大小:
1 | float ambient = 0.1f; |
之后计算光照方向:
1 | float3 lightDir = - lightPos; |
最后,使用光照方向的反向量来和法线向量点乘获得 cos 值:
1 | float diffuse = saturate(dot(normalize(input.normal), normalize(-lightDir))); // staturate 将其值限制在 0 1 区间内 |
配合纹理颜色和环境光颜色来计算最终颜色:
1 | return tex.Sample(samp , input.texcoord) * (ambient + diffuse); |
最终效果如下: