图形学初识--纹理采样和Wrap方式

2024-05-28 00:36

本文主要是介绍图形学初识--纹理采样和Wrap方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 正文
    • 1、为什么需要纹理采样?
    • 2、什么是纹理采样?
    • 3、如何进行纹理采样?
        • (1)假设绘制区域为矩形
        • (2)假设绘制区域为三角形
    • 4、什么是纹理的Wrap方式?
    • 5、有哪些纹理的Wrap方式?
        • (1)Repeat
        • (2)Mirror_Repeat
        • (3)Clamp_To_Edge
        • (4)Clamp_To_Border
    • 6、如何实现纹理的Wrap方式?
        • (1)Repeat
        • (2)Mirror_Repeat
  • 结尾:喜欢的小伙伴可以点点关注+赞哦

前言

上节讲述了双线性插值算法,虽然也有提到主要应用的点就是纹理采样,但是对于这一块有些小小白可能还不了解,所以这一节补充一下纹理采样的内容!

请叫我贴心航火火!梦想为小白而生!

正文

1、为什么需要纹理采样?

想象一个场景: 如果有这么一个需求,需要在屏幕的一块400x400目标区域显示一张图片,正好这张图片的尺寸也是400x400像素,怎么做?

答: 啥都不需要做,是的,根本不需要做什么处理,直接一一对应像素显示即可!

但是,实际情况中,往往几乎不可能这么巧合的一一对应,要么纹理图片过大,要么纹理图片过小,没法一一对应,怎么办呢?

答: 通过引入一种机制,进行等比例对应,这就是uv坐标的由来,它本质上就表示百分比,一般地,uv坐标的标准取值范围是:0.0 - 1.0。

举个纹理图片过小的例子,如下图: 当我们需要绘制 400x400 窗口区域图片纹理大小是 200x200,如果要在窗口 (20, 20) 位置绘制,那么我们就相当于取纹理图片的 ( 20 / 400 , 20 / 400 ) = ( 0.05 , 0.05 ) (20 / 400 , 20 / 400) = (0.05, 0.05) (20/400,20/400)=(0.05,0.05) 比例位置的像素数据,也就是 ( 0.05 ∗ 200 , 0.05 ∗ 200 ) = ( 10 , 10 ) (0.05 * 200,0.05 * 200) = (10, 10) (0.052000.05200)=(10,10) 位置的数据!这里的 ( 0.05 , 0.05 ) (0.05, 0.05) (0.05,0.05)​ 其实就是uv坐标!

在这里插入图片描述

这里引申一下,由于上述举的例子是绘制区域大,纹理图片小。所以自然而然会存在多个绘制区域对应一个纹理像素位置的情况。这时候就应用到上节的内容。是直接采用最邻近的采样方式,还是双线性插值的方式,来缓解像素化的情况,取决于自身的需求!

2、什么是纹理采样?

在屏幕上某一像素绘制时,根据像素所在位置,去图片上寻找对应像素值的过程,这个过程就是纹理采样!如下图所示:

在这里插入图片描述

3、如何进行纹理采样?

其实需要采样的情形无非就是两种情况,上面也说了!纹理太大或太大。这里咱们只说纹理太小的情况,需要用到上一节的双线性插值的知识。

纹理太大的时,解决的思路无非就是让纹理变小,变到一个最适合绘制窗口的大小。如果想要适应各种绘制窗口大小,就需要利用MipMap的知识,后面章节有空的话,会把这部分给补上哦,童鞋们!

(1)假设绘制区域为矩形

需要在一个分辨率为 screen_width X screen_height 的矩形窗口区域绘制一张图片,这张图片分辨率为picture_width X picture_height,假设绘制区域左下角的uv坐标为 ( u x 0 , u y 0 ) (u_{x0}, u_{y0}) (ux0,uy0),右上角的uv坐标为 ( u x 1 , u y 1 ) (u_{x1}, u_{y1}) (ux1,uy1) ,且满足 0 = < u x 0 、 u x 1 、 u y 0 、 u y 1 < = 1.0 0 =< u_{x0}、u_{x1}、u_{y0}、u_{y1} <= 1.0 0=<ux0ux1uy0uy1<=1.0 ,则对于任何绘制区域坐标为 ( x , y ) (x,y) (x,y)​ 的uv坐标为
u x = x s c r e e n _ w i d t h ∗ u x 1 + ( 1 − x s c r e e n _ w i d t h ) ∗ u x 0 u y = y s c r e e n _ h e i g h t ∗ u y 1 + ( 1 − y s c r e e n _ h e i g h t ) ∗ u y 1 u_x = \frac{x}{screen\_width} *u_{x1} + (1 - \frac{x}{screen\_width}) * u_{x0}\\ u_y = \frac{y}{screen\_height} *u_{y1} + (1 - \frac{y}{screen\_height}) * u_{y1}\\ ux=screen_widthxux1+(1screen_widthx)ux0uy=screen_heightyuy1+(1screen_heighty)uy1
既然已经有了绘制区域每一个位置的uv坐标,咱么只需要根据uv坐标,去纹理图片进行采样像素值即可,至于采取何种采样方法,可以参考上一片文章,既可以采用最邻近取整的方式,也可以采取双线性插值的方式!这里根据用户需求,自行决定,不多赘述!

