LightsprintSDK 2021.08.08
rr::RRSolver Class Reference

#include <RRSolver.h>

Inheritance diagram for rr::RRSolver:
rr::RRUniformlyAllocatedNonCopyable rr::RRUniformlyAllocated rr_gl::RRSolverGL

Classes

struct  CalculateParameters
 
struct  FilteringParameters
 
struct  Multipliers
 
struct  PathTracingParameters
 
struct  SmoothingParameters
 
struct  UpdateParameters
 

Public Types

enum  InternalSolverType {
  NONE ,
  ARCHITECT ,
  FIREBALL ,
  BOTH
}
 

Public Member Functions

 RRSolver ()
 
virtual ~RRSolver ()
 
virtual void setColorSpace (const RRColorSpace *colorSpace)
 
const RRColorSpacegetColorSpace () const
 
void setEnvironment (RRBuffer *environment0, RRBuffer *environment1=nullptr, RRReal angleRad0=0, RRReal angleRad1=0)
 
RRBuffergetEnvironment (unsigned environmentIndex=0, RRReal *angleRad=nullptr) const
 
void setEnvironmentBlendFactor (float blendFactor)
 
float getEnvironmentBlendFactor () const
 
virtual void setLights (const RRLights &lights)
 
const RRLightsgetLights () const
 
void setDirectIllumination (const unsigned *perTriangleIrradianceRGBA)
 
const unsigned * getDirectIllumination ()
 
virtual void setStaticObjects (const RRObjects &objects, const SmoothingParameters *smoothing, const char *cacheLocation=nullptr, RRCollider::IntersectTechnique intersectTechnique=RRCollider::IT_BVH_FAST, RRSolver *copyFrom=nullptr)
 
const RRObjectsgetStaticObjects () const
 
void setDynamicObjects (const RRObjects &objects)
 
const RRObjectsgetDynamicObjects () const
 
RRObjects getObjects () const
 
RRObjectgetObject (unsigned index) const
 
RRCollidergetCollider () const
 
const RRObjectgetAABB (RRVec3 *_mini, RRVec3 *_maxi, RRVec3 *_center) const
 
void processBuffers (const RRVector< unsigned > *layers, std::function< void(RRBuffer *)> func) const
 
virtual void calculate (const CalculateParameters *params=nullptr)
 
unsigned getSolutionVersion () const
 
virtual unsigned updateLightmap (int objectNumber, RRBuffer *lightmap, RRBuffer *directionalLightmap[3], RRBuffer *bentNormals, const UpdateParameters *params, const FilteringParameters *filtering=nullptr)
 
virtual unsigned updateLightmaps (int layerLightmap, int layerDirectionalLightmap, int layerBentNormals, const UpdateParameters *params, const FilteringParameters *filtering)
 
virtual unsigned updateEnvironmentMap (RRObjectIllumination *illumination, unsigned layerEnvironment, unsigned layerLightmap, unsigned layerAmbientMap)
 
bool getTriangleMeasure (unsigned triangle, unsigned vertex, RRRadiometricMeasure measure, RRVec3 &out) const
 
virtual void reportMaterialChange (bool dirtyShadows, bool dirtyGI)
 
virtual void reportDirectIlluminationChange (int lightIndex, bool dirtyShadows, bool dirtyGI, bool dirtyRange)
 
virtual void reportInteraction ()
 
bool buildFireball (unsigned avgRaysPerTriangle, const RRString &filename)
 
bool loadFireball (const RRString &filename, bool onlyPerfectMatch)
 
void leaveFireball ()
 
InternalSolverType getInternalSolverType () const
 
void checkConsistency ()
 
virtual bool containsLightSource () const
 
virtual bool containsRealtimeGILightSource () const
 
virtual void allocateBuffersForRealtimeGI (int layerLightmap, int layerEnvironment, unsigned diffuseEnvMapSize=4, unsigned specularEnvMapSize=16, unsigned refractEnvMapSize=16, bool allocateNewBuffers=true, bool changeExistingBuffers=true, float specularThreshold=0.2f, float depthThreshold=0.1f) const
 
RRObjectgetMultiObject () const
 
void pathTraceFrame (const RRCamera &camera, RRBuffer *frame, unsigned accumulate, const PathTracingParameters &parameters)
 
- Public Member Functions inherited from rr::RRUniformlyAllocated
void * operator new (std::size_t n)
 
void * operator new[] (std::size_t n)
 
void operator delete (void *p, std::size_t n)
 
void operator delete[] (void *p, std::size_t n)
 

