likes
comments
collection
share

跟着感觉走 threejs 第一篇

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

threejsjavascript 编写的一个 WebGL 第三方库。在 threejs 中,我们通过 Scene(场景)Camera(相机)Renderer(渲染器) 来实现一个3d的场景,然后往里面添加各种光源、物体等等,形成一个3d世界。

创建一个项目

为了方便起见 这里我们使用vite直接创建一个vanilla模板

mkdir three && cd three
yarn create vite first-three --template vanilla

这样我们就创建了一个基础的模板工程, 删除不必要的代码和文件,只保留index.html以及main.js, 删除main.js中的代码。 其目录结构应该是这个样子的

跟着感觉走 threejs 第一篇

第一步: 安装 和 引入

yarn add three

接下来包就会被下载并安装,然后就可以在代码中引入了。 在main.js中引入

import * as THREE from 'three';

创建三要素

Scene(场景)、Camera(相机)、Renderer(渲染器) 被称为threejs的三要素。 — scene是一个三维空间 用于承载空间内的元素; — camera 可以理解为上帝视角,可以在任意角度和位置观察场景内的元素 — renderer 渲染器是用于渲染所有要素

import * as THREE from 'three';
class MyThree {
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000 );
  renderer = new THREE.WebGLRenderer();
}

定义一个初始化方法用于设置一些初始属性

initGl() {
    document.body.appendChild( this.renderer.domElement );
    this.camera.position.z = 5;
    this.renderer.setSize( window.innerWidth, window.innerHeight);
  }

这时候我们的三要素就设置完成了,打开页面发现一片空白,什么也没有,这时候我们需要调用渲染器的渲染方法将场景渲染到页面, 首先在MyTherr类中定义一个render方法

 class MyThree {
  ...
  render() {
    this.renderer.render(this.scene, this.camera)
  }

接下来我们看看效果

const myThree = new MyThree()
myThree.initGl()
myThree.render()

这时候运行代码 打开浏览器 就可以看到黑色的场景被渲染到了页面中

添加模型

模型也包括三要素: 模型对象,材质, 网格。网格用于将材质和模型对象联系起来。比如可以通过将对象和不同的材质联系起来 实现模型换肤。

接下来 我们在场景中添加一个正方体 同样在MyThree中定义一个方法

class MyClass {
	...
	
	createCube() {
    // 建立一个立方体对象
    const geometry = new THREE.BoxGeometry( 1, 1, 1 );
    // 材质
    const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
    // 网格,用于将材质和立方体联系起来
    const cube = new THREE.Mesh( geometry, material );

    this.scene.add(cube)
  }
}

调用该方法将会把一个绿色的正方体添加到场景中,然后重新调用render方法就可以看到正方体已经被渲染到页面中了

现在整理一下代码

import * as THREE from 'three';

class MyThree {
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000 );
  renderer = new THREE.WebGLRenderer();

  render() {
    this.renderer.render(this.scene, this.camera)
  }

  initGl() {
    // 将rennder的dom元素(canvas)挂载到页面
    document.body.appendChild( this.renderer.domElement );
    // 这里设置camera的位置为(0,0,5)
    this.camera.position.z = 5;
    // 设置渲染器的尺寸
    // https://threejs.org/docs/index.html#manual/zh/introduction/Creating-a-scene
    this.renderer.setSize( window.innerWidth, window.innerHeight);
  }
  createCube() {
    // 建立一个立方体对象
    const geometry = new THREE.BoxGeometry( 1, 1, 1 );
    // 材质
    const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
    // 网格,用于将材质和立方体联系起来
    const cube = new THREE.Mesh( geometry, material );

    // 将网格添加到场景中
    this.scene.add(cube)
  }

  start() {
    this.initGl()
    this.createCube()
    this.render()
  }

}

const myThree = new MyThree()

myThree.start()

运行代码 就可以在页面中看到已经渲染好的正方体了

::思考问题::

  • 为什么将camera的位置设置为(0,0,5) 场景三维坐标系(0,0,0)点就是canvas的中心点 这里我们可以添加个辅助坐标来理解
const axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );

当camera的坐标为(0,0,0)时,相机位置是位于立方体内部的 所以看不到立方体

实现模型的旋转

在上面的例子中我们只能看到一个正方形,并不能看到立方体的全貌,那是因为从相机位置看过去正好看到的是立方体的正视图,所以是一个正方形,接下来我们让立方体旋转起来

首先让我们定义一个动画函数 再此之前修改一下之前的代码:

createCube() {
    // 建立一个立方体对象
    const geometry = new THREE.BoxGeometry( 1, 1, 1 );
    // 材质
    const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
    // 网格,用于将材质和立方体联系起来
--  const cube = new THREE.Mesh( geometry, material );
++  this.cube = new THREE.Mesh( geometry, material );

    // 将网格添加到场景中
    this.scene.add(this.cube)
  }

接下来增加animate函数,修改start方法

class MyThree {
	...
	animate() {
    // 围绕x轴旋转
    this.cube.rotation.x += 0.01
    // 围绕y轴旋转
    this.cube.rotation.y += 0.01
    // 重新render
    this.render()
    // 使用requestAnimationFrame动画函数循环调用
    requestAnimationFrame( this.animate.bind(this) );
  }
  
	start() {
    this.initGl()
    this.createCube(
 -- this.render()
 ++ this.animate()
  }

}

接下来运行代码就可以看到一个旋转的立方体了

以下是完整代码

import * as THREE from 'three';

class MyThree {
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000 );
  renderer = new THREE.WebGLRenderer();
  axesHelper = new THREE.AxesHelper( 5 );
  render() {
    this.renderer.render(this.scene, this.camera)
  }

  initGl() {
    // 将rennder的dom元素(canvas)挂载到页面
    document.body.appendChild( this.renderer.domElement );
    // 这里设置camera的位置为(0,0,5)
    this.camera.position.set(0, 0, 5)
    // 设置渲染器的尺寸
    // https://threejs.org/docs/index.html#manual/zh/introduction/Creating-a-scene
    this.renderer.setSize( window.innerWidth, window.innerHeight);
    this.scene.add(this.axesHelper)
  }
  createCube() {
    // 建立一个立方体对象
    const geometry = new THREE.BoxGeometry( 1, 1, 1 );
    // 材质
    const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
    // 网格,用于将材质和立方体联系起来
    this.cube = new THREE.Mesh( geometry, material );

    // 将网格添加到场景中
    this.scene.add(this.cube)
  }

  animate() {
    // 围绕x轴旋转
    this.cube.rotation.x += 0.01
    // 围绕y轴旋转
    this.cube.rotation.y += 0.01
    // 重新render
    this.render()
    // 使用requestAnimationFrame动画函数循环调用
    requestAnimationFrame( this.animate.bind(this) );
  }

  start() {
    this.initGl()
    this.createCube()
    this.animate()
  }

}

const myThree = new MyThree()

myThree.start()

  • 参考资料
  1. three.js官网
  2. create-vite