three.js初探

关于Three.js

  • Three.js是基于原生WebGL封装运行的三维引擎,WebGL只能绘制点、线和三角形;Three.js封装了诸如场景、灯光、阴影、材质、贴图、空间运算等一系列功能,相对于WebGL方便简单了不少。

  • 建立基本场景 在Three.js中有三要素:场景、摄像机和渲染器,我们创建好场景(Scene)和一个摄像机(Camera)渲染器(Renderer)中就可以渲染三维维场景渲染成一个二维图片显示在画布上。

相关文档

  • THREE.JS 教程:https://threejsfundamentals.org/threejs/lessons/zh_cn/
  • 官方文档 https://threejs.org/docs/index.html#manual/zh/introduction/Creating-a-scene
  • 郭隆邦技术博客 http://www.yanhuangxueyuan.com/

创建一个简单的场景

下载three.js

npm i three
<template>
    <canvas width="500"   height="500" ref="threeCanvas" ></canvas>
</template>
<script>
import { defineComponent, ref, onMounted } from 'vue';
import * as THREE from 'three';
export default defineComponent({
    setup() {
        let threeCanvas = ref(null); //canvas
        let renderer, //渲染器
            scene, //场景
            camera, //相机
            mesh; //几何体
        function init() {
            /***********创建渲染器对象***************/
            renderer = new THREE.WebGLRenderer({
                canvas: threeCanvas.value
            });
            renderer.setClearColor('#fff');
            /*********** 创建场景对象Scene**************/
            scene = new THREE.Scene();
            /*************创建网格模型**************/
            const geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry
            const material = new THREE.MeshLambertMaterial({
                color: 0x0000ff
            }); //材质对象Material
            mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
            scene.add(mesh); //网格模型添加到场景中
            /*************设置光源*******************/
            //点光源
            let point = new THREE.PointLight(0xffffff);
            point.position.set(400, 200, 300); //点光源位置
            scene.add(point); //点光源添加到场景中
            //环境光
            let ambient = new THREE.AmbientLight(0x444444);
            scene.add(ambient);
            /*************相机设置*******************/
            //创建相机对象
            camera = new THREE.PerspectiveCamera(60, 500 / 500, 1, 1000);
            camera.position.set(200, 300, 200); //设置相机位置
            camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
            //执行渲染方法
            render();
        }
        function render() {
            //执行渲染操作   指定场景、相机作为参数
            renderer.render(scene, camera);
        }
        onMounted(() => {
            init();
        });
        return {
            threeCanvas
        };
    }
});
</script>

<style lang="scss" scoped>
</style>

绘制出一个立方体

在这里插入图片描述

几何体的本质

几何体本质上就是一系列的顶点构成的,每三个点构成一个三角形平面
在这里插入图片描述

几何变换(缩放、平移、旋转)

缩放

立方体网格模型x轴方向放大2倍,如果连续执行两次该语句,相等于比原来方法4倍

mesh.scale.x 设置轴方向的缩放 ;y轴和z轴的缩放类似

    mesh.scale.x = 2.0;//x轴方向放大2倍    

立方体网格模型整体缩小0.5倍,相当于xyz三个方向分别缩小0.5倍

    mesh.scale.set(0.5,0.5,0.5);//缩小为原来0.5倍
平移

立方体网格模型沿着x轴正方向平移100,可以多次执行该语句,每次执行都是相对上一次的位置进行平移变换

     mesh.translateX(100);//沿着x轴正方向平移距离100

网格模型沿着向量(0,1,0)表示的方向平移100

    const axis = new THREE.Vector3(0,1,0);//向量axis
    mesh.translateOnAxis(axis,100);//沿着axis轴表示方向平移100
旋转

立方体网格模型绕立方体的x轴旋转π/4,可以多次执行该语句,每次执行都是相对上一次的角度进行旋转变化

    mesh.rotateX(Math.PI/4);//绕x轴旋转π/4

网格模型绕(0,1,0)向量表示的轴旋转π/8

    var axis = new THREE.Vector3(0,1,0);//向量axis
    mesh.rotateOnAxis(axis,Math.PI/8);//绕axis轴旋转π/8

旋转动画

设置一个定时器 去一直旋转集合体,如果要实现一个60帧的动画,时间间隔应为1000/60

修改渲染方法使用定时器进行旋转

function render() {
      //执行渲染操作   指定场景、相机作为参数
      renderer.render(scene, camera);
      setInterval(() => {
            mesh.rotateY(Math.PI / 100); //每次旋转Π/100*
       }, 1000 / 60);
   }

在这里插入图片描述

由于画面一直停留在第一帧所以我们正方体并没有旋转,我们需要在旋转后重新渲染

