likes
comments
collection
share

从0开始学习Three.js | 大帅老猿threejs特训

作者站长头像
站长
· 阅读数 14

一、Three.js 简介

提到 Three.js,不得不先提 OpenGL 和 WebGL,OpenGL 是一个跨平台的3D/2D的绘图标准(规范),WebGL(Web Graphics Library)是一种3D绘图协议。

WebGL允许把JavaScript和OpenGL 结合在一起运用,但使用WebGL原生的API来写3D程序非常的复杂,同时需要相对较多的数学知识,对于开发者来说学习成本非常高。

Three.js是基于webGL的封装的一个易于使用且轻量级的3D库,Three.js对WebGL提供的接口进行了非常好的封装,简化了很多细节,大大降低了学习成本,极大地提高了性能,功能也非常强大。

(1)Three.js官网

(2)Three.js 的 github 地址

二、起步阶段先从简单开始,直接引用 Three.js,学会最基本的 Three.js 的使用方法

<!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>
</head>
<body>
  <script src="js/three.min.js"></script>
  <script>
    // 创建场景
    const scene = new THREE.Scene(); 
    // 创建相机,PerspectiveCamera(透视相机),参数(视野角度,长宽比,进截面,远截面)
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); 
    // 渲染器
    const renderer = new THREE.WebGLRenderer();
    // 设置渲染器的宽高
    renderer.setSize( window.innerWidth, window.innerHeight );
    // 将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中
    document.body.appendChild( renderer.domElement );

    // demo--立方体
    const geometry = new THREE.BoxGeometry( 1, 1, 1 ); // BoxGeometry 立方体对象
    const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );  // MeshBasicMaterial 其中的一种材质,设置颜色绿色
    const cube = new THREE.Mesh( geometry, material ); // 创立一个网格对象
    scene.add( cube ); // 将网格对象添加到场景中
    camera.position.z = 5; 
    
    // 
    function animate() {
      requestAnimationFrame( animate ); // 创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循
      cube.rotation.x += 0.01; // 使正方体能动起来
      cube.rotation.y += 0.01; // 使正方体能动起来
      renderer.render( scene, camera ); 
    }
    animate();
  </script>
</body>
</html>

以上代码可以直接运行,运行的效果如下从0开始学习Three.js | 大帅老猿threejs特训

三、使用 npm 来开发并测试

(1)获取项目代码,项目的git地址(2)安装依赖

npm install

(3)开发主要代码 day01.js

// 引入
import * as THREE from 'three';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';

// 基础场景三大件
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 10);
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

// 加灯光
const ambientLight = new THREE.AmbientLight(0xffffff,0.5);
scene.add(ambientLight);

// 创建一个盒子
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const boxMesh = new THREE.Mesh( geometry, material );
scene.add( boxMesh );


function animate() {
  requestAnimationFrame( animate );
  renderer.render( scene, camera ); 
}
animate();

(4)执行 npm run start ,打开 http://localhost:3000/,目前看到的是一片黑色,并未看到盒子展示出来,原因是因为相机的的位置是处在盒子的中心点,此时需要设置相机的位置。

camera.position.set(0.6,0.6,1);

(5)此时目标还不能拖动,需要加上轨道控制器,使得相机围绕目标进行轨道运动,就能看到目标的立体图像了

const controls = new OrbitControls( camera, renderer.domElement );

(6)加载模型,并加入动画播放

new GLTFLoader().load('../resources/donuts.glb',(gltf)=>{
  scene.add(gltf.scene);
  
  mixer = new THREE.AnimationMixer(gltf.scene); //AnimationMixer(动画混合器)
  const clips = gltf.animations; // 播放所有动画
  clips.forEach(function (clip) {
    const action = mixer.clipAction(clip);
    action.loop = THREE.LoopOnce;
    action.play();
    // 停在最后一帧,使得动画播完了不会回到初始状态下
    action.clampWhenFinished = true;
  });
})

(7)加载环境光HDR图片:RGBELoader

new RGBELoader().load('../resources/sky.hdr', function (texture) {
  texture.mapping = THREE.EquirectangularReflectionMapping;
  scene.environment = texture;
  renderer.outputEncoding = THREE.sRGBEncoding;
  renderer.render(scene, camera);
});

(8)完整 js 代码展示

// 引入
import * as THREE from 'three';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';

// 基础场景三大件
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 10);
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

let mixer;
// 设置相机的位置
camera.position.set(0.6,0.6,1);

// 轨道控制器,使得相机围绕目标进行轨道运动
const controls = new OrbitControls( camera, renderer.domElement );


// 加灯光
/* const ambientLight = new THREE.AmbientLight(0xffffff,0.5);
scene.add(ambientLight); */

// 创建一个盒子
/* const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const boxMesh = new THREE.Mesh( geometry, material );
scene.add( boxMesh ); */

// 加载模型
new GLTFLoader().load('../resources/donuts.glb',(gltf)=>{
  // console.log(gltf);
  scene.add(gltf.scene);

  /* gltf.scene.traverse((child)=>{
    console.log(child.name);
  }) */

  mixer = new THREE.AnimationMixer(gltf.scene); //AnimationMixer(动画混合器)
  const clips = gltf.animations; // 播放所有动画
  clips.forEach(function (clip) {
    const action = mixer.clipAction(clip);
    action.loop = THREE.LoopOnce;
    action.play();
    // 停在最后一帧
    action.clampWhenFinished = true;
  });
})

// 加载环境光HDR图片:RGBELoader
new RGBELoader().load('../resources/sky.hdr', function (texture) {
  texture.mapping = THREE.EquirectangularReflectionMapping;
  scene.environment = texture;
  renderer.outputEncoding = THREE.sRGBEncoding;
  renderer.render(scene, camera);
});


function animate() {
  requestAnimationFrame( animate );
  renderer.render( scene, camera );
  controls.update();
  if(mixer){
    mixer.update(0.02);
  }
}
animate();

(9)成果展示从0开始学习Three.js | 大帅老猿threejs特训

四、结束语

可以加入猿创营 (v:dashuailaoyuan),一起交流学习。