Three.js——基础纹理、凹凸纹理、法向贴图、环境贴图、canvas贴图

个人简介

👀个人主页: 前端杂货铺
开源项目: rich-vue3 (基于 Vue3 + TS + Pinia + Element Plus + Spring全家桶 + MySQL)
🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展
📃个人状态: 研发工程师,现效力于中国工业软件事业
🚀人生格言: 积跬步至千里,积小流成江海
🥇推荐学习:🍖开源 rich-vue3 🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js实战 🍒Three.js

🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧

内容参考链接
WebGL专栏WebGL 入门
Three.js(一)创建场景、渲染三维对象、添加灯光、添加阴影、添加雾化
Three.js(二)scene场景、几何体位置旋转缩放、正射投影相机、透视投影相机
Three.js(三)聚光灯、环境光、点光源、平行光、半球光
Three.js(四)基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质
Three.js(五)Three.js——二维平面、二维圆、自定义二维图形、立方体、球体、圆柱体、圆环、扭结、多面体、文字

文章目录

    • 前言
    • 一、基础纹理
    • 二、凹凸贴图
    • 三、法向纹理
    • 四、环境贴图
    • 五、canvas 贴图
    • 总结

前言

大家好,这里是前端杂货铺。

上篇文章我们学习了 骨骼动画。接下来,我们继续我们 three.js 的学习!

在学习的过程中,如若需要深入了解或扩展某些知识,可以自行查阅 => three.js官方文档。


一、基础纹理

纹理简单来说就是给几何体设置外表的显示,跟贴图差不多。要想给几何体添加纹理,我们首先得知道纹理加载器。

TextureLoader,加载 texture 的一个类。 内部使用 ImageLoader 来加载文件。

// manager — 加载器使用的 loadingManager,默认值为 THREE.DefaultLoadingManager
new TextureLoader( manager : LoadingManager )

接下来,我们创建纹理加载器,加载一个外部文件(草地),应用到二维平面上。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <style>* { margin: 0;padding: 0; }
    </style>
</head>

<body>
<script>
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机 视野角度FOV、长宽比、近截面、远截面
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    // 设置相机位置
    camera.position.set(0, 0, 20);

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

    // 添加平面 平面沿着 X 轴的宽度 | 平面沿着 Y 轴的高度 | 平面的宽度分段数 | 平面的高度分段数
    const geometry = new THREE.PlaneBufferGeometry(10, 10, 2, 2);

    // 创建纹理加载器
    const loader = new THREE.TextureLoader();
    loader.load('../assets/grass.png', (texture) => {
        // 创建材质
        const lambert = new THREE.MeshLambertMaterial({
            map: texture
        });
        const mesh = new THREE.Mesh(geometry, lambert);

        // 添加到场景
        scene.add(mesh);
    })

    // 添加灯光
    const spotLight = new THREE.SpotLight(0xffffff);
    spotLight.position.set(-10, 10, 90);
    scene.add(spotLight);

    const animation = () => {
        // 渲染
        renderer.render(scene, camera);
        requestAnimationFrame(animation);
    }

    animation();
</script>
</body>

</html>

在这里插入图片描述


二、凹凸贴图

凹凸贴图使得物体凹凸不平,对于一些场景会显得更加真实。

.bumpMap:用于创建凹凸贴图的纹理。黑色和白色值映射到与光照相关的感知深度。凹凸实际上不会影响对象的几何形状,只影响光照。如果定义了法线贴图,则将忽略该贴图。

接下来,我们针对墙面添加 基础纹理凹凸贴图,来对比一下不同的呈现效果

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <style>* { margin: 0; padding: 0; }</style>
</head>

