【ThreeJS基础教程-高级几何体篇】2.1 纹理贴图入门

初识纹理Texture

先提前纠正一下纹理(Texture)和贴图(Map)不是一个东西

纹理一般是指贴图贴在模型表面之后,显示出来的样子,称为纹理,通常会由贴图来生成纹理

贴图的本质就是一张图片资源

如何生成一片草地

	    let geometry = new THREE.PlaneGeometry(10,10,10).rotateX(-Math.PI/2);
        let material = new THREE.MeshBasicMaterial({
            color:"#00ff00"
        });
        let mesh = new THREE.Mesh(geometry,material);
        scene.add(mesh);

在这里插入图片描述
上述方式虽然可以制作一块绿色的平面,但是这很难让人联想到这里是一块草地

这时候我们就需要借助纹理来生成草地了

    function addMesh(){

        let texture = new THREE.TextureLoader().load("./grass.jpg");

        let geometry = new THREE.PlaneGeometry(10,10,10).rotateX(-Math.PI/2);
        let material = new THREE.MeshBasicMaterial({
            map:texture
        });
        let mesh = new THREE.Mesh(geometry,material);
        scene.add(mesh);
    }

在这里插入图片描述
这样的草地是否显得更逼真一些呢?

Texture与TextureLoader

先在这里说明一下,官方的写法这里存在问题
在这里插入图片描述
上面的案例也是按照官方写法而写的,但是这种写法会存在一个问题,就是TextureLoader.load()是一个异步函数,当你的图片加载速度低于你使用纹理的速度时,就有可能会出现错误,尤其是当你要一次加载多个纹理时,或者你加载的贴图过于巨大时(极高分辨率的大型巨型图片),此时受网速影响加载纹理太慢时,就会出现这样的问题
这种错误一般是线上更容易发生,而在本地开发过程中几乎不会遇到

因此笔者建议从一开始接触纹理时,就使用下面的写法

    function addMesh(){
    	//创建纹理加载器
        let textureLoader = new THREE.TextureLoader();
        //加载器读取grass.jpg,加载完成时执行下面的函数
        textureLoader.load("./grass.jpg",(texture)=>{
            let geometry = new THREE.PlaneGeometry(10,10,10).rotateX(-Math.PI/2);
            let material = new THREE.MeshBasicMaterial({
                map:texture
            });
            let mesh = new THREE.Mesh(geometry,material);
            scene.add(mesh);
        });
        
    }

官方文档中的wrapS和warpT等暂时不在本篇讨论,后续将有一篇文章单独对纹理详细讲解

Texture官方文档
TextureLoader官方文档
关于Loader会在后续专门写一篇文章来详细讲解,本篇仅对纹理做基本介绍

函数:textureLoader.load(url : String, onLoad : Function, onProgress : Function, onError : Function );
url:图片路径
onLoad:资源全部加载完成时的回调函数
onProgress:在加载过程中调用,用于监控加载进度
onError:加载错误时回调

在前期的学习和开发中,笔者建议始终添加onError参数来监控加载情况,后续讲到模型加载时会再提这方面事宜

        let textureLoader = new THREE.TextureLoader();

        textureLoader.load("./gr2ass.jpg",(texture)=>{
            let geometry = new THREE.PlaneGeometry(10,10,10).rotateX(-Math.PI/2);
            let material = new THREE.MeshBasicMaterial({
                map:texture
            });
            let mesh = new THREE.Mesh(geometry,material);
            scene.add(mesh);
        },null,(error)=>{
            console.log(error);
        });

如果仅对一个文件做加载时,onProgress函数可以先写为null

在onLoad函数中,我们可以获取到加载完成的资源,textureLoader中,已经将生成好的纹理,以对象的方式返回给我们了,所以这里我们直接访问它即可

官方写法中,并没有使用()=>{}这样的箭头函数,这种写法容易造成this指向错误,所以这里笔者建议,从这里开始,每一个Load函数,都使用箭头函数,以免出现一些奇奇怪怪的问题

箭头函数为ES6的语法,不熟悉ES6的同学这时还可以去了解一下

当我们拿到了加载完成后的纹理后,将它作为值,传给Material的map属性

 let material = new THREE.MeshBasicMaterial({
                map:texture
            });

如果这里再添加Color属性的话,Color会覆盖当前加载出来的纹理颜色

这样我们的草地就被创建出来了

