基于三平面映射的地形纹理化【Triplanar Mapping】

news2024/12/23 11:57:12

你可能遇到过这样的地形:悬崖陡峭的一侧的纹理拉伸得如此之大,以至于看起来不切实际。 也许你有一个程序化生成的世界,你无法对其进行 UV 展开和纹理处理。
在这里插入图片描述

推荐:用 NSDT编辑器 快速搭建可编程3D场景

三平面映射(Triplanar Mapping)提供了一种优雅的技术来解决这些问题,并为你提供来自任何角度或任何复杂形状的逼真纹理。 在本文中我们将了解该技术,查看代码,并了解使用三平面映射时的一些优点、缺点和其他可能性。

1、地形纹理化的UV问题

最常见的问题是纹理拉伸,尤其是在地形方面。 问题在于正在纹理化的对象的 UV 坐标。 对于地形,UV 坐标分布在网格中,在 X-Y 平面上均匀分布,如下所示:
在这里插入图片描述

上图中的UV 布局未考虑地形的高度差并导致拉伸。 你可以采取措施,通过仔细展开 UV 坐标来均匀陡峭多边形的区域,但这会导致结果不太理想。 你仍然有扭曲的纹理,并且一些图块(例如中间的图块)被压缩。
在这里插入图片描述

你也可能无法展开网格物体 UV 坐标:可以通过程序生成地形或形状。 也许你的形状中有一个洞穴系统或洞。

我们可以使用三平面映射技术(也称为“三平面纹理”)来解决这些问题。

2、基于Triplanar映射的地形纹理化

首先,让我们再次查看应用了三平面映射的地形:

在这里插入图片描述

使用三平面映射的地形

现在好多了! 拉伸消失了,陡峭的斜坡看起来更加真实。

Triplanar映射通过在 3 个不同的方向(X、Y 和 Z 轴)上渲染纹理 3 次来实现此目的。 想象一个盒子。 首先,纹理从正 X 轴向下投影到负 X 轴。 面向 X 轴方向的任何片段(几何体的像素)都会应用纹理。 Y轴和Z轴也进行同样的处理。

这些渲染混合在一起。 因此,一半面向 X 轴、一半面向 Z 轴的片段将占用一半的 X 轴渲染和一半的 Z 轴渲染。 如果片段的 90% 面向 X 轴,则它会接收 90% 的 X 轴渲染,而仅接收 10% 的 Z 轴渲染。 就像拿3个喷雾罐,从顶部、侧面、正面喷射。

在这里插入图片描述

从 3 个角度投射的纹理

所有这些都是在材质的片段着色器中完成的。 它本质上对几何体进行 3 次纹理处理,每个方向一次,然后混合结果。

Triplanar映射根本不使用 UV 坐标。 相反,它使用实际的世界坐标。 知道了这一点,我们来看看代码。

第一部分计算每个方向的混合因子:

// in wNorm is the world-space normal of the fragment 
vec3 blending = abs( wNorm );
blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0 
float b = (blending.x + blending.y + blending.z);
blending /= vec3(b, b, b);

这里它采用片段的世界空间法线(它将被标准化,并且每个分量将在 -1 和 1 的范围内),我们将其设为绝对值。 我们不关心法线是否面向 -X 或 X,只要它位于 X 轴即可。 如果我们确实担心绝对方向,我们就会从前、后、左、右、上、下绘制形状; 比我们需要的多3倍。

接下来我们强制它在 0 到 1 的范围内,因此我们最终得到每个轴分量的百分比乘数。 如果法线在 Y 轴上朝上,我们得到的 Y 值为 1,它会得到所有 Y 轴绘画,而其他轴的值为 0,不会得到任何结果。

这是最困难的部分。 接下来,我们将三个混合值 (x,y,z) 与该纹理坐标处的纹理混合。 请记住,纹理坐标位于世界空间中:

vec4 xaxis = texture2D( rockTexture, coords.yz);
vec4 yaxis = texture2D( rockTexture, coords.xz);
vec4 zaxis = texture2D( rockTexture, coords.xy);
// blend the results of the 3 planar projections. 
vec4 tex = xaxis * blending.x + xaxis * blending.y + zaxis * blending.z;

我们终于得到它了。 tex是片段的最终颜色,从 3 个轴混合 3 次。

将比例因子应用于纹理会非常方便,因为你无疑会想要缩放它:

// in float scale 
vec4 xaxis = texture2D( rockTexture, coords.yz * scale);
vec4 yaxis = texture2D( rockTexture, coords.xz * scale);
vec4 zaxis = texture2D( rockTexture, coords.xy * scale);
vec4 tex = xaxis * blending.x + xaxis * blending.y + zaxis * blending.z;

