学习threejs,使用THREE.ImageUtils.loadTexture加载纹理贴图

发布于:2025-04-01 ⋅ 阅读:(34) ⋅ 点赞:(0)

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师



一、🍀前言

本文详细介绍如何基于threejs在三维场景中使用THREE.ImageUtils.loadTexture加载纹理贴图,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️THREE.ImageUtils.loadTexture

THREE.ImageUtils.loadTexture 加载纹理贴图,Three.js r76 之前版本版本使用

语法:

THREE.ImageUtils.loadTexture(
  url: String,
  mapping?: THREE.Mapping,
  onLoad?: Function,
  onError?: Function,
  crossOrigin?: String
): THREE.Texture

url(必填): 图片文件的路径(如 ‘textures/wood.jpg’)。

mapping(可选): 纹理映射模式,默认是 THREE.UVMapping(适用于普通 UV 贴图)。

onLoad(可选): 加载完成后的回调函数,参数为加载好的 THREE.Texture。

onError(可选): 加载失败时的错误回调函数。

crossOrigin(可选): 跨域策略(如 ‘anonymous’,用于解决 CORS 跨域问题)。

示例代码

var texture = THREE.ImageUtils.loadTexture(
  'texture.jpg',
  THREE.UVMapping,
  function (loadedTexture) {
    console.log('纹理加载成功');
    material.map = loadedTexture;
  },
  function (err) {
    console.error('纹理加载失败:', err);
  },
  'anonymous' // 允许跨域
);

替代方案:
THREE.TextureLoader 自 Three.js r76 起,ImageUtils 被弃用,推荐使用更简洁的 TextureLoader
语法

const loader = new THREE.TextureLoader();
loader.load(
  url: String,
  onLoad?: Function,
  onProgress?: Function,
  onError?: Function
): THREE.Texture

url(必填): 图片路径。

onLoad(可选): 加载完成的回调函数,参数为 THREE.Texture。

onProgress(可选): 加载进度回调(常用于大文件)。

onError(可选): 加载失败回调。

示例代码

const loader = new THREE.TextureLoader();
loader.setCrossOrigin('anonymous'); // 设置跨域

const texture = loader.load(
  'texture.jpg',
  (texture) => {
    console.log('纹理加载成功');
    material.map = texture;
    texture.wrapS = THREE.RepeatWrapping; // 设置纹理重复
    texture.wrapT = THREE.RepeatWrapping;
  },
  (progress) => {
    console.log(`加载进度: ${progress.loaded / progress.total * 100}%`);
  },
  (err) => {
    console.error('加载失败:', err);
  }
);

使用 Promise(异步加载):
Three.js ≥ r125 支持 loadAsync 方法(基于 Promise):

async function loadTexture() {
  try {
    const loader = new THREE.TextureLoader();
    loader.setCrossOrigin('anonymous');
    const texture = await loader.loadAsync('texture.jpg');
    material.map = texture;
  } catch (err) {
    console.error('加载失败:', err);
  }
}

注意事项:
跨域问题:若从外部域名加载纹理,需设置 crossOrigin:

loader.setCrossOrigin('anonymous');

纹理属性配置:加载后设置纹理行为:

texture.wrapS = THREE.RepeatWrapping; // 水平重复
texture.wrapT = THREE.RepeatWrapping; // 垂直重复
texture.minFilter = THREE.LinearFilter; // 缩小过滤模式

统一加载管理:使用 THREE.LoadingManager 统一管理所有资源加载:

const manager = new THREE.LoadingManager();
manager.onProgress = (url, loaded, total) => {
  console.log(`已加载 ${loaded}/${total} 个文件`);
};
const loader = new THREE.TextureLoader(manager);

1.2 ☘️THREE.MeshPhongMaterial材质

THREE.MeshPhongMaterial 是 Three.js 中的一种材质类型,用于模拟物体表面的光照效果,包括漫反射(diffuse)和镜面反射(specular)。这种材质遵循 Phong 反射模型,可以模拟出光滑表面的高光效果,因此非常适合用来渲染金属、塑料、瓷器等具有光泽表面的物体。
常用属性:
THREE.MeshPhongMaterial 继承自 THREE.Material,并具有一些特定的属性,可以用来控制材质的外观:

color:材质的基本颜色,默认为白色(0xffffff)。可以是一个整数,表示十六进制颜色值。
map:基础颜色贴图,可以用来替代材质的颜色。可以是一个 THREE.Texture 对象。
alphaMap:透明度贴图,可以用来定义材质的透明度。可以是一个 THREE.Texture 对象。
emissive:自发光颜色,默认为黑色(0x000000)。即使在没有光源的情况下,也会显示这个颜色。
emissiveMap:自发光贴图,可以用来定义自发光的颜色。可以是一个 THREE.Texture 对象。
specular:高光颜色,默认为白色(0x111111)。高光颜色定义了镜面反射的颜色。
shininess:高光强度,默认为 30。高光强度定义了高光区域的锐度,数值越高,高光越集中。
opacity:材质的全局透明度,默认为 1(不透明)。
transparent:是否开启透明模式,默认为 false。如果设置为 true,则需要设置 opacity 或者使用 alphaMap。
side:指定材质在哪一面渲染,可以是 THREE.FrontSide(正面)、THREE.BackSide(背面)或 THREE.DoubleSide(双面)。
wireframe:是否启用线框模式,默认为 false。
visible:是否渲染该材质,默认为 true。
depthTest:是否进行深度测试,默认为 true。
depthWrite:是否写入深度缓冲区,默认为 true。
blending:混合模式,默认为 THREE.NormalBlending。可以设置为 THREE.AdditiveBlending、THREE.SubtractiveBlending 等。
vertexColors:是否启用顶点颜色,默认为 THREE.NoColors。可以设置为 THREE.VertexBasicColors、THREE.VertexColors 或 THREE.FaceColors。
flatShading:是否使用平滑着色,默认为 false。如果设置为 true,则每个面片都将使用平均法线。
envMap:环境贴图,可以用来模拟环境光照。可以是一个 THREE.Texture 对象。
reflectivity:环境光反射率,默认为 1。
refractionRatio:折射率,默认为 0.98。
combine:环境贴图的组合方式,默认为 THREE.MixOperation。
bumpMap:凹凸贴图,可以用来模拟表面细节。可以是一个 THREE.Texture 对象。
bumpScale:凹凸贴图的比例,默认为 1。
normalMap:法线贴图,可以用来模拟表面细节。可以是一个 THREE.Texture 对象。
normalScale:法线贴图的比例,默认为 Vector2(1, 1)。
displacementMap:置换贴图,可以用来改变表面的高度。可以是一个 THREE.Texture 对象。
displacementScale:置换贴图的比例,默认为 1。
displacementBias:置换贴图的偏移,默认为 0。

