three.js第一个3D案例

在正式学习Three.js之前,先做一些必要的准备工作,具体说就是下载threejs官方文件包 ,threejs官方文件包提供了很多有用的学习资源

threejs官方文件包所有版本:https://github.com/mrdoob/three.js/releases

threejs文件资源目录介绍

对于开发者而言,大家经常接触的是文档docs案例examples 两个文件夹,平时查看文档,可以打开文档docs 里面html文件,案例examples里面提供了海量threejs功能案例。

复制代码
three.js-文件包
└───build------three.js相关库,可以引入你的.html文件中。
    │
└───docs------Three.js API文档文件
    │───index.html------打开该文件,本地离线方式预览threejs文档
└───examples------大量的3D案例,是你平时开发参考学习的最佳资源
    │───jsm------threejs各种功能扩展库
└───src------Three.js引擎的源码,有兴趣可以阅读。
    │
└───editor------Three.js的可视化编辑器,可以编辑3D场景
    │───index.html------打开应用程序  

工欲善其事,必先利其器

Web3D开发的代码编辑器和平时web前端开发一样,你可以根据自己的喜好选择,本课程选择的代码编辑器是 vscode

本地静态服务器

如果你想预览代码3D效果 ,咱们需要提供一个本地静态服务器的开发环境,正式的web项目开发,往往会用webpack或vite或其它方式配置一个开发环境。

如果只是学习threejs的话,可通过代码编辑器 快速创建本地静态服务器 ,比如vsocde,安装live-server插件即可。或者使用phpstudy, 下载下来直接给下载的three.js包放在www目录里面,创建自己的HTML文件,引入three.js,就可以学习了

vscode配置live-server插件

  • 安装: vscode软件界面左侧,点击扩展 ,输入live-server关键词查询安装。
  • 使用:如果你想预览代码3D效果 ,打开对应.html文件,右键点击Open with Live Server即可。
预览3D案例和文档

打开课件案例,注意把Three.js视频教程源码文件作为根目录,使用vscode创建本地静态服务就可以预览。

复制代码
three.js-文件包
...
└───docs------Three.js API文档文件
    │───index.html------打开该文件,本地离线方式预览threejs文档
└───examples------大量的3D案例,是你平时开发参考学习的最佳资源
    │───.html------各种3D案例
...    

script标签方式引入three.js

通过script标签把three.js当做一个js库引入你的项目。three.js库可以在threejs官方文件包下面的build目录获取到。

javascript 复制代码
<script src="./build/three.js"></script>

console.log(THREE.Scene); 

ES6 import方式引入

给script标签设置type="module",也可以在.html文件中使用import方式引入three.js。

javascript 复制代码
<script type="module">
// 现在浏览器支持ES6语法,自然包括import方式引入js文件
import * as THREE from './build/three.module.js';
</script>

type="importmap"配置路径

通过配置<script type="importmap">,实现学习环境.html文件和vue或reaact脚手架开发环境一样的写法。这样你实际项目的开发环境复制课程源码,不用改变threejs引入代码。

下面配置的type="importmap"代码具体写法不用掌握记忆,复制粘贴后,能修改目录就行,

javascript 复制代码
<!-- 具体路径配置,你根据自己文件目录设置,我的是课件中源码形式 -->
<script type="importmap">
    {
		"imports": {
			"three": "../../../three.js/build/three.module.js"
		}
	}
</script>

<!-- 配置type="importmap",.html文件也能和项目开发环境一样方式引入threejs -->
<script type="module">
    import * as THREE from 'three';
    // 浏览器控制台测试,是否引入成功
    console.log(THREE.Scene);
</script>

type="importmap"配置------扩展库引入

通过配置<script type="importmap">,让学习环境.html文件,也能和vue或react开发环境中一样方式方式引入threejs扩展库。

javascript 复制代码
<script type="importmap">
    {
		"imports": {
			"three": "./three.js/build/three.module.js",
            "three/addons/": "./three.js/examples/jsm/"
		}
	}
</script>

<script type="module">
    // three/addons/路径之后对应的是three.js官方文件包`/examples/jsm/`中的js库
    // 扩展库OrbitControls.js
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
    // 扩展库GLTFLoader.js
    import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
    console.log(OrbitControls);
    console.log(GLTFLoader);
