DirectX11 使用Cube Mapping 立方体环境贴图实现天空、物体反射效果

这一章中,我们将学习使用立方体环境贴图(Cube Mapping)实现天空环境、模型反射效果。

在《赛达尔传说:荒野之息》中,明朗或阴暗的天空都可以通过Cube Mapping来实现:
这里写图片描述
(图为《赛达尔传说:荒野之息》游戏截图)

一、使用Cube Map实现天空效果

立方体环境贴图是一个数组纹理,用于模拟全包围的环境,类似带有6个面的正方体,因而称为 Cube Map。

这里写图片描述

实际上打开dds文件后,只是一组合并6张图片的纹理:
这里写图片描述

立方体环境贴图有6个面,我们可以把它们跟世界坐标轴对齐,每个轴有两个方向分别对应2个面,因此(±X, ±Y, ±Z)对应了六个面。DirectX还提供了一个枚举类型D3D11_TEXTURECUBE_FACE来指示Cube Map的每个面:

typedef enum D3D11_TEXTURECUBE_FACE {
D3D11_TEXTURECUBE_FACE_POSITIVE_X = 0,
D3D11_TEXTURECUBE_FACE_NEGATIVE_X = 1,
D3D11_TEXTURECUBE_FACE_POSITIVE_Y = 2,
D3D11_TEXTURECUBE_FACE_NEGATIVE_Y = 3,
D3D11_TEXTURECUBE_FACE_POSITIVE_Z = 4,
D3D11_TEXTURECUBE_FACE_NEGATIVE_Z = 5
} D3D11_TEXTURECUBE_FACE;

为什么只需要6个面就可以获得整个天空环境呢?可以这样想,一周360度,一个面可以获得90度的内容,那么你围绕一圈的4个面就可以获得一圈的环境,还有抬头与低头两个面也是90度的内容。

我们可以介绍预先渲染这样一张环境贴图的方法,DirectX也提供了一个工具DxTex.exe让我们通过载入6个面来制作一张Cube Map。

这里写图片描述

我们以前对2D纹理进行采样的时候,是通过uv坐标采样的,那么对于cube map该怎么采样呢?我们可以想象把cube map折叠成一个正方体,那么通过在原点处通过一个方向向量来获得一个颜色。如下图所示(化简的2D图示):

这里写图片描述

例如,在像素着色器中可以这样采样:

float3 v = float3(x,y,z); // 3D方向向量
float4 color = gCubeMap.Sample(gTriLinearSam, v); //通过3D方向来采样

目前描述三维天空的方案主要包括三种模型:

1.平面型天空(Sky Plane),仅用一个平面放到玩家头顶。这种方案太弱了,太容易被玩家们看穿,真实感太低,技术含量也太低。但是对于并不太注意远景的场景,用天空平面也不失为一种办法。在这种情况下,用纯色的雾来覆盖整个远景,使得远处充满神秘,遮一下羞也效果凑合。

2.天空盒(Sky Box),将Cube Map映射到正方体,即用一个模拟的映射正方体包围住场景。效果一般,但是实现简单、性能较好。Unity3D默认也是这种方案。但是在VR中不能使用该方案,会看到明显的边角。

这里写图片描述

3.天空穹庐(Sky Dome),将Cube Map映射到球体,即用一个模拟的映射球体包围住场景。效果最好,但也略微费时。也是本篇博文使用的方案。

这里写图片描述

我们先载入该cube map文件,生成2D纹理和着色器资源视图:

ID3D11ShaderResourceView* mCubeMapSRV;
HR(D3DX11CreateShaderResourceViewFromFile(device,
cubemapFilename.c_str(), 0, 0, &mCubeMapSRV, 0));

然后再设置着色器资源视图进.fx文件:

// .fx 变量
TextureCube gCubeMap;
// .cpp 代码
ID3DX11EffectShaderResourceVariable* CubeMap;
CubeMap = mFX->GetVariableByName("gCubeMap")->AsShaderResource();
…
CubeMap->SetResource(cubemap);

因为我们选用的方案是将Cupe Map投影到球体,那么就需要创建一个球体。(但是这个球体不需要真的非常大,因为我们在fx文件中进行变换的时候会让z = w使得z/w=1,顶点总是处于远平面)我们只需要创建球体外形的模型顶点即可,半径不重要:

Sky::Sky(ID3D11Device* device, const std::ws
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值