(2)假设绘制区域为三角形

给定三个顶点 p 1 = ( x 1 , y 1 ) 、 p 2 = ( x 2 , y 2 ) 、 p 3 = ( x 3 , y 3 ) p1 = (x_1,y_1)、p2 = (x_2,y_2)、p3 = (x_3,y_3) p1=(x1,y1)p2=(x2,y2)p3=(x3,y3) 并且给定三个顶点的uv坐标分别为 u 1 = ( u x 1 , u y 1 ) , u 2 = ( u x 2 , u y 2 ) , u 3 = ( u x 3 , u y 3 ) u_1 = (u_{x1},u_{y1}),u_2 = (u_{x2},u_{y2}),u_3 = (u_{x3},u_{y3}) u1=(ux1,uy1),u2=(ux2,uy2),u3=(ux3,uy3),如何得知三角形内每一个顶点 p ( x , y ) p(x,y) p(x,y) 的uv坐标呢?

这时候重心坐标插值公式,又派上用上了,之前的章节已经介绍过,就不过多阐释了!

这时候 每一个三角形内的顶点 p ( x , y ) p(x,y) p(x,y) 的uv坐标 u p = α u 1 + β u 2 + γ u 3 u_p = \alpha u_1 + \beta u_2 +\gamma u_3 up=αu1+βu2+γu3 ,三个系数根据重心坐标公式即可算得!这时候同样,根据uv坐标去纹理图片进行采样像素值即可!

简单给个参考图:

在这里插入图片描述

4、什么是纹理的Wrap方式?

虽然标准规定的uv坐标范围为: ( 0.0 , 1.0 ) (0.0, 1.0) (0.0,1.0) ,但是如果越界了,对应的uv坐标的采样值如何取呢?这个问题的答案就是纹理的Wrap属性!

5、有哪些纹理的Wrap方式?

常见的Wrap方式有四种:

  • Repeat
  • Mirror_Repeat
  • Clamp_To_Edge
  • Clamp_To_Border

这里分别简单介绍并给出示例图:

(1)Repeat

超出部分,不断循环重复

在这里插入图片描述

(2)Mirror_Repeat

超出部分,不断循环镜像重复

在这里插入图片描述

(3)Clamp_To_Edge

纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果

在这里插入图片描述

(4)Clamp_To_Border

超出的坐标为用户指定的边缘颜色

在这里插入图片描述

6、如何实现纹理的Wrap方式?

上述的第(3)和第(4)很好理解,咱们就讨论下第(1)种和第(2)种的计算方式吧!

(1)Repeat

计算公式:
记 f ( x ) 函数表示取浮点数 x 的小数部分 , 则坐标 ( u x , u y ) 的最终坐标为 u x = f ( f ( u x ) + 1 ) u y = f ( f ( u y ) + 1 ) 记f(x)函数表示取浮点数x的小数部分,则坐标(u_x, u_y)的最终坐标为\\ u_x = f(\ f(u_x) + 1\ )\\ u_y = f(\ f(u_y) + 1\ ) f(x)函数表示取浮点数x的小数部分,则坐标(ux,uy)的最终坐标为ux=f( f(ux)+1 )uy=f( f(uy)+1 )

举例佐证:

  • ( 1.2 , 2.2 ) = > ( f ( 0.2 + 1 ) , f ( 0.2 + 1 ) ) = > ( 0.2 , 0.2 ) (1.2, 2.2) => (\ f(0.2 + 1),f(0.2 + 1)\ ) => (0.2, 0.2) (1.2,2.2)=>( f(0.2+1),f(0.2+1) )=>(0.2,0.2) ok

  • ( 0.3 , 0.8 ) = > ( f ( 0.3 + 1 ) , f ( 0.8 + 1 ) ) = > ( 0.3 , 0.8 ) (0.3, 0.8) => (\ f(0.3 + 1),f(0.8 + 1)\ ) => (0.3, 0.8) (0.3,0.8)=>( f(0.3+1),f(0.8+1) )=>(0.3,0.8) ok

  • ( − 0.5 , − 2.2 ) = > ( f ( − 0.5 + 1 ) , f ( − 0.2 + 1 ) ) = > ( 0.5 , 0.8 ) (-0.5, -2.2) => (\ f(-0.5 + 1),f(-0.2 + 1)\ ) => (0.5, 0.8) (0.5,2.2)=>( f(0.5+1),f(0.2+1) )=>(0.5,0.8) ok