1.3 ☘️TGA加载器TGALoader

构造函数
TGALoader( manager : LoadingManager )
manager — 供加载器使用的 loadingManager。默认值为 THREE.DefaultLoadingManager。

创建一个新的 TGALoader。

属性
请参阅基本 Loader 类以了解公共属性。

方法
常用方法见 Loader 基类。

.load ( url : String, onLoad : Function, onProgress : Function, onError : Function ) : DataTexture
url — 包含 .tga 文件的路径/URL 的字符串。

onLoad — (可选)加载成功完成后要调用的函数。该函数接收加载的 DataTexture 作为参数。

onProgress — (可选)在加载过程中调用的函数。参数将是 XMLHttpRequest 实例,它包含 .total 和 .loaded 字节。

onError —(可选)加载期间发生错误时调用的函数。该函数接收错误作为参数。

从 url 开始加载并将加载的纹理传递给 onLoad。纹理也直接返回以供立即使用(但可能未完全加载)。

二、🍀使用THREE.ImageUtils.loadTexture加载纹理贴图

1. ☘️实现思路

  • 1、初始化renderer渲染器
  • 2、初始化Scene三维场景scene
  • 3、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt。
  • 4、创建THREE.AmbientLight环境光源ambiLight,scene场景加入环境光源ambiLight。创建THREE.DirectionalLight平行光源light,设置平行光源位置,scene添加平行光源light。
  • 5、加载几何模型:定义createMesh方法,用于创建THREE.Mesh网格对象mesh,该方法中mesh调用THREE.ImageUtils.loadTexture方法使用‘metal-rust.jpg’、‘floor-wood.jpg’和‘brick-wall.jpg’图片进行贴图。调用createMesh方法,生成二十面几何体网格对象polyhedron,生成立方体网格对象cube,球体网格对象sphere,设置polyhedron、cube网格对象位置,场景scene加入生成的网格对象。定义render方法,实现几何体渲染和旋转动画,执行render方法。具体代码参考下面代码样例。
  • 6、加入stats监控器,监控帧数信息。

2. ☘️代码样例

<!DOCTYPE html>
<html>
<head>
    <title>学习threejs,使用THREE.ImageUtils.loadTexture加载纹理贴图</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>

<!-- Js代码块 -->
<script type="text/javascript">

    // 初始化
    function init() {

        var stats = initStats();

        // 创建三维场景scene
        var scene = new THREE.Scene();

        // 创建透视相机camera
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // 创建webgl渲染器webGLRenderer,设置颜色、大小和投影
        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        var polyhedron = createMesh(new THREE.IcosahedronGeometry(5, 0), "metal-rust.jpg");
        polyhedron.position.x = 12;
        scene.add(polyhedron);

        var sphere = createMesh(new THREE.SphereGeometry(5, 20, 20), "floor-wood.jpg");
        scene.add(sphere);

        var cube = createMesh(new THREE.BoxGeometry(5, 5, 5), "brick-wall.jpg");
        cube.position.x = -12;
        scene.add(cube);
        console.log(cube.geometry.faceVertexUvs);

        // 设置相机位置和方向
        camera.position.x = 00;
        camera.position.y = 12;
        camera.position.z = 28;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var ambiLight = new THREE.AmbientLight(0x141414);
        scene.add(ambiLight);

        var light = new THREE.DirectionalLight();
        light.position.set(0, 30, 20);
        scene.add(light);

        // webGLRenderer渲染器绑定html要素
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        var step = 0;
        var controls = new function () {
        };

        var gui = new dat.GUI();

        render();

        function createMesh(geom, imageFile) {
            var texture = THREE.ImageUtils.loadTexture("../assets/textures/general/" + imageFile);
            var mat = new THREE.MeshPhongMaterial();
            mat.map = texture;
            var mesh = new THREE.Mesh(geom, mat);
            return mesh;
        }

        function render() {
            stats.update();

            polyhedron.rotation.y = step += 0.01;
            polyhedron.rotation.x = step;
            cube.rotation.y = step;
            cube.rotation.x = step;
            sphere.rotation.y = step;
            sphere.rotation.x = step;

            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }

        function initStats() {

            var stats = new Stats();
            stats.setMode(0);

            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';

            document.getElementById("Stats-output").appendChild(stats.domElement);

            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

效果如下:
在这里插入图片描述