纹理贴图映射(texturemapping)是可以显著提高场景细节和真实感的一种技术,基本原理是将图像数据映射到3D三角形表面(之前的文章提到过,三维模型其实是由很多个三角形拼接而成)。当使用纹理资源时,只要将每个3D三角形与纹理资源上的三角形对应,就可以实现贴图效果。如图1,有一个立方体模型和纹理贴图,将立方体上的点与纹理贴图上的点对应,就像给一个没有颜色的正方体贴一层木纹包装纸。

Direct3D的纹理坐标系由表示图像水平方向的u轴和表示图像垂直方向的v轴组成。坐标 (u,v) 指定了纹理上的一个元素,该元素称为纹理元素(texture element),其中 0≤u,v≤1。将规范化坐标区间设为[0,1]是因为这样可以使Direct3D拥有一个独立于纹理尺寸的坐标空间。即无论纹理的实际尺寸是 256×256还是512×512,(0.5,0.5)永远表示中间的纹理元素。

另外还有一个问题,纹理资源不管多精细都是由离散的数据点组成,如果指定的纹理坐标(u,v)与任何一个纹理元素点都不对应时该怎么办?如图1中的立方体。假设木头纹理的分辨率为 512×512,显示器的分辨率为 1024×1024,当观察点逐渐靠近立方体,立方体会被放大,甚至能盖住整个屏幕。这时就需要用很少的纹理元素来覆盖很多的像素,称为倍增。与倍增相反的问题是缩减,要用很多的纹理元素来覆盖很少的像素。DirectX为解决这些问题定义了多种过滤器,如点过滤和线性过滤。使用时只要对应好顶点和其纹理坐标,过滤器就能通过插值或抽取估计顶点之间每个像素的颜色。

下面就来实现纹理贴图映射。

使用模版新建Direct3D立方体项目。首先依然是更改HLSL代码。

顶点着色器部分:使用纹理资源时不需要指定颜色,所以用这部分空间存储顶点的法向量,用于计算光照效果。添加纹理坐标成员,它与3D顶点坐标对应。这样,每3个顶点构成的3D三角形在纹理空间中都会有一个对应的2D纹理三角形。代码如下:

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{matrix model;matrix view;matrix projection;
};struct VertexShaderInput
{float3 pos : POSITION;float3 normal : NORMAL;float2 tex : TEXCOOD;
};struct VertexShaderOutput
{float4 pos : SV_POSITION;float3 normal : NORMAL;float2 tex : TEXCOOD;
};VertexShaderOutput main(VertexShaderInput input)
{VertexShaderOutputoutput;float4 pos = float4(input.pos, 1.0f);// 转换坐标到投影空间pos = mul(pos,model);pos = mul(pos,view);pos = mul(pos,projection);output.pos =pos;// 转换法向量到世界空间用于光照计算float4 normal = float4(normalize(input.normal),0.0f);normal =mul(normal, model);output.normal =normalize(normal.xyz);// 纹理坐标不需要改动output.tex =input.tex;return output;
}

像素着色器部分:输入结构体定义必须和顶点着色器的输出结构体格式一致。还要添加纹理资源,并在main方法中添加简单漫反射光的计算。另外,使用过滤器访问纹理资源需要通过采样器。代码如下:

SamplerState samplerLinear : register(s0);
Texture2D woodDiffuse : register(t0);struct PixelShaderInput
{float4 pos : SV_POSITION;float3 normal : NORMAL;float2 tex : TEXCOOD;
};float4 main(PixelShaderInput input) : SV_TARGET
{float3 lightDirection =normalize(float3(1, -1, 0));float4 texelColor = woodDiffuse.Sample(samplerLinear,input.tex);// 计算简单漫反射float lightMagnitude =0.8f * saturate(dot(input.normal, -lightDirection)) + 0.2f;return texelColor *lightMagnitude;
}

HLSL代码完成后就要修改主程序。在Windows 8 Store App中载入纹理资源可以使用WICTextureLoader。它支持读取多种图片资源(jpg、png)创建纹理。使用时将.cpp和.h文件加入项目即可。如果想载入DDS格式的资源可以看DirectXTex的说明。

完成后在CubeRenderer类里更改结构体定义,与着色器对应:

struct VertexPositionColor
{DirectX::XMFLOAT3 pos;DirectX::XMFLOAT3 normal;DirectX::XMFLOAT2 tex;
};

然后添加三个成员以使用纹理资源和采样器:

