1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef API_3D_UTIL_IPICKING_H
17 #define API_3D_UTIL_IPICKING_H
18 
19 #include <limits>
20 
21 #include <3d/namespace.h>
22 #include <base/containers/array_view.h>
23 #include <base/containers/refcnt_ptr.h>
24 #include <base/containers/vector.h>
25 #include <base/math/matrix.h>
26 #include <base/namespace.h>
27 #include <base/util/uid.h>
28 #include <core/namespace.h>
29 #include <core/plugin/intf_interface.h>
30 
BASE_BEGIN_NAMESPACE()31 BASE_BEGIN_NAMESPACE()
32 namespace Math {
33 class Mat4X4;
34 } // namespace Math
35 BASE_END_NAMESPACE()
36 
37 CORE_BEGIN_NAMESPACE()
38 class IEcs;
39 struct Entity;
40 CORE_END_NAMESPACE()
41 
42 CORE3D_BEGIN_NAMESPACE()
43 class ISceneNode;
44 
45 /** \addtogroup group_util_picking
46  *  @{
47  */
48 struct MinAndMax {
49 #define CORE_FMAX std::numeric_limits<float>::max()
50     BASE_NS::Math::Vec3 minAABB { CORE_FMAX, CORE_FMAX, CORE_FMAX };
51     BASE_NS::Math::Vec3 maxAABB { -CORE_FMAX, -CORE_FMAX, -CORE_FMAX };
52 #undef CORE_FMAX
53 };
54 
55 /** Raycast result. */
56 struct RayCastResult {
57     /** Node that was hit. */
58     ISceneNode* node { nullptr };
59 
60     /** Distance to AABB center. */
61     float centerDistance { 0.0f };
62 
63     /** Distance to the hit position. */
64     float distance { 0.0f };
65 
66     /** Position of the hit. */
67     BASE_NS::Math::Vec3 worldPosition { 0.0f, 0.0f, 0.0f };
68 };
69 
70 /** Raycast result for ray-triangle intersection. */
71 struct RayTriangleCastResult {
72     /** Distance to the hit position. */
73     float distance { 0.0f };
74 
75     /** Position of the hit. */
76     BASE_NS::Math::Vec3 worldPosition { 0.0f, 0.0f, 0.0f };
77 
78     /** Ray hit UV for ray-triangle intersection. */
79     BASE_NS::Math::Vec2 hitUv { 0.0f, 0.0f };
80 
81     /** The index of the triangle hit. */
82     uint64_t triangleIndex { 0 };
83 };
84 
85 class IPicking : public CORE_NS::IInterface {
86 public:
87     static constexpr auto UID = BASE_NS::Uid { "9a4791d7-19e2-4dc0-a4fd-b0804d153d70" };
88 
89     using Ptr = BASE_NS::refcnt_ptr<IPicking>;
90 
91     /** Projects normalized screen coordinates to world coordinates. Origin is at the top left corner. Z-value of the
92      * screen coordinate is interpreted so that 0.0 maps to the near plane and 1.0 to the far plane.
93      * @param ecs Entity component system where cameraEntity lives.
94      * @param cameraEntity Camera entity to be used for projection.
95      * @param screenCoordinate Normalized screen coordinates.
96      * @return Projected world coordinates.
97      */
98     virtual BASE_NS::Math::Vec3 ScreenToWorld(
99         CORE_NS::IEcs const& ecs, CORE_NS::Entity cameraEntity, BASE_NS::Math::Vec3 screenCoordinate) const = 0;
100 
101     /** Projects world coordinates to normalized screen coordinates.
102      * @param ecs Entity component system where cameraEntity lives.
103      * @param cameraEntity Camera entity to be used for projection.
104      * @param worldCoordinate World coordinates to be projected.
105      * @return Projected screen coordinates.
106      */
107     virtual BASE_NS::Math::Vec3 WorldToScreen(
108         CORE_NS::IEcs const& ecs, CORE_NS::Entity cameraEntity, BASE_NS::Math::Vec3 worldCoordinate) const = 0;
109 
110     /** Calculates a world space AABB from local min max values. */
111     virtual MinAndMax GetWorldAABB(const BASE_NS::Math::Mat4X4& world, const BASE_NS::Math::Vec3& aabbMin,
112         const BASE_NS::Math::Vec3& aabbMax) const = 0;
113 
114     /**
115      * Calculates a world space AABB for an entity and optionally all of it's children recursively. Uses the world
116      * matrix component for the calculations i.e. the values are only valid after the ECS has updated all the systems
117      * that manipulate the world matrix.
118      */
119     virtual MinAndMax GetWorldMatrixComponentAABB(
120         CORE_NS::Entity entity, bool isRecursive, CORE_NS::IEcs& ecs) const = 0;
121 
122     /**
123      * Calculates a world space AABB for an entity and optionally all of it's children recursively. Uses only the
124      * transform component for the calculations. This way the call will also give valid results even when the ECS has
125      * not been updated. Does not take skinning or animations into account.
126      */
127     virtual MinAndMax GetTransformComponentAABB(CORE_NS::Entity entity, bool isRecursive, CORE_NS::IEcs& ecs) const = 0;
128 
129     /**
130      * Get all nodes hit by ray.
131      * @param ecs Entity component system where hit test is done.
132      * @param start Starting point of the ray.
133      * @param direction Direction of the ray.
134      * @return Array of raycast results that describe node that was hit and distance to intersection (ordered by
135      * distance).
136      */
137     virtual BASE_NS::vector<RayCastResult> RayCast(
138         CORE_NS::IEcs const& ecs, const BASE_NS::Math::Vec3& start, const BASE_NS::Math::Vec3& direction) const = 0;
139 
140     /**
141      * Get nodes hit by ray. Only entities included in the given layer mask are in the result. Entities without
142      * LayerComponent default to LayerConstants::DEFAULT_LAYER_MASK.
143      * @param ecs Entity component system where hit test is done.
144      * @param start Starting point of the ray.
145      * @param direction Direction of the ray.
146      * @param layerMask Layer mask for limiting the returned result.
147      * @return Array of raycast results that describe node that was hit and distance to intersection (ordered by
148      * distance).
149      */
150     virtual BASE_NS::vector<RayCastResult> RayCast(CORE_NS::IEcs const& ecs, const BASE_NS::Math::Vec3& start,
151         const BASE_NS::Math::Vec3& direction, uint64_t layerMask) const = 0;
152 
153     /**
154      * Raycast against a triangle.
155      * @param start Starting point of the ray.
156      * @param direction Direction of the ray.
157      * @param triangles A list of triangles defined by 3 corner vertices. Must be TRIANGLE_LIST.
158      * @return Array of ray-triangle cast results that describe the intersection against triangles.
159      */
160     virtual BASE_NS::vector<RayTriangleCastResult> RayCast(const BASE_NS::Math::Vec3& start,
161         const BASE_NS::Math::Vec3& direction, BASE_NS::array_view<const BASE_NS::Math::Vec3> triangles) const = 0;
162 
163     /**
164      * Get all nodes hit by ray using a camera and 2D screen coordinates as input.
165      * @param ecs EntityComponentSystem where hit test is done.
166      * @param camera Camera entity to be used for the hit test.
167      * @param screenPos screen coordinates for hit test. Where (0, 0) is the upper left corner of the screen and (1, 1)
168      * the lower left corner.
169      * @return Array of raycast results that describe node that was hit and distance to intersection (ordered by
170      * distance).
171      */
172     virtual BASE_NS::vector<RayCastResult> RayCastFromCamera(
173         CORE_NS::IEcs const& ecs, CORE_NS::Entity camera, const BASE_NS::Math::Vec2& screenPos) const = 0;
174 
175     /**
176      * Get nodes hit by ray using a camera and 2D screen coordinates as input. Only entities included in the given layer
177      * mask are in the result. Entities without LayerComponent default to LayerConstants::DEFAULT_LAYER_MASK.
178      * @param ecs EntityComponentSystem where hit test is done.
179      * @param camera Camera entity to be used for the hit test.
180      * @param screenPos screen coordinates for hit test. Where (0, 0) is the upper left corner of the screen and (1, 1)
181      * the lower left corner.
182      * @param layerMask Layer mask for limiting the returned result.
183      * @return Array of raycast results that describe node that was hit and distance to intersection (ordered by
184      * distance).
185      */
186     virtual BASE_NS::vector<RayCastResult> RayCastFromCamera(CORE_NS::IEcs const& ecs, CORE_NS::Entity camera,
187         const BASE_NS::Math::Vec2& screenPos, uint64_t layerMask) const = 0;
188 
189     /**
190      * Calculates the ray-triangle intersection between a ray and a triangle.
191      * @param ecs EntityComponentSystem where hit test is done.
192      * @param camera Camera entity to be used for the hit test.
193      * @param screenPos screen coordinates for hit test. Where (0, 0) is the upper left corner of the screen and (1, 1)
194      * the lower left corner.
195      * @param triangles Triangle list where every triangle is defined by 3 corner vertices. Must be TRIANGLE_LIST.
196      * @return Array of ray-triangle cast results.
197      */
198     virtual BASE_NS::vector<RayTriangleCastResult> RayCastFromCamera(CORE_NS::IEcs const& ecs, CORE_NS::Entity camera,
199         const BASE_NS::Math::Vec2& screenPos, BASE_NS::array_view<const BASE_NS::Math::Vec3> triangles) const = 0;
200 
201 protected:
202     IPicking() = default;
203     virtual ~IPicking() = default;
204 };
205 
206 /** @} */
207 CORE3D_END_NAMESPACE()
208 
209 #endif // API_3D_UTIL_IPICKING_H
210