200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > three.js案例解析之游戏帧碰撞检测

three.js案例解析之游戏帧碰撞检测

时间:2020-10-27 14:41:50

相关推荐

three.js案例解析之游戏帧碰撞检测

先看效果

/examples/ga…

开场白

看到游戏帧这个名字有点奇怪,这个场景其实和碰撞检测有关,为什么又叫游戏帧呢?

引入的新对象

import { Octree } from './jsm/math/Octree.js';import { OctreeHelper } from './jsm/helpers/OctreeHelper.js';import { Capsule } from './jsm/math/Capsule.js';

octree的英文意思为八叉树。

八叉树(Octree)的定义是:若不为空树的话,树中任一节点的子节点恰好只会有八个,或零个,也就是子节点不会有0与8以外的数目。那么,这要用来做什么?想象一个立方体,我们最少可以切成多少个相同等分的小立方体?答案就是8个

从上面描述可知道,八叉树一般用于三维空间的管理,特别是在进行碰撞检测时,分而治之,理清碰撞检测的流程。

八叉树的直观认识

文字通常比较抽象,我们可以用代码来直观地描述它。

{root: true,value: '0',name: '根节点',children: [{ value: '0-0', name: '子节点'},// ...{ value: '0-7', name: '子节点'}]}

同时通过图形视觉上认识它。

是不是对八叉树有一个直观的了解了。

八叉树碰撞检测的流程

三维场景地形

collision-world.glb

通过glb格式的3d模型导出的三维场景。

空间管理八叉树的建立

worldOctree.fromGraphNode( gltf.scene );

fromGraphNode( group ) {group.updateWorldMatrix( true, true );group.traverse( ( obj ) => {if ( obj.isMesh === true ) {let geometry, isTemp = false;if ( obj.geometry.index !== null ) {isTemp = true;geometry = obj.geometry.toNonIndexed();} else {geometry = obj.geometry;}const positionAttribute = geometry.getAttribute( 'position' );for ( let i = 0; i < positionAttribute.count; i += 3 ) {const v1 = new Vector3().fromBufferAttribute( positionAttribute, i );const v2 = new Vector3().fromBufferAttribute( positionAttribute, i + 1 );const v3 = new Vector3().fromBufferAttribute( positionAttribute, i + 2 );v1.applyMatrix4( obj.matrixWorld );v2.applyMatrix4( obj.matrixWorld );v3.applyMatrix4( obj.matrixWorld );this.addTriangle( new Triangle( v1, v2, v3 ) );}if ( isTemp ) {geometry.dispose();}}} );this.build();return this;}

通过glb3d模型导出是一个Three.Group类型的对象。通过调用group的遍历方法,我们只对网格对象进行处理。获得网格对象的几何体对象。获取几何体的位置属性获得构建三角形的的三个顶点坐标通过addTriangle方法构建八叉树。

this.triangles.push( triangle );

不过这光是添加了顶点,并没有构建一个八叉树。

build() {this.calcBox();this.split( 0 );return this;}

这段是真正的构建。

for ( let x = 0; x < 2; x ++ ) {for ( let y = 0; y < 2; y ++ ) {for ( let z = 0; z < 2; z ++ ) {const box = new Box3();const v = _v1.set( x, y, z );box.min.copy( this.box.min ).add( v.multiply( halfsize ) );box.max.copy( box.min ).add( halfsize );subTrees.push( new Octree( box ) );}}}

2 * 2 * 2 = 8。

然后获得这个八叉树所要包裹的物体的边界值,用于大于物体的立方体包裹这个物体。

Box3表示三维空间中的一个轴对齐包围盒(axis-aligned bounding box,AABB)。

球体的碰撞检测

sphereIntersect( sphere ) {_sphere.copy( sphere );const triangles = [];let result, hit = false;this.getSphereTriangles( sphere, triangles );for ( let i = 0; i < triangles.length; i ++ ) {if ( result = this.triangleSphereIntersect( _sphere, triangles[ i ] ) ) {hit = true;_sphere.center.add( result.normal.multiplyScalar( result.depth ) );}}if ( hit ) {const collisionVector = _sphere.center.clone().sub( sphere.center );const depth = collisionVector.length();return { normal: collisionVector.normalize(), depth: depth };}return false;}

首先获得球体所经过的顶点数据。如果判断顶点和球体相交,那么则说明碰撞了。然后根据球体的状态来返回碰撞角度以供碰撞后期处理。

sphere.intersectsBox( subTree.box )

根据包裹立方体来判断物体是否和包裹立方体碰撞了。

这个时候,通过这个包裹立方体来算出具体有多少顶点与物体碰撞了。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。