第九章 Normal Mapping and Displacement Mapping

第九章 Normal Mapping and Displacement Mapping

本章主要讲述两种图形学技术,支持在不增加objects的poly primitive的情况下,在场景中增加更多的细节。第一种是normal mapping,通过创建一些“fake” geometry(虚设的多边形图元)模拟光照作用。第二种是displacement mapping,根据纹理数据moving vertices actually(与“fake”相对应,这里指真实的移动)来创建凹凸不平的表面。

Normal Mapping(法线贴图)

前面几章,已经讨论了specualr maps,environment maps以及transparency maps,这些texture maps都提供了附加的数据信息。Specular maps中的数据用于限制specular highlight,environment maps则包含了用于reflective surfaces的colors,transparency maps用于控制output-merge阶段的alpha blending。这些额外的信息由每一个pixel提供,比仅由每一个vertex提供,具有更高的精度。同样 ,一个normal map也是对每一个pixel都提供表面的法向量数量,该额外的数据可以应用于多种技术上。
Normal maps的其中一个应用是虚构一个凹凸表面的细节,比如石墙。可以使用足够的geometry来模拟这中凹凸不平的墙面,使用的vertices越多,得到的细节也越多。这样就可以在场景中更好的处理光照,远离光源的石块就会显示为较暗的区域。但是,增加geometry会导致计算成本也增大。相反,对于一个含有少量poly geometry的object(即使是一个flat plane),使用normal map方法,也可以模拟与大量增加geometry情况下同样的光照效果。这种应用就称为normal mapping。

Normal Maps

图9.1中显示了用于一面石墙的color map(左图)和normal map(右图)。相对于color map,normal map看起来有点奇怪。虽然可以把norml map显示出来,但是normal map中存储的是3D directions vectors(3维的方向向量)。对normal map进行采样时,从RGB通道中得到的结果表示方向向量的x,y,z分量。这些法向量可用于一些效果的计算,比如diffuse lighting。

图9.1 A color map (left) and normal map (right) for a stone wall. (Textures by Nick
Zuccarello, Florida Interactive Entertainment Academy.)
RGB texture的每一个channels都存储一个unsigned 8-bit值(unsigned char),该类型的数值范围为[0, 255]。但是一个规范化的方向向量,对应的xyz各个分量值范围是[-1, 1]。因此,法线向量存储到texture之前必须先转换到范围[0, 255],对texture进行采样的时候必须再转换到范围[-1, 1]。可以使用如下的公式,把浮点型向量从范围[-1, 1]转换到范围[0, 255]:

f(x) = (0.5x + 0.5) * 255

再使用下面的方程式变换回来:

实际工作中,一般会使用图像处理软件(比如Adobe Photoshop)把一个normal map编码成RGB texture格式。但是采样texture时需要在shader中手动计算,把数据从范围[0, 255]转换回[-1, 1]。在采样过程中已经执行了浮点除法(除以255)操作,所以得到的采样结果在范围[0, 1]之间。因此,只需要使用下面的方程函数把范围[0, 1]转换到范围[1, 1]:

f(x) = 2x − 1

或者,也可以使用16位或32位浮点型数值作为normal maps的texture格式,这样可以产生更好的细节效果,但会牺牲一些性能。


Tangent Space(切空间)

一般使用每一个vertex的法线来计算diffuse,同样也可以使用每一个pixel的法线。但是法线必须与light处于同一个坐标空间。对于per-vertex法线,由object space提供。但是normal maps的法线值处于tangent space。
Tangent space(或者texture space)是一个相对于纹理的坐标系,由三个相互正交的向量确定:surface normal向量,tangent向量以及binormal向量。图9.2描述了这三个向量。

图9.2 An illustration of tangent space. (Texture by Nick Zuccarello, Florida Interactive Entertainment Academy.)

其中normal向量,N,是一个vertex的表面法向量。Tangent向量,T,与表面的法线垂直,与指向texture的u轴方向。Binormal向量,B,则指向texture的v轴方向。
可以使用这三个向量创建一个TBN(tangent, binormal, normal)变换矩阵,如下所示:

可以使用这个矩阵把向量由tangent space变换到object space中。但是,由于light vector通常是在world space中,因此需要把从normal map中采样得到的noraml从tangent space变换到world space。或者换一种方式,直接使用已经处于world space中的向量创建TBN矩阵。

注意
可以把normals直接编码到world space中,就可以省去从tangent space到world space的变换。但是,使用这些normals的objects只能保持静止不动(不能执行变换)。另外,这些normals也不能简单地在多个ojbects之间重用(因为这些normals不能再进行变换)。

TBN矩阵有一个非常值得关注的特性,该矩阵由三个orthonormal向量(相互正交的单位向量)构成,并形成了一个正交基(定义了一个坐标系)。也就说该矩阵是一个正交矩阵,而正交矩阵的逆等于其转置。因此,把一个向量从object或者world space变换回tangent space(inverse mapping反向映射),只需要把该向量与TBN矩阵的转置相乘即可。另外,根据TBN矩阵的orthonormal性质,如果已经知道了任意两个向量,就可以推导出第三个向量。通常情况下,normal和tangent向量与geometry一起存储,而binormal向量(在vertex shader中)由这两个向量进行cross product计算得出。执行这种计算是对GPU运算和数据传输(在CPU和GPU之间)高成本之间的一种折衷的方法。

A Normal Mapping Effect

根据上面所讨论的方法,列表9.1列出了一种normal mapping effect的代码。
列表9.1 NormalMapping.fx
#include "include\\Common.fxh"

cbuffer CBufferPerFrame
{
    float4 AmbientColor : AMBIENT <
        string UIName =  "Ambient Light";
        string UIWidget = "Color";
    > = {1.0f, 1.0f, 1.0f, 1.0f};
    
    float4 LightColor : COLOR <
        string Object = "LightColor0";
        string UIName =  "Light Color";
        string UIWidget = "Color";
    > = {1.0f, 1.0f, 1.0f, 1.0f};

    float3 LightDirection : DIRECTION <
        string Object = "DirectionalLight0";
        string UIName =  "Light Direction";
        string Space = "World";
    > = {0.0f, 0.0f, -1.0f};

    float3 CameraPosition : CAMERAPOSITION < string UIWidget="None"; >;
}

cbuffer CBufferPerObject
{
    float4x4 WorldViewProjection : WORLDVIEWPROJECTION < string UIWidget="None"; >;
    float4x4 World : WORLD < string UIWidget="None"; >;
    
    float4 SpecularColor : SPECULAR <
        string UIName =  "Specular Color";
        string UIWidget = "Color";
    > = {1.0f, 1.0f, 1.0f, 1.0f};

    float SpecularPower : SPECULARPOWER <
        string UIName =  "Specular Power";
        string UIWidget = "slider";
        float UIMin = 1.0;
        float UIMax = 255.0;
        float UIStep = 1.0;
    > = {25.0f};	
}

Texture2D ColorTexture <
    string ResourceName = "default_color.dds";
    string UIName =  "Color Texture";
    string ResourceType = "2D";
>;

Texture2D NormalMap <
    string ResourceName = "default_bump_normal.dds";
    string UIName =  "Normap Map";
    string ResourceType = "2D";
>;

SamplerState TrilinearSampler
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
};

RasterizerState DisableCulling
{
    CullMode = NONE;
};

/************* Data Structures *************/

struct VS_INPUT
{
    float4 ObjectPosition : POSITION;
    float2 TextureCoordinate : TEXCOORD;
    float3 Normal : NORMAL;
    float3 Tangent : TANGENT;
};

struct VS_OUTPUT
{
    float4 Position : SV_Position;	
    float3 Normal : NORMAL;
    float3 Tangent : TANGENT;
    float3 Binormal : BINORMAL;
    float2 TextureCoordinate : TEXCOORD0;
    float3 LightDirection : TEXCOORD1;
    float3 ViewDirection : TEXCOORD2;
};