Public Attributes

bool aborting
 

Protected Member Functions

void calculateDirtyLights (const CalculateParameters *params=nullptr)
 
- Protected Member Functions inherited from rr::RRUniformlyAllocatedNonCopyable
 RRUniformlyAllocatedNonCopyable ()
 
 ~RRUniformlyAllocatedNonCopyable ()
 

Friends

class PathtracerWorker
 

Detailed Description

Global illumination solver for interactive applications.

Usage for interactive realtime visualizations and tools: Create one instance at the beginning of interactive session and load it with all static objects in scene. Call calculate() at each frame, it will spend some time by improving illumination. When scene changes, report it using report* methods.

Usage for non interactive tools/precalculators is the same as for interactive applications, with these differences:

Custom access to GPU and your renderer is not implemented here. You may implement it in your RRSolver subclass or use rr_gl::RRSolverGL, that implements GPU access using OpenGL 2.0.

Sample RealtimeRadiosity shows both typical usage scenarios, rendering with realtime global illumination and precalculations.

It is not allowed to create and use multiple instances at the same time.

Thread safe: Partially, see functions for more details. All updateXxxx() functions automatically use all cores.

Member Enumeration Documentation

◆ InternalSolverType

Type of internal solver. For debugging purposes.

Enumerator
NONE 
ARCHITECT 
FIREBALL 
BOTH 

Constructor & Destructor Documentation

◆ RRSolver()

rr::RRSolver::RRSolver ( )

◆ ~RRSolver()

virtual rr::RRSolver::~RRSolver ( )
virtual

Member Function Documentation

◆ setColorSpace()

virtual void rr::RRSolver::setColorSpace ( const RRColorSpace colorSpace)
virtual

Set colorSpace used by this scene i/o operations.

It switches solver inputs and outputs from physical scale to custom scale defined by colorSpace, e.g. screen colors. See RRColorSpace for details.

In 99% of cases you want to set colorSpace before using solver as nearly all existing renderers and datasets use sRGB or other custom scale. Not setting colorSpace is allowed for future rendering pipelines working fully in physical scale.

Parameters
colorSpaceColor space for converting illumination from/to linear colors. It will be used by all data input and output paths in RRSolver, if not specified otherwise. Note that colorSpace is not adopted, you are still responsible for deleting it when it's no longer needed.

◆ getColorSpace()

const RRColorSpace * rr::RRSolver::getColorSpace ( ) const

Returns colorSpace used by this scene i/o operations, set by setColorSpace().

◆ setEnvironment()

void rr::RRSolver::setEnvironment ( RRBuffer environment0,
RRBuffer environment1 = nullptr,
RRReal  angleRad0 = 0,
RRReal  angleRad1 = 0 
)

Sets environment around scene.

This is one of ways for light to enter solver; others are setLights(), setDirectIllumination(), emissive materials. Environment is rendered around scene and scene is illuminated by environment.

By default, scene contains no environment, which is the same as black environment.

Parameters
environment0LDR or HDR environment stored in cube map or in 2d texture with 360*180 degree panorama (equirectangular projection). Buffer is not adopted, you are still responsible for deleting it when it's no longer needed.
environment1Optional second environment map, solver is able to work with blend of two environments, see setEnvironmentBlendFactor(). It's ok to mix LDR and HDR maps, 2d and cube maps, all combinations work. Buffer is not adopted, you are still responsible for deleting it when it's no longer needed.
angleRad0
angleRad1

◆ getEnvironment()

RRBuffer * rr::RRSolver::getEnvironment ( unsigned  environmentIndex = 0,
RRReal angleRad = nullptr 
) const

Returns scene environment set by setEnvironment().

◆ setEnvironmentBlendFactor()

void rr::RRSolver::setEnvironmentBlendFactor ( float  blendFactor)

Sets environment blend factor, specifies how two environments are blended together.

Parameters
blendFactorAny value between 0 and 1, tells solver how to blend two environments. 0 = use only environment0, this is default. 1 = use only environment1. Lightsprint realtime GI solvers and realtime renderer fully support blending, offline GI solver works as if blendFactor is 0.

◆ getEnvironmentBlendFactor()

float rr::RRSolver::getEnvironmentBlendFactor ( ) const

Returns environment blend factor set by setEnvironment().

◆ setLights()

virtual void rr::RRSolver::setLights ( const RRLights lights)
virtual

Sets lights in scene, all at once.

This is one of ways how light enters solver, others are setEnvironment(), setDirectIllumination(), emissive materials.

