D3D12渲染技术之光源

灯光有Point光源,Spot光源,Directional光源,Area光源等等,网上这方面的文章很多,在此我们就不详细介绍每个光源的计算公式了,我们直接介绍将光源应用到我们的案例中。先看我们已经实现好的案例截图:
在这里插入图片描述

顶点格式

照明计算需要表面法线, 我们使用顶点定义法线,然后在三角形的像素上插入这些法线,以便我们可以对每个像素进行光照计算。 而且,我们不再指定顶点颜色, 相反,通过对每个像素应用照明方程来生成像素颜色, 为了支持顶点法线,我们修改我们的顶点结构,如下所示:

// C++ Vertex structure
struct Vertex
{
  DirectX::XMFLOAT3 Pos;
  DirectX::XMFLOAT3 Normal;
};
 
// Corresponding HLSL vertex structure
struct VertexIn
{
  float3 PosL  : POSITION;
  float3 NormalL : NORMAL;
};
When we add a new vertex format, we need to describe it with a new input layout description:
mInputLayout =,
{
  { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, 
   D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
};

法线计算

GeometryGenerator中的形状函数已经创建了具有顶点法线的数据,因此我们都设置在那里。 但是,因为我们在这个演示中修改网格的高度使其看起来像地形,我们需要自己为地形生成法线向量。
因为我们的地形表面由函数y = f(x,z)给出,我们可以使用微积分直接计算法向量,而不是前面描述的常规平均计算。 对于曲面上的每个点,我们通过取偏导数在+ x-和+ z-方向上形成两个切向量:
在这里插入图片描述
这两个矢量位于表面点的切平面中, 计算法线向量得到:
在这里插入图片描述
我们用于生成地形网格的函数是:
在这里插入图片描述
偏导数是:
在这里插入图片描述
因此,表面点(x,f(x,z),z)处的表面法线由下式给出:
在这里插入图片描述
我们注意到这个曲面法线不是单位长度,因此需要在光照计算之前进行标准化。特别是,我们在每个顶点处进行上述常规计算以获得顶点法线:

XMFLOAT3 LitWavesApp::GetHillsNormal(float x, float z)const
{
  // n = (-df/dx, 1, -df/dz)
  XMFLOAT3 n( -0.03f*z*cosf(0.1f*x) - 0.3f*cosf(0.1f*z),
    1.0f,
    -0.3f*sinf(0.1f*x) + 0.03f*x*sinf(0.1f*z));
 
  XMVECTOR unitNormal = XMVector3Normalize(XMLoadFloat3(&n));
  XMStoreFloat3(&n, unitNormal);
 
  return n;
}

水面的法向矢量以类似的方式完成, 可以使用有限差分方案来近似每个顶点处的切向量。

更新灯光方向

我们的Lights数组被放入per-pass常量缓冲区, 该案例使用一个方向灯来表示太阳,并允许用户使用向左,向右,向上和向下箭头键旋转太阳位置。 因此,每一帧,我们都需要从太阳计算新的光方向,并将其设置为通道常量缓冲区。
我们以球坐标(ρ,θ,φ)跟踪太阳位置,但半径ρ无关紧要,因为我们假设太阳是无限远的。 特别是,我们只使用ρ= 1使其位于单位球面上并将(1,θ,φ)解释为朝向太阳的方向,以下是更新太阳的相关代码。

float mSunTheta = 1.25f*XM_PI;
float mSunPhi = XM_PIDIV4;
 
void LitWavesApp::OnKeyboardInput(const GameTimer& gt)
{
  const float dt = gt.DeltaTime();
 
  if(GetAsyncKeyState(VK_LEFT) & 0x8000)
    mSunTheta -= 1.0f*dt;
 
  if(GetAsyncKeyState(VK_RIGHT) & 0x8000)
    mSunTheta += 1.0f*dt;
 
  if(GetAsyncKeyState(VK_UP) & 0x8000)
    mSunPhi -= 1.0f*dt;
    if(GetAsyncKeyState(VK_DOWN) & 0x8000)
    mSunPhi += 1.0f*dt;
 
  mSunPhi = MathHelper::Clamp(mSunPhi, 0.1f, XM_PIDIV2);
}
 
void LitWavesApp::UpdateMainPassCB(const GameTimer& gt)
{
    …
  XMVECTOR lightDir = -MathHelper::SphericalToCartesian(1.0f, mSunTheta, mSunPhi);
 
  XMStoreFloat3(&mMainPassCB.Lights[0].Direction, lightDir);
  mMainPassCB.Lights[0].Strength = { 0.8f, 0.8f, 0.7f };
 
  auto currPassCB = mCurrFrameResource->PassCB.get();
  currPassCB->CopyData(0, mMainPassCB);
}
 

Light数组放入per-pass常量缓冲区意味着每个渲染通道不能超过16个(我们支持的最大光数)灯, 这对于Demo来说已经足够了。 然而,对于大型游戏世界来说,这还不够,因为你可以想象有数百个灯光的游戏关卡遍布整个关卡, 解决此问题的一种方法是将Light数组移动到每个对象的常量缓冲区。 然后,对于每个对象,搜索场景并找到影响对象的灯光,并将这些灯光绑定到常量缓冲区。 影响对象的灯光是其体积(点光源和聚光灯锥体)与其相交的灯光, 另一种流行的策略是使用延迟渲染或前向+渲染。

Lighting为我们的着色器程序引入了一个新的材质常量缓冲区, 为了支持这一点,我们需要更新根签名以支持额外的常量缓冲区。 与每个对象常量缓冲区一样,我们使用材质常量缓冲区的根描述符来支持直接绑定常量缓冲区,而不是通过描述符堆。

代码下载地址:链接:https://pan.baidu.com/s/1X0Vikf6qGYGPKU-Nwf-wYA 密码:h79q

已标记关键词 清除标记
相关推荐
程序员的必经之路! 【限时优惠】 现在下单,还享四重好礼: 1、教学课件免费下载 2、课程案例代码免费下载 3、专属VIP学员群免费答疑 4、下单还送800元编程大礼包 【超实用课程内容】  根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能!   套餐中一共包含2门MySQL数据库必学的核心课程(共98课时)   课程1:《MySQL数据库从入门到实战应用》   课程2:《高性能MySQL实战课》   【哪些人适合学习这门课程?】  1)平时只接触了语言基础,并未学习任何数据库知识的人;  2)对MySQL掌握程度薄弱的人,课程可以让你更好发挥MySQL最佳性能; 3)想修炼更好的MySQL内功,工作中遇到高并发场景可以游刃有余; 4)被面试官打破沙锅问到底的问题问到怀疑人生的应聘者。 【课程主要讲哪些内容?】 课程一:《MySQL数据库从入门到实战应用》 主要从基础篇,SQL语言篇、MySQL进阶篇三个角度展开讲解,帮助大家更加高效的管理MySQL数据库。 课程二:《高性能MySQL实战课》主要从高可用篇、MySQL8.0新特性篇,性能优化篇,面试篇四个角度展开讲解,帮助大家发挥MySQL的最佳性能的优化方法,掌握如何处理海量业务数据和高并发请求 【你能收获到什么?】  1.基础再提高,针对MySQL核心知识点学透,用对; 2.能力再提高,日常工作中的代码换新貌,不怕问题; 3.面试再加分,巴不得面试官打破沙锅问到底,竞争力MAX。 【课程如何观看?】  1、登录CSDN学院 APP 在我的课程中进行学习; 2、移动端:CSDN 学院APP(注意不是CSDN APP哦)  本课程为录播课,课程永久有效观看时长 【资料开放】 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化。  下载方式:电脑登录课程观看页面,点击右侧课件,可进行课程资料的打包下载。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页