Directx11学习笔记【十七】纹理贴图
本文由zhangbaochong原创,转载请注明出处http://www.cnblogs.com/zhangbaochong/p/5596180.html
在之前的例子中,我们实现了光照和材质使得场景大大增加了真实感,然而材质提供的细节只是在顶点级别上,要想在像素级别提供细节还得借助于纹理,这次让我们学习dx11中一些有关纹理的基础。
1.纹理坐标
1
在direct3d中,纹理坐标用一个二维向量(u,v)表示,纹理左上角为原点,u正方向沿纹理水平向右,v正方向沿纹理垂直向下,且0<=u,v<=1。所以,(0,0)代表左上角,(1,1)代表右下角,(0.5,0.25)代表图中点的位置。这样,我们在指定纹理坐标时就不需要考虑纹理大小了,无论对于256*256,512*512还是1024*1024的纹理,(0.5,0.5)表示的都是正中间。
如果给出了一个三角形三个顶点对应的纹理坐标,那么三角形内部的纹理坐标就需要插值来计算了。如下图所示,一个三角形三个顶点(p1,p2,p3)对应纹理坐标(q1,q2,q3),那么三角形内部任意一点(x,y,z)=p0 + s(p1 - p0) + t(p2 - p0),那么对应的纹理坐标(u,v)=q0 + s(q1 - q0) + t(q2 - q0)。
2.纹理过滤
纹理贴图的元素实际上是由离散的颜色值组成的,而不能看做是一块矩形区域。理想情况是一张512*512纹理恰好投影在一块512*512大小的屏幕上,一个像素对应一个纹理值,但是通常情况并不是这样的。当屏幕像素不能和纹理值一一对应时应该怎么做呢?这种情况也分为两种:一种是摄像机不断靠近纹理,这时一张很小的纹理就可能覆盖整个屏幕,于是一个纹理值就要对应很多个像素;第二种情况恰恰相反,摄像机不断远离纹理图片,当投影在屏幕的足够小时,就有可能很多纹理值会投影在同一像素上。这种情况,就需要纹理过滤,两种情况也对应两种纹理过滤方式:Magnification和Minification情况。
2.1放大(Magnification)
假设一张 256*256的纹理覆盖了1024*1024的屏幕大小,那么这时一个纹理对应16个屏幕像素,这16个像素对应同一个纹理值,如何取得颜色呢?d3d主要有两种过滤方式:取最近点和线性插值。
2.1.1取最近点(Nearest neighbor point)
对于任意像素对应的纹理坐标值,取距离最近的纹理值。
2.1.2线性插值(Linear interpolate)
与坐标最近的4个纹理值进行插值得到最终结果。看下图就很清楚了:
2.2缩小(Minification)
在Minification情况下,多个纹理元素被投影在屏幕上同一个像素位置。比如一个1024*1024的纹理,投影在屏幕上256*256范围的空间内,平均每个像素覆盖16个纹理值。这种情况下,最流行的过滤方法称为Mipmaping。在该方法中,使用到一个Mipmap链。Mipmap链是原纹理组成的一个数组,数组中第一个纹理为原始纹理,后面的第一个纹理在u、v尺寸上为上一个纹理的一半,依次计算,直接纹理尺寸为1为止。如下图所示:
这样在运行时,硬件会选择合适的纹理。选择合适的纹理也有两种方法:Point Filtering和Linear Filtering。原理与上面说的很相近就不再说明了。
2.3各向异性过滤(Anisotropic Filtering)
还有一种高级的过滤方式称为各向异性过滤,这种过滤方式对于视线与物体表面法线成90度时情况的效果比较好。
右边图使用了各向异性过滤方式。
3.纹理坐标寻址(Address modes)
纹理坐标被限制在(0,1)之间,但为顶点指点(0,1)之外的纹理坐标仍然是被允许的,这时解析出来的坐标值就和纹理坐标寻址方式有关了。d3d中支持的纹理寻址方式主要有以下几种:
3.1wrap
贴图在物体表面重复,类似于我们设置桌面是图片的平铺方式。当坐标大于1时,通过去掉整数部分,根据得到的小数部分来得到纹理值;坐标小于0,则加上一个最小正数,让坐标大于0。
3.2border
当纹理坐标不在(0,1)范围时,我们可以手动指定一个值来使用。
3.3clamp
坐标超过正常范围时,使用在(0,1)范围的坐标与该坐标最近的点的纹理值。例如,坐标(u,v),u在(0,1)范围内,而v>1,则使用(u,1)作为最终纹理值。如果u>1,v>1,则使用(1,1)作为纹理值。
3.4mirror
每当纹理坐标越过一个整数值时,使用的纹理与越过整数值之前的纹理成镜像关系。
4.使用纹理
d3d11中纹理对应的接口为ID3D11Texture2D,一个纹理可以在管线的多个阶段使用,使用的时候要先绑定到相应阶段。而真正绑定到管线的不是纹理本身,而是纹理对应的视图。下面来介绍一下c++和HLSL中纹理的使用方式。
4.1 c++中
在c++读取图片使用纹理主要有两个步骤:创建纹理和创建相应阶段的视图。在dx11龙书中这两个步骤是通过一个函数D3DX11CreateShaderResourceViewFromFile实现的,函数原型如下:
HRESULT D3DX11CreateShaderResourceViewFromFile(
_In_ ID3D11Device *pDevice,
_In_ LPCTSTR pSrcFile,
_In_ D3DX11_IMAGE_LOAD_INFO *pLoadInfo,
_In_ ID3DX11ThreadPump *pPump,
_Out_ ID3D11ShaderResourceView **ppShaderResourceView,
_Out_ HRESULT *pHResult
);
但是在最新的sdk中该方法已经废弃了,针对这一点MSDN的解释:
Note The D3DX (D3DX 9, D3DX 10, and D3DX 11) utility library is deprecated for Windows 8 and is not supported for Windows Store apps.
Note Instead of using this function, we recommend that you use these:
- DirectXTK library (runtime), CreateXXXTextureFromFile (where XXX is DDS or WIC)
- DirectXTex library (tools), LoadFromXXXFile (where XXX is WIC, DDS, or TGA; WIC doesn't support DDS and TGA; D3DX 9 supported TGA as a common art source format for games) then CreateShaderResourceView
为了加载纹理图片,我们可以到github上下载DirectXTK或者DirectXTex,使用框架中的方法来代替D3DX11CreateShaderResourceViewFromFile。这里以DirectXTex为例,从github上下载下来,把DDSTextureLoader的代码载入到我们的工程中,使用CreateDDSTextureFromFile加载纹理图像(纹理格式为.dds,加载其他格式纹理请自行查看文档说明),函数原型如下:
HRESULT CreateDDSTextureFromFile( _In_ ID3D11Device* d3dDevice,
_In_z_ const wchar_t* szFileName,
_Outptr_opt_ ID3D11Resource** texture,
_Outptr_opt_ ID3D11ShaderResourceView** textureView,
_In_ size_t maxsize = ,
_Out_opt_ DDS_ALPHA_MODE* alphaMode = nullptr
);
c++程序中使用:首先定义一个 ID3D11ShaderResourceView接口保存创建的视图, 然后调用CreateDDSTextureFromFile函数创建。
hr = CreateDDSTextureFromFile(m_pd3dDevice, L"Texture/Wood.dds", nullptr, &m_pTexSRV);
if (FAILED(hr))
{
MessageBox(nullptr, L"create texture failed!", L"error",MB_OK);
return hr;
}
调用后相应的视图就创建好了。
为了将纹理资源传递到effect文件中,我们还需要定义一个指向effect全局变量的接口:ID3DX11EffectShaderResourceVariable,然后在编译shader时得到:
m_pFxTex = m_pFx->GetVariableByName("g_tex")->AsShaderResource();
在Update函数中调用SetResource方法将创建的纹理视图赋值给effect中的全局变量。
4.2 effect中
在HLSL中对应2D纹理的是Texture2D,但是要注意的是Texture2D的定义不能放在cbuffer中。
在c++程序中我们可以通过ID3D11DeviceContext::PSSetSamplers来设置纹理过滤方式,在effect文件中我们同样可以设置过滤方式(推荐在effect中设置),设置方法如下:
//设置过滤方式
SamplerState samTex
{
Filter = MIN_MAG_MIP_LINEAR;
};
这里Minification、Magnification和Mipmap中纹理过滤方式全部使用线性过滤方法,如需要查看其它过滤方法,可以查看MSDN中D3D11_FILTER的说明。
由于使用了纹理,顶点结构也需要改变。我们不再使用光照了,所以去掉法线,添加纹理坐标:
struct VertexIn
{
float3 pos : POSITION;
float2 tex : TEXCOORD;
}; struct VertexOut
{
float4 posH : SV_POSITION;
float2 tex : TEXCOORD;
};
顶点着色器很简单:
VertexOut VS(VertexIn vin)
{
VertexOut vout;
vout.posH = mul(float4(vin.pos, 1.0f), g_worldViewProj);
vout.tex = vin.tex;
return vout;
}
像素着色器中需要使用纹理资源,通过函数Texture2D::sample(SamplerState samper, float2 texcoord)实现:
float4 PS(VertexOut pin) : SV_Target
{
float4 texColor = g_tex.Sample(samTex,pin.tex);
return texColor;
}
5.运行结果
源码下载:http://files.cnblogs.com/files/zhangbaochong/TextureDemo.zip
Directx11学习笔记【十七】纹理贴图的更多相关文章
- Directx11学习笔记【二十二】 用高度图实现地形
本文由zhangbaochong原创,转载请注明出处http://www.cnblogs.com/zhangbaochong/p/5827714.html 在前面我们曾经实现过简单的地形(Direct ...
- Directx11学习笔记【九】 3D渲染管线
原文:Directx11学习笔记[九] 3D渲染管线 原文地址:http://blog.csdn.net/bonchoix/article/details/8298116 3D图形学研究的基本内容,即 ...
- python3.4学习笔记(十七) 网络爬虫使用Beautifulsoup4抓取内容
python3.4学习笔记(十七) 网络爬虫使用Beautifulsoup4抓取内容 Beautiful Soup 是用Python写的一个HTML/XML的解析器,它可以很好的处理不规范标记并生成剖 ...
- 学习笔记:APP切图那点事儿–详细介绍android和ios平台
学习笔记:APP切图那点事儿–详细介绍android和ios平台 转载自:http://www.woofeng.cn/articles/168.html 版权归原作者所有 作者:亚茹有李 原文地址 ...
- Directx11学习笔记【二】 将HelloWin封装成类
我们把上一个教程的代码封装到一个类中来方便以后的使用. 首先新建一个空工程叫做MyHelloWin,添加一个main.cpp文件,然后新建一个类叫做MyWindow,将于窗体有关的操作封装到里面 My ...
- Directx11学习笔记【一】 最简单的windows程序HelloWin
声明:本系列教程代码有部分来自dx11龙书及dx11游戏编程入门两本书,后面不再说明 首先,在vs2013中创建一个空的解决方案Dx11Demo,以后的工程都会放在这个解决方案下面.然后创建一个win ...
- Directx11学习笔记【二十一】 封装键盘鼠标响应类
原文:Directx11学习笔记[二十一] 封装键盘鼠标响应类 摘要: 本文由zhangbaochong原创,转载请注明出处:http://www.cnblogs.com/zhangbaochong/ ...
- Directx11学习笔记【八】 龙书D3DApp的实现
原文:Directx11学习笔记[八] 龙书D3DApp的实现 directx11龙书中的初始化程序D3DApp跟我们上次写的初始化程序大体一致,只是包含了计时器的内容,而且使用了深度模板缓冲. D3 ...
- AC自动机学习笔记-2(Trie图&&last优化)
我是连月更都做不到的蒟蒻博主QwQ 考虑到我太菜了,考完noip就要退役了,所以我决定还是把博客的倒数第二篇博客给写了,也算是填了一个坑吧.(最后一篇?当然是悲怆のnoip退役记啦QAQ) 所以我们今 ...
随机推荐
- JavaScript(15)jQuery 选择器
jQuery 选择器 选择器同意对元素组或单个元素进行操作. jQuery 元素选择器和属性选择器同意通过标签名.属性名或内容对 HTML 元素进行选择. 在 HTML DOM 术语中:选择器同意对 ...
- form表单中的 action=./?> 是什么意思
./代表当前目录,?代表查询字符串为空 action="" //一般可以为空的,这里的双引号都要有的,表示提单提交给自己(也就是当前页处理)action="a.php&q ...
- VB.NET 机房收费系统项目总结
VB.NET机房收费系统项目总结 从2013年5月3日——2013年8月20日历时三个多月的.NET机房收费系统终于完成了.项目做完了,真有一种如释重负的感觉. 下面我将从文档.UML图,代码这三个方 ...
- ExtJs 设置GridPanel表格文本垂直居中
业务场景,需要实现最终效果图如下: GridPanel代码如下配置: { xtype : 'grid', id : 'grid_jglb', frame : true, region : 'cente ...
- JavaScript RegExp对象
一.什么是RegExp 1.RegExp 是正則表達式的缩写. 2.当您检索某个文本时,能够使用一种模式来描写叙述要检索的内容.RegExp 就是这样的模式. 3.简单的模式能够是一个 ...
- java 中间 final修饰符
修饰符final:它是一个常数,我不同意改变 ,可以修改 变数,办法 ,分类 final修改变量:是final成常量,一旦赋值不能改变 常量能够在初始化时直接赋值.也能够在构造方法里赋值.仅仅能在这两 ...
- spring 普通类获取四大作用域request、applicationContext、session、page
几乎所有web应用容器都提供了四种类似Map的结构:application session request page,Jsp或者Servlet通过向着这四个对象放入数据,从而实现Jsp和Servlet ...
- WPF界面设计技巧(11)-认知流文档 & 小议WPF的野心
原文:WPF界面设计技巧(11)-认知流文档 & 小议WPF的野心 流文档是WPF中的一种独特的文档承载格式,它的书写和呈现方式都很像HTML,它也几乎具备了HTML的绝大多数优势,并提供了更 ...
- 十年linux命令总结
十年linux命令总结 本文链接: http://codingstandards.iteye.com/blog/786653 关于命令类型划分 本表中列出了我穷尽了我所有的记忆整理出来的Linux命令 ...
- linux网络编程学习笔记之三 -----多进程并发服务端
首先是fork()函数.移步APUE 8.3. 比較清晰的解释能够參考http://blog.csdn.net/lingdxuyan/article/details/4993883和http://w ...