第五章 Texture Mapping
来源:互联网 发布:财税软件推广方案 编辑:程序博客网 时间:2024/04/29 20:42
第五章 Texture Mapping
纹理映射就是在3D object表面添加细节的过程。可以比喻成包装礼品的过程,包装纸就是一种2D纹理。纹理映射是现代渲染的基础,并用于多种有趣的图形技术中。
An Introduction to Texture Mapping
相比如上一章使用HelloShaders和HelloShaders effects产生的纯色效果,通常情况你会期望在3D objects中渲染更多的细节。正如之前所讲的,3D模型由vertices组成,并组织成三角形,这些vertices至少包含一个坐标位置。但可以包含更多的内容。进一步增加表面细节可以为每一个vertex提供一种颜色值。对比一下图5.1中的3D cubes。
图5.1 3D cubes with different colors for each vertex (left) and solid red (right).
左边的cube中,每个vertex带有一种不同的颜色值;而右边的cube中,每个vertex的颜色值都相同。很明显左边的cube显示了更多的细节。这些颜色值使得object更加有趣,并定义了cube的多个表面。此外,单个pixels的颜色值随着该pixels所处的位置相对于vertices的位置不同而变化(回想一下第一章,“Introducing DirectX”讨论的在rasterizer阶段的插值)。通过增加3D objects中带有颜色值的vertices数量,就可以更好的控制表面的颜色。然而,一旦要精细的显示,就无法得到足够的vertices来进行高质量的渲染,而且任何尝试都会迅速产生大量的vertices。解决这高质量渲染的办法是使用纹理映射。
要将纹理映射到一个三角形上,需要知道每个vertex的二维坐标。该坐标用于查找存储在2D纹理中的颜色值。查找过程是在pixel shader中进行的,用于确定三角形中每个pixel的颜色值。而且纹理坐标是通过三角形的vertices插值计算得到的,而不是通过vertex color。
DirectX的纹理坐标范围在水平和垂直轴上都是[0, 1],以左上角为起点。一般情况下水平轴命名为u,垂直轴叫v。如图5.2所示,一个纹理映射到一个四边形上(由两个三角形组成),并标出了每个vertex对应的纹理坐标。
图5.2 DirectX 2D texture coordinates. (Original texture from Reto Stöckli, NASA Earth Observatory.
Additional texturing by Nick Zuccarello, Florida Interactive Entertainment Academy.)
注意
Direct3D支持1D,2D,和3D纹理,以及texture arrays和texture cubes(将于第8章,“Gleaming the Cube”讲述)。需要查找的坐标数量与对应的纹理维数相关。
A Texture Mapping Effect
列表5.1是一种纹理映射effect的代码。与之前一样,在NVIDIA FX Composer中创建一种新的effect/material,并把列表中的代码拷贝过去。然后就可以一步一步的测试代码了。
列表5.1 TextureMapping.fx
/************* Resources *************/#define FLIP_TEXTURE_Y 1cbuffer CBufferPerObject{float4x4 WorldViewProjection : WORLDVIEWPROJECTION < string UIWidget = "None"; >;}RasterizerState DisableCulling{CullMode = NONE;};Texture2D ColorTexture <string ResourceName = "default_color.dds";string UIName = "Color Texture";string ResourceType = "2D";>;SamplerState ColorSampler{Filter = MIN_MAG_MIP_LINEAR;AddressU = WRAP;AddressV = WRAP;};/************* Data Structures *************/struct VS_INPUT{float4 ObjectPosition : POSITION;float2 TextureCoordinate : TEXCOORD;};struct VS_OUTPUT{float4 Position : SV_Position;float2 TextureCoordinate : TEXCOORD;};/************* Utility Functions *************/float2 get_corrected_texture_coordinate(float2 textureCoordinate){#if FLIP_TEXTURE_Yreturn float2(textureCoordinate.x, 1.0 - textureCoordinate.y);#elsereturn textureCoordinate;#endif}/************* Vertex Shader *************/VS_OUTPUT vertex_shader(VS_INPUT IN){VS_OUTPUT OUT = (VS_OUTPUT)0;OUT.Position = mul(IN.ObjectPosition, WorldViewProjection);OUT.TextureCoordinate = get_corrected_texture_coordinate(IN.TextureCoordinate);return OUT;}/************* Pixel Shader *************/float4 pixel_shader(VS_OUTPUT IN) : SV_Target{return ColorTexture.Sample(ColorSampler, IN.TextureCoordinate);}/************* Techniques *************/technique10 main10{pass p0{SetVertexShader(CompileShader(vs_4_0, vertex_shader()));SetGeometryShader(NULL);SetPixelShader(CompileShader(ps_4_0, pixel_shader()));SetRasterizerState(DisableCulling);}}
Comments, the Preprocessor, and Annotations
有很多编程语言结构都支持注释和预处理。先来看看代码的注释,HLSL支持C++风格的单行注释(// 注释)和多行注释(/* 注释 */)方式。
再看看代码最上方的宏定义,#define FLIP_TEXTURE_Y 1。这种宏定义与C/C++的宏定义行为完成一样。实际上,HLSL也有一些很熟悉的预处理命令,包括#if,#else,#endif,以及#include。
接下来开始研究在cubbfer中声明的shader常量WorldViewProjection。该常量与HelloShaders和HelloStructs中的作用一样,但在常量声明的末尾增加了一个备注。这些备注以尖括号的形式括起来,用于CPU端的应用程序访问,不会影响shader的运行,但是应用程序可以使用他们。例如,WorldViewProjection中的UIWidget备注,可以控制NVIDIA FC Composer如何对待该shader常量。由于UIWidget赋值为None,在NVIDIA FX Composer的material properties列表中无法看到WorldViewProjection常量。如图5.3所示,左图中没有UIWidget = “None”的备注,可以在Properties panel中看到WorldViewProjection常量,右图中有了该备注,所以无法看到WorldViewProjection常量。需要注意的是,只是在Properties panel看不到该常量,CPU依然会更新。隐藏该常量的意义在于,不需要手动编辑WorldViewProjection矩阵。
图5.3 NVIDIA FX Composer Properties panel showing the properties for TextureMapping.fx without
the UIWidget="None" annotation on WorldViewProjection (left) and with the annotation (right).
Texture Objects and Samplers
在HLSL effect中使用一种纹理需要三个步骤。第一步,必须声明texture object(如列表5.2所示)。声明一个HLSL的纹理可以使用显示类型(比如Texture2D)或者更通用的texture数据类型。Texture objects不能使用cubffers类型声明。
列表5.2 The Texture Object Declaration from TextureMapping.fx
Texture2D ColorTexture <string ResourceName = "default_color.dds";string UIName = "Color Texture";string ResourceType = "2D";>;
注意
在列表5.2中,ColorTexture变量包含了三个备注,虽然说所有的备注都是可选的,但是这些备注在NVIDIA FX Composer中却很有用。
通过UIName备注可以在Properties panel中自定义变量名。ResourceType备注指定了可以texture的类型,而ResourceName则支持在用户没有指定纹理的时候使用默认的纹理。
第二步,必须声明并初始化一个texture sampler(纹理采样)(如列表5.3所示)。Samplers控制如何从一个纹理中获取颜色值。Direct3D 10介绍了SamplerState数据类型,并直接映射到对应的Direct3D C结构体的成员中,用于filtering(过滤)和texture address modes(纹理寻址模式)。马上就会讨论这些主题。
列表5.3 The Sampler Object Declaration from TexureMapping.fx
SamplerState ColorSampler{Filter = MIN_MAG_MIP_LINEAR;AddressU = WRAP;AddressV = WRAP;};
最后一步,就是使用声明的sampler object来进行纹理采样。这一步是在pixel shader的执行的(如列表5.4)
列表 5.4 The Pixel Shader from TextureMapping.fx
float4 pixel_shader(VS_OUTPUT IN) : SV_Target{return ColorTexture.Sample(ColorSampler, IN.TextureCoordinate);}
调用ColorTexture object的函数Sample()与C++风格的成员函数调用类似。Sample()函数的第一个参数是sampler object,第二个参数是texture中对应的坐标。
Texture Coordinates
纹理采样的坐标来自vertex数据流,并与VS_INPUT和VS_OUTPUT中成员保持一致(如列表5.5所示)。注意下与2D TextureCoordinate成员关联的TEXCOORD语义。
列表5.5 The Vertex Shader Input and Output Data Structures from TextureMapping.fx
struct VS_INPUT{float4 ObjectPosition : POSITION;float2 TextureCoordinate : TEXCOORD;};struct VS_OUTPUT{float4 Position : SV_Position;float2 TextureCoordinate : TEXCOORD;};
如列表5.6所示,vertex shader把输入的纹理坐标用做输出,但要先调用get_corrected_texture_coordinate()以得到正确的纹理坐标。HLSL支持自定义的C风格的辅助函数get_corrected_texture_coordinate(),如果FLIP_TEXTURE_Y非0,该函数只是简单的反转垂直方向的纹理坐标。这是必须的,因为NVIDIA FX Composer针对内置的3D模型(Sphere,Teapot,Torus,Plane)使用OpenGL风格的纹理坐标。在DirectX中纹理坐标以左上角为起点,而在OpenGL中以左下角为起点。因此,在对NVIDIA FX Composer中内置的模型进行shaders显示时,需要翻转垂直方向的纹理坐标。如果导入了一个自定义的模型,并且该模型具有DirectX风格的纹理坐标,只需要禁用FLIP_TEXTURE_Y宏定义。
列表5.6 The Vertex Shader and a Utility Function from TextureMapping.fx
float2 get_corrected_texture_coordinate(float2 textureCoordinate){#if FLIP_TEXTURE_Yreturn float2(textureCoordinate.x, 1.0 - textureCoordinate.y);#elsereturn textureCoordinate;#endif}/************* Vertex Shader *************/VS_OUTPUT vertex_shader(VS_INPUT IN){VS_OUTPUT OUT = (VS_OUTPUT)0;OUT.Position = mul(IN.ObjectPosition, WorldViewProjection);OUT.TextureCoordinate = get_corrected_texture_coordinate(IN.TextureCoordinate);return OUT;}
Texture Mapping Output
图5.4显示了把纹理映射effect应用于一个sphere的输出结果。(注意:需要在Properties panel中修改ColorTexture的纹理映射图片)
图5.4 TextureMapping.fx applied to a sphere with a texture of Earth. (Original texture from Reto
Stöckli, NASA Earth Observatory. Additional texturing by Nick Zuccarello, Florida Interactive Entertainment
Academy.)
- 第五章 Texture Mapping
- Texture mapping
- Texture Mapping
- Texture Mapping
- OpenGl 第七章:纹理映射 (texture mapping)
- Texture mapping a pyramid
- 纹理映射 (texture mapping)
- projective texture mapping
- 纹理映射(Texture Mapping)
- OpenGl 编程指南笔记 第九章:纹理映射 (texture mapping)
- openGL中的Texture/MultiTexture Mapping
- Decals - Using Projective Texture Mapping
- [gpu pro]virtual texture mapping
- Tutorial 16 - Basic Texture Mapping
- Animation and texture mapping
- 图形学实验三:Texture Mapping
- 纹理映射(Texture Mapping)
- UV Texture Coordinates and Texture Mapping - OpenGL / DirectX
- 发布自己的工程库
- call back回调函数理解
- Hibernate Learning
- 实用电脑软件推荐
- oracle 显式游标示例
- 第五章 Texture Mapping
- 【图像处理】三种边缘保持的滤波器(双边,引导,加权最小二乘)
- QT自制类分享 一图流按钮
- JavaScript--02 CSS基础 中 CSS样式表的冲突解决
- 快速排序的递归写法
- java简单排序-选择排序
- iOS 使用Charts框架 折线,柱状,K线,饼状,雷达全攻略
- ACM课程总结
- 用URL传值到JSP时EL表达式接收中文乱码