Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Ray tracing services are provided by the renderer via the GetNearestHits() and GetTransmission() methods provided on the RixIntegratorContext.

GetNearestHits() is invoked by an integrator to send rays against the geometric database and return the list of nearest ray hits. Two versions of this routine are provided.

  • The first version returns its ray hits in the form of a list of RixShadingContext. These shading contexts represent a collection of points which have had their associated Bxdfs fully executed and set up for sample evaluation and generation. Since a Bxdf evaluation may trigger an upstream evaluation of all input patterns, this call is considered to be very expensive as it invokes full shading. Any shading contexts that are returned by this routine must be released back to the renderer with the ReleaseShadingContexts() method after the integrator is done evaluating or generating samples on the associated Bxdfs of the shading contexts. 
  • The second version of this call returns its ray hits in the form of a list of RtHitGeometry. No shading contexts are set up in this routine, and only information about the geometric locale is returned. This version of the call is preferred if no shading needs to be performed, such as in the case of an occlusion-only integrator.

GetTransmittanceAll the shading contexts that are returned by GetNearestHits() can be invoked by an integrator to compute the transmittance between two points in space. This is of use for bidirectional path tracing applications where the transmittance between vertex connections needs to be computed. It may also be used for computing shadow rays if the lighting services cannot be used for this purpose for some reason.

Both methods above need to be provided with an array of RtRayGeometry that have been properly initialized.

Integration

The IntegrateRays() method is the primary entry point for this class invoked by the renderer. The implementation of this routine is expected to fire the list of active primary rays delivered via the RixIntegratorContext& ictx parameter. This method has output parameters: the numShadingCtxs and shadingCtxs parameters are expected to be filled in with a list of primary shading contexts that are associated with the firing of the active primary rays. These primary shading contexts should not be released by the integrator.

Note