<body>
<script>
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机 视野角度FOV、长宽比、近截面、远截面
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    // 设置相机位置
    camera.position.set(0, 0, 20);

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

    const geometry = new THREE.BoxGeometry(6, 6, 3);

    // 创建纹理加载器
    const loader = new THREE.TextureLoader();
    loader.load('../assets/wall.jpg', (texture) => {
        // 创建材质
        const lambert = new THREE.MeshPhongMaterial({
            map: texture // 颜色贴图
        });

        const mesh = new THREE.Mesh(geometry, lambert);
        mesh.rotation.y = -0.1;
        mesh.position.x = -4;

        // 添加到场景
        scene.add(mesh);
    })

    renderer.setClearColor(0xffffff);

    // 凹凸贴图
    loader.load('../assets/wall.jpg', (texture) => {
        loader.load('../assets/wall-bump.jpg', (bump) => {
            const lambert = new THREE.MeshPhongMaterial({
                map: texture, // 基础纹理
                bumpMap: bump, // 凹凸贴图
                bumpScale: 0.2 // 凹凸贴图的高度
            })

            const mesh = new THREE.Mesh(geometry, lambert);
            mesh.rotation.y = -0.5;
            mesh.position.x = 4;

            scene.add(mesh);
        })
    })

    // 添加灯光
    const spotLight = new THREE.SpotLight(0xffffff);
    spotLight.position.set(-10, 10, 90);
    scene.add(spotLight);

    const animation = () => {
        // 渲染
        renderer.render(scene, camera);
        requestAnimationFrame(animation);
    }

    animation();
</script>
</body>

</html>

在这里插入图片描述


三、法向纹理

.normalMap : 用于创建法线贴图的纹理。RGB值会影响每个像素片段的曲面法线,并更改颜色照亮的方式。法线贴图不会改变曲面的实际形状,只会改变光照。

接下来,我们针对玉石雕刻添加 基础纹理法向贴图,来对比一下不同的呈现效果

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../lib/three/three.js"></script>
    <style>* { margin: 0;padding: 0; }</style>
</head>

<body>
<script>
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机 视野角度FOV、长宽比、近截面、远截面
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    // 设置相机位置
    camera.position.set(0, 0, 40);

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

    const geometry = new THREE.BoxGeometry(10, 10, 10);

    // 创建纹理加载器
    const loader = new THREE.TextureLoader();

    // 创建材质
    const lambert = new THREE.MeshPhongMaterial({
        map: THREE.ImageUtils.loadTexture('../assets/plaster.jpg'),
    });

    const mesh = new THREE.Mesh(geometry, lambert);
    mesh.rotation.y = 0.5;
    mesh.position.x = -12;

    // 添加到场景
    scene.add(mesh);

    renderer.setClearColor(0xffffff);
    
    const lambert2 = new THREE.MeshPhongMaterial({
        map: THREE.ImageUtils.loadTexture('../assets/plaster.jpg'),
        normalMap: THREE.ImageUtils.loadTexture('../assets/plaster-normal.jpg') // 法向贴图
    })

    const mesh2 = new THREE.Mesh(geometry, lambert2);
    mesh2.rotation.y = -0.5;
    mesh2.position.x = 12;

    scene.add(mesh2);

    // 添加灯光
    const spotLight = new THREE.SpotLight(0xffffff);
    spotLight.position.set(-10, 10, 90);
    scene.add(spotLight);

    const animation = () => {
        // 渲染
        renderer.render(scene, camera);
        requestAnimationFrame(animation);
    }

    animation();
</script>
</body>

</html>

在这里插入图片描述


四、环境贴图

立方相机(CubeCamera),创建 6个 渲染到 WebGLCubeRenderTarget 的摄像机, 并将其拍摄的场景渲染到一个 WebGLCubeRenderTarget 上。

new THREE.CubeCamera( near : Number, far : Number, renderTarget : WebGLCubeRenderTarget )
参数名称描述
near近剪切面的距离
far远剪切面的距离
renderTarget目标多维数据集渲染目标
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>*{ margin: 0; padding: 0;}</style>
    <script src="../lib/three/three.js"></script>

    <!--  轨道控件  -->
    <script src="../lib/three/OrbitControls.js"></script>
</head>

