Threejs系列–7游戏开发加载glb模型之牛刀小试

终极效果展示

目标如下,先来熟悉下threejs吧~~

在这里插入图片描述

开发环境搭建

  1. emmmmmm ~~~ 一台非常攒劲的电脑
  2. 编辑器vscode
  3. js运行环境nodejs
  4. 浏览器chrome

目录结构

|-- src					源代码
	|-- assets 			资源目录
		|-- model
			|-- 630cfe7e8388bff5bfda6692ce4ca40b.glb   一看就是网上随便巴拉的文件^^
	|-- js				核心目录
		|-- events.ts 	事件
		|-- helper.ts 	辅助工具
		|-- role.ts 	角色
		|-- main.ts 	游戏主场景
	|-- index.ts		入口文件
|-- index.html   		模板文件
|-- webpack.config.js	webpack配置

重要依赖

//通过npm直接下载

"dependencies": {
	"three": "^0.134.0"
},
"devDependencies": {
	"@types/three": "^0.133.1",
	"copy-webpack-plugin": "^9.0.1",
	"html-webpack-plugin": "^5.5.0",
	"ts-loader": "^9.2.6",
	"typescript": "^4.4.4",
	"webpack": "^5.61.0",
	"webpack-cli": "^4.9.1",
	"webpack-dev-server": "^4.4.0"
}

代码

html模板内容

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			* {margin: 0; padding: 0;}
			html,body,#webgl {height: 100%;}
			body {overflow: hidden;}
		</style>
	</head>
	<body>
		<canvas id="webgl"></canvas>
	</body>
</html>

main.ts游戏主场景

import * as THREE from 'three';
import LightHelper from './helper';

export default class Main {
	public  mesh: THREE.Mesh;
	public  scene: THREE.Scene;
	public  camera: THREE.PerspectiveCamera;
	public  renderer: THREE.WebGLRenderer;
	private geometry: THREE.PlaneGeometry;
	private material: THREE.Material;
	public  width: number = window.innerWidth;
	public  height: number  = window.innerHeight;
	
	
	constructor() {
		this.initScent();
		this.createGeometry();
		this.setCamera();
		this.setLight();
		this.setRenderer();
	}
	
	createGeometry() {
		this.geometry = new THREE.PlaneGeometry(600, 600);
		
		this.material = new THREE.MeshLambertMaterial({
			color: 0xeaeaea,
			side: THREE.DoubleSide
		});
		
		//网格模型
		this.mesh = new THREE.Mesh(this.geometry, this.material);
		this.mesh.rotation.x = -Math.PI / 2;
		this.mesh.position.x = Math.PI/2
		
		this.mesh.receiveShadow = true;
		this.scene.add(this.mesh);
	}
	
	initScent() {
		//创建场景
		this.scene = new THREE.Scene();
	}
	
	setCamera() {
		const k: number = this.width / this.height;
		const s: number = 75;
		
		//创建相机对象
		this.camera = new THREE.PerspectiveCamera(s, this.width / this.height, 0.1, 10000);
		this.camera.position.set(0, 300, 400);
		
		this.camera.lookAt(this.scene.position);
	}
	
	setLight() {
		const offset = 160
		const Helper:LightHelper = new LightHelper(this.scene);
		//头顶四方四盏灯  增加无尽神秘感
		Array(4).fill(0).forEach((item: any, index: number) => {
			//灯光与位置
			let spotLight = new THREE.SpotLight(0xffffff, 2);
			spotLight.position.x = index>1 ? (index%2?offset:~offset) : 0;
			spotLight.position.z = index<2 ? (index%2?offset:~offset) : 0;
			spotLight.position.y = 400
			//阴影与大小
			spotLight.castShadow = true;
			spotLight.shadow.mapSize.width = 1200;
			spotLight.shadow.mapSize.height = 1200;
			//载入场景
			this.scene.add( spotLight );
			Helper.spointLightHelper(spotLight);
		})
	}
	
	setRenderer() {
		//渲染器
		this.renderer = new THREE.WebGLRenderer({
			canvas: document.getElementById('webgl'),
			antialias: true,
			alpha: true
		});
		this.renderer.setSize(this.width, this.height);//设置渲染区域尺寸
		this.renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
		
		this.renderer.shadowMap.enabled = true;
	}
	
	render() {
		this.renderer.render(this.scene,this.camera);//执行渲染操作
	}
}

role.ts角色构建

import * as THREE from 'three';
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader';
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader';
import {DRACOLoader} from 'three/examples/jsm/loaders/DRACOLoader';
import Main from './main'

export default class Role {
	main: Main;
	mixer: THREE.AnimationMixer = null;
	
	constructor(main: Main) {
		this.main = main;
		this.loader();
	}
	
	loader() {
		// const loader = new FBXLoader();//创建一个FBX加载器
		const loader = new GLTFLoader();//创建一个GLTF加载器
		
		var dracoLoader = new DRACOLoader();
		dracoLoader.setDecoderPath( 'draco/' );
		loader.setDRACOLoader( dracoLoader );


		loader.load('model/630cfe7e8388bff5bfda6692ce4ca40b.glb', (obj) => {
			obj.scene.traverse( child => {
			    if (child.type == 'Mesh') {
			        child.castShadow = true
			        child.receiveShadow = true
			    }
			})
			obj.scene.receiveShadow = true
			obj.scene.rotation.x = - Math.PI / 2
			
			this.main.scene.add(obj.scene)
			
			//this.mixer = new THREE.AnimationMixer(obj);
			//AnimationAction.play();//播放动画
		})
	}
}

helper.ts辅助线

import * as THREE from 'three';

export default class LightHelper {
	private scene: THREE.Scene;
	
	constructor(scene: THREE.Scene) {
		this.scene = scene;
	}
	
	/**
	 * 聚光灯辅助线
	 */
	spointLightHelper(spotLight: THREE.SpotLight) {
		var sphereSize = 1;
		var spointLightHelper = new THREE.PointLightHelper( spotLight, sphereSize );
		this.scene.add( spointLightHelper );
	}
}

events.ts事件

import Main from './main'

export default class Events {
	main: Main;
	
	constructor(main: Main) {
		this.main = main;
		
	    window.addEventListener('resize', this.resize.bind(this));
		window.addEventListener('dblclick', this.fullScreen.bind(this));
	}
	
	resize() {
		this.main.camera.aspect = window.innerWidth / window.innerHeight;
		this.main.camera.updateProjectionMatrix();
		this.main.renderer.setSize(window.innerWidth, window.innerHeight);
	}
	
	fullScreen() {
		if(document.fullscreen) {
			document.exitFullscreen();
		}else{
			document.documentElement.requestFullscreen();
		}
	}
}

代码运行

项目根目录下执行   webpack

作者的话

emmm~~ 准备工作已经完成,顺便熟悉了程序,下节将开始正式的游戏开发。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>