(2)Mirror_Repeat

计算公式:
记 f ( x ) 函数表示取浮点数 x 的小数部分 , 则坐标 ( u x , u y ) 的最终坐标为 u x = 1 − f ( f ( u x ) + 1 ) u y = 1 − f ( f ( u y ) + 1 ) 记f(x)函数表示取浮点数x的小数部分,则坐标(u_x, u_y)的最终坐标为\\ u_x = 1 - f(\ f(u_x) + 1\ )\\ u_y = 1 - f(\ f(u_y) + 1\ ) f(x)函数表示取浮点数x的小数部分,则坐标(ux,uy)的最终坐标为ux=1f( f(ux)+1 )uy=1f( f(uy)+1 )

举例佐证:

  • ( 1.2 , 2.2 ) = > ( 1 − f ( 0.2 + 1 ) , 1 − f ( 0.2 + 1 ) ) = > ( 1 − 0.2 , 1 − 0.2 ) = > ( 0.8 , 0.8 ) (1.2, 2.2) => (\ 1 - f(0.2 + 1),1 - f(0.2 + 1)\ ) => (1 - 0.2, 1 - 0.2) => (0.8,0.8) (1.2,2.2)=>( 1f(0.2+1),1f(0.2+1) )=>(10.2,10.2)=>(0.8,0.8) ok
  • ( 0.3 , 0.8 ) = > ( 1 − f ( 0.3 + 1 ) , 1 − f ( 0.8 + 1 ) ) = > ( 1 − 0.3 , 1 − 0.8 ) = > ( 0.7 , 0.2 ) (0.3, 0.8) => (\ 1 - f(0.3 + 1),1 - f(0.8 + 1)\ ) => (1 - 0.3, 1 - 0.8) => (0.7, 0.2) (0.3,0.8)=>( 1f(0.3+1),1f(0.8+1) )=>(10.3,10.8)=>(0.7,0.2) ok
  • ( − 0.5 , − 2.2 ) = > ( 1 − f ( − 0.5 + 1 ) , 1 − f ( − 0.2 + 1 ) ) = > ( 1 − 0.5 , 1 − 0.8 ) = > ( 0.5 , 0.2 ) (-0.5, -2.2) => (\ 1 - f(-0.5 + 1),1 - f(-0.2 + 1)\ ) => (1 - 0.5, 1 - 0.8) => (0.5, 0.2) (0.5,2.2)=>( 1f(0.5+1),1f(0.2+1) )=>(10.5,10.8)=>(0.5,0.2) ok

结尾:喜欢的小伙伴可以点点关注+赞哦

希望对各位小伙伴能够有所帮助哦,永远在学习的道路上伴你而行, 我是航火火,火一般的男人!

这篇关于图形学初识--纹理采样和Wrap方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

SQL 中多表查询的常见连接方式详解

《SQL中多表查询的常见连接方式详解》本文介绍SQL中多表查询的常见连接方式,包括内连接(INNERJOIN)、左连接(LEFTJOIN)、右连接(RIGHTJOIN)、全外连接(FULLOUTER... 目录一、连接类型图表(ASCII 形式)二、前置代码(创建示例表)三、连接方式代码示例1. 内连接(I

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

JS 实现复制到剪贴板的几种方式小结

《JS实现复制到剪贴板的几种方式小结》本文主要介绍了JS实现复制到剪贴板的几种方式小结,包括ClipboardAPI和document.execCommand这两种方法,具有一定的参考价值,感兴趣的... 目录一、Clipboard API相关属性方法二、document.execCommand优点:缺点:

Python创建Excel的4种方式小结

《Python创建Excel的4种方式小结》这篇文章主要为大家详细介绍了Python中创建Excel的4种常见方式,文中的示例代码简洁易懂,具有一定的参考价值,感兴趣的小伙伴可以学习一下... 目录库的安装代码1——pandas代码2——openpyxl代码3——xlsxwriterwww.cppcns.c

Deepseek使用指南与提问优化策略方式

《Deepseek使用指南与提问优化策略方式》本文介绍了DeepSeek语义搜索引擎的核心功能、集成方法及优化提问策略,通过自然语言处理和机器学习提供精准搜索结果,适用于智能客服、知识库检索等领域... 目录序言1. DeepSeek 概述2. DeepSeek 的集成与使用2.1 DeepSeek API

CSS弹性布局常用设置方式

《CSS弹性布局常用设置方式》文章总结了CSS布局与样式的常用属性和技巧,包括视口单位、弹性盒子布局、浮动元素、背景和边框样式、文本和阴影效果、溢出隐藏、定位以及背景渐变等,通过这些技巧,可以实现复杂... 一、单位元素vm 1vm 为视口的1%vh 视口高的1%vmin 参照长边vmax 参照长边re