使用 Svelte 的理由纯粹是它足够轻量级,而且有现代构建工具,编程体验比原生好很多。

svelte 安装

对官网的安装命令略有变动,更换名字并且使用 TypeScript 和 yarn:

1
2
3
4
5
6
7
8
npx degit sveltejs/template my-svelte-three
cd my-svelte-project

# 使用 typescript
node scripts/setupTypeScript.js

yarn
yarn dev

安装 three 与 @types/three

1
2
yarn add three
yarn add @types/three --dev

修改 App.svelte

three.js 场景框架也无外乎就是观察者(相机)、光源、材质、对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<script lang="ts">
import * as THREE from 'three'
import { onMount } from 'svelte';

export let width = 800;
export let height = 400;

// 绑定的 DOM 引用
let domElem;

let scene = new THREE.Scene()

let camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
let renderer = new THREE.WebGLRenderer();
renderer.setClearColor(new THREE.Color(0x000000));
renderer.setSize(width, height);

let axes = new THREE.AxesHelper(20);
scene.add(axes);

camera.position.set(-30, 40, 30);
camera.lookAt(scene.position);

onMount(() => {
domElem.appendChild(renderer.domElement)
renderer.render(scene, camera)
})
</script>

<main>
<div bind:this={domElem}></div>
</main>

<style>
</style>

实际开发通用的组件,内部参数不应该用固定的数值,使用 export 并提供默认值是一种更好的方式。这里只是演示,就只控制 heightwidth

1
2
3
4
5
6
7
8
// main.ts
const app = new App({
target: document.body,
props: {
width: 800,
height: 400,
}
});

当然,如果需要铺满视口,也可以使用 window.innerWidthwindow.innerHeight 代替这两个数字。

如果使用原生的 JavaScript 进行开发,一般会给用 id 来标识 <div>,之后通过 document.getElementById 来获取该 DOM 节点。Svelte 使用 bind:this 来引用 DOM,体验就有了很大的改善。

注意需要使用 onMount 在挂载完成后进行渲染操作

基础场景

three.js 的入门操作

如果觉得这个场景过于空洞,那就随意添加想要的元素咯。

平面

1
2
3
4
5
6
7
8
9
10
let planeGeometry = new THREE.PlaneGeometry(60, 20);
let planeMaterial = new THREE.MeshBasicMaterial({
color: 0xaaaaaa
});
let plane = new THREE.Mesh(planeGeometry, planeMaterial);

plane.rotation.x = -0.5 * Math.PI;
plane.position.set(15, 0, 0);

scene.add(plane);

立方体:

1
2
3
4
5
6
7
8
9
let cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
let cubeMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000,
wireframe: true,
})
let cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(-4, 3, 0);

scene.add(cube);

球体

最后放一个球体,就差不多了。至于材质、灯光、阴影、动画,下次再说。

1
2
3
4
5
6
7
8
9
10
let sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
let sphereMaterial = new THREE.MeshBasicMaterial({
color: 0x7777ff,
wireframe: true,
});
let sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);

sphere.position.set(20, 4, 2);

scene.add(sphere);

最终效果

带物体的场景

小结

使用 Svelte 可以获得现代构建工具(例如自动刷新),而且使用 bind 省去起 id 名字的过程(笑)。