[C++]DirectX 12 3D游戏开发实战—第9章 学习笔记03 2019.5.4

@个人学习用,请勿转赞。

DirectX 12 3D游戏开发实战—第9章 学习笔记03

词汇

内容

9.11附有纹理的山川演示程序

  • 给陆地网格重复铺设草地纹理
  • 根据时间函数令流水纹理延波浪滚动起来
  • 演示程序

9.11.1生成栅格纹理坐标

栅格

  • 上图是一个m*n的栅格,右侧是在归一化纹理坐标[0,1]2中与之相对应的栅格。
  • 纹理坐标中的第i行第j列顶点坐标为
    u i j = j ⋅ δ u u_{ij}=j·\delta uuij=jδu
    v i j = j ⋅ δ v v_{ij}=j·\delta vvij=jδv

其中,δ u = 1 n − 1 \delta u=\frac 1{n-1}δu=n11,δ v = 1 m − 1 \delta v=\frac 1{m-1}δv=m11

  • 据此根据GeometryGenerator::CreateGrid方法来生成栅格的纹理坐标
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;

	//
	// Create the vertices.
	//
	//创建顶点

	float halfWidth = 0.5f*width;
	float halfDepth = 0.5f*depth;

	float dx = width / (n-1);
	float dz = depth / (m-1);

	float du = 1.0f / (n-1);//计算纹理坐标,u的单位长度
	float dv = 1.0f / (m-1);//计算纹理坐标,v的单位长度

	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.0f, z);
			meshData.Vertices[i*n+j].Normal   = XMFLOAT3(0.0f, 1.0f, 0.0f);
			meshData.Vertices[i*n+j].TangentU = XMFLOAT3(1.0f, 0.0f, 0.0f);

			// Stretch texture over grid.
			//在栅格上拉伸纹理
			meshData.Vertices[i*n+j].TexC.x = j*du;//计算纹理坐标
			meshData.Vertices[i*n+j].TexC.y = i*dv;//计算纹理坐标
		}
	}
 

9.11.2铺设纹理

指定重复寻址模式,并通过纹理变换矩阵使纹理坐标按比例放大5倍,纹理坐标就会被映射到区间[0,5]中,而纹理也会咋陆地网格上铺设5*5次

void TexWavesApp::BuildRenderItems()
{

    auto gridRitem = std::make_unique<RenderItem>();
    gridRitem->World = MathHelper::Identity4x4();
	XMStoreFloat4x4(&gridRitem->TexTransform, XMMatrixScaling(5.0f, 5.0f, 1.0f));
	...
}

9.11.3纹理动画

时流水纹理顺着波浪滚动播放,需要在每个更新周期中调用AnimationMaterials方法,以此根据时间函数在纹理平面内平移纹理坐标,每帧的位移量要小以使动画看上去更平滑流畅。

  • 使用无缝纹理按重复寻址进行贴图。
void TexWavesApp::AnimateMaterials(const GameTimer& gt)
{
	// Scroll the water material texture coordinates.
	//使流水材质的纹理坐标滚动起来
	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.0f)
		tu -= 1.0f;

	if(tv >= 1.0f)
		tv -= 1.0f;

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

	// Material has changed, so need to update cbuffer.
	//材质发生变化,更新常量缓冲区
	waterMat->NumFramesDirty = gNumFrameResources;
}

9.12小结

  1. 纹理坐标用于定义将要映射到3D三角形上的纹理三角形
  2. 游戏创建纹理的常用方法是在图像编辑工具中创作完后存储为图像文件,然后在游戏加载资源的期间载入ID3D12Resource对象
  3. nVidia的Photoshop插件和texconv可以将传统图像格式改成DDS格式
  4. 通过CreateDDSTextureFromFile12函数以存于磁盘中的图像文件来创建纹理
  5. 纹理放大和纹理缩小问题
  6. 纹理的寻址模式定义了Direct3D如何处理超出范围的纹理坐标
  7. 可以像变换普通点那样利用纹理坐标堆对纹理进行变换

版权声明:本文为qq_36028073原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。