likes
comments
collection
share

【Threejs】入门到并没放弃

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

前言:

一阶段的任务完成后,有幸被安排来调研3D相关内容,提到3D那就不能不提threejs,此篇文章就从最基础的示例入手,来完成基础的入门动作,如果需要完整代码,可以私信我。

  • 既然我们要使用Threejs,那我们就需要它到底是啥 ???

  • 它和WebGLOpenGL有啥区别 ???

  • 为什么我们要用Threejs,而不用WebGL来开发 ???

  • 更或者我们能直接用OpenGL来开发web页面吗 ???

概念介绍:

Threejs是什么:

Three.js 是一个纯 JavaScript 实现的,是一个用于创建和呈现实时3D 渲染库,它是一个基于WebGL 的封装,为开发者提供了一套易于使用的API,使得在网页上实现复杂的3D可视化变得更加简单和高效。 github地址,截止当前: github 上的 start 94 kfork 34.9 k


WebGL是什么:

WebGL(Web Graphics Library)是一种基于JavaScript的图形库,用于在网页上通过浏览器进行硬件加速的2D3D图形渲染。WebGL 可以直接访问计算机的图形硬件,通过GPU(图形处理单元)实现高性能的图形渲染。


ThreejsWebGL区别如下:

  1. 抽象层级不同:Three.js 是建立在 WebGL 之上的一个抽象层,提供了更高级别的 API,使得使用者更轻松地创建和操作 3D 场景。WebGL 则是直接操作 GPU 的底层 API
  2. 复杂度:使用 Three.js 相对于直接使用 WebGL,可以更快速地创建复杂的 3D 交互效果。Three.js 封装了很多底层细节,提供了更简单的使用接口,减少了一些重复的工作和处理细节。
  3. 兼容性:Three.js 会自动处理浏览器兼容性和底层 WebGL 的复杂性,这样您不需要担心不同浏览器之间的差异。而直接使用 WebGL 则需要您自己处理浏览器兼容性问题。

总结来说,Three.js 是一个建立在 WebGL 之上的高级库,为开发者提供了更方便的工具和接口来创建Web上的 3D 图形。WebGL 则是原生的、复杂的JavascripAPI,直接操作 GPU 实现高性能的图形渲染。


OpenGL是什么:

OpenGL(Open Graphics Library) 是一个跨平台的、用于渲染2D3D图形的图形库。它提供了一套用于绘制复杂图形的函数和接口,以及用于管理图形资源和状态的机制。它是一个底层的图形库,可以直接与计算机的图形硬件进行交互,提供高性能的图形渲染能力。它可以用于开发应用程序,包括游戏、虚拟现实、科学可视化、CAD(计算机辅助设计)以及其他需要实时图形渲染的领域。可以在多个操作系统和硬件平台上使用,例如Windows 、macOS、Linux和移动设备等。它可以与多种编程语言(C++、Python、Java等)进行集成,方便开发。

WebGLOpenGL的区别如下:

技术应用平台程序语言硬件访问
WebGLweb网页主要依赖于 JavaScript通过浏览器来间接实现硬件加速
OpenGLWindows 、macOS、Linux和移动设备等可可以使用多种编程语言进行开发,例如 C++、Python、Java直接访问计算机的图形硬件

总结: Threejs 就是封装好的WebGLWebGL 就是前端界的 OpenGLOpenGL是应用于桌面端的WebGL


Threejs 整体大概结构

下面是基于自己当前的研究出一张结构图,我们可以看到要得到一个完整的场景,需要的元素还是蛮多的。

【Threejs】入门到并没放弃


  • 场景(Scene):场景属于threejs中最基础的组件,其他物体、灯光、摄像机都依托场景为基础
  • 渲染器(Renderer):负责将camera看到的内容通过绘制给到canvas
  • 相机(Camera): 负责当眼睛,通过设置在不同角度,看到不同内容
  • 物体(Mesh):可见物体,例如:猫、狗、山、树、花、草等

【Threejs】入门到并没放弃


threejs 第一个场景

毕竟站在岸上学不会游泳,下面我就创建一个项目来尝试一下:

当前项目使用的是parcel来辅助开发,parcel是一个轻量级的、零配置的打包工具,且支持热替换。

初始化package.json

npm init -y

安装打包工具parcel

npm install --save-dev parcel

配置项目启动和打包命令:

"scripts": {
    "dev": "parcel src/index.html",
    "build": "parcel build src/index.html"
}

新建src/index.html

引入threejs文件

<script type="module" src="./src/main.js"></script>

这里的type必须是 module

 type="module"

下面是完整示例:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Three.js入门</title>
  </head>
  <body>
    <script src="./script.js" type="module"></script>
  </body>
</html

新建src/script.js 并启动项目

import * as THREE from "three"; 

console.log(THREE); // 验证是否正确添加到项目中

万事俱备,正式开搞!!!

在后面的示例中,只修改js中的代码,html不改

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

console.log(THREE); 

// 初始化渲染器, antialias 是用于设置抗锯齿
const renderer = new THREE.WebGLRenderer({ antialias: true });

// 将渲染器的像素比设置为与设备像素比相同的值,以匹配设备的分辨率,并提供更好的显示效果。
renderer.pixelRatio = window.devicePixelRatio;