setInterval(() => {
      mesh.rotateY(Math.PI/ 100);*//每次旋转Π/100*
      renderer.render(scene, camera);
}, 1000 / 60);
requestAnimationFrame
  • requestAnimationFrame()调用一个函数一般默认保持60FPS的频率无限执行

  • requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。

  • 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。

    requestAnimationFrame比setInterval更好,所以可以使用requestAnimationFrame实现60帧渲染

     function render() {
          //执行渲染操作   指定场景、相机作为参数
          renderer.render(scene, camera);
          mesh.rotateY(Math.PI / 100); //每次旋转Π/100*
          requestAnimationFrame(render); //请求再次执行渲染函数render
     }
    

坐标

世界坐标系和本地坐标
  • 世界坐标系就是整个场景的坐标系

  • 本地坐标系是物体的坐标,在物体中心点。

辅助坐标

创建一个辅助坐标添加到场景中,会在场景中显示世界坐标系以共开发时使用

let axisHelper = new THREE.AxesHelper(2000);
scene.add(axisHelper);

在这里插入图片描述

鼠标操作三维场景

OrbitControls.js控件支持鼠标左中右键操作和键盘方向键操作

场景操作
  • 缩放:滚动—鼠标中键
  • 旋转:拖动—鼠标左键
  • 平移:拖动—鼠标右键
使用

引入

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

在render最后加上

 new OrbitControls(camera, renderer.domElement); //创建控件对象

OrbitControls会根据鼠标的动作对相机的参数进行改变

如果要键盘操作只需要定义键盘监听事件然后操作三维场景

window.addEventListener('keydown',function(e){
    console.log(e);
}); 

材质

在创建立方体是我们创建的Lambert网格材质只设置了颜色

 const material = new THREE.MeshLambertMaterial({
      color: 0x0000ff
 }); //材质对象Material

当然还有其他设置项

材质常见属性
材质属性简介
color材质颜色,比如蓝色0x0000ff
wireframe将几何图形渲染为线框。 默认值为false
opacity透明度设置,0表示完全透明,1表示完全不透明
transparent是否开启透明,默认false
map贴图

three.js提供的材质

材质类型功能
MeshBasicMaterial基础网格材质,不受光照影响的材质
MeshLambertMaterialLambert网格材质,与光照有反应,漫反射
MeshPhongMaterial高光Phong材质,与光照有反应
MeshStandardMaterialPBR物理材质,相比较高光Phong材质可以更好的模拟金属、玻璃等效果

纹理贴图

three.js可以使用**图片Canvas画布视频**作为贴图

图片作为贴图

通过纹理贴图加载器TextureLoaderload()方法加载一张图片可以返回一个纹理对象Texture,纹理对象Texture可以作为模型材质颜色贴图.map属性的值。

修改创建几何体的代码创建一个球体并使用一张世界地图作为贴图

行星素材 http://planetpixelemporium.com/mercury.html

在这里插入图片描述

  /*************创建网格模型**************/
            const geometry = new THREE.SphereGeometry(50, 100, 100); // 球体
            const textureLoader = new THREE.TextureLoader(); // 纹理贴图加载器
            textureLoader.load(require('@/assets/image/world_500x250.jpg'), (texture) => {
                const material = new THREE.MeshLambertMaterial({
                    map: texture,
                    transparent: true,
                    opacity: 1
                });
                mesh = new THREE.Mesh(geometry, material);
                scene.add(mesh);
                //执行渲染方法
                render();
            });
 /*************设置光源*******************/

球体表面使用世界地图作为贴图可以实现一个地球
在这里插入图片描述

Canvas画布作为贴图

创建canvas并绘制文字使用THREE.CanvasTexture转为贴图

function  canvasText(text) {
            //创建一个canvas
            let canvas = document.createElement('canvas');
            canvas.style = 'z-index:99';
            canvas.width = 50;
            canvas.height = 30;
            let ctx = canvas.getContext('2d');
            //透明背景
            ctx.fillStyle = 'rgba(255, 255, 255, 255)';
            // 矩形区域填充背景
            ctx.fillRect(0, 0, 50, 30);
            // 文字
            ctx.beginPath();
            ctx.translate(25, 5);
            ctx.fillStyle = '#3387DB'; //文本填充颜色
            ctx.font = '900 12px impact'; //字体样式设置
            ctx.textBaseline = 'middle'; //文本与fillText定义的纵坐标
            ctx.textAlign = 'center'; //文本居中(以fillText定义的横坐标)
            ctx.fillText(text, 0, 0);
            // canvas画布对象作为CanvasTexture的参数重建一个纹理对象
            // canvas画布可以理解为一张图片
            let texture = new THREE.CanvasTexture(canvas);
            return texture;
 }

将材质 map设置为Canvas 在代码最后执行render();

