1 // 2 // Copyright 2019 Pixar 3 // 4 // Licensed under the Apache License, Version 2.0 (the "Apache License") 5 // with the following modification; you may not use this file except in 6 // compliance with the Apache License and the following modification to it: 7 // Section 6. Trademarks. is deleted and replaced with: 8 // 9 // 6. Trademarks. This License does not grant permission to use the trade 10 // names, trademarks, service marks, or product names of the Licensor 11 // and its affiliates, except as required to comply with Section 4(c) of 12 // the License and to reproduce the content of the NOTICE file. 13 // 14 // You may obtain a copy of the Apache License at 15 // 16 // http://www.apache.org/licenses/LICENSE-2.0 17 // 18 // Unless required by applicable law or agreed to in writing, software 19 // distributed under the Apache License with the above modification is 20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21 // KIND, either express or implied. See the Apache License for the specific 22 // language governing permissions and limitations under the Apache License. 23 // 24 #ifndef PXR_IMAGING_HDX_PICK_TASK_H 25 #define PXR_IMAGING_HDX_PICK_TASK_H 26 27 #include "pxr/pxr.h" 28 #include "pxr/imaging/hdx/api.h" 29 30 #include "pxr/imaging/hd/enums.h" 31 #include "pxr/imaging/hd/renderPass.h" 32 #include "pxr/imaging/hd/renderPassState.h" 33 #include "pxr/imaging/hd/rprimCollection.h" 34 #include "pxr/imaging/hd/task.h" 35 36 #include "pxr/base/tf/declarePtrs.h" 37 #include "pxr/base/gf/matrix4d.h" 38 #include "pxr/base/gf/vec2i.h" 39 #include "pxr/base/gf/vec2f.h" 40 #include "pxr/base/gf/vec4i.h" 41 #include "pxr/base/gf/vec4d.h" 42 #include "pxr/usd/sdf/path.h" 43 44 #include <vector> 45 #include <memory> 46 47 PXR_NAMESPACE_OPEN_SCOPE 48 49 #define HDX_PICK_TOKENS \ 50 /* Task context */ \ 51 (pickParams) \ 52 \ 53 /* Pick target */ \ 54 (pickPrimsAndInstances) \ 55 (pickFaces) \ 56 (pickEdges) \ 57 (pickPoints) \ 58 \ 59 /* Resolve mode */ \ 60 (resolveNearestToCamera) \ 61 (resolveNearestToCenter) \ 62 (resolveUnique) \ 63 (resolveAll) 64 65 TF_DECLARE_PUBLIC_TOKENS(HdxPickTokens, HDX_API, HDX_PICK_TOKENS); 66 67 TF_DECLARE_WEAK_AND_REF_PTRS(GlfDrawTarget); 68 69 class HdStRenderPassState; 70 using HdStShaderCodeSharedPtr = std::shared_ptr<class HdStShaderCode>; 71 72 /// Pick task params. This contains render-style state (for example), but is 73 /// augmented by HdxPickTaskContextParams, which is passed in on the task 74 /// context. 75 struct HdxPickTaskParams 76 { HdxPickTaskParamsHdxPickTaskParams77 HdxPickTaskParams() 78 : cullStyle(HdCullStyleNothing) 79 , enableSceneMaterials(true) 80 {} 81 82 HdCullStyle cullStyle; 83 bool enableSceneMaterials; 84 }; 85 86 /// Picking hit structure. This is output by the pick task as a record of 87 /// what objects the picking query found. 88 struct HdxPickHit { 89 SdfPath delegateId; 90 SdfPath objectId; 91 SdfPath instancerId; 92 int instanceIndex; 93 int elementIndex; 94 int edgeIndex; 95 int pointIndex; 96 GfVec3f worldSpaceHitPoint; 97 GfVec3f worldSpaceHitNormal; 98 // normalizedDepth is in the range [0,1]. 99 float normalizedDepth; 100 IsValidHdxPickHit101 inline bool IsValid() const { 102 return !objectId.IsEmpty(); 103 } 104 105 HDX_API 106 size_t GetHash() const; 107 }; 108 109 using HdxPickHitVector = std::vector<HdxPickHit>; 110 111 /// Pick task context params. This contains task params that can't come from 112 /// the scene delegate (like resolution mode and pick location, that might 113 /// be resolved late), as well as the picking collection and the output 114 /// hit vector. 115 /// 'pickTarget': The target of the pick operation, which may influence the 116 /// data filled in the HdxPickHit(s). 117 /// The available options are: 118 /// HdxPickTokens->pickPrimsAndInstances 119 /// HdxPickTokens->pickFaces 120 /// HdxPickTokens->pickEdges 121 /// HdxPickTokens->pickPoints 122 /// 123 /// 'resolveMode': Dictates the resolution of which hit(s) are returned in 124 /// 'outHits'. 125 /// The available options are: 126 /// 1. HdxPickTokens->resolveNearestToCamera : Returns the hit whose 127 /// position is nearest to the camera 128 /// 2. HdxPickTokens->resolveNearestToCenter : Returns the hit whose 129 /// position is nearest to center of the pick location/region. 130 /// 3. HdxPickTokens->resolveUnique : Returns the unique hits, by hashing 131 /// the relevant member fields of HdxPickHit. The 'pickTarget' 132 /// influences this operation. For e.g., the subprim indices are ignored 133 /// when the pickTarget is pickPrimsAndInstances. 134 /// 4. HdxPickTokens->resolveAll: Returns all the hits for the pick location 135 /// or region. The number of hits returned depends on the resolution 136 /// used and may have duplicates. 137 /// 138 struct HdxPickTaskContextParams 139 { 140 using DepthMaskCallback = std::function<void(void)>; 141 HdxPickTaskContextParamsHdxPickTaskContextParams142 HdxPickTaskContextParams() 143 : resolution(128, 128) 144 , pickTarget(HdxPickTokens->pickPrimsAndInstances) 145 , resolveMode(HdxPickTokens->resolveNearestToCamera) 146 , doUnpickablesOcclude(false) 147 , viewMatrix(1) 148 , projectionMatrix(1) 149 , clipPlanes() 150 , depthMaskCallback(nullptr) 151 , collection() 152 , outHits(nullptr) 153 {} 154 155 GfVec2i resolution; 156 TfToken pickTarget; 157 TfToken resolveMode; 158 bool doUnpickablesOcclude; 159 GfMatrix4d viewMatrix; 160 GfMatrix4d projectionMatrix; 161 std::vector<GfVec4d> clipPlanes; 162 DepthMaskCallback depthMaskCallback; 163 HdRprimCollection collection; 164 HdxPickHitVector *outHits; 165 }; 166 167 /// \class HdxPickTask 168 /// 169 /// A task for running picking queries against the current scene. 170 /// This task generates an id buffer for a "pick frustum" (normally the 171 /// camera frustum with the near plane narrowed to an (x,y) location and a 172 /// pick radius); then it resolves that id buffer into a series of prim paths. 173 /// The "Hit" output also contains subprim picking results (e.g. picked face, 174 /// edge, point, instance) and the intersection point in scene worldspace. 175 /// 176 /// HdxPickTask takes an HdxPickTaskParams through the scene delegate, and 177 /// HdxPickTaskContextParams through the task context as "pickParams". 178 /// It produces a hit vector, in the task context as "pickHits". 179 class HdxPickTask : public HdTask 180 { 181 public: 182 HDX_API 183 HdxPickTask(HdSceneDelegate* delegate, SdfPath const& id); 184 185 HDX_API 186 ~HdxPickTask() override; 187 188 /// Sync the render pass resources 189 HDX_API 190 void Sync(HdSceneDelegate* delegate, 191 HdTaskContext* ctx, 192 HdDirtyBits* dirtyBits) override; 193 194 /// Prepare the pick task 195 HDX_API 196 void Prepare(HdTaskContext* ctx, 197 HdRenderIndex* renderIndex) override; 198 199 /// Execute the pick task 200 HDX_API 201 void Execute(HdTaskContext* ctx) override; 202 203 HDX_API 204 const TfTokenVector &GetRenderTags() const override; 205 206 /// Utility: Given a UNorm8Vec4 pixel, unpack it into an int32 ID. DecodeIDRenderColor(unsigned char const idColor[4])207 static inline int DecodeIDRenderColor(unsigned char const idColor[4]) { 208 return (int32_t(idColor[0] & 0xff) << 0) | 209 (int32_t(idColor[1] & 0xff) << 8) | 210 (int32_t(idColor[2] & 0xff) << 16) | 211 (int32_t(idColor[3] & 0xff) << 24); 212 } 213 214 private: 215 HdxPickTaskParams _params; 216 HdxPickTaskContextParams _contextParams; 217 TfTokenVector _renderTags; 218 219 // We need to cache a pointer to the render index so Execute() can 220 // map prim ID to paths. 221 HdRenderIndex *_index; 222 223 void _InitIfNeeded(GfVec2i const& widthHeight); 224 void _ConditionStencilWithGLCallback( 225 HdxPickTaskContextParams::DepthMaskCallback maskCallback); 226 227 bool _UseOcclusionPass() const; 228 229 // Create a shared render pass each for pickables and unpickables 230 HdRenderPassSharedPtr _pickableRenderPass; 231 HdRenderPassSharedPtr _occluderRenderPass; 232 233 // Having separate render pass states allows us to use different 234 // shader mixins if we choose to (we don't currently). 235 HdRenderPassStateSharedPtr _pickableRenderPassState; 236 HdRenderPassStateSharedPtr _occluderRenderPassState; 237 238 // A single draw target is shared for all contexts. Since the FBO cannot 239 // be shared, we clone the attachments on each request. 240 GlfDrawTargetRefPtr _drawTarget; 241 242 HdxPickTask() = delete; 243 HdxPickTask(const HdxPickTask &) = delete; 244 HdxPickTask &operator =(const HdxPickTask &) = delete; 245 }; 246 247 /// A utility class for resolving ID buffers into hits. 248 class HdxPickResult { 249 public: 250 251 // Pick result takes a tuple of ID buffers: 252 // - (primId, instanceId, elementId, edgeId, pointId) 253 // along with some geometric buffers: 254 // - (depth, Neye) 255 // ... and resolves them into a series of hits, using one of the 256 // algorithms specified below. 257 // 258 // index is used to fill in the HdxPickHit structure; 259 // pickTarget is used to determine what a valid hit is; 260 // viewMatrix, projectionMatrix, depthRange are used for unprojection 261 // to calculate the worldSpaceHitPosition and worldSpaceHitNormal. 262 // bufferSize is the size of the ID buffers, and subRect is the sub-region 263 // of the id buffers to iterate over in the resolution algorithm. 264 // 265 // All buffers need to be the same size, if passed in. It's legal for 266 // only the depth and primId buffers to be provided; everything else is 267 // optional but provides a richer picking result. 268 HDX_API 269 HdxPickResult(int const* primIds, 270 int const* instanceIds, 271 int const* elementIds, 272 int const* edgeIds, 273 int const* pointIds, 274 int const* neyes, 275 float const* depths, 276 HdRenderIndex const *index, 277 TfToken const& pickTarget, 278 GfMatrix4d const& viewMatrix, 279 GfMatrix4d const& projectionMatrix, 280 GfVec2f const& depthRange, 281 GfVec2i const& bufferSize, 282 GfVec4i const& subRect); 283 284 HDX_API 285 ~HdxPickResult(); 286 287 HDX_API 288 HdxPickResult(HdxPickResult &&); 289 HDX_API 290 HdxPickResult& operator=(HdxPickResult &&); 291 292 /// Return whether the result was given well-formed parameters. 293 HDX_API 294 bool IsValid() const; 295 296 /// Return the nearest single hit point. Note that this method may be 297 /// considerably more efficient, as it only needs to construct a single 298 /// Hit object. 299 HDX_API 300 void ResolveNearestToCamera(HdxPickHitVector* allHits) const; 301 302 /// Return the nearest single hit point from the center of the viewport. 303 /// Note that this method may be considerably more efficient, as it only 304 /// needs to construct a single Hit object. 305 HDX_API 306 void ResolveNearestToCenter(HdxPickHitVector* allHits) const; 307 308 /// Return all hit points. Note that this may contain redundant objects, 309 /// however it allows access to all depth values for a given object. 310 HDX_API 311 void ResolveAll(HdxPickHitVector* allHits) const; 312 313 /// Return the set of unique hit points, keeping only the nearest depth 314 /// value. 315 HDX_API 316 void ResolveUnique(HdxPickHitVector* allHits) const; 317 318 private: 319 bool _ResolveHit(int index, int x, int y, float z, HdxPickHit* hit) const; 320 size_t _GetHash(int index) const; 321 bool _IsValidHit(int index) const; 322 323 // Provide accessors for all of the ID buffers. Since all but _primIds 324 // are optional, if the buffer doesn't exist just return -1 (== no hit). _GetPrimId(int index)325 int _GetPrimId(int index) const { 326 return _primIds ? _primIds[index] : -1; 327 } _GetInstanceId(int index)328 int _GetInstanceId(int index) const { 329 return _instanceIds ? _instanceIds[index] : -1; 330 } _GetElementId(int index)331 int _GetElementId(int index) const { 332 return _elementIds ? _elementIds[index] : -1; 333 } _GetEdgeId(int index)334 int _GetEdgeId(int index) const { 335 return _edgeIds ? _edgeIds[index] : -1; 336 } _GetPointId(int index)337 int _GetPointId(int index) const { 338 return _pointIds ? _pointIds[index] : -1; 339 } 340 341 // Provide an accessor for the normal buffer. If the normal buffer is 342 // provided, this function will unpack the normal. The fallback is 343 // GfVec3f(0.0f). 344 GfVec3f _GetNormal(int index) const; 345 346 int const* _primIds; 347 int const* _instanceIds; 348 int const* _elementIds; 349 int const* _edgeIds; 350 int const* _pointIds; 351 int const* _neyes; 352 float const* _depths; 353 HdRenderIndex const *_index; 354 TfToken _pickTarget; 355 GfMatrix4d _ndcToWorld; 356 GfMatrix4d _eyeToWorld; 357 GfVec2f _depthRange; 358 GfVec2i _bufferSize; 359 GfVec4i _subRect; 360 }; 361 362 // For sorting, order hits by ndc depth. 363 HDX_API 364 bool operator<(HdxPickHit const& lhs, HdxPickHit const& rhs); 365 366 // VtValue requirements 367 HDX_API 368 std::ostream& operator<<(std::ostream& out, const HdxPickHit& h); 369 HDX_API 370 bool operator==(const HdxPickHit& lhs, 371 const HdxPickHit& rhs); 372 HDX_API 373 bool operator!=(const HdxPickHit& lhs, 374 const HdxPickHit& rhs); 375 376 HDX_API 377 std::ostream& operator<<(std::ostream& out, const HdxPickTaskParams& pv); 378 HDX_API 379 bool operator==(const HdxPickTaskParams& lhs, 380 const HdxPickTaskParams& rhs); 381 HDX_API 382 bool operator!=(const HdxPickTaskParams& lhs, 383 const HdxPickTaskParams& rhs); 384 385 HDX_API 386 std::ostream& operator<<(std::ostream& out, const HdxPickTaskContextParams& pv); 387 HDX_API 388 bool operator==(const HdxPickTaskContextParams& lhs, 389 const HdxPickTaskContextParams& rhs); 390 HDX_API 391 bool operator!=(const HdxPickTaskContextParams& lhs, 392 const HdxPickTaskContextParams& rhs); 393 PXR_NAMESPACE_CLOSE_SCOPE 394 395 #endif // PXR_IMAGING_HDX_PICK_TASK_H 396