<body>
<script>
    const clock = new THREE.Clock();
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机 视野角度FOV、长宽比、近截面、远截面
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    // 设置相机位置
    camera.position.set(100, 100, 0);
    camera.lookAt(new THREE.Vector3(0, 0, 0));

    // 轨道控制器
    const controls = new THREE.OrbitControls(camera);
    controls.minDistance = 1; // 将相机向内移动
    controls.maxDistance = 50; // 将相机向外移动

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

    // 添加灯光
    const spotLight = new THREE.SpotLight(0xffffff);
    scene.add(spotLight);

    // 创建虚拟的场景(天空盒子)
    const imgs = [
        '../assets/sky/right.jpg',
        '../assets/sky/left.jpg',
        '../assets/sky/top.jpg',
        '../assets/sky/bottom.jpg',
        '../assets/sky/front.jpg',
        '../assets/sky/back.jpg',
    ]

    // 材质数组
    const mats = [];
    // 用于每个面加载不同的材质
    for (let i = 0; i < imgs.length; i++) {
        mats.push(new THREE.MeshBasicMaterial({
            map: THREE.ImageUtils.loadTexture(imgs[i]),
            side: THREE.DoubleSide, // 双面-里和外
        }))
    }

    // 天空盒子,当作场景
    const skybox = new THREE.Mesh(new THREE.BoxGeometry(100, 100, 100), new THREE.MeshFaceMaterial(mats));
    scene.add(skybox);

    // 创建一个球体和一个立方体
    const sphereGeometry = new THREE.SphereGeometry(4, 15, 15);
    const cubeGeometry = new THREE.BoxGeometry(5, 5, 5);

    // 立方体贴图和环境一致,球体是跟随当前环境
    const cubeMaterial = new THREE.MeshBasicMaterial({
        envMap: THREE.ImageUtils.loadTextureCube(imgs) // 环境贴图-六张图片
    })

    // 通过立方相机实现(创建 6 个渲染到 WebGLCubeRenderTarget 的摄像机)
    const cubeCamera = new THREE.CubeCamera(0.1, 2000, 256);
    scene.add(cubeCamera);

    const sphereMaterial = new THREE.MeshBasicMaterial({
        envMap: cubeCamera.renderTarget, // 环境贴图-渲染目标对象
    })

    const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
    const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

    sphere.position.x = 5;
    cube.position.x = -5;

    scene.add(sphere);
    scene.add(cube);

    const animation = () => {
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        // 更新轨道控制器
        controls.update(clock.getDelta());
        // 渲染
        renderer.render(scene, camera);
        requestAnimationFrame(animation);

        // 更新立方相机
        cubeCamera.updateCubeMap(renderer, scene);
    }

    animation();
</script>
</body>

</html>

环境贴图


五、canvas 贴图

要想实现 canvas 贴图,我们首先得创建 canvas 的内容,然后把绘制好的 canvas 当作参数传到纹理中,供网格材质使用。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>*{ margin: 0; padding: 0;}</style>
    <script src="../lib/three/three.js"></script>
</head>

<body>
<script>
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机 视野角度FOV、长宽比、近截面、远截面
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    // 设置相机位置
    camera.position.set(100, 100, 0);
    camera.lookAt(new THREE.Vector3(0, 0, 0));

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

    renderer.setClearColor(0xffffff);

    // 添加灯光
    const spotLight = new THREE.SpotLight(0xffffff);
    scene.add(spotLight);

    function getSprite() {
        const canvas = document.createElement('canvas');
        canvas.width = 160;
        canvas.height = 160;

        const c = canvas.getContext('2d');
        c.fillStyle = 'red';
        // 绘制圆形
        c.arc(80, 80, 32, 0, Math.PI * 2);
        c.fill();

        // canvas 纹理,返回出去
        const texture = new THREE.Texture(canvas);
        // 更新纹理
        texture.needsUpdate = true;
        return texture;
    }

    // 创建一个立方体
    const cubeGeometry = new THREE.BoxGeometry(25, 25, 25);

    // canvas 贴图
    const cubeMaterial = new THREE.MeshBasicMaterial({ map: getSprite() })

    const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

    cube.position.x = -5;

    scene.add(cube);

    const animation = () => {
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        // 渲染
        renderer.render(scene, camera);
        requestAnimationFrame(animation);
    }

    animation();
</script>
</body>

</html>

在这里插入图片描述


总结

本篇文章我们讲解了几种常见纹理的基本使用,包括 基础纹理、凹凸纹理、法向贴图、环境贴图、canvas贴图

