D3D12渲染技术之纹理案例

2023-10-11 16:59

本文主要是介绍D3D12渲染技术之纹理案例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我们现在回顾一下将纹理添加到箱子模型上面,就跟以前的博客中提到的那样。下面我们详细介绍如何实现?

指定纹理坐标

GeometryGenerator :: CreateBox生成箱子的纹理坐标,以便将整个纹理图像映射到箱子的每个面上。 为简洁起见,我们仅显示正面,背面和顶面的顶点定义。 另请注意,我们省略了顶点构造函数中法线和切线向量的坐标(纹理坐标以粗体显示)。

GeometryGenerator::MeshData GeometryGenerator::CreateBox(float width, float height, float depth, uint32 numSubdivisions)
{MeshData meshData;Vertex v[24];float w2 = 0.5f*width;float h2 = 0.5f*height;float d2 = 0.5f*depth;// Fill in the front face vertex data.v[0] = Vertex(-w2, -h2, -d2, …, 0.0f, 1.0f);v[1] = Vertex(-w2, +h2, -d2, …, 0.0f, 0.0f);v[2] = Vertex(+w2, +h2, -d2, …, 1.0f, 0.0f);v[3] = Vertex(+w2, -h2, -d2, …, 1.0f, 1.0f);// Fill in the back face vertex data.v[4] = Vertex(-w2, -h2, +d2, …, 1.0f, 1.0f);v[5] = Vertex(+w2, -h2, +d2, …, 0.0f, 1.0f);v[6] = Vertex(+w2, +h2, +d2, …, 0.0f, 0.0f);v[7] = Vertex(-w2, +h2, +d2, …, 1.0f, 0.0f);// Fill in the top face vertex data.v[8] = Vertex(-w2, +h2, -d2, …, 0.0f, 1.0f);v[9] = Vertex(-w2, +h2, +d2, …, 0.0f, 0.0f);v[10] = Vertex(+w2, +h2, +d2, …, 1.0f, 0.0f);v[11] = Vertex(+w2, +h2, -d2, …, 1.0f, 1.0f);

创建纹理

我们在初始化时从文件创建纹理,如下所示:

// Helper structure to group data related to the texture.
struct Texture
{// Unique material name for lookup.std::string Name;std::wstring Filename;Microsoft::WRL::ComPtr<ID3D12Resource> Resource = nullptr;Microsoft::WRL::ComPtr<ID3D12Resource> UploadHeap = nullptr;};std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;void CrateApp::LoadTextures()
{auto woodCrateTex = std::make_unique<Texture>();woodCrateTex->Name = "woodCrateTex";woodCrateTex->Filename = L"Textures/WoodCrate01.dds";ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),mCommandList.Get(), woodCrateTex->Filename.c_str(),woodCrateTex->Resource, woodCrateTex->UploadHeap));mTextures[woodCrateTex->Name] = std::move(woodCrateTex);
}

我们将所有独特纹理存储在无序地图中,以便我们可以按名称查找它们。 在代码中,在加载纹理之前,需要检查纹理数据是否已经加载(即,它是否已经包含在无序映射中),以便它不会多次加载。

设置纹理

一旦创建了纹理并在描述符堆中为它创建了SRV,将纹理绑定到管道以便可以在着色器程序中使用它只需将其设置为需要纹理的根签名参数:

// Get SRV to texture we want to bind.
CD3DX12_GPU_DESCRIPTOR_HANDLE tex(
mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);…// Bind to root parameter 0. The root parameter description specifies which 
// shader register slot this corresponds to.
cmdList->SetGraphicsRootDescriptorTable(0, tex);

纹理转换

我们没有讨论过的两个常量缓冲区变量是gTexTransform和gMatTransform。 这些变量在顶点着色器中用于变换输入纹理坐标:

在这里插入代码片// Output vertex attributes for interpolation across triangle.
float4 texC = mul(float4(vin.TexC, 0.0f, 1.0f), gTexTransform);
vout.TexC = mul(texC, gMatTransform).xy;

