当前位置: 首页 > article >正文

【three.js】纹理贴图

目录

 1.纹理贴图

2.纹理过滤

3.UV映射原理

3.1纹理UV坐标

3.2纹理映射

4.纹理阵列,偏移和旋转

4.1纹理阵列

4.2纹理偏移

4.3纹理旋转

5.UV动画


 1.纹理贴图

在Three.js中,纹理贴图是一种将二维图像应用到三维物体表面的技术,显著提升物体的视觉表现力。通过使用THREE.TextureLoader类,可以轻松地加载和应用纹理。

例如,加载一个纹理并应用到一个立方体上,可以通过以下代码实现:

const loader = new THREE.TextureLoader();
loader.load('path/to/your/texture.png', function(texture) {
  const material = new THREE.MeshBasicMaterial({map: texture});
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  const cube = new THREE.Mesh(geometry, material);
  scene.add(cube);
});

        除了基本的THREE.MeshBasicMaterial,Three.js还支持其他材质类型,如THREE.MeshStandardMaterialTHREE.MeshPhongMaterial,它们提供了更逼真的光照和反射效果。

2.纹理过滤

纹理过滤是决定纹理映射到不同尺寸像素时如何采样的技术。Three.js支持三种主要的纹理过滤方法:

线性过滤(Linear Filtering):使用最近四个像素的加权平均值,产生平滑效果,但可能模糊高对比度纹理。

最近邻过滤(Nearest Filtering):选择最近的像素颜色,适用于保持锐利边缘的纹理,但可能导致锯齿状边缘。

Mipmap过滤:创建纹理的多个缩小版本(mipmap),根据纹理在屏幕上的大小选择合适的mipmap进行采样,提供不同距离下的良好表现,但增加内存使用。

在Three.js中,可以通过设置纹理的minFiltermagFilter属性来控制纹理过滤。例如

var loader = new THREE.TextureLoader();
​
// 加载纹理
loader.load('textures/yourTexture.png', function(texture) {
    // 设置纹理过滤
    texture.minFilter = THREE.NearestFilter;
    texture.magFilter = THREE.LinearFilter;
​
    // 创建材质
    var material = new THREE.MeshBasicMaterial({map: texture});
​
    // 创建网格
    var mesh = new THREE.Mesh(geometry, material);
​
    // 将网格添加到场景
    scene.add(mesh);
});

3.UV映射原理

UV映射是将二维纹理坐标映射到三维模型上的过程。UV坐标独立于三维坐标,通常范围从0到1,其中(0,0)表示纹理的左下角,(1,1)表示右上角。在Three.js中,UV坐标通过THREE.Geometry(已被THREE.BufferGeometry取代)或THREE.BufferGeometry对象的.uv属性定义。每个面或三角形都有自己的UV坐标集合。

定义UV坐标和创建纹理映射的示例如下:

var geometry = new THREE.BufferGeometry(); // 使用BufferGeometry替代Geometry
// ... 创建顶点和面,并设置UV坐标 ...
var loader = new THREE.TextureLoader();
loader.load('textures/yourTexture.png', function(texture) {
  var material = new THREE.MeshBasicMaterial({map: texture});
  var mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
});

对于复杂的几何体,建议使用专业的3D建模软件(如Blender)生成UV坐标,并导出为Three.js可识别的格式。

3.1纹理UV坐标

纹理UV坐标是定义在二维纹理图像上的坐标系统,用于将纹理图像上的每个点映射到三维模型的表面上。UV坐标通常被归一化到[0, 1]范围内,其中(0, 0)表示纹理的左下角,(1, 1)表示纹理的右上角。通过调整UV坐标,可以控制纹理在模型表面上的布局和重复