更多内容扩展请大家自行查阅 => three.js官方文档,真心推荐读一读!!

好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!


参考资料:

  1. Three.js 官方文档
  2. WebGL+Three.js 入门与实战【作者:慕课网_yancy】

在这里插入图片描述


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux嵌入式设备测试wifi信号强度方法

首先我们要清楚设备具体链接在哪个wifi热点上 执行&#xff1a;nmcli dev wifi list rootubuntu:/home/ubuntu# nmcli dev wifi list IN-USE BSSID SSID MODE CHAN RATE SIGNAL BARS > * 14:EB:08:51:7D:20 wifi22222_5G Infr…

香橙派安装 opencv 4.9.0

香橙派Orange AI Pro / 华为昇腾310 使用源码方式安装opencv 4.9.0 下载源码到香橙派 https://opencv.org/releases/ 解压 unzip opencv-4.9.0.zip进入解压后的文件 cd opencv-4.9.0创建构建目录build mkdir build进入目录 cd build使用cmake配置后续的构建环境 cmake -D…

SwiftUI 利用 Swizz 黑魔法为系统创建的默认对象插入新协议方法(二)

功能需求 在 SwiftUI 的开发中,我们往往需要借助底层 UIKit 的“上帝之手”来进一步实现额外的定制功能。比如,在可拖放(Dragable)SwiftUI 的实现中,会缺失拖放取消的回调方法让我们这些秃头码农们“欲哭无泪” 如上图所示,我们在拖放取消时将界面中的一切改变都恢复如初…

SpringBoot校园疫情管理系统-计算机毕业设计源码81164

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;校园当然也不例外。校园疫情管理系统是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;采用J…

SmartEDA:Multisim与Proteus的强劲对手,引领电子设计新纪元

在电子设计领域&#xff0c;Multisim与Proteus长久以来一直占据着重要的地位&#xff0c;它们以其强大的仿真功能和丰富的组件库&#xff0c;深受设计师们的喜爱。然而&#xff0c;随着科技的不断进步和创新&#xff0c;一款名为SmartEDA的新兴电子设计工具正悄然崭露头角&…

MYSQL数据库客户端常规指令使用

这里新开一章&#xff0c;对MYSQL进行更加底层的系统的一个学习 Mysql常用工具简介 emmmm这里的话就默认大家在linux系统上面都进行了MYSQL的安装了. 在mysql安装完成之后&#xff0c;一般在路径 /usr/bin 下的 我们对该路径进行一个文件的展示 这里是展示出来的辅助工具 …

Web3.0区块链技术开发方案丨ICO与IDO代币开发

在Web3.0时代的到来下&#xff0c;区块链技术不仅改变着金融领域的格局&#xff0c;也在资金筹集和代币发行方面掀起了一场变革。初始代币发行&#xff08;ICO&#xff09;和去中心化代币发行&#xff08;IDO&#xff09;成为了项目融资的主要方式&#xff0c;其基于区块链技术…

【android 9】【input】【8.发送按键事件2——InputDispatcher线程】

系列文章目录 本人系列文章-CSDN博客 目录 系列文章目录 1.简介 1.1流程介绍 1.2 时序图 2.普通按键消息发送部分源码分析&#xff08;按键按下事件&#xff09; 2.1 开机后分发线程阻塞的地方 2.2 InputDispatcher::dispatchOnceInnerLocked 2.3 InputDispatcher::disp…

有没有不用写代码,贴图也简单的HTML WEB 3D 产品展示配置器?

品牌零售商&#xff0c;产品有3D模型但没有贴图&#xff0c;以前是直接送去生产&#xff0c;现在需要上线电商&#xff0c;看到国外挺多这种展示方式的网店&#xff0c;国内有没有这方面的供应商&#xff0c;网店顾客可以自己鼠标转动、换零件、换颜色等看定制效果&#xff0c;…

深入理解并发之LongAdder、DoubleAdder的实现原理

深入理解LongAdder、DoubleAdder的实现原理 本文主要通过LongAdder和DoubleAdder的源码&#xff0c;讲述一下其实现原理。通过LongAdder和DoubleAdder的源码可知。两者都是继承了Striped64的类。下面我们将通过源码的形式讲述一下这三个类都做了哪些事情。 1: Striped64 ​ …

