d3d12龙书学习之MiniEngine的最小化实现(四) 光照shader的实现

    xiaoxiao2021-04-15  282

    文章目录

    前言修改MiniEngine的坐标转换d3d12book的光照shader添加shapes对应的光照shader最终结果为什么结果比d3d12book的要亮

    前言

    光照的实现,主要是shader做的,C++代码层没添加多少东西。 理解了shader,看懂d3d12book的源码,shader直接拷进来,C++代码直接转过来就可以了。 难度主要是看懂shader。对于光照的计算,应该说我也没有深入学,仅仅是了解了一些概念,就像是很多数学公式我也不会推一样。正确理解自己的能力,做好能力范围内的事情,对于数学的提高,觉得可以稍微靠后放一放。主要还是学习d3d12的一些使用上的东西。

    修改MiniEngine的坐标转换

    在前边的学习过程中,就挺纠结的。因为在VS shader中mul函数的俩参数是反过来的。最初以为是MiniEngine做了什么奇怪的操作,后来发现不是。 这篇博客讲得很清楚,可以学习下。 https://www.cnblogs.com/X-Jun/p/9808727.html

    我觉得 mul(点,矩阵) 更符合直觉,也更符合公式。 所以第八章第一步就是要在C++部分对传入的矩阵先做一次转置。 为了更好的贴合d3d12book的shader,也同样的把常量缓冲区改成3部分,只是槽有点区别。

    先实现shapes这个例子,只需要两个常量缓冲区,一个放入模型转世界的矩阵,一个放入摄像机的世界转投影矩阵。 简易的修改如下:

    修改根签名: m_RootSignature.Reset(3, 0); m_RootSignature[0].InitAsConstantBuffer(0, D3D12_SHADER_VISIBILITY_VERTEX); m_RootSignature[1].InitAsConstantBuffer(1, D3D12_SHADER_VISIBILITY_ALL); 动态传入投影矩阵的转置矩阵 __declspec(align(16)) struct { Matrix4 viewProj; // 从世界坐标转为投影坐标的矩阵 }passConstants; // https://www.cnblogs.com/X-Jun/p/9808727.html // C++代码端进行转置,HLSL中使用matrix(列矩阵) // mul函数让向量放在左边(行向量),实际运算是(行向量 X 行矩阵) 然后行矩阵为了使用dp4运算发生了转置成了列矩阵 passConstants.viewProj = Transpose(m_ViewProjMatrix); gfxContext.SetDynamicConstantBufferView(1, sizeof(passConstants), &passConstants); 修改模型的世界矩阵为转置矩阵 // box item.modelToWorld = Transpose(Matrix4(AffineTransform(Matrix3::MakeScale(2.0f, 2.0f, 2.0f), Vector3(0.0f, 0.5f, 0.0f)))); item.indexCount = (UINT)box.Indices32.size(); item.startIndex = boxIndexOffset; item.baseVertex = boxVertexOffset; item.diffuseAlbedo = XMFLOAT4(Colors::LightSteelBlue); item.fresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f); item.roughness = 0.3f; m_vecShapes.push_back(item); .... 修改vs shader中mul的参数顺序 本步骤的github代码地址: https://github.com/mversace/DirectX12-MiniEngine-Dragon/tree/9ac87af5b5bab2da12f745a75936f6a45ca736b1

    d3d12book的光照shader

    对于光照,书中讲的已经很详细了。 在d3d12book项目中。LightingUtil.hlsl就是一个通用的计算光照的文件。 就是把书中讲的计算公式写成了shader。

    而对于MiniEngine中呢,这一部分写的是比较复杂的,主要是牵扯的参数比较多,比如包含了纹理的参数。 本章内容纹理是没有的,只是提供了光照渲染需要的3个参数。 对于MiniEngine中的光照shader,将在学习纹理之后一次性加进去,到时候做个替换。

    d3d12book的shader复杂就是计算光照的模块,这部分跳过,因为我也没背下来。我觉得暂时会用就可以了。

    添加shapes对应的光照shader

    我们直接把LightingUtil.hls放入我们工程,然后改写vs和ps文件 在vs文件中,传入的不再是颜色,而是当前顶点的法向量。传给ps多一个法向量参数

    VertexOut vout = (VertexOut)0.0f; // 将定点转化为世界坐标系中的点 float4 posW = mul(float4(vin.PosL, 1.0f), modelToWorld); vout.PosW = posW.xyz; // 将法向量转换成世界坐标系中的法向量 vout.NormalW = mul(vin.NormalL, (float3x3)modelToWorld); // 点转化为投影坐标系中的点 vout.PosH = mul(posW, gViewProj); return vout;

    再来看下ps文件,ps文件中有一个常量缓冲区,也就是1槽的数据,这个每一帧都会写入的 不需要d3d12book中的那么多参数,只需要如下几个就好了

    cbuffer cbPass : register(b1) { float4x4 gViewProj; // 投影坐标系矩阵 float3 gEyePosW; // 摄像机位置 float cbPerObjectPad1; // 忘记删了,没啥用 float4 gAmbientLight; // 环境光 // Indices [0, NUM_DIR_LIGHTS) are directional lights; // indices [NUM_DIR_LIGHTS, NUM_DIR_LIGHTS+NUM_POINT_LIGHTS) are point lights; // indices [NUM_DIR_LIGHTS+NUM_POINT_LIGHTS, NUM_DIR_LIGHTS+NUM_POINT_LIGHT+NUM_SPOT_LIGHTS) // are spot lights for a maximum of MaxLights per object. Light gLights[MaxLights]; // 平行光源 }; // 2槽放入纹理,不同的渲染物体会动态塞入不同的纹理 cbuffer cbMaterial : register(b2) { float4 gDiffuseAlbedo; // 漫反射反射率 float3 gFresnelR0; // 材质属性 float gRoughness; // 粗糙度 };

    main函数也是很简单的,因为复杂的光照计算都封装在LightingUtil.hls中了

    // 法向量规范化 pin.NormalW = normalize(pin.NormalW); // 当前点反射到眼睛的向量 float3 toEyeW = normalize(gEyePosW - pin.PosW); // 漫发射直接点积就可以 float4 ambient = gAmbientLight * gDiffuseAlbedo; // 构造材质参数,计算光照结果。gLights是一个光照数组 const float shininess = 1.0f - gRoughness; Material mat = { gDiffuseAlbedo, gFresnelR0, shininess }; float3 shadowFactor = 1.0f; float4 directLight = ComputeLighting(gLights, mat, pin.PosW, pin.NormalW, toEyeW, shadowFactor); // 漫反射+其他光源,得出最后的颜色值 float4 litColor = ambient + directLight; // Common convention to take alpha from diffuse material. litColor.a = gDiffuseAlbedo.a; return litColor;

    最终结果

    shapes git: https://github.com/mversace/DirectX12-MiniEngine-Dragon/tree/b1fd81579267c8b8f657c62a90d8e4314fd174ec land and waves git: https://github.com/mversace/DirectX12-MiniEngine-Dragon/tree/032bc099f71261fed81c497406b864d39885979f

    为什么结果比d3d12book的要亮

    最初我看到,也是调了挺久。后来发现是MiniEngine自带了动态光照技术(HDR,LDR)。 可以直接把图象渲染到交换链中的缓冲区就可以了。

    还有一个帧数问题。debug版本和release版本帧数差距极大,这点要注意。


    最新回复(0)