// 引入Three.js库(这里假设已经通过<script>标签或模块系统正确引入)

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight, 
    0.1, 
    1000
);
camera.position.z = 5;

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 加载纹理
const textureLoader = new THREE.TextureLoader();
textureLoader.load('path/to/your/texture.jpg', function(texture) {
    // 创建一个平面几何体,但先不设置UV坐标(Three.js会自动生成默认的)
    const planeGeometry = new THREE.PlaneGeometry(2, 2); // 2x2的平面

    // 手动设置UV坐标
    // 我们将纹理的一部分(例如左上角1/4区域)映射到整个平面上
    planeGeometry.faceVertexUvs[0] = [
        [
            new THREE.Vector2(0, 0),       // 左下角的UV坐标(纹理的左上角)
            new THREE.Vector2(0.5, 0),     // 右下角的UV坐标(纹理横向1/2处)
            new THREE.Vector2(0.5, 0.5),   // 右上角的UV坐标(纹理的1/4右上角)
            new THREE.Vector2(0, 0.5)      // 左上角的UV坐标(与左下角相同,形成闭环)
        ]
    ];

    // 注意:上面的UV设置实际上会导致纹理在平面上重复,因为两个对角点的UV坐标相同。
    // 为了正确映射纹理的一部分到平面,我们应该这样设置:
    planeGeometry.faceVertexUvs[0] = [
        [
            new THREE.Vector2(0, 0),       // 左下角的UV坐标(纹理的左上角)
            new THREE.Vector2(0.25, 0),    // 右下角的UV坐标(纹理横向1/4处)
            new THREE.Vector2(0.25, 0.25), // 右上角的UV坐标(纹理的1/4右上角)
            new THREE.Vector2(0, 0.25)     // 左上角的UV坐标(纹理纵向1/4处)
        ]
    ];

    // 创建一个材质,并将加载的纹理应用到该材质上
    const material = new THREE.MeshBasicMaterial({ map: texture });

    // 使用几何体和材质创建一个网格,并将其添加到场景中
    const plane = new THREE.Mesh(planeGeometry, material);
    scene.add(plane);

    // 渲染循环
    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
    }
    animate();
});

// 处理窗口大小变化(可选)
window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

3.2纹理映射

纹理映射是一种技术,它将二维纹理图像应用到三维模型的表面上。这通常通过UV坐标来实现,使得当模型被渲染时,其表面会呈现出纹理图像的外观。纹理映射可以极大地增强三维模型的真实感和细节

// 引入Three.js库(假设已经通过<script>标签或模块导入)

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(75, 
    window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 加载纹理
const textureLoader = new THREE.TextureLoader();
textureLoader.load('path/to/your/texture.jpg', function(texture) {
    // 创建一个平面几何体(PlaneGeometry)
    const geometry = new THREE.PlaneGeometry(2, 2); // 创建一个2x2的平面

    // 默认情况下,PlaneGeometry的UV坐标已经设置好了,覆盖整个纹理
    // 但如果你想手动设置UV坐标,可以这样做:
    // geometry.faceVertexUvs[0] = [
    //     [
    //          new THREE.Vector2(0, 0), 
    //          new THREE.Vector2(1, 0), 
    //          new THREE.Vector2(1, 1), 
    //          new THREE.Vector2(0, 1)
    //      ]
    // ]; // 这会设置一个简单的矩形UV映射

    // 创建一个材质,并将纹理应用于该材质
    const material = new THREE.MeshBasicMaterial({ map: texture });

    // 创建一个网格并添加到场景中
    const plane = new THREE.Mesh(geometry, material);
    scene.add(plane);

    // 渲染循环
    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
    }
    animate();
});

// 处理窗口大小变化(可选)
window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

4.纹理阵列,偏移和旋转

纹理阵列、偏移和旋转进一步增强了纹理的灵活性和表现力:

纹理阵列:通过设置texture.wrapStexture.wrapTTHREE.RepeatWrapping,并使用texture.repeat属性,可以在物体表面上重复使用纹理。

纹理偏移:通过调整texture.offset属性,可以实现纹理的局部移动效果。

纹理旋转:通过设置texture.rotation属性,可以旋转纹理。需要注意的是,旋转角度是以弧度为单位的。

        最后,通过修改纹理的offset属性,可以在每一帧中稍微改变其值,从而实现UV动画效果。结合THREE.Clock对象,可以更加流畅和可控地控制动画的速度和帧率。

4.1纹理阵列

纹理阵列(Texture Array)是一种将多个纹理图像组合成一个单一纹理对象的技术。这样,可以在一个渲染过程中使用多个纹理,而无需频繁地切换纹理。纹理阵列在图形处理中非常有用,特别是在需要同时处理多个纹理时,如场景的背景、物体的不同部分等。

实例:

假设有一个包含多个不同纹理的纹理阵列,可以在Shader中通过索引来选择要使用的纹理。例如,在Unity的Shader中,可以使用tex2DArray函数来从纹理阵列中采样纹理。

sampler2DArray _TexArray;
float4 frag(v2f i) : SV_Target
{
    float4 col = tex2DArray(_TexArray, float3(i.uv, 0)); // 假设使用第一个纹理
    return col;
}

4.2纹理偏移