/*************创建网格模型**************/
            const geometry = new THREE.SphereGeometry(50, 100, 100); // 球体
            const textureLoader = new THREE.TextureLoader(); // 纹理贴图
            let texture = canvasText('我是地球');
            const material = new THREE.MeshLambertMaterial({
                map: texture,
                transparent: true,
                opacity: 1
            });
            mesh = new THREE.Mesh(geometry, material);
            scene.add(mesh);
 /*************设置光源*******************/

在这里插入图片描述

视频作为贴图
// 创建video对象
let video = document.createElement('video');
video.src = "视频.mp4"; // 设置视频地址
video.autoplay = "autoplay"; //要设置播放
// video对象作为VideoTexture参数创建纹理对象
let texture = new THREE.VideoTexture(video)

将 texture 给材质的map

精灵模型

精灵模型相当于一个平面矩形几何体,同时精灵模型的矩形平面会始终平行于Canvas画布。

创建一个精灵模型并且添加到地球中

            /******************精灵模型*****************/
            // 创建精灵材质对象SpriteMaterial
            let spriteMaterial = new THREE.SpriteMaterial({
                color: 0xff00ff, //设置精灵矩形区域颜色
                rotation: Math.PI / 4, //旋转精灵对象45度,弧度值
                map: texture //设置精灵纹理贴图
            });
            // 创建精灵模型对象,不需要几何体geometry参数
            let sprite = new THREE.Sprite(spriteMaterial);
            // 控制精灵大小,比如可视化中精灵大小表征数据大小
            sprite.scale.set(30, 30, 1);  只需要设置x、y两个分量就可以
            sprite.position.set(100, 100, 100); //设置精灵模型位置
            mesh.add(sprite);//添加到mesh(地球)中
            /*************相机设置*******************/

精灵模型跟随地球转动,且精灵模型始终平行于Canvas平面

在这里插入图片描述

导出模型

直接将几何体转化为JSON

            const geometry = new THREE.SphereGeometry(50, 100, 100); // 球体
            console.log(JSON.stringify(geometry));

导入导出的json

let loader = new THREE.FileLoader();
loader.load('material.json', function (elem) {
    console.log(elem); // 查看加载返回的内容
    let obj = JSON.parse(elem); // 字符串转JSON对象
});

加载外部模型

three.js可任意导入3D使用3D软件建好的模型(包括模型,贴图和动画) (stl、obj、fbx等文件)

  • OBJ是一种3D模型文件,因此不包含动画、材质特性、贴图路径、动力学、粒子等信息。

  • MTL文件则是 obj附属文件,用以描述几何体的表面描影属性,obj的贴图

  • stl、obj都是静态模型,不可以包含动画,

  • fbx除了包含几何、材质信息,可以存储骨骼动画等数据。

3D素材 https://free3d.com/zh/3d-models/obj

vue项目中obj等3D文件必须放在静态资源(static)要不然加载不出来

  • 在vue中存放obj模型必须要放在静态资源(static)文件下,否则会出错。
  • 由于4.x版本的vue没有static这个文件夹,但是他的静态资源文件夹是叫public,这样我在public下面创建一个文件夹叫static,再在static文件夹下存放的我的obj模型文件以及mtl文件。
    在这里插入图片描述

引入 加载器

加载器在three/examples/jsm/loaders目录下

import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js';

在这里插入图片描述

使用 OBJLoader 加载obj模型文件添加到场景中

   /*************加载外部模型****************/
            const objLoader = new OBJLoader(); //obj加载器
            const mtlLoader = new MTLLoader(); //mtl加载器
            //加载mtl材质
            mtlLoader.load('/static/low_poly_tree/Lowpoly_tree_sample.mtl', (materials) => {
                //obj的模型会和MaterialCreator包含的材质对应起来
                objLoader.setMaterials(materials);
                //加载obj模型
                objLoader.load('/static/low_poly_tree/Lowpoly_tree_sample.obj', (obj) => {
                    mesh = obj;
                    //返回的组对象插入场景中
                    scene.add(obj); 
                    //执行渲染
                    render();
                });
            });
 /*************设置光源*******************/

在这里插入图片描述

雾化效果

场景scene对象的fog属性用于设置雾化效果

雾有两种 分别是:线性雾(Fog()),和指数雾(FogExp2()).

线性雾(Fog())

雾化效果成线性增长

new THREE.Fog( hex, near, far);

参数:hex:雾的颜色,near:场景添加雾的最小距离,far:雾化效果的截止距离。

定义0xffffff颜色的雾 设置雾的最小距离120 雾化效果的截止距离 150

 // 定义线性雾,密度随着距离的增加而线性增长
 scene.fog = new THREE.Fog(0xffffff, 120, 150);
指数雾(FogExp2()).

雾随着距离呈指数增长的雾化效果,只需要设置雾的颜色和浓度即可

scene.fog = new THREE.FogExp2(0xffffff,0.02);

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值