</script>

配置**addons/** 等价于**examples/jsm/**。

项目的开发环境引入threejs

比如你采用的是Vue + threejsReact + threejs 技术栈,这很简单,threejs就是一个js库,直接通过npm命令行安装就行。

javascript 复制代码
// 比如安装148版本
npm install [email protected] --save

//执行import * as THREE from 'three';ES6语法引入three.js核心。

// 引入three.js
import * as THREE from 'three';

npm安装后,如何引入three.js其他扩展库

了three.js核心库以外,在threejs文件包中examples/jsm目录下,你还可以看到各种不同功能的扩展库。一般来说,你项目用到那个扩展库,就引入那个,用不到就不需要引入。

javascript 复制代码
// 引入扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入扩展库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

前期准备工作准备好后,我们就可以开始创建自己的第一个3D场景案例了。

入门Three.js的第一步,就是认识场景Scene相机Camera渲染器Renderer三个基本概念

三维场景Scene

你可以把三维场景Scene (opens new window)对象理解为虚拟的3D场景,用来表示模拟生活中的真实三维场景,或者说三维世界。

javascript 复制代码
// 创建3D场景对象Scene
const scene = new THREE.Scene();

物体形状:几何体Geometry

Three.js提供了各种各样的几何体API,用来表示三维物体的几何形状。

javascript 复制代码
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(200, 200, 200); 

物体外观:材质Material

如果你想定义物体的外观效果,比如颜色,就需要通过**材质Material**相关的API实现。

threejs不同材质渲染效果不同,下面就以threejs最简单的网格基础材质 MeshBasicMaterial为例实现一个蓝色材质效果。

javascript 复制代码
//创建一个材质对象Material
const material = new THREE.MeshBasicMaterial({
    color: 0x00ff00,//0x00ff00设置材质颜色为蓝色
}); 

物体:网格模型Mesh

在threejs中可以通过网格模型 Mesh表示一个虚拟的物体,比如一个电脑等。

javascript 复制代码
// 两个参数分别为几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh

模型位置.position

实际生活中,一个物体往往是有位置的,对于threejs而言也是一样的,你可以通过位置属性.position定义网格模型Mesh在三维场景Scene中的位置。

javascript 复制代码
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0,10,0);

在threejs中你创建了一个表示物体的虚拟对象Mesh,需要通过.add()方法,把网格模型mesh添加到三维场景scene中。

javascript 复制代码
scene.add(mesh); 

透视投影相机PerspectiveCamera

Threejs如果想把三维场景Scene渲染到web网页上,还需要定义一个虚拟相机 Camera,就像你生活中想获得一张照片,需要一台用来拍照的相机。

Threejs提供了正投影相机OrthographicCamera和透视投影相机PerspectiveCamera

透视投影相机PerspectiveCamera 本质上就是在模拟人眼观察这个世界的规律

javascript 复制代码
// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera();

相机位置.position

相机对象Camera具有位置属性.position,通过位置属性.position可以设置相机的位置。

javascript 复制代码
//相机在Three.js三维坐标系中的位置
// 根据需要设置相机位置具体值
camera.position.set(200, 100, 400); 

相机观察目标.lookAt()

你用相机拍照你需要控制相机的拍照目标 ,具体说相机镜头对准哪个物体或说哪个坐标。对于threejs相机而言,就是设置.lookAt()方法的参数,指定一个3D坐标。

javascript 复制代码
//相机观察目标指向Threejs 3D空间中某个位置
camera.lookAt(0, 0, 0); //坐标原点

camera.lookAt(0, 10, 0);  //y轴上位置10


camera.lookAt(mesh.position);//指向mesh对应的位置

判断相机相对三维场景中长方体位置

你可以把三维场景中长方体mesh想象为一个房间,然后根据相机位置和长方体位置尺寸对比,判断两者相对位置。你可以发现设置相机坐标(200, 200, 200),位于长方体外面一处位置。

javascript 复制代码
// 长方体尺寸100, 100, 100
const geometry = new THREE.BoxGeometry( 100, 100, 100 );
const mesh = new THREE.Mesh(geometry,material);
// 网格模型位置xyz坐标:0,10,0
mesh.position.set(0,10,0);
// 相机位置xyz坐标:200, 200, 200
camera.position.set(200, 200, 200); 

定义相机渲染输出的画布尺寸

Canvas画布 :课程中会把threejs虚拟相机渲染三维场景在浏览器网页上呈现的结果称为Canvas画布

javascript 复制代码
// 定义相机输出画布的尺寸(单位:像素px)
const width = 800; //宽度
const height = 500; //高度

透视投影相机PerspectiveCamera:视锥体

透视投影相机的四个参数fov, aspect, near, far构成一个四棱台 3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上。

javascript 复制代码
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = 800; //宽度
const height = 500; //高度
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
javascript 复制代码
PerspectiveCamera( fov, aspect, near, far )

//参数	含义	                            默认值
fov	    相机视锥体竖直方向视野角度。	        50

aspect	相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比。 width / height	1

near	相机视锥体近裁截面相对相机距离	。        0.1

far	    相机视锥体远裁截面相对相机距离,far-near构成了视锥体高度方向。	2000

WebGL渲染器WebGLRenderer

通过WebGL渲染器WebGLRenderer可以实例化一个WebGL渲染器对象

javascript 复制代码
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();

设置Canvas画布尺寸.setSize()

javascript 复制代码
// 定义threejs输出画布的尺寸(单位:像素px)
const width = 1000; //宽度
const height = 500; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)

渲染器渲染方法.render()

渲染器**WebGLRenderer** 执行渲染方法**.render()** 就可以生成一个Canvas画布(照片),并把三维场景Scene 呈现在canvas 画布上面,你可以把**.render()**

javascript 复制代码
renderer.render(scene, camera); //执行渲染操作

渲染器Canvas画布属性.domElement

渲染器**WebGLRenderer** 通过属性**.domElement** 可以获得渲染方法**.render()** 生成的Canvas画布,**.domElement**本质上就是一个HTML元素:Canvas画布。

javascript 复制代码
document.body.appendChild(renderer.domElement);

到这里我们就可以创建了一个自己的3D场景第一个案例了,Canvas画布插入到任意HTML元素中

javascript 复制代码
<div id="webgl" style="margin-top: 200px;margin-left: 100px;"></div>

document.getElementById('webgl').appendChild(renderer.domElement);

轨道控制器

在 ThreeJS 中使用轨道控制器后,你可以通过长按鼠标左键并拖动鼠标来控制摄像头所处的位置。

javascript 复制代码
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

// 用法
const orbitControls = new OrbitControls(camera, renderer.domElement);
javascript 复制代码
<div class="first" id="myFirst"></div>
  <script type="importmap">
    {
      "imports": {
        "three": "./js/three.module.js",
        "three/jsm/": "./js/jsm/"
      }
    }
  </script>
  <script type="module">
    import * as THREE from 'three';
    import { OrbitControls } from './js/jsm/controls/OrbitControls.js'; // 引入相机控件
    // three内置了 gui工具 我们先进行一个导入 允许我们动态的对于一些参数进行设置方便我们预览效果
    import { GUI } from './js/jsm/libs/lil-gui.module.min.js';
    //3D场景对象Scene
    const scene = new THREE.Scene();
    //创建一个长方体几何体
    const geometry = new THREE.BoxGeometry(2,4,1);
    //创建一个材质对象Material MeshBasicMaterial  不受光照影响
    const material = new THREE.MeshBasicMaterial({
      color: 0xff0000, //0xff0000设置材质颜色为红色
      transparent: true,
      opacity: 0.5,
    });
    //网格模型对象Mesh
    const mesh = new THREE.Mesh(geometry, material);
    // 添加到场景中去
    scene.add(mesh);

    let myFirst = document.getElementById("myFirst");
    // 实例化一个透视投影相机对象 PerspectiveCamera
    const camera = new THREE.PerspectiveCamera(75, myFirst.offsetWidth / myFirst.offsetHeight, 0.1, 1000);
    camera.position.z = 15;
    camera.position.x = 5;
    camera.position.y = 2;
    //camera.lookAt(-100, 100, 10); //坐标原点

    // 创建渲染器 WebGLRenderer
    const renderer = new THREE.WebGLRenderer({
      //lpha: true, // 背景是否可以设置透明色
      antialias: true, // 表示是否开启反锯齿
    });
    // AxesHelper:辅助观察的坐标系
    const axesHelper = new THREE.AxesHelper(150)
    scene.add(axesHelper)

    // 网格辅助线  第一个值是长度   第二个值是分割的段数
    const gridHelper = new THREE.GridHelper(10,10);
    scene.add(gridHelper)

    // 输出画布的尺寸
    
    renderer.setSize(myFirst.offsetWidth, myFirst.offsetHeight); // 设置渲染大小
    // 渲染到元素中
    myFirst.appendChild(renderer.domElement);
    //  相机控制控制的就是相机的postion的位置而在界面当中出现不同的几何体的观察形态
    const controls = new OrbitControls(camera, renderer.domElement);
    // addEventListener
    controls.addEventListener('change', ()=>{
      renderer.render(scene, camera)
    })

    // 创建一个GUI实例
    const gui = new GUI();
    // cube的位置
    const originPositon = {
      x: 0,
      y: 0,
      z: 0
    };
    // camera的位置
    const cameraPosition = {
      x: 0,
      y: 0,
      z: 5
    };
    // 创建第一个 gui的参数分组   几何体位置
    const cubeParams = gui.addFolder('几何体位置');
    cubeParams.add(originPositon, 'x', 0, 100).onChange(val => {
      cube.position.x = val;
      renderer.render(scene, camera)
    });
    cubeParams.add(originPositon, 'y', 0, 100).onChange(val => {
      cube.position.y = val;
      renderer.render(scene, camera)
    });

    //  相机位置的分组
    const cameraParams = gui.addFolder('相机的位置')
    // add(对象,属性名,数值)  生成的是一个数字输入框的交互
    // add(对象,属性名,数值1,数值2) 生成的是一个有可选范围的数字选择框
    cameraParams.add(cameraPosition, 'x', -5, 50).onChange(val => {
      camera.position.x = val;
      renderer.render(scene, camera)
    })
    cameraParams.add(cameraPosition, 'y', -5, 50).onChange(val => {
      camera.position.y = val;
      renderer.render(scene, camera)
    })
    // add(对象,属性名,数组)  会自动生成一个下拉菜单的交互界面
    //   cameraParams.add(cameraPosition,'x' ,[1,3,6]).onChange(val=>{
    //     camera.position.x = val;
    //     renderer.render(scene, camera) 
    //  })
    // add( 对象,属性名, 对象 ) 也会生成一下下拉菜单的交互方式
    // cameraParams.add(cameraPosition,'x' ,{
    //     param1: 1,
    //     param2: 5
    // }).onChange(val=>{
    //     camera.position.x = val;
    //     renderer.render(scene, camera) 
    //  })
    const testObj = {
        color: 0xff6600,
        val1: 10
    }
    // addColor 在gui当中添加一个 颜色选择器的交互 
    gui.addColor(testObj, 'color').onChange(val => {
      console.log('颜色的值', val)
    })
    // add()的其他后续的方法
    // .name(直接展示为参数的指定名称 方便理解)
    // .step(步进的数量) 每一个变化的最小单位
    gui.add(testObj, 'val1', 0, 100).name('某个值的大小').step(1)
    renderer.render(scene, camera)
  </script>

案例实际效果:

相关推荐
zhougl9962 小时前
html处理Base文件流
linux·前端·html
花花鱼2 小时前
node-modules-inspector 可视化node_modules
前端·javascript·vue.js
HBR666_2 小时前
marked库(高效将 Markdown 转换为 HTML 的利器)
前端·markdown
careybobo3 小时前
海康摄像头通过Web插件进行预览播放和控制
前端
TDengine (老段)4 小时前
TDengine 中的关联查询
大数据·javascript·网络·物联网·时序数据库·tdengine·iotdb
杉之5 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
喝拿铁写前端5 小时前
字段聚类,到底有什么用?——从系统混乱到结构认知的第一步
前端
再学一点就睡5 小时前
大文件上传之切片上传以及开发全流程之前端篇
前端·javascript
木木黄木木6 小时前
html5炫酷图片悬停效果实现详解
前端·html·html5
请来次降维打击!!!7 小时前
优选算法系列(5.位运算)
java·前端·c++·算法