纹理偏移(Texture Offset)是一种通过改变UV坐标来移动纹理图像在模型表面位置的技术。通过调整UV坐标的偏移量,可以实现纹理在模型表面的平移效果。

示例

在Unity中,可以通过调整材质的_MainTex_ST.zw属性来改变纹理的偏移量。例如,要向右移动纹理,可以增加_MainTex_ST.x的值;要向上移动纹理,可以增加_MainTex_ST.y的值。

// 假设有一个名为_MainTex的纹理
Renderer renderer = GetComponent<Renderer>();
Material material = renderer.material;
Vector4 offsetScale = material.GetVector("_MainTex_ST");
offsetScale.x += 0.1f; // 向右移动纹理
material.SetVector("_MainTex_ST", offsetScale);

4.3纹理旋转

纹理旋转(Texture Rotation)是一种通过改变UV坐标来旋转纹理图像在模型表面方向的技术。通过调整UV坐标的旋转角度,可以实现纹理在模型表面的旋转效果。

示例

在Unity的Shader中,可以通过调整UV坐标的旋转矩阵来实现纹理的旋转。例如,要旋转纹理90度,可以使用以下Shader代码:

struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
};

struct v2f
{
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
};

v2f vert(appdata v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    // 旋转UV坐标(90度)
    float2 rotatedUV = float2(
        cos(PI/2) * v.uv.x - sin(PI/2) * v.uv.y, 
        sin(PI/2) * v.uv.x + cos(PI/2) * v.uv.y
    );
    o.uv = rotatedUV;
    return o;
}

sampler2D _MainTex;
float4 frag(v2f i) : SV_Target
{
    float4 col = tex2D(_MainTex, i.uv);
    return col;
}

5.UV动画

UV动画是一种通过动态改变UV坐标来实现纹理在模型表面移动或变化的效果。通过逐帧更新UV坐标,可以创建出各种动态的纹理效果,如滚动、波动、闪烁等。

示例

在Unity中,可以通过编写脚本来实现UV动画。例如,以下脚本实现了一个简单的UV滚动动画:

using UnityEngine;

public class UVScrollAnimation : MonoBehaviour
{
    public float scrollSpeed = 0.1f;
    private Mesh mesh;
    private Vector2[] uvs;

    void Start()
    {
        mesh = GetComponent<MeshFilter>().mesh;
        uvs = mesh.uv.Clone() as Vector2[];
    }

    void Update()
    {
        for (int i = 0; i < uvs.Length; i++)
        {
            uvs[i].x += Time.deltaTime * scrollSpeed;
            if (uvs[i].x > 1.0f)
            {
                uvs[i].x -= 1.0f; // 纹理循环滚动
            }
        }
        mesh.uv = uvs;
    }
}

将上述脚本附加到一个带有MeshFilter组件的GameObject上,并设置scrollSpeed属性,即可看到纹理在模型表面滚动的动画效果。

码字不易,各位大佬点点赞呗


http://www.kler.cn/a/509454.html

相关文章:

  • Qt Desiogn生成的ui文件转化为h文件
  • 【原创】大数据治理入门(2)《提升数据质量:质量评估与改进策略》入门必看 高赞实用
  • 网络安全---CMS指纹信息实战
  • Net Core微服务入门全纪录(三)——Consul-服务注册与发现(下)
  • 语义检索效果差?深度学习rerank VS 统计rerank选哪个
  • windows下安装并使用node.js
  • 1.4走向不同:GPT 与 BERT 的选择——两大NLP模型的深度解析
  • HTML元素新视角:置换元素与非置换元素的区分与理解
  • Golang笔记——常用库reflect和unsafe
  • 今天你学C++了吗?——C++中的STL
  • Docker部署php-fpm服务器详细教程
  • 嵌入式知识点总结(一)-C/C++关键字
  • HunyuanVideo 文生视频模型实践
  • # [游戏开发] [Unity游戏开发]3D滚球游戏设计与实现教程
  • 构建core模块
  • 接口测试Day10-接口对象封装封装TpShop登录接口
  • mono3d汇总
  • Go语言之路————数组、切片、map
  • PL/SQL语言的文件操作
  • macOS 安装JDK17
  • 【HarmonyOS-开发指南】
  • 使用opencv.js 的时候报错 Uncaught 1022911432
  • JAVA:在IDEA引入本地jar包的方法(不读取maven目录jar包)
  • 【AcWing】蓝桥杯辅导课-递归与递推
  • 了解EJB两种主要类型:BMP与CMP
  • 【Unity】使用Canvas Group改变UI的透明度