//设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);

// 将webgl 渲染的canvas 内容添加到body
document.body.append(renderer.domElement);

// 创建场景
const scene = new THREE.Scene();

// 添加相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

camera.position.set(5, 5, 10);
camera.lookAt(0, 0, 0);

// 添加坐标轴
const axis = new THREE.AxesHelper(5);
scene.add(axis);

// 添加立方体
const geometry = new THREE.BoxGeometry(4, 4, 4); // 立方体
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); // 材质
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 添加控制器(放大、缩小、旋转)
const controls = new OrbitControls(camera, renderer.domElement);
controls.update();

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

// 监听鼠标移动事件
window.addEventListener('mousemove', () => {
  animate();
});

// 渲染
renderer.render(scene, camera);

页面展示:

当前页面添加了一个最简单的box基础几何图形,坐标轴,并添加了控制器工具,支持放大缩小,旋转。至此,我们已经开启threejs的大门,是不是感觉也挺简单的,哈哈哈,自己动手试试吧。

【Threejs】入门到并没放弃

参考文档:你的第一个 three.js 场景:你好,立方体!:


让物体动起来

在上面的例子里,我们已经知道怎么在页面里添加物体,并设置相机位置和控制器等功能,现在我们就尝试让物体运动起来。

核心的方法就是这个方法requestAnimationFrame,这个方法告诉浏览器您希望在下一次绘制帧之前执行某些操作,当前是在渲染下一帧时候就回调用render函数,从而改变cube的位置,这样我们视觉看起来就是每帧都在运动。

requestAnimationFrame(render())

完整代码如下:

import * as THREE from 'three';
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 设置相机位置
camera.position.set(0, 0, 10);
scene.add(camera);

// 添加物体
// 创建几何体
const cubeGeometry = new THREE.BoxGeometry();
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });

// 根据几何体和材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

// 设置物体旋转 X Y Z  Math.PI= 180'  Math.PI / 4 =45',最后一个参数可以设置旋转的先后顺序
cube.rotation.set(Math.PI / 4, 0, 0, 'XYZ');

// 设置物体缩放
cube.scale.set(1, 2, 3);

// 将几何体添加到场景中
scene.add(cube);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();

//设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);

// 将webgl 渲染的canvas 内容添加到body
document.body.appendChild(renderer.domElement);

//使用渲染器通过相机将场景渲染进来
renderer.render(scene, camera);

// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);

// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

function render() {
  // 自动移动位置
  cube.position.x += 0.01;
  cube.rotation.x += 0.01;
  if (cube.position.x > 5) {
    cube.position.x = 0;
  }

  renderer.render(scene, camera);
  //渲染下一帧时候就回调用render函数
  requestAnimationFrame(render);
}
render();


页面展现:

当前模型在每一帧的运动过程中,改变着positionrotation,以X轴为中心坐标顺时针旋转,位置也同样以X轴的定位向右移动

【Threejs】入门到并没放弃

【Threejs】入门到并没放弃


给场景添加模型

web前端且非专业的领域中,glbgltffbx 三种格式更为常用

核心代码:

这里就贴一下核心代码,其他的代码就需要宝子们自己填空喽,其实和上面示例差不多

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
....

// 加载模型
const loader = new GLTFLoader();
const fbxloader = new FBXLoader();

// 载入桌子 - gltf 文件 - 静态模型
loader.load('./model/SimpleSkinning.gltf', (gltf) => {
  gltf.scene.scale.set(8, 1, 3);
  gltf.scene.position.x = -5;
  gltf.scene.position.y = 5;
  gltf.scene.position.z = 1;
  scene.add(gltf.scene);
});

// 载入模拟人 - glb 文件 - 静态模型
loader.load('./model/girl.glb', (gltf) => {
  gltf.scene.scale.set(7, 7, 7);
  gltf.scene.position.x = 5;
  gltf.scene.position.y = 2;
  gltf.scene.position.z = 10;
  scene.add(gltf.scene);
});

// 载入动漫女孩 - 带动作
fbxloader.load('./model/Hip Hop Dancing-withskin.fbx', (object) => {
  object.scale.set(10, 10, 10);
  object.position.set(1, 0, 20);
  scene.add(object);
  mixer = new THREE.AnimationMixer(object);
  const action = mixer.clipAction(object.animations[0]);
  action.play();
  animate();
});

// 执行动作
function animate() {
  requestAnimationFrame(animate);
  const mixerUpdateDelta = clock.getDelta();
  mixer.update(mixerUpdateDelta);
  renderer.render(scene, camera);
}

页面展现:

【Threejs】入门到并没放弃


总结:

至此我们已经完成了threejs的入门操作,可以自己建一个简单的场景,可以自己添加模型,设置模型移动,后面就需要再多的去了解threejs还有哪些功能,毕竟我们也才知道这冰山一角,设置不同灯光、不同模型的加载、如何创建模型、怎么添加动作、如何让导出的文件更小这些问题,我们还不知道,距离真正的使用它完成项目,还有十万八千里,但它也确实是有趣的,所以那就继续研究下去吧!!!

参考资料:


相关链接:


喜欢就加个关注吧!

转载自:https://juejin.cn/post/7268539219161169979
评论
请登录