By default, scene contains no lights.

Setting lights is important for offline GI and for direct illumination in realtime renderer. If you integrate Lightsprint realtime GI with third party renderer and you use solver only to calculate realtime indirect illumination, calling setLights() is not necessary; calling setDirectIllumination() instead gives solver necessary information.

Reimplemented in rr_gl::RRSolverGL.

◆ getLights()

const RRLights & rr::RRSolver::getLights ( ) const

Returns lights in scene, set by setLights().

◆ setDirectIllumination()

void rr::RRSolver::setDirectIllumination ( const unsigned *  perTriangleIrradianceRGBA)

Sets custom irradiance for all static triangles in scene.

This is one of paths for light to enter solver, others are setLights(), setEnvironment(), emissive materials. Unlike the other paths, this one is usually called many times - whenever lighting changes.

If you use rr_gl::RRSolverGL, setDirectIllumination() is called automatically from calculate().

If you want to provide your own direct illumination data, for example when integrating Lightsprint realtime GI with third party renderer, use RRSolver and call setDirectIllumination() manually before calculate() whenever lighting changes. Note that functions that reset solver or change its type (setStaticObjects(), loadFireball() etc) might reset also direct illumination, so you need to set it again after such functions.

Parameters
perTriangleIrradianceRGBAArray of average per-triangle direct-lighting irradiances in custom scale. In other words, average triangle colors when direct lighting+shadows are applied, but materials are not. Format is RGBA8, i.e. first byte is red, second one is green, third one is blue, fourth one is ignored.

Length of array is getMultiObject()->getCollider()->getMesh()->getNumTriangles(). Order of values in array is defined by order of static triangles in scene, first all triangles from static object 0, then all triangles from static object 1 etc.

Array must stay valid at least until next setDirectIllumination() call. Array is not adopted+deleted, you are still responsible for deleting it. You are free to set always the same array or each time different one, performace is identical.

Setting nullptr is the same as setting array filled by zeroes, no custom irradiance.

◆ getDirectIllumination()

const unsigned * rr::RRSolver::getDirectIllumination ( )

Returns pointer previously passed to setDirectIllumination(), or nullptr if it was not set yet.

◆ setStaticObjects()

virtual void rr::RRSolver::setStaticObjects ( const RRObjects objects,
const SmoothingParameters smoothing,
const char *  cacheLocation = nullptr,
RRCollider::IntersectTechnique  intersectTechnique = RRCollider::IT_BVH_FAST,
RRSolver copyFrom = nullptr 
)
virtual

Sets static contents of scene, all static objects at once. Only objects with ! RRObject::isDynamic are taken, the rest is ignored.

Solver creates internal set of static objects, by taking only those of your objects with isDynamic=false, you can query accepted objects by getStaticObjects(). Solver preserves your order of static objects. Any reference to n-th object in documentation refers to getStaticObjects()[n]. If you pass only static objects, then getStaticObjects()[n]==objects[n]. Solver reads isDynamic only in this function; if you change it later, it won't have any effect.