/************* Vertex Shader *************/

VS_OUTPUT vertex_shader(VS_INPUT IN)
{
    VS_OUTPUT OUT = (VS_OUTPUT)0;
    
    OUT.Position = mul(IN.ObjectPosition, WorldViewProjection);    
    OUT.Normal = normalize(mul(float4(IN.Normal, 0), World).xyz);
    OUT.Tangent = normalize(mul(float4(IN.Tangent, 0), World).xyz);
    OUT.Binormal = cross(OUT.Normal, OUT.Tangent);
    OUT.TextureCoordinate = get_corrected_texture_coordinate(IN.TextureCoordinate);
    OUT.LightDirection = normalize(-LightDirection);
    
    float3 worldPosition = mul(IN.ObjectPosition, World).xyz;
    float3 viewDirection = CameraPosition - worldPosition;
    OUT.ViewDirection = normalize(viewDirection);
        
    return OUT;
}

/************* Pixel Shader *************/

float4 pixel_shader(VS_OUTPUT IN) : SV_Target
{
    float4 OUT = (float4)0;
    
    float3 sampledNormal = (2 * NormalMap.Sample(TrilinearSampler, IN.TextureCoordinate).xyz) - 1.0; // Map normal from [0..1] to [-1..1]
    float3x3 tbn = float3x3(IN.Tangent, IN.Binormal, IN.Normal);    

    sampledNormal = mul(sampledNormal, tbn); // Transform normal to world space
    
    float3 viewDirection = normalize(IN.ViewDirection);
    float4 color = ColorTexture.Sample(TrilinearSampler, IN.TextureCoordinate);
    float3 ambient = get_vector_color_contribution(AmbientColor, color.rgb);
    
    LIGHT_CONTRIBUTION_DATA lightContributionData;
    lightContributionData.Color = color;
    lightContributionData.Normal = sampledNormal;
    lightContributionData.ViewDirection = viewDirection;
    lightContributionData.LightDirection = float4(IN.LightDirection, 1);
    lightContributionData.SpecularColor = SpecularColor;
    lightContributionData.SpecularPower = SpecularPower;
    lightContributionData.LightColor = LightColor;
    float3 light_contribution = get_light_contribution(lightContributionData);
    
    OUT.rgb = ambient + light_contribution;
    OUT.a = 1.0f;
    
    return OUT;
}

/************* Techniques *************/

technique10 main10
{
    pass p0
    {
        SetVertexShader(CompileShader(vs_4_0, vertex_shader()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_4_0, pixel_shader()));
            
        SetRasterizerState(DisableCulling);
    }
}

Normal Mapping Preamble

在该effect中,首先使用了一个ambient light,specular highlight以及一个directional light。新增了一个用于表示normal map的Texture2D对象,VS_INPUT结构体包含一个surface normal和一个tangent vector(处于object space中)。VS_OUPUT中新增了表示tangent和binormal的成员,在传递给下一个管线阶段之间,需要变换到world space中。

Normal Mapping Vertex and Pixel Shader

在vertex shader中,先把normal和tangent向量变换到world space中,然后计算这两个向量的cross product得到binormal向量。在pixel shader,先对normal map进行采样,再把采样得到的normal向量由范围[0, 1]转换到范围[-1, 1]。然后创建TBN矩阵,并用该矩阵把采样的normal向量变换到world space中。当normal变换到world space中之后,接下来的光照计算与之前的完全一样。

注意
如果你发现vertex shader是一个性能瓶颈,可以在输入参数中直接提供bionormal(与surface normal和tangent一起)。这是为了平衡vertex shader性能和图形总线中数据传输成本的一种折衷方法。更普遍的情况是,图形管线成为了瓶颈。

Normal Mapping Output