纹理坐标表示纹理平面中的2D点, 因此,我们可以像任何其他点一样平移,旋转和缩放它们, 以下是转换纹理的一些示例用法:
1、砖纹理沿墙壁被拉伸, 墙顶点当前具有范围[0,1]中的纹理坐标。 我们将纹理坐标放大4倍,以将它们放大到范围[0,4],这样纹理将在墙上重复四到四次。
2、天空飘动的云层, 通过将纹理坐标转换为时间的函数,云在天空上就可以飘动了。
3、纹理旋转有时对粒子效果非常有用,例如,我们会随着时间的推移旋转火球纹理。

在本篇博客提供的案例中,我们使用单位矩阵变换,以便输入纹理坐标保持不变,但在下篇博客中,我们将解释使用纹理变换的演示。

请注意,要将2D纹理坐标转换为4×4矩阵,我们将其扩展为4D矢量:

vin.TexC ---> float4(vin.Tex, 0.0f, 1.0f)

在乘法完成之后,通过丢弃z分量和w分量将得到的4D矢量转回到2D矢量。

vout.TexC = mul(float4(vin.TexC, 0.0f, 1.0f), gTexTransform).xy;

我们使用两个单独的纹理变换矩阵gTexTransform和gMatTransform,因为有时它对材质转换纹理(对于像水这样的动画材料)更有意义,但有时它使纹理变换更有意义成为对象的属性。
因为我们正在处理2D纹理坐标,所以我们只关心对前两个坐标进行的转换。 例如,如果纹理矩阵转换了z坐标,则它对结果纹理坐标没有影响。最后给大家看一下实现的Demo:
在这里插入图片描述

Demo下载地址:链接:https://pan.baidu.com/s/1X0Vikf6qGYGPKU-Nwf-wYA 密码:h79q

这篇关于D3D12渲染技术之纹理案例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/189516

相关文章

setsid 命令工作原理和使用案例介绍

《setsid命令工作原理和使用案例介绍》setsid命令在Linux中创建独立会话,使进程脱离终端运行,适用于守护进程和后台任务,通过重定向输出和确保权限,可有效管理长时间运行的进程,本文给大家介... 目录setsid 命令介绍和使用案例基本介绍基本语法主要特点命令参数使用案例1. 在后台运行命令2.

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

RabbitMQ消费端单线程与多线程案例讲解

《RabbitMQ消费端单线程与多线程案例讲解》文章解析RabbitMQ消费端单线程与多线程处理机制,说明concurrency控制消费者数量,max-concurrency控制最大线程数,prefe... 目录 一、基础概念详细解释:举个例子:✅ 单消费者 + 单线程消费❌ 单消费者 + 多线程消费❌ 多

Python实现PDF按页分割的技术指南

《Python实现PDF按页分割的技术指南》PDF文件处理是日常工作中的常见需求,特别是当我们需要将大型PDF文档拆分为多个部分时,下面我们就来看看如何使用Python创建一个灵活的PDF分割工具吧... 目录需求分析技术方案工具选择安装依赖完整代码实现使用说明基本用法示例命令输出示例技术亮点实际应用场景扩

MySql基本查询之表的增删查改+聚合函数案例详解

《MySql基本查询之表的增删查改+聚合函数案例详解》本文详解SQL的CURD操作INSERT用于数据插入(单行/多行及冲突处理),SELECT实现数据检索(列选择、条件过滤、排序分页),UPDATE... 目录一、Create1.1 单行数据 + 全列插入1.2 多行数据 + 指定列插入1.3 插入否则更

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

PostgreSQL的扩展dict_int应用案例解析

《PostgreSQL的扩展dict_int应用案例解析》dict_int扩展为PostgreSQL提供了专业的整数文本处理能力,特别适合需要精确处理数字内容的搜索场景,本文给大家介绍PostgreS... 目录PostgreSQL的扩展dict_int一、扩展概述二、核心功能三、安装与启用四、字典配置方法

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

Python get()函数用法案例详解

《Pythonget()函数用法案例详解》在Python中,get()是字典(dict)类型的内置方法,用于安全地获取字典中指定键对应的值,它的核心作用是避免因访问不存在的键而引发KeyError错... 目录简介基本语法一、用法二、案例:安全访问未知键三、案例:配置参数默认值简介python是一种高级编

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2