Once set, triangles and vertices in static objects must not change (that's the difference from dynamic objects). If you modify static triangles or vertices anyway, call setStaticObjects() again otherwise solver might crash.

Scene must always contain static objects. Major occluders (buildings, large furniture etc) should be part of static scene. Handling major occluders as dynamic objects is safe, but it reduces realism of realtime indirect illumination, so it is not recommended.

If Fireball was enabled, setStaticObjects() disables it.

Parameters
objectsStatic contents of your scene, set of static objects.
Objects are passed via RRObjects, collection of pointers to objects. Solver creates its own copy of these pointers, but it does not copy actual objects. So while your collection is no longer accessed after this call, actual objects are, you must not deallocate or modify them until next setStaticObjects() call or solver destruction. Changing objects, meshes, positions, colors etc while they are set in solver could crash program. Changing illumiation stored in objects is safe.
smoothingStatic scene illumination smoothing. Set nullptr for default values.
cacheLocationWhether and where to cache colliders (speeds up startup when opening the same geometry next time). It is passed to RRCollider::create(), so default nullptr caches in temp, "*" or any other invalid path disables caching, any valid is path where to cache colliders.
intersectTechniqueIntersection technique used by solver. Techniques differ by speed and memory requirements.
copyFromShould stay nullptr (used by sceneViewer to reuse multiObject and smoothing from old solver).

◆ getStaticObjects()

const RRObjects & rr::RRSolver::getStaticObjects ( ) const

Returns static contents of scene, all static objects at once. It is very fast, returning reference to existing collection.

◆ setDynamicObjects()

void rr::RRSolver::setDynamicObjects ( const RRObjects objects)

Sets dynamic contents of scene, all dynamic objects at once. Only objects with RRObject::isDynamic are taken, the rest is ignored.

Solver creates internal set of dynamic objects, by taking only those of your objects with isDynamic=true, you can query accepted objects by getDynamicObjects(). Solver preserves your order of dynamic objects. If you pass only dynamic objects, then getDynamicObjects()[n]==objects[n]. Solver reads isDynamic only in this function; if you change it later, it won't have any effect.

Unlike static objects, you may freely edit dynamic objects between frames. If you want to add or remove objects, call setDynamicObjects() again. If you only edit object properties, there's no need to call it again.

Dynamic objects affect realtime lighting, they are ignored when building static lightmaps. API does not even let you build lightmaps for dynamic objects, as it does not make big sense, dynamic objects are better illuminated by diffuse and specular reflection maps, see updateEnvironmentMap(). If you really have to bake lightmap for dynamic object, make the object static first; if you also need the object to have no effect on other static objects (no shadows etc), but still receive light/shadows from other static objects, make the object transparent during lightmap baking (via material->specularTransmittance).

◆ getDynamicObjects()

const RRObjects & rr::RRSolver::getDynamicObjects ( ) const

Returns dynamic contents of scene, all dynamic objects at once. It is very fast, returning reference to existing collection.

◆ getObjects()

RRObjects rr::RRSolver::getObjects ( ) const

Returns collection of all objects in scene. It is slower than getStaticObjects() and getDynamicObjects(), returning newly allocated collection.

◆ getObject()

RRObject * rr::RRSolver::getObject ( unsigned  index) const

Returns given object or nullptr for out of range index. Objects are indexed from 0, static objects go first, then dynamic.

◆ getCollider()

RRCollider * rr::RRSolver::getCollider ( ) const

Returns collider for whole scene, both static and dynamic.

Never returns nullptr, even if scene is empty. Returned collider is valid until next getCollider() call. It is owned by solver, you don't delete it.

This is slightly heavier operation as it updates acceleration structures. Therefore recommended usage is to call it once, use returned collider many times (ideally until scene changes) rather than getting collider for each ray.

When a dynamic object moves, call reportDirectIlluminationChange(-1,...) to update illumination. As a sideeffect, solver marks collider dirty and builds new one next time you call getCollider(). If you don't get correct intersections, verify that reportDirectIlluminationChange(-1,...) is called after object movement.

Thread safe: no, you must not use solver or modify objects while getCollider() executes. Returned collider is thread safe as usual, many threads can calculate intersections at once.

Returned collider does not necessarily know about objects, so ray.hitObjects is not necessarily set after intersection. If you need to know what single object was intersected, follow instructions

  • before calling intersect() on this collider, do ray.hitObject = solver->getMultiObject();
  • when intersect() on this collider returns true, do ray.convertHitFromMultiToSingleObject(solver);

If you can afford to ignore dynamic objects, collide with static objects only, it's faster. To collide with static objects only, use getMultiObject()->getCollider().

◆ getAABB()

const RRObject * rr::RRSolver::getAABB ( RRVec3 _mini,
RRVec3 _maxi,
RRVec3 _center 
) const

Fills bounding box of all objects in solver.

Returns
Some planar dynamic objects (like ocean surface) would make box very large, so we exclude them from calculation. In such case, pointer to one of excluded planes is returned.

◆ processBuffers()

void rr::RRSolver::processBuffers ( const RRVector< unsigned > *  layers,
std::function< void(RRBuffer *)>  func 
) const

Does something once for each buffer in solver's materials, lights, environment and illumination layers.

Can be used to gather all texture filenames, to pause all videos etc.

Parameters
layersIllumination from given layers will be processed too.
funcCode to run for each buffer once.

◆ calculate()

virtual void rr::RRSolver::calculate ( const CalculateParameters params = nullptr)
virtual

Calculates and improves indirect illumination on static objects.

Call this function once per frame while rendering realtime GI. You can call it even when not rendering, to improve GI solution inside solver (so that you have it ready when you render scene later). On the other hand, don't call it when you don't need realtime GI, for example when rendering offline baked lightmaps, it would still spend time calculating realtime GI even if you don't need it.

It helps to improve performance if you don't repeatedly render scene that doesn't change, for example in game editor. Note that user can't see any difference, you only save time and power by not rendering the same image again. calculate() uses these periods for more intense calculations, creating higher quality illumination. It detects these periods from you not calling reportDirectIlluminationChange() and reportInteraction().

For games, it is recommended to call loadFireball() before first calculate(). Without fireball, first calculate() takes longer, solver internals are initialized.

Parameters
paramsOptional calculation parameters. Currently used only by Fireball.

Reimplemented in rr_gl::RRSolverGL.

◆ getSolutionVersion()

unsigned rr::RRSolver::getSolutionVersion ( ) const

Returns version of global illumination solution.

You may use this number to avoid unnecessary updates of illumination buffers. Store version together with your illumination buffers and don't update them (updateLightmaps()) until this number changes.

Version may be incremented only by calculate().

◆ updateLightmap()

virtual unsigned rr::RRSolver::updateLightmap ( int  objectNumber,
RRBuffer lightmap,
RRBuffer directionalLightmap[3],
RRBuffer bentNormals,
const UpdateParameters params,
const FilteringParameters filtering = nullptr 
)
virtual

For single static object, calculates and updates lightmap and/or bent normals; in per-pixel or per-vertex; with direct, indirect or global illumination.

This is universal update for both per-pixel and per-vertex buffers. Type and format of data produced depends only on type and format of buffer you provide. Combinations like per-pixel colors, per-vertex bent normals are supported too. Format of buffer is preserved.

For 2d texture buffer (lightmap, bentNormalMap), uv channel material->lightmap.texcoord is used. All uv coordinates must be in 0..1 range and two triangles must not overlap in texture space. If it's not satisfied, contents of created lightmap is undefined.

Thread safe: no, but there's no need to run it from multiple threads at the same time, all cores are used automatically.

Parameters
objectNumberNumber of object in this scene. Object numbers are defined by order in which you pass objects to setStaticObjects(). In case of vertex buffer, -1 is allowed for multiobject with whole static scene.
lightmapBuffer for storing calculated illumination.
May be nullptr.
Types supported: BT_VERTEX_BUFFER, BT_2D_TEXTURE, however with Fireball, only vertex buffer is supported.
Formats supported: All color formats, RGB, RGBA, bytes, floats. Data are converted to format of buffer.
Lightmap could contain direct, indirect or global illumination, depending on parameters you set in params.
directionalLightmapPointer to array of three lightmaps for storing calculated directional illumination.
Compatible with Unreal Engine 3 directional lightmaps.
May be nullptr.
Supports the same types and formats as parameter 'lightmap'.
bentNormalsBuffer for storing calculated bent normals, compact representation of directional information.
May be nullptr.
RGB values (range 0..1) are calculated from XYZ worldspace normalized normals (range -1..1) by this formula: (XYZ+1)/2.
Supports the same types and formats as parameter 'lightmap'.
paramsParameters of the update process. Set nullptr for default parameters that specify very fast realtime/preview update.
filteringParameters of lightmap filtering, set nullptr for default ones.
Returns
Number of lightmaps and bent normal maps updated, 0 1 or 2. If it's lower than you expect, read system messages (RRReporter) for more details on possible failure.
Remarks
In comparison with more general updateLightmaps() function, this one lacks paramsIndirect. However, you can still include indirect illumination while updating single lightmap, see updateLightmaps() remarks.

◆ updateLightmaps()

virtual unsigned rr::RRSolver::updateLightmaps ( int  layerLightmap,
int  layerDirectionalLightmap,
int  layerBentNormals,
const UpdateParameters params,
const FilteringParameters filtering 
)
virtual

For all static objects, calculates and updates lightmap and/or bent normal; in per-pixel or per-vertex; with direct, indirect or global illumination.

This is more powerful full scene version of single object's updateLightmap().

Usage:

  1. create buffers of arbitrary types and formats (per-pixel, per-vertex, bytes, floats, rgb, rgba, physical scale, custom scale) and store them to getStaticObjects()[objectNumber]->illumination->getLayer(layerIndex)
  2. call updatelightmaps()
  3. enjoy buffers with computed lighting, you can do buffer->save(), buffer->lock(), renderer->render()...

For 2d texture buffer (lightmap, bentNormalMap), uv channel material->lightmap.texcoord is used. All uv coordinates must be in 0..1 range and two triangles must not overlap in texture space. If it's not satisfied, contents of created lightmap is undefined.

Lightmap update is one of the most demanding functions in Lightsprint SDK. Its time complexity can be roughly predicted.

Thread safe: no, but there's no need to run it from multiple threads at the same time, all cores are used automatically.

Parameters
layerLightmap1 lightmap per object will be computed into existing buffers in this layer, getStaticObjects()[objectNumber]->illumination->getLayer(layerNumber).
Negative number disables update of lightmaps.
layerDirectionalLightmap3 directional lightmaps per object will be computed into existing buffers in this layer and two successive layers, getStaticObjects()[objectNumber]->illumination->getLayer(layerNumber).
Negative number disables update of directional lightmaps.
layerBentNormalsBent normals will be computed into existing buffers in this layer, getStaticObjects()[objectNumber]->illumination->getLayer(layerBentNormals).
Negative number disables update of bent normals.
paramsParameters of the update process. With nullptr or quality=0, update is realtime, but options are limited, only vertex buffers are filed with indirect illumination in physical scale, read from current solution in solver. With quality>0, you get much more flexibility, but update is non-realtime.
filteringParameters of lightmap filtering, set nullptr for default ones.
Returns
Number of lightmaps updated. If it's lower than you expect, read system messages (RRReporter) for more details on possible failure.
Remarks
As a byproduct of calculation with indirect ilumination, internal state of solver (current solution) is updated, so that it holds computed indirect illumination for sources and quality specified in params. Internal state is properly updated even when buffers don't exist (so no other output is produced). Following updateLightmap() will include this indirect lighting into computed buffer if you call it with params->useCurrentSolution=true.
Update of selected objects (rather than all objects) is supported in multiple ways, use one of them. All three ways produce the same quality, but first one may be faster in some cases.
  • create buffers for selected objects, make sure other buffers are nullptr and call updateLightmaps()
  • if you don't need indirect illumination, simply call updateLightmap() for all selected objects
  • call updateLightmaps(-1,-1,params,nullptr) once to update current solution, call updateLightmap(params with useCurrentSolution=true) for all selected objects
Sharing one lightmap by multiple objects is not supported out of the box. Please consult us for possible solutions.

◆ updateEnvironmentMap()

virtual unsigned rr::RRSolver::updateEnvironmentMap ( RRObjectIllumination illumination,
unsigned  layerEnvironment,
unsigned  layerLightmap,
unsigned  layerAmbientMap 
)
virtual

Calculates and updates object's environment map, stored in given layer of given illumination.

Function updates existing buffer, it does nothing if buffer does not exist. You can allocate buffers

Generated environment can be used for illumination of both static and dynamic objects.

Function is fast for low resolution cubemaps, suitable for use in realtime applications. It is safe to call it often, it returns quickly if it detects that illumination is already up to date. For high resolution (more than approximately 32x32x6) envmaps, consider calling RRSolverGL::updateEnvironmentMap() instead, it is faster.

Function reads static scene illumination, so don't call it before calculate(), otherwise dynamic objects will reflect light from previous frame, or no light at all. If you have to update envmaps before calculate(), use RRSolverGL::updateEnvironmentMap().

Thread safe: yes, may be called from multiple threads at the same time (but there's no need as it uses all cores internally)

Parameters
illuminationObject's illumination to be updated. (It's not necessary to have RRObject adapter for dynamic object, but its RRObjectIllumination must exist.)
layerEnvironmentNumber of layer with environment maps, they are addressed by illumination->getLayer(layerEnvironment).
layerLightmapNumber of layer with lightmaps, they are addressed by illumination->getLayer(layerLightmap). Unused by default implementation.
layerAmbientMapNumber of layer with ambient maps, they are addressed by illumination->getLayer(layerAmbientMap). Unused by default implementation. While default implementation reads illumination directly from solver, access to lightmaps and/or ambient maps allows other implementations (rr_gl::RRSolverGL::updateEnvironmentMap()) to read illumination from lights and these maps instead.
Returns
Number of environment maps updated, 0 or 1.

Reimplemented in rr_gl::RRSolverGL.

◆ getTriangleMeasure()

bool rr::RRSolver::getTriangleMeasure ( unsigned  triangle,
unsigned  vertex,
RRRadiometricMeasure  measure,
RRVec3 out 
) const

Reads illumination of triangle's vertex in units given by measure.

Reads results in format suitable for fast vertex based rendering without subdivision.

Parameters
triangleIndex of triangle in multiobject you want to get results for.
vertexIndex of triangle's vertex you want to get results for. Valid vertices are 0, 1, 2. For invalid vertex number, average value for whole triangle is taken instead of smoothed value in vertex.
measureSpecifies what to measure, using what units.
outFor valid inputs, illumination level is stored here. For invalid inputs, nothing is changed.
Returns
True if out was successfully filled. False may be caused by invalid inputs.

◆ reportMaterialChange()

virtual void rr::RRSolver::reportMaterialChange ( bool  dirtyShadows,
bool  dirtyGI 
)
virtual

Reports that appearance of one or more materials in static objects has changed.

Call this when you changed material properties of static objects. It is not necessary to report change in dynamic objects (it would only cost time, without affecting GI).

Note that solver creates physically validated copy of all materials in static objects, you can edit both original materials (in custom scale, used for realtime rendering) and validated copies (in physical scale, used for indirect illumination), but you are responsible for keeping them in sync. Complete code sequence to edit original material, synchronize copy in solver and report change could look like

... here you edit material's color
material->convertToLinear(solver->getColorSpace()); // converts material's color to colorLinear
solver->reallocateBuffersForRealtimeGI(); // allocates specular reflection cubes if you add specular
solver->reportMaterialChange();

If you make e.g. red color and blue colorLinear, realtime renderer will render red material, but reflected light will be blue.

Parameters
dirtyShadowsSet this if you want shadows updated. Shadows may need update after change in material transparency.
dirtyGISet this if you want GI updated, or keep it false to save time. If you use Fireball, changes in emissive textures are recognized automatically, you don't have to report them, however, some other material changes won't affect GI until you rebuild fireball with buildFireball().

◆ reportDirectIlluminationChange()

virtual void rr::RRSolver::reportDirectIlluminationChange ( int  lightIndex,
bool  dirtyShadows,
bool  dirtyGI,
bool  dirtyRange 
)
virtual

Reports that scene has changed and direct or global illumination should be updated.

Call this function when light moves, changes color etc.. or when geometry changes, so that shadows and/or GI should be updated. Note that direct illumination changes also when dynamic objects move, call it with lightIndex -1 in such case.

Parameters
lightIndexLight number in list of lights, see setLights(). If geometry changes, pass -1, change will be reported to all lights in solver.
dirtyShadowsTells that direct shadows should be updated. Generic RRSolver uses it only to invalidate collider returned by getCollider() (because when shadows need update, it's most likely because geometry did change); subclasses (e.g. rr_gl::RRSolverGL) use it also to update light's shadowmaps.
dirtyGITells that global illumination should be updated. Generic RRSolver ignores it, but subclasses (e.g. rr_gl::RRSolverGL) use it to redetect appropriate direct irradiances and call setDirectIllumination(). You can save time by setting false when changes in scene were so small, that change in GI would be hardly visible. This is usually case when objects move, but lights stay static or nearly static - moving objects have much weaker global effects than moving lights.
dirtyRangeTells that shadowmapping near/far range should be updated. Near should be small enough to not clip objects, but not smaller (it would increase shadow bias). Solver recalculates it on demand from distance of nearby objects.

Reimplemented in rr_gl::RRSolverGL.

◆ reportInteraction()

virtual void rr::RRSolver::reportInteraction ( )
virtual

Reports interaction between user and application.

This is useful for better CPU utilization in non-interactive periods of life of your application. Call it each time user hits key, moves mouse etc, or animation frame is played.

When called often, solver calculates illumination in small batches to preserve realtime performance. This is typical mode for games.

When not called at all, there's no interaction between user and application and solver increases calculation batches up to 100ms at once to better utilize CPU. This happens for example in game editor, when level designer stops moving mouse.

◆ buildFireball()

bool rr::RRSolver::buildFireball ( unsigned  avgRaysPerTriangle,
const RRString filename 
)

Build and start Fireball. Optionally save it to file.

Builds Fireball from scratch, starts it and optionally saves it to file. Later you can load saved file and start Fireball faster, see loadFireball(). This function must be called after setStaticObjects(), because it depends on static objects in scene. It doesn't depend on lights end environment.

Build complexity is O( avgRaysPerTriangle * t * log(t) ) where t is number of triangles in static objects.

Fireball is faster, higher quality, smaller, realtime only solver; it is highly recommended for games. When used, non-realtime functions like updateLightmaps(some params..) are not supported, but realtime functions like updateLightmaps(other params..) and updateEnvironmentMap() are faster and produce better results using less memory.

Parameters
avgRaysPerTriangleAverage number of rays per triangle used to compute form factors. Higher number = longer calculation, higher quality results, bigger file.
filenameData precomputed for current static scene will be saved to this file. If empty, automatically generated name (in temp directory) is used.
Returns
True if successful. For better consistency, if save (disk operation) fails, Fireball is not started.

◆ loadFireball()

bool rr::RRSolver::loadFireball ( const RRString filename,
bool  onlyPerfectMatch 
)

Load and start Fireball.

Loads and starts Fireball previously saved by buildFireball(). This function should be called before calculate() to avoid unnecessary operations.

Fireball is faster, higher quality, smaller, realtime only solver; it is highly recommended for games. When used, non-realtime functions like updateLightmaps(some params..) are not supported, but realtime functions like updateLightmaps(other params..) and updateEnvironmentMap() are faster and produce better results using less memory.

Parameters
filenameFile with data to load, previously created by buildFireball(). If empty, automatically generated name is used (in your temp directory).
onlyPerfectMatchLoads file only if it was built for exactly the same scene on the same CPU architecture. Applications that build fireball on end-user machines should use true. Applications that ship with fireball pre-built by developer should use true during development (so that any change in scene results in rebuild) and false on end-user machines (so that supplied fireball is always loaded even if scene seems different; difference may be caused by different floation point precision on end-user's system).
Returns
True if successful.

◆ leaveFireball()

void rr::RRSolver::leaveFireball ( )

Switch to non-Fireball solver that supports offline calculations.

◆ getInternalSolverType()

InternalSolverType rr::RRSolver::getInternalSolverType ( ) const

Returns type of active internal solver.

◆ checkConsistency()

void rr::RRSolver::checkConsistency ( )

Checks consistency of data in solver and reports problems found using RRReporter.

While all precomputed lighting and cheap-to-detect realtime lighting problems are reported immediately even without checkConsistency(), more expensive realtime lighting checks are done only on this request.

◆ containsLightSource()

virtual bool rr::RRSolver::containsLightSource ( ) const
virtual

Returns true if solver contains at least one light source.

This could be enabled light, emissive material or environment/skybox. Simple presence of light source is tested, it is not guaranteed that light source actually affects objects in scene.

◆ containsRealtimeGILightSource()

virtual bool rr::RRSolver::containsRealtimeGILightSource ( ) const
virtual

Returns true if solver contains at least one realtime GI capable light source.

All light sources are realtime GI capable with Fireball, the only light source ignored by Architect solver is environment/skybox.

◆ allocateBuffersForRealtimeGI()

virtual void rr::RRSolver::allocateBuffersForRealtimeGI ( int  layerLightmap,
int  layerEnvironment,
unsigned  diffuseEnvMapSize = 4,
unsigned  specularEnvMapSize = 16,
unsigned  refractEnvMapSize = 16,
bool  allocateNewBuffers = true,
bool  changeExistingBuffers = true,
float  specularThreshold = 0.2f,
float  depthThreshold = 0.1f 
) const
virtual

Allocates buffers for realtime GI illumination of objects in solver.

See RRObjects::allocateBuffersForRealtimeGI() for parameters and additional information.

◆ getMultiObject()

RRObject * rr::RRSolver::getMultiObject ( ) const

Returns multiObject created by merging all static objects in scene, see setStaticObjects().

◆ pathTraceFrame()

void rr::RRSolver::pathTraceFrame ( const RRCamera camera,
RRBuffer frame,
unsigned  accumulate,
const PathTracingParameters parameters 
)

Renders scene image into given frame, using pathtracer.

Pathtracing is slower and noisier than rasterization, but it offers higher quality if you give it enough time. Pathtraced images contain random noise, so if you accumulate multiple noisy images, you get smoother one.

Parameters
cameraCamera to view scene from.
frameFramebuffer to render to. If you accumulate multiple frames into single buffer, format should be BF_RGBF or BF_RGBAF, to avoid color banding.
accumulateNumber of frames already accumulated in frame. Increase this number each time you call pathTraceFrame, zero it only when camera or scene change.
parametersAdditional parameters.

◆ calculateDirtyLights()

void rr::RRSolver::calculateDirtyLights ( const CalculateParameters params = nullptr)
protected

Optional extension of calculate(), sets dirty flags in lights when it detects change in transparency texture or video.

Realtime GI implementations (like rr_gl::RRSolverGL) call it from calculate(), before updating shadowmaps.

Friends And Related Symbol Documentation

◆ PathtracerWorker

friend class PathtracerWorker
friend

Member Data Documentation

◆ aborting

bool rr::RRSolver::aborting

Makes other solver functions abort, returning quickly with bogus results.

You may set/unset it asynchronously, from other threads. Solver only reads it, never modifies it, so don't forget to clear it after abort.