Direct X 12 – Texture 贴图

9.11 Hills and Waves Demo

本章节的demo与之前大体上相同,不过我们为地面以及水面加入了贴图。我们遇到的第一个问题就是在地面上tile贴图。由于地面是一个面积巨大网格模型,如果我们只是将一张贴图进行拉伸,那么每个三角形网格上的texel点将会很少。也就是贴图的分辨率会很低。因此,我们需要在地形的网格模型上去重复贴图以得到更高的分辨率。第二个问题是,我们如何让水面贴图基于时间在水面的网格模型上产生滚动的效果。而这个效果也能让水面看上去更为真实。以下为该demo的截图。

9.11.1 生成贴图坐标

下图展示了xz平面中的一个由m x n个格子组成的平面,而每个顶点的贴图坐标位于范围[0,1]内。顶点ij的贴图坐标为:

因此,我们可以使用以下代码来生成每个格子的贴图坐标:

GeometryGenerator::MeshData
GeometryGenerator::CreateGrid(float width, float depth, uint32 m, uint32 n)
{
    MeshData meshData;
    uint32 vertexCount = m * n;
    uint32 faceCount = (m - 1) * (n - 1) * 2;
    float halfWidth = 0.5f * width;
    float halfDepth = 0.5f * depth;
    float dx = width / (n - 1);
    float dz = depth / (m - 1);

    float du = 1.f / (n - 1);
    float dz = 1.f / (m - 1);

    meshData.Vertices.resize(vertexCount);

    for(uint32 i = 0; i < m; ++i)
    {
        float z = halfDepth - i * dz;
        for(uint32 j = 0; j < n; ++j)
        {
            float x = -halfWidth + j * dx;
            meshData.Vertices[i * n + j].Position = XMFLOAT3(x, 0.f, z);
            meshData.Vertices[i * n + j].Normal = XMFLOAT3(0.f, 1.f, 0.f);
            meshData.Vertices[i * n + j].TangentU = XMFLOAT3(1.f, 0.f, 0.f);

            // 生成贴图坐标
            meshData.Vertices[i * n + j].TexC.x = j * du;
            meshData.Vertices[i * n + j].TexC.z = i * dv;
        }
    }

    ...
}

9.11.2 贴图Tiling

正如之前提到的,我们将在地面的网格模型上tile一张贴图。但是根据上面的代码,我们所计算的贴图坐标仍然在范围[0,1]之内。为了tile贴图,我们需要使用wrap address mode并且使用贴图转换矩阵将贴图坐标缩放4倍。之后,贴图坐标的范围将变为[0, 5],这也意味着贴图在地面网格模型上被tile了5 x 5倍:

void TexWavesApp::BuildRenderItems()
{
    auto gridRitem = std::make_unique<RenderItem>();
    gridRitem->World = MathHelper::Identity4x4();
    XMStoreFloat4x4(&gridRitem->TexTransform,
        XMMatrixScaling(5.f, 5.f, 1.f));

    ...
}

9.11.3 贴图动画

为了让水面贴图在水面模型上产生位移效果,我们将在函数AnimateMaterial中基于时间去移动贴图坐标。如果每一帧的位移都很小,那么就能产生较为顺滑的动画效果。我们的贴图是无缝的,而且使用了wrap address mode,因此可以一直在移动贴图的坐标。以下代码展示了如何计算水面贴图的位移向量和如何构建水面贴图的矩阵:

void TexWavesApp::AnimateMaterials(const GameTimer& gt)
{
    // 使水面贴图产生位移
    auto waterMat = mMaterials["water"].get();
    
    float& tu = waterMat->MatTransform(3, 0);
    float& tv = waterMat->MatTransform(3, 1);

    tu += 0.1f * gt.DeltaTime();
    tv += 0.02f * gt.DeltaTime();

    if(tu >= 1.f)
        tu -= 1.f;
    
    if(tv >= 1.f)
        tv -= 1.f;

    waterMat->MatTransform(3, 0) = tu;
    waterMat->MatTransform(3, 1) = tv;

    // 由于材质的数据发生了变化,我们需要更新constant buffer。
    waterMat->NumFramesDirty = gNumFrameResources;
}

《Direct X 12 – Texture 贴图》有5条留言

  1. 老铁,这本书的中译版正在走最后阶段,预计今年就要出版了……
    而且这本书坑很多,如果要翻译造福大家,请用心……
    谢谢!

    回复
    • 哈哈,中文版已经要出版啦,是在审核还是在翻译?是程序员翻译的么,还是那种大学老师翻译的?写这本书的老铁感觉没有写dx11时那么认真,里面有些东西直接从上一本拷过来。。坑的话我觉得还行吧,就是一些要点容易遗漏。。。

      回复
      • 已经在最后审核期了,大约几个月后就能出了吧~
        如果不是这些坑,这本书的中文版半年前可能就已经出来了……
        十分同意老铁的感觉,尤其是改得还不彻底,还漏了些东西。
        最坑的是阿三带领的微软团队,随着win10的更新方式的更改,隔半年就有新特性、新函数加进去,简直是坑神之神吗~ XD
        另外,题外话,就冲着win10,我感觉GitHub早晚要被微软玩儿坏……
        应该说算是程序员翻译的,之前做过相关的东西,我觉得中译本质量应该还算说得过去,如果出版社不坑的话……到现在,这本书已经翻译快满两年了,一个人翻译的……
        不管怎么说,也要感谢老铁在业余时间给大伙分享技术!
        DX 12与福尔康一样,偏底层,不好(容易)玩儿,到现在也没见有谁正经用它优化,做出什么强大的游戏来……
        您翻译的速度还真是挺快的……orz
        我记得今年八月rtr 4th就要来了,如果能翻译好,定是国内图形界的福音啦~ 🙂

        回复
        • 额。。。两年也太久了吧,辛苦啦,哈哈。我是觉得翻译的话,对书中知识点的理解挺有用的,如果只是粗略地看比较容易漏。。
          DX12可能还是微软自己旗下的工作室在用吧,这一个世代的xbx one肯定还是DX11为主。。看看下一代主机上新的话能不能普及DX12

          回复
          • 扎心啊,老铁!
            里面的事儿太多太杂,水深啊……如果愿意的话,届时买一本(估摸也不太可能……)看看就明白了……不过他马上就要弄完了,好歹算了了这件心事儿啦……据说裤衩都要当出去鸟……
            总是在黑暗的角落里暗想,这玩意儿也许他们自己也不会使的,驱动配合、无穷更新……统统加起来这玩意儿其实……
            嗯,这次1803倒没更新什么东西,说明相对趋于稳定了,或许这个节骨眼儿上发出中译本是个合适的时机?谁知道捏……
            最后再贫一句话,书里的错误有软有硬,所以就算是一字一句对着翻出来,结果也可想而知,这就是为什么这本要花那么长时间准备的原因之一啦,老铁!所以,我才会说如果要翻译给大家看,要用心啦……

留下评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据