案例完整源码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        canvas{
            display: block;
        }
        body {
            margin: 0;
            overscroll-behavior: none;
        }
        #btns{
            position: absolute;
            top:10%;
            width: 500px;
            height: 100px;
            left: 50%;
            transform:translateX(-50%);
        }
    </style>
</head>
<body>
<div id="btns"></div>

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

<script type="importmap">
			{
				"imports": {
					"three": "../../three.js-master/build/three.module.js"
				}
			}
		</script>
<script type="module">
    import * as THREE from '../../three.js-master/build/three.module.js';
    import {OrbitControls} from "../../three.js-master/examples/jsm/controls/OrbitControls.js";

    let scene,renderer,camera,orbitControls;

    function init(){
        scene = new THREE.Scene();
        renderer = new THREE.WebGLRenderer({
            alpha:true,
            antialias:true
        });
        renderer.setSize(window.innerWidth,window.innerHeight);
        document.body.appendChild(renderer.domElement);
        camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);
        camera.position.set(10,10,10);
        orbitControls = new OrbitControls(camera,renderer.domElement);
        scene.add(new THREE.AmbientLight(0xffffff,1));
        let helper = new THREE.AxesHelper(5);
        scene.add(helper);
    }
    function addMesh(){


        let textureLoader = new THREE.TextureLoader();

        textureLoader.load("./grass.jpg",(texture)=>{
            let geometry = new THREE.PlaneGeometry(10,10,10).rotateX(-Math.PI/2);
            let material = new THREE.MeshBasicMaterial({
                map:texture
            });
            let mesh = new THREE.Mesh(geometry,material);
            scene.add(mesh);
        },null,(error)=>{
            console.log(error);
        });

    }
    function render(){
        renderer.render(scene,camera);
        requestAnimationFrame(render);
    }
    init();
    addMesh();
    render();
</script>
</body>
</html>

案例使用的图片文件,图片来源:three.js-master\examples\textures\terrain下的草地贴图
在这里插入图片描述

做一个简单的地球出来

上面我们学会了怎么使用纹理,那么,这次我们不再将纹理贴到plane上,贴到我们的球体Sphere上

地球的贴图素材three.js-master\examples\textures\planets,这里我们选用的素材是earth_atmos_2048.jpg

在这里插入图片描述
完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        canvas{
            display: block;
        }
        body {
            margin: 0;
            overscroll-behavior: none;
        }
        #btns{
            position: absolute;
            top:10%;
            width: 500px;
            height: 100px;
            left: 50%;
            transform:translateX(-50%);
        }
    </style>
</head>
<body>
<div id="btns"></div>

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

<script type="importmap">
			{
				"imports": {
					"three": "../../three.js-master/build/three.module.js"
				}
			}
		</script>
<script type="module">
    import * as THREE from '../../three.js-master/build/three.module.js';
    import {OrbitControls} from "../../three.js-master/examples/jsm/controls/OrbitControls.js";

    let scene,renderer,camera,orbitControls;

    function init(){
        scene = new THREE.Scene();
        renderer = new THREE.WebGLRenderer({
            antialias:true
        });
        renderer.setSize(window.innerWidth,window.innerHeight);
        document.body.appendChild(renderer.domElement);
        camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);
        camera.position.set(10,10,10);
        orbitControls = new OrbitControls(camera,renderer.domElement);

        let helper = new THREE.AxesHelper(5);
        scene.add(helper);

        let light = new THREE.PointLight();
        camera.add(light);
        scene.add(camera);
    }
    function addMesh(){

        let textureLoader = new THREE.TextureLoader();

        textureLoader.load("./earth_atmos_2048.jpg",(texture)=>{
            let geometry = new THREE.SphereGeometry(5,32,32);
            let material = new THREE.MeshStandardMaterial({
                map:texture
            });
            let mesh = new THREE.Mesh(geometry,material);
            scene.add(mesh);
        },null,(error)=>{
            console.log(error);
        });
    }
    function render(){
        renderer.render(scene,camera);
        requestAnimationFrame(render);
    }
    init();
    addMesh();
    render();
</script>
</body>
</html>

完整效果:
在这里插入图片描述
大多数知识点在前面已经解析完成,笔者在这里就不多做解释了

下一篇预告:加载模型

下一篇主要讲解主流的几种模型格式与Loader,以及加载管理器LoadingManager

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值