import { mat3 , mat4 , vec3 } from 'gl-matrix' ; import { inject , injectable } from 'inversify' ; import { ComponentManager } from '../../ComponentManager' ; import { IDENTIFIER } from '../../identifier' ; import { ISystem } from '../../ISystem' ; import { AABB } from '../../shape/AABB' ; import { Mask } from '../../shape/Frustum' ; import { Plane } from '../../shape/Plane' ; import { getRotationScale } from '../../utils/math' ; import { GeometryComponent } from '../geometry/GeometryComponent' ; import { MaterialComponent } from '../material/MaterialComponent' ; import { IView } from '../renderer/IRendererService' ; import { HierarchyComponent } from '../scenegraph/HierarchyComponent' ; import { TransformComponent } from '../scenegraph/TransformComponent' ; import { CullableComponent } from './CullableComponent' ; import { IMeshParams } from './interface' ; import { MeshComponent } from './MeshComponent' ; @ injectable ( ) export class MeshSystem implements ISystem { @ inject ( IDENTIFIER . MeshComponentManager ) private readonly mesh : ComponentManager < MeshComponent > ; @ inject ( IDENTIFIER . CullableComponentManager ) private readonly cullable : ComponentManager < CullableComponent > ; @ inject ( IDENTIFIER . GeometryComponentManager ) private readonly geometry : ComponentManager < GeometryComponent > ; @ inject ( IDENTIFIER . HierarchyComponentManager ) private readonly hierarchy : ComponentManager < HierarchyComponent > ; @ inject ( IDENTIFIER . TransformComponentManager ) private readonly transform : ComponentManager < TransformComponent > ; private planes : Plane [ ] ; public setFrustumPlanes ( planes ) { this . planes = planes ; } public async execute ( views ) { for ( const view of views ) { const scene = view . getScene ( ) ; const camera = view . getCamera ( ) ; for ( const entity of scene . getEntities ( ) ) { const component = this . mesh . getComponentByEntity ( entity ) ; if ( component ) { const hierarchyComponent = this . hierarchy . getComponentByEntity ( entity ) ; const cullableComponent = this . cullable . getComponentByEntity ( entity ) ; const geometryComponent = component . geometry ; const meshTransform = this . transform . getComponentByEntity ( entity ) ; if ( geometryComponent && geometryComponent . aabb && meshTransform && component . aabbDirty ) { const { worldTransform } = meshTransform ; const { center , halfExtents } = geometryComponent . aabb ; const transformedCenter = vec3 . transformMat4 ( vec3 . create ( ) , center , worldTransform ) ; const rotationScale = getRotationScale ( worldTransform , mat3 . create ( ) ) ; const transformedHalfExtents = vec3 . transformMat3 ( vec3 . create ( ) , halfExtents , rotationScale ) ; component . aabb . update ( transformedCenter , transformedHalfExtents ) ; component . aabbDirty = false ; } if ( cullableComponent && geometryComponent ) { const parentCullableComponent = this . cullable . getComponentByEntity ( hierarchyComponent ?. parentID || - 1 ) ; cullableComponent . visibilityPlaneMask = this . computeVisibilityWithPlaneMask ( component . aabb , parentCullableComponent ?. visibilityPlaneMask || Mask . INDETERMINATE , this . planes || camera . getFrustum ( ) . planes ) ; cullableComponent . visible = cullableComponent . visibilityPlaneMask !== Mask . OUTSIDE ; } } } } } public tearDown ( ) { this . cullable . clear ( ) ; this . mesh . clear ( ) ; } see see https see https see https param aabb param parentPlaneMask param planes public computeVisibilityWithPlaneMask ( aabb , parentPlaneMask , planes ) { if ( parentPlaneMask === Mask . OUTSIDE || parentPlaneMask === Mask . INSIDE ) { return parentPlaneMask ; } let mask = Mask . INSIDE ; for ( let k = 0 , len = planes . length ; k < len ; ++ k ) { const flag = k < 31 ? 1 << k : 0 ; if ( k < 31 && ( parentPlaneMask & flag ) === 0 ) { continue ; } const { normal , distance } = planes [ k ] ; if ( vec3 . dot ( normal , aabb . getNegativeFarPoint ( planes [ k ] ) ) + distance > 0 ) { return Mask . OUTSIDE ; } if ( vec3 . dot ( normal , aabb . getPositiveFarPoint ( planes [ k ] ) ) + distance > 0 ) { mask |= flag ; } } return mask ; } }