3、法线的处理方法

如果你使用三平面映射和法线贴图,还需要对片段着色器中的法线应用相同的过程,如下所示:

vec4 xaxis = texture2D( rockNormalTexture, coords.yz * scale);
vec4 yaxis = texture2D( rockNormalTexture, coords.xz * scale);
vec4 zaxis = texture2D( rockNormalTexture, coords.xy * scale);
vec4 tex = xaxis * blending.x + xaxis * blending.y + zaxis * blending.z;

小技巧:
可以创建 getTriPlanarBlend() 函数来计算漫反射、法线和镜面纹理的混合。

4、Triplanar映射的问题

你将遇到的第一个问题是性能。 几何体的片段将被渲染 3 次,每个方向一次。 这意味着颜色和照明计算(法线)将被重复然后混合。 如果已经有空闲帧问题,可能不想使用三平面映射。

下一个重大问题是 45 度角的混合,尤其是在使用纹理泼溅的地方不同纹理重叠的情况。 你可以从角点再执行 4 次渲染,但这样做所带来的性能损失可能不值得。 你可以尝试与深度图混合,这是一种有时用于纹理泼溅的技术。

在这里插入图片描述

可见的透明重叠

5、结束语

现在我们理解了三平面贴图的工作原理及其用途。 但它还有许多其他应用程序,可以稍微改变它以产生有趣的结果。

如前所述,程序化地形是该技术的良好候选者。 洞穴、悬崖和复杂的熔岩隧道现在很容易纹理化。 你甚至可以根据一些随机或伪随机(噪声)例程来影响使用的纹理。 标高甚至坡度可以决定使用什么纹理。

通过修改例程以仅从顶部(y 轴)投影纹理并将混合值牢固地限制在可接受的范围内,即 10%,那么你可以在场景中所有物体的顶部渲染雪。 使用相同的技术,原子爆炸可以烧焦从某个世界坐标原点辐射出的所有物体,但基于原点的角度并使用暗烧纹理。


原文链接:地形纹理Triplanar映射 — BimAnt

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1061083.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】String -- 详解

⚪C语言中的字符串 C 语言中,字符串是以 \0 结尾的一些字符的集合,为了操作方便,C 标准库中提供了一些 str 系列的库函数,但是这些库函数与字符串是分离开的,不太符合 OOP 的思想,而且底层空间需要用户自己…

Java实现整数互转罗马数字基本算法

目录 一、罗马数字的起源? 二、算法代码 (1)整数转罗马数字算法代码 (2)罗马数字转整数算法代码 三、测试结果 (1)整数转罗马数字测试结果 (2)罗马数字转整数测试…

GD32F103 硬件 IIC

1. 硬件IIC 1. 硬件IIC的框图 如果MCU做为主机SCL就做为输出,做从机SCL就做为输入。 主机: 当MCU作为主机发送数据流程从数据缓冲寄存器里拿到移位寄存器。在从移位寄存器一位一位发送。 当MCU作为主机接收数据流程先放到移位寄存器。在从移位寄存…

微信小程序软件著作权申请成功!

软件著作权登记是对自己开发的软件享有著作权的一种保障,也是对自己开发能力的一种认证,在个人找工作或者公司拿项目资质审查时都可能发挥作用。我成功开发了一款微信小程序后,便了解了许多相关资料,花钱请代理代办速度快、省事&a…

Visopsys 0.92 发布

Visopsys 是一个 PC 机的操作系统,系统小型、快速而且开源。有着丰富的图形界面、抢先式多任务机制以及支持虚拟内存。Visopsys 视图兼容很多操作系统,但并不是他们的克隆版本。Visopsys 0.92 现已发布,此维护版本引入了多任务处理程序、文件…

C++标准模板(STL)- 类型支持 (定宽整数类型)(int8_t,int_fast8_t,int_least8_t,intmax_t,intptr_t)

定宽整数类型 类型 定义于头文件 <cstdint> int8_tint16_tint32_tint64_t (可选) 分别为宽度恰为 8、16、32 和 64 位的有符号整数类型 无填充位并对负值使用补码 &#xff08;仅若实现支持该类型才提供&#xff09; (typedef) int_fast8_tint_fast16_tint_fast32_tint…

进程调度算法之先来先服务(FCFS),短作业优先(SJF)以及高响应比优先(HRRN)

1.先来先服务&#xff08;FCFS&#xff09; first come first service 1.算法思想 主要从“公平”的角度考虑(类似于我们生活中排队买东西的例子) 2.算法规则 按照作业/进程到达的先后顺序进行服务。 3.用于作业/进程调度 用于作业调度时&#xff0c;考虑的是哪个作业先…

Spring 原理