ID3D11Resource* tex;
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_WoodSRV;
Microsoft::WRL::ComPtr<ID3D11SamplerState> m_Sampler;

接着就开始修改初始化部分。在CreateDeviceResources方法中在载入顶点着色器和像素着色器之后添加createWoodTexTask,用于初始化纹理资源和采样器:

auto createWoodTexTask = (createPSTask &&createVSTask).then([this] () {DX::ThrowIfFailed(CreateWICTextureFromFile(m_d3dDevice.Get(),m_d3dContext.Get(),L"wood.jpg",&tex,m_WoodSRV.GetAddressOf()));D3D11_SAMPLER_DESC samplerDesc;samplerDesc.Filter= D3D11_FILTER_MIN_MAG_MIP_LINEAR;samplerDesc.AddressU= D3D11_TEXTURE_ADDRESS_WRAP;samplerDesc.AddressV= D3D11_TEXTURE_ADDRESS_WRAP;samplerDesc.AddressW= D3D11_TEXTURE_ADDRESS_WRAP;samplerDesc.MipLODBias= 0;samplerDesc.MaxAnisotropy= 1;samplerDesc.ComparisonFunc= D3D11_COMPARISON_NEVER;samplerDesc.BorderColor[0 ] = 1.0f;samplerDesc.BorderColor[1 ] = 1.0f;samplerDesc.BorderColor[2 ] = 1.0f;samplerDesc.BorderColor[3 ] = 1.0f;samplerDesc.MinLOD= -3.402823466e+38F; // -FLT_MAXsamplerDesc.MaxLOD= 3.402823466e+38F; // FLT_MAXDX::ThrowIfFailed(m_d3dDevice->CreateSamplerState(&samplerDesc,m_Sampler.GetAddressOf()));});

接下来自然是设置顶点缓冲区和索引数组。顶点的数据需要根据结构体的变化修改:

auto createCubeTask = createWoodTexTask.then([this] () {VertexPositionColor cubeVertices[] ={// +x{XMFLOAT3( 0.5f,  0.5f, -0.5f), XMFLOAT3( 1.0f, 0.0f, 0.0f),XMFLOAT2(0.0f, 0.0f), },{XMFLOAT3( 0.5f,  0.5f, 0.5f), XMFLOAT3( 1.0f, 0.0f, 0.0f), XMFLOAT2(1.0f, 0.0f), },{XMFLOAT3( 0.5f, -0.5f,  0.5f), XMFLOAT3( 1.0f, 0.0f, 0.0f),XMFLOAT2(1.0f, 1.0f), },{XMFLOAT3( 0.5f, -0.5f,-0.5f), XMFLOAT3( 1.0f, 0.0f, 0.0f), XMFLOAT2(0.0f, 1.0f), },// -x{XMFLOAT3(-0.5f,  0.5f, -0.5f), XMFLOAT3(-1.0f, 0.0f, 0.0f),XMFLOAT2(0.0f, 0.0f), },{XMFLOAT3(-0.5f,  0.5f, 0.5f), XMFLOAT3(-1.0f, 0.0f, 0.0f), XMFLOAT2(1.0f, 0.0f), },{XMFLOAT3(-0.5f, -0.5f,  0.5f), XMFLOAT3(-1.0f, 0.0f, 0.0f),XMFLOAT2(1.0f, 1.0f), },{XMFLOAT3(-0.5f, -0.5f,-0.5f), XMFLOAT3(-1.0f, 0.0f, 0.0f), XMFLOAT2(0.0f, 1.0f), },// +y{XMFLOAT3(-0.5f,  0.5f, 0.5f), XMFLOAT3( 0.0f, 1.0f, 0.0f), XMFLOAT2(1.0f, 0.0f), },{XMFLOAT3( 0.5f,  0.5f, 0.5f), XMFLOAT3( 0.0f, 1.0f, 0.0f), XMFLOAT2(0.0f, 1.0f), },{XMFLOAT3( 0.5f,  0.5f, -0.5f), XMFLOAT3( 0.0f, 1.0f, 0.0f),XMFLOAT2(1.0f, 1.0f), },{XMFLOAT3(-0.5f,  0.5f, -0.5f), XMFLOAT3( 0.0f, 1.0f, 0.0f),XMFLOAT2(0.0f, 0.0f), },// -y{XMFLOAT3(-0.5f, -0.5f,  0.5f), XMFLOAT3( 0.0f, -1.0f,0.0f), XMFLOAT2(1.0f, 0.0f), },{XMFLOAT3( 0.5f, -0.5f,  0.5f), XMFLOAT3( 0.0f, -1.0f,0.0f), XMFLOAT2(0.0f, 1.0f), },{XMFLOAT3( 0.5f, -0.5f,-0.5f), XMFLOAT3( 0.0f, -1.0f, 0.0f), XMFLOAT2(1.0f, 1.0f), },{XMFLOAT3(-0.5f, -0.5f,-0.5f), XMFLOAT3( 0.0f, -1.0f, 0.0f), XMFLOAT2(0.0f, 0.0f), },// +z{XMFLOAT3(-0.5f,  0.5f, 0.5f), XMFLOAT3( 0.0f, 0.0f, 1.0f), XMFLOAT2(0.0f, 0.0f), },{XMFLOAT3( 0.5f,  0.5f, 0.5f), XMFLOAT3( 0.0f, 0.0f, 1.0f), XMFLOAT2(1.0f, 0.0f), },{XMFLOAT3( 0.5f, -0.5f,  0.5f), XMFLOAT3( 0.0f, 0.0f, 1.0f),XMFLOAT2(1.0f, 1.0f), },{XMFLOAT3(-0.5f, -0.5f,  0.5f), XMFLOAT3( 0.0f, 0.0f, 1.0f),XMFLOAT2(0.0f, 1.0f), },// -z{XMFLOAT3(-0.5f,  0.5f, -0.5f), XMFLOAT3( 0.0f, 0.0f,-1.0f), XMFLOAT2(1.0f, 0.0f), },{XMFLOAT3( 0.5f,  0.5f, -0.5f), XMFLOAT3( 0.0f, 0.0f,-1.0f), XMFLOAT2(0.0f, 0.0f), },{XMFLOAT3( 0.5f, -0.5f,-0.5f), XMFLOAT3( 0.0f, 0.0f, -1.0f), XMFLOAT2(0.0f, 1.0f), },{XMFLOAT3(-0.5f, -0.5f,-0.5f), XMFLOAT3( 0.0f, 0.0f, -1.0f), XMFLOAT2(1.0f, 1.0f), },};D3D11_SUBRESOURCE_DATA vertexBufferData ={0};vertexBufferData.pSysMem= cubeVertices;vertexBufferData.SysMemPitch= 0;vertexBufferData.SysMemSlicePitch= 0;CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER);DX::ThrowIfFailed(m_d3dDevice->CreateBuffer(&vertexBufferDesc,&vertexBufferData,&m_vertexBuffer));unsigned short cubeIndices[] ={0,2,1, // +x0,3,2,4,5,6, // -x4,6,7,8,10,9, // +y8,11,10,12,13,14,// -y12,14,15,16,17,18,// +z16,18,19,20,22,21,// -z20,23,22,};m_indexCount= ARRAYSIZE(cubeIndices);D3D11_SUBRESOURCE_DATA indexBufferData ={0};indexBufferData.pSysMem= cubeIndices;indexBufferData.SysMemPitch= 0;indexBufferData.SysMemSlicePitch= 0;CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER);DX::ThrowIfFailed(m_d3dDevice->CreateBuffer(&indexBufferDesc,&indexBufferData,&m_indexBuffer));});

完成后就可以在渲染时使用纹理资源了。在Render方法里添加以下代码使纹理资源生效:

// 设置纹理资源
m_d3dContext->PSSetShaderResources(0,1,m_WoodSRV.GetAddressOf());// 设置纹理采样器
m_d3dContext->PSSetSamplers(0,1,m_Sampler.GetAddressOf());

运行后效果如下图:

本篇文章的源代码:

DirectX_CubeTexture

Windows 8 Directx 开发学习笔记(十)纹理贴图实现旋转的木箱相关推荐

  1. Windows 8 Directx 开发学习笔记(十一)地形纹理贴图

    前一篇实现木箱贴图时,木箱的六个面都正好用一整张纹理图,即六个面的纹理坐标均在[0,1]内.然而在为比较大的模型贴图时,像山峰河谷模型,如果只用一张纹理图,那么每个三角形只得到几个纹理元素,无法为提供 ...

  2. Windows 8 Directx 开发学习笔记(十二)利用混合实现浮在水面的木箱

    在场景中绘制多个不透明物体时很简单,哪个物体离得近,看到的就是哪个物体.但如果加入一个透明的物体,像玻璃,如何渲染就有些麻烦.拿一块红色的玻璃挡住眼睛,看到的物体都偏红,换成蓝色的玻璃,物体都偏蓝.D ...

  3. Windows 8 Directx开发学习笔记(一)应用基本框架

    Windows 8系统10月25日就要正式发布,其应用可与Windows Phone 8应用兼容,所以打算转到Windows 8系列的开发.之前虽然开发过应用,但对游戏开发更感兴趣,随意开始学习Met ...

  4. Windows 8 DirectX 开发学习笔记(十六)使用Terragen生成自然环境贴图

    DirectX 游戏编程入门中提到一个Terragen软件可以生成环境贴图,所以登陆它的官方网站看了下.没想到Terragen生成的图片和照片一样,效果非常好,很多电影里有用到,所以下载免费版尝试一下 ...

  5. Windows 8 DirectX 开发学习笔记(十五)使用Billboard实现树木贴图

    要使用DirectX来获得三维效果,一般首先要生成一个三维模型,然后计算它在可视空间中的投影.这样得到的二维图像十分真实,但是计算量也很大.在大规模场景渲染中,随着模型精度的提高,这样的处理方式十分消 ...

  6. Windows 8 Directx 开发学习笔记(十四)使用几何着色器实现三角形细分

    几何着色器是从DirectX 10才引入的着色器,是一个可选阶段,位于顶点着色器和像素着色器阶段之间.顶点着色器以顶点作为输入数据,而几何着色器以完整的图元作为输入数据,像点.直线.三角形等.之所以引 ...

  7. Windows 8 Directx 开发学习笔记(十三)利用模板实现木箱镜像

    假设墙上有一面镜子,镜子前面有个木箱.如果观察角度合适,整个木箱镜像都会在镜子里,计算起来还比较简单:而变换个角度,木箱的镜像可能只有一部分在镜子里,这时单纯依靠计算来实现就很麻烦.DirectX提供 ...

  8. Windows 8 Directx 开发学习笔记(二)建立模型及初始化设备

    上一篇中介绍的DirectxApp类给整个应用搭建了一个框架,而这篇文章涉及的CubeRenderer类则是负责填充框架,呈现实际内容:一个旋转的彩色立方体.CubeRenderer类中的方法通过名称 ...

  9. Windows 8 Directx 开发学习笔记(九)材质定义及混合光照效果实现

    在真实环境中,同一个物体在不同光源照射下的颜色并不一样,因为物体本身并没有颜色,而是它会反射不同颜色的光.物体对不同颜色光的吸收率.反射率,加上光泽度.透明度等其他物理属性组合在一起,定义了这个物体的 ...

最新文章

  1. linux 下的lamp的简单安装
  2. HDU 2094 产生冠军
  3. 剑指offer(Java实现) 二叉搜索树的后序遍历序列
  4. c 语言 文本处理范例
  5. 【渝粤题库】国家开放大学2021春2108刑法学(2)题目
  6. 神舟战神换cpu教程_神舟将十代i5称为“神U出世”?聊聊到底有哪些优势
  7. HTML5给我们带来了什么
  8. js 弹窗中写html代码,简单了解JavaScript弹窗实现代码
  9. Python爬虫(二)——urllib库,Post与Get数据传送区别,设置Headers,urlopen方法,简单爬虫
  10. js页面打印去掉页眉页脚
  11. 程序员,30岁+,看完让你不再焦虑
  12. jmeter perfMon插件的使用
  13. python怎么表示不等于_Python关系运算符中表示“不等于”的是哪个?________
  14. 【计算机网络13】网络安全
  15. [CF1039E]Summer Oenothera Exhibition[根号分治+lct]
  16. 移动后端即服务(BaaS)市场现状及未来发展趋势
  17. 教你如何解决win10电脑局域网看不到其他共享电脑
  18. Postman(七): postman应用实战
  19. 中国疗养院行业发展规模与十四五战略规划研究报告2022-2028年版
  20. 总结一波 Redis 面试题,收藏起来。

热门文章

  1. php获取微信uninoid_微信小程序获取openid和unionid方法
  2. python如何编程日期_python编程开发之日期操作实例分析
  3. 想成为测试工程师,这7件事你必须先知道
  4. MeterSphere场景变量—常量整理总结
  5. java贝叶斯分类器 开源_贝叶斯分类器
  6. ajax在php中使用方法,在项目中如何使用ajax请求
  7. python调用caffe时,出现ImportError: No module named _caffe
  8. r语言 index_基于R语言绘制BBC风格图表
  9. oracle裸设备文件复制,Oracle Goldengate在HP平台裸设备文件系统OGG-01028处理
  10. 发现孩子做作业用计算机,儿童不宜长期使用计算器做作业