An implementation of IntegrateRays() may choose to ignore the camera rays supplied in the RixIntegratorContext entirely, and shoot an entirely different set of rays. If it chooses to do so, it should be extremely careful about splatting with the display services, as those routines are set up to be indexed by the integratorCtxIndex field of the original primary rays.

 must be explicitly released back to the renderer with the ReleaseShadingContexts() method. However:

  • shading contexts that are provided by the renderer to the integrator (through RixIntegrator::Integrate())
  • shading contexts returned to the renderer (through RixIntegrator::IntegrateRays()

do not need to be released. The renderer will take care of this when appropriate. 

Shading contexts associated with a bxdf closure can use a consequent amount of memory, so it is recommended to release them as soon as they are not needed anymore. This is usually possible after the integrator is done evaluating or generating samples for these bxdfs. 

GetTransmittance() can be invoked by an integrator to compute the transmittance between two points in space. This is of use for bidirectional path tracing applications where the transmittance between vertex connections needs to be computed. It may also be used for computing shadow rays if the lighting services cannot be used for this purpose for some reason.

Both methods above need to be provided with an array of RtRayGeometry that have been properly initialized.

Integration

The IntegrateRays() method is the primary entry point for this class invoked by the renderer. The implementation of this routine is expected to fire the list of active primary rays delivered via the RixIntegratorContext& ictx parameter. This method has output parameters: the numShadingCtxs and shadingCtxs parameters are expected to be filled in with a list of primary shading contexts that are associated with the firing of the active primary rays. These primary shading contexts should not be released by the integrator.

Note

An implementation of IntegrateRays() may choose to ignore the camera rays supplied in the RixIntegratorContext entirely, and shoot an entirely different set of rays. If it chooses to do so, it should be extremely careful about splatting with the display services, as those routines are set up to be indexed by the integratorCtxIndex field of the original primary rays.

The default implementation supplied for IntegrateRays() simply calls RixIntegratorContext::GetNearestHits to trace the primary rays, and passes the associated shading context results to Integrate(), The default implementation supplied for IntegrateRays() simply calls RixIntegratorContext::GetNearestHits to trace the primary rays, and passes the associated shading context results to Integrate(), which is the secondary entry point for this class. Integrate() is never directly invoked by the renderer; it is provided as an override convenience for implementors that are content with the default behavior of IntegrateRays. Following a call to IntegrateRays() (or Integrate()), integrators are expected to provide results to the renderer via the display services.

...

Generating light samples, evaluating bxdf response
Code Block
// numLightSamples is the number of light samples generated for *each* shading point.
// Currently, this value is used for all points in the current shading context.


// RixLightingServices::GenerateLightSamples() fill array parameters with the first
// sample for all shading points first, then the second sample, and so on...


// m_ClDiffuse, m_ClSpecular, m_ClUser are arrays of RtColorRGB buffers. Each buffer is of size
// numLightSamples * numPoints.  They will store the generated light samples.

RixBXLobeWeights lightContributions(
    numLightSamples * numPoints,
    m_numPotentialDiffuseLobes,
    m_numPotentialSpecularLobes,
    m_numPotentialUserLobes,
    m_ClDiffuse,
    m_ClSpecular,
    m_ClUser);

// m_diffuse, m_specular, m_user are arrays of RtColorRGB buffers. Each buffer is of size
// numLightSamples * numPoints. They will store the bxdf contribution for each light sample.

RixBXLobeWeights evaluatedMaterialContributions(
    numLightSamples * numPoints,
    m_numPotentialDiffuseLobes,
    m_numPotentialSpecularLobes,
    m_numPotentialUserLobes,
    m_diffuse,
    m_specular,
    m_user);

// For additional description of the call parameters, see RixLightingServices API.
lightingSvc->GenerateSamples(
    numLightSamples, &rixRNG, lightGroupIds, lightLpeTokens, directions, lightNormals, distance, 
    &lightContributions, transmission, nullptr, lightPdf, 
    lobesWanted, &evaluatedMaterialContributions, evaluatedMaterialFPdf, evaluatedMaterialRPdf,
    lobesEvaluated, nullptr, throughput);


// We don't need to make an explicit call to the bxdf's EvaluateSamples(), because the lighting
// services have done it for us, since we provided them with 'evaluatedMaterialContributions'.

...

Generating bxdf samples, evaluating light contribution
Code Block
// numBxdfSamples is the number of bxdf samples generated for *each* shading point.
// Currently, this value is used for all points in the current shading context.


RixBXLobeWeights bxdfContributions(
    numBxdfSamples* numPoints,
    m_numPotentialDiffuseLobes,
    m_numPotentialSpecularLobes,
    m_numPotentialUserLobes, 
    m_diffuse,
    m_specular,
    m_user);

// The RixBxdf GenerateSample API is single-sample (per shading point), so when dealing with
// multiple bxdf samples, we need to wrap it inside a loop.
for (int bs = 0; bs < numBxdfSamples; bs++) {
    int offset = bs * numPoints;

    // Changing the offset of the lobe weights will write into the lobe weights at the appropriate
    // offset for this set of bxdf samples.
    bxdfContribution.SetOffset(offset);

    bxdf.GenerateSample(k_RixBXDirectLighting, lobesWanted, &rixRNG,
                        lobeSampled + offset, directions + offset,
                        bxdfContributions, materialFPdf + offset,
                        materialRPdf + offset, nullptr);

    for (int i = 0; i < numPoints; i++) distances[offset + i] = 1e20f;

    incRNG(shadingContext);
}

// Reset the offset of the lobe weights back to zero for the code below.
bxdfContributions.SetOffset(0);

RixBXLobeWeights lightContributions(
    numBxdfSamples * numPoints,
    m_numPotentialDiffuseLobes,
    m_numPotentialSpecularLobes,
    m_numPotentialUserLobes, 
    m_ClDiffuse,
    m_ClSpecular, 
    m_ClUser);

lightingSvc->EvaluateSamples(
    // inputs
    numBxdfSamples, &rixRNG, directions, distances, materialFPdf, &bxdfContributions, lobeSampled,
    // outputs
    lightGroupIds, lightLpeTokens, &lightContributions, transmission, nullptr, lightPdf,
    nullptr, nullptr, throughput);

...

For reflection we compute the reflected ray spread using two approaches:

  1. Ray spread based on surface curvature.

...

  1.  The ray spread for reflection from a curved smooth surface is simple to compute accurately using Igehy's differentiation formula:


    Code Block
    spread' = spread + 2*curvature*PRadius

...


  1. Ray spread based on roughness (pdf).

...

  1.  The ray spread from a flat rough surface depends on roughness: the higher the roughness the lower the pdf in a given direction; here we map the pdf to a ray spread using a heuristic mapping:

    Code Block
    spread' = c * 1/sqrt(pdf) -- with c = 1/8

...


We set the overall ray spread to the max of these two.

...