用C#(WinForm)开发触摸屏,体验感满满

用C#&#xff08;WinForm&#xff09;开发触摸屏&#xff0c;体验感满满

人工智能大模型的进化之路:探索如何让它们变得更“聪明”

一、引言 在人工智能&#xff08;AI&#xff09;领域&#xff0c;大模型凭借其强大的处理能力和广泛的应用前景&#xff0c;已经成为研究的热点。然而&#xff0c;尽管这些模型在多个领域展现出了惊人的能力&#xff0c;但它们仍然面临着理解力、泛化能力和适应性等方面的挑战…

中央空调节能的分户计费系统

中央空调节能 在建筑能耗中&#xff0c;中央空调能耗一般占到了40%---60%的比例&#xff0c;因此如何有效降低空调能耗就成为建筑节能的重中之重。 项目案例描述 山东银座购物广场&#xff1a;为集购物中心、高级酒店式公寓和办公为一体的综合性公共建筑。整体建筑共为地下3层&…

我们身边的北斗:你知道吗北斗还能帮我们演唱会抢票

当我们步入2024年&#xff0c;演唱会与音乐节的热潮依然不减。每当周末或节假日&#xff0c;各大城市的演唱会场馆总是人头攒动&#xff0c;歌声与掌声交织成一片欢乐的海洋。而在朋友圈里&#xff0c;也总能看到乐迷们晒出的演唱会现场照片和视频&#xff0c;分享着那份独特的…

智领未来,安全无忧:智能网联汽车监控大屏的守护之旅

在繁忙的都市中&#xff0c;驾驶者往往面临着诸多安全隐患。传统的驾驶辅助系统虽然能够提供一定的帮助&#xff0c;但在复杂多变的交通环境中&#xff0c;其局限性也逐渐显现。而智能网联汽车安全监控大屏&#xff0c;正是为了解决这一问题而诞生的。 山海鲸可视化大屏 大屏采…

36. 【Java教程】输入输出流

本小节将会介绍基本输入输出的 Java 标准类&#xff0c;通过本小节的学习&#xff0c;你将了解到什么是输入和输入&#xff0c;什么是流&#xff1b;输入输出流的应用场景&#xff0c;File类的使用&#xff0c;什么是文件&#xff0c;Java 提供的输入输出流相关 API 等内容。 1…

【翻译软件】CopyTranslator复制即翻译的外文辅助阅读翻译软件NO.102

使用平台&#xff1a;Windows/Linux/macOS 设置里选择翻译引擎和翻译API&#xff0c;谷歌翻译已经退出中国了&#xff0c;但还是提供了镜像地址 一、复制即翻译 只需要复制文本到剪贴板&#xff0c;就可以查看翻译结果 记得开启“自动粘贴”哦。 二、多段同时翻译 三、智能…

别再emo了,还不赶紧去考PMP,搞钱要紧~

自从疫情之后经济大不如从前&#xff0c;现在大环境都不好&#xff0c;很多公司都在裁员&#xff0c;像我朋友就在上个月被裁掉了&#xff0c;虽说拿了补偿但也不可能靠那点补偿生活的&#xff0c;所以我朋友找了很久的工作&#xff0c;但是由于大环境的缺失所以导致他的薪资直…

误删照片怎么办?恢复删除的图片,3个指南!

在我们的日常生活中&#xff0c;照片就像是我们的小秘密宝藏&#xff0c;记录着我们与亲朋好友一起嗨皮的时光&#xff0c;还有那些让我们激动不已的人生大事。可是&#xff0c;有时候我们可能会因为一时的疏忽&#xff0c;比如手滑点错了按钮&#xff0c;或者在清理手机内存时…

微软云计算Windows Azure(一)

目录 一、微软云计算平台二、微软云操作系统Windows Azure&#xff08;一&#xff09;Windows Azure概述&#xff08;二&#xff09;Windows Azure计算服务&#xff08;三&#xff09;Windows Azure存储服务&#xff08;四&#xff09;Windows Azure Connect&#xff08;五&…