图9.3显示了在一个带有stone wall纹理的plane上,使用normal mapping effect的输出结果。左图中使用了图9.1中的normal map。而右图中,使用了一个normal map但是没有任何效果。两幅图中,ambient light都是禁用的,direcitonal light是纯白色,full-intensity(强度值为1.0),specular highlight的power值为100,intensity值为0.35。

图9.3 NormalMapping.fx applied to a plane with a stone wall texture using a normal
map (left) and without a normal map (right). (Textures by Nick Zuccarello, Florida Interactive
Entertainment Academy.)
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: Mapping and charting solutions是一种可以用来制作地图和图表的软件工具。它可以帮助用户将自己的数据制作成各种类型的图表或地图,以便更好地理解和分析数据。 该软件可以用于各种领域,包括业务分析、市场研究、科学研究等。用户可以通过设置不同的参数来定义图表或地图的样式和格式,比如颜色、字体等。 此外,mapping and charting solutions还提供了数据可视化的功能,可以将数据以直观、易懂的形式展现出来,帮助用户更好地理解数据关系。通过这种方式,用户可以更快、更准确地分析数据,发现可能存在的问题,并采取相应的措施。 总之,mapping and charting solutions是一种非常有用和有效的数据可视化工具。它为用户提供了一种快速、直观的展现数据的方式,使得数据分析变得更加轻松和高效。 ### 回答2: 如果您需要下载mapping和charting solutions,您可以从以下几个途径获取: 1. 在官方网站上下载:许多mapping and charting solutions的开发商会在其官方网站上提供下载链接。您可以通过谷歌或其他搜索引擎搜索特定的mapping and charting solutions,然后找到它们的官方网站并在该网站上找到下载选项。 2. 在应用商店下载:一些mapping and charting solutions也会有相应的应用程序,您可以在各大应用商店(如苹果的App Store、安卓的Google Play商店)中搜索并下载这些应用。 3. 在开源社区下载:许多mapping and charting solutions是以开源的形式发布的,您可以在GitHub等开源社区找到并下载这些解决方案。在这些平台上,您可以通过搜索相关的关键字来找到开源的mapping and charting solutions,然后按照指示下载并使用它们。 无论您选择哪种方式下载mapping and charting solutions,建议您在下载和使用之前先了解其功能、使用规则和操作步骤,以便更好地利用这些解决方案来进行地图制作和图表绘制。个别mapping and charting solutions可能需要购买授权或注册才能完全使用,所以请在下载之前了解相关许可证的要求。 ### 回答3: mapping and charting solutions可以被理解为地图制作和绘图解决方案。这样的解决方案通常提供了各种工具和技术,用于创建、编辑和呈现地图和图表。它们能够将地理数据可视化,从而帮助用户更好地理解和分析地理信息。 对于专业测绘人员、地理信息系统(GIS)专家、地理学家和城市规划师来说,mapping and charting solutions是非常重要的工具。它们使他们能够创建高质量的地图,并进行准确的测量和绘制。 mapping and charting solutions通常提供的功能包括: 1. 数据收集和整理:通过收集和整理地理数据,用户可以构建具有准确性和可靠性的地图和图表。工具可以通过不同的方式收集数据,如GPS测量、遥感技术、航空摄影等。 2. 数据编辑和渲染:这些解决方案提供了一系列编辑工具,用于编辑地理数据,包括添加和删除地点、绘制和修改线条、多边形和面。用户还可以选择适当的符号和颜色来呈现地理元素。 3. 数据分析和可视化:mapping and charting solutions可以帮助用户分析地理数据,并将其呈现为可视化的图表。这些图表可以包括统计数据、热力图、线条图等。 4. 地图输出和共享:用户可以将地图和图表输出为不同的格式,如印刷版地图、电子文档或在线地图。这样,用户可以与其他人共享地理信息,并在不同的设备上查看和导航。 总而言之,mapping and charting solutions是为了帮助用户创建、编辑和呈现地图和图表,并提供数据收集、编辑、分析和共享功能的专业工具。这些解决方案在测绘、GIS和地理学等领域被广泛使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值