关于UV纹理坐标映(Texture Mapping)射原理

本文详细介绍了纹理坐标在OpenGL ES中的使用方法,包括如何将纹理映射到多边形,通过调整纹理坐标实现不同区域的显示效果,以及如何使用纹理坐标实现纹理的旋转、翻转和扭曲。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

纹理坐标

 

当纹理映射启动后绘图时,你必须为OpenGL ES提供其他数据,即顶点数组中各顶点的 纹理坐标。纹理坐标定义了图像的哪一部分将被映射到多边形。它的工作方式有点奇怪。你有一个正方形或长方形的纹理,其左下角为二维平面的原点,高和宽的单位为一。像这样:

texture_coords

 

这就是我们的“纹理坐标系统”,不使用xy 来代表二维空间,我们使用 st 作为纹理坐标轴,但原理上是一样的。

 

除了 st 轴外,被映射的纹理在多边形同样有两个轴,它们称为 uv轴。这是源于许多3D图像程序中的UV 映射 的术语。

uvst

 

好,我们明白了纹理坐标系统,我们现在讨论怎样使用这些纹理坐标。当我们指定顶点数组中的顶点时,我们需要在另一个数组中提供纹理坐标,它称为纹理坐标数组。 每个顶点,我们将传递两个GLfloats (s, t) 来指定顶点在上图所示坐标系统的位置。让我们看看一个可能是最为简单的例子,将整个图像映射到一个由三角形条组成的正方形上。首先,我们创建一个由四个顶点组成的顶点数组:

trianglestrip

 

现在将两个框图叠在一起,所使用的坐标数组的值变得很明显:

overlay

将其转化为 GLfloat数组:

    static const GLfloat texCoords[] = {
        0.0, 1.0,
        1.0, 1.0,
        0.0, 0.0,
        1.0, 0.0
    };

 

下面是我使用的纹理:

texture

 

运行时的结果:

textureapp1

 

请等下:那并不正确。如果你仔细对比一下纹理图像和上面的截屏,你就会发现它们并不完全相同。截屏中图像的y轴(或t轴)完全颠倒了。它上下颠倒了,并不是旋转,而是翻转了。

 


 

更多的映射方式

 

上个例子中这个图像都被映射到绘制的正方形上。那是因为设定的纹理坐标所决定的。我们可以改变坐标数组仅使用源图像的中心部分。让我们看看仅使用了图像中心部分的另一个框图:

mapping3

 

其坐标数组为:

    static const GLfloat texCoords[] = {
        0.25, 0.75,
        0.75, 0.75,
        0.25, 0.25,
        0.75, 0.25
    };

 

运行使用了新映射到程序,屏幕上只显示了图像的中心部分:

middle

 

类似地,如果我们只希望显示纹理的左下部:

lowerleft

 

坐标数组为:

    static const GLfloat texCoords[] = {
        0.0, 0.5,
        0.5, 0.5,
        0.0, 0.0,
        0.5, 0.0
    };

 

显示结果:

lowerleft1

 

等一下,还有更多的方式

 

实际上,并不是真正还有更多的映射方式,只是说此功能在正方形到正方形的映射时并不很明显。同样的步骤适合于几何体中任何三角形,而且你甚至可以通过非常规方式的映射来扭曲纹理。例如,我们可以定义一个等腰三角形:

triangle

 

但将底部顶点映射到纹理的左下角:

weirdMapping

 

运行时结果如下:

trianglesimul

 

注意到纹理正方形左下角的弧形花纹现在处于三角形的底部了吗?总而言之,纹理上的任何一点都可以映射到多边形的任何一点。或者换而言之,你可以对任何地点(u,v)使用任何(s,t)而OpenGL ES则为你进行映射。

(2011-12-30,文章来源:http://www.iphone-geek.cn/%E7%BC%96%E7%A8%8B/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E5%AD%A6%E4%B9%A0opengl-es%E4%B9%8B%E5%85%AD-%E7%BA%B9%E7%90%86%E5%8F%8A%E7%BA%B9%E7%90%86%E6%98%A0%E5%B0%84


Projective Texture Mapping 是一种常用的 Shader 技术,可以用来在 Unity 中实现纹理投影效果。它的原理是通过将投影纹理到场景物体上,并基于物体的表面法线和光照方向来计算出光照效果,从而实现物体表面的投影纹理效果。 以下是一个简单的 Projective Texture Mapping 的 Shader 示例: ```shader Shader "Custom/ProjectiveTextureMapping" { Properties { _MainTex ("Texture", 2D) = "white" {} _ProjTex ("Projection Texture", 2D) = "white" {} _Intensity ("Intensity", Range(0,1)) = 1 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 projPos : TEXCOORD0; float3 worldNormal : TEXCOORD1; float4 vertex : SV_POSITION; }; sampler2D _MainTex; sampler2D _ProjTex; float _Intensity; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.projPos = ComputeGrabScreenPos(o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { // 计算纹理坐标 float2 projCoord = i.projPos.xy / i.projPos.w; projCoord = 0.5 * (projCoord + 1.0); // 计算投影纹理颜色 fixed4 projColor = tex2D(_ProjTex, projCoord); // 计算漫反光照 float3 worldNormal = normalize(i.worldNormal); float3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); float intensity = _Intensity * max(0, dot(worldNormal, worldLightDir)); // 计算最终颜色并返回 fixed4 texColor = tex2D(_MainTex, i.uv); fixed4 finalColor = lerp(texColor, projColor, intensity); return finalColor; } ENDCG } } } ``` 这个 Shader 的主要实现思路是,将投影纹理的颜色和物体表面原有的颜色进行插值计算,插值的比例根据光照方向和表面法线来计算。其中,ComputeGrabScreenPos() 函数用于将物体的顶点坐标转换为屏幕坐标,从而计算出纹理坐标。在 Pass 中的 vert 函数中,通过 UnityObjectToWorldNormal() 函数将物体的法线转换为世界坐标系下的法线,从而能够正确计算出光照效果。 使用这个 Shader,将它添加到一个材质中,并将这个材质应用到需要投影纹理的物体上,就可以实现 Projective Texture Mapping 技术了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值