热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

附有纹理的山川演示程序(第九章内容)

仅供个人学习使用,请勿转载。谢谢!附有纹理的山川演示程序(第九章内容)9.11、附有纹理的山川演示程序在该演示程序中,我们将会为陆地和河流的场景演示程序中添加纹理。为陆地和河流的场

仅供个人学习使用,请勿转载。谢谢!


附有纹理的山川演示程序(第九章内容)

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

在该演示程序中,我们将会为陆地和河流的场景演示程序中添加纹理。为陆地和河流的场景演示程序添加纹理主要有两个问题:



  1. 由于陆地的网格是一个极大且不规则的曲面,所以如果只是简单的拉伸纹理,将导致每个三角形只能分配到极少量的纹素,即最终只能得到纹理放大的失真效果。目前的解决方案是通过多次重复铺设纹理以获得更高的分辨率,从而改善失真。

  2. 我们要根据时间函数让水流纹理随着波浪几何体流动起来


9.11.1、生成栅格纹理坐标

假设有一个位于平面xz内的mxn栅格,栅格内的顶点坐标和归一化纹理坐标一一对应,则纹理坐标系中第i行,第j列的顶点坐标为

\[
u = j·u1;v = i`v1
\]

\[
u1 = 1/(n-1);v1 = 1/(m-1)
\]

上述公式的推演过程不展开介绍了。

根据上述公式,我们可以生成栅格的纹理坐标:

/*
** Summary:生成栅格顶点
** Parameters:
** width:栅格的宽度
** depth:栅格的深度
** m:行数
** n:列数
** Return:栅格的网格数据
*/
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.0f / (n-1);
float dv = 1.0f / (m-1);
meshData.Vertices.resize(vertexCount);
for(uint32 i = 0; i {
float z = halfDepth - i*dz;
for(uint32 j = 0; 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);

//根据栅格拉伸纹理
meshData.Vertices[i*n+j].TexC.x = j*du;
meshData.Vertices[i*n+j].TexC.y = i*dv;
}
}

9.11.2、铺设纹理

我们要在陆地网格上铺设纹理,但是目前为止我们所计算的纹理坐标仅限于单位域[0,1]内,所以,我们需要指定重复寻址模式,然后通过纹理变换矩阵使纹理坐标按比例增大5倍,这样纹理坐标将会被映射到区间[0,5]中,纹理也会在陆地网格上重复铺设5x5次了。

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

9.11.3、纹理动画

为了使水流纹理可以随着波浪几何体流动,我们需要在每一个更新周期中调用AnimateMaterial方法,以此根据时间函数在纹理平面内平移纹理坐标。我们使用重复寻址模式进行纹理贴图,这样就可以沿着纹理坐标平面接连不断的平移纹理坐标。下列代码展示了如何计算水流纹理的偏移向量,并且构建并设置流水的纹理矩阵

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.0f)
tu -= 1.0f;
if(tv >= 1.0f)
tv -= 1.0f;
waterMat->MatTransform(3, 0) = tu;
waterMat->MatTransform(3, 1) = tv;
// 材质已经发生变化,更新常量缓冲区
waterMat->NumFramesDirty = gNumFrameResources;
}

9.11.4、示例程序演示效果

技术分享图片


9.12、小结



  1. 纹理坐标用于定义将要映射到3D三角形上的纹理三角形

  2. 对于游戏而言,创建纹理的常用方法是:贴图师在图像编辑器(如Photoshop)中进行创作,然后打包成某一种格式的图像文件,如BMP、DDS、TGA或PNG等等,然后游戏应用程序会在加载资源的时候将图像资源载入ID3DResource对象。(对于实时图形应用程序来说,DDS图像文件格式是最好的选择

  3. 到处DDS文件格式的方法:使用图像编辑器或者微软提供的texconv的命令行工具。

  4. 我们可以通过CreateDDSTextureFromFile12函数来创建纹理

  5. 当我们放大或者缩小物体表面时,会出现需要以少量纹素来覆盖大量屏幕像素或者以大量纹素来覆盖少量屏幕像素的问题,这个时候我们需要涉及纹理放大和纹理缩小的相关操作。mipmap和纹理过滤器是处理纹理缩小和放大的关键技术。GPU支持3中原生的纹理过滤器(根据质量由低到高,开销由低到高排序)——点过滤,线性过滤,各向异性过滤。

  6. 纹理的寻址模式定义了DirectX3D如何处理超过[0,1]范围的纹理坐标,常用的寻址模式由四种:重复寻址模式、边框颜色寻址模式、镜像寻址模式和钳位寻址模式

  7. 我们可以像变换普通的2D点一样,利用纹理坐标对纹理进行缩放,旋转和平移操作,通过在每一帧中小幅度并且渐进的变换纹理坐标,我们可以实现纹理的动画效果。


推荐阅读
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文内容为asp.net微信公众平台开发的目录汇总,包括数据库设计、多层架构框架搭建和入口实现、微信消息封装及反射赋值、关注事件、用户记录、回复文本消息、图文消息、服务搭建(接入)、自定义菜单等。同时提供了示例代码和相关的后台管理功能。内容涵盖了多个方面,适合综合运用。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文介绍了一种解析GRE报文长度的方法,通过分析GRE报文头中的标志位来计算报文长度。具体实现步骤包括获取GRE报文头指针、提取标志位、计算报文长度等。该方法可以帮助用户准确地获取GRE报文的长度信息。 ... [详细]
  • PDF内容编辑的两种小方法,你知道怎么操作吗?
    本文介绍了两种PDF内容编辑的方法:迅捷PDF编辑器和Adobe Acrobat DC。使用迅捷PDF编辑器,用户可以通过选择需要更改的文字内容并设置字体形式、大小和颜色来编辑PDF文件。而使用Adobe Acrobat DC,则可以通过在软件中点击编辑来编辑PDF文件。PDF文件的编辑可以帮助办公人员进行文件内容的修改和定制。 ... [详细]
  • CentOS 6.5安装VMware Tools及共享文件夹显示问题解决方法
    本文介绍了在CentOS 6.5上安装VMware Tools及解决共享文件夹显示问题的方法。包括清空CD/DVD使用的ISO镜像文件、创建挂载目录、改变光驱设备的读写权限等步骤。最后给出了拷贝解压VMware Tools的操作。 ... [详细]
  • 深入理解CSS中的margin属性及其应用场景
    本文主要介绍了CSS中的margin属性及其应用场景,包括垂直外边距合并、padding的使用时机、行内替换元素与费替换元素的区别、margin的基线、盒子的物理大小、显示大小、逻辑大小等知识点。通过深入理解这些概念,读者可以更好地掌握margin的用法和原理。同时,文中提供了一些相关的文档和规范供读者参考。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
author-avatar
苗Tinal3
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有