1
+ using SharpDX ;
2
+ using System ;
3
+ #if ! NETFX_CORE
4
+ namespace HelixToolkit . Wpf . SharpDX
5
+ #else
6
+ #if CORE
7
+ namespace HelixToolkit . SharpDX . Core
8
+ #else
9
+ namespace HelixToolkit . UWP
10
+ #endif
11
+ #endif
12
+ {
13
+ using Cameras ;
14
+ public static class CameraCoreExtensions
15
+ {
16
+ public static BoundingFrustum CreateFrustum ( this CameraCore camera , float aspectRatio )
17
+ {
18
+ return new BoundingFrustum ( camera . CreateViewMatrix ( ) * camera . CreateProjectionMatrix ( aspectRatio ) ) ;
19
+ }
20
+
21
+ // Returns whether or not the given point is the outermost point in the given direction among all points of the bounds
22
+ private static bool IsOutermostPointInDirection ( int pointIndex , ref Vector3 direction , Vector3 [ ] corners )
23
+ {
24
+ Vector3 point = corners [ pointIndex ] ;
25
+ for ( int i = 0 ; i < corners . Length ; i ++ )
26
+ {
27
+ if ( i != pointIndex && Vector3 . Dot ( direction , corners [ i ] - point ) > 0 )
28
+ return false ;
29
+ }
30
+
31
+ return true ;
32
+ }
33
+
34
+ // Credit: http://wiki.unity3d.com/index.php/3d_Math_functions
35
+ // Returns the edge points of the closest line segment between 2 lines
36
+ private static void FindClosestPointsOnTwoLines ( ref Ray line1 , ref Ray line2 , out Vector3 closestPointLine1 , out Vector3 closestPointLine2 )
37
+ {
38
+ Vector3 line1Direction = line1 . Direction ;
39
+ Vector3 line2Direction = line2 . Direction ;
40
+
41
+ float a = Vector3 . Dot ( line1Direction , line1Direction ) ;
42
+ float b = Vector3 . Dot ( line1Direction , line2Direction ) ;
43
+ float e = Vector3 . Dot ( line2Direction , line2Direction ) ;
44
+
45
+ float d = a * e - b * b ;
46
+
47
+ Vector3 r = line1 . Position - line2 . Position ;
48
+ float c = Vector3 . Dot ( line1Direction , r ) ;
49
+ float f = Vector3 . Dot ( line2Direction , r ) ;
50
+
51
+ float s = ( b * f - c * e ) / d ;
52
+ float t = ( a * f - c * b ) / d ;
53
+
54
+ closestPointLine1 = line1 . Position + line1Direction * s ;
55
+ closestPointLine2 = line2 . Position + line2Direction * t ;
56
+ }
57
+ /// <summary>
58
+ /// Ref: https://github.com/yasirkula/UnityRuntimePreviewGenerator/blob/7a3b44b07949f712010b680b9f2c499e5aa2ebc1/Plugins/RuntimePreviewGenerator/RuntimePreviewGenerator.cs#L347
59
+ /// </summary>
60
+ /// <param name="camera"></param>
61
+ /// <param name="aspectRatio"></param>
62
+ /// <param name="boundingBox"></param>
63
+ /// <param name="position"></param>
64
+ /// <param name="lookDir"></param>
65
+ /// <param name="upDir"></param>
66
+ public static void ZoomExtents ( this PerspectiveCameraCore camera , float aspectRatio , BoundingBox boundingBox , out Vector3 position , out Vector3 lookDir , out Vector3 upDir )
67
+ {
68
+ var cameraDir = Vector3 . Normalize ( camera . LookDirection ) ;
69
+ var cameraUp = Vector3 . Normalize ( camera . UpDirection ) ;
70
+ var cameraRight = Vector3 . Cross ( cameraDir , cameraUp ) ;
71
+ cameraUp = Vector3 . Cross ( cameraRight , cameraDir ) ;
72
+
73
+ var corners = boundingBox . GetCorners ( ) ;
74
+
75
+ var frustum = camera . CreateFrustum ( aspectRatio ) ;
76
+ var leftNormal = - frustum . Left . Normal ;
77
+ var rightNormal = - frustum . Right . Normal ;
78
+ var topNormal = - frustum . Top . Normal ;
79
+ var bottomNormal = - frustum . Bottom . Normal ;
80
+
81
+ int leftMostPoint = - 1 , rightMostPoint = - 1 , topMostPoint = - 1 , bottomMostPoint = - 1 ;
82
+ for ( int i = 0 ; i < corners . Length ; i ++ )
83
+ {
84
+ if ( leftMostPoint < 0 && IsOutermostPointInDirection ( i , ref leftNormal , corners ) )
85
+ {
86
+ leftMostPoint = i ;
87
+ }
88
+ if ( rightMostPoint < 0 && IsOutermostPointInDirection ( i , ref rightNormal , corners ) )
89
+ {
90
+ rightMostPoint = i ;
91
+ }
92
+ if ( topMostPoint < 0 && IsOutermostPointInDirection ( i , ref topNormal , corners ) )
93
+ {
94
+ topMostPoint = i ;
95
+ }
96
+ if ( bottomMostPoint < 0 && IsOutermostPointInDirection ( i , ref bottomNormal , corners ) )
97
+ {
98
+ bottomMostPoint = i ;
99
+ }
100
+ }
101
+
102
+ var plane1 = new Plane ( corners [ leftMostPoint ] , leftNormal ) ;
103
+ var plane2 = new Plane ( corners [ rightMostPoint ] , rightNormal ) ;
104
+ PlaneExtensions . PlaneIntersectsPlane ( ref plane1 , ref plane2 , out var horizontalIntersection ) ;
105
+ plane1 = new Plane ( corners [ topMostPoint ] , topNormal ) ;
106
+ plane2 = new Plane ( corners [ bottomMostPoint ] , bottomNormal ) ;
107
+ PlaneExtensions . PlaneIntersectsPlane ( ref plane1 , ref plane2 , out var verticalIntersection ) ;
108
+ FindClosestPointsOnTwoLines ( ref horizontalIntersection , ref verticalIntersection , out var closestPointLine1 , out var closestPointLine2 ) ;
109
+ position = Vector3 . Dot ( closestPointLine1 - closestPointLine2 , cameraDir ) < 0 ? closestPointLine1 : closestPointLine2 ;
110
+ upDir = cameraUp ;
111
+ var boundPlane = new Plane ( boundingBox . Center , cameraDir ) ;
112
+ var lookRay = new Ray ( position , cameraDir ) ;
113
+ boundPlane . Intersects ( ref lookRay , out float dist ) ;
114
+ lookDir = cameraDir * dist ;
115
+ }
116
+ /// <summary>
117
+ /// Ref: https://github.com/yasirkula/UnityRuntimePreviewGenerator/blob/7a3b44b07949f712010b680b9f2c499e5aa2ebc1/Plugins/RuntimePreviewGenerator/RuntimePreviewGenerator.cs#L347
118
+ /// </summary>
119
+ /// <param name="camera"></param>
120
+ /// <param name="aspectRatio"></param>
121
+ /// <param name="boundingBox"></param>
122
+ /// <param name="position"></param>
123
+ /// <param name="lookDir"></param>
124
+ /// <param name="upDir"></param>
125
+ /// <param name="width"></param>
126
+ public static void ZoomExtents ( this OrthographicCameraCore camera , float aspectRatio , BoundingBox boundingBox , out Vector3 position , out Vector3 lookDir , out Vector3 upDir , out float width )
127
+ {
128
+ float minX = float . PositiveInfinity , minY = float . PositiveInfinity , maxX = float . NegativeInfinity , maxY = float . NegativeInfinity ;
129
+ var corners = boundingBox . GetCorners ( ) ;
130
+ var view = camera . CreateViewMatrix ( ) ;
131
+ foreach ( var p in corners )
132
+ {
133
+ var local = Vector3 . TransformCoordinate ( p , view ) ;
134
+ minX = Math . Min ( minX , local . X ) ;
135
+ minY = Math . Min ( minY , local . Y ) ;
136
+ maxX = Math . Max ( maxX , local . X ) ;
137
+ maxY = Math . Max ( maxY , local . Y ) ;
138
+ }
139
+ width = aspectRatio > 1 ? Math . Max ( ( maxX - minX ) , ( maxY - minY ) * aspectRatio ) : Math . Max ( ( maxX - minX ) / aspectRatio , maxY - minY ) ;
140
+ position = boundingBox . Center - camera . LookDirection . Normalized ( ) * width ;
141
+ lookDir = camera . LookDirection . Normalized ( ) * width ;
142
+ upDir = camera . UpDirection ;
143
+ }
144
+ }
145
+ }
0 commit comments