RenderMan  26.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
RixLPE.h
Go to the documentation of this file.
1 /*
2 # ------------------------------------------------------------------------------
3 #
4 # Copyright (c) 2021 Pixar. All rights reserved.
5 #
6 # The information in this file (the "Software") is provided for the exclusive
7 # use of the software licensees of Pixar ("Licensees"). Licensees have the
8 # right to incorporate the Software into other products for use by other
9 # authorized software licensees of Pixar, without fee. Except as expressly
10 # permitted herein, the Software may not be disclosed to third parties, copied
11 # or duplicated in any form, in whole or in part, without the prior written
12 # permission of Pixar.
13 #
14 # The copyright notices in the Software and this entire statement, including the
15 # above license grant, this restriction and the following disclaimer, must be
16 # included in all copies of the Software, in whole or in part, and all permitted
17 # derivative works of the Software, unless such copies or derivative works are
18 # solely in the form of machine-executable object code generated by a source
19 # language processor.
20 #
21 # PIXAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
22 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL PIXAR BE
23 # LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
25 # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26 # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. IN NO CASE WILL
27 # PIXAR'S TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR IN CONNECTION WITH
28 # THE USE OR PERFORMANCE OF THIS SOFTWARE EXCEED $50.
29 #
30 # Pixar
31 # 1200 Park Ave
32 # Emeryville CA 94608
33 #
34 # ------------------------------------------------------------------------------
35 */
36 
37 #ifndef RixLPE_h
38 #define RixLPE_h
39 
40 #include <map> // for map
41 #include <vector> // for vector
42 #include "RixBxdfLobe.h"
43 #include "RixIntegrator.h" // for RixChannelId, etc
44 #include "RixInterfaces.h" // for RixLPEToken, etc
45 #include "RixShadingUtils.h" // for k_ZeroRGB
46 #include "prmanapi.h" // for PRMAN_INLINE
47 #include "RiTypesHelper.h" // for RtColorRGB
48 
49 class RixLPEAutomata;
50 class RixLPEState;
52 
53 typedef std::vector<RixChannelId> ChanIdVec;
54 
55 /* RixLPE interface -- Rix Light Path Expression (LPE) interface
56  *
57  * Use this interface to help support light path expression AOV display
58  * channels in RIS integrators.
59  *
60  * RIS usage:
61  *
62  * See the source code for PxrDirectLighting and PxrPathTracer for
63  * example code that uses the RixLPE interface in order to support light
64  * path expression AOV display channels, and/or follow the example code
65  * below.
66  *
67  * First, use RixIntegratorContext::GetRixLPE() to obtain a RixLPE instance:
68  *
69  * RixLPE *rixLPE = integratorCtx->GetRixLPE();
70  *
71  * Then allocate RixLPEState instances (typically one per light path):
72  *
73  * RixLPEState *states = rixLPE->AllocateStates(maxShadingCtxSize);
74  *
75  * Next, at each scattering event along the light path, call MoveXXX() on
76  * the RixLPEState instance corresponding to that light path in order to
77  * perform state transitions in the LPE deterministic finite automata for
78  * each scattering event.
79  *
80  * states[sCtxIndex].MoveCamera(sCtx, sCtxIndex);
81  * states[sCtxIndex].MoveVertex(sCtx, sCtxIndex, scatterEvent1); // primary hit
82  * states[sCtxIndex].MoveVertex(sCtx, sCtxIndex, scatterEvent2); // secondary hit
83  *
84  * Finally, use the RixLPE::SplatHelper class to aid with writing results to
85  * the LPE AOV display channels:
86  *
87  * RixLPE::SplatHelper aovs(...);
88  * aovs.SplatPerLobe(lobeWeights, weightIndex, thruput, isFinite, clamp, isHoldout);
89  *
90  * Note that SplatHelper::SplatPerLobe() is a utility routine that performs
91  * the final direct lighting (or emissive object) light path transitions and
92  * will accumulate the per-lobe contributions into the beauty and LPE AOVs.
93  * (See the implementation of SplatPerLobe() in RixLPEInline.h for details.)
94  *
95  * Alternatively, some integrators may wish to manually perform the final
96  * state transitions that reach a light or emissive object, and then make
97  * separate per-lobe invocations of the SplatHelper::SplatValue() method to
98  * accumulate contributions for each lobe. E.g.,:
99  *
100  * states[sCtxIndex].MoveVertex(sCtx, sCtxIndex, scatterEvent3);
101  * states[sCtxIndex].MoveLight(sCtx, sCtxIndex, ...);
102  * RixLPE::SplatHelper aovs(...);
103  * aovs.SplatValue(lobe1Contribution, isFinite, clamp);
104  * aovs.SplatValue(lobe2Contribution, isFinite, clamp);
105  *
106  * For emissive objects, the SplatHelper::SplatEmission() method is used to
107  * record the illumination scattering event information:
108  *
109  * aovs.SplatEmission(emission, thruput, isFinite, clamp, isHoldout);
110  *
111  * When the integrator is finished with the RixLPEState instances, then
112  * use RixLPE::FreeStates() to free the memory of the RixLPEState instances:
113  *
114  * rixLPE->FreeStates(maxShadingCtxSize, states);
115  *
116  * Use the RixLPE::AnyLPEs() method to determine whether there are any
117  * light path expression (LPE) AOV display channels at all.
118  *
119  * Use the RixLPE::AnyCustomLPEs() method to determine whether there are any
120  * custom (non-display channel) light path expressions (LPEs) at all.
121  *
122  * Use RixLPE::LgtGrpIdToToken() to convert a lightGroupId into a RixLPEToken
123  * that can be passed into RixLPEState::MoveLight().
124  *
125  */
126 
127 class RixLPE : public RixInterface
128 {
129 public:
130  // The built-in LPE tokens.
132  {
133  k_NULL = 0,
173  };
174 
175  // Flags that control various aspects of what is written to the framebuffer
176  // for LPE AOVs.
178  {
186  k_FlagWhite = 0x80,
190  k_FlagVector = 0x800,
191  k_FlagNormal = 0x1000,
192  };
193 
195 
196  // How to update LPE AOVs with the overwrite flag set.
198  {
202  };
203 
205  : RixInterface(1),
206  m_anyLPEs(false),
207  m_anyCustomLPEs(false),
208  m_beautyChanId(k_InvalidChannelId)
209  {
210  }
211 
212  // Allocate and initialize an array of size 'count' of RixLPEState
213  // instances.
214  virtual RixLPEState* AllocateStates(int count) = 0;
215 
216  // Free an array of RixLPEState instances.
217  virtual void FreeStates(int count, RixLPEState* states) = 0;
218 
219  // Convert an integer RixLPEToken identifier to a string.
220  virtual RtUString TokenToString(RixLPEToken token) const = 0;
221 
222  // Convert a string to an integer RixLPEToken identifier.
223  virtual RixLPEToken StringToToken(RtUString str) const = 0;
224 
225  // Convert an LPE group / object name to an integer RixLPEToken identifier.
226  virtual RixLPEToken GroupAndObjectToToken(RtUString lpeGroup,
227  RtUString objName) const = 0;
228 
229  // Increment reference count on this object.
230  virtual void IncRef() = 0;
231 
232  // Decrement reference count on this object, deleting it when zero.
233  virtual void DecRef() = 0;
234 
235  // Return the current reference count on this object.
236  virtual int GetRefCnt() const = 0;
237 
239  PRMAN_INLINE static RixLPEToken LgtGrpIdToToken(int lightGroupId);
240 
241  // Return true if there are any light path expression AOVs.
242  PRMAN_INLINE bool AnyLPEs() const;
243 
244  // Return true if there are any custom light path expressions.
245  PRMAN_INLINE bool AnyCustomLPEs() const;
246 
247  virtual void Splat(const RixLPEState& accum, RixDisplayServices *dspy,
248  const RtColorRGB& val,
249  const int integratorCtxIdx, const RtColorRGB* lgtTrans,
250  const float clamp, const bool isFinite,
251  const OverwritePolicy overwritePolicy,
252  const bool isHoldout,
253  const RtMatrix4x4* worldXform = nullptr,
254  const RtMatrix4x4* objectXform = nullptr,
255  const RtMatrix4x4* cameraXform = nullptr) const = 0;
256 
257 protected:
258  // The destructor is protected: no need to delete RixLPE instances.
259  virtual ~RixLPE() {}
260 
261  // True if there are any light path expression AOVs.
262  bool m_anyLPEs;
263 
264  // True if there are any custom light path expressions.
266 
267  // The channel id of the beauty pass.
269 
270 public:
271  // Represents the necessary information that we'll need to write out the
272  // standard AOV channels.
274  {
275  public:
276  // Constructor overload that sets all fields. Pass in the current
277  // RixLPEState instance up to this point along the light path
278  // (the 'state' parameter), along with the light LPE token of the
279  // current sample ('lightLpeToken'), the camera to primary hit transmission
280  // ('eyeTrans'), and the shadowing term ('lightTrans').
281  PRMAN_INLINE
282  SplatHelper(
283  RixDisplayServices* displaySvc,
284  int integratorCtxIndex,
285  RixLPE& rixLpe,
286  RixLPEState& state,
287  int depth,
288  RixLPEToken lightLpeToken,
289  RixLPEToken lpeGroupId,
290  bool isReflect,
291  RtColorRGB const& eyeTrans,
292  RtColorRGB const& lightTrans,
293  RixShadingContext const* shadingCtx,
294  int shadingCtxIndex,
295  bool writeOpacityAllowed = true);
296 
297  PRMAN_INLINE ~SplatHelper();
298 
299  // Call this routine to splat per-lobe illumination to the beauty and
300  // LPE AOVs when performing the direct lighting optimization. We want
301  // to perform the splat for some AOVs only if each component of the
302  // beauty RGB value is finite. Also, in the case of clamping, we want
303  // to use a consistent clamp factor across all illumination AOVs, so
304  // pass in the clamping scalar factor as an argument to this method
305  // (default is 1.0, or no clamping).
306  PRMAN_INLINE void SplatPerLobe(
307  RixBXActiveLobeWeights& activeLobes,
308  int weightIndex,
309  RtColorRGB const& thruput,
310  bool isFinite,
311  float clamp = 1.0f,
312  bool isHoldout = false);
313 
314  // Call this routine to splat emissive objects to the beauty and
315  // LPE AOVs when performing the direct lighting optimization. We want
316  // to perform the splat for some AOVs only if each component of the
317  // beauty RGB value is finite. Also, in the case of clamping, we want
318  // to use a consistent clamp factor across all illumination AOVs, so
319  // pass in the clamping scalar factor as an argument to this method
320  // (default is 1.0, or no clamping).
321  PRMAN_INLINE void SplatEmission(
322  RtColorRGB const& emission,
323  RtColorRGB const& thruput,
324  bool isFinite,
325  float clamp = 1.0f,
326  bool isHoldout = false);
327 
328  // Call this routine to splat a single illumination contribution to the
329  // beauty and LPE AOVs. The RixLPEState instance passed by reference
330  // into the SplatHelper class constructor should have already performed
331  // the final state transition that corresponds to hitting a geolight or
332  // emissive object just prior to calling this routine, and then this
333  // method will accumulate the illumination contribution for the
334  // appropriate set of LPE AOVs (along with the beauty display channel).
335  PRMAN_INLINE void SplatValue(
336  RtColorRGB const& color,
337  bool isFinite,
338  float clamp = 1.0f);
339 
340  // Helper routine to splat a color/alpha to the beauty channel id.
341  PRMAN_INLINE void SplatBeauty(
342  RtColorRGB const& val,
343  RtColorRGB& trans) const;
344 
345  // Helper routine to splat a color/alpha to the array of channel ids
346  // associated with the current light path expression automata state.
347  PRMAN_INLINE void SplatLPE(
348  RtColorRGB const& val,
349  RtColorRGB const* lightTrans,
350  bool isFinite,
351  float clamp,
352  int lpeId = -1,
353  OverwritePolicy overwritePolicy = k_Overwrite,
354  bool isHoldout = false);
355 
356  // The following fields represent the information that we'll
357  // need to write out the standard set of AOVs.
358  int m_depth;
362  RtColorRGB m_eyeTrans;
363  RtColorRGB m_lgtTrans;
364 
365  // Cached references to the display services, context index, rixLpe,
366  // and the state of the LPE automata.
374  const RtMatrix4x4 * m_worldXform;
375  const RtMatrix4x4 * m_objectXform;
376  const RtMatrix4x4 * m_cameraXform;
377  };
378 };
379 
380 // Represents a scatter event in the LPE system. One of these should be
381 // constructed for each call to the MoveVertex overloads when state should
382 // be transitioned at a light path vertex.
383 // There are three constructors for three use-cases:
384 // One to construct a scatter event from a vertex that has generated a sample
385 // This is predominantly used by a forward path tracer
386 //
387 // One to construct a scatter event from a vertex that has evaluated a sample
388 // This is predominantly used when trying to connect paths or merge paths in
389 // a bidirectional path tracer or VCM
390 //
391 // One to allow the LPE system to transition state for multiple lobes generated
392 // by next-event-estimation independently.
393 //
394 // The constructors perform error checking to ensure that there is only one
395 // scatter event defined by the passed in lobe traits and to ensure that the
396 // sampled lobe is valid. If neither of these are true an invalid scatter
397 // event is returned. Invalid scatter events have no effect on the LPE automatas
398 // when transitioning state.
400 {
401 public:
402  // Configures the event from a lobe sampled. The user lobe is ignored in the
403  // lobe sampled so this is mostly useful to transition state for indirect.
404  PRMAN_INLINE RixLPEScatterEvent(RixBXLobeSampled lobeSampled);
405 
406  // Configures the event as a scatter event determined from traits. The
407  // traits must represent a single lobe, otherwise the scatter event is
408  // invalid.
409  PRMAN_INLINE RixLPEScatterEvent(RixBXLobeTraits traits);
410 
411  // Configures the event arbitrarily.
412  PRMAN_INLINE RixLPEScatterEvent(bool isReflect, bool isUser,
413  bool isSpecular, unsigned char lpeId);
414 
415  // Is the scatter event valid
416  PRMAN_INLINE bool GetValid() const;
417 
418  // Get the token corresponding to the event type from this scatter event.
419  // Should be one of k_REFLECT or k_TRANSMIT
420  PRMAN_INLINE RixLPEToken GetEvent() const;
421 
422  // Get the token corresponding to the scatter type. This will be one of
423  // the DIFFUSE, SPECULAR or USER types.
424  PRMAN_INLINE RixLPEToken GetScatt() const;
425 
426  // Get the lpe id of the lobe that this scatter event represents
427  PRMAN_INLINE unsigned char GetLpeId() const;
428 
429  // Get the lpe index of the lobe that this scatter event represents. This
430  // is different from the lpe id since this is an absolute index starting
431  // at 0. E.g. the 0'th specular index is k_numDiffuse since the specular
432  // indices follow the diffuse indices, although the specular lpe id will
433  // be 0 in this case.
434  PRMAN_INLINE unsigned char GetLpeIndex() const;
435 
436 private:
437  bool m_isReflect;
438  unsigned char m_lpeId;
439  unsigned char m_lpeIndex;
440  RixLPEToken m_scatter;
441 };
442 
452 {
453 public:
454  RixLPEState( RixLPEAutomata const* automata, const int nautomata );
455 
456  ~RixLPEState();
457 
458  void Reset();
459 
460  std::vector<short>& GetState();
461  const std::vector<short>& GetState() const;
462  void SetState(const std::vector<short>& state);
463  bool Broken() const;
464  bool Test(const RixLPEToken dir, const RixLPEToken sca,
465  const RixLPEToken custom);
466 
467  const RtColorRGB& GetThruput() const;
468  const RixLPEAutomata* GetAutomata(int &nautomata) const;
469 
480  void MoveCamera(RixShadingContext const* sCtx, int sCtxIndex);
481 
493  void MoveCamera(RixShadingContext const* sCtx, int sCtxIndex,
494  const RtColorRGB& thruput);
495 
509  void MoveEmissiveObject(
510  RixShadingContext const* sCtx,
511  int sCtxIndex,
512  RtColorRGB const& thruput,
513  RixLPEToken lpeGroupId = RixLPE::k_BLANK);
514 
530  void MoveLight(
531  RixShadingContext const* sCtx,
532  int sCtxIndex,
533  RtColorRGB const& thruput,
534  RtColorRGB const* lightTrans,
535  bool firstContribution,
536  RixLPEToken lgtLpeToken);
537 
554  void MoveVertex(
555  RixShadingContext const* sCtx,
556  int sCtxIndex,
557  RixLPEScatterEvent const scatterEvent,
558  RixLPEToken lpeGroupId = RixLPE::k_BLANK);
559 
576  void MoveVertex(
577  RixShadingContext const* sCtx,
578  int sCtxIndex,
579  RixLPEScatterEvent const scatterEvent,
580  const RtColorRGB& thruput,
581  RixLPEToken lpeGroupId = RixLPE::k_BLANK,
582  bool doStateTransition = true);
583 
584 private:
585 
586  void move( const RixLPEToken event, const RixLPEToken scatt,
587  const RixLPEToken custom = RixLPE::k_BLANK );
588 
589  // Constant, read-only, data shared amongst all state mutable accumulator
590  // instances
591  const RixLPEAutomata *m_automata;
592  int m_nautomata;
593 
594  // Mutable data specific per-path
595  std::vector<short> m_state;
596 
597  // This LPE's current path thruput
598  RtColorRGB m_thruput;
599 };
600 
601 //
602 // class RixLPE inline method implementation
603 //
604 
605 #include "RixLPEInline.h" // IWYU pragma: export
606 
607 #endif