RenderMan API  23.0
RixLPE.h
Go to the documentation of this file.
1 /*
2 # ------------------------------------------------------------------------------
3 #
4 # Copyright (c) 1986-2019 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 
38 #ifndef RixLPE_h
39 #define RixLPE_h
40 
41 #include <map> // for map
42 #include <vector> // for vector
43 #include "RixBxdfLobe.h"
44 #include "RixIntegrator.h" // for RixChannelId, etc
45 #include "RixInterfaces.h" // for RixLPEToken, etc
46 #include "RixShadingUtils.h" // for k_ZeroRGB
47 #include "prmanapi.h" // for PRMAN_INLINE
48 #include "ri.h" // for RtColorRGB
49 
50 class RixLPEAutomata;
51 class RixLPEState;
53 
54 typedef std::vector<RixChannelId> ChanIdVec;
55 
56 /* RixLPE interface -- Rix Light Path Expression (LPE) interface
57  *
58  * Use this interface to help support light path expression AOV display
59  * channels in RIS integrators.
60  *
61  * RIS usage:
62  *
63  * See the source code for PxrDirectLighting and PxrPathTracer for
64  * example code that uses the RixLPE interface in order to support light
65  * path expression AOV display channels, and/or follow the example code
66  * below.
67  *
68  * First, use RixIntegratorContext::GetRixLPE() to obtain a RixLPE instance:
69  *
70  * RixLPE *rixLPE = integratorCtx->GetRixLPE();
71  *
72  * Then allocate RixLPEState instances (typically one per light path):
73  *
74  * RixLPEState *states = rixLPE->AllocateStates(maxShadingCtxSize);
75  *
76  * Next, at each scattering event along the light path, call MoveXXX() on
77  * the RixLPEState instance corresponding to that light path in order to
78  * perform state transitions in the LPE deterministic finite automata for
79  * each scattering event.
80  *
81  * states[sCtxIndex].MoveCamera(sCtx, sCtxIndex);
82  * states[sCtxIndex].MoveVertex(sCtx, sCtxIndex, scatterEvent1); // primary hit
83  * states[sCtxIndex].MoveVertex(sCtx, sCtxIndex, scatterEvent2); // secondary hit
84  *
85  * Finally, use the RixLPE::SplatHelper class to aid with writing results to
86  * the LPE AOV display channels:
87  *
88  * RixLPE::SplatHelper aovs(...);
89  * aovs.SplatPerLobe(lobeWeights, weightIndex, thruput, isFinite, clamp, isHoldout);
90  *
91  * Note that SplatHelper::SplatPerLobe() is a utility routine that performs
92  * the final direct lighting (or emissive object) light path transitions and
93  * will accumulate the per-lobe contributions into the beauty and LPE AOVs.
94  * (See the implementation of SplatPerLobe() in RixLPEInline.h for details.)
95  *
96  * Alternatively, some integrators may wish to manually perform the final
97  * state transitions that reach a light or emissive object, and then make
98  * separate per-lobe invocations of the SplatHelper::SplatValue() method to
99  * accumulate contributions for each lobe. E.g.,:
100  *
101  * states[sCtxIndex].MoveVertex(sCtx, sCtxIndex, scatterEvent3);
102  * states[sCtxIndex].MoveLight(sCtx, sCtxIndex, ...);
103  * RixLPE::SplatHelper aovs(...);
104  * aovs.SplatValue(lobe1Contribution, isFinite, clamp);
105  * aovs.SplatValue(lobe2Contribution, isFinite, clamp);
106  *
107  * For emissive objects, the SplatHelper::SplatEmission() method is used to
108  * record the illumination scattering event information:
109  *
110  * aovs.SplatEmission(emission, thruput, isFinite, clamp, isHoldout);
111  *
112  * When the integrator is finished with the RixLPEState instances, then
113  * use RixLPE::FreeStates() to free the memory of the RixLPEState instances:
114  *
115  * rixLPE->FreeStates(maxShadingCtxSize, states);
116  *
117  * Use the RixLPE::AnyLPEs() method to determine whether there are any
118  * light path expression (LPE) AOV display channels at all.
119  *
120  * Use the RixLPE::AnyCustomLPEs() method to determine whether there are any
121  * custom (non-display channel) light path expressions (LPEs) at all.
122  *
123  * Use RixLPE::LgtGrpIdToToken() to convert a lightGroupId into a RixLPEToken
124  * that can be passed into RixLPEState::MoveLight().
125  *
126  */
127 
128 class RixLPE : public RixInterface
129 {
130 public:
131  // The built-in LPE tokens.
133  {
134  k_NULL = 0,
174  };
175 
176  // Flags that control various aspects of what is written to the framebuffer
177  // for LPE AOVs.
179  {
187  };
188 
190 
191  // How to update LPE AOVs with the overwrite flag set.
193  {
197  };
198 
200  : RixInterface(1),
201  m_anyLPEs(false),
202  m_anyCustomLPEs(false),
203  m_beautyChanId(k_InvalidChannelId)
204  {
205  }
206 
207  // Allocate and initialize an array of size 'count' of RixLPEState
208  // instances.
209  virtual RixLPEState* AllocateStates(int count) = 0;
210 
211  // Free an array of RixLPEState instances.
212  virtual void FreeStates(int count, RixLPEState* states) = 0;
213 
214  // Convert an integer RixLPEToken identifier to a string.
215  virtual RtUString TokenToString(RixLPEToken token) const = 0;
216 
217  // Convert a string to an integer RixLPEToken identifier.
218  virtual RixLPEToken StringToToken(RtUString str) const = 0;
219 
220  // Convert an LPE group / object name to an integer RixLPEToken identifier.
221  virtual RixLPEToken GroupAndObjectToToken(RtUString lpeGroup,
222  RtUString objName) const = 0;
223 
224  // Increment reference count on this object.
225  virtual void IncRef() = 0;
226 
227  // Decrement reference count on this object, deleting it when zero.
228  virtual void DecRef() = 0;
229 
230  // Return the current reference count on this object.
231  virtual int GetRefCnt() const = 0;
232 
234  PRMAN_INLINE static RixLPEToken LgtGrpIdToToken(int lightGroupId);
235 
236  // Return true if there are any light path expression AOVs.
237  PRMAN_INLINE bool AnyLPEs() const;
238 
239  // Return true if there are any custom light path expressions.
240  PRMAN_INLINE bool AnyCustomLPEs() const;
241 
242  virtual void Splat(const RixLPEState& accum, RixDisplayServices *dspy,
243  const RtColorRGB& val,
244  const int integratorCtxIdx, const RtColorRGB* lgtTrans,
245  const float clamp, const bool isFinite,
246  const OverwritePolicy overwritePolicy,
247  const bool isHoldout) const = 0;
248 
249 protected:
250  // The destructor is protected: no need to delete RixLPE instances.
251  virtual ~RixLPE() {}
252 
253  // True if there are any light path expression AOVs.
254  bool m_anyLPEs;
255 
256  // True if there are any custom light path expressions.
258 
259  // The channel id of the beauty pass.
261 
262 public:
263  // Represents the necessary information that we'll need to write out the
264  // standard AOV channels.
266  {
267  public:
268  // Constructor overload that sets all fields. Pass in the current
269  // RixLPEState instance up to this point along the light path
270  // (the 'state' parameter), along with the light LPE token of the
271  // current sample ('lightLpeToken'), the camera to primary hit transmission
272  // ('eyeTrans'), and the shadowing term ('lightTrans').
274  SplatHelper(
275  RixDisplayServices* displaySvc,
276  int integratorCtxIndex,
277  RixLPE& rixLpe,
278  RixLPEState& state,
279  int depth,
280  RixLPEToken lightLpeToken,
281  RixLPEToken lpeGroupId,
282  bool isReflect,
283  RtColorRGB const& eyeTrans,
284  RtColorRGB const& lightTrans,
285  RixShadingContext const* shadingCtx,
286  int shadingCtxIndex,
287  bool writeOpacityAllowed = true);
288 
290 
291  // Call this routine to splat per-lobe illumination to the beauty and
292  // LPE AOVs when performing the direct lighting optimization. We want
293  // to perform the splat for some AOVs only if each component of the
294  // beauty RGB value is finite. Also, in the case of clamping, we want
295  // to use a consistent clamp factor across all illumination AOVs, so
296  // pass in the clamping scalar factor as an argument to this method
297  // (default is 1.0, or no clamping).
299  RixBXActiveLobeWeights& activeLobes,
300  int weightIndex,
301  RtColorRGB const& thruput,
302  bool isFinite,
303  float clamp = 1.0f,
304  bool isHoldout = false);
305 
306  // Call this routine to splat emissive objects to the beauty and
307  // LPE AOVs when performing the direct lighting optimization. We want
308  // to perform the splat for some AOVs only if each component of the
309  // beauty RGB value is finite. Also, in the case of clamping, we want
310  // to use a consistent clamp factor across all illumination AOVs, so
311  // pass in the clamping scalar factor as an argument to this method
312  // (default is 1.0, or no clamping).
314  RtColorRGB const& emission,
315  RtColorRGB const& thruput,
316  bool isFinite,
317  float clamp = 1.0f,
318  bool isHoldout = false);
319 
320  // Call this routine to splat a single illumination contribution to the
321  // beauty and LPE AOVs. The RixLPEState instance passed by reference
322  // into the SplatHelper class constructor should have already performed
323  // the final state transition that corresponds to hitting a geolight or
324  // emissive object just prior to calling this routine, and then this
325  // method will accumulate the illumination contribution for the
326  // appropriate set of LPE AOVs (along with the beauty display channel).
328  RtColorRGB const& color,
329  bool isFinite,
330  float clamp = 1.0f);
331 
332  // Helper routine to splat a color/alpha to the beauty channel id.
334  RtColorRGB const& val,
335  RtColorRGB& trans) const;
336 
337  // Helper routine to splat a color/alpha to the array of channel ids
338  // associated with the current light path expression automata state.
339  PRMAN_INLINE void SplatLPE(
340  RtColorRGB const& val,
341  RtColorRGB const* lightTrans,
342  bool isFinite,
343  float clamp,
344  int lpeId = -1,
345  OverwritePolicy overwritePolicy = k_Overwrite,
346  bool isHoldout = false);
347 
348  // The following fields represent the information that we'll
349  // need to write out the standard set of AOVs.
350  int m_depth;
356 
357  // Cached references to the display services, context index, rixLpe,
358  // and the state of the LPE automata.
366  };
367 };
368 
369 // Represents a scatter event in the LPE system. One of these should be
370 // constructed for each call to the MoveVertex overloads when state should
371 // be transitioned at a light path vertex.
372 // There are three constructors for three use-cases:
373 // One to construct a scatter event from a vertex that has generated a sample
374 // This is predominantly used by a forward path tracer
375 //
376 // One to construct a scatter event from a vertex that has evaluated a sample
377 // This is predominantly used when trying to connect paths or merge paths in
378 // a bidirectional path tracer or VCM
379 //
380 // One to allow the LPE system to transition state for multiple lobes generated
381 // by next-event-estimation independently.
382 //
383 // The constructors perform error checking to ensure that there is only one
384 // scatter event defined by the passed in lobe traits and to ensure that the
385 // sampled lobe is valid. If neither of these are true an invalid scatter
386 // event is returned. Invalid scatter events have no effect on the LPE automatas
387 // when transitioning state.
389 {
390 public:
391  // Configures the event from a lobe sampled. The user lobe is ignored in the
392  // lobe sampled so this is mostly useful to transition state for indirect.
394 
395  // Configures the event as a scatter event determined from traits. The
396  // traits must represent a single lobe, otherwise the scatter event is
397  // invalid.
398  PRMAN_INLINE RixLPEScatterEvent(RixBXLobeTraits traits);
399 
400  // Configures the event arbitrarily.
401  PRMAN_INLINE RixLPEScatterEvent(bool isReflect, bool isUser,
402  bool isSpecular, unsigned char lpeId);
403 
404  // Is the scatter event valid
405  PRMAN_INLINE bool GetValid() const;
406 
407  // Get the token corresponding to the event type from this scatter event.
408  // Should be one of k_REFLECT or k_TRANSMIT
409  PRMAN_INLINE RixLPEToken GetEvent() const;
410 
411  // Get the token corresponding to the scatter type. This will be one of
412  // the DIFFUSE, SPECULAR or USER types.
413  PRMAN_INLINE RixLPEToken GetScatt() const;
414 
415  // Get the lpe id of the lobe that this scatter event represents
416  PRMAN_INLINE unsigned char GetLpeId() const;
417 
418  // Get the lpe index of the lobe that this scatter event represents. This
419  // is different from the lpe id since this is an absolute index starting
420  // at 0. E.g. the 0'th specular index is k_numDiffuse since the specular
421  // indices follow the diffuse indices, although the specular lpe id will
422  // be 0 in this case.
423  PRMAN_INLINE unsigned char GetLpeIndex() const;
424 
425 private:
426  bool m_isReflect;
427  unsigned char m_lpeId;
428  unsigned char m_lpeIndex;
429  RixLPEToken m_scatter;
430 };
431 
441 {
442 public:
443  RixLPEState( RixLPEAutomata const* automata, const int nautomata );
444 
445  ~RixLPEState();
446 
447  void Reset();
448 
449  std::vector<short>& GetState();
450  const std::vector<short>& GetState() const;
451  void SetState(const std::vector<short>& state);
452  bool Broken() const;
453  bool Test(const RixLPEToken dir, const RixLPEToken sca,
454  const RixLPEToken custom);
455 
456  const RtColorRGB& GetThruput() const;
457  const RixLPEAutomata* GetAutomata(int &nautomata) const;
458 
469  void MoveCamera(RixShadingContext const* sCtx, int sCtxIndex);
470 
482  void MoveCamera(RixShadingContext const* sCtx, int sCtxIndex,
483  const RtColorRGB& thruput);
484 
498  void MoveEmissiveObject(
499  RixShadingContext const* sCtx,
500  int sCtxIndex,
501  RtColorRGB const& thruput,
502  RixLPEToken lpeGroupId = RixLPE::k_BLANK);
503 
519  void MoveLight(
520  RixShadingContext const* sCtx,
521  int sCtxIndex,
522  RtColorRGB const& thruput,
523  RtColorRGB const* lightTrans,
524  bool firstContribution,
525  RixLPEToken lgtLpeToken);
526 
543  void MoveVertex(
544  RixShadingContext const* sCtx,
545  int sCtxIndex,
546  RixLPEScatterEvent const scatterEvent,
547  RixLPEToken lpeGroupId = RixLPE::k_BLANK);
548 
565  void MoveVertex(
566  RixShadingContext const* sCtx,
567  int sCtxIndex,
568  RixLPEScatterEvent const scatterEvent,
569  const RtColorRGB& thruput,
570  RixLPEToken lpeGroupId = RixLPE::k_BLANK,
571  bool doStateTransition = true);
572 
573 private:
574 
575  void move( const RixLPEToken event, const RixLPEToken scatt,
576  const RixLPEToken custom = RixLPE::k_BLANK );
577 
578  // Constant, read-only, data shared amongst all state mutable accumulator
579  // instances
580  const RixLPEAutomata *m_automata;
581  int m_nautomata;
582 
583  // Mutable data specific per-path
584  std::vector<short> m_state;
585 
586  // This LPE's current path thruput
587  RtColorRGB m_thruput;
588 };
589 
590 //
591 // class RixLPE inline method implementation
592 //
593 
594 #include "RixLPEInline.h" // IWYU pragma: export
595 
596 #endif
virtual RtUString TokenToString(RixLPEToken token) const =0
static PRMAN_INLINE RixLPEToken LgtGrpIdToToken(int lightGroupId)
Convert an integer light group id to an LPE token.
Definition: RixLPEInline.h:126
pxrcore::ColorRGB RtColorRGB
bool m_anyCustomLPEs
Definition: RixLPE.h:257
virtual int GetRefCnt() const =0
virtual RixLPEToken GroupAndObjectToToken(RtUString lpeGroup, RtUString objName) const =0
This struct represents the characteristics of just one lobe of a bxdf.
Definition: RixBxdfLobe.h:64
virtual void Splat(const RixLPEState &accum, RixDisplayServices *dspy, const RtColorRGB &val, const int integratorCtxIdx, const RtColorRGB *lgtTrans, const float clamp, const bool isFinite, const OverwritePolicy overwritePolicy, const bool isHoldout) const =0
RtColorRGB m_lgtTrans
Definition: RixLPE.h:355
RixLPEToken m_lpeGrpId
Definition: RixLPE.h:352
PRMAN_INLINE void SplatPerLobe(RixBXActiveLobeWeights &activeLobes, int weightIndex, RtColorRGB const &thruput, bool isFinite, float clamp=1.0f, bool isHoldout=false)
Definition: RixLPEInline.h:501
PRMAN_INLINE void SplatLPE(RtColorRGB const &val, RtColorRGB const *lightTrans, bool isFinite, float clamp, int lpeId=-1, OverwritePolicy overwritePolicy=k_Overwrite, bool isHoldout=false)
Definition: RixLPEInline.h:730
std::vector< RixChannelId > ChanIdVec
Definition: RixLPE.h:52
RixLPE & m_rixLpe
Definition: RixLPE.h:361
Definition: RixLPE.h:128
RixLPEBuiltInTokens
Definition: RixLPE.h:132
bool m_anyLPEs
Definition: RixLPE.h:254
virtual ~RixLPE()
Definition: RixLPE.h:251
virtual void IncRef()=0
static const int k_baseLgtGrpTokenOffset
Definition: RixLPE.h:189
PRMAN_INLINE ~SplatHelper()
Definition: RixLPEInline.h:496
pxrcore::UString RtUString
RixLPEFlags
Definition: RixLPE.h:178
#define PRMAN_INLINE
Definition: prmanapi.h:86
PRMAN_INLINE void SplatEmission(RtColorRGB const &emission, RtColorRGB const &thruput, bool isFinite, float clamp=1.0f, bool isHoldout=false)
Definition: RixLPEInline.h:634
RixDisplayServices * m_displaySvc
Definition: RixLPE.h:359
PRMAN_INLINE void SplatValue(RtColorRGB const &color, bool isFinite, float clamp=1.0f)
Definition: RixLPEInline.h:696
OverwritePolicy
Definition: RixLPE.h:192
PRMAN_INLINE bool AnyLPEs() const
Definition: RixLPEInline.h:137
PRMAN_INLINE void SplatBeauty(RtColorRGB const &val, RtColorRGB &trans) const
Definition: RixLPEInline.h:717
RixLPEState & m_state
Definition: RixLPE.h:362
RixLPEToken m_lgtLpeToken
Definition: RixLPE.h:351
virtual RixLPEToken StringToToken(RtUString str) const =0
bool m_writeOpacityAllowed
Definition: RixLPE.h:365
RixLPE()
Definition: RixLPE.h:199
RixChannelId m_beautyChanId
Definition: RixLPE.h:260
PRMAN_INLINE SplatHelper(RixDisplayServices *displaySvc, int integratorCtxIndex, RixLPE &rixLpe, RixLPEState &state, int depth, RixLPEToken lightLpeToken, RixLPEToken lpeGroupId, bool isReflect, RtColorRGB const &eyeTrans, RtColorRGB const &lightTrans, RixShadingContext const *shadingCtx, int shadingCtxIndex, bool writeOpacityAllowed=true)
Definition: RixLPEInline.h:466
virtual void FreeStates(int count, RixLPEState *states)=0
virtual void DecRef()=0
unsigned int RixChannelId
Definition: RixIntegrator.h:55
PRMAN_INLINE bool AnyCustomLPEs() const
Definition: RixLPEInline.h:144
RtColorRGB m_eyeTrans
Definition: RixLPE.h:354
RixShadingContext const * m_sCtx
Definition: RixLPE.h:363
virtual RixLPEState * AllocateStates(int count)=0
int RixLPEToken
int m_integratorCtxIdx
Definition: RixLPE.h:360