使用typescript构建three.js项目
文章目录
1.初始化一个npm项目
新建一个文件夹,打开控制台输入npm初始化命令,然后一路enter,最后Y一下。文件夹中就多了一个package.json的配置文件。
npm init
2.安装webpack
参考这个文章,里面配置和插件都可以直接用webpack入门使用教程
分别安装了:webpack ,webpack-cli 以及html-webpack-plugin ,webpack-dev-server。
"devDependencies": {
"html-webpack-plugin": "^3.2.0",
"ts-loader": "^5.3.3",
"typescript": "^3.3.3333",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
}
3.安装typescript
https://www.tslang.cn/docs/handbook/tsconfig-json.html
需要安装ts-loader和typescript。还有一个配置文件夹,可以用命令自动生成一个,默认的就要行。
tsc --init
初始化一个tsconfig.json.如果tsc命令报错,那么就全局安装一次试试
关于配置问题可以参考这篇文章:tsconfig.json配置说明
4.安装three和@types/three
three和@types/three是必须安装的。(@types/three
已经废弃了不用装了,直接three就可以了,里面带有type)
npm install --save three
npm install --save-dev @types/three
5.一个简单的three场景
three开发的基本套路如下:
- 引入three库文件
- 创建scene、camera、renderer。
- 配置camera、renderer。
- 设置render和animate。
- 把渲染结果添加到body中。
下面就演示一个这个基本套路,为了证明程序运行正确,在场景中添加了一个AxesHelper。
下面的代码中有两个地方因为this指向问题,采用了箭头函数
。在函数中引用了自身,会存在作用域问题。可以对比一下编译后的代码,发现普通的函数是写在原型prototype中,而箭头函数则直接当成属性写在函数本身上。
项目从js转到ts,这个作用域问题非常的常见。简单的处理方式就是用箭头函数代替function
animate = ()=>{
requestAnimationFrame(this.animate)
}
scene.ts
//源代码
import * as THREE from "three"
export default class Threescene{
scene:THREE.Scene
camera:THREE.PerspectiveCamera
renderer:THREE.WebGLRenderer
constructor(){
this.scene = new THREE.Scene()
this.camera = new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,1,2000)
this.renderer = new THREE.WebGLRenderer()
this.init()
window.addEventListener('resize',this.onWindowResize,false)
}
private init(){
this.camera.position.set(-40,40,40)
this.camera.lookAt(this.scene.position)
this.renderer.setClearColor(0x222222)
this.renderer.setSize(window.innerWidth,window.innerHeight)
document.body.appendChild( this.renderer.domElement );
this.scene.add(new THREE.AxesHelper(10))
this.animate()
}
private onWindowResize = ()=>{
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize( window.innerWidth, window.innerHeight );
}
private render(){
this.renderer.render(this.scene,this.camera)
}
private animate = ()=>{
requestAnimationFrame(this.animate)
this.render()
}
}
//编译后部分代码
var Threescene = /** @class */ (function () {
function Threescene() {
var _this = this;
this.onWindowResize = function () {
_this.camera.aspect = window.innerWidth / window.innerHeight;
_this.camera.updateProjectionMatrix();
_this.renderer.setSize(window.innerWidth, window.innerHeight);
};
this.animate = function () {
requestAnimationFrame(_this.animate);
_this.render();
};
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
this.renderer = new THREE.WebGLRenderer();
this.init();
window.addEventListener('resize', this.onWindowResize, false);
}
Threescene.prototype.init = function () {
this.camera.position.set(-40, 40, 40);
this.camera.lookAt(this.scene.position);
this.renderer.setClearColor(0x222222);
this.renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(this.renderer.domElement);
this.scene.add(new THREE.AxesHelper(10));
this.animate();
};
Threescene.prototype.render = function () {
this.renderer.render(this.scene, this.camera);
};
return Threescene;
}());
index.ts
import ThreeScee from "./util/scene"
import "./assets/css/index.css"
new ThreeScee()
程序运行后会在场景中显示一个AxesHelper。
6.添加orbitcontrols相机控制器
npm install --save three-orbitcontrols
这个坑真多,坑的我无语了。 three-orbitcontrols没有@type文件,官方也不出,而且也不在核心three库中,不知道官方几个意思。
安装了three-orbitcontrols后,去看看他的源码,发现采用的是module.export,而不是export,所以出现了问题。这个需要require进来的,是commonjs的方式吧,export是es6的方式,不统一。说白了就是three-orbitcontrols不是three.js亲生的吧。
module.exports = exports.default = THREE.OrbitControls;
这样引入:import * as OrbitControls from “three-orbitcontrols” 或者 import OrbitControls from "three-orbitcontrols"会提示无法找到模块“three-orbitcontrols”的声明文件。
可以新建个.d.ts文件来屏蔽这个警告:declare module ‘three-orbitcontrols’
*** as** 要不要加?我不知道,有的时候加了报错,有的时候不加报错,我无语了。
还有同样的配置,一个项目只能any,不加as,一个加不加都行,还可以用THREE.OrbitControls的类型。(没排查去原因)
controls: any
controls: THREE.OrbitControls
还有一种简单的处理方式,自己改造一下orbitcontrols.js文件,变成inport和export的形式,作为资源文件引入进来。
这个坑不准备继续踩了,估计不久就会统一修复的。
每次配置都踩一次,这次是这样的:
104版本 安装 three 和 three-orbitcontrols
import { Threescene } from “./basescene”
import OrbitControls from “three-orbitcontrols”
ts–“module”: “commonjs”,
自己慢慢体会three的更新吧
7.添加项目中引入css和图片
css 需要"css-loader",“style-loader”,分别安装一下。配置项也需要修改一下。
之后我们就可以使用import "./assets/css/index.css"
来引入css文件了。给body加个样式来屏蔽滚动条。
body {
margin: 0px;
overflow: hidden;
}
8.添加图片和其他资源
图片资源有两种处理方式,一直是打包到js文件中,一直是拷贝到指定目录中。
webpack打包图片需要url-loader,
{
test: /\.(png|jpg)$/,
loader: 'url-loader?limit=819200&name=images/[hash:8].[name].[ext]'
}
拷贝文件可以使用copy-webpack-plugin插件。
参考文章:https://blog.csdn.net/lin5165352/article/details/85267088
场景中使用的三维模型,比如obj,fbx,glft等,也可以使用这个拷贝插件拷贝过去,方便使用。
当然你也可以不安装这个插件,自己手动拷贝过去,这样你在使用webpack-dev-server开发的时候才会找到资源。
9.其他配置问题
9.1 安装tween.js
这个函数库是用来做动画用的,使用频率非常高。
记得安装的名称是@tweenjs/tween.js,而不是tween.js。
@tweenjs/tween.js --npm i @tweenjs/tween.js
10.项目GitHub地址
https://github.com/scqilin/three.js-typescript