【ThreeJS基础教程-高级几何体篇】2.1更好的视觉效果-综合案例(2)

学习ThreeJS的捷径

本段内容会写在0篇以外所有的,本人所编写的Threejs教程中

对,学习ThreeJS有捷径
当你有哪个函数不懂的时候,第一时间去翻一翻文档
当你有哪个效果不会做的时候,第一时间去翻一翻所有的案例,也许就能找到你想要的效果
最重要的一点,就是,绝对不要怕问问题,越怕找找别人问题,你的问题就会被拖的越久

如果你确定要走WebGL/ThreeJS的开发者路线的话,以下行为可以让你更快的学习ThreeJS

  1. 没事就把所有的文档翻一遍,哪怕看不懂,也要留个印象,至少要知道Threejs有什么
  2. 没事多看看案例效果,当你记忆的案例效果足够多时,下次再遇到相似问题时,你就有可能第一时间来找对应的案例,能更快解决你自己的问题
  3. 上述案例不只是官网的案例,郭隆邦技术博客,跃焱邵隼,暮志未晚等站点均有不少优质案例,记得一并收藏
    http://www.yanhuangxueyuan.com/ 郭隆邦技术博客
    https://www.wellyyss.cn/ 跃焱邵隼
    http://www.wjceo.com/ 暮志未晚
    这三个站点是我最常逛的站点,推荐各位有事没事逛一下,看看他们的案例和写法思路,绝对没坏处

初识纹理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
    评论
对整threeJS体系进行全面剖析。整理出全面的教学大纲,涵盖内容面非常广。此教学版本为threeJS107版本。关于版本不建议大家使用低于90的版本学习。以下是课程目录1-ThreeJS概览(基本图形简介,什么是点线面如何绘制点线面,什么是材质,什么是几何体,什么是相机,什么是渲染器,什么是场景)2-相机和渲染器(详解相机类型,渲染器如何使用,针对不同场景怎么用,怎么调效果,怎么渲染,怎么输出画布,如何解决透明问题等等)3-创建平面几何(常见的几何体如何使用,如何使用简单的几何体绘制出自定义自己想要的几何体,关于几何体的性能剖析,如何解决性能,几何体的渲染原理)4-高级图形算法常见库(求直线的斜率  计算线段与圆的交点 计算线段的长度 判断折线是否在多边形内 等等)5-sprite精灵(怎么让一个图标永远朝向屏幕,精灵的属性,精灵材质原理等,广告提示框必用)6-骨骼游戏动画(什么是模型动画,常见游戏案例,如何让人头进行各种攻击动作)7-3d模型加载(常见模型格式,如何渲染不同格式,不同格式的特点,什么格式性能优越,模型渲染异常,贴图不显示等问题详解)8-高阶动态纹理(你所不知道的纹理用法,我说你不知道,你肯定不知道)9-漫游轨迹以及其动画路径(怎么绘制贝塞尔曲线,如何使用曲线上的路径,跟随路径移动的原理,相机如何运动,物体如何运动)10-着色器(什么是着色器。初识着色器基础,着色器材质怎么用,怎么使用着色器库)11-常见渲染以及透明度问题12-对象拾取以及拖拽(3d世界里面如何拖拽物体,拖拽的原理,mousemove mouseon等的事件效果)13-世界坐标以及组的问题(什么是相对坐标,什么是世界坐标,什么是当前坐标,怎么转化父子坐标系,组的优化,为什么用组,组的优势)14-指定对象旋转中心(什么是物体的几何体中心,如何改变中心,如何绕轴转动)15-层级对象渲染(多个场景一键切换,切换的优势,针对大项目的用法)16-拓展了解系列(不定期不断更新案例,各种酷炫效果bloom,halo等,以及各种3d图表,粒子案例等,不断构建你的3d实践能力)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值