@@ -6,6 +6,8 @@ import { PickingInfo } from "../Collisions/pickingInfo";
6
6
import { IntersectionInfo } from "../Collisions/intersectionInfo" ;
7
7
import { BoundingBox } from "./boundingBox" ;
8
8
import { BoundingSphere } from "./boundingSphere" ;
9
+ import { Scene } from '../scene' ;
10
+ import { Camera } from '../Cameras/camera' ;
9
11
/**
10
12
* Class representing a ray with position and direction
11
13
*/
@@ -530,3 +532,234 @@ export class Ray {
530
532
this . direction . normalize ( ) ;
531
533
}
532
534
}
535
+
536
+ // Picking
537
+
538
+ declare module "../scene" {
539
+ export interface Scene {
540
+ /** @hidden */
541
+ _tempPickingRay : Nullable < Ray > ;
542
+
543
+ /** @hidden */
544
+ _cachedRayForTransform : Ray ;
545
+
546
+ /** @hidden */
547
+ _pickWithRayInverseMatrix : Matrix ;
548
+
549
+ /** @hidden */
550
+ _internalPick ( rayFunction : ( world : Matrix ) => Ray , predicate ?: ( mesh : AbstractMesh ) => boolean , fastCheck ?: boolean ) : Nullable < PickingInfo > ;
551
+
552
+ /** @hidden */
553
+ _internalMultiPick ( rayFunction : ( world : Matrix ) => Ray , predicate ?: ( mesh : AbstractMesh ) => boolean ) : Nullable < PickingInfo [ ] > ;
554
+
555
+ }
556
+ }
557
+
558
+ Scene . prototype . createPickingRay = function ( x : number , y : number , world : Matrix , camera : Nullable < Camera > , cameraViewSpace = false ) : Ray {
559
+ let result = Ray . Zero ( ) ;
560
+
561
+ this . createPickingRayToRef ( x , y , world , result , camera , cameraViewSpace ) ;
562
+
563
+ return result ;
564
+ } ;
565
+
566
+ Scene . prototype . createPickingRayToRef = function ( x : number , y : number , world : Matrix , result : Ray , camera : Nullable < Camera > , cameraViewSpace = false ) : Scene {
567
+ var engine = this . getEngine ( ) ;
568
+
569
+ if ( ! camera ) {
570
+ if ( ! this . activeCamera ) {
571
+ throw new Error ( "Active camera not set" ) ;
572
+ }
573
+
574
+ camera = this . activeCamera ;
575
+ }
576
+
577
+ var cameraViewport = camera . viewport ;
578
+ var viewport = cameraViewport . toGlobal ( engine . getRenderWidth ( ) , engine . getRenderHeight ( ) ) ;
579
+
580
+ // Moving coordinates to local viewport world
581
+ x = x / engine . getHardwareScalingLevel ( ) - viewport . x ;
582
+ y = y / engine . getHardwareScalingLevel ( ) - ( engine . getRenderHeight ( ) - viewport . y - viewport . height ) ;
583
+
584
+ result . update ( x , y , viewport . width , viewport . height , world ? world : Matrix . IdentityReadOnly , cameraViewSpace ? Matrix . IdentityReadOnly : camera . getViewMatrix ( ) , camera . getProjectionMatrix ( ) ) ;
585
+ return this ;
586
+ } ;
587
+
588
+ Scene . prototype . createPickingRayInCameraSpace = function ( x : number , y : number , camera ?: Camera ) : Ray {
589
+ let result = Ray . Zero ( ) ;
590
+
591
+ this . createPickingRayInCameraSpaceToRef ( x , y , result , camera ) ;
592
+
593
+ return result ;
594
+ } ;
595
+
596
+ Scene . prototype . createPickingRayInCameraSpaceToRef = function ( x : number , y : number , result : Ray , camera ?: Camera ) : Scene {
597
+ if ( ! PickingInfo ) {
598
+ return this ;
599
+ }
600
+
601
+ var engine = this . getEngine ( ) ;
602
+
603
+ if ( ! camera ) {
604
+ if ( ! this . activeCamera ) {
605
+ throw new Error ( "Active camera not set" ) ;
606
+ }
607
+
608
+ camera = this . activeCamera ;
609
+ }
610
+
611
+ var cameraViewport = camera . viewport ;
612
+ var viewport = cameraViewport . toGlobal ( engine . getRenderWidth ( ) , engine . getRenderHeight ( ) ) ;
613
+ var identity = Matrix . Identity ( ) ;
614
+
615
+ // Moving coordinates to local viewport world
616
+ x = x / engine . getHardwareScalingLevel ( ) - viewport . x ;
617
+ y = y / engine . getHardwareScalingLevel ( ) - ( engine . getRenderHeight ( ) - viewport . y - viewport . height ) ;
618
+ result . update ( x , y , viewport . width , viewport . height , identity , identity , camera . getProjectionMatrix ( ) ) ;
619
+ return this ;
620
+ } ;
621
+
622
+ Scene . prototype . _internalPick = function ( rayFunction : ( world : Matrix ) => Ray , predicate ?: ( mesh : AbstractMesh ) => boolean , fastCheck ?: boolean ) : Nullable < PickingInfo > {
623
+ if ( ! PickingInfo ) {
624
+ return null ;
625
+ }
626
+
627
+ var pickingInfo = null ;
628
+
629
+ for ( var meshIndex = 0 ; meshIndex < this . meshes . length ; meshIndex ++ ) {
630
+ var mesh = this . meshes [ meshIndex ] ;
631
+
632
+ if ( predicate ) {
633
+ if ( ! predicate ( mesh ) ) {
634
+ continue ;
635
+ }
636
+ } else if ( ! mesh . isEnabled ( ) || ! mesh . isVisible || ! mesh . isPickable ) {
637
+ continue ;
638
+ }
639
+
640
+ var world = mesh . getWorldMatrix ( ) ;
641
+ var ray = rayFunction ( world ) ;
642
+
643
+ var result = mesh . intersects ( ray , fastCheck ) ;
644
+ if ( ! result || ! result . hit ) {
645
+ continue ;
646
+ }
647
+
648
+ if ( ! fastCheck && pickingInfo != null && result . distance >= pickingInfo . distance ) {
649
+ continue ;
650
+ }
651
+
652
+ pickingInfo = result ;
653
+
654
+ if ( fastCheck ) {
655
+ break ;
656
+ }
657
+ }
658
+
659
+ return pickingInfo || new PickingInfo ( ) ;
660
+ } ;
661
+
662
+ Scene . prototype . _internalMultiPick = function ( rayFunction : ( world : Matrix ) => Ray , predicate ?: ( mesh : AbstractMesh ) => boolean ) : Nullable < PickingInfo [ ] > {
663
+ if ( ! PickingInfo ) {
664
+ return null ;
665
+ }
666
+ var pickingInfos = new Array < PickingInfo > ( ) ;
667
+
668
+ for ( var meshIndex = 0 ; meshIndex < this . meshes . length ; meshIndex ++ ) {
669
+ var mesh = this . meshes [ meshIndex ] ;
670
+
671
+ if ( predicate ) {
672
+ if ( ! predicate ( mesh ) ) {
673
+ continue ;
674
+ }
675
+ } else if ( ! mesh . isEnabled ( ) || ! mesh . isVisible || ! mesh . isPickable ) {
676
+ continue ;
677
+ }
678
+
679
+ var world = mesh . getWorldMatrix ( ) ;
680
+ var ray = rayFunction ( world ) ;
681
+
682
+ var result = mesh . intersects ( ray , false ) ;
683
+ if ( ! result || ! result . hit ) {
684
+ continue ;
685
+ }
686
+
687
+ pickingInfos . push ( result ) ;
688
+ }
689
+
690
+ return pickingInfos ;
691
+ } ;
692
+
693
+ Scene . prototype . pick = function ( x : number , y : number , predicate ?: ( mesh : AbstractMesh ) => boolean , fastCheck ?: boolean , camera ?: Nullable < Camera > ) : Nullable < PickingInfo > {
694
+ if ( ! PickingInfo ) {
695
+ return null ;
696
+ }
697
+ var result = this . _internalPick ( ( world ) => {
698
+ if ( ! this . _tempPickingRay ) {
699
+ this . _tempPickingRay = Ray . Zero ( ) ;
700
+ }
701
+
702
+ this . createPickingRayToRef ( x , y , world , this . _tempPickingRay , camera || null ) ;
703
+ return this . _tempPickingRay ;
704
+ } , predicate , fastCheck ) ;
705
+ if ( result ) {
706
+ result . ray = this . createPickingRay ( x , y , Matrix . Identity ( ) , camera || null ) ;
707
+ }
708
+ return result ;
709
+ } ;
710
+
711
+ Scene . prototype . pickWithRay = function ( ray : Ray , predicate ?: ( mesh : AbstractMesh ) => boolean , fastCheck ?: boolean ) : Nullable < PickingInfo > {
712
+ var result = this . _internalPick ( ( world ) => {
713
+ if ( ! this . _pickWithRayInverseMatrix ) {
714
+ this . _pickWithRayInverseMatrix = Matrix . Identity ( ) ;
715
+ }
716
+ world . invertToRef ( this . _pickWithRayInverseMatrix ) ;
717
+
718
+ if ( ! this . _cachedRayForTransform ) {
719
+ this . _cachedRayForTransform = Ray . Zero ( ) ;
720
+ }
721
+
722
+ Ray . TransformToRef ( ray , this . _pickWithRayInverseMatrix , this . _cachedRayForTransform ) ;
723
+ return this . _cachedRayForTransform ;
724
+ } , predicate , fastCheck ) ;
725
+ if ( result ) {
726
+ result . ray = ray ;
727
+ }
728
+ return result ;
729
+ } ;
730
+
731
+ Scene . prototype . multiPick = function ( x : number , y : number , predicate ?: ( mesh : AbstractMesh ) => boolean , camera ?: Camera ) : Nullable < PickingInfo [ ] > {
732
+ return this . _internalMultiPick ( ( world ) => this . createPickingRay ( x , y , world , camera || null ) , predicate ) ;
733
+ } ;
734
+
735
+ Scene . prototype . multiPickWithRay = function ( ray : Ray , predicate : ( mesh : AbstractMesh ) => boolean ) : Nullable < PickingInfo [ ] > {
736
+ return this . _internalMultiPick ( ( world ) => {
737
+ if ( ! this . _pickWithRayInverseMatrix ) {
738
+ this . _pickWithRayInverseMatrix = Matrix . Identity ( ) ;
739
+ }
740
+ world . invertToRef ( this . _pickWithRayInverseMatrix ) ;
741
+
742
+ if ( ! this . _cachedRayForTransform ) {
743
+ this . _cachedRayForTransform = Ray . Zero ( ) ;
744
+ }
745
+
746
+ Ray . TransformToRef ( ray , this . _pickWithRayInverseMatrix , this . _cachedRayForTransform ) ;
747
+ return this . _cachedRayForTransform ;
748
+ } , predicate ) ;
749
+ } ;
750
+
751
+ Camera . prototype . getForwardRay = function ( length = 100 , transform ?: Matrix , origin ?: Vector3 ) : Ray {
752
+ if ( ! transform ) {
753
+ transform = this . getWorldMatrix ( ) ;
754
+ }
755
+
756
+ if ( ! origin ) {
757
+ origin = this . position ;
758
+ }
759
+ var forward = this . _scene . useRightHandedSystem ? new Vector3 ( 0 , 0 , - 1 ) : new Vector3 ( 0 , 0 , 1 ) ;
760
+ var forwardWorld = Vector3 . TransformNormal ( forward , transform ) ;
761
+
762
+ var direction = Vector3 . Normalize ( forwardWorld ) ;
763
+
764
+ return new Ray ( origin , direction , length ) ;
765
+ } ;
0 commit comments