它是一个全面的、企业应用开发一站式的解决方案&#xff0c;贯穿表现层、业务层、持久层。但是 Spring仍然可以和其他的框架无缝整合。 1 Spring 特点 轻量级控制反转面向切面容器框架集合 2 Spring 核心组件 3 Spring 常用模块 4 Spring 主要包 5 Spring 常用注解 bean…

【HTTP】URL结构、HTTP请求和响应的报文格式、HTTP请求的方法、常见的状态码、GET和POST有什么区别、Cookie、Session等重点知识汇总

目录 URL格式 HTTP请求和响应报文的字段&#xff1f; HTTP请求方法 常见的状态码 GET 和 POST 的区别 Cookie 和 Session URL格式 &#xff1f;&#xff1a;是用来分割URL的主体部分&#xff08;通常是路径&#xff09;和查询字符串&#xff08;query string&#xff09;…

MyBatisPlus(九)模糊查询

说明 模糊查询&#xff0c;对应SQL语句中的 like 语句&#xff0c;模糊匹配“要查询的内容”。 like /*** 查询用户列表&#xff0c; 查询条件&#xff1a;姓名包含 "J"*/Testvoid like() {String name "J";LambdaQueryWrapper<User> wrapper ne…

十天学完基础数据结构-第六天(树(Tree))

树的基本概念 树是一种层次性的数据结构&#xff0c;它由节点组成&#xff0c;这些节点按照层次关系相互连接。树具有以下基本概念&#xff1a; 根节点&#xff1a;树的顶部节点&#xff0c;没有父节点。 子节点&#xff1a;树中每个节点可以有零个或多个子节点。 叶节点&am…

力扣第102题 广度优先搜索 二叉数 c++

题目 102. 二叉树的层序遍历 中等 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20…

八大排序算法汇总(C语言实现)

本专栏内容为&#xff1a;八大排序汇总 通过本专栏的深入学习&#xff0c;你可以了解并掌握八大排序以及相关的排序算法。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;八大排序汇总 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库…

【1++的刷题系列】之双指针

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的刷题系列】 文章目录 一&#xff0c;什么是双指针二&#xff0c;相关例题例一例二例三例四例五 一&#xff0c;什么是双指针 常见的双指针有两种形式&#xff1a;一种是对撞指针&#xff08…

tinymce富文本编辑器【tip】

项目场景&#xff1a; tinymce富文本编辑器在iview的modal框中显示的问题 问题描述 最近在使用tinymceiviewvue写项目&#xff0c;在富文本编辑器配合弹框一起使用时&#xff0c;总是存在问题&#xff1a;弹框弹出的时候&#xff0c;富文本编辑器不能点击&#xff0c;鼠标的光…

【软考】PV 操作

#国庆发生的那些事儿# 临界资源: 诸进程间需要互斥方式对其进行共享的资源&#xff0c;如打印机、磁带机等临界区: 每个进程中访问临界资源的那段代码称为临界区信号量: 是一种特殊的变量。 信号量的值与相应资源的使用情况有关: ①: 当信号量的值大于0时&#xff0c;表示当…

Lucene学习总结之Lucene的索引文件格式

四、具体格式 上面曾经交代过&#xff0c;Lucene保存了从Index到Segment到Document到Field一直到Term的正向信息&#xff0c;也包括了从Term到Document映射的反向信息&#xff0c;还有其他一些Lucene特有的信息。下面对这三种信息一一介绍。 4.1. 正向信息 Index –> Seg…

Spring 体系架构模块和三大核心组件介绍

Spring架构图 模块介绍 1. Spring Core&#xff08;核心容器&#xff09;&#xff1a;提供了IOC,DI,Bean配置装载创建的核心实现。 spring-core &#xff1a;IOC和DI的基本实现 spring-beans&#xff1a;BeanFactory和Bean的装配管理(BeanFactory) spring-context&#xff1…

LLMs 用强化学习进行微调 RLHF: Fine-tuning with reinforcement learning

让我们把一切都整合在一起&#xff0c;看看您将如何在强化学习过程中使用奖励模型来更新LLM的权重&#xff0c;并生成与人对齐的模型。请记住&#xff0c;您希望从已经在您感兴趣的任务上表现良好的模型开始。您将努力使指导发现您的LLM对齐。首先&#xff0c;您将从提示数据集…

<C++> 模板-上

目录 前言 一、函数模板 1. 概念 2. 格式 3. 原理 4. 函数模板的实例化 4.1 隐式实例化 4.2 显示实例化 5. 模板参数的匹配原则 5.1 5.2 5.3 二、类模板 1. 类模板定义格式 2. 类模板的实例化 总结 前言 如何实现一个通用的函数&#xff0c;